chromium/ios/chrome/browser/lens/model/lens_tab_helper_unittest.mm

// Copyright 2023 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/lens/model/lens_tab_helper.h"

#import "base/memory/raw_ptr.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/lens_commands.h"
#import "ios/chrome/browser/shared/public/commands/open_lens_input_selection_command.h"
#import "ios/chrome/browser/ui/lens/lens_entrypoint.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"

namespace {

class LensTabHelperTest : public PlatformTest {
 public:
  LensTabHelperTest() {
    browser_state_ = TestChromeBrowserState::Builder().Build();

    web::WebState::CreateParams params(browser_state_.get());
    web_state_ = web::WebState::Create(params);

    LensTabHelper::CreateForWebState(web_state_.get());
  }

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

    id dispatcher = [[CommandDispatcher alloc] init];
    dispatcher_ = dispatcher;

    helper_ = LensTabHelper::FromWebState(web_state_.get());
    ASSERT_TRUE(helper_);

    helper_->SetLensCommandsHandler(dispatcher);
  }

 protected:
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  std::unique_ptr<web::WebState> web_state_;
  web::WebTaskEnvironment task_environment_{
      web::WebTaskEnvironment::MainThreadType::IO};
  raw_ptr<LensTabHelper> helper_ = nullptr;
  id handler_;
  id dispatcher_;
};

// Test `ShouldAllowRequest` for the web search bar.
TEST_F(LensTabHelperTest, ShouldAllowRequest_WebSearchBar) {
  NSURLRequest* request = [NSURLRequest
      requestWithURL:
          [NSURL URLWithString:@"googlechromeaction://lens/web-search-box"]];
  const web::WebStatePolicyDecider::RequestInfo request_info(
      ui::PageTransition::PAGE_TRANSITION_LINK,
      /*target_frame_is_main=*/true,
      /*target_frame_is_cross_origin=*/false,
      /*target_window_is_cross_origin=*/false,
      /*is_user_initiated=*/false, /*user_tapped_recently=*/false);
  __block bool callback_called = false;
  __block web::WebStatePolicyDecider::PolicyDecision request_policy =
      web::WebStatePolicyDecider::PolicyDecision::Allow();
  auto callback =
      base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) {
        request_policy = decision;
        callback_called = true;
      });

  id mock_lens_commands_handler = OCMProtocolMock(@protocol(LensCommands));
  [dispatcher_ startDispatchingToTarget:mock_lens_commands_handler
                            forProtocol:@protocol(LensCommands)];

  OCMExpect([mock_lens_commands_handler
      openLensInputSelection:[OCMArg
                                 checkWithBlock:^(
                                     OpenLensInputSelectionCommand* command) {
                                   return command.entryPoint ==
                                          LensEntrypoint::WebSearchBar;
                                 }]]);

  helper_->ShouldAllowRequest(request, request_info, std::move(callback));

  EXPECT_OCMOCK_VERIFY(mock_lens_commands_handler);
  EXPECT_TRUE(callback_called);
  EXPECT_TRUE(request_policy.ShouldCancelNavigation());
}

// Test `ShouldAllowRequest` for the translate onebox.
TEST_F(LensTabHelperTest, ShouldAllowRequest_TranslateOnebox) {
  NSURLRequest* request = [NSURLRequest
      requestWithURL:
          [NSURL URLWithString:@"googlechromeaction://lens/translate-onebox"]];
  const web::WebStatePolicyDecider::RequestInfo request_info(
      ui::PageTransition::PAGE_TRANSITION_LINK,
      /*target_frame_is_main=*/true,
      /*target_frame_is_cross_origin=*/false,
      /*target_window_is_cross_origin=*/false,
      /*is_user_initiated=*/false, /*user_tapped_recently=*/false);
  __block bool callback_called = false;
  __block web::WebStatePolicyDecider::PolicyDecision request_policy =
      web::WebStatePolicyDecider::PolicyDecision::Allow();
  auto callback =
      base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) {
        request_policy = decision;
        callback_called = true;
      });

  id mock_lens_commands_handler = OCMProtocolMock(@protocol(LensCommands));
  [dispatcher_ startDispatchingToTarget:mock_lens_commands_handler
                            forProtocol:@protocol(LensCommands)];

  OCMExpect([mock_lens_commands_handler
      openLensInputSelection:[OCMArg
                                 checkWithBlock:^(
                                     OpenLensInputSelectionCommand* command) {
                                   return command.entryPoint ==
                                          LensEntrypoint::TranslateOnebox;
                                 }]]);

  helper_->ShouldAllowRequest(request, request_info, std::move(callback));

  EXPECT_OCMOCK_VERIFY(mock_lens_commands_handler);
  EXPECT_TRUE(callback_called);
  EXPECT_TRUE(request_policy.ShouldCancelNavigation());
}

