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