Fix build break
[chromium-blink-merge.git] / chrome / browser / printing / printing_layout_browsertest.cc
blob73053ac7ad5fbd8b963eacb7524076dfbd25d281
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.
5 #include "base/command_line.h"
6 #include "base/file_util.h"
7 #include "base/files/file_path.h"
8 #include "base/message_loop.h"
9 #include "base/path_service.h"
10 #include "base/process_util.h"
11 #include "base/string_util.h"
12 #include "base/test/test_file_util.h"
13 #include "base/threading/simple_thread.h"
14 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/printing/print_job.h"
16 #include "chrome/browser/printing/print_view_manager.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_commands.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/common/chrome_notification_types.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/test/base/in_process_browser_test.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "content/public/browser/notification_observer.h"
26 #include "content/public/browser/notification_registrar.h"
27 #include "content/public/browser/notification_service.h"
28 #include "net/test/test_server.h"
29 #include "printing/image.h"
30 #include "printing/printing_test.h"
32 namespace {
34 using printing::Image;
36 const char kGenerateSwitch[] = "print-layout-generate";
38 class PrintingLayoutTest : public PrintingTest<InProcessBrowserTest>,
39 public content::NotificationObserver {
40 public:
41 PrintingLayoutTest() {
42 base::FilePath browser_directory;
43 PathService::Get(chrome::DIR_APP, &browser_directory);
44 emf_path_ = browser_directory.AppendASCII("metafile_dumps");
47 virtual void SetUp() OVERRIDE {
48 // Make sure there is no left overs.
49 CleanupDumpDirectory();
50 InProcessBrowserTest::SetUp();
53 virtual void TearDown() OVERRIDE {
54 InProcessBrowserTest::TearDown();
55 file_util::Delete(emf_path_, true);
58 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
59 command_line->AppendSwitchPath(switches::kDebugPrint, emf_path_);
62 protected:
63 void PrintNowTab() {
64 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
65 content::NotificationService::AllSources());
67 content::WebContents* web_contents =
68 browser()->tab_strip_model()->GetActiveWebContents();
69 printing::PrintViewManager::FromWebContents(web_contents)->PrintNow();
70 content::RunMessageLoop();
71 registrar_.RemoveAll();
74 virtual void Observe(int type,
75 const content::NotificationSource& source,
76 const content::NotificationDetails& details) {
77 ASSERT_EQ(chrome::NOTIFICATION_PRINT_JOB_EVENT, type);
78 switch (content::Details<printing::JobEventDetails>(details)->type()) {
79 case printing::JobEventDetails::JOB_DONE: {
80 // Succeeded.
81 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
82 break;
84 case printing::JobEventDetails::USER_INIT_CANCELED:
85 case printing::JobEventDetails::FAILED: {
86 // Failed.
87 ASSERT_TRUE(false);
88 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
89 break;
91 case printing::JobEventDetails::NEW_DOC:
92 case printing::JobEventDetails::USER_INIT_DONE:
93 case printing::JobEventDetails::DEFAULT_INIT_DONE:
94 case printing::JobEventDetails::NEW_PAGE:
95 case printing::JobEventDetails::PAGE_DONE:
96 case printing::JobEventDetails::DOC_DONE:
97 case printing::JobEventDetails::ALL_PAGES_REQUESTED: {
98 // Don't care.
99 break;
101 default: {
102 NOTREACHED();
103 break;
108 // Finds the dump for the last print job and compares it to the data named
109 // |verification_name|. Compares the saved printed job pixels with the test
110 // data pixels and returns the percentage of different pixels; 0 for success,
111 // [0, 100] for failure.
112 double CompareWithResult(const std::wstring& verification_name) {
113 base::FilePath test_result(ScanFiles(verification_name));
114 if (test_result.value().empty()) {
115 // 100% different, the print job buffer is not there.
116 return 100.;
119 base::FilePath base_path(ui_test_utils::GetTestFilePath(
120 base::FilePath().AppendASCII("printing"), base::FilePath()));
121 base::FilePath emf(base_path.Append(verification_name + L".emf"));
122 base::FilePath png(base_path.Append(verification_name + L".png"));
124 base::FilePath cleartype(
125 base_path.Append(verification_name + L"_cleartype.png"));
126 // Looks for Cleartype override.
127 if (file_util::PathExists(cleartype) && IsClearTypeEnabled())
128 png = cleartype;
130 if (GenerateFiles()) {
131 // Copy the .emf and generate an .png.
132 file_util::CopyFile(test_result, emf);
133 Image emf_content(emf);
134 emf_content.SaveToPng(png);
135 // Saving is always fine.
136 return 0;
137 } else {
138 // File compare between test and result.
139 Image emf_content(emf);
140 Image test_content(test_result);
141 Image png_content(png);
142 double diff_emf = emf_content.PercentageDifferent(test_content);
144 EXPECT_EQ(0., diff_emf) << WideToUTF8(verification_name) <<
145 " original size:" << emf_content.size().ToString() <<
146 " result size:" << test_content.size().ToString();
147 if (diff_emf) {
148 // Backup the result emf file.
149 base::FilePath failed(
150 base_path.Append(verification_name + L"_failed.emf"));
151 file_util::CopyFile(test_result, failed);
154 // This verification is only to know that the EMF rendering stays
155 // immutable.
156 double diff_png = emf_content.PercentageDifferent(png_content);
157 EXPECT_EQ(0., diff_png) << WideToUTF8(verification_name) <<
158 " original size:" << emf_content.size().ToString() <<
159 " result size:" << test_content.size().ToString();
160 if (diff_png) {
161 // Backup the rendered emf file to detect the rendering difference.
162 base::FilePath rendering(
163 base_path.Append(verification_name + L"_rendering.png"));
164 emf_content.SaveToPng(rendering);
166 return std::max(diff_png, diff_emf);
170 // Makes sure the directory exists and is empty.
171 void CleanupDumpDirectory() {
172 EXPECT_TRUE(file_util::DieFileDie(emf_path_, true));
173 EXPECT_TRUE(file_util::CreateDirectory(emf_path_));
176 // Returns if Clear Type is currently enabled.
177 static bool IsClearTypeEnabled() {
178 BOOL ct_enabled = 0;
179 if (SystemParametersInfo(SPI_GETCLEARTYPE, 0, &ct_enabled, 0) && ct_enabled)
180 return true;
181 UINT smoothing = 0;
182 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothing, 0) &&
183 smoothing == FE_FONTSMOOTHINGCLEARTYPE)
184 return true;
185 return false;
188 private:
189 // Verifies that there is one .emf and one .prn file in the dump directory.
190 // Returns the path of the .emf file and deletes the .prn file.
191 std::wstring ScanFiles(const std::wstring& verification_name) {
192 // Try to 10 seconds.
193 std::wstring emf_file;
194 std::wstring prn_file;
195 bool found_emf = false;
196 bool found_prn = false;
197 for (int i = 0; i < 100; ++i) {
198 file_util::FileEnumerator enumerator(emf_path_, false,
199 file_util::FileEnumerator::FILES);
200 emf_file.clear();
201 prn_file.clear();
202 found_emf = false;
203 found_prn = false;
204 base::FilePath file;
205 while (!(file = enumerator.Next()).empty()) {
206 std::wstring ext = file.Extension();
207 if (base::strcasecmp(WideToUTF8(ext).c_str(), ".emf") == 0) {
208 EXPECT_FALSE(found_emf) << "Found a leftover .EMF file: \"" <<
209 emf_file << "\" and \"" << file.value() <<
210 "\" when looking for \"" << verification_name << "\"";
211 found_emf = true;
212 emf_file = file.value();
213 continue;
215 if (base::strcasecmp(WideToUTF8(ext).c_str(), ".prn") == 0) {
216 EXPECT_FALSE(found_prn) << "Found a leftover .PRN file: \"" <<
217 prn_file << "\" and \"" << file.value() <<
218 "\" when looking for \"" << verification_name << "\"";
219 prn_file = file.value();
220 found_prn = true;
221 file_util::Delete(file, false);
222 continue;
224 EXPECT_TRUE(false);
226 if (found_emf && found_prn)
227 break;
228 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
230 EXPECT_TRUE(found_emf) << ".PRN file is: " << prn_file;
231 EXPECT_TRUE(found_prn) << ".EMF file is: " << emf_file;
232 return emf_file;
235 static bool GenerateFiles() {
236 return CommandLine::ForCurrentProcess()->HasSwitch(kGenerateSwitch);
239 base::FilePath emf_path_;
240 content::NotificationRegistrar registrar_;
242 DISALLOW_COPY_AND_ASSIGN(PrintingLayoutTest);
245 class PrintingLayoutTextTest : public PrintingLayoutTest {
246 typedef PrintingLayoutTest Parent;
247 public:
248 // Returns if the test is disabled.
249 // http://crbug.com/64869 Until the issue is fixed, disable the test if
250 // ClearType is enabled.
251 static bool IsTestCaseDisabled() {
252 return Parent::IsTestCaseDisabled() || IsClearTypeEnabled();
256 // Finds the first dialog window owned by owner_process.
257 HWND FindDialogWindow(DWORD owner_process) {
258 HWND dialog_window(NULL);
259 for (;;) {
260 dialog_window = FindWindowEx(NULL,
261 dialog_window,
262 MAKEINTATOM(32770),
263 NULL);
264 if (!dialog_window)
265 break;
267 // The dialog must be owned by our target process.
268 DWORD process_id = 0;
269 GetWindowThreadProcessId(dialog_window, &process_id);
270 if (process_id == owner_process)
271 break;
273 return dialog_window;
276 // Tries to close a dialog window.
277 bool CloseDialogWindow(HWND dialog_window) {
278 LRESULT res = SendMessage(dialog_window, DM_GETDEFID, 0, 0);
279 if (!res)
280 return false;
281 EXPECT_EQ(DC_HASDEFID, HIWORD(res));
282 WORD print_button_id = LOWORD(res);
283 res = SendMessage(
284 dialog_window,
285 WM_COMMAND,
286 print_button_id,
287 reinterpret_cast<LPARAM>(GetDlgItem(dialog_window, print_button_id)));
288 return res == 0;
291 // Dismiss the first dialog box owned by owner_process by "executing" the
292 // default button.
293 class DismissTheWindow : public base::DelegateSimpleThread::Delegate {
294 public:
295 DismissTheWindow()
296 : owner_process_(base::Process::Current().pid()) {
299 virtual void Run() {
300 HWND dialog_window;
301 for (;;) {
302 // First enumerate the windows.
303 dialog_window = FindDialogWindow(owner_process_);
305 // Try to close it.
306 if (dialog_window) {
307 if (CloseDialogWindow(dialog_window)) {
308 break;
311 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
314 // Now verify that it indeed closed itself.
315 while (IsWindow(dialog_window)) {
316 CloseDialogWindow(dialog_window);
317 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
321 DWORD owner_process() { return owner_process_; }
323 private:
324 DWORD owner_process_;
327 } // namespace
329 // Fails, see http://crbug.com/7721.
330 IN_PROC_BROWSER_TEST_F(PrintingLayoutTextTest, DISABLED_Complex) {
331 if (IsTestCaseDisabled())
332 return;
334 DismissTheWindow dismisser;
335 base::DelegateSimpleThread close_printdlg_thread(&dismisser,
336 "close_printdlg_thread");
338 // Print a document, check its output.
339 ASSERT_TRUE(test_server()->Start());
341 ui_test_utils::NavigateToURL(
342 browser(), test_server()->GetURL("files/printing/test1.html"));
343 close_printdlg_thread.Start();
344 PrintNowTab();
345 close_printdlg_thread.Join();
346 EXPECT_EQ(0., CompareWithResult(L"test1"));
349 struct TestPool {
350 const char* source;
351 const wchar_t* result;
354 const TestPool kTestPool[] = {
355 // ImagesB&W
356 "files/printing/test2.html", L"test2",
357 // ImagesTransparent
358 "files/printing/test3.html", L"test3",
359 // ImageColor
360 "files/printing/test4.html", L"test4",
363 // http://crbug.com/7721
364 IN_PROC_BROWSER_TEST_F(PrintingLayoutTest, DISABLED_ManyTimes) {
365 if (IsTestCaseDisabled())
366 return;
368 ASSERT_TRUE(test_server()->Start());
370 DismissTheWindow dismisser;
372 ASSERT_GT(arraysize(kTestPool), 0u);
373 for (int i = 0; i < arraysize(kTestPool); ++i) {
374 if (i)
375 CleanupDumpDirectory();
376 const TestPool& test = kTestPool[i % arraysize(kTestPool)];
377 ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(test.source));
378 base::DelegateSimpleThread close_printdlg_thread1(&dismisser,
379 "close_printdlg_thread");
380 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
381 close_printdlg_thread1.Start();
382 PrintNowTab();
383 close_printdlg_thread1.Join();
384 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
385 CleanupDumpDirectory();
386 base::DelegateSimpleThread close_printdlg_thread2(&dismisser,
387 "close_printdlg_thread");
388 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
389 close_printdlg_thread2.Start();
390 PrintNowTab();
391 close_printdlg_thread2.Join();
392 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
393 CleanupDumpDirectory();
394 base::DelegateSimpleThread close_printdlg_thread3(&dismisser,
395 "close_printdlg_thread");
396 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
397 close_printdlg_thread3.Start();
398 PrintNowTab();
399 close_printdlg_thread3.Join();
400 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
401 CleanupDumpDirectory();
402 base::DelegateSimpleThread close_printdlg_thread4(&dismisser,
403 "close_printdlg_thread");
404 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process()));
405 close_printdlg_thread4.Start();
406 PrintNowTab();
407 close_printdlg_thread4.Join();
408 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result;
412 // Prints a popup and immediately closes it. Disabled because it crashes.
413 IN_PROC_BROWSER_TEST_F(PrintingLayoutTest, DISABLED_Delayed) {
414 if (IsTestCaseDisabled())
415 return;
417 ASSERT_TRUE(test_server()->Start());
420 bool is_timeout = true;
421 GURL url = test_server()->GetURL("files/printing/popup_delayed_print.htm");
422 ui_test_utils::NavigateToURL(browser(), url);
424 DismissTheWindow dismisser;
425 base::DelegateSimpleThread close_printdlg_thread(&dismisser,
426 "close_printdlg_thread");
427 close_printdlg_thread.Start();
428 close_printdlg_thread.Join();
430 // Force a navigation elsewhere to verify that it's fine with it.
431 url = test_server()->GetURL("files/printing/test1.html");
432 ui_test_utils::NavigateToURL(browser(), url);
434 chrome::CloseWindow(browser());
435 content::RunAllPendingInMessageLoop();
437 EXPECT_EQ(0., CompareWithResult(L"popup_delayed_print"))
438 << L"popup_delayed_print";
441 // Prints a popup and immediately closes it. http://crbug.com/7721
442 IN_PROC_BROWSER_TEST_F(PrintingLayoutTest, DISABLED_IFrame) {
443 if (IsTestCaseDisabled())
444 return;
446 ASSERT_TRUE(test_server()->Start());
449 GURL url = test_server()->GetURL("files/printing/iframe.htm");
450 ui_test_utils::NavigateToURL(browser(), url);
452 DismissTheWindow dismisser;
453 base::DelegateSimpleThread close_printdlg_thread(&dismisser,
454 "close_printdlg_thread");
455 close_printdlg_thread.Start();
456 close_printdlg_thread.Join();
458 // Force a navigation elsewhere to verify that it's fine with it.
459 url = test_server()->GetURL("files/printing/test1.html");
460 ui_test_utils::NavigateToURL(browser(), url);
462 chrome::CloseWindow(browser());
463 content::RunAllPendingInMessageLoop();
465 EXPECT_EQ(0., CompareWithResult(L"iframe")) << L"iframe";