// 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 "views/ime/character_composer.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/gtk+/gdk/gdkkeysyms.h" #include "ui/base/gtk/gtk_integers.h" namespace views { 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 = >k_compose_seqs_compact[index]; const uint16* sequence_prev = sequence - stride; EXPECT_EQ(compare_sequence(sequence, sequence_prev, length), 1); } } } } } // namespace views