summaryrefslogtreecommitdiffstats
path: root/ui/base/ime/character_composer_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ui/base/ime/character_composer_unittest.cc')
-rw-r--r--ui/base/ime/character_composer_unittest.cc196
1 files changed, 196 insertions, 0 deletions
diff --git a/ui/base/ime/character_composer_unittest.cc b/ui/base/ime/character_composer_unittest.cc
new file mode 100644
index 0000000..14eea8f
--- /dev/null
+++ b/ui/base/ime/character_composer_unittest.cc
@@ -0,0 +1,196 @@
+// Copyright (c) 2011 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 "ui/base/ime/character_composer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/gtk+/gdk/gdkkeysyms.h"
+#include "ui/base/glib/glib_integers.h"
+
+namespace ui {
+
+namespace {
+
+// Expects key is not filtered and no character is composed.
+void ExpectKeyNotFiltered(CharacterComposer* character_composer, uint key) {
+ EXPECT_FALSE(character_composer->FilterKeyPress(key));
+ EXPECT_TRUE(character_composer->composed_character().empty());
+}
+
+// Expects key is filtered and no character is composed.
+void ExpectKeyFiltered(CharacterComposer* character_composer, uint key) {
+ EXPECT_TRUE(character_composer->FilterKeyPress(key));
+ EXPECT_TRUE(character_composer->composed_character().empty());
+}
+
+// Expects |expected_character| is composed after sequence [key1, key2].
+void ExpectCharacterComposed(CharacterComposer* character_composer,
+ uint key1,
+ uint key2,
+ const string16& expected_character) {
+ ExpectKeyFiltered(character_composer, key1);
+ EXPECT_TRUE(character_composer->FilterKeyPress(key2));
+ EXPECT_EQ(character_composer->composed_character(), expected_character);
+}
+
+// Expects |expected_character| is composed after sequence [key1, key2, key3].
+void ExpectCharacterComposed(CharacterComposer* character_composer,
+ uint key1,
+ uint key2,
+ uint key3,
+ const string16& expected_character) {
+ ExpectKeyFiltered(character_composer, key1);
+ ExpectCharacterComposed(character_composer, key2, key3, expected_character);
+}
+
+// Expects |expected_character| is composed after sequence [key1, key2, key3,
+// key 4].
+void ExpectCharacterComposed(CharacterComposer* character_composer,
+ uint key1,
+ uint key2,
+ uint key3,
+ uint key4,
+ const string16& expected_character) {
+ ExpectKeyFiltered(character_composer, key1);
+ ExpectCharacterComposed(character_composer, key2, key3, key4,
+ expected_character);
+}
+
+} // namespace
+
+TEST(CharacterComposerTest, InitialState) {
+ CharacterComposer character_composer;
+ EXPECT_TRUE(character_composer.composed_character().empty());
+}
+
+TEST(CharacterComposerTest, NormalKeyIsNotFiltered) {
+ CharacterComposer character_composer;
+ ExpectKeyNotFiltered(&character_composer, GDK_KEY_B);
+ ExpectKeyNotFiltered(&character_composer, GDK_KEY_Z);
+ ExpectKeyNotFiltered(&character_composer, GDK_KEY_c);
+ ExpectKeyNotFiltered(&character_composer, GDK_KEY_m);
+ ExpectKeyNotFiltered(&character_composer, GDK_KEY_0);
+ ExpectKeyNotFiltered(&character_composer, GDK_KEY_1);
+ ExpectKeyNotFiltered(&character_composer, GDK_KEY_8);
+}
+
+TEST(CharacterComposerTest, PartiallyMatchingSequence) {
+ CharacterComposer character_composer;
+
+ // Composition with sequence ['dead acute', '1'] will fail.
+ ExpectKeyFiltered(&character_composer, GDK_KEY_dead_acute);
+ EXPECT_TRUE(character_composer.FilterKeyPress(GDK_KEY_1));
+ EXPECT_TRUE(character_composer.composed_character().empty());
+
+ // Composition with sequence ['dead acute', 'dead circumflex', '1'] will fail.
+ ExpectKeyFiltered(&character_composer, GDK_KEY_dead_acute);
+ ExpectKeyFiltered(&character_composer, GDK_KEY_dead_circumflex);
+ EXPECT_TRUE(character_composer.FilterKeyPress(GDK_KEY_1));
+ EXPECT_TRUE(character_composer.composed_character().empty());
+}
+
+TEST(CharacterComposerTest, FullyMatchingSequences) {
+ CharacterComposer character_composer;
+ // LATIN SMALL LETTER A WITH ACUTE
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_a,
+ string16(1, 0x00E1));
+ // LATIN CAPITAL LETTER A WITH ACUTE
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_A,
+ string16(1, 0x00C1));
+ // GRAVE ACCENT
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_grave,
+ GDK_KEY_dead_grave, string16(1, 0x0060));
+ // LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute,
+ GDK_KEY_dead_circumflex, GDK_KEY_a,
+ string16(1, 0x1EA5));
+ // LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_grave,
+ GDK_KEY_dead_horn, GDK_KEY_U, string16(1, 0x1EEA));
+ // LATIN CAPITAL LETTER C WITH CEDILLA
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_C,
+ string16(1, 0x00C7));
+ // LATIN SMALL LETTER C WITH CEDILLA
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_c,
+ string16(1, 0x00E7));
+}
+
+TEST(CharacterComposerTest, FullyMatchingSequencesAfterMatchingFailure) {
+ CharacterComposer character_composer;
+ // Composition with sequence ['dead acute', 'dead circumflex', '1'] will fail.
+ ExpectKeyFiltered(&character_composer, GDK_KEY_dead_acute);
+ ExpectKeyFiltered(&character_composer, GDK_KEY_dead_circumflex);
+ EXPECT_TRUE(character_composer.FilterKeyPress(GDK_KEY_1));
+ EXPECT_TRUE(character_composer.composed_character().empty());
+ // LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute,
+ GDK_KEY_dead_circumflex, GDK_KEY_a,
+ string16(1, 0x1EA5));
+}
+
+TEST(CharacterComposerTest, ComposedCharacterIsClearedAfterReset) {
+ CharacterComposer character_composer;
+ ExpectCharacterComposed(&character_composer, GDK_KEY_dead_acute, GDK_KEY_a,
+ string16(1, 0x00E1));
+ character_composer.Reset();
+ EXPECT_TRUE(character_composer.composed_character().empty());
+}
+
+TEST(CharacterComposerTest, CompositionStateIsClearedAfterReset) {
+ CharacterComposer character_composer;
+ // Even though sequence ['dead acute', 'a'] will compose 'a with acute',
+ // no character is composed here because of reset.
+ ExpectKeyFiltered(&character_composer, GDK_KEY_dead_acute);
+ character_composer.Reset();
+ EXPECT_FALSE(character_composer.FilterKeyPress(GDK_KEY_a));
+ EXPECT_TRUE(character_composer.composed_character().empty());
+}
+
+// ComposeCheckerWithCompactTable in character_composer.cc is depending on the
+// assumption that the data in gtkimcontextsimpleseqs.h is correctly ordered.
+TEST(CharacterComposerTest, MainTableIsCorrectlyOrdered) {
+ // This file is included here intentionally, instead of the top of the file,
+ // because including this file at the top of the file will define a
+ // global constant and contaminate the global namespace.
+#include "third_party/gtk+/gtk/gtkimcontextsimpleseqs.h"
+ const int index_size = 26;
+ const int index_stride = 6;
+
+ // Verify that the index is correctly ordered
+ for (int i = 1; i < index_size; ++i) {
+ const int index_key_prev = gtk_compose_seqs_compact[(i - 1)*index_stride];
+ const int index_key = gtk_compose_seqs_compact[i*index_stride];
+ EXPECT_TRUE(index_key > index_key_prev);
+ }
+
+ // Verify that the sequenes are correctly ordered
+ struct {
+ int operator()(const uint16* l, const uint16* r, int length) const{
+ for (int i = 0; i < length; ++i) {
+ if (l[i] > r[i])
+ return 1;
+ if (l[i] < r[i])
+ return -1;
+ }
+ return 0;
+ }
+ } compare_sequence;
+
+ for (int i = 0; i < index_size; ++i) {
+ for (int length = 1; length < index_stride - 1; ++length) {
+ const int index_begin = gtk_compose_seqs_compact[i*index_stride + length];
+ const int index_end =
+ gtk_compose_seqs_compact[i*index_stride + length + 1];
+ const int stride = length + 1;
+ for (int index = index_begin + stride; index < index_end;
+ index += stride) {
+ const uint16* sequence = &gtk_compose_seqs_compact[index];
+ const uint16* sequence_prev = sequence - stride;
+ EXPECT_EQ(compare_sequence(sequence, sequence_prev, length), 1);
+ }
+ }
+ }
+}
+
+} // namespace ui