blob: 0b724da1dea9445bec467df93ff1efd7edb2f752 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/editing/state_machines/backspace_state_machine.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/unicode.h"
namespace blink {
namespace backspace_state_machine_test {
const TextSegmentationMachineState kNeedMoreCodeUnit =
TextSegmentationMachineState::kNeedMoreCodeUnit;
const TextSegmentationMachineState kFinished =
TextSegmentationMachineState::kFinished;
TEST(BackspaceStateMachineTest, DoNothingCase) {
BackspaceStateMachine machine;
EXPECT_EQ(0, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(0, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, SingleCharacter) {
BackspaceStateMachine machine;
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
machine.Reset();
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('-'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
machine.Reset();
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('\t'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
machine.Reset();
// U+3042 HIRAGANA LETTER A.
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(0x3042));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, SurrogatePair) {
BackspaceStateMachine machine;
// U+20BB7 is \uD83D\uDDFA in UTF-16.
const UChar kLeadSurrogate = 0xD842;
const UChar kTrailSurrogate = 0xDFB7;
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kTrailSurrogate));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kLeadSurrogate));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Edge cases
// Unpaired trailing surrogate. Delete only broken trail surrogate.
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kTrailSurrogate));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kTrailSurrogate));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kTrailSurrogate));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kTrailSurrogate));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Unpaired leading surrogate. Delete only broken lead surrogate.
machine.Reset();
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kLeadSurrogate));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, CRLF) {
BackspaceStateMachine machine;
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('\r'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit('\n'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit('\n'));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(' '));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// CR LF should be deleted at the same time.
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit('\n'));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('\r'));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, KeyCap) {
BackspaceStateMachine machine;
const UChar kKeycap = 0x20E3;
const UChar kVs16 = 0xFE0F;
const UChar kNotKeycapBaseLead = 0xD83C;
const UChar kNotKeycapBaseTrail = 0xDCCF;
// keycapBase + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('0'));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// keycapBase + VS + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('0'));
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
// Followings are edge cases. Remove only keycap character.
// Not keycapBase + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Not keycapBase + VS + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Not keycapBase(surrogate pair) + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotKeycapBaseTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kNotKeycapBaseLead));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Not keycapBase(surrogate pair) + VS + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotKeycapBaseTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kNotKeycapBaseLead));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Sot + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Sot + VS + keycap
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKeycap));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, EmojiModifier) {
BackspaceStateMachine machine;
const UChar kEmojiModifierLead = 0xD83C;
const UChar kEmojiModifierTrail = 0xDFFB;
const UChar kEmojiModifierBase = 0x261D;
const UChar kEmojiModifierBaseLead = 0xD83D;
const UChar kEmojiModifierBaseTrail = 0xDC66;
const UChar kNotEmojiModifierBaseLead = 0xD83C;
const UChar kNotEmojiModifierBaseTrail = 0xDCCF;
const UChar kVs16 = 0xFE0F;
// EMOJI_MODIFIER_BASE + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kEmojiModifierBase));
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
// EMOJI_MODIFIER_BASE(surrogate pairs) + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierBaseTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kEmojiModifierBaseLead));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// EMOJI_MODIFIER_BASE + VS + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kEmojiModifierBase));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// EMOJI_MODIFIER_BASE(surrogate pairs) + VS + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierBaseTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kEmojiModifierBaseLead));
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
// Followings are edge cases. Remove only emoji modifier.
// Not EMOJI_MODIFIER_BASE + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not EMOJI_MODIFIER_BASE(surrogate pairs) + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotEmojiModifierBaseTrail));
EXPECT_EQ(kFinished,
machine.FeedPrecedingCodeUnit(kNotEmojiModifierBaseLead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not EMOJI_MODIFIER_BASE + VS + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not EMOJI_MODIFIER_BASE(surrogate pairs) + VS + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotEmojiModifierBaseTrail));
EXPECT_EQ(kFinished,
machine.FeedPrecedingCodeUnit(kNotEmojiModifierBaseLead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Sot + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Sot + VS + EMOJI_MODIFIER
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, RegionalIndicator) {
BackspaceStateMachine machine;
const UChar kRegionalIndicatorULead = 0xD83C;
const UChar kRegionalIndicatorUTrail = 0xDDFA;
const UChar kRegionalIndicatorSLead = 0xD83C;
const UChar kRegionalIndicatorSTrail = 0xDDF8;
const UChar kNotRegionalIndicatorLead = 0xD83C;
const UChar kNotRegionalIndicatorTrail = 0xDCCF;
// Not RI + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// Not RI(surrogate pairs) + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorTrail));
EXPECT_EQ(kFinished,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorLead));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// Sot + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// Not RI + RI + RI + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// Not RI(surrogate pairs) + RI + RI + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorTrail));
EXPECT_EQ(kFinished,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorLead));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// Sot + RI + RI + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// Followings are edge cases. Delete last regional indicator only.
// Not RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not RI(surrogate pairs) + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorTrail));
EXPECT_EQ(kFinished,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorLead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Sot + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not RI + RI + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit('a'));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not RI(surrogate pairs) + RI + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorTrail));
EXPECT_EQ(kFinished,
machine.FeedPrecedingCodeUnit(kNotRegionalIndicatorLead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Sot + RI + RI + RI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorSLead));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorUTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kRegionalIndicatorULead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, VariationSequencec) {
BackspaceStateMachine machine;
UChar vs01 = 0xFE00;
UChar vs01_base = 0xA85E;
UChar vs01_base_lead = 0xD802;
UChar vs01_base_trail = 0xDEC6;
UChar vs17_lead = 0xDB40;
UChar vs17_trail = 0xDD00;
UChar vs17_base = 0x3402;
UChar vs17_base_lead = 0xD841;
UChar vs17_base_trail = 0xDC8C;
UChar mongolian_vs = 0x180B;
UChar mongolian_vs_base = 0x1820;
// Variation selectors can't be a base of variation sequence.
UChar notvs_base = 0xFE00;
UChar notvs_base_lead = 0xDB40;
UChar notvs_base_trail = 0xDD01;
// VS_BASE + VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs01));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(vs01_base));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// VS_BASE + VS(surrogate pairs)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_trail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_lead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(vs17_base));
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
// VS_BASE(surrogate pairs) + VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs01));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs01_base_trail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(vs01_base_lead));
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-3, machine.FinalizeAndGetBoundaryOffset());
// VS_BASE(surrogate pairs) + VS(surrogate pairs)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_trail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_lead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_base_trail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(vs17_base_lead));
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-4, machine.FinalizeAndGetBoundaryOffset());
// mongolianVsBase + mongolianVs
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(mongolian_vs));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(mongolian_vs_base));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Followings are edge case. Delete only variation selector.
// Not VS_BASE + VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs01));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(notvs_base));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Not VS_BASE + VS(surrogate pairs)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_trail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_lead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(notvs_base));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not VS_BASE(surrogate pairs) + VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs01));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(notvs_base_trail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(notvs_base_lead));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Not VS_BASE(surrogate pairs) + VS(surrogate pairs)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_trail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_lead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(notvs_base_trail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(notvs_base_lead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Not VS_BASE + MONGOLIAN_VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(mongolian_vs));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(notvs_base));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Not VS_BASE(surrogate pairs) + MONGOLIAN_VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(mongolian_vs));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(notvs_base_trail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(notvs_base_lead));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Sot + VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs01));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Sot + VS(surrogate pair)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_trail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(vs17_lead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Sot + MONGOLIAN_VS
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(mongolian_vs));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
}
TEST(BackspaceStateMachineTest, ZWJSequence) {
BackspaceStateMachine machine;
const UChar kZwj = 0x200D;
const UChar kEyeLead = 0xD83D;
const UChar kEyeTrail = 0xDC41;
const UChar kLeftSpeachBubbleLead = 0xD83D;
const UChar kLeftSpeachBubbleTrail = 0xDDE8;
const UChar kManLead = 0xD83D;
const UChar kManTrail = 0xDC68;
const UChar kBoyLead = 0xD83D;
const UChar kBoyTrail = 0xDC66;
const UChar kHeart = 0x2764;
const UChar kKissLead = 0xD83D;
const UChar kKillTrail = 0xDC8B;
const UChar kVs16 = 0xFE0F;
const UChar kOther = 'a';
const UChar kOtherLead = 0xD83C;
const UChar kOtherTrail = 0xDCCF;
// Followings are chosen from valid zwj sequcne.
// See http://www.unicode.org/Public/emoji/2.0//emoji-zwj-sequences.txt
// others + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use EYE + ZWJ + LEFT_SPEACH_BUBBLE
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kLeftSpeachBubbleTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kLeftSpeachBubbleLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kEyeTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kEyeLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOther));
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
// others(surrogate pairs) + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use EYE + ZWJ + LEFT_SPEACH_BUBBLE
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kLeftSpeachBubbleTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kLeftSpeachBubbleLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kEyeTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kEyeLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kOtherTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOtherLead));
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
// Sot + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use EYE + ZWJ + LEFT_SPEACH_BUBBLE
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kLeftSpeachBubbleTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kLeftSpeachBubbleLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kEyeTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kEyeLead));
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-5, machine.FinalizeAndGetBoundaryOffset());
// others + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOther));
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
// others(surrogate pairs) + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kOtherTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOtherLead));
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
// Sot + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
// others + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + VS + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + vs16 + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOther));
EXPECT_EQ(-8, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-8, machine.FinalizeAndGetBoundaryOffset());
// others(surrogate pairs) + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + VS + ZWJ +
// ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + vs16 + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kOtherTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOtherLead));
EXPECT_EQ(-8, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-8, machine.FinalizeAndGetBoundaryOffset());
// Sot + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + VS + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + vs16 + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(-8, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-8, machine.FinalizeAndGetBoundaryOffset());
// others + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + MAN + ZWJ + boy + ZWJ + BOY
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOther));
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
// others(surrogate pairs) + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI +
// ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + MAN + ZWJ + boy + ZWJ + BOY
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kOtherTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOtherLead));
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
// Sot + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + MAN + ZWJ + boy + ZWJ + BOY
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBoyLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
// others + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + VS + ZWJ + ZWJ_EMOJI + ZWJ +
// ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + VS + ZWJ + KISS + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKillTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKissLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOther));
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
// others(surrogate pairs) + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + VS + ZWJ +
// ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + VS + ZWJ + KISS + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKillTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKissLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kOtherTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOtherLead));
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
// Sot + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI + VS + ZWJ + ZWJ_EMOJI + ZWJ + ZWJ_EMOJI
// As an example, use MAN + ZWJ + heart + VS + ZWJ + KISS + ZWJ + MAN
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKillTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kKissLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kVs16));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-11, machine.FinalizeAndGetBoundaryOffset());
// Sot + EMOJI_MODIFIER_BASE + EMOJI_MODIFIER + ZWJ + ZWJ_EMOJI
// As an example, use WOMAN + MODIFIER + ZWJ + BRIEFCASE
const UChar kWomanLead = 0xD83D;
const UChar kWomanTrail = 0xDC69;
const UChar kEmojiModifierLead = 0xD83C;
const UChar kEmojiModifierTrail = 0xDFFB;
const UChar kBriefcaseLead = 0xD83D;
const UChar kBriefcaseTrail = 0xDCBC;
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBriefcaseTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kBriefcaseLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierTrail));
EXPECT_EQ(kNeedMoreCodeUnit,
machine.FeedPrecedingCodeUnit(kEmojiModifierLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kWomanTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kWomanLead));
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-7, machine.FinalizeAndGetBoundaryOffset());
// Followings are not edge cases but good to check.
// If leading character is not zwj, delete only ZWJ_EMOJI.
// other + ZWJ_EMOJI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOther));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// other(surrogate pairs) + ZWJ_EMOJI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kOtherTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOtherLead));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// Sot + ZWJ_EMOJI
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kHeart));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
// other + ZWJ_EMOJI(surrogate pairs)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOther));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// other(surrogate pairs) + ZWJ_EMOJI(surrogate pairs)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kOtherTrail));
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kOtherLead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Sot + ZWJ_EMOJI(surrogate pairs)
machine.Reset();
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManTrail));
EXPECT_EQ(kNeedMoreCodeUnit, machine.FeedPrecedingCodeUnit(kManLead));
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
EXPECT_EQ(-2, machine.FinalizeAndGetBoundaryOffset());
// Followings are edge case.
// It is hard to list all edge case patterns. Check only over deleting by ZWJ.
// any + ZWJ: should delete only last ZWJ.
machine.Reset();
EXPECT_EQ(kFinished, machine.FeedPrecedingCodeUnit(kZwj));
EXPECT_EQ(-1, machine.FinalizeAndGetBoundaryOffset());
}
} // namespace backspace_state_machine_test
} // namespace blink