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