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#import <Carbon/Carbon.h>
6#import <Cocoa/Cocoa.h>
7#import <Foundation/Foundation.h>
8#import <Foundation/NSAppleEventDescriptor.h>
9#import <objc/message.h>
10#import <objc/runtime.h>
11#include <stddef.h>
12
13#include "base/bind.h"
14#include "base/callback_helpers.h"
15#include "base/command_line.h"
16#include "base/mac/foundation_util.h"
17#include "base/mac/scoped_nsobject.h"
18#include "base/run_loop.h"
19#include "base/strings/string16.h"
20#include "base/strings/sys_string_conversions.h"
21#include "base/strings/utf_string_conversions.h"
22#include "base/test/scoped_feature_list.h"
23#include "base/threading/thread_restrictions.h"
24#include "chrome/app/chrome_command_ids.h"
25#import "chrome/browser/app_controller_mac.h"
26#include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
27#include "chrome/browser/bookmarks/bookmark_model_factory.h"
28#include "chrome/browser/browser_process.h"
29#include "chrome/browser/history/history_service_factory.h"
30#include "chrome/browser/lifetime/application_lifetime.h"
31#include "chrome/browser/profiles/profile_attributes_entry.h"
32#include "chrome/browser/profiles/profile_attributes_storage.h"
33#include "chrome/browser/profiles/profile_manager.h"
34#include "chrome/browser/signin/signin_util.h"
35#include "chrome/browser/ui/browser.h"
36#include "chrome/browser/ui/browser_finder.h"
37#include "chrome/browser/ui/browser_list.h"
38#include "chrome/browser/ui/browser_navigator_params.h"
39#include "chrome/browser/ui/browser_window.h"
40#include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
41#include "chrome/browser/ui/cocoa/history_menu_bridge.h"
42#include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
43#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
44#include "chrome/browser/ui/profile_picker.h"
45#include "chrome/browser/ui/search/local_ntp_test_utils.h"
46#include "chrome/browser/ui/tabs/tab_strip_model.h"
47#include "chrome/browser/ui/ui_features.h"
48#include "chrome/browser/ui/user_manager.h"
49#include "chrome/browser/ui/webui/welcome/helpers.h"
50#include "chrome/common/chrome_constants.h"
51#include "chrome/common/chrome_switches.h"
52#include "chrome/common/pref_names.h"
53#include "chrome/common/url_constants.h"
54#include "chrome/test/base/in_process_browser_test.h"
55#include "chrome/test/base/ui_test_utils.h"
56#include "components/account_id/account_id.h"
57#include "components/bookmarks/browser/bookmark_model.h"
58#include "components/bookmarks/test/bookmark_test_helpers.h"
59#include "components/prefs/pref_service.h"
60#include "content/public/browser/navigation_controller.h"
61#include "content/public/browser/web_contents.h"
62#include "content/public/test/browser_test.h"
63#include "content/public/test/browser_test_utils.h"
64#include "content/public/test/test_navigation_observer.h"
65#include "extensions/browser/app_window/app_window_registry.h"
66#include "extensions/common/extension.h"
67#include "extensions/test/extension_test_message_listener.h"
68#include "net/test/embedded_test_server/embedded_test_server.h"
69#import "ui/events/test/cocoa_test_event_utils.h"
70
71using base::SysUTF16ToNSString;
72
73@interface AppController (ForTesting)
74- (void)getUrl:(NSAppleEventDescriptor*)event
75     withReply:(NSAppleEventDescriptor*)reply;
76@end
77
78namespace {
79
80GURL g_open_shortcut_url = GURL::EmptyGURL();
81
82// Returns an Apple Event that instructs the application to open |url|.
83NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) {
84  NSAppleEventDescriptor* shortcut_event = [[[NSAppleEventDescriptor alloc]
85      initWithEventClass:kASAppleScriptSuite
86                 eventID:kASSubroutineEvent
87        targetDescriptor:nil
88                returnID:kAutoGenerateReturnID
89           transactionID:kAnyTransactionID] autorelease];
90  NSString* url_string = [NSString stringWithUTF8String:url.spec().c_str()];
91  [shortcut_event setParamDescriptor:[NSAppleEventDescriptor
92                                         descriptorWithString:url_string]
93                          forKeyword:keyDirectObject];
94  return shortcut_event;
95}
96
97// Instructs the NSApp's delegate to open |url|.
98void SendAppleEventToOpenUrlToAppController(const GURL& url) {
99  AppController* controller =
100      base::mac::ObjCCast<AppController>([NSApp delegate]);
101  [controller getUrl:AppleEventToOpenUrl(url) withReply:nullptr];
102}
103
104void RunClosureWhenProfileInitialized(const base::RepeatingClosure& closure,
105                                      Profile* profile,
106                                      Profile::CreateStatus status) {
107  // This will be called multiple times. Wait until the profile is initialized
108  // fully to quit the loop.
109  if (status == Profile::CREATE_STATUS_INITIALIZED)
110    closure.Run();
111}
112
113}  // namespace
114
115@interface TestOpenShortcutOnStartup : NSObject
116- (void)applicationWillFinishLaunching:(NSNotification*)notification;
117@end
118
119@implementation TestOpenShortcutOnStartup
120
121- (void)applicationWillFinishLaunching:(NSNotification*)notification {
122  if (!g_open_shortcut_url.is_valid())
123    return;
124
125  SendAppleEventToOpenUrlToAppController(g_open_shortcut_url);
126}
127
128@end
129
130namespace {
131
132using AppControllerBrowserTest = InProcessBrowserTest;
133
134// Returns whether a window's pixels are actually on the screen, which is the
135// case when it and all of its parents are marked visible.
136bool IsReallyVisible(NSWindow* window) {
137  while (window) {
138    if (!window.visible)
139      return false;
140    window = [window parentWindow];
141  }
142  return true;
143}
144
145size_t CountVisibleWindows() {
146  size_t count = 0;
147  for (NSWindow* w in [NSApp windows])
148    count = count + (IsReallyVisible(w) ? 1 : 0);
149  return count;
150}
151
152// Returns how many visible NSWindows are expected for a given count of browser
153// windows.
154size_t ExpectedWindowCountForBrowserCount(size_t browsers) {
155  return browsers;
156}
157
158// Test browser shutdown with a command in the message queue.
159IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, CommandDuringShutdown) {
160  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
161  EXPECT_EQ(ExpectedWindowCountForBrowserCount(1), CountVisibleWindows());
162
163  chrome::AttemptExit();  // Set chrome::IsTryingToQuit and close all windows.
164
165  // Opening a new window here is fine (unload handlers can also interrupt
166  // exit). But closing the window posts an autorelease on
167  // BrowserWindowController, which calls ~Browser() and, if that was the last
168  // Browser, it invokes applicationWillTerminate: (because IsTryingToQuit is
169  // set). So, verify assumptions then process that autorelease.
170
171  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
172  EXPECT_EQ(ExpectedWindowCountForBrowserCount(0), CountVisibleWindows());
173
174  base::RunLoop().RunUntilIdle();
175
176  EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
177  EXPECT_EQ(ExpectedWindowCountForBrowserCount(0), CountVisibleWindows());
178
179  NSEvent* cmd_n = cocoa_test_event_utils::KeyEventWithKeyCode(
180      'n', 'n', NSKeyDown, NSCommandKeyMask);
181  [[NSApp mainMenu] performSelector:@selector(performKeyEquivalent:)
182                         withObject:cmd_n
183                         afterDelay:0];
184  // Let the run loop get flushed, during process cleanup and try not to crash.
185}
186
187class AppControllerPlatformAppBrowserTest
188    : public extensions::PlatformAppBrowserTest {
189 protected:
190  AppControllerPlatformAppBrowserTest()
191      : active_browser_list_(BrowserList::GetInstance()) {}
192
193  void SetUpCommandLine(base::CommandLine* command_line) override {
194    PlatformAppBrowserTest::SetUpCommandLine(command_line);
195    command_line->AppendSwitchASCII(switches::kAppId,
196                                    "1234");
197  }
198
199  const BrowserList* active_browser_list_;
200};
201
202// Test that if only a platform app window is open and no browser windows are
203// open then a reopen event does nothing.
204IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
205                       DISABLED_PlatformAppReopenWithWindows) {
206  AppController* ac = base::mac::ObjCCast<AppController>(
207      [[NSApplication sharedApplication] delegate]);
208  ASSERT_TRUE(ac);
209
210  NSUInteger old_window_count = [[NSApp windows] count];
211  EXPECT_EQ(1u, active_browser_list_->size());
212  [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
213  // We do not EXPECT_TRUE the result here because the method
214  // deminiaturizes windows manually rather than return YES and have
215  // AppKit do it.
216
217  EXPECT_EQ(old_window_count, [[NSApp windows] count]);
218  EXPECT_EQ(1u, active_browser_list_->size());
219}
220
221IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
222                       DISABLED_ActivationFocusesBrowserWindow) {
223  AppController* app_controller = base::mac::ObjCCast<AppController>(
224      [[NSApplication sharedApplication] delegate]);
225  ASSERT_TRUE(app_controller);
226
227  ExtensionTestMessageListener listener("Launched", false);
228  const extensions::Extension* app =
229      InstallAndLaunchPlatformApp("minimal");
230  ASSERT_TRUE(listener.WaitUntilSatisfied());
231
232  NSWindow* app_window = extensions::AppWindowRegistry::Get(profile())
233                             ->GetAppWindowsForApp(app->id())
234                             .front()
235                             ->GetNativeWindow()
236                             .GetNativeNSWindow();
237  NSWindow* browser_window =
238      browser()->window()->GetNativeWindow().GetNativeNSWindow();
239
240  chrome::testing::NSRunLoopRunAllPending();
241  EXPECT_LE([[NSApp orderedWindows] indexOfObject:app_window],
242            [[NSApp orderedWindows] indexOfObject:browser_window]);
243  [app_controller applicationShouldHandleReopen:NSApp
244                              hasVisibleWindows:YES];
245  chrome::testing::NSRunLoopRunAllPending();
246  EXPECT_LE([[NSApp orderedWindows] indexOfObject:browser_window],
247            [[NSApp orderedWindows] indexOfObject:app_window]);
248}
249
250class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
251 protected:
252  AppControllerWebAppBrowserTest()
253      : active_browser_list_(BrowserList::GetInstance()) {}
254
255  void SetUpCommandLine(base::CommandLine* command_line) override {
256    command_line->AppendSwitchASCII(switches::kApp, GetAppURL());
257  }
258
259  std::string GetAppURL() const {
260    return "http://example.com/";
261  }
262
263  const BrowserList* active_browser_list_;
264};
265
266// Test that in web app mode a reopen event opens the app URL.
267IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
268                       WebAppReopenWithNoWindows) {
269  AppController* ac = base::mac::ObjCCast<AppController>(
270      [[NSApplication sharedApplication] delegate]);
271  ASSERT_TRUE(ac);
272
273  EXPECT_EQ(1u, active_browser_list_->size());
274  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
275
276  EXPECT_FALSE(result);
277  EXPECT_EQ(2u, active_browser_list_->size());
278
279  Browser* browser = active_browser_list_->get(0);
280  GURL current_url =
281      browser->tab_strip_model()->GetActiveWebContents()->GetURL();
282  EXPECT_EQ(GetAppURL(), current_url.spec());
283}
284
285// Called when the ProfileManager has created a profile.
286void CreateProfileCallback(const base::RepeatingClosure& quit_closure,
287                           Profile* profile,
288                           Profile::CreateStatus status) {
289  EXPECT_TRUE(profile);
290  EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
291  EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
292  // This will be called multiple times. Wait until the profile is initialized
293  // fully to quit the loop.
294  if (status == Profile::CREATE_STATUS_INITIALIZED)
295    quit_closure.Run();
296}
297
298void CreateAndWaitForSystemProfile() {
299  ProfileManager::CreateCallback create_callback = base::BindRepeating(
300      &CreateProfileCallback,
301      base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
302  g_browser_process->profile_manager()->CreateProfileAsync(
303      ProfileManager::GetSystemProfilePath(),
304      create_callback,
305      base::string16(),
306      std::string());
307  base::RunLoop().Run();
308}
309
310class AppControllerNewProfileManagementBrowserTest
311    : public InProcessBrowserTest {
312 protected:
313  AppControllerNewProfileManagementBrowserTest()
314      : active_browser_list_(BrowserList::GetInstance()) {}
315
316  const BrowserList* active_browser_list_;
317};
318
319// Test that for a regular last profile, a reopen event opens a browser.
320IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
321                       RegularProfileReopenWithNoWindows) {
322  AppController* ac = base::mac::ObjCCast<AppController>(
323      [[NSApplication sharedApplication] delegate]);
324  ASSERT_TRUE(ac);
325
326  EXPECT_EQ(1u, active_browser_list_->size());
327  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
328
329  EXPECT_FALSE(result);
330  EXPECT_EQ(2u, active_browser_list_->size());
331  EXPECT_FALSE(UserManager::IsShowing());
332}
333
334// Test that for a locked last profile, a reopen event opens the User Manager.
335IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
336                       LockedProfileReopenWithNoWindows) {
337  // The User Manager uses the system profile as its underlying profile. To
338  // minimize flakiness due to the scheduling/descheduling of tasks on the
339  // different threads, pre-initialize the guest profile before it is needed.
340  CreateAndWaitForSystemProfile();
341  AppController* ac = base::mac::ObjCCast<AppController>(
342      [[NSApplication sharedApplication] delegate]);
343  ASSERT_TRUE(ac);
344
345  // Lock the active profile.
346  base::ScopedAllowBlockingForTesting allow_blocking;
347  Profile* profile = [ac lastProfile];
348  ProfileAttributesEntry* entry;
349  ASSERT_TRUE(g_browser_process->profile_manager()->
350                  GetProfileAttributesStorage().
351                  GetProfileAttributesWithPath(profile->GetPath(), &entry));
352  entry->SetIsSigninRequired(true);
353  EXPECT_TRUE(entry->IsSigninRequired());
354
355  EXPECT_EQ(1u, active_browser_list_->size());
356  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
357  EXPECT_FALSE(result);
358
359  base::RunLoop().RunUntilIdle();
360  EXPECT_EQ(1u, active_browser_list_->size());
361  EXPECT_TRUE(UserManager::IsShowing());
362  UserManager::Hide();
363}
364
365// Test that for a guest last profile, commandDispatch should open UserManager
366// if guest mode is disabled. Note that this test might be flaky under ASAN
367// due to https://crbug.com/674475. Please disable this test under ASAN
368// as the tests below if that happened.
369IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
370                       OpenGuestProfileOnlyIfGuestModeIsEnabled) {
371  CreateAndWaitForSystemProfile();
372  PrefService* local_state = g_browser_process->local_state();
373  local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
374  local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
375
376  AppController* ac = base::mac::ObjCCast<AppController>(
377      [[NSApplication sharedApplication] delegate]);
378  ASSERT_TRUE(ac);
379
380  base::ScopedAllowBlockingForTesting allow_blocking;
381  Profile* profile = [ac lastProfile];
382  EXPECT_TRUE(profile->IsGuestSession());
383
384  NSMenu* menu = [ac applicationDockMenu:NSApp];
385  ASSERT_TRUE(menu);
386  NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW];
387  ASSERT_TRUE(item);
388  EXPECT_EQ(1u, active_browser_list_->size());
389
390  [ac commandDispatch:item];
391
392  base::RunLoop().RunUntilIdle();
393
394  EXPECT_EQ(1u, active_browser_list_->size());
395  EXPECT_TRUE(UserManager::IsShowing());
396  UserManager::Hide();
397
398  local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, true);
399  [ac commandDispatch:item];
400  base::RunLoop().RunUntilIdle();
401  EXPECT_EQ(2u, active_browser_list_->size());
402  EXPECT_FALSE(UserManager::IsShowing());
403}
404
405// Test that for a guest last profile, a reopen event opens the User Manager.
406IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
407                       GuestProfileReopenWithNoWindows) {
408  // Create the system profile. Set the guest as the last used profile so the
409  // app controller can use it on init.
410  CreateAndWaitForSystemProfile();
411  PrefService* local_state = g_browser_process->local_state();
412  local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
413
414  AppController* ac = base::mac::ObjCCast<AppController>(
415      [[NSApplication sharedApplication] delegate]);
416  ASSERT_TRUE(ac);
417
418  base::ScopedAllowBlockingForTesting allow_blocking;
419  Profile* profile = [ac lastProfile];
420  EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
421  EXPECT_TRUE(profile->IsGuestSession());
422
423  EXPECT_EQ(1u, active_browser_list_->size());
424  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
425  EXPECT_FALSE(result);
426
427  base::RunLoop().RunUntilIdle();
428
429  EXPECT_EQ(1u, active_browser_list_->size());
430  EXPECT_TRUE(UserManager::IsShowing());
431  UserManager::Hide();
432}
433
434IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
435                       AboutChromeForcesUserManager) {
436  AppController* ac = base::mac::ObjCCast<AppController>(
437      [[NSApplication sharedApplication] delegate]);
438  ASSERT_TRUE(ac);
439
440  // Create the guest profile, and set it as the last used profile so the
441  // app controller can use it on init.
442  CreateAndWaitForSystemProfile();
443  PrefService* local_state = g_browser_process->local_state();
444  local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
445
446  // Prohibiting guest mode forces the user manager flow for About Chrome.
447  local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
448
449  base::ScopedAllowBlockingForTesting allow_blocking;
450  Profile* guest_profile = [ac lastProfile];
451  EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath());
452  EXPECT_TRUE(guest_profile->IsGuestSession());
453
454  // Tell the browser to open About Chrome.
455  EXPECT_EQ(1u, active_browser_list_->size());
456  [ac orderFrontStandardAboutPanel:NSApp];
457
458  base::RunLoop().RunUntilIdle();
459
460  // No new browser is opened; the User Manager opens instead.
461  EXPECT_EQ(1u, active_browser_list_->size());
462  EXPECT_TRUE(UserManager::IsShowing());
463
464  UserManager::Hide();
465}
466
467class AppControllerProfilePickerBrowserTest
468    : public AppControllerNewProfileManagementBrowserTest {
469 public:
470  AppControllerProfilePickerBrowserTest() {
471    feature_list_.InitAndEnableFeature(features::kNewProfilePicker);
472  }
473
474  ~AppControllerProfilePickerBrowserTest() override {
475    signin_util::ResetForceSigninForTesting();
476  }
477
478 private:
479  base::test::ScopedFeatureList feature_list_;
480};
481
482// Test that for a regular last profile, a reopen event opens a browser.
483IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
484                       RegularProfileReopenWithNoWindows) {
485  AppController* ac = base::mac::ObjCCastStrict<AppController>(
486      [[NSApplication sharedApplication] delegate]);
487
488  EXPECT_EQ(1u, active_browser_list_->size());
489  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
490
491  EXPECT_FALSE(result);
492  EXPECT_EQ(2u, active_browser_list_->size());
493  EXPECT_FALSE(UserManager::IsShowing());
494  EXPECT_FALSE(ProfilePicker::IsOpen());
495}
496
497// Test that for a locked last profile, a reopen event opens the User Manager,
498// because the profile picker does not support locked profiles yet.
499IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
500                       LockedProfileReopenWithNoWindows) {
501  signin_util::SetForceSigninForTesting(true);
502  // The User Manager uses the system profile as its underlying profile. To
503  // minimize flakiness due to the scheduling/descheduling of tasks on the
504  // different threads, pre-initialize the guest profile before it is needed.
505  CreateAndWaitForSystemProfile();
506  AppController* ac = base::mac::ObjCCastStrict<AppController>(
507      [[NSApplication sharedApplication] delegate]);
508
509  // Lock the active profile.
510  base::ScopedAllowBlockingForTesting allow_blocking;
511  Profile* profile = [ac lastProfile];
512  ProfileAttributesEntry* entry;
513  ASSERT_TRUE(g_browser_process->profile_manager()
514                  ->GetProfileAttributesStorage()
515                  .GetProfileAttributesWithPath(profile->GetPath(), &entry));
516  entry->SetIsSigninRequired(true);
517  EXPECT_TRUE(entry->IsSigninRequired());
518
519  EXPECT_EQ(1u, active_browser_list_->size());
520  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
521  EXPECT_FALSE(result);
522
523  base::RunLoop().RunUntilIdle();
524  EXPECT_EQ(1u, active_browser_list_->size());
525  EXPECT_TRUE(UserManager::IsShowing());
526  UserManager::Hide();
527}
528
529// Test that for a guest last profile, a reopen event opens the ProfilePicker.
530IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
531                       GuestProfileReopenWithNoWindows) {
532  // Create the system profile. Set the guest as the last used profile so the
533  // app controller can use it on init.
534  CreateAndWaitForSystemProfile();
535  PrefService* local_state = g_browser_process->local_state();
536  local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
537
538  AppController* ac = base::mac::ObjCCastStrict<AppController>(
539      [[NSApplication sharedApplication] delegate]);
540
541  base::ScopedAllowBlockingForTesting allow_blocking;
542  Profile* profile = [ac lastProfile];
543  EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
544  EXPECT_TRUE(profile->IsGuestSession());
545
546  EXPECT_EQ(1u, active_browser_list_->size());
547  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
548  EXPECT_FALSE(result);
549
550  base::RunLoop().RunUntilIdle();
551
552  EXPECT_EQ(1u, active_browser_list_->size());
553  EXPECT_TRUE(ProfilePicker::IsOpen());
554  ProfilePicker::Hide();
555}
556
557// Test that the ProfilePicker is shown when there are multiple profiles.
558IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
559                       MultiProfilePickerShown) {
560  CreateAndWaitForSystemProfile();
561  AppController* ac = base::mac::ObjCCastStrict<AppController>(
562      [[NSApplication sharedApplication] delegate]);
563
564  // Add a profile in the cache (simulate another profile on disk).
565  base::ScopedAllowBlockingForTesting allow_blocking;
566  ProfileManager* profile_manager = g_browser_process->profile_manager();
567  ProfileAttributesStorage* profile_storage =
568      &profile_manager->GetProfileAttributesStorage();
569  const base::FilePath profile_path =
570      profile_manager->GenerateNextProfileDirectoryPath();
571  profile_storage->AddProfile(
572      profile_path, base::ASCIIToUTF16("name_1"), "12345", base::string16(),
573      /*is_consented_primary_account=*/false, /*icon_index=*/0,
574      /*supervised_user_id*/ std::string(), EmptyAccountId());
575
576  EXPECT_EQ(1u, active_browser_list_->size());
577  BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
578  EXPECT_FALSE(result);
579
580  base::RunLoop().RunUntilIdle();
581  EXPECT_EQ(1u, active_browser_list_->size());
582  EXPECT_TRUE(ProfilePicker::IsOpen());
583  EXPECT_FALSE(UserManager::IsShowing());
584  ProfilePicker::Hide();
585}
586
587class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
588 protected:
589  AppControllerOpenShortcutBrowserTest() {
590    scoped_feature_list_.InitWithFeatures({welcome::kForceEnabled}, {});
591  }
592
593  void SetUpInProcessBrowserTestFixture() override {
594    // In order to mimic opening shortcut during browser startup, we need to
595    // send the event before -applicationDidFinishLaunching is called, but
596    // after AppController is loaded.
597    //
598    // Since -applicationWillFinishLaunching does nothing now, we swizzle it to
599    // our function to send the event. We need to do this early before running
600    // the main message loop.
601    //
602    // NSApp does not exist yet. We need to get the AppController using
603    // reflection.
604    Class appControllerClass = NSClassFromString(@"AppController");
605    Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup");
606
607    ASSERT_TRUE(appControllerClass != nil);
608    ASSERT_TRUE(openShortcutClass != nil);
609
610    SEL targetMethod = @selector(applicationWillFinishLaunching:);
611    Method original = class_getInstanceMethod(appControllerClass,
612        targetMethod);
613    Method destination = class_getInstanceMethod(openShortcutClass,
614        targetMethod);
615
616    ASSERT_TRUE(original != NULL);
617    ASSERT_TRUE(destination != NULL);
618
619    method_exchangeImplementations(original, destination);
620
621    ASSERT_TRUE(embedded_test_server()->Start());
622    g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html");
623  }
624
625  void SetUpCommandLine(base::CommandLine* command_line) override {
626    // If the arg is empty, PrepareTestCommandLine() after this function will
627    // append about:blank as default url.
628    command_line->AppendArg(chrome::kChromeUINewTabURL);
629  }
630
631 private:
632  base::test::ScopedFeatureList scoped_feature_list_;
633};
634
635IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest,
636                       OpenShortcutOnStartup) {
637  // The two tabs expected are the Welcome page and the desired URL.
638  EXPECT_EQ(2, browser()->tab_strip_model()->count());
639  EXPECT_EQ(g_open_shortcut_url,
640      browser()->tab_strip_model()->GetActiveWebContents()
641          ->GetLastCommittedURL());
642}
643
644class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest {
645 protected:
646  AppControllerReplaceNTPBrowserTest() {}
647
648  void SetUpInProcessBrowserTestFixture() override {
649    ASSERT_TRUE(embedded_test_server()->Start());
650  }
651
652  void SetUpCommandLine(base::CommandLine* command_line) override {
653    // If the arg is empty, PrepareTestCommandLine() after this function will
654    // append about:blank as default url.
655    command_line->AppendArg(chrome::kChromeUINewTabURL);
656  }
657};
658
659// Tests that when a GURL is opened after startup, it replaces the NTP.
660IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest,
661                       ReplaceNTPAfterStartup) {
662  // Depending on network connectivity, the NTP URL can either be
663  // chrome://newtab/ or chrome-search://local-ntp/local-ntp.html. See
664  // local_ntp_test_utils::GetFinalNtpUrl for more details.
665  std::string expected_url =
666      local_ntp_test_utils::GetFinalNtpUrl(browser()->profile()).spec();
667
668  // Ensure that there is exactly 1 tab showing, and the tab is the NTP.
669  GURL ntp(expected_url);
670  EXPECT_EQ(1, browser()->tab_strip_model()->count());
671  browser()->tab_strip_model()->GetActiveWebContents()->GetController().LoadURL(
672      GURL(expected_url), content::Referrer(),
673      ui::PageTransition::PAGE_TRANSITION_LINK, std::string());
674
675  // Wait for one navigation on the active web contents.
676  content::TestNavigationObserver ntp_navigation_observer(
677      browser()->tab_strip_model()->GetActiveWebContents());
678  ntp_navigation_observer.Wait();
679
680  EXPECT_EQ(ntp,
681            browser()
682                ->tab_strip_model()
683                ->GetActiveWebContents()
684                ->GetLastCommittedURL());
685
686  GURL simple(embedded_test_server()->GetURL("/simple.html"));
687  SendAppleEventToOpenUrlToAppController(simple);
688
689  EXPECT_EQ(1, browser()->tab_strip_model()->count());
690  content::TestNavigationObserver event_navigation_observer(
691      browser()->tab_strip_model()->GetActiveWebContents());
692  event_navigation_observer.Wait();
693
694  EXPECT_EQ(simple,
695            browser()
696                ->tab_strip_model()
697                ->GetActiveWebContents()
698                ->GetLastCommittedURL());
699}
700
701// Tests that when a GURL is opened, it is not opened in incognito mode.
702IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, OpenInRegularBrowser) {
703  ASSERT_TRUE(embedded_test_server()->Start());
704  // Create an incognito browser.
705  Browser* incognito_browser = CreateIncognitoBrowser(browser()->profile());
706  EXPECT_EQ(incognito_browser, chrome::GetLastActiveBrowser());
707  EXPECT_EQ(1, browser()->tab_strip_model()->count());
708  EXPECT_EQ(1, incognito_browser->tab_strip_model()->count());
709  // Open a url.
710  GURL simple(embedded_test_server()->GetURL("/simple.html"));
711  SendAppleEventToOpenUrlToAppController(simple);
712  // It should be opened in the regular browser.
713  content::TestNavigationObserver event_navigation_observer(
714      browser()->tab_strip_model()->GetActiveWebContents());
715  event_navigation_observer.Wait();
716  EXPECT_EQ(2, browser()->tab_strip_model()->count());
717  EXPECT_EQ(1, incognito_browser->tab_strip_model()->count());
718  EXPECT_EQ(simple, browser()
719                        ->tab_strip_model()
720                        ->GetActiveWebContents()
721                        ->GetLastCommittedURL());
722}
723
724class AppControllerMainMenuBrowserTest : public InProcessBrowserTest {
725 protected:
726  AppControllerMainMenuBrowserTest() {
727  }
728};
729
730IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
731    HistoryMenuResetAfterProfileDeletion) {
732  ProfileManager* profile_manager = g_browser_process->profile_manager();
733  AppController* ac =
734      base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
735
736  // Use the existing profile as profile 1.
737  Profile* profile1 = browser()->profile();
738
739  // Create profile 2.
740  base::FilePath profile2_path =
741      profile_manager->GenerateNextProfileDirectoryPath();
742  base::RunLoop run_loop;
743  profile_manager->CreateProfileAsync(
744      profile2_path,
745      base::BindRepeating(&RunClosureWhenProfileInitialized,
746                          run_loop.QuitClosure()),
747      base::string16(), std::string());
748  run_loop.Run();
749  Profile* profile2 = profile_manager->GetProfileByPath(profile2_path);
750  ASSERT_TRUE(profile2);
751
752  // Load profile1's History Service backend so it will be assigned to the
753  // HistoryMenuBridge when windowChangedToProfile is called, or else this test
754  // will fail flaky.
755  ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
756      profile1, ServiceAccessType::EXPLICIT_ACCESS));
757  // Switch the controller to profile1.
758  [ac windowChangedToProfile:profile1];
759  base::RunLoop().RunUntilIdle();
760
761  // Verify the controller's History Menu corresponds to profile1.
762  EXPECT_TRUE([ac historyMenuBridge]->service());
763  EXPECT_EQ([ac historyMenuBridge]->service(),
764      HistoryServiceFactory::GetForProfile(profile1,
765                                           ServiceAccessType::EXPLICIT_ACCESS));
766
767  // Load profile2's History Service backend so it will be assigned to the
768  // HistoryMenuBridge when windowChangedToProfile is called, or else this test
769  // will fail flaky.
770  ui_test_utils::WaitForHistoryToLoad(
771      HistoryServiceFactory::GetForProfile(profile2,
772                                           ServiceAccessType::EXPLICIT_ACCESS));
773  // Switch the controller to profile2.
774  [ac windowChangedToProfile:profile2];
775  base::RunLoop().RunUntilIdle();
776
777  // Verify the controller's History Menu has changed.
778  EXPECT_TRUE([ac historyMenuBridge]->service());
779  EXPECT_EQ([ac historyMenuBridge]->service(),
780      HistoryServiceFactory::GetForProfile(profile2,
781                                           ServiceAccessType::EXPLICIT_ACCESS));
782  EXPECT_NE(
783      HistoryServiceFactory::GetForProfile(profile1,
784                                           ServiceAccessType::EXPLICIT_ACCESS),
785      HistoryServiceFactory::GetForProfile(profile2,
786                                           ServiceAccessType::EXPLICIT_ACCESS));
787
788  // Delete profile2.
789  profile_manager->ScheduleProfileForDeletion(profile2->GetPath(),
790                                              base::DoNothing());
791  base::RunLoop().RunUntilIdle();
792
793  // Verify the controller's history is back to profile1.
794  EXPECT_EQ([ac historyMenuBridge]->service(),
795      HistoryServiceFactory::GetForProfile(profile1,
796                                           ServiceAccessType::EXPLICIT_ACCESS));
797}
798
799IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
800    BookmarksMenuIsRestoredAfterProfileSwitch) {
801  ProfileManager* profile_manager = g_browser_process->profile_manager();
802  AppController* ac = base::mac::ObjCCast<AppController>(
803      [[NSApplication sharedApplication] delegate]);
804  ASSERT_TRUE(ac);
805
806  [ac mainMenuCreated];
807
808  // Constants for bookmarks that we will create later.
809  const base::string16 title1(base::ASCIIToUTF16("Dinosaur Comics"));
810  const GURL url1("http://qwantz.com//");
811
812  const base::string16 title2(base::ASCIIToUTF16("XKCD"));
813  const GURL url2("https://www.xkcd.com/");
814
815  // Use the existing profile as profile 1.
816  Profile* profile1 = browser()->profile();
817  bookmarks::test::WaitForBookmarkModelToLoad(
818      BookmarkModelFactory::GetForBrowserContext(profile1));
819
820  // Create profile 2.
821  base::ScopedAllowBlockingForTesting allow_blocking;
822  base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath();
823  std::unique_ptr<Profile> profile2 =
824      Profile::CreateProfile(path2, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
825  Profile* profile2_ptr = profile2.get();
826  profile_manager->RegisterTestingProfile(std::move(profile2), false);
827  bookmarks::test::WaitForBookmarkModelToLoad(
828      BookmarkModelFactory::GetForBrowserContext(profile2_ptr));
829
830  // Switch to profile 1, create bookmark 1 and force the menu to build.
831  [ac windowChangedToProfile:profile1];
832  [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
833      [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
834      0, title1, url1);
835  NSMenu* profile1_submenu = [ac bookmarkMenuBridge]->BookmarkMenu();
836  [[profile1_submenu delegate] menuNeedsUpdate:profile1_submenu];
837
838  // Switch to profile 2, create bookmark 2 and force the menu to build.
839  [ac windowChangedToProfile:profile2_ptr];
840  [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
841      [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
842      0, title2, url2);
843  NSMenu* profile2_submenu = [ac bookmarkMenuBridge]->BookmarkMenu();
844  [[profile2_submenu delegate] menuNeedsUpdate:profile2_submenu];
845  EXPECT_NE(profile1_submenu, profile2_submenu);
846
847  // Test that only bookmark 2 is shown.
848  EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
849      SysUTF16ToNSString(title1)]);
850  EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
851      SysUTF16ToNSString(title2)]);
852
853  // Switch *back* to profile 1 and *don't* force the menu to build.
854  [ac windowChangedToProfile:profile1];
855
856  // Test that only bookmark 1 is shown in the restored menu.
857  EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
858      SysUTF16ToNSString(title1)]);
859  EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
860      SysUTF16ToNSString(title2)]);
861
862  // Ensure a cached menu was used.
863  EXPECT_EQ(profile1_submenu, [ac bookmarkMenuBridge]->BookmarkMenu());
864}
865
866}  // namespace
867
868//--------------------------AppControllerHandoffBrowserTest---------------------
869
870static GURL g_handoff_url;
871
872@interface AppController (BrowserTest)
873- (void)new_passURLToHandoffManager:(const GURL&)handoffURL;
874@end
875
876@implementation AppController (BrowserTest)
877- (void)new_passURLToHandoffManager:(const GURL&)handoffURL {
878  g_handoff_url = handoffURL;
879}
880@end
881
882namespace {
883
884class AppControllerHandoffBrowserTest : public InProcessBrowserTest {
885 protected:
886  AppControllerHandoffBrowserTest() {}
887
888  // Exchanges the implementations of the two selectors on the class
889  // AppController.
890  void ExchangeSelectors(SEL originalMethod, SEL newMethod) {
891    Class appControllerClass = NSClassFromString(@"AppController");
892
893    ASSERT_TRUE(appControllerClass != nil);
894
895    Method original =
896        class_getInstanceMethod(appControllerClass, originalMethod);
897    Method destination = class_getInstanceMethod(appControllerClass, newMethod);
898
899    ASSERT_TRUE(original != NULL);
900    ASSERT_TRUE(destination != NULL);
901
902    method_exchangeImplementations(original, destination);
903  }
904
905  // Swizzle Handoff related implementations.
906  void SetUpInProcessBrowserTestFixture() override {
907    // This swizzle intercepts the URL that would be sent to the Handoff
908    // Manager, and instead puts it into a variable accessible to this test.
909    SEL originalMethod = @selector(passURLToHandoffManager:);
910    SEL newMethod = @selector(new_passURLToHandoffManager:);
911    ExchangeSelectors(originalMethod, newMethod);
912  }
913
914  // Closes the tab, and waits for the close to finish.
915  void CloseTab(Browser* browser, int index) {
916    content::WebContentsDestroyedWatcher destroyed_watcher(
917        browser->tab_strip_model()->GetWebContentsAt(index));
918    browser->tab_strip_model()->CloseWebContentsAt(
919        index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
920    destroyed_watcher.Wait();
921  }
922};
923
924// Tests that as a user switches between tabs, navigates within a tab, and
925// switches between browser windows, the correct URL is being passed to the
926// Handoff.
927IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) {
928  ASSERT_TRUE(embedded_test_server()->Start());
929  EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL));
930
931  // Test that navigating to a URL updates the handoff URL.
932  GURL test_url1 = embedded_test_server()->GetURL("/title1.html");
933  ui_test_utils::NavigateToURL(browser(), test_url1);
934  EXPECT_EQ(g_handoff_url, test_url1);
935
936  // Test that opening a new tab updates the handoff URL.
937  GURL test_url2 = embedded_test_server()->GetURL("/title2.html");
938  NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK);
939  params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
940  ui_test_utils::NavigateToURL(&params);
941  EXPECT_EQ(g_handoff_url, test_url2);
942
943  // Test that switching tabs updates the handoff URL.
944  browser()->tab_strip_model()->ActivateTabAt(
945      0, {TabStripModel::GestureType::kOther});
946  EXPECT_EQ(g_handoff_url, test_url1);
947
948  // Test that closing the current tab updates the handoff URL.
949  CloseTab(browser(), 0);
950  EXPECT_EQ(g_handoff_url, test_url2);
951
952  // Test that opening a new browser window updates the handoff URL.
953  GURL test_url3 = embedded_test_server()->GetURL("/title3.html");
954  ui_test_utils::NavigateToURLWithDisposition(
955      browser(), GURL(test_url3), WindowOpenDisposition::NEW_WINDOW,
956      ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
957  EXPECT_EQ(g_handoff_url, test_url3);
958
959  // Check that there are exactly 2 browsers.
960  BrowserList* active_browser_list = BrowserList::GetInstance();
961  EXPECT_EQ(2u, active_browser_list->size());
962
963  // Close the second browser window (which only has 1 tab left).
964  Browser* browser2 = active_browser_list->get(1);
965  CloseBrowserSynchronously(browser2);
966  EXPECT_EQ(g_handoff_url, test_url2);
967
968  // The URLs of incognito windows should not be passed to Handoff.
969  GURL test_url4 = embedded_test_server()->GetURL("/simple.html");
970  ui_test_utils::NavigateToURLWithDisposition(
971      browser(), GURL(test_url4), WindowOpenDisposition::OFF_THE_RECORD,
972      ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
973  EXPECT_EQ(g_handoff_url, GURL());
974
975  // Open a new tab in the incognito window.
976  EXPECT_EQ(2u, active_browser_list->size());
977  Browser* browser3 = active_browser_list->get(1);
978  ui_test_utils::NavigateToURLWithDisposition(
979      browser3, test_url4, WindowOpenDisposition::NEW_FOREGROUND_TAB,
980      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
981  EXPECT_EQ(g_handoff_url, GURL());
982
983  // Navigate the current tab in the incognito window.
984  ui_test_utils::NavigateToURL(browser3, test_url1);
985  EXPECT_EQ(g_handoff_url, GURL());
986
987  // Activate the original browser window.
988  Browser* browser1 = active_browser_list->get(0);
989  browser1->window()->Show();
990  EXPECT_EQ(g_handoff_url, test_url2);
991}
992
993}  // namespace
994