Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk_unittest.cc

Issue 231733005: Delete the GTK+ port of Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remerge to ToT Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h"
6
7 #include <gtk/gtk.h>
8
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/autocomplete/autocomplete_match.h"
13 #include "chrome/browser/autocomplete/autocomplete_result.h"
14 #include "components/variations/entropy_provider.h"
15 #include "testing/platform_test.h"
16 #include "ui/base/gtk/gtk_hig_constants.h"
17 #include "ui/gfx/font.h"
18 #include "ui/gfx/rect.h"
19
20 namespace {
21
22 const GdkColor kContentTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00);
23 const GdkColor kDimContentTextColor = GDK_COLOR_RGB(0x80, 0x80, 0x80);
24 const GdkColor kURLTextColor = GDK_COLOR_RGB(0x00, 0x88, 0x00);
25
26 class TestableOmniboxPopupViewGtk : public OmniboxPopupViewGtk {
27 public:
28 TestableOmniboxPopupViewGtk()
29 : OmniboxPopupViewGtk(gfx::Font(), NULL, NULL, NULL),
30 show_called_(false),
31 hide_called_(false) {
32 }
33
34 virtual ~TestableOmniboxPopupViewGtk() {
35 }
36
37 virtual void Show(size_t num_results) OVERRIDE {
38 show_called_ = true;
39 }
40
41 virtual void Hide() OVERRIDE {
42 hide_called_ = true;
43 }
44
45 virtual const AutocompleteResult& GetResult() const OVERRIDE {
46 return result_;
47 }
48
49 using OmniboxPopupViewGtk::GetRectForLine;
50 using OmniboxPopupViewGtk::LineFromY;
51 using OmniboxPopupViewGtk::GetHiddenMatchCount;
52
53 AutocompleteResult result_;
54 bool show_called_;
55 bool hide_called_;
56 };
57
58 } // namespace
59
60 class OmniboxPopupViewGtkTest : public PlatformTest {
61 public:
62 OmniboxPopupViewGtkTest() {}
63
64 virtual void SetUp() {
65 PlatformTest::SetUp();
66
67 window_ = gtk_window_new(GTK_WINDOW_POPUP);
68 layout_ = gtk_widget_create_pango_layout(window_, NULL);
69 view_.reset(new TestableOmniboxPopupViewGtk);
70 field_trial_list_.reset(new base::FieldTrialList(
71 new metrics::SHA1EntropyProvider("42")));
72 }
73
74 virtual void TearDown() {
75 g_object_unref(layout_);
76 gtk_widget_destroy(window_);
77
78 PlatformTest::TearDown();
79 }
80
81 // The google C++ Testing Framework documentation suggests making
82 // accessors in the fixture so that each test doesn't need to be a
83 // friend of the class being tested. This method just proxies the
84 // call through after adding the fixture's layout_.
85 void SetupLayoutForMatch(
86 const base::string16& text,
87 const AutocompleteMatch::ACMatchClassifications& classifications,
88 const GdkColor* base_color,
89 const GdkColor* dim_color,
90 const GdkColor* url_color,
91 const std::string& prefix_text) {
92 OmniboxPopupViewGtk::SetupLayoutForMatch(layout_,
93 text,
94 classifications,
95 base_color,
96 dim_color,
97 url_color,
98 prefix_text);
99 }
100
101 struct RunInfo {
102 PangoAttribute* attr_;
103 guint length_;
104 RunInfo() : attr_(NULL), length_(0) { }
105 };
106
107 RunInfo RunInfoForAttrType(guint location,
108 guint end_location,
109 PangoAttrType type) {
110 RunInfo retval;
111
112 PangoAttrList* attrs = pango_layout_get_attributes(layout_);
113 if (!attrs)
114 return retval;
115
116 PangoAttrIterator* attr_iter = pango_attr_list_get_iterator(attrs);
117 if (!attr_iter)
118 return retval;
119
120 for (gboolean more = true, findNextStart = false;
121 more;
122 more = pango_attr_iterator_next(attr_iter)) {
123 PangoAttribute* attr = pango_attr_iterator_get(attr_iter, type);
124
125 // This iterator segment doesn't have any elements of the
126 // desired type; keep looking.
127 if (!attr)
128 continue;
129
130 // Skip attribute ranges before the desired start point.
131 if (attr->end_index <= location)
132 continue;
133
134 // If the matching type went past the iterator segment, then set
135 // the length to the next start - location.
136 if (findNextStart) {
137 // If the start is still less than the location, then reset
138 // the match. Otherwise, check that the new attribute is, in
139 // fact different before shortening the run length.
140 if (attr->start_index <= location) {
141 findNextStart = false;
142 } else if (!pango_attribute_equal(retval.attr_, attr)) {
143 retval.length_ = attr->start_index - location;
144 break;
145 }
146 }
147
148 gint start_range, end_range;
149 pango_attr_iterator_range(attr_iter,
150 &start_range,
151 &end_range);
152
153 // Now we have a match. May need to keep going to shorten
154 // length if we reach a new item of the same type.
155 retval.attr_ = attr;
156 if (attr->end_index > (guint)end_range) {
157 retval.length_ = end_location - location;
158 findNextStart = true;
159 } else {
160 retval.length_ = attr->end_index - location;
161 break;
162 }
163 }
164
165 pango_attr_iterator_destroy(attr_iter);
166 return retval;
167 }
168
169 guint RunLengthForAttrType(guint location,
170 guint end_location,
171 PangoAttrType type) {
172 RunInfo info = RunInfoForAttrType(location,
173 end_location,
174 type);
175 return info.length_;
176 }
177
178 gboolean RunHasAttribute(guint location,
179 guint end_location,
180 PangoAttribute* attribute) {
181 RunInfo info = RunInfoForAttrType(location,
182 end_location,
183 attribute->klass->type);
184
185 return info.attr_ && pango_attribute_equal(info.attr_, attribute);
186 }
187
188 gboolean RunHasColor(guint location,
189 guint end_location,
190 const GdkColor& color) {
191 PangoAttribute* attribute =
192 pango_attr_foreground_new(color.red,
193 color.green,
194 color.blue);
195
196 gboolean retval = RunHasAttribute(location,
197 end_location,
198 attribute);
199
200 pango_attribute_destroy(attribute);
201
202 return retval;
203 }
204
205 gboolean RunHasWeight(guint location,
206 guint end_location,
207 PangoWeight weight) {
208 PangoAttribute* attribute = pango_attr_weight_new(weight);
209
210 gboolean retval = RunHasAttribute(location,
211 end_location,
212 attribute);
213
214 pango_attribute_destroy(attribute);
215
216 return retval;
217 }
218
219 GtkWidget* window_;
220 PangoLayout* layout_;
221
222 scoped_ptr<TestableOmniboxPopupViewGtk> view_;
223 scoped_ptr<base::FieldTrialList> field_trial_list_;
224
225 private:
226 DISALLOW_COPY_AND_ASSIGN(OmniboxPopupViewGtkTest);
227 };
228
229 // Simple inputs with no matches should result in styled output who's
230 // text matches the input string, with the passed-in color, and
231 // nothing bolded.
232 TEST_F(OmniboxPopupViewGtkTest, DecorateMatchedStringNoMatch) {
233 const base::string16 kContents = base::ASCIIToUTF16("This is a test");
234
235 AutocompleteMatch::ACMatchClassifications classifications;
236
237 SetupLayoutForMatch(kContents,
238 classifications,
239 &kContentTextColor,
240 &kDimContentTextColor,
241 &kURLTextColor,
242 std::string());
243
244 EXPECT_EQ(kContents.length(), RunLengthForAttrType(0U, kContents.length(),
245 PANGO_ATTR_FOREGROUND));
246
247 EXPECT_TRUE(RunHasColor(0U, kContents.length(), kContentTextColor));
248
249 // This part's a little wacky - either we don't have a weight, or
250 // the weight run is the entire string and is NORMAL
251 guint weightLength = RunLengthForAttrType(0U, kContents.length(),
252 PANGO_ATTR_WEIGHT);
253 if (weightLength) {
254 EXPECT_EQ(kContents.length(), weightLength);
255 EXPECT_TRUE(RunHasWeight(0U, kContents.length(), PANGO_WEIGHT_NORMAL));
256 }
257 }
258
259 // Identical to DecorateMatchedStringNoMatch, except test that URL
260 // style gets a different color than we passed in.
261 TEST_F(OmniboxPopupViewGtkTest, DecorateMatchedStringURLNoMatch) {
262 const base::string16 kContents = base::ASCIIToUTF16("This is a test");
263 AutocompleteMatch::ACMatchClassifications classifications;
264
265 classifications.push_back(
266 ACMatchClassification(0U, ACMatchClassification::URL));
267
268 SetupLayoutForMatch(kContents,
269 classifications,
270 &kContentTextColor,
271 &kDimContentTextColor,
272 &kURLTextColor,
273 std::string());
274
275 EXPECT_EQ(kContents.length(), RunLengthForAttrType(0U, kContents.length(),
276 PANGO_ATTR_FOREGROUND));
277 EXPECT_TRUE(RunHasColor(0U, kContents.length(), kURLTextColor));
278
279 // This part's a little wacky - either we don't have a weight, or
280 // the weight run is the entire string and is NORMAL
281 guint weightLength = RunLengthForAttrType(0U, kContents.length(),
282 PANGO_ATTR_WEIGHT);
283 if (weightLength) {
284 EXPECT_EQ(kContents.length(), weightLength);
285 EXPECT_TRUE(RunHasWeight(0U, kContents.length(), PANGO_WEIGHT_NORMAL));
286 }
287 }
288
289 // Test that DIM works as expected.
290 TEST_F(OmniboxPopupViewGtkTest, DecorateMatchedStringDimNoMatch) {
291 const base::string16 kContents = base::ASCIIToUTF16("This is a test");
292 // Dim "is".
293 const guint kRunLength1 = 5, kRunLength2 = 2, kRunLength3 = 7;
294 // Make sure nobody messed up the inputs.
295 EXPECT_EQ(kRunLength1 + kRunLength2 + kRunLength3, kContents.length());
296
297 // Push each run onto classifications.
298 AutocompleteMatch::ACMatchClassifications classifications;
299 classifications.push_back(
300 ACMatchClassification(0U, ACMatchClassification::NONE));
301 classifications.push_back(
302 ACMatchClassification(kRunLength1, ACMatchClassification::DIM));
303 classifications.push_back(
304 ACMatchClassification(kRunLength1 + kRunLength2,
305 ACMatchClassification::NONE));
306
307 SetupLayoutForMatch(kContents,
308 classifications,
309 &kContentTextColor,
310 &kDimContentTextColor,
311 &kURLTextColor,
312 std::string());
313
314 // Check the runs have expected color and length.
315 EXPECT_EQ(kRunLength1, RunLengthForAttrType(0U, kContents.length(),
316 PANGO_ATTR_FOREGROUND));
317 EXPECT_TRUE(RunHasColor(0U, kContents.length(), kContentTextColor));
318 EXPECT_EQ(kRunLength2, RunLengthForAttrType(kRunLength1, kContents.length(),
319 PANGO_ATTR_FOREGROUND));
320 EXPECT_TRUE(RunHasColor(kRunLength1, kContents.length(),
321 kDimContentTextColor));
322 EXPECT_EQ(kRunLength3, RunLengthForAttrType(kRunLength1 + kRunLength2,
323 kContents.length(),
324 PANGO_ATTR_FOREGROUND));
325 EXPECT_TRUE(RunHasColor(kRunLength1 + kRunLength2, kContents.length(),
326 kContentTextColor));
327
328 // This part's a little wacky - either we don't have a weight, or
329 // the weight run is the entire string and is NORMAL
330 guint weightLength = RunLengthForAttrType(0U, kContents.length(),
331 PANGO_ATTR_WEIGHT);
332 if (weightLength) {
333 EXPECT_EQ(kContents.length(), weightLength);
334 EXPECT_TRUE(RunHasWeight(0U, kContents.length(), PANGO_WEIGHT_NORMAL));
335 }
336 }
337
338 // Test that the matched run gets bold-faced, but keeps the same
339 // color.
340 TEST_F(OmniboxPopupViewGtkTest, DecorateMatchedStringMatch) {
341 const base::string16 kContents = base::ASCIIToUTF16("This is a test");
342 // Match "is".
343 const guint kRunLength1 = 5, kRunLength2 = 2, kRunLength3 = 7;
344 // Make sure nobody messed up the inputs.
345 EXPECT_EQ(kRunLength1 + kRunLength2 + kRunLength3, kContents.length());
346
347 // Push each run onto classifications.
348 AutocompleteMatch::ACMatchClassifications classifications;
349 classifications.push_back(
350 ACMatchClassification(0U, ACMatchClassification::NONE));
351 classifications.push_back(
352 ACMatchClassification(kRunLength1, ACMatchClassification::MATCH));
353 classifications.push_back(
354 ACMatchClassification(kRunLength1 + kRunLength2,
355 ACMatchClassification::NONE));
356
357 SetupLayoutForMatch(kContents,
358 classifications,
359 &kContentTextColor,
360 &kDimContentTextColor,
361 &kURLTextColor,
362 std::string());
363
364 // Check the runs have expected weight and length.
365 EXPECT_EQ(kRunLength1, RunLengthForAttrType(0U, kContents.length(),
366 PANGO_ATTR_WEIGHT));
367 EXPECT_TRUE(RunHasWeight(0U, kContents.length(), PANGO_WEIGHT_NORMAL));
368 EXPECT_EQ(kRunLength2, RunLengthForAttrType(kRunLength1, kContents.length(),
369 PANGO_ATTR_WEIGHT));
370 EXPECT_TRUE(RunHasWeight(kRunLength1, kContents.length(), PANGO_WEIGHT_BOLD));
371 EXPECT_EQ(kRunLength3, RunLengthForAttrType(kRunLength1 + kRunLength2,
372 kContents.length(),
373 PANGO_ATTR_WEIGHT));
374 EXPECT_TRUE(RunHasWeight(kRunLength1 + kRunLength2, kContents.length(),
375 PANGO_WEIGHT_NORMAL));
376
377 // The entire string should be the same, normal color.
378 EXPECT_EQ(kContents.length(), RunLengthForAttrType(0U, kContents.length(),
379 PANGO_ATTR_FOREGROUND));
380 EXPECT_TRUE(RunHasColor(0U, kContents.length(), kContentTextColor));
381 }
382
383 // Just like DecorateMatchedStringURLMatch, this time with URL style.
384 TEST_F(OmniboxPopupViewGtkTest, DecorateMatchedStringURLMatch) {
385 const base::string16 kContents = base::ASCIIToUTF16("http://hello.world/");
386 // Match "hello".
387 const guint kRunLength1 = 7, kRunLength2 = 5, kRunLength3 = 7;
388 // Make sure nobody messed up the inputs.
389 EXPECT_EQ(kRunLength1 + kRunLength2 + kRunLength3, kContents.length());
390
391 // Push each run onto classifications.
392 AutocompleteMatch::ACMatchClassifications classifications;
393 classifications.push_back(
394 ACMatchClassification(0U, ACMatchClassification::URL));
395 const int kURLMatch =
396 ACMatchClassification::URL | ACMatchClassification::MATCH;
397 classifications.push_back(
398 ACMatchClassification(kRunLength1, kURLMatch));
399 classifications.push_back(
400 ACMatchClassification(kRunLength1 + kRunLength2,
401 ACMatchClassification::URL));
402
403 SetupLayoutForMatch(kContents,
404 classifications,
405 &kContentTextColor,
406 &kDimContentTextColor,
407 &kURLTextColor,
408 std::string());
409
410 // One color for the entire string, and it's not the one we passed
411 // in.
412 EXPECT_EQ(kContents.length(), RunLengthForAttrType(0U, kContents.length(),
413 PANGO_ATTR_FOREGROUND));
414 EXPECT_TRUE(RunHasColor(0U, kContents.length(), kURLTextColor));
415 }
416
417 // Test that the popup is not shown if there is only one hidden match.
418 TEST_F(OmniboxPopupViewGtkTest, HidesIfOnlyOneHiddenMatch) {
419 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
420 "InstantExtended", "Group1 hide_verbatim:1"));
421 ACMatches matches;
422 AutocompleteMatch match;
423 match.destination_url = GURL("http://verbatim/");
424 match.type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED;
425 matches.push_back(match);
426 view_->result_.AppendMatches(matches);
427 ASSERT_TRUE(view_->result_.ShouldHideTopMatch());
428
429 // Since there is only one match which is hidden, the popup should close.
430 view_->UpdatePopupAppearance();
431 EXPECT_TRUE(view_->hide_called_);
432 }
433
434 // Test that the top match is skipped if the model indicates it should be
435 // hidden.
436 TEST_F(OmniboxPopupViewGtkTest, SkipsTopMatchIfHidden) {
437 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
438 "InstantExtended", "Group1 hide_verbatim:1"));
439 ACMatches matches;
440 {
441 AutocompleteMatch match;
442 match.destination_url = GURL("http://verbatim/");
443 match.type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED;
444 matches.push_back(match);
445 }
446 {
447 AutocompleteMatch match;
448 match.destination_url = GURL("http://not-verbatim/");
449 match.type = AutocompleteMatchType::SEARCH_OTHER_ENGINE;
450 matches.push_back(match);
451 }
452 view_->result_.AppendMatches(matches);
453 ASSERT_TRUE(view_->result_.ShouldHideTopMatch());
454
455 EXPECT_EQ(1U, view_->GetHiddenMatchCount());
456 EXPECT_EQ(1U, view_->LineFromY(0));
457 gfx::Rect rect = view_->GetRectForLine(1, 100);
458 EXPECT_EQ(1, rect.y());
459 }
460
461 // Test that the top match is not skipped if the model does not indicate it
462 // should be hidden.
463 TEST_F(OmniboxPopupViewGtkTest, DoesNotSkipTopMatchIfVisible) {
464 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
465 "InstantExtended", "Group1 hide_verbatim:1"));
466 ACMatches matches;
467 AutocompleteMatch match;
468 match.destination_url = GURL("http://not-verbatim/");
469 match.type = AutocompleteMatchType::SEARCH_OTHER_ENGINE;
470 matches.push_back(match);
471 view_->result_.AppendMatches(matches);
472 ASSERT_FALSE(view_->result_.ShouldHideTopMatch());
473
474 EXPECT_EQ(0U, view_->GetHiddenMatchCount());
475 EXPECT_EQ(0U, view_->LineFromY(0));
476 gfx::Rect rect = view_->GetRectForLine(1, 100);
477 EXPECT_EQ(25, rect.y());
478
479 // The single match is visible so the popup should be open.
480 view_->UpdatePopupAppearance();
481 EXPECT_TRUE(view_->show_called_);
482 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698