Index: chrome/browser/chromeos/login/screenshot_tester.cc |
diff --git a/chrome/browser/chromeos/login/screenshot_tester.cc b/chrome/browser/chromeos/login/screenshot_tester.cc |
index 683f987d6d0f82c460edeaf1d1ef6841bf16722d..a90f105a77ec1d39c1fa117cc971c40d2e30cbae 100644 |
--- a/chrome/browser/chromeos/login/screenshot_tester.cc |
+++ b/chrome/browser/chromeos/login/screenshot_tester.cc |
@@ -4,10 +4,14 @@ |
#include "chrome/browser/chromeos/login/screenshot_tester.h" |
+#include <algorithm> |
+#include <string> |
ygorshenin1
2014/07/31 13:19:14
nit: remove <string> inclusion since you already i
Lisa Ignatyeva
2014/07/31 16:37:39
Done.
|
+ |
#include "ash/shell.h" |
#include "base/base_export.h" |
#include "base/bind_internal.h" |
#include "base/command_line.h" |
+#include "base/logging.h" |
#include "base/memory/weak_ptr.h" |
#include "base/prefs/pref_service.h" |
#include "base/run_loop.h" |
@@ -15,13 +19,17 @@ |
#include "chrome/common/pref_names.h" |
#include "chromeos/chromeos_switches.h" |
#include "content/public/browser/browser_thread.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "third_party/skia/include/core/SkCanvas.h" |
#include "ui/compositor/compositor_switches.h" |
+#include "ui/gfx/codec/png_codec.h" |
#include "ui/gfx/image/image.h" |
#include "ui/snapshot/snapshot.h" |
namespace chromeos { |
-ScreenshotTester::ScreenshotTester() : weak_factory_(this) { |
+ScreenshotTester::ScreenshotTester() : test_mode_(false), weak_factory_(this) { |
} |
ScreenshotTester::~ScreenshotTester() { |
@@ -29,7 +37,7 @@ ScreenshotTester::~ScreenshotTester() { |
bool ScreenshotTester::TryInitialize() { |
CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
- if (!command_line.HasSwitch(switches::kEnableScreenshotTesting)) |
+ if (!command_line.HasSwitch(switches::kEnableScreenshotTestingWithMode)) |
return false; |
if (!command_line.HasSwitch(::switches::kEnablePixelOutputInTests) || |
!command_line.HasSwitch(::switches::kUIEnableImplSidePainting)) { |
@@ -40,64 +48,172 @@ bool ScreenshotTester::TryInitialize() { |
<< "screenshots"; |
return false; |
} |
- if (!command_line.HasSwitch(switches::kScreenshotDestinationDir)) { |
- LOG(ERROR) << "No destination for screenshots specified"; |
- return false; |
+ |
+ std::string mode = command_line.GetSwitchValueASCII( |
+ switches::kEnableScreenshotTestingWithMode); |
+ if (mode != "update" && mode != "test") { |
+ LOG(ERROR) << "Invalid mode for screenshot testing: " << mode; |
+ DCHECK(false); |
ygorshenin1
2014/07/31 13:19:14
I thought it's better to return false instead of D
Lisa Ignatyeva
2014/07/31 16:37:39
That's actually a question of strictness. I believ
ygorshenin1
2014/07/31 16:50:17
So you should replace DCHECK() by CHECK(), because
Lisa Ignatyeva
2014/07/31 16:58:39
Done.
|
+ } |
+ |
+ if (!command_line.HasSwitch(chromeos::switches::kGoldenScreenshotsDir)) { |
+ LOG(ERROR) << "No directory for golden screenshots specified"; |
+ DCHECK(false); |
+ } |
+ |
+ golden_screenshots_dir_ = |
+ command_line.GetSwitchValuePath(switches::kGoldenScreenshotsDir); |
+ |
+ if (mode == "test") { |
ygorshenin1
2014/07/31 13:19:14
Could you please define a couple of string constan
Lisa Ignatyeva
2014/07/31 16:37:39
Done.
|
+ test_mode_ = true; |
+ if (!command_line.HasSwitch(switches::kArtifactsDir)) { |
+ artifacts_dir_ = golden_screenshots_dir_; |
+ LOG(WARNING) |
+ << "No directory for artifact storing specified. Artifacts will be" |
+ << "saved at golden screenshots directory."; |
+ } else { |
+ artifacts_dir_ = command_line.GetSwitchValuePath(switches::kArtifactsDir); |
+ } |
} |
- screenshot_dest_ = command_line.GetSwitchValuePath( |
- chromeos::switches::kScreenshotDestinationDir); |
return true; |
} |
-void ScreenshotTester::Run(const std::string& file_name) { |
- TakeScreenshot(); |
- PNGFile current_screenshot = screenshot_; |
- UpdateGoldenScreenshot(file_name, current_screenshot); |
+void ScreenshotTester::Run(const std::string& test_name) { |
+ test_name_ = test_name; |
+ PNGFile current_screenshot = TakeScreenshot(); |
+ if (test_mode_) { |
+ PNGFile golden_screenshot = LoadGoldenScreenshot(); |
+ VLOG(0) << "Loaded golden screenshot"; |
+ CompareScreenshots(golden_screenshot, current_screenshot); |
+ } else { |
+ UpdateGoldenScreenshot(current_screenshot); |
+ return; |
+ } |
+} |
+ |
+void ScreenshotTester::UpdateGoldenScreenshot(PNGFile png_data) { |
+ SaveImage("golden_screenshot", golden_screenshots_dir_, png_data); |
} |
-void ScreenshotTester::UpdateGoldenScreenshot(const std::string& file_name, |
- PNGFile png_data) { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+void ScreenshotTester::SaveImage(const std::string& file_name, |
+ const base::FilePath& screenshot_dir, |
+ PNGFile png_data) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ base::FilePath screenshot_path = |
+ screenshot_dir.AppendASCII(test_name_ + "_" + file_name + ".png"); |
if (!png_data) { |
LOG(ERROR) << "Can't take a screenshot"; |
- return; |
+ DCHECK(false); |
} |
- base::FilePath golden_screenshot_path = |
- screenshot_dest_.AppendASCII(file_name + ".png"); |
- if (!base::CreateDirectory(golden_screenshot_path.DirName())) { |
- LOG(ERROR) << "Can't create a directory "; |
- return; |
+ if (!base::CreateDirectory(screenshot_path.DirName())) { |
+ LOG(ERROR) << "Can't create a directory " |
+ << screenshot_path.DirName().value(); |
+ DCHECK(false); |
ygorshenin1
2014/07/31 13:19:14
It's better add return value for SaveImage() and r
Lisa Ignatyeva
2014/07/31 16:37:39
Done.
|
} |
if (static_cast<size_t>( |
- base::WriteFile(golden_screenshot_path, |
+ base::WriteFile(screenshot_path, |
reinterpret_cast<char*>(&(png_data->data()[0])), |
png_data->size())) != png_data->size()) { |
- LOG(ERROR) << "Can't save screenshot"; |
+ LOG(ERROR) << "Can't save screenshot " << file_name; |
+ DCHECK(false); |
} |
- VLOG(0) << "Golden screenshot updated successfully"; |
+ VLOG(0) << "Screenshot " << file_name << ".png saved successfully to " |
+ << screenshot_dir.value(); |
} |
-void ScreenshotTester::ReturnScreenshot(PNGFile png_data) { |
- // TODO(elizavetai): rewrite this function so that TakeScreenshot |
- // could return a |PNGFile| -- current screenshot. |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
- screenshot_ = png_data; |
+void ScreenshotTester::ReturnScreenshot(const PNGFile& screenshot, |
+ PNGFile png_data) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
ygorshenin1
2014/07/31 13:19:14
nit: replace this DCHECK() by DCHECK_CURRENTLY_ON(
Lisa Ignatyeva
2014/07/31 16:37:39
Done.
|
+ screenshot->data() = png_data->data(); |
content::BrowserThread::PostTask( |
content::BrowserThread::UI, FROM_HERE, run_loop_quitter_); |
} |
-void ScreenshotTester::TakeScreenshot() { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ScreenshotTester::PNGFile ScreenshotTester::TakeScreenshot() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
aura::Window* primary_window = ash::Shell::GetPrimaryRootWindow(); |
gfx::Rect rect = primary_window->bounds(); |
+ PNGFile screenshot = new base::RefCountedBytes; |
ui::GrabWindowSnapshotAsync(primary_window, |
rect, |
content::BrowserThread::GetBlockingPool(), |
base::Bind(&ScreenshotTester::ReturnScreenshot, |
- weak_factory_.GetWeakPtr())); |
+ weak_factory_.GetWeakPtr(), |
+ screenshot)); |
base::RunLoop run_loop; |
run_loop_quitter_ = run_loop.QuitClosure(); |
run_loop.Run(); |
+ return screenshot; |
+} |
+ |
+ScreenshotTester::PNGFile ScreenshotTester::LoadGoldenScreenshot() { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ |
+ base::FilePath screenshot_path = golden_screenshots_dir_.AppendASCII( |
+ test_name_ + "_golden_screenshot.png"); |
+ if (!base::PathExists(screenshot_path)) { |
+ LOG(ERROR) << "Can't find a golden screenshot for this test"; |
+ DCHECK(false); |
ygorshenin1
2014/07/31 13:19:14
No need in DCHECK(), since path does not exists an
Lisa Ignatyeva
2014/07/31 16:37:38
I can return NULL instead of loaded file if someth
ygorshenin1
2014/07/31 16:50:17
I suggest you to replace DCHECK by CHECK, as I exp
Lisa Ignatyeva
2014/07/31 16:58:39
Done.
|
+ } |
+ |
+ size_t golden_screenshot_size; |
+ base::GetFileSize(screenshot_path, |
+ reinterpret_cast<int64*>(&golden_screenshot_size)); |
+ |
+ PNGFile png_data = new base::RefCountedBytes; |
+ png_data->data().resize(golden_screenshot_size); |
+ base::ReadFile(screenshot_path, |
+ reinterpret_cast<char*>(&(png_data->data()[0])), |
+ golden_screenshot_size); |
+ |
+ return png_data; |
+} |
+ |
+void ScreenshotTester::CompareScreenshots(PNGFile model, PNGFile sample) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ |
+ ASSERT_FALSE(model == NULL); |
ygorshenin1
2014/07/31 13:19:14
nit: ASSERT_TRUE(model.get());
ASSERT_TRUE(sa
Lisa Ignatyeva
2014/07/31 16:37:39
Done.
|
+ ASSERT_FALSE(sample == NULL); |
+ |
+ SkBitmap model_bitmap; |
+ SkBitmap sample_bitmap; |
+ gfx::PNGCodec::Decode(reinterpret_cast<unsigned char*>(&(model->data()[0])), |
+ model->data().size(), |
+ &model_bitmap); |
+ gfx::PNGCodec::Decode(reinterpret_cast<unsigned char*>(&(sample->data()[0])), |
+ sample->data().size(), |
+ &sample_bitmap); |
+ |
+ ASSERT_EQ(model_bitmap.config(), sample_bitmap.config()); |
+ ASSERT_EQ(model_bitmap.width(), sample_bitmap.width()); |
+ ASSERT_EQ(model_bitmap.height(), sample_bitmap.height()); |
+ |
+ bool screenshots_match = true; |
+ |
+ SkCanvas diff_canvas(sample_bitmap); |
+ for (int i = 0; i < model_bitmap.width(); i++) |
+ for (int j = 0; j < model_bitmap.height(); j++) { |
+ if (model_bitmap.getColor(i, j) == sample_bitmap.getColor(i, j)) { |
+ diff_canvas.drawPoint(i, j, SK_ColorWHITE); |
+ } else { |
+ screenshots_match = false; |
+ diff_canvas.drawPoint(i, j, SK_ColorRED); |
+ } |
+ } |
+ |
+ if (!screenshots_match) { |
+ SaveImage("failed_screenshot", artifacts_dir_, sample); |
+ gfx::PNGCodec::EncodeBGRASkBitmap(sample_bitmap, false, &sample->data()); |
+ SaveImage("difference", artifacts_dir_, sample); |
+ LOG(ERROR) |
+ << "Screenshots testing failed. Screenshots differ in some pixels"; |
+ VLOG(0) << "Current screenshot and diff picture saved to " |
+ << artifacts_dir_.value(); |
+ ASSERT_TRUE(screenshots_match); |
ygorshenin1
2014/07/31 13:19:14
This assertion contradicts with if's condition.
Lisa Ignatyeva
2014/07/31 16:37:39
Yes, that was done intentionally. The test is fail
|
+ } else { |
+ VLOG(0) << "Current screenshot matches the golden screenshot. Screenshot " |
+ "testing passed."; |
+ } |
} |
} // namespace chromeos |