// 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/toolbar/legacy/ui_bundled/adaptive_toolbar_mediator.h"

#import <memory>

#import "base/apple/foundation_util.h"
#import "base/files/scoped_temp_dir.h"
#import "base/memory/raw_ptr.h"
#import "base/strings/string_number_conversions.h"
#import "base/strings/sys_string_conversions.h"
#import "base/strings/utf_string_conversions.h"
#import "base/test/scoped_feature_list.h"
#import "components/collaboration/test_support/mock_messaging_backend_service.h"
#import "components/data_sharing/public/features.h"
#import "components/open_from_clipboard/clipboard_recent_content.h"
#import "components/open_from_clipboard/fake_clipboard_recent_content.h"
#import "ios/chrome/browser/collaboration/model/messaging/messaging_backend_service_bridge.h"
#import "ios/chrome/browser/menu/ui_bundled/browser_action_factory.h"
#import "ios/chrome/browser/policy/model/policy_util.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/url/chrome_url_constants.h"
#import "ios/chrome/browser/shared/model/web_state_list/tab_group.h"
#import "ios/chrome/browser/shared/model/web_state_list/test/fake_web_state_list_delegate.h"
#import "ios/chrome/browser/shared/model/web_state_list/test/web_state_list_builder_from_description.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_list_observer_bridge.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h"
#import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/gemini_commands.h"
#import "ios/chrome/browser/shared/public/commands/qr_scanner_commands.h"
#import "ios/chrome/browser/shared/public/commands/scene_commands.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/toolbar/legacy/ui_bundled/legacy_toolbar_consumer.h"
#import "ios/chrome/browser/toolbar/legacy/ui_bundled/test/toolbar_test_navigation_manager.h"
#import "ios/chrome/browser/web/model/web_navigation_browser_agent.h"
#import "ios/chrome/grit/ios_strings.h"
#import "ios/chrome/test/providers/voice_search/test_voice_search.h"
#import "ios/public/provider/chrome/browser/voice_search/voice_search_api.h"
#import "ios/web/public/test/fakes/fake_navigation_context.h"
#import "ios/web/public/test/fakes/fake_navigation_manager.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "ios/web/public/web_state_observer_bridge.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "ui/base/l10n/l10n_util.h"

using testing::_;
using testing::Return;

@interface TestAdaptiveToolbarMediator
    : AdaptiveToolbarMediator <CRWWebStateObserver,
                               MessagingBackendServiceObserving,
                               WebStateListObserving>
@end

@implementation TestAdaptiveToolbarMediator
@end

