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/memory/scoped_ptr.h"
6#include "base/run_loop.h"
7#include "chrome/browser/printing/print_preview_dialog_controller.h"
8#include "chrome/browser/ui/browser.h"
9#include "chrome/browser/ui/browser_commands.h"
10#include "chrome/browser/ui/tabs/tab_strip_model.h"
11#include "chrome/common/print_messages.h"
12#include "chrome/common/url_constants.h"
13#include "chrome/test/base/in_process_browser_test.h"
14#include "chrome/test/base/ui_test_utils.h"
15#include "content/public/browser/web_contents_observer.h"
16#include "content/public/test/browser_test_utils.h"
17#include "url/gurl.h"
18#include "ipc/ipc_message_macros.h"
19
20using content::WebContents;
21using content::WebContentsObserver;
22
23class RequestPrintPreviewObserver : public WebContentsObserver {
24 public:
25  explicit RequestPrintPreviewObserver(WebContents* dialog)
26      : WebContentsObserver(dialog) {
27  }
28  virtual ~RequestPrintPreviewObserver() {}
29
30  void set_quit_closure(const base::Closure& quit_closure) {
31    quit_closure_ = quit_closure;
32  }
33
34 private:
35  // content::WebContentsObserver implementation.
36  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
37    IPC_BEGIN_MESSAGE_MAP(RequestPrintPreviewObserver, message)
38      IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview,
39                          OnRequestPrintPreview)
40      IPC_MESSAGE_UNHANDLED(break;)
41    IPC_END_MESSAGE_MAP();
42    return false;  // Report not handled so the real handler receives it.
43  }
44
45  void OnRequestPrintPreview(
46      const PrintHostMsg_RequestPrintPreview_Params& /* params */) {
47    base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
48  }
49
50  base::Closure quit_closure_;
51
52  DISALLOW_COPY_AND_ASSIGN(RequestPrintPreviewObserver);
53};
54
55class PrintPreviewDialogClonedObserver : public WebContentsObserver {
56 public:
57  explicit PrintPreviewDialogClonedObserver(WebContents* dialog)
58      : WebContentsObserver(dialog) {
59  }
60  virtual ~PrintPreviewDialogClonedObserver() {}
61
62  RequestPrintPreviewObserver* request_preview_dialog_observer() {
63    return request_preview_dialog_observer_.get();
64  }
65
66 private:
67  // content::WebContentsObserver implementation.
68  virtual void DidCloneToNewWebContents(
69      WebContents* old_web_contents,
70      WebContents* new_web_contents) OVERRIDE {
71    request_preview_dialog_observer_.reset(
72        new RequestPrintPreviewObserver(new_web_contents));
73  }
74
75  scoped_ptr<RequestPrintPreviewObserver> request_preview_dialog_observer_;
76
77  DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogClonedObserver);
78};
79
80class PrintPreviewDialogDestroyedObserver : public WebContentsObserver {
81 public:
82  explicit PrintPreviewDialogDestroyedObserver(WebContents* dialog)
83      : WebContentsObserver(dialog),
84        dialog_destroyed_(false) {
85  }
86  virtual ~PrintPreviewDialogDestroyedObserver() {}
87
88  bool dialog_destroyed() const { return dialog_destroyed_; }
89
90 private:
91  // content::WebContentsObserver implementation.
92  virtual void WebContentsDestroyed() OVERRIDE {
93    dialog_destroyed_ = true;
94  }
95
96  bool dialog_destroyed_;
97
98  DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDestroyedObserver);
99};
100
101class PrintPreviewDialogControllerBrowserTest : public InProcessBrowserTest {
102 public:
103  PrintPreviewDialogControllerBrowserTest() : initiator_(NULL) {}
104  virtual ~PrintPreviewDialogControllerBrowserTest() {}
105
106  WebContents* initiator() {
107    return initiator_;
108  }
109
110  void PrintPreview() {
111    base::RunLoop run_loop;
112    request_preview_dialog_observer()->set_quit_closure(run_loop.QuitClosure());
113    chrome::Print(browser());
114    run_loop.Run();
115  }
116
117  WebContents* GetPrintPreviewDialog() {
118    printing::PrintPreviewDialogController* dialog_controller =
119        printing::PrintPreviewDialogController::GetInstance();
120    return dialog_controller->GetPrintPreviewForContents(initiator_);
121  }
122
123 private:
124  virtual void SetUpOnMainThread() OVERRIDE {
125    WebContents* first_tab =
126        browser()->tab_strip_model()->GetActiveWebContents();
127    ASSERT_TRUE(first_tab);
128
129    // Open a new tab so |cloned_tab_observer_| can see it first and attach a
130    // RequestPrintPreviewObserver to it before the real
131    // PrintPreviewMessageHandler gets created. Thus enabling
132    // RequestPrintPreviewObserver to get messages first for the purposes of
133    // this test.
134    cloned_tab_observer_.reset(new PrintPreviewDialogClonedObserver(first_tab));
135    chrome::DuplicateTab(browser());
136
137    initiator_ = browser()->tab_strip_model()->GetActiveWebContents();
138    ASSERT_TRUE(initiator_);
139    ASSERT_NE(first_tab, initiator_);
140  }
141
142  virtual void TearDownOnMainThread() OVERRIDE {
143    cloned_tab_observer_.reset();
144    initiator_ = NULL;
145  }
146
147  RequestPrintPreviewObserver* request_preview_dialog_observer() {
148    return cloned_tab_observer_->request_preview_dialog_observer();
149  }
150
151  scoped_ptr<PrintPreviewDialogClonedObserver> cloned_tab_observer_;
152  WebContents* initiator_;
153
154  DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogControllerBrowserTest);
155};
156
157// Test to verify that when a initiator navigates, we can create a new preview
158// dialog for the new tab contents.
159// http://crbug.com/377337
160#if defined(OS_WIN)
161#define MAYBE_NavigateFromInitiatorTab DISABLED_NavigateFromInitiatorTab
162#else
163#define MAYBE_NavigateFromInitiatorTab NavigateFromInitiatorTab
164#endif
165IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest,
166                       MAYBE_NavigateFromInitiatorTab) {
167  // print for the first time.
168  PrintPreview();
169
170  // Get the preview dialog for the initiator tab.
171  WebContents* preview_dialog = GetPrintPreviewDialog();
172
173  // Check a new print preview dialog got created.
174  ASSERT_TRUE(preview_dialog);
175  ASSERT_NE(initiator(), preview_dialog);
176
177  // Navigate in the initiator tab. Make sure navigating destroys the print
178  // preview dialog.
179  PrintPreviewDialogDestroyedObserver dialog_destroyed_observer(preview_dialog);
180  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
181  ASSERT_TRUE(dialog_destroyed_observer.dialog_destroyed());
182
183  // Try printing again.
184  PrintPreview();
185
186  // Get the print preview dialog for the initiator tab.
187  WebContents* new_preview_dialog = GetPrintPreviewDialog();
188
189  // Check a new preview dialog got created.
190  EXPECT_TRUE(new_preview_dialog);
191}
192
193// Test to verify that after reloading the initiator, it creates a new print
194// preview dialog.
195// http://crbug.com/377337
196#if defined(OS_WIN)
197#define MAYBE_ReloadInitiatorTab DISABLED_ReloadInitiatorTab
198#else
199#define MAYBE_ReloadInitiatorTab ReloadInitiatorTab
200#endif
201IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest,
202                       MAYBE_ReloadInitiatorTab) {
203  // print for the first time.
204  PrintPreview();
205
206  WebContents* preview_dialog = GetPrintPreviewDialog();
207
208  // Check a new print preview dialog got created.
209  ASSERT_TRUE(preview_dialog);
210  ASSERT_NE(initiator(), preview_dialog);
211
212  // Reload the initiator. Make sure reloading destroys the print preview
213  // dialog.
214  PrintPreviewDialogDestroyedObserver dialog_destroyed_observer(preview_dialog);
215  chrome::Reload(browser(), CURRENT_TAB);
216  content::WaitForLoadStop(
217      browser()->tab_strip_model()->GetActiveWebContents());
218  ASSERT_TRUE(dialog_destroyed_observer.dialog_destroyed());
219
220  // Try printing again.
221  PrintPreview();
222
223  // Create a preview dialog for the initiator tab.
224  WebContents* new_preview_dialog = GetPrintPreviewDialog();
225  EXPECT_TRUE(new_preview_dialog);
226}
227