chromium/ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator_unittest.mm

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/location_bar/ui_bundled/location_bar_coordinator.h"

#import <memory>
#import <string>
#import <vector>

#import "components/omnibox/browser/test_location_bar_model.h"
#import "components/variations/scoped_variations_ids_provider.h"
#import "components/variations/variations_ids_provider.h"
#import "ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h"
#import "ios/chrome/browser/favicon/model/favicon_service_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_large_icon_service_factory.h"
#import "ios/chrome/browser/history/model/history_service_factory.h"
#import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h"
#import "ios/chrome/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/help_commands.h"
#import "ios/chrome/browser/shared/public/commands/lens_commands.h"
#import "ios/chrome/browser/shared/public/commands/qr_scanner_commands.h"
#import "ios/chrome/browser/shared/public/commands/quick_delete_commands.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/shared/public/commands/toolbar_commands.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_focus_delegate.h"
#import "ios/chrome/browser/url_loading/model/fake_url_loading_browser_agent.h"
#import "ios/chrome/browser/url_loading/model/url_loading_notifier_browser_agent.h"
#import "ios/chrome/browser/url_loading/model/url_loading_params.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"

using variations::VariationsIdsProvider;

@interface TestOmniboxFocusDelegate : NSObject <OmniboxFocusDelegate>

@end

@implementation TestOmniboxFocusDelegate {
  std::unique_ptr<LocationBarModel> _model;
}

- (void)omniboxDidBecomeFirstResponder {
}
- (void)omniboxDidResignFirstResponder {
}

- (LocationBarModel*)locationBarModel {
  if (!_model) {
    _model = std::make_unique<TestLocationBarModel>();
  }

  return _model.get();
}

@end

namespace {

class LocationBarCoordinatorTest : public PlatformTest {
 protected:
  LocationBarCoordinatorTest() {}

  void SetUp() override {
    PlatformTest::SetUp();

    TestChromeBrowserState::Builder test_cbs_builder;

    test_cbs_builder.AddTestingFactory(
        ios::TemplateURLServiceFactory::GetInstance(),
        ios::TemplateURLServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        ios::AutocompleteClassifierFactory::GetInstance(),
        ios::AutocompleteClassifierFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        IOSChromeFaviconLoaderFactory::GetInstance(),
        IOSChromeFaviconLoaderFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        IOSChromeLargeIconServiceFactory::GetInstance(),
        IOSChromeLargeIconServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        ios::FaviconServiceFactory::GetInstance(),
        ios::FaviconServiceFactory::GetDefaultFactory());
    test_cbs_builder.AddTestingFactory(
        ios::HistoryServiceFactory::GetInstance(),
        ios::HistoryServiceFactory::GetDefaultFactory());

    browser_state_ = std::move(test_cbs_builder).Build();

    browser_ = std::make_unique<TestBrowser>(browser_state_.get());
    UrlLoadingNotifierBrowserAgent::CreateForBrowser(browser_.get());
    FakeUrlLoadingBrowserAgent::InjectForBrowser(browser_.get());

    auto web_state = std::make_unique<web::FakeWebState>();
    web_state->SetBrowserState(browser_state_.get());
    web_state->SetCurrentURL(GURL("http://test/"));
    browser_->GetWebStateList()->InsertWebState(
        std::move(web_state), WebStateList::InsertionParams::AtIndex(0));

    CommandDispatcher* dispatcher = browser_->GetCommandDispatcher();

    id mock_qr_scanner_handler = OCMProtocolMock(@protocol(QRScannerCommands));
    [dispatcher startDispatchingToTarget:mock_qr_scanner_handler
                             forProtocol:@protocol(QRScannerCommands)];
    id mock_lens_handler = OCMProtocolMock(@protocol(LensCommands));
    [dispatcher startDispatchingToTarget:mock_lens_handler
                             forProtocol:@protocol(LensCommands)];
    id mock_help_handler = OCMProtocolMock(@protocol(HelpCommands));
    [dispatcher startDispatchingToTarget:mock_help_handler
                             forProtocol:@protocol(HelpCommands)];
    id mock_toolbar_handler = OCMProtocolMock(@protocol(ToolbarCommands));
    [dispatcher startDispatchingToTarget:mock_toolbar_handler
                             forProtocol:@protocol(ToolbarCommands)];

    // Set up application and settings handler mocks.
    id mock_application_handler =
        OCMProtocolMock(@protocol(ApplicationCommands));
    id mock_settings_handler = OCMProtocolMock(@protocol(SettingsCommands));
    [dispatcher startDispatchingToTarget:mock_application_handler
                             forProtocol:@protocol(ApplicationCommands)];
    [dispatcher startDispatchingToTarget:mock_settings_handler
                             forProtocol:@protocol(SettingsCommands)];

    id mock_quick_delete_handler =
        OCMProtocolMock(@protocol(QuickDeleteCommands));
    [dispatcher startDispatchingToTarget:mock_quick_delete_handler
                             forProtocol:@protocol(QuickDeleteCommands)];

    delegate_ = [[TestOmniboxFocusDelegate alloc] init];

    coordinator_ = [[LocationBarCoordinator alloc]

        initWithBrowser:browser_.get()];
    coordinator_.delegate = delegate_;
  }