namespace {

MenuScenarioHistogram kTestMenuScenario = kMenuScenarioHistogramHistoryEntry;

static const int kNumberOfWebStates = 3;
static const char kTestUrl[] = "http://www.chromium.org";

// Returns a vector of messages containing an update for `tab_group`.
std::vector<collaboration::messaging::PersistentMessage> UpdateForGroup(
    const TabGroup* tab_group) {
  collaboration::messaging::TabGroupMessageMetadata metadata;
  metadata.local_tab_group_id = std::make_optional(tab_group->tab_group_id());
  collaboration::messaging::PersistentMessage message;
  message.type =
      collaboration::messaging::PersistentNotificationType::DIRTY_TAB_GROUP;
  message.attribution.tab_group_metadata = std::make_optional(metadata);
  return std::vector{message};
}

class AdaptiveToolbarMediatorTest : public PlatformTest {
 public:
  AdaptiveToolbarMediatorTest() {
    scoped_feature_list_.InitWithFeatures(
        /*enabled_features=*/
        {
            data_sharing::features::kDataSharingFeature,
        },
        /*disable_features=*/{});

    ios::provider::test::SetVoiceSearchEnabled(false);

    TestProfileIOS::Builder builder;

    builder.AddTestingFactory(
        ios::TemplateURLServiceFactory::GetInstance(),
        ios::TemplateURLServiceFactory::GetDefaultFactory());

    profile_ = std::move(builder).Build();
    test_browser_ = std::make_unique<TestBrowser>(profile_.get());
    WebNavigationBrowserAgent::CreateForBrowser(test_browser_.get());

    std::unique_ptr<ToolbarTestNavigationManager> navigation_manager =
        std::make_unique<ToolbarTestNavigationManager>();
    navigation_manager_ = navigation_manager.get();
    test_web_state_ = std::make_unique<web::FakeWebState>();
    test_web_state_->SetBrowserState(profile_.get());
    test_web_state_->SetNavigationManager(std::move(navigation_manager));
    test_web_state_->SetLoading(true);
    web_state_ = test_web_state_.get();
    mediator_ = [[TestAdaptiveToolbarMediator alloc]
        initWithMessagingService:&messaging_backend_];
    mediator_.navigationBrowserAgent =
        WebNavigationBrowserAgent::FromBrowser(test_browser_.get());
    mediator_.actionFactory =
        [[BrowserActionFactory alloc] initWithBrowser:test_browser_.get()
                                             scenario:kTestMenuScenario];
    mediator_.templateURLService =
        ios::TemplateURLServiceFactory::GetForProfile(profile_.get());
    consumer_ = OCMProtocolMock(@protocol(LegacyToolbarConsumer));
    strict_consumer_ = OCMStrictProtocolMock(@protocol(LegacyToolbarConsumer));
    SetUpWebStateList();

    mock_scene_handler_ = OCMStrictProtocolMock(@protocol(SceneCommands));
    [test_browser_->GetCommandDispatcher()
        startDispatchingToTarget:mock_scene_handler_
                     forProtocol:@protocol(SceneCommands)];

    mock_settings_commands_handler_ =
        OCMStrictProtocolMock(@protocol(SettingsCommands));
    [test_browser_->GetCommandDispatcher()
        startDispatchingToTarget:mock_settings_commands_handler_
                     forProtocol:@protocol(SettingsCommands)];

    mock_browser_coordinator_commands_handler_ =
        OCMStrictProtocolMock(@protocol(BrowserCoordinatorCommands));
    [test_browser_->GetCommandDispatcher()
        startDispatchingToTarget:mock_browser_coordinator_commands_handler_
                     forProtocol:@protocol(BrowserCoordinatorCommands)];

    mock_qr_scanner_commands_handler_ =
        OCMStrictProtocolMock(@protocol(QRScannerCommands));
    [test_browser_->GetCommandDispatcher()
        startDispatchingToTarget:mock_qr_scanner_commands_handler_
                     forProtocol:@protocol(QRScannerCommands)];

    mock_gemini_handler_ = OCMStrictProtocolMock(@protocol(GeminiCommands));
    [test_browser_->GetCommandDispatcher()
        startDispatchingToTarget:mock_gemini_handler_
                     forProtocol:@protocol(GeminiCommands)];

    [[UIPasteboard generalPasteboard] setItems:@[]];

    ClipboardRecentContent::SetInstance(
        std::make_unique<FakeClipboardRecentContent>());
  }

  // Explicitly disconnect the mediator so there won't be any WebStateList
  // observers when web_state_list_ gets dealloc.
  ~AdaptiveToolbarMediatorTest() override {
    ios::provider::test::SetVoiceSearchEnabled(false);

    ClipboardRecentContent::SetInstance(nullptr);

    [mediator_ disconnect];

    EXPECT_OCMOCK_VERIFY(consumer_);
    EXPECT_OCMOCK_VERIFY(strict_consumer_);
    EXPECT_OCMOCK_VERIFY(mock_scene_handler_);
    EXPECT_OCMOCK_VERIFY(mock_settings_commands_handler_);
    EXPECT_OCMOCK_VERIFY(mock_browser_coordinator_commands_handler_);
    EXPECT_OCMOCK_VERIFY(mock_qr_scanner_commands_handler_);
  }

 protected:
  web::WebTaskEnvironment task_environment_;
  void SetUpWebStateList() {
    web_state_list_ = std::make_unique<WebStateList>(&web_state_list_delegate_);
    web_state_list_->InsertWebState(std::move(test_web_state_),
                                    WebStateList::InsertionParams::AtIndex(0));
    for (int i = 1; i < kNumberOfWebStates; i++) {
      InsertNewWebState(i);
    }
  }

