Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / themes / browser_theme_pack_unittest.cc
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/themes/browser_theme_pack.h"
6
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/json/json_reader.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/path_service.h"
12 #include "base/values.h"
13 #include "chrome/browser/themes/theme_properties.h"
14 #include "chrome/common/chrome_paths.h"
15 #include "content/public/test/test_browser_thread.h"
16 #include "grit/theme_resources.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "ui/gfx/color_utils.h"
19 #include "ui/gfx/image/image.h"
20 #include "ui/gfx/image/image_skia.h"
21 #include "ui/gfx/image/image_skia_rep.h"
22
23 using content::BrowserThread;
24 using extensions::Extension;
25
26 // Maps scale factors (enum values) to file path.
27 // A similar typedef in BrowserThemePack is private.
28 typedef std::map<ui::ScaleFactor, base::FilePath> TestScaleFactorToFileMap;
29
30 // Maps image ids to maps of scale factors to file paths.
31 // A similar typedef in BrowserThemePack is private.
32 typedef std::map<int, TestScaleFactorToFileMap> TestFilePathMap;
33
34 class BrowserThemePackTest : public ::testing::Test {
35  public:
36   BrowserThemePackTest()
37       : message_loop(),
38         fake_ui_thread(BrowserThread::UI, &message_loop),
39         fake_file_thread(BrowserThread::FILE, &message_loop) {
40     std::vector<ui::ScaleFactor> scale_factors;
41     scale_factors.push_back(ui::SCALE_FACTOR_100P);
42     scale_factors.push_back(ui::SCALE_FACTOR_200P);
43     scoped_set_supported_scale_factors_.reset(
44       new ui::test::ScopedSetSupportedScaleFactors(scale_factors));
45     theme_pack_ = new BrowserThemePack();
46   }
47
48   // Transformation for link underline colors.
49   SkColor BuildThirdOpacity(SkColor color_link) {
50     return SkColorSetA(color_link, SkColorGetA(color_link) / 3);
51   }
52
53   void GenerateDefaultFrameColor(std::map<int, SkColor>* colors,
54                                  int color, int tint) {
55     (*colors)[color] = HSLShift(
56         ThemeProperties::GetDefaultColor(
57             ThemeProperties::COLOR_FRAME),
58         ThemeProperties::GetDefaultTint(tint));
59   }
60
61   // Returns a mapping from each COLOR_* constant to the default value for this
62   // constant. Callers get this map, and then modify expected values and then
63   // run the resulting thing through VerifyColorMap().
64   std::map<int, SkColor> GetDefaultColorMap() {
65     std::map<int, SkColor> colors;
66     for (int i = ThemeProperties::COLOR_FRAME;
67          i <= ThemeProperties::COLOR_BUTTON_BACKGROUND; ++i) {
68       colors[i] = ThemeProperties::GetDefaultColor(i);
69     }
70
71     GenerateDefaultFrameColor(&colors, ThemeProperties::COLOR_FRAME,
72                               ThemeProperties::TINT_FRAME);
73     GenerateDefaultFrameColor(&colors,
74                               ThemeProperties::COLOR_FRAME_INACTIVE,
75                               ThemeProperties::TINT_FRAME_INACTIVE);
76     GenerateDefaultFrameColor(&colors,
77                               ThemeProperties::COLOR_FRAME_INCOGNITO,
78                               ThemeProperties::TINT_FRAME_INCOGNITO);
79     GenerateDefaultFrameColor(
80         &colors,
81         ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE,
82         ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE);
83
84     return colors;
85   }
86
87   void VerifyColorMap(const std::map<int, SkColor>& color_map) {
88     for (std::map<int, SkColor>::const_iterator it = color_map.begin();
89          it != color_map.end(); ++it) {
90       SkColor color = ThemeProperties::GetDefaultColor(it->first);
91       theme_pack_->GetColor(it->first, &color);
92       EXPECT_EQ(it->second, color) << "Color id = " << it->first;
93     }
94   }
95
96   void LoadColorJSON(const std::string& json) {
97     scoped_ptr<base::Value> value(base::JSONReader::Read(json));
98     ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY));
99     LoadColorDictionary(static_cast<base::DictionaryValue*>(value.get()));
100   }
101
102   void LoadColorDictionary(base::DictionaryValue* value) {
103     theme_pack_->BuildColorsFromJSON(value);
104   }
105
106   void LoadTintJSON(const std::string& json) {
107     scoped_ptr<base::Value> value(base::JSONReader::Read(json));
108     ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY));
109     LoadTintDictionary(static_cast<base::DictionaryValue*>(value.get()));
110   }
111
112   void LoadTintDictionary(base::DictionaryValue* value) {
113     theme_pack_->BuildTintsFromJSON(value);
114   }
115
116   void LoadDisplayPropertiesJSON(const std::string& json) {
117     scoped_ptr<base::Value> value(base::JSONReader::Read(json));
118     ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY));
119     LoadDisplayPropertiesDictionary(
120         static_cast<base::DictionaryValue*>(value.get()));
121   }
122
123   void LoadDisplayPropertiesDictionary(base::DictionaryValue* value) {
124     theme_pack_->BuildDisplayPropertiesFromJSON(value);
125   }
126
127   void ParseImageNamesJSON(const std::string& json,
128                            TestFilePathMap* out_file_paths) {
129     scoped_ptr<base::Value> value(base::JSONReader::Read(json));
130     ASSERT_TRUE(value->IsType(base::Value::TYPE_DICTIONARY));
131     ParseImageNamesDictionary(static_cast<base::DictionaryValue*>(value.get()),
132                               out_file_paths);
133   }
134
135   void ParseImageNamesDictionary(
136       base::DictionaryValue* value,
137       TestFilePathMap* out_file_paths) {
138     theme_pack_->ParseImageNamesFromJSON(value, base::FilePath(),
139                                          out_file_paths);
140
141     // Build the source image list for HasCustomImage().
142     theme_pack_->BuildSourceImagesArray(*out_file_paths);
143   }
144
145   bool LoadRawBitmapsTo(const TestFilePathMap& out_file_paths) {
146     return theme_pack_->LoadRawBitmapsTo(out_file_paths,
147                                          &theme_pack_->images_on_ui_thread_);
148   }
149
150   // This function returns void in order to be able use ASSERT_...
151   // The BrowserThemePack is returned in |pack|.
152   void BuildFromUnpackedExtension(const base::FilePath& extension_path,
153                                   scoped_refptr<BrowserThemePack>& pack) {
154     base::FilePath manifest_path =
155         extension_path.AppendASCII("manifest.json");
156     std::string error;
157     JSONFileValueSerializer serializer(manifest_path);
158     scoped_ptr<base::DictionaryValue> valid_value(
159         static_cast<base::DictionaryValue*>(
160             serializer.Deserialize(NULL, &error)));
161     EXPECT_EQ("", error);
162     ASSERT_TRUE(valid_value.get());
163     scoped_refptr<Extension> extension(
164         Extension::Create(
165             extension_path,
166             extensions::Manifest::INVALID_LOCATION,
167             *valid_value,
168             Extension::REQUIRE_KEY,
169             &error));
170     ASSERT_TRUE(extension.get());
171     ASSERT_EQ("", error);
172     pack = BrowserThemePack::BuildFromExtension(extension.get());
173     ASSERT_TRUE(pack.get());
174   }
175
176   base::FilePath GetStarGazingPath() {
177     base::FilePath test_path;
178     if (!PathService::Get(chrome::DIR_TEST_DATA, &test_path)) {
179       NOTREACHED();
180       return test_path;
181     }
182
183     test_path = test_path.AppendASCII("profiles");
184     test_path = test_path.AppendASCII("profile_with_complex_theme");
185     test_path = test_path.AppendASCII("Default");
186     test_path = test_path.AppendASCII("Extensions");
187     test_path = test_path.AppendASCII("mblmlcbknbnfebdfjnolmcapmdofhmme");
188     test_path = test_path.AppendASCII("1.1");
189     return base::FilePath(test_path);
190   }
191
192   base::FilePath GetHiDpiThemePath() {
193     base::FilePath test_path;
194     if (!PathService::Get(chrome::DIR_TEST_DATA, &test_path)) {
195       NOTREACHED();
196       return test_path;
197     }
198     test_path = test_path.AppendASCII("extensions");
199     test_path = test_path.AppendASCII("theme_hidpi");
200     return base::FilePath(test_path);
201   }
202
203   // Verifies the data in star gazing. We do this multiple times for different
204   // BrowserThemePack objects to make sure it works in generated and mmapped
205   // mode correctly.
206   void VerifyStarGazing(BrowserThemePack* pack) {
207     // First check that values we know exist, exist.
208     SkColor color;
209     EXPECT_TRUE(pack->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT,
210                                &color));
211     EXPECT_EQ(SK_ColorBLACK, color);
212
213     EXPECT_TRUE(pack->GetColor(ThemeProperties::COLOR_NTP_BACKGROUND,
214                                &color));
215     EXPECT_EQ(SkColorSetRGB(57, 137, 194), color);
216
217     color_utils::HSL expected = { 0.6, 0.553, 0.5 };
218     color_utils::HSL actual;
219     EXPECT_TRUE(pack->GetTint(ThemeProperties::TINT_BUTTONS, &actual));
220     EXPECT_DOUBLE_EQ(expected.h, actual.h);
221     EXPECT_DOUBLE_EQ(expected.s, actual.s);
222     EXPECT_DOUBLE_EQ(expected.l, actual.l);
223
224     int val;
225     EXPECT_TRUE(pack->GetDisplayProperty(
226         ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &val));
227     EXPECT_EQ(ThemeProperties::ALIGN_TOP, val);
228
229     // The stargazing theme defines the following images:
230     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND));
231     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME));
232     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_NTP_BACKGROUND));
233     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND));
234     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TOOLBAR));
235     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND));
236
237     // Here are a few images that we shouldn't expect because even though
238     // they're included in the theme pack, they were autogenerated and
239     // therefore shouldn't show up when calling HasCustomImage().
240     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INACTIVE));
241     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
242     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO_INACTIVE));
243 #if !defined(OS_MACOSX)
244     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_INCOGNITO));
245 #endif
246
247     // Make sure we don't have phantom data.
248     EXPECT_FALSE(pack->GetColor(ThemeProperties::COLOR_CONTROL_BACKGROUND,
249                                 &color));
250     EXPECT_FALSE(pack->GetTint(ThemeProperties::TINT_FRAME, &actual));
251   }
252
253   void VerifyHiDpiTheme(BrowserThemePack* pack) {
254     // The high DPI theme defines the following images:
255     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME));
256     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INACTIVE));
257     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
258     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME_INCOGNITO_INACTIVE));
259     EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_TOOLBAR));
260
261     // The high DPI theme does not define the following images:
262     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND));
263 #if !defined(OS_MACOSX)
264     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_INCOGNITO));
265 #endif
266     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_TAB_BACKGROUND_V));
267     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_NTP_BACKGROUND));
268     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_OVERLAY));
269     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_FRAME_OVERLAY_INACTIVE));
270     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND));
271     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION));
272     EXPECT_FALSE(pack->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND));
273
274     // Compare some known pixel colors at know locations for a theme
275     // image where two different PNG files were specified for scales 100%
276     // and 200% respectively.
277     int idr = IDR_THEME_FRAME;
278     gfx::Image image = pack->GetImageNamed(idr);
279     EXPECT_FALSE(image.IsEmpty());
280     const gfx::ImageSkia* image_skia = image.ToImageSkia();
281     ASSERT_TRUE(image_skia);
282     // Scale 100%.
283     const gfx::ImageSkiaRep& rep1 = image_skia->GetRepresentation(1.0f);
284     ASSERT_FALSE(rep1.is_null());
285     EXPECT_EQ(80, rep1.sk_bitmap().width());
286     EXPECT_EQ(80, rep1.sk_bitmap().height());
287     rep1.sk_bitmap().lockPixels();
288     EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 4,  4));
289     EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 8,  8));
290     EXPECT_EQ(SkColorSetRGB(  0, 241, 237), rep1.sk_bitmap().getColor(16, 16));
291     EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(24, 24));
292     EXPECT_EQ(SkColorSetRGB(  0, 241, 237), rep1.sk_bitmap().getColor(32, 32));
293     rep1.sk_bitmap().unlockPixels();
294     // Scale 200%.
295     const gfx::ImageSkiaRep& rep2 = image_skia->GetRepresentation(2.0f);
296     ASSERT_FALSE(rep2.is_null());
297     EXPECT_EQ(160, rep2.sk_bitmap().width());
298     EXPECT_EQ(160, rep2.sk_bitmap().height());
299     rep2.sk_bitmap().lockPixels();
300     EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor( 4,  4));
301     EXPECT_EQ(SkColorSetRGB(223,  42,   0), rep2.sk_bitmap().getColor( 8,  8));
302     EXPECT_EQ(SkColorSetRGB(223,  42,   0), rep2.sk_bitmap().getColor(16, 16));
303     EXPECT_EQ(SkColorSetRGB(223,  42,   0), rep2.sk_bitmap().getColor(24, 24));
304     EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor(32, 32));
305     rep2.sk_bitmap().unlockPixels();
306
307     // TODO(sschmitz): I plan to remove the following (to the end of the fct)
308     // Reason: this test may be brittle. It depends on details of how we scale
309     // an 100% image to an 200% image. If there's filtering etc, this test would
310     // break. Also High DPI is new, but scaling from 100% to 200% is not new
311     // and need not be tested here. But in the interrim it is useful to verify
312     // that this image was scaled and did not appear in the input.
313
314     // Compare pixel colors and locations for a theme image that had
315     // only one PNG file specified (for scale 100%). The representation
316     // for scale of 200% was computed.
317     idr = IDR_THEME_FRAME_INCOGNITO_INACTIVE;
318     image = pack->GetImageNamed(idr);
319     EXPECT_FALSE(image.IsEmpty());
320     image_skia = image.ToImageSkia();
321     ASSERT_TRUE(image_skia);
322     // Scale 100%.
323     const gfx::ImageSkiaRep& rep3 = image_skia->GetRepresentation(1.0f);
324     ASSERT_FALSE(rep3.is_null());
325     EXPECT_EQ(80, rep3.sk_bitmap().width());
326     EXPECT_EQ(80, rep3.sk_bitmap().height());
327     rep3.sk_bitmap().lockPixels();
328     // We take samples of colors and locations along the diagonal whenever
329     // the color changes. Note these colors are slightly different from
330     // the input PNG file due to input processing.
331     std::vector<std::pair<int, SkColor> > normal;
332     int xy = 0;
333     SkColor color = rep3.sk_bitmap().getColor(xy, xy);
334     normal.push_back(std::make_pair(xy, color));
335     for (int xy = 0; xy < 40; ++xy) {
336       SkColor next_color = rep3.sk_bitmap().getColor(xy, xy);
337       if (next_color != color) {
338         color = next_color;
339         normal.push_back(std::make_pair(xy, color));
340       }
341     }
342     EXPECT_EQ(static_cast<size_t>(9), normal.size());
343     rep3.sk_bitmap().unlockPixels();
344     // Scale 200%.
345     const gfx::ImageSkiaRep& rep4 = image_skia->GetRepresentation(2.0f);
346     ASSERT_FALSE(rep4.is_null());
347     EXPECT_EQ(160, rep4.sk_bitmap().width());
348     EXPECT_EQ(160, rep4.sk_bitmap().height());
349     rep4.sk_bitmap().lockPixels();
350     // We expect the same colors and at locations scaled by 2
351     // since this bitmap was scaled by 2.
352     for (size_t i = 0; i < normal.size(); ++i) {
353       int xy = 2 * normal[i].first;
354       SkColor color = normal[i].second;
355       EXPECT_EQ(color, rep4.sk_bitmap().getColor(xy, xy));
356     }
357     rep4.sk_bitmap().unlockPixels();
358   }
359
360   base::MessageLoop message_loop;
361   content::TestBrowserThread fake_ui_thread;
362   content::TestBrowserThread fake_file_thread;
363
364   typedef scoped_ptr<ui::test::ScopedSetSupportedScaleFactors>
365       ScopedSetSupportedScaleFactors;
366   ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_;
367   scoped_refptr<BrowserThemePack> theme_pack_;
368 };
369
370
371 TEST_F(BrowserThemePackTest, DeriveUnderlineLinkColor) {
372   // If we specify a link color, but don't specify the underline color, the
373   // theme provider should create one.
374   std::string color_json = "{ \"ntp_link\": [128, 128, 128],"
375                            "  \"ntp_section_link\": [128, 128, 128] }";
376   LoadColorJSON(color_json);
377
378   std::map<int, SkColor> colors = GetDefaultColorMap();
379   SkColor link_color = SkColorSetRGB(128, 128, 128);
380   colors[ThemeProperties::COLOR_NTP_LINK] = link_color;
381   colors[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] =
382       BuildThirdOpacity(link_color);
383   colors[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color;
384   colors[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] =
385       BuildThirdOpacity(link_color);
386
387   VerifyColorMap(colors);
388 }
389
390 TEST_F(BrowserThemePackTest, ProvideUnderlineLinkColor) {
391   // If we specify the underline color, it shouldn't try to generate one.
392   std::string color_json = "{ \"ntp_link\": [128, 128, 128],"
393                            "  \"ntp_link_underline\": [255, 255, 255],"
394                            "  \"ntp_section_link\": [128, 128, 128],"
395                            "  \"ntp_section_link_underline\": [255, 255, 255]"
396                            "}";
397   LoadColorJSON(color_json);
398
399   std::map<int, SkColor> colors = GetDefaultColorMap();
400   SkColor link_color = SkColorSetRGB(128, 128, 128);
401   SkColor underline_color = SkColorSetRGB(255, 255, 255);
402   colors[ThemeProperties::COLOR_NTP_LINK] = link_color;
403   colors[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] = underline_color;
404   colors[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color;
405   colors[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] =
406       underline_color;
407
408   VerifyColorMap(colors);
409 }
410
411 TEST_F(BrowserThemePackTest, UseSectionColorAsNTPHeader) {
412   std::string color_json = "{ \"ntp_section\": [190, 190, 190] }";
413   LoadColorJSON(color_json);
414
415   std::map<int, SkColor> colors = GetDefaultColorMap();
416   SkColor ntp_color = SkColorSetRGB(190, 190, 190);
417   colors[ThemeProperties::COLOR_NTP_HEADER] = ntp_color;
418   colors[ThemeProperties::COLOR_NTP_SECTION] = ntp_color;
419   VerifyColorMap(colors);
420 }
421
422 TEST_F(BrowserThemePackTest, ProvideNtpHeaderColor) {
423   std::string color_json = "{ \"ntp_header\": [120, 120, 120], "
424                            "  \"ntp_section\": [190, 190, 190] }";
425   LoadColorJSON(color_json);
426
427   std::map<int, SkColor> colors = GetDefaultColorMap();
428   SkColor ntp_header = SkColorSetRGB(120, 120, 120);
429   SkColor ntp_section = SkColorSetRGB(190, 190, 190);
430   colors[ThemeProperties::COLOR_NTP_HEADER] = ntp_header;
431   colors[ThemeProperties::COLOR_NTP_SECTION] = ntp_section;
432   VerifyColorMap(colors);
433 }
434
435 TEST_F(BrowserThemePackTest, CanReadTints) {
436   std::string tint_json = "{ \"buttons\": [ 0.5, 0.5, 0.5 ] }";
437   LoadTintJSON(tint_json);
438
439   color_utils::HSL expected = { 0.5, 0.5, 0.5 };
440   color_utils::HSL actual = { -1, -1, -1 };
441   EXPECT_TRUE(theme_pack_->GetTint(
442       ThemeProperties::TINT_BUTTONS, &actual));
443   EXPECT_DOUBLE_EQ(expected.h, actual.h);
444   EXPECT_DOUBLE_EQ(expected.s, actual.s);
445   EXPECT_DOUBLE_EQ(expected.l, actual.l);
446 }
447
448 TEST_F(BrowserThemePackTest, CanReadDisplayProperties) {
449   std::string json = "{ \"ntp_background_alignment\": \"bottom\", "
450                      "  \"ntp_background_repeat\": \"repeat-x\", "
451                      "  \"ntp_logo_alternate\": 0 }";
452   LoadDisplayPropertiesJSON(json);
453
454   int out_val;
455   EXPECT_TRUE(theme_pack_->GetDisplayProperty(
456       ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &out_val));
457   EXPECT_EQ(ThemeProperties::ALIGN_BOTTOM, out_val);
458
459   EXPECT_TRUE(theme_pack_->GetDisplayProperty(
460       ThemeProperties::NTP_BACKGROUND_TILING, &out_val));
461   EXPECT_EQ(ThemeProperties::REPEAT_X, out_val);
462
463   EXPECT_TRUE(theme_pack_->GetDisplayProperty(
464       ThemeProperties::NTP_LOGO_ALTERNATE, &out_val));
465   EXPECT_EQ(0, out_val);
466 }
467
468 TEST_F(BrowserThemePackTest, CanParsePaths) {
469   std::string path_json = "{ \"theme_button_background\": \"one\", "
470                           "  \"theme_toolbar\": \"two\" }";
471   TestFilePathMap out_file_paths;
472   ParseImageNamesJSON(path_json, &out_file_paths);
473
474   size_t expected_file_paths = 2u;
475 #if defined(USE_ASH) && !defined(OS_CHROMEOS)
476   // On desktop builds with ash, additional theme paths are generated to map to
477   // the special resource ids like IDR_THEME_FRAME_DESKTOP, etc
478   expected_file_paths = 3u;
479 #endif
480   EXPECT_EQ(expected_file_paths, out_file_paths.size());
481   // "12" and "5" are internal constants to BrowserThemePack and are
482   // PRS_THEME_BUTTON_BACKGROUND and PRS_THEME_TOOLBAR, but they are
483   // implementation details that shouldn't be exported.
484   // By default the scale factor is for 100%.
485   EXPECT_TRUE(base::FilePath(FILE_PATH_LITERAL("one")) ==
486               out_file_paths[12][ui::SCALE_FACTOR_100P]);
487   EXPECT_TRUE(base::FilePath(FILE_PATH_LITERAL("two")) ==
488               out_file_paths[5][ui::SCALE_FACTOR_100P]);
489 }
490
491 TEST_F(BrowserThemePackTest, InvalidPathNames) {
492   std::string path_json = "{ \"wrong\": [1], "
493                           "  \"theme_button_background\": \"one\", "
494                           "  \"not_a_thing\": \"blah\" }";
495   TestFilePathMap out_file_paths;
496   ParseImageNamesJSON(path_json, &out_file_paths);
497
498   // We should have only parsed one valid path out of that mess above.
499   EXPECT_EQ(1u, out_file_paths.size());
500 }
501
502 TEST_F(BrowserThemePackTest, InvalidColors) {
503   std::string invalid_color = "{ \"toolbar\": [\"dog\", \"cat\", [12]], "
504                               "  \"sound\": \"woof\" }";
505   LoadColorJSON(invalid_color);
506   std::map<int, SkColor> colors = GetDefaultColorMap();
507   VerifyColorMap(colors);
508 }
509
510 TEST_F(BrowserThemePackTest, InvalidTints) {
511   std::string tints = "{ \"buttons\": [ \"dog\", \"cat\", [\"x\"]], "
512                        " \"frame\": [-2, 2, 3],"
513                        " \"frame_incognito_inactive\": [-1, 2, 0.6],"
514                        " \"invalid\": \"entry\" }";
515   LoadTintJSON(tints);
516
517   // We should ignore completely invalid (non-numeric) tints.
518   color_utils::HSL actual = { -1, -1, -1 };
519   EXPECT_FALSE(theme_pack_->GetTint(ThemeProperties::TINT_BUTTONS, &actual));
520
521   // We should change invalid numeric HSL tint components to the special -1 "no
522   // change" value.
523   EXPECT_TRUE(theme_pack_->GetTint(ThemeProperties::TINT_FRAME, &actual));
524   EXPECT_EQ(-1, actual.h);
525   EXPECT_EQ(-1, actual.s);
526   EXPECT_EQ(-1, actual.l);
527
528   // We should correct partially incorrect inputs as well.
529   EXPECT_TRUE(theme_pack_->GetTint(
530       ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE, &actual));
531   EXPECT_EQ(-1, actual.h);
532   EXPECT_EQ(-1, actual.s);
533   EXPECT_EQ(0.6, actual.l);
534 }
535
536 TEST_F(BrowserThemePackTest, InvalidDisplayProperties) {
537   std::string invalid_properties = "{ \"ntp_background_alignment\": [15], "
538                                    "  \"junk\": [15.3] }";
539   LoadDisplayPropertiesJSON(invalid_properties);
540
541   int out_val;
542   EXPECT_FALSE(theme_pack_->GetDisplayProperty(
543       ThemeProperties::NTP_BACKGROUND_ALIGNMENT, &out_val));
544 }
545
546 // These three tests should just not cause a segmentation fault.
547 TEST_F(BrowserThemePackTest, NullPaths) {
548   TestFilePathMap out_file_paths;
549   ParseImageNamesDictionary(NULL, &out_file_paths);
550 }
551
552 TEST_F(BrowserThemePackTest, NullTints) {
553   LoadTintDictionary(NULL);
554 }
555
556 TEST_F(BrowserThemePackTest, NullColors) {
557   LoadColorDictionary(NULL);
558 }
559
560 TEST_F(BrowserThemePackTest, NullDisplayProperties) {
561   LoadDisplayPropertiesDictionary(NULL);
562 }
563
564 TEST_F(BrowserThemePackTest, TestHasCustomImage) {
565   // HasCustomImage should only return true for images that exist in the
566   // extension and not for autogenerated images.
567   std::string images = "{ \"theme_frame\": \"one\" }";
568   TestFilePathMap out_file_paths;
569   ParseImageNamesJSON(images, &out_file_paths);
570
571   EXPECT_TRUE(theme_pack_->HasCustomImage(IDR_THEME_FRAME));
572   EXPECT_FALSE(theme_pack_->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
573 }
574
575 TEST_F(BrowserThemePackTest, TestNonExistantImages) {
576   std::string images = "{ \"theme_frame\": \"does_not_exist\" }";
577   TestFilePathMap out_file_paths;
578   ParseImageNamesJSON(images, &out_file_paths);
579
580   EXPECT_FALSE(LoadRawBitmapsTo(out_file_paths));
581 }
582
583 // TODO(erg): This test should actually test more of the built resources from
584 // the extension data, but for now, exists so valgrind can test some of the
585 // tricky memory stuff that BrowserThemePack does.
586 TEST_F(BrowserThemePackTest, CanBuildAndReadPack) {
587   base::ScopedTempDir dir;
588   ASSERT_TRUE(dir.CreateUniqueTempDir());
589   base::FilePath file = dir.path().AppendASCII("data.pak");
590
591   // Part 1: Build the pack from an extension.
592   {
593     base::FilePath star_gazing_path = GetStarGazingPath();
594     scoped_refptr<BrowserThemePack> pack;
595     BuildFromUnpackedExtension(star_gazing_path, pack);
596     ASSERT_TRUE(pack->WriteToDisk(file));
597     VerifyStarGazing(pack.get());
598   }
599
600   // Part 2: Try to read back the data pack that we just wrote to disk.
601   {
602     scoped_refptr<BrowserThemePack> pack =
603         BrowserThemePack::BuildFromDataPack(
604             file, "mblmlcbknbnfebdfjnolmcapmdofhmme");
605     ASSERT_TRUE(pack.get());
606     VerifyStarGazing(pack.get());
607   }
608 }
609
610 TEST_F(BrowserThemePackTest, HiDpiThemeTest) {
611   base::ScopedTempDir dir;
612   ASSERT_TRUE(dir.CreateUniqueTempDir());
613   base::FilePath file = dir.path().AppendASCII("theme_data.pak");
614
615   // Part 1: Build the pack from an extension.
616   {
617     base::FilePath hidpi_path = GetHiDpiThemePath();
618     scoped_refptr<BrowserThemePack> pack;
619     BuildFromUnpackedExtension(hidpi_path, pack);
620     ASSERT_TRUE(pack->WriteToDisk(file));
621     VerifyHiDpiTheme(pack.get());
622   }
623
624   // Part 2: Try to read back the data pack that we just wrote to disk.
625   {
626     scoped_refptr<BrowserThemePack> pack =
627         BrowserThemePack::BuildFromDataPack(file, "gllekhaobjnhgeag");
628     ASSERT_TRUE(pack.get());
629     VerifyHiDpiTheme(pack.get());
630   }
631 }