  void TearDown() override {
    // Started coordinator has to be stopped before WebStateList destruction.
    [coordinator_ stop];

    PlatformTest::TearDown();
  }

  web::WebTaskEnvironment task_environment_;
  IOSChromeScopedTestingLocalState scoped_testing_local_state_;
  variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
      variations::VariationsIdsProvider::Mode::kUseSignedInState};
  LocationBarCoordinator* coordinator_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<Browser> browser_;
  TestOmniboxFocusDelegate* delegate_;
};

TEST_F(LocationBarCoordinatorTest, Stops) {
  EXPECT_TRUE(coordinator_.locationBarViewController == nil);
  [coordinator_ start];
  EXPECT_TRUE(coordinator_.locationBarViewController != nil);
  [coordinator_ stop];
  EXPECT_TRUE(coordinator_.locationBarViewController == nil);
}

// Removes the existing WebState to ensure that nothing breaks when there is no
// active WebState.
TEST_F(LocationBarCoordinatorTest, RemoveLastWebState) {
  browser_->GetWebStateList()->CloseWebStateAt(0, 0);
}

// Calls -loadGURLFromLocationBar:transition: with https://www.google.com/ URL.
// Verifies that URLLoader receives correct load request, which also includes
// variations header.
TEST_F(LocationBarCoordinatorTest, LoadGoogleUrl) {
  ASSERT_EQ(VariationsIdsProvider::ForceIdsResult::SUCCESS,
            VariationsIdsProvider::GetInstance()->ForceVariationIds(
                /*variation_ids=*/{"100"}, /*command_line_variation_ids=*/""));

  GURL url("https://www.google.com/");
  ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
  WindowOpenDisposition disposition = WindowOpenDisposition::SWITCH_TO_TAB;
  [coordinator_ start];
  [coordinator_ loadGURLFromLocationBar:url
                                 postContent:nil
                                  transition:transition
                                 disposition:disposition
      destination_url_entered_without_scheme:false];

  FakeUrlLoadingBrowserAgent* url_loader =
      FakeUrlLoadingBrowserAgent::FromUrlLoadingBrowserAgent(
          UrlLoadingBrowserAgent::FromBrowser(browser_.get()));
  EXPECT_EQ(url, url_loader->last_params.web_params.url);
  EXPECT_TRUE(url_loader->last_params.web_params.referrer.url.is_empty());
  EXPECT_EQ(web::ReferrerPolicyDefault,
            url_loader->last_params.web_params.referrer.policy);
  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(
      transition, url_loader->last_params.web_params.transition_type));
  EXPECT_FALSE(url_loader->last_params.web_params.is_renderer_initiated);
  ASSERT_EQ(1U, url_loader->last_params.web_params.extra_headers.count);
  EXPECT_GT([url_loader->last_params.web_params.extra_headers[@"X-Client-Data"]
                length],
            0U);
  EXPECT_EQ(disposition, url_loader->last_params.disposition);
}

// Calls -loadGURLFromLocationBar:transition: with https://www.nongoogle.com/
// URL. Verifies that URLLoader receives correct load request without variations
// header.
TEST_F(LocationBarCoordinatorTest, LoadNonGoogleUrl) {
  ASSERT_EQ(VariationsIdsProvider::ForceIdsResult::SUCCESS,
            VariationsIdsProvider::GetInstance()->ForceVariationIds(
                /*variation_ids=*/{"100"}, /*command_line_variation_ids=*/""));

  GURL url("https://www.nongoogle.com/");
  ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
  WindowOpenDisposition disposition = WindowOpenDisposition::CURRENT_TAB;
  [coordinator_ start];
  [coordinator_ loadGURLFromLocationBar:url
                                 postContent:nil
                                  transition:transition
                                 disposition:disposition
      destination_url_entered_without_scheme:false];

  FakeUrlLoadingBrowserAgent* url_loader =
      FakeUrlLoadingBrowserAgent::FromUrlLoadingBrowserAgent(
          UrlLoadingBrowserAgent::FromBrowser(browser_.get()));

  EXPECT_EQ(url, url_loader->last_params.web_params.url);
  EXPECT_TRUE(url_loader->last_params.web_params.referrer.url.is_empty());
  EXPECT_EQ(web::ReferrerPolicyDefault,
            url_loader->last_params.web_params.referrer.policy);
  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(
      transition, url_loader->last_params.web_params.transition_type));
  EXPECT_FALSE(url_loader->last_params.web_params.is_renderer_initiated);
  ASSERT_EQ(0U, url_loader->last_params.web_params.extra_headers.count);
  EXPECT_EQ(disposition, url_loader->last_params.disposition);
}

}  // namespace