  void InsertNewWebState(int index) {
    auto web_state = std::make_unique<web::FakeWebState>();
    web_state->SetBrowserState(profile_.get());
    web_state->SetNavigationManager(
        std::make_unique<web::FakeNavigationManager>());
    GURL url("http://test/" + base::NumberToString(index));
    web_state->SetCurrentURL(url);
    web_state_list_->InsertWebState(
        std::move(web_state), WebStateList::InsertionParams::AtIndex(index));
  }

  void SetUpActiveWebState() { web_state_list_->ActivateWebStateAt(0); }

  base::test::ScopedFeatureList scoped_feature_list_;
  TestAdaptiveToolbarMediator* mediator_;
  std::unique_ptr<TestBrowser> test_browser_;
  raw_ptr<web::FakeWebState, DanglingUntriaged> web_state_;
  raw_ptr<ToolbarTestNavigationManager, DanglingUntriaged> navigation_manager_;
  std::unique_ptr<WebStateList> web_state_list_;
  FakeWebStateListDelegate web_state_list_delegate_;
  id consumer_;
  id strict_consumer_;
  id mock_scene_handler_;
  id mock_settings_commands_handler_;
  id mock_browser_coordinator_commands_handler_;
  id mock_qr_scanner_commands_handler_;
  id mock_gemini_handler_;
  std::unique_ptr<TestProfileIOS> profile_;
  collaboration::messaging::MockMessagingBackendService messaging_backend_;

 private:
  std::unique_ptr<web::FakeWebState> test_web_state_;
};

// Test no setup is being done on the Toolbar if there's no Webstate.
TEST_F(AdaptiveToolbarMediatorTest, TestToolbarSetupWithNoWebstate) {
  mediator_.consumer = consumer_;

  [[consumer_ reject] setCanGoForward:NO];
  [[consumer_ reject] setCanGoBack:NO];
  [[consumer_ reject] setLoadingState:YES];
}

// Test no setup is being done on the Toolbar if there's no active Webstate.
TEST_F(AdaptiveToolbarMediatorTest, TestToolbarSetupWithNoActiveWebstate) {
  mediator_.webStateList = web_state_list_.get();
  mediator_.consumer = consumer_;

  [[consumer_ reject] setCanGoForward:NO];
  [[consumer_ reject] setCanGoBack:NO];
  [[consumer_ reject] setLoadingState:YES];
}

// Test no WebstateList related setup is being done on the Toolbar if there's no
// WebstateList.
TEST_F(AdaptiveToolbarMediatorTest, TestToolbarSetupWithNoWebstateList) {
  mediator_.consumer = consumer_;

  [[[consumer_ reject] ignoringNonObjectArgs] setTabCount:0
                                        addedInBackground:NO];
}

// Tests the Toolbar Setup gets called when the mediator's WebState and Consumer
// have been set.
TEST_F(AdaptiveToolbarMediatorTest, TestToolbarSetup) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  [consumer_ setCanGoForward:NO];
  [consumer_ setCanGoBack:NO];
  [consumer_ setLoadingState:YES];
  [consumer_ setShareMenuEnabled:NO];
}

// Tests the Toolbar Setup gets called when the mediator's WebState and Consumer
// have been set in reverse order.
TEST_F(AdaptiveToolbarMediatorTest, TestToolbarSetupReverse) {
  mediator_.consumer = consumer_;
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();

  [consumer_ setCanGoForward:NO];
  [consumer_ setCanGoBack:NO];
  [consumer_ setLoadingState:YES];
  [consumer_ setShareMenuEnabled:NO];
}

// Test the WebstateList related setup gets called when the mediator's WebState
// and Consumer have been set.
TEST_F(AdaptiveToolbarMediatorTest, TestWebstateListRelatedSetup) {
  mediator_.webStateList = web_state_list_.get();
  mediator_.consumer = consumer_;

  [consumer_ setTabCount:3 addedInBackground:NO];
}

