1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6#include <utility>
7
8#include "base/basictypes.h"
9#include "base/logging.h"
10#include "testing/gtest/include/gtest/gtest.h"
11#include "ui/base/gtk/gtk_im_context_util.h"
12#include "ui/base/ime/composition_text.h"
13
14namespace {
15
16struct AttributeInfo {
17  int type;
18  int value;
19  int start_offset;
20  int end_offset;
21};
22
23struct Underline {
24  unsigned start_offset;
25  unsigned end_offset;
26  uint32 color;
27  bool thick;
28};
29
30struct TestData {
31  const char* text;
32  const AttributeInfo attrs[10];
33  const Underline underlines[10];
34};
35
36const TestData kTestData[] = {
37  // Normal case
38  { "One Two Three",
39    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
40      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_DOUBLE, 4, 7 },
41      { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
42      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13 },
43      { 0, 0, 0, 0 } },
44    { { 0, 3, SK_ColorBLACK, false },
45      { 4, 7, SK_ColorBLACK, true },
46      { 8, 13, SK_ColorBLACK, false },
47      { 0, 0, 0, false } }
48  },
49
50  // Offset overflow.
51  { "One Two Three",
52    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
53      { PANGO_ATTR_BACKGROUND, 0, 4, 7 },
54      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 20 },
55      { 0, 0, 0, 0 } },
56    { { 0, 3, SK_ColorBLACK, false },
57      { 4, 7, SK_ColorBLACK, true },
58      { 8, 13, SK_ColorBLACK, false },
59      { 0, 0, 0, false} }
60  },
61
62  // Error underline.
63  { "One Two Three",
64    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
65      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_ERROR, 4, 7 },
66      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 8, 13 },
67      { 0, 0, 0, 0 } },
68    { { 0, 3, SK_ColorBLACK, false },
69      { 4, 7, SK_ColorRED, false },
70      { 8, 13, SK_ColorBLACK, false },
71      { 0, 0, 0, false} }
72  },
73
74  // Default underline.
75  { "One Two Three",
76    { { 0, 0, 0, 0 } },
77    { { 0, 13, SK_ColorBLACK, false },
78      { 0, 0, 0, false } }
79  },
80
81  // Unicode, including non-BMP characters: "123你好����一丁 456"
82  { "123\xE4\xBD\xA0\xE5\xA5\xBD\xF0\xA0\x80\x80\xF0\xA0\x80\x81\xE4\xB8\x80"
83    "\xE4\xB8\x81 456",
84    { { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 0, 3 },
85      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 3, 5 },
86      { PANGO_ATTR_BACKGROUND, 0, 5, 7 },
87      { PANGO_ATTR_UNDERLINE, PANGO_UNDERLINE_SINGLE, 7, 13 },
88      { 0, 0, 0, 0 } },
89    { { 0, 3, SK_ColorBLACK, false },
90      { 3, 5, SK_ColorBLACK, false },
91      { 5, 9, SK_ColorBLACK, true },
92      { 9, 15, SK_ColorBLACK, false },
93      { 0, 0, 0, false } }
94  },
95};
96
97void CompareUnderline(const Underline& a,
98                      const ui::CompositionUnderline& b) {
99  EXPECT_EQ(a.start_offset, b.start_offset);
100  EXPECT_EQ(a.end_offset, b.end_offset);
101  EXPECT_EQ(a.color, b.color);
102  EXPECT_EQ(a.thick, b.thick);
103}
104
105class GtkIMContextWrapperTest : public testing::Test {
106};
107
108TEST(GtkIMContextUtilTest, ExtractCompositionText) {
109  for (size_t i = 0; i < arraysize(kTestData); ++i) {
110    const char* text = kTestData[i].text;
111    const AttributeInfo* attrs = kTestData[i].attrs;
112    SCOPED_TRACE(testing::Message() << "Testing:" << i
113                 << " text:" << text);
114
115    PangoAttrList* pango_attrs = pango_attr_list_new();
116    for (size_t a = 0; attrs[a].type; ++a) {
117      PangoAttribute* pango_attr = NULL;
118      switch (attrs[a].type) {
119        case PANGO_ATTR_UNDERLINE:
120          pango_attr = pango_attr_underline_new(
121              static_cast<PangoUnderline>(attrs[a].value));
122          break;
123        case PANGO_ATTR_BACKGROUND:
124          pango_attr = pango_attr_background_new(0, 0, 0);
125          break;
126        default:
127          NOTREACHED();
128      }
129      pango_attr->start_index =
130          g_utf8_offset_to_pointer(text, attrs[a].start_offset) - text;
131      pango_attr->end_index =
132          g_utf8_offset_to_pointer(text, attrs[a].end_offset) - text;
133      pango_attr_list_insert(pango_attrs, pango_attr);
134    }
135
136    ui::CompositionText result;
137    ui::ExtractCompositionTextFromGtkPreedit(text, pango_attrs, 0, &result);
138
139    const Underline* underlines = kTestData[i].underlines;
140    for (size_t u = 0; underlines[u].color &&
141         u < result.underlines.size(); ++u) {
142      SCOPED_TRACE(testing::Message() << "Underline:" << u);
143      CompareUnderline(underlines[u], result.underlines[u]);
144    }
145
146    pango_attr_list_unref(pango_attrs);
147  }
148}
149
150}  // namespace
151