OLD | NEW |
| (Empty) |
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 "base/command_line.h" | |
6 #include "base/file_path.h" | |
7 #include "base/file_util.h" | |
8 #include "base/process_util.h" | |
9 #include "base/string_util.h" | |
10 #include "base/test/test_file_util.h" | |
11 #include "base/threading/simple_thread.h" | |
12 #include "base/utf_string_conversions.h" | |
13 #include "chrome/test/automation/tab_proxy.h" | |
14 #include "chrome/test/ui/ui_test.h" | |
15 #include "net/test/test_server.h" | |
16 #include "printing/image.h" | |
17 #include "printing/printing_test.h" | |
18 | |
19 namespace { | |
20 | |
21 using printing::Image; | |
22 | |
23 const char kGenerateSwitch[] = "print-layout-generate"; | |
24 const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data"); | |
25 | |
26 class PrintingLayoutTest : public PrintingTest<UITest> { | |
27 public: | |
28 PrintingLayoutTest() { | |
29 emf_path_ = browser_directory_.AppendASCII("metafile_dumps"); | |
30 launch_arguments_.AppendSwitchPath("debug-print", emf_path_); | |
31 show_window_ = true; | |
32 } | |
33 | |
34 virtual void SetUp() { | |
35 // Make sure there is no left overs. | |
36 CleanupDumpDirectory(); | |
37 UITest::SetUp(); | |
38 } | |
39 | |
40 virtual void TearDown() { | |
41 UITest::TearDown(); | |
42 file_util::Delete(emf_path_, true); | |
43 } | |
44 | |
45 protected: | |
46 void PrintNowTab() { | |
47 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); | |
48 ASSERT_TRUE(tab_proxy.get()); | |
49 ASSERT_TRUE(tab_proxy->PrintNow()); | |
50 } | |
51 | |
52 // Finds the dump for the last print job and compares it to the data named | |
53 // |verification_name|. Compares the saved printed job pixels with the test | |
54 // data pixels and returns the percentage of different pixels; 0 for success, | |
55 // [0, 100] for failure. | |
56 double CompareWithResult(const std::wstring& verification_name) { | |
57 FilePath test_result(ScanFiles(verification_name)); | |
58 if (test_result.value().empty()) { | |
59 // 100% different, the print job buffer is not there. | |
60 return 100.; | |
61 } | |
62 | |
63 FilePath base_path(test_data_directory_.AppendASCII("printing")); | |
64 FilePath emf(base_path.Append(verification_name + L".emf")); | |
65 FilePath png(base_path.Append(verification_name + L".png")); | |
66 | |
67 FilePath cleartype(base_path.Append(verification_name + L"_cleartype.png")); | |
68 // Looks for Cleartype override. | |
69 if (file_util::PathExists(cleartype) && IsClearTypeEnabled()) | |
70 png = cleartype; | |
71 | |
72 if (GenerateFiles()) { | |
73 // Copy the .emf and generate an .png. | |
74 file_util::CopyFile(test_result, emf); | |
75 Image emf_content(emf); | |
76 emf_content.SaveToPng(png); | |
77 // Saving is always fine. | |
78 return 0; | |
79 } else { | |
80 // File compare between test and result. | |
81 Image emf_content(emf); | |
82 Image test_content(test_result); | |
83 Image png_content(png); | |
84 double diff_emf = emf_content.PercentageDifferent(test_content); | |
85 | |
86 EXPECT_EQ(0., diff_emf) << WideToUTF8(verification_name) << | |
87 " original size:" << emf_content.size().ToString() << | |
88 " result size:" << test_content.size().ToString(); | |
89 if (diff_emf) { | |
90 // Backup the result emf file. | |
91 FilePath failed(base_path.Append(verification_name + L"_failed.emf")); | |
92 file_util::CopyFile(test_result, failed); | |
93 } | |
94 | |
95 // This verification is only to know that the EMF rendering stays | |
96 // immutable. | |
97 double diff_png = emf_content.PercentageDifferent(png_content); | |
98 EXPECT_EQ(0., diff_png) << WideToUTF8(verification_name) << | |
99 " original size:" << emf_content.size().ToString() << | |
100 " result size:" << test_content.size().ToString(); | |
101 if (diff_png) { | |
102 // Backup the rendered emf file to detect the rendering difference. | |
103 FilePath rendering( | |
104 base_path.Append(verification_name + L"_rendering.png")); | |
105 emf_content.SaveToPng(rendering); | |
106 } | |
107 return std::max(diff_png, diff_emf); | |
108 } | |
109 } | |
110 | |
111 // Makes sure the directory exists and is empty. | |
112 void CleanupDumpDirectory() { | |
113 EXPECT_TRUE(file_util::DieFileDie(emf_path(), true)); | |
114 EXPECT_TRUE(file_util::CreateDirectory(emf_path())); | |
115 } | |
116 | |
117 // Returns if Clear Type is currently enabled. | |
118 static bool IsClearTypeEnabled() { | |
119 BOOL ct_enabled = 0; | |
120 if (SystemParametersInfo(SPI_GETCLEARTYPE, 0, &ct_enabled, 0) && ct_enabled) | |
121 return true; | |
122 UINT smoothing = 0; | |
123 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothing, 0) && | |
124 smoothing == FE_FONTSMOOTHINGCLEARTYPE) | |
125 return true; | |
126 return false; | |
127 } | |
128 | |
129 private: | |
130 // Verifies that there is one .emf and one .prn file in the dump directory. | |
131 // Returns the path of the .emf file and deletes the .prn file. | |
132 std::wstring ScanFiles(const std::wstring& verification_name) { | |
133 // Try to 10 seconds. | |
134 std::wstring emf_file; | |
135 std::wstring prn_file; | |
136 bool found_emf = false; | |
137 bool found_prn = false; | |
138 for (int i = 0; i < 100; ++i) { | |
139 file_util::FileEnumerator enumerator(emf_path(), false, | |
140 file_util::FileEnumerator::FILES); | |
141 emf_file.clear(); | |
142 prn_file.clear(); | |
143 found_emf = false; | |
144 found_prn = false; | |
145 FilePath file; | |
146 while (!(file = enumerator.Next()).empty()) { | |
147 std::wstring ext = file.Extension(); | |
148 if (base::strcasecmp(WideToUTF8(ext).c_str(), ".emf") == 0) { | |
149 EXPECT_FALSE(found_emf) << "Found a leftover .EMF file: \"" << | |
150 emf_file << "\" and \"" << file.value() << | |
151 "\" when looking for \"" << verification_name << "\""; | |
152 found_emf = true; | |
153 emf_file = file.value(); | |
154 continue; | |
155 } | |
156 if (base::strcasecmp(WideToUTF8(ext).c_str(), ".prn") == 0) { | |
157 EXPECT_FALSE(found_prn) << "Found a leftover .PRN file: \"" << | |
158 prn_file << "\" and \"" << file.value() << | |
159 "\" when looking for \"" << verification_name << "\""; | |
160 prn_file = file.value(); | |
161 found_prn = true; | |
162 file_util::Delete(file, false); | |
163 continue; | |
164 } | |
165 EXPECT_TRUE(false); | |
166 } | |
167 if (found_emf && found_prn) | |
168 break; | |
169 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); | |
170 } | |
171 EXPECT_TRUE(found_emf) << ".PRN file is: " << prn_file; | |
172 EXPECT_TRUE(found_prn) << ".EMF file is: " << emf_file; | |
173 return emf_file; | |
174 } | |
175 | |
176 static bool GenerateFiles() { | |
177 return CommandLine::ForCurrentProcess()->HasSwitch(kGenerateSwitch); | |
178 } | |
179 | |
180 const FilePath& emf_path() const { return emf_path_; } | |
181 | |
182 FilePath emf_path_; | |
183 | |
184 DISALLOW_COPY_AND_ASSIGN(PrintingLayoutTest); | |
185 }; | |
186 | |
187 // Tests that don't need UI access. | |
188 class PrintingLayoutTestHidden : public PrintingLayoutTest { | |
189 public: | |
190 PrintingLayoutTestHidden() { | |
191 show_window_ = false; | |
192 } | |
193 }; | |
194 | |
195 class PrintingLayoutTextTest : public PrintingLayoutTest { | |
196 typedef PrintingLayoutTest Parent; | |
197 public: | |
198 // Returns if the test is disabled. | |
199 // http://crbug.com/64869 Until the issue is fixed, disable the test if | |
200 // ClearType is enabled. | |
201 static bool IsTestCaseDisabled() { | |
202 return Parent::IsTestCaseDisabled() || IsClearTypeEnabled(); | |
203 } | |
204 }; | |
205 | |
206 // Finds the first dialog window owned by owner_process. | |
207 HWND FindDialogWindow(DWORD owner_process) { | |
208 HWND dialog_window(NULL); | |
209 for (;;) { | |
210 dialog_window = FindWindowEx(NULL, | |
211 dialog_window, | |
212 MAKEINTATOM(32770), | |
213 NULL); | |
214 if (!dialog_window) | |
215 break; | |
216 | |
217 // The dialog must be owned by our target process. | |
218 DWORD process_id = 0; | |
219 GetWindowThreadProcessId(dialog_window, &process_id); | |
220 if (process_id == owner_process) | |
221 break; | |
222 } | |
223 return dialog_window; | |
224 } | |
225 | |
226 // Tries to close a dialog window. | |
227 bool CloseDialogWindow(HWND dialog_window) { | |
228 LRESULT res = SendMessage(dialog_window, DM_GETDEFID, 0, 0); | |
229 if (!res) | |
230 return false; | |
231 EXPECT_EQ(DC_HASDEFID, HIWORD(res)); | |
232 WORD print_button_id = LOWORD(res); | |
233 res = SendMessage( | |
234 dialog_window, | |
235 WM_COMMAND, | |
236 print_button_id, | |
237 reinterpret_cast<LPARAM>(GetDlgItem(dialog_window, print_button_id))); | |
238 return res == 0; | |
239 } | |
240 | |
241 // Dismiss the first dialog box owned by owner_process by "executing" the | |
242 // default button. | |
243 class DismissTheWindow : public base::DelegateSimpleThread::Delegate { | |
244 public: | |
245 explicit DismissTheWindow(DWORD owner_process) | |
246 : owner_process_(owner_process) { | |
247 } | |
248 | |
249 virtual void Run() { | |
250 HWND dialog_window; | |
251 for (;;) { | |
252 // First enumerate the windows. | |
253 dialog_window = FindDialogWindow(owner_process_); | |
254 | |
255 // Try to close it. | |
256 if (dialog_window) { | |
257 if (CloseDialogWindow(dialog_window)) { | |
258 break; | |
259 } | |
260 } | |
261 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); | |
262 } | |
263 | |
264 // Now verify that it indeed closed itself. | |
265 while (IsWindow(dialog_window)) { | |
266 CloseDialogWindow(dialog_window); | |
267 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); | |
268 } | |
269 } | |
270 | |
271 DWORD owner_process() { return owner_process_; } | |
272 | |
273 private: | |
274 DWORD owner_process_; | |
275 }; | |
276 | |
277 } // namespace | |
278 | |
279 // Fails, see http://crbug.com/7721. | |
280 TEST_F(PrintingLayoutTextTest, DISABLED_Complex) { | |
281 if (IsTestCaseDisabled()) | |
282 return; | |
283 | |
284 DismissTheWindow dismisser(base::GetProcId(process())); | |
285 base::DelegateSimpleThread close_printdlg_thread(&dismisser, | |
286 "close_printdlg_thread"); | |
287 | |
288 // Print a document, check its output. | |
289 net::TestServer test_server(net::TestServer::TYPE_HTTP, | |
290 net::TestServer::kLocalhost, | |
291 FilePath(kDocRoot)); | |
292 ASSERT_TRUE(test_server.Start()); | |
293 | |
294 NavigateToURL(test_server.GetURL("files/printing/test1.html")); | |
295 close_printdlg_thread.Start(); | |
296 PrintNowTab(); | |
297 close_printdlg_thread.Join(); | |
298 EXPECT_EQ(0., CompareWithResult(L"test1")); | |
299 } | |
300 | |
301 struct TestPool { | |
302 const char* source; | |
303 const wchar_t* result; | |
304 }; | |
305 | |
306 const TestPool kTestPool[] = { | |
307 // ImagesB&W | |
308 "files/printing/test2.html", L"test2", | |
309 // ImagesTransparent | |
310 "files/printing/test3.html", L"test3", | |
311 // ImageColor | |
312 "files/printing/test4.html", L"test4", | |
313 }; | |
314 | |
315 // http://crbug.com/7721 | |
316 TEST_F(PrintingLayoutTestHidden, DISABLED_ManyTimes) { | |
317 if (IsTestCaseDisabled()) | |
318 return; | |
319 | |
320 net::TestServer test_server(net::TestServer::TYPE_HTTP, | |
321 net::TestServer::kLocalhost, | |
322 FilePath(kDocRoot)); | |
323 ASSERT_TRUE(test_server.Start()); | |
324 | |
325 DismissTheWindow dismisser(base::GetProcId(process())); | |
326 | |
327 ASSERT_GT(arraysize(kTestPool), 0u); | |
328 for (int i = 0; i < arraysize(kTestPool); ++i) { | |
329 if (i) | |
330 CleanupDumpDirectory(); | |
331 const TestPool& test = kTestPool[i % arraysize(kTestPool)]; | |
332 NavigateToURL(test_server.GetURL(test.source)); | |
333 base::DelegateSimpleThread close_printdlg_thread1(&dismisser, | |
334 "close_printdlg_thread"); | |
335 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process())); | |
336 close_printdlg_thread1.Start(); | |
337 PrintNowTab(); | |
338 close_printdlg_thread1.Join(); | |
339 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result; | |
340 CleanupDumpDirectory(); | |
341 base::DelegateSimpleThread close_printdlg_thread2(&dismisser, | |
342 "close_printdlg_thread"); | |
343 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process())); | |
344 close_printdlg_thread2.Start(); | |
345 PrintNowTab(); | |
346 close_printdlg_thread2.Join(); | |
347 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result; | |
348 CleanupDumpDirectory(); | |
349 base::DelegateSimpleThread close_printdlg_thread3(&dismisser, | |
350 "close_printdlg_thread"); | |
351 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process())); | |
352 close_printdlg_thread3.Start(); | |
353 PrintNowTab(); | |
354 close_printdlg_thread3.Join(); | |
355 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result; | |
356 CleanupDumpDirectory(); | |
357 base::DelegateSimpleThread close_printdlg_thread4(&dismisser, | |
358 "close_printdlg_thread"); | |
359 EXPECT_EQ(NULL, FindDialogWindow(dismisser.owner_process())); | |
360 close_printdlg_thread4.Start(); | |
361 PrintNowTab(); | |
362 close_printdlg_thread4.Join(); | |
363 EXPECT_EQ(0., CompareWithResult(test.result)) << test.result; | |
364 } | |
365 } | |
366 | |
367 // Prints a popup and immediately closes it. Disabled because it crashes. | |
368 TEST_F(PrintingLayoutTest, DISABLED_Delayed) { | |
369 if (IsTestCaseDisabled()) | |
370 return; | |
371 | |
372 net::TestServer test_server(net::TestServer::TYPE_HTTP, | |
373 net::TestServer::kLocalhost, | |
374 FilePath(kDocRoot)); | |
375 ASSERT_TRUE(test_server.Start()); | |
376 | |
377 { | |
378 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); | |
379 ASSERT_TRUE(tab_proxy.get()); | |
380 bool is_timeout = true; | |
381 GURL url = test_server.GetURL("files/printing/popup_delayed_print.htm"); | |
382 EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, | |
383 tab_proxy->NavigateToURL(url)); | |
384 | |
385 DismissTheWindow dismisser(base::GetProcId(process())); | |
386 base::DelegateSimpleThread close_printdlg_thread(&dismisser, | |
387 "close_printdlg_thread"); | |
388 close_printdlg_thread.Start(); | |
389 close_printdlg_thread.Join(); | |
390 | |
391 // Force a navigation elsewhere to verify that it's fine with it. | |
392 url = test_server.GetURL("files/printing/test1.html"); | |
393 EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, | |
394 tab_proxy->NavigateToURL(url)); | |
395 } | |
396 CloseBrowserAndServer(); | |
397 | |
398 EXPECT_EQ(0., CompareWithResult(L"popup_delayed_print")) | |
399 << L"popup_delayed_print"; | |
400 } | |
401 | |
402 // Prints a popup and immediately closes it. http://crbug.com/7721 | |
403 TEST_F(PrintingLayoutTest, DISABLED_IFrame) { | |
404 if (IsTestCaseDisabled()) | |
405 return; | |
406 | |
407 net::TestServer test_server(net::TestServer::TYPE_HTTP, | |
408 net::TestServer::kLocalhost, | |
409 FilePath(kDocRoot)); | |
410 ASSERT_TRUE(test_server.Start()); | |
411 | |
412 { | |
413 scoped_refptr<TabProxy> tab_proxy(GetActiveTab()); | |
414 ASSERT_TRUE(tab_proxy.get()); | |
415 GURL url = test_server.GetURL("files/printing/iframe.htm"); | |
416 EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, | |
417 tab_proxy->NavigateToURL(url)); | |
418 | |
419 DismissTheWindow dismisser(base::GetProcId(process())); | |
420 base::DelegateSimpleThread close_printdlg_thread(&dismisser, | |
421 "close_printdlg_thread"); | |
422 close_printdlg_thread.Start(); | |
423 close_printdlg_thread.Join(); | |
424 | |
425 // Force a navigation elsewhere to verify that it's fine with it. | |
426 url = test_server.GetURL("files/printing/test1.html"); | |
427 EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, | |
428 tab_proxy->NavigateToURL(url)); | |
429 } | |
430 CloseBrowserAndServer(); | |
431 | |
432 EXPECT_EQ(0., CompareWithResult(L"iframe")) << L"iframe"; | |
433 } | |
OLD | NEW |