// Test the WebstateList related setup gets called when the mediator's WebState
// and Consumer have been set in reverse order.
TEST_F(AdaptiveToolbarMediatorTest, TestWebstateListRelatedSetupReverse) {
  mediator_.consumer = consumer_;
  mediator_.webStateList = web_state_list_.get();

  [consumer_ setTabCount:3 addedInBackground:NO];
}

// Tests the Toolbar is updated when the Webstate observer method
// DidStartLoading is triggered by SetLoading.
TEST_F(AdaptiveToolbarMediatorTest, TestDidStartLoading) {
  // Change the default loading state to false to verify the Webstate
  // callback with true.
  web_state_->SetLoading(false);
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  web_state_->SetLoading(true);
  [consumer_ setLoadingState:YES];
}

// Tests the Toolbar is updated when the Webstate observer method DidStopLoading
// is triggered by SetLoading.
TEST_F(AdaptiveToolbarMediatorTest, TestDidStopLoading) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  web_state_->SetLoading(false);
  [consumer_ setLoadingState:NO];
}

// Tests the Toolbar is not updated when the Webstate observer method
// DidStartLoading is triggered by SetLoading on the NTP.
TEST_F(AdaptiveToolbarMediatorTest, TestDidStartLoadingNTP) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  web_state_->SetLoading(false);
  web_state_->SetVisibleURL(GURL(kChromeUINewTabURL));
  web_state_->SetLoading(true);
  [consumer_ setLoadingState:NO];
}

// Tests the Toolbar is updated when the Webstate observer method
// DidLoadPageWithSuccess is triggered by OnPageLoaded.
TEST_F(AdaptiveToolbarMediatorTest, TestDidLoadPageWithSucess) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  navigation_manager_->set_can_go_forward(true);
  navigation_manager_->set_can_go_back(true);

  web_state_->SetCurrentURL(GURL(kTestUrl));
  web_state_->OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);

  [consumer_ setCanGoForward:YES];
  [consumer_ setCanGoBack:YES];
  [consumer_ setShareMenuEnabled:YES];
}

// Tests the Toolbar is updated when the Webstate observer method
// didFinishNavigation is called.
TEST_F(AdaptiveToolbarMediatorTest, TestDidFinishNavigation) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  navigation_manager_->set_can_go_forward(true);
  navigation_manager_->set_can_go_back(true);

  web_state_->SetCurrentURL(GURL(kTestUrl));
  web::FakeNavigationContext context;
  web_state_->OnNavigationFinished(&context);

  [consumer_ setCanGoForward:YES];
  [consumer_ setCanGoBack:YES];
  [consumer_ setShareMenuEnabled:YES];
}

// Tests the Toolbar is updated when the Webstate observer method
// didChangeVisibleSecurityState is called.
TEST_F(AdaptiveToolbarMediatorTest, TestDidChangeVisibleSecurityState) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  navigation_manager_->set_can_go_forward(true);
  navigation_manager_->set_can_go_back(true);

  web_state_->SetCurrentURL(GURL(kTestUrl));
  web_state_->OnVisibleSecurityStateChanged();

  [consumer_ setCanGoForward:YES];
  [consumer_ setCanGoBack:YES];
  [consumer_ setShareMenuEnabled:YES];
}

// Tests the Toolbar is updated when the Webstate observer method
// didChangeLoadingProgress is called.
TEST_F(AdaptiveToolbarMediatorTest, TestLoadingProgress) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  [mediator_ webState:web_state_ didChangeLoadingProgress:0.42];
  [consumer_ setLoadingProgressFraction:0.42];
}

// Tests the Toolbar is updated when Webstate observer method
// didChangeBackForwardState is called.
TEST_F(AdaptiveToolbarMediatorTest, TestDidChangeBackForwardState) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  navigation_manager_->set_can_go_forward(true);
  navigation_manager_->set_can_go_back(true);

  web_state_->OnBackForwardStateChanged();

  [consumer_ setCanGoForward:YES];
  [consumer_ setCanGoBack:YES];
}

// Test that increasing the number of Webstates will update the consumer with
// the right value.
TEST_F(AdaptiveToolbarMediatorTest, TestIncreaseNumberOfWebstates) {
  mediator_.webStateList = web_state_list_.get();
  mediator_.consumer = consumer_;

  InsertNewWebState(0);
  [consumer_ setTabCount:kNumberOfWebStates + 1 addedInBackground:YES];
}

