blob: ccb69f0fcf17ad74d83eda14b454464bd8d4c10f [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/nearby_sharing/nearby_share_delegate_impl.h"
#include <memory>
#include "ash/public/cpp/nearby_share_controller.h"
#include "ash/public/cpp/session/session_controller.h"
#include "base/memory/raw_ptr.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/clock.h"
#include "build/branding_buildflags.h"
#include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
#include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
#include "chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_local_device_data_manager.h"
#include "chrome/browser/nearby_sharing/mock_nearby_sharing_service.h"
#include "chrome/browser/nearby_sharing/nearby_share_settings.h"
#include "chrome/browser/ui/ash/session/test_session_controller.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/vector_icon_types.h"
namespace {
const char kDefaultDeviceName[] = "Josh's Chromebook";
} // namespace
using ::testing::_;
using ::testing::Assign;
using ::testing::AtLeast;
using ::testing::Return;
using ::testing::ReturnPointee;
class MockSettingsOpener : public NearbyShareDelegateImpl::SettingsOpener {
public:
MOCK_METHOD(void, ShowSettingsPage, (const std::string&), (override));
};
class MockNearbyShareController : public ash::NearbyShareController {
public:
MOCK_METHOD(void, HighVisibilityEnabledChanged, (bool), (override));
MOCK_METHOD(void, NearbyShareEnabledChanged, (bool), (override));
MOCK_METHOD(void,
VisibilityChanged,
(::nearby_share::mojom::Visibility),
(const override));
};
// TODO(crbug.com/1127940): Refactor these tests to avoid use of GMock.
class NearbyShareDelegateImplTest : public ::testing::Test {
public:
NearbyShareDelegateImplTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
test_local_device_data_(kDefaultDeviceName) {
RegisterNearbySharingPrefs(test_pref_service_.registry());
settings_ = std::make_unique<NearbyShareSettings>(&test_pref_service_,
&test_local_device_data_);
}
~NearbyShareDelegateImplTest() override = default;
base::Time Now() const { return task_environment_.GetMockClock()->Now(); }
// Fast-forwards mock time by |delta| and fires relevant timers.
void FastForward(base::TimeDelta delta) {
task_environment_.FastForwardBy(delta);
}
void SetHighVisibilityOn(bool high_visibility_on) {
if (high_visibility_on_ != high_visibility_on) {
high_visibility_on_ = high_visibility_on;
delegate_->OnHighVisibilityChanged(high_visibility_on);
}
}
void SetNearbyShareEnabled(bool enabled) {
delegate_->OnEnabledChanged(enabled);
}
void SetUp() override {
settings_->SetIsOnboardingComplete(true);
settings_->SetEnabled(false);
InitDelegate();
}
void InitDelegate() {
if (delegate_) {
delegate_.reset();
}
delegate_ = std::make_unique<NearbyShareDelegateImpl>(&controller_);
EXPECT_CALL(nearby_share_service_, GetSettings())
.WillRepeatedly(Return(settings_.get()));
EXPECT_CALL(nearby_share_service_, IsInHighVisibility())
.WillRepeatedly(ReturnPointee(&high_visibility_on_));
EXPECT_CALL(nearby_share_service_, AddObserver(_))
.WillRepeatedly(Assign(&service_observer_bound_, true));
EXPECT_CALL(nearby_share_service_, RemoveObserver(_))
.WillRepeatedly(Assign(&service_observer_bound_, false));
EXPECT_CALL(nearby_share_service_, HasObserver(_))
.WillRepeatedly(ReturnPointee(&service_observer_bound_));
delegate_->SetNearbyShareServiceForTest(&nearby_share_service_);
delegate_->SetNearbyShareSettingsForTest(settings_.get());
std::unique_ptr<MockSettingsOpener> settings_opener =
std::make_unique<MockSettingsOpener>();
settings_opener_ = settings_opener.get();
delegate_->set_settings_opener_for_test(std::move(settings_opener));
}
NearbyShareSettings* settings() { return settings_.get(); }
protected:
content::BrowserTaskEnvironment task_environment_;
MockNearbySharingService nearby_share_service_;
TestSessionController session_controller_;
sync_preferences::TestingPrefServiceSyncable test_pref_service_;
FakeNearbyShareLocalDeviceDataManager test_local_device_data_;
std::unique_ptr<NearbyShareSettings> settings_;
raw_ptr<MockSettingsOpener, DanglingUntriaged> settings_opener_;
MockNearbyShareController controller_;
std::unique_ptr<NearbyShareDelegateImpl> delegate_;
bool high_visibility_on_ = false;
bool service_observer_bound_ = false;
};
TEST_F(NearbyShareDelegateImplTest, StartHighVisibilityAndTimeout) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(chromeos::features::kQuickShareV2);
InitDelegate();
settings()->SetEnabled(true);
EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
delegate_->EnableHighVisibility();
SetHighVisibilityOn(true);
EXPECT_CALL(nearby_share_service_, ClearForegroundReceiveSurfaces()).Times(0);
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(false)).Times(0);
FastForward(base::Minutes(9));
EXPECT_CALL(nearby_share_service_, ClearForegroundReceiveSurfaces()).Times(1);
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(false)).Times(1);
FastForward(base::Minutes(1));
// DisableHighVisibility will be called automatically after the timer fires.
SetHighVisibilityOn(false);
}
TEST_F(NearbyShareDelegateImplTest, StartHighVisibilityAndTimeout_Legacy) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(chromeos::features::kQuickShareV2);
InitDelegate();
settings()->SetEnabled(true);
EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
delegate_->EnableHighVisibility();
SetHighVisibilityOn(true);
EXPECT_CALL(nearby_share_service_, ClearForegroundReceiveSurfaces());
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(false));
// DisableHighVisibility will be called automatically after the timer fires.
FastForward(base::Minutes(10));
SetHighVisibilityOn(false);
}
TEST_F(NearbyShareDelegateImplTest, StartStopHighVisibility) {
settings()->SetEnabled(true);
EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
delegate_->EnableHighVisibility();
SetHighVisibilityOn(true);
EXPECT_CALL(nearby_share_service_, ClearForegroundReceiveSurfaces());
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(false));
delegate_->DisableHighVisibility();
SetHighVisibilityOn(false);
}
TEST_F(NearbyShareDelegateImplTest, TestIsEnableHighVisibilityRequestActive) {
settings()->SetEnabled(true);
EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
delegate_->EnableHighVisibility();
EXPECT_TRUE(delegate_->IsEnableHighVisibilityRequestActive());
SetHighVisibilityOn(true);
EXPECT_FALSE(delegate_->IsEnableHighVisibilityRequestActive());
}
TEST_F(NearbyShareDelegateImplTest, TestIsEnableOnHighVisibilityRequest) {
settings()->SetEnabled(true);
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
delegate_->OnHighVisibilityChangeRequested();
EXPECT_TRUE(delegate_->IsEnableHighVisibilityRequestActive());
SetHighVisibilityOn(true);
EXPECT_FALSE(delegate_->IsEnableHighVisibilityRequestActive());
}
TEST_F(NearbyShareDelegateImplTest, StopHighVisibilityOnScreenLock) {
settings()->SetEnabled(true);
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(true));
EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
delegate_->EnableHighVisibility();
SetHighVisibilityOn(true);
EXPECT_CALL(controller_, HighVisibilityEnabledChanged(false));
EXPECT_CALL(nearby_share_service_, ClearForegroundReceiveSurfaces());
// DisableHighVisibility will be called when the screen locks.
delegate_->OnLockStateChanged(/*locked=*/true);
SetHighVisibilityOn(false);
}
TEST_F(NearbyShareDelegateImplTest, ShowNearbyShareSettings) {
EXPECT_CALL(*settings_opener_, ShowSettingsPage(_));
delegate_->ShowNearbyShareSettings();
}
TEST_F(NearbyShareDelegateImplTest,
ExpectControllerObservation_OnNearbyShareToggled) {
EXPECT_CALL(controller_, NearbyShareEnabledChanged(true));
settings()->SetEnabled(true);
SetNearbyShareEnabled(true);
EXPECT_CALL(controller_, NearbyShareEnabledChanged(false));
settings()->SetEnabled(false);
SetNearbyShareEnabled(false);
}
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
TEST_F(NearbyShareDelegateImplTest, GetIconFlagEnabledOfficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{::features::kIsNameEnabled},
/*disabled_features=*/{});
EXPECT_FALSE(delegate_->GetIcon(/*on_icon=*/false).is_empty());
EXPECT_FALSE(delegate_->GetIcon(/*on_icon=*/true).is_empty());
}
TEST_F(NearbyShareDelegateImplTest, GetIconFlagDisabledOfficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/{::features::kIsNameEnabled});
EXPECT_TRUE(delegate_->GetIcon(/*on_icon=*/false).is_empty());
EXPECT_TRUE(delegate_->GetIcon(/*on_icon=*/true).is_empty());
}
TEST_F(NearbyShareDelegateImplTest,
GetPlaceholderFeatureNameFlagEnabledOfficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{::features::kIsNameEnabled},
/*disabled_features=*/{});
// Just enforce non empty string for official branded builds..
EXPECT_NE(delegate_->GetPlaceholderFeatureName(), u"");
}
TEST_F(NearbyShareDelegateImplTest,
GetPlaceholderFeatureNameFlagDisabledOfficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/{::features::kIsNameEnabled});
// Returns empty string when feature is disabled or on unofficial build.
EXPECT_EQ(delegate_->GetPlaceholderFeatureName(), u"");
}
TEST_F(NearbyShareDelegateImplTest, SetVisibility) {
settings()->SetEnabled(true);
EXPECT_EQ(settings()->GetVisibility(),
::nearby_share::mojom::Visibility::kNoOne);
delegate_->SetVisibility(::nearby_share::mojom::Visibility::kAllContacts);
EXPECT_CALL(controller_, VisibilityChanged(
::nearby_share::mojom::Visibility::kAllContacts))
.Times(0);
EXPECT_EQ(settings()->GetVisibility(),
::nearby_share::mojom::Visibility::kAllContacts);
}
#else // !BUILDFLAG(GOOGLE_CHROME_BRANDING)
TEST_F(NearbyShareDelegateImplTest, GetIconFlagEnabledUnofficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{::features::kIsNameEnabled},
/*disabled_features=*/{});
EXPECT_TRUE(delegate_->GetIcon(/*on_icon=*/false).is_empty());
EXPECT_TRUE(delegate_->GetIcon(/*on_icon=*/true).is_empty());
}
TEST_F(NearbyShareDelegateImplTest, GetIconFlagDisabledUnofficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/{::features::kIsNameEnabled});
EXPECT_TRUE(delegate_->GetIcon(/*on_icon=*/false).is_empty());
EXPECT_TRUE(delegate_->GetIcon(/*on_icon=*/true).is_empty());
}
TEST_F(NearbyShareDelegateImplTest,
GetPlaceholderFeatureNameFlagEnabledUnofficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{::features::kIsNameEnabled},
/*disabled_features=*/{});
// Returns empty string when feature is disabled or on unofficial build.
EXPECT_EQ(delegate_->GetPlaceholderFeatureName(), u"");
}
TEST_F(NearbyShareDelegateImplTest,
GetPlaceholderFeatureNameFlagDisabledUnofficialBuild) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
/*enabled_features=*/{},
/*disabled_features=*/{::features::kIsNameEnabled});
// Returns empty string when feature is disabled or on unofficial build.
EXPECT_EQ(delegate_->GetPlaceholderFeatureName(), u"");
}
#endif // !BUILDFLAG(GOOGLE_CHROME_BRANDING)