blob: 5e09719282dd1a241b4749e1190c500f20bc0b8b [file] [log] [blame]
// 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 = &gtk_compose_seqs_compact[index];
const uint16* sequence_prev = sequence - stride;
EXPECT_EQ(compare_sequence(sequence, sequence_prev, length), 1);
}
}
}
}
} // namespace views