// Test `ShouldAllowRequest` for the web images search bar.
TEST_F(LensTabHelperTest, ShouldAllowRequest_WebImagesSearchBar) {
  NSURLRequest* request = [NSURLRequest
      requestWithURL:[NSURL URLWithString:@"googlechromeaction://lens/"
                                          @"web-images-search-box"]];
  const web::WebStatePolicyDecider::RequestInfo request_info(
      ui::PageTransition::PAGE_TRANSITION_LINK,
      /*target_frame_is_main=*/true,
      /*target_frame_is_cross_origin=*/false,
      /*target_window_is_cross_origin=*/false,
      /*is_user_initiated=*/false, /*user_tapped_recently=*/false);
  __block bool callback_called = false;
  __block web::WebStatePolicyDecider::PolicyDecision request_policy =
      web::WebStatePolicyDecider::PolicyDecision::Allow();
  auto callback =
      base::BindOnce(^(web::WebStatePolicyDecider::PolicyDecision decision) {
        request_policy = decision;
        callback_called = true;
      });

  id mock_lens_commands_handler = OCMProtocolMock(@protocol(LensCommands));
  [dispatcher_ startDispatchingToTarget:mock_lens_commands_handler
                            forProtocol:@protocol(LensCommands)];

  OCMExpect([mock_lens_commands_handler
      openLensInputSelection:[OCMArg
                                 checkWithBlock:^(
                                     OpenLensInputSelectionCommand* command) {
                                   return command.entryPoint ==
                                          LensEntrypoint::WebImagesSearchBar;
                                 }]]);

  helper_->ShouldAllowRequest(request, request_info, std::move(callback));

  EXPECT_OCMOCK_VERIFY(mock_lens_commands_handler);
  EXPECT_TRUE(callback_called);
  EXPECT_TRUE(request_policy.ShouldCancelNavigation());
}

// Test `EntryPointForGoogleChromeActionURLPath` for the web search bar.
TEST_F(LensTabHelperTest, EntryPointForGoogleChromeActionURLPath_WebSearchBar) {
  std::optional<LensEntrypoint> entry_point =
      LensTabHelper::EntryPointForGoogleChromeActionURLPath(@"/web-search-box");
  ASSERT_TRUE(entry_point);
  EXPECT_EQ(entry_point.value(), LensEntrypoint::WebSearchBar);
}

// Test `EntryPointForGoogleChromeActionURLPath` for the translate onebox.
TEST_F(LensTabHelperTest,
       EntryPointForGoogleChromeActionURLPath_TranslateOnebox) {
  std::optional<LensEntrypoint> entry_point =
      LensTabHelper::EntryPointForGoogleChromeActionURLPath(
          @"/translate-onebox");
  ASSERT_TRUE(entry_point);
  EXPECT_EQ(entry_point.value(), LensEntrypoint::TranslateOnebox);
}

// Test `EntryPointForGoogleChromeActionURLPath` for the web images search bar.
TEST_F(LensTabHelperTest,
       EntryPointForGoogleChromeActionURLPath_WebImagesSearchBar) {
  std::optional<LensEntrypoint> entry_point =
      LensTabHelper::EntryPointForGoogleChromeActionURLPath(
          @"/web-images-search-box");
  ASSERT_TRUE(entry_point);
  EXPECT_EQ(entry_point.value(), LensEntrypoint::WebImagesSearchBar);
}

// Test `EntryPointForGoogleChromeActionURLPath` for an invalid entry point.
TEST_F(LensTabHelperTest, EntryPointForGoogleChromeActionURLPath_Invalid) {
  std::optional<LensEntrypoint> entry_point =
      LensTabHelper::EntryPointForGoogleChromeActionURLPath(@"/invalid");
  EXPECT_FALSE(entry_point);
}

}  // namespace