// Test that decreasing the number of Webstates will update the consumer with
// the right value.
TEST_F(AdaptiveToolbarMediatorTest, TestDecreaseNumberOfWebstates) {
  mediator_.webStateList = web_state_list_.get();
  mediator_.consumer = consumer_;

  web_state_list_->DetachWebStateAt(0);
  [consumer_ setTabCount:kNumberOfWebStates - 1 addedInBackground:NO];
}

// Test that consumer is informed that voice search is enabled.
TEST_F(AdaptiveToolbarMediatorTest, TestVoiceSearchProviderEnabled) {
  ios::provider::test::SetVoiceSearchEnabled(true);

  OCMExpect([consumer_ setVoiceSearchEnabled:YES]);
  mediator_.consumer = consumer_;
}

// Test that consumer is informed that voice search is not enabled.
TEST_F(AdaptiveToolbarMediatorTest, TestVoiceSearchProviderNotEnabled) {
  ios::provider::test::SetVoiceSearchEnabled(false);

  OCMExpect([consumer_ setVoiceSearchEnabled:NO]);
  mediator_.consumer = consumer_;
}

// Test that updating the consumer for a specific webState works.
TEST_F(AdaptiveToolbarMediatorTest, TestUpdateConsumerForWebState) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();
  mediator_.consumer = consumer_;

  auto navigation_manager = std::make_unique<ToolbarTestNavigationManager>();
  navigation_manager->set_can_go_forward(true);
  navigation_manager->set_can_go_back(true);
  std::unique_ptr<web::FakeWebState> test_web_state =
      std::make_unique<web::FakeWebState>();
  test_web_state->SetNavigationManager(std::move(navigation_manager));
  test_web_state->SetCurrentURL(GURL(kTestUrl));
  test_web_state->OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);

  OCMExpect([consumer_ setCanGoForward:YES]);
  OCMExpect([consumer_ setCanGoBack:YES]);
  OCMExpect([consumer_ setShareMenuEnabled:YES]);

  [mediator_ updateConsumerForWebState:test_web_state.get()];
}

// Tests the menu elements.
TEST_F(AdaptiveToolbarMediatorTest, MenuElements) {
  mediator_.webStateList = web_state_list_.get();
  SetUpActiveWebState();

  UIMenu* new_tab_menu =
      [mediator_ menuForButtonOfType:AdaptiveToolbarButtonTypeNewTab];

  ASSERT_EQ(4U, new_tab_menu.children.count);
  for (UIMenuElement* element in new_tab_menu.children) {
    ASSERT_TRUE([element isKindOfClass:[UIAction class]]);
    UIAction* action = (UIAction*)element;
    EXPECT_EQ(0U, action.attributes);
  }

  UIMenu* tab_grid_menu =
      [mediator_ menuForButtonOfType:AdaptiveToolbarButtonTypeTabGrid];

  ASSERT_EQ(3U, tab_grid_menu.children.count);

  ASSERT_TRUE([tab_grid_menu.children[0] isKindOfClass:[UIAction class]]);
  UIAction* close_tab = (UIAction*)tab_grid_menu.children[0];
  EXPECT_NSEQ(l10n_util::GetNSString(IDS_IOS_TOOLS_MENU_CLOSE_TAB),
              close_tab.title);
  EXPECT_EQ(UIMenuElementAttributesDestructive, close_tab.attributes);

  ASSERT_TRUE([tab_grid_menu.children[1] isKindOfClass:[UIAction class]]);
  UIAction* action = (UIAction*)tab_grid_menu.children[1];
  EXPECT_EQ(0U, action.attributes);

  ASSERT_TRUE([tab_grid_menu.children[2] isKindOfClass:[UIAction class]]);
  action = (UIAction*)tab_grid_menu.children[2];
  EXPECT_EQ(0U, action.attributes);
}

// Tests the back/forward items for the menu.
TEST_F(AdaptiveToolbarMediatorTest, MenuElementsBackForward) {
  std::unique_ptr<web::FakeNavigationManager> navigation_manager =
      std::make_unique<web::FakeNavigationManager>();

  navigation_manager->AddItem(GURL("http://chromium.org/1"),
                              ui::PageTransition::PAGE_TRANSITION_LINK);
  navigation_manager->AddItem(GURL("http://chromium.org/2"),
                              ui::PageTransition::PAGE_TRANSITION_LINK);

  navigation_manager->AddItem(GURL("http://chromium.org/current"),
                              ui::PageTransition::PAGE_TRANSITION_LINK);

  navigation_manager->AddItem(GURL("http://chromium.org/4"),
                              ui::PageTransition::PAGE_TRANSITION_LINK);
  navigation_manager->AddItem(GURL("http://chromium.org/5"),
                              ui::PageTransition::PAGE_TRANSITION_LINK);
  navigation_manager->AddItem(GURL("http://chromium.org/6"),
                              ui::PageTransition::PAGE_TRANSITION_LINK);
  navigation_manager->GoBack();
  navigation_manager->GoBack();
  navigation_manager->GoBack();

  auto web_state = std::make_unique<web::FakeWebState>();
  web_state->SetBrowserState(profile_.get());
  web_state->SetNavigationManager(std::move(navigation_manager));
  web_state_list_->InsertWebState(
      std::move(web_state),
      WebStateList::InsertionParams::Automatic().Activate());

  mediator_.webStateList = web_state_list_.get();
  mediator_.consumer = consumer_;

  UIMenu* back_menu =
      [mediator_ menuForButtonOfType:AdaptiveToolbarButtonTypeBack];

  ASSERT_EQ(2U, back_menu.children.count);
  EXPECT_NSEQ(@"chromium.org/2", back_menu.children[0].title);
  EXPECT_NSEQ(@"chromium.org/1", back_menu.children[1].title);

  UIMenu* forward_menu =
      [mediator_ menuForButtonOfType:AdaptiveToolbarButtonTypeForward];
  ASSERT_EQ(3U, forward_menu.children.count);
  EXPECT_NSEQ(@"chromium.org/4", forward_menu.children[0].title);
  EXPECT_NSEQ(@"chromium.org/5", forward_menu.children[1].title);
  EXPECT_NSEQ(@"chromium.org/6", forward_menu.children[2].title);
}

// Tests adding a message for a group update while not in a group.
TEST_F(AdaptiveToolbarMediatorTest, MessageOnNonGroupAtStartup) {
  CloseAllWebStates(*web_state_list_, WebStateList::ClosingReason::kDefault);
  WebStateListBuilderFromDescription builder(web_state_list_.get());
  ASSERT_TRUE(
      builder.BuildWebStateListFromDescription("| [0 a b] c* [1 d] e f"));
  mediator_.webStateList = web_state_list_.get();

  const TabGroup* tab_group = web_state_list_->GetGroupOfWebStateAt(0);
  std::vector<collaboration::messaging::PersistentMessage> messages =
      UpdateForGroup(tab_group);

  ON_CALL(messaging_backend_, IsInitialized).WillByDefault(Return(true));
  ON_CALL(messaging_backend_, GetMessages(_)).WillByDefault(Return(messages));
  [mediator_ onMessagingBackendServiceInitialized];

  OCMExpect([consumer_ setTabGridButtonBlueDot:YES]);

  mediator_.consumer = consumer_;
}

// Tests adding a message for a group update while not in a group, the backend
// not being initialized.
TEST_F(AdaptiveToolbarMediatorTest, MessageOnNonGroupNotInitialized) {
  CloseAllWebStates(*web_state_list_, WebStateList::ClosingReason::kDefault);
  WebStateListBuilderFromDescription builder(web_state_list_.get());
  ASSERT_TRUE(
      builder.BuildWebStateListFromDescription("| [0 a b] c* [1 d] e f"));
  mediator_.webStateList = web_state_list_.get();

  const TabGroup* tab_group = web_state_list_->GetGroupOfWebStateAt(0);
  std::vector<collaboration::messaging::PersistentMessage> messages =
      UpdateForGroup(tab_group);

  ON_CALL(messaging_backend_, IsInitialized).WillByDefault(Return(false));
  ON_CALL(messaging_backend_, GetMessages(_)).WillByDefault(Return(messages));

  mediator_.consumer = consumer_;

  ON_CALL(messaging_backend_, IsInitialized).WillByDefault(Return(true));

  OCMExpect([consumer_ setTabGridButtonBlueDot:YES]);

  // Fake the initialization of the service.
  [mediator_ onMessagingBackendServiceInitialized];
}

// Tests adding a message for a group update while not in a group, receiving the
// update after startup.
TEST_F(AdaptiveToolbarMediatorTest, MessageOnNonGroupNotification) {
  CloseAllWebStates(*web_state_list_, WebStateList::ClosingReason::kDefault);
  WebStateListBuilderFromDescription builder(web_state_list_.get());
  ASSERT_TRUE(
      builder.BuildWebStateListFromDescription("| [0 a b] c* [1 d] e f"));
  mediator_.webStateList = web_state_list_.get();

  const TabGroup* tab_group = web_state_list_->GetGroupOfWebStateAt(0);
  std::vector<collaboration::messaging::PersistentMessage> messages =
      UpdateForGroup(tab_group);

  ON_CALL(messaging_backend_, IsInitialized).WillByDefault(Return(true));
  [mediator_ onMessagingBackendServiceInitialized];

  mediator_.consumer = consumer_;

  ON_CALL(messaging_backend_, GetMessages(_)).WillByDefault(Return(messages));

  OCMExpect([consumer_ setTabGridButtonBlueDot:YES]);

  // Fake the update of the backend.
  [mediator_ displayPersistentMessage:messages[0]];
}

// Tests adding a message for a group update while in a group, receiving the
// update for this group after startup.
TEST_F(AdaptiveToolbarMediatorTest, MessageForGroupInGroupNotification) {
  CloseAllWebStates(*web_state_list_, WebStateList::ClosingReason::kDefault);
  WebStateListBuilderFromDescription builder(web_state_list_.get());
  ASSERT_TRUE(
      builder.BuildWebStateListFromDescription("| [0 a b*] c [1 d] e f"));
  mediator_.webStateList = web_state_list_.get();

  const TabGroup* tab_group = web_state_list_->GetGroupOfWebStateAt(0);
  std::vector<collaboration::messaging::PersistentMessage> messages =
      UpdateForGroup(tab_group);

  ON_CALL(messaging_backend_, IsInitialized).WillByDefault(Return(true));
  [mediator_ onMessagingBackendServiceInitialized];

  mediator_.consumer = consumer_;

  ON_CALL(messaging_backend_, GetMessages(_)).WillByDefault(Return(messages));

  OCMExpect([consumer_ setTabGridButtonBlueDot:YES]);

  // Fake the update of the backend.
  [mediator_ displayPersistentMessage:messages[0]];
}

// Tests adding a message for a group update while in a group, receiving the
// update for another group after startup.
TEST_F(AdaptiveToolbarMediatorTest, MessageForOtherGroupInGroupNotification) {
  CloseAllWebStates(*web_state_list_, WebStateList::ClosingReason::kDefault);
  WebStateListBuilderFromDescription builder(web_state_list_.get());
  ASSERT_TRUE(
      builder.BuildWebStateListFromDescription("| [0 a b] c [1 d*] e f"));
  mediator_.webStateList = web_state_list_.get();

  const TabGroup* tab_group = web_state_list_->GetGroupOfWebStateAt(0);
  std::vector<collaboration::messaging::PersistentMessage> messages =
      UpdateForGroup(tab_group);

  ON_CALL(messaging_backend_, IsInitialized).WillByDefault(Return(true));
  [mediator_ onMessagingBackendServiceInitialized];

  mediator_.consumer = consumer_;

  ON_CALL(messaging_backend_, GetMessages(_)).WillByDefault(Return(messages));

  OCMExpect([consumer_ setTabGridButtonBlueDot:NO]);

  // Fake the update of the backend.
  [mediator_ displayPersistentMessage:messages[0]];
}

}  // namespace
