| // 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_settings.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/containers/contains.h" | 
 | #include "base/feature_list.h" | 
 | #include "base/run_loop.h" | 
 | #include "base/test/bind.h" | 
 | #include "base/test/scoped_feature_list.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/test/base/testing_browser_process.h" | 
 | #include "chrome/test/base/testing_profile.h" | 
 | #include "chrome/test/base/testing_profile_manager.h" | 
 | #include "chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom-test-utils.h" | 
 | #include "chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom.h" | 
 | #include "chromeos/constants/chromeos_features.h" | 
 | #include "components/prefs/testing_pref_service.h" | 
 | #include "content/public/test/browser_task_environment.h" | 
 | #include "content/public/test/test_utils.h" | 
 | #include "mojo/public/cpp/bindings/pending_receiver.h" | 
 | #include "mojo/public/cpp/bindings/receiver.h" | 
 | #include "testing/gmock/include/gmock/gmock.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace { | 
 |  | 
 | const char kDefaultDeviceName[] = "Josh's Chromebook"; | 
 |  | 
 | }  // namespace | 
 |  | 
 | using NearbyShareSettingsAsyncWaiter = | 
 |     nearby_share::mojom::NearbyShareSettingsAsyncWaiter; | 
 |  | 
 | class FakeNearbyShareSettingsObserver | 
 |     : public nearby_share::mojom::NearbyShareSettingsObserver { | 
 |  public: | 
 |   void OnEnabledChanged(bool enabled) override { enabled_ = enabled; } | 
 |   void OnFastInitiationNotificationStateChanged( | 
 |       nearby_share::mojom::FastInitiationNotificationState state) override { | 
 |     fast_initiation_notification_state_ = state; | 
 |   } | 
 |   void OnIsFastInitiationHardwareSupportedChanged(bool is_supported) override { | 
 |     is_fast_initiation_notification_hardware_supported_ = is_supported; | 
 |   } | 
 |   void OnDeviceNameChanged(const std::string& device_name) override { | 
 |     device_name_ = device_name; | 
 |   } | 
 |   void OnDataUsageChanged(nearby_share::mojom::DataUsage data_usage) override { | 
 |     data_usage_ = data_usage; | 
 |   } | 
 |   void OnVisibilityChanged( | 
 |       nearby_share::mojom::Visibility visibility) override { | 
 |     visibility_ = visibility; | 
 |   } | 
 |   void OnAllowedContactsChanged( | 
 |       const std::vector<std::string>& allowed_contacts) override { | 
 |     allowed_contacts_ = allowed_contacts; | 
 |   } | 
 |   void OnIsOnboardingCompleteChanged(bool is_complete) override { | 
 |     is_onboarding_complete_ = is_complete; | 
 |   } | 
 |  | 
 |   bool enabled_ = false; | 
 |   nearby_share::mojom::FastInitiationNotificationState | 
 |       fast_initiation_notification_state_ = | 
 |           nearby_share::mojom::FastInitiationNotificationState::kEnabled; | 
 |   bool is_fast_initiation_notification_hardware_supported_ = false; | 
 |   bool is_onboarding_complete_ = false; | 
 |   std::string device_name_ = "uncalled"; | 
 |   nearby_share::mojom::DataUsage data_usage_ = | 
 |       nearby_share::mojom::DataUsage::kUnknown; | 
 |   nearby_share::mojom::Visibility visibility_ = | 
 |       nearby_share::mojom::Visibility::kUnknown; | 
 |   std::vector<std::string> allowed_contacts_; | 
 |   mojo::Receiver<nearby_share::mojom::NearbyShareSettingsObserver> receiver_{ | 
 |       this}; | 
 | }; | 
 |  | 
 | class NearbyShareSettingsTest : public ::testing::Test { | 
 |  public: | 
 |   NearbyShareSettingsTest() : local_device_data_manager_(kDefaultDeviceName) { | 
 |     RegisterNearbySharingPrefs(pref_service_.registry()); | 
 |     nearby_share_settings_ = std::make_unique<NearbyShareSettings>( | 
 |         &pref_service_, &local_device_data_manager_); | 
 |     nearby_share_settings_waiter_ = | 
 |         std::make_unique<NearbyShareSettingsAsyncWaiter>( | 
 |             nearby_share_settings_.get()); | 
 |  | 
 |     nearby_share_settings_->AddSettingsObserver( | 
 |         observer_.receiver_.BindNewPipeAndPassRemote()); | 
 |   } | 
 |   ~NearbyShareSettingsTest() override = default; | 
 |  | 
 |   void FlushMojoMessages() { observer_.receiver_.FlushForTesting(); } | 
 |  | 
 |   NearbyShareSettings* settings() { return nearby_share_settings_.get(); } | 
 |  | 
 |   NearbyShareSettingsAsyncWaiter* settings_waiter() { | 
 |     return nearby_share_settings_waiter_.get(); | 
 |   } | 
 |  | 
 |   void SetIsOnboardingComplete(bool is_complete) { | 
 |     pref_service_.SetBoolean(prefs::kNearbySharingOnboardingCompletePrefName, | 
 |                              is_complete); | 
 |   } | 
 |  | 
 |  protected: | 
 |   content::BrowserTaskEnvironment task_environment_; | 
 |   TestingPrefServiceSimple pref_service_; | 
 |   FakeNearbyShareLocalDeviceDataManager local_device_data_manager_; | 
 |   FakeNearbyShareSettingsObserver observer_; | 
 |   std::unique_ptr<NearbyShareSettings> nearby_share_settings_; | 
 |   std::unique_ptr<NearbyShareSettingsAsyncWaiter> nearby_share_settings_waiter_; | 
 |   base::test::ScopedFeatureList feature_list_; | 
 | }; | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetEnabled) { | 
 |   EXPECT_FALSE(observer_.enabled_); | 
 |   settings()->SetIsOnboardingComplete(true); | 
 |   settings()->SetEnabled(true); | 
 |   EXPECT_TRUE(settings()->GetEnabled()); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_TRUE(observer_.enabled_); | 
 |  | 
 |   bool enabled = false; | 
 |   settings_waiter()->GetEnabled(&enabled); | 
 |   EXPECT_TRUE(enabled); | 
 |  | 
 |   settings()->SetEnabled(false); | 
 |   EXPECT_FALSE(settings()->GetEnabled()); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_FALSE(observer_.enabled_); | 
 |  | 
 |   settings_waiter()->GetEnabled(&enabled); | 
 |   EXPECT_FALSE(enabled); | 
 |  | 
 |   // Verify that setting the value to false again value doesn't trigger an | 
 |   // observer event. | 
 |   observer_.enabled_ = true; | 
 |   settings()->SetEnabled(false); | 
 |   EXPECT_FALSE(settings()->GetEnabled()); | 
 |   FlushMojoMessages(); | 
 |   // the observers's value should not have been updated. | 
 |   EXPECT_TRUE(observer_.enabled_); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetFastInitiationNotificationState) { | 
 |   // Fast init notifications are enabled by default. | 
 |   EXPECT_EQ(nearby_share::mojom::FastInitiationNotificationState::kEnabled, | 
 |             observer_.fast_initiation_notification_state_); | 
 |   settings()->SetFastInitiationNotificationState( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByUser); | 
 |   EXPECT_EQ( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByUser, | 
 |       settings()->GetFastInitiationNotificationState()); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_EQ( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByUser, | 
 |       observer_.fast_initiation_notification_state_); | 
 |  | 
 |   nearby_share::mojom::FastInitiationNotificationState state = | 
 |       nearby_share::mojom::FastInitiationNotificationState::kEnabled; | 
 |   settings_waiter()->GetFastInitiationNotificationState(&state); | 
 |   EXPECT_EQ( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByUser, | 
 |       state); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, | 
 |        ParentFeatureChangesFastInitiationNotificationState) { | 
 |   // Fast init notifications are enabled by default. | 
 |   EXPECT_EQ(nearby_share::mojom::FastInitiationNotificationState::kEnabled, | 
 |             observer_.fast_initiation_notification_state_); | 
 |   settings()->SetIsOnboardingComplete(true); | 
 |   settings()->SetEnabled(true); | 
 |   FlushMojoMessages(); | 
 |  | 
 |   // Simulate toggling the parent feature off. | 
 |   settings()->SetEnabled(false); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_FALSE(settings()->GetEnabled()); | 
 |   EXPECT_EQ( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByFeature, | 
 |       observer_.fast_initiation_notification_state_); | 
 |  | 
 |   // Simulate toggling the parent feature on. | 
 |   settings()->SetEnabled(true); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_TRUE(settings()->GetEnabled()); | 
 |   EXPECT_EQ(nearby_share::mojom::FastInitiationNotificationState::kEnabled, | 
 |             observer_.fast_initiation_notification_state_); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, | 
 |        ParentFeatureChangesFastInitiationNotificationDisabedByUser) { | 
 |   // Fast init notifications are enabled by default. | 
 |   EXPECT_EQ(nearby_share::mojom::FastInitiationNotificationState::kEnabled, | 
 |             observer_.fast_initiation_notification_state_); | 
 |  | 
 |   // Set explicitly disabled by user. | 
 |   settings()->SetFastInitiationNotificationState( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByUser); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_EQ( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByUser, | 
 |       observer_.fast_initiation_notification_state_); | 
 |  | 
 |   // Simulate toggling parent feature on. | 
 |   settings()->SetIsOnboardingComplete(true); | 
 |   settings()->SetEnabled(true); | 
 |   FlushMojoMessages(); | 
 |  | 
 |   // Disabled by user should persist if parent feature was turned on. | 
 |   EXPECT_EQ( | 
 |       nearby_share::mojom::FastInitiationNotificationState::kDisabledByUser, | 
 |       observer_.fast_initiation_notification_state_); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetIsOnboardingComplete) { | 
 |   EXPECT_FALSE(observer_.is_onboarding_complete_); | 
 |   SetIsOnboardingComplete(true); | 
 |   EXPECT_TRUE(settings()->IsOnboardingComplete()); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_TRUE(observer_.is_onboarding_complete_); | 
 |  | 
 |   bool is_complete = false; | 
 |   settings_waiter()->IsOnboardingComplete(&is_complete); | 
 |   EXPECT_TRUE(is_complete); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetIsFastInitiationHardwareSupported) { | 
 |   EXPECT_FALSE(observer_.is_fast_initiation_notification_hardware_supported_); | 
 |   settings()->SetIsFastInitiationHardwareSupported(true); | 
 |  | 
 |   FlushMojoMessages(); | 
 |   EXPECT_TRUE(observer_.is_fast_initiation_notification_hardware_supported_); | 
 |  | 
 |   bool is_supported = false; | 
 |   settings_waiter()->GetIsFastInitiationHardwareSupported(&is_supported); | 
 |   EXPECT_TRUE(is_supported); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, ValidateDeviceName) { | 
 |   auto result = nearby_share::mojom::DeviceNameValidationResult::kValid; | 
 |   local_device_data_manager_.set_next_validation_result( | 
 |       nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty); | 
 |   settings_waiter()->ValidateDeviceName("", &result); | 
 |   EXPECT_EQ(result, | 
 |             nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty); | 
 |  | 
 |   local_device_data_manager_.set_next_validation_result( | 
 |       nearby_share::mojom::DeviceNameValidationResult::kValid); | 
 |   settings_waiter()->ValidateDeviceName("this string is 32 bytes in UTF-8", | 
 |                                         &result); | 
 |   EXPECT_EQ(result, nearby_share::mojom::DeviceNameValidationResult::kValid); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetDeviceName) { | 
 |   std::string name = "not_the_default"; | 
 |   settings_waiter()->GetDeviceName(&name); | 
 |   EXPECT_EQ(kDefaultDeviceName, name); | 
 |  | 
 |   // When we get a validation error, setting the name should not succeed. | 
 |   EXPECT_EQ("uncalled", observer_.device_name_); | 
 |   auto result = nearby_share::mojom::DeviceNameValidationResult::kValid; | 
 |   local_device_data_manager_.set_next_validation_result( | 
 |       nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty); | 
 |   settings_waiter()->SetDeviceName("", &result); | 
 |   EXPECT_EQ(result, | 
 |             nearby_share::mojom::DeviceNameValidationResult::kErrorEmpty); | 
 |   EXPECT_EQ(kDefaultDeviceName, settings()->GetDeviceName()); | 
 |  | 
 |   // When the name is valid, setting should succeed. | 
 |   EXPECT_EQ("uncalled", observer_.device_name_); | 
 |   result = nearby_share::mojom::DeviceNameValidationResult::kValid; | 
 |   local_device_data_manager_.set_next_validation_result( | 
 |       nearby_share::mojom::DeviceNameValidationResult::kValid); | 
 |   settings_waiter()->SetDeviceName("d", &result); | 
 |   EXPECT_EQ(result, nearby_share::mojom::DeviceNameValidationResult::kValid); | 
 |   EXPECT_EQ("d", settings()->GetDeviceName()); | 
 |  | 
 |   EXPECT_EQ("uncalled", observer_.device_name_); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_EQ("d", observer_.device_name_); | 
 |  | 
 |   settings_waiter()->GetDeviceName(&name); | 
 |   EXPECT_EQ("d", name); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetDataUsage) { | 
 |   EXPECT_EQ(nearby_share::mojom::DataUsage::kUnknown, observer_.data_usage_); | 
 |   settings()->SetDataUsage(nearby_share::mojom::DataUsage::kOffline); | 
 |   EXPECT_EQ(nearby_share::mojom::DataUsage::kOffline, | 
 |             settings()->GetDataUsage()); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_EQ(nearby_share::mojom::DataUsage::kOffline, observer_.data_usage_); | 
 |  | 
 |   nearby_share::mojom::DataUsage data_usage = | 
 |       nearby_share::mojom::DataUsage::kUnknown; | 
 |   settings_waiter()->GetDataUsage(&data_usage); | 
 |   EXPECT_EQ(nearby_share::mojom::DataUsage::kOffline, data_usage); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetVisibility) { | 
 |   EXPECT_EQ(nearby_share::mojom::Visibility::kUnknown, observer_.visibility_); | 
 |   settings()->SetVisibility(nearby_share::mojom::Visibility::kNoOne); | 
 |   EXPECT_EQ(nearby_share::mojom::Visibility::kNoOne, | 
 |             settings()->GetVisibility()); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_EQ(nearby_share::mojom::Visibility::kNoOne, observer_.visibility_); | 
 |  | 
 |   nearby_share::mojom::Visibility visibility = | 
 |       nearby_share::mojom::Visibility::kUnknown; | 
 |   settings_waiter()->GetVisibility(&visibility); | 
 |   EXPECT_EQ(nearby_share::mojom::Visibility::kNoOne, visibility); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, GetAndSetAllowedContacts) { | 
 |   const std::string id1("1"); | 
 |  | 
 |   std::vector<std::string> allowed_contacts; | 
 |  | 
 |   settings_waiter()->GetAllowedContacts(&allowed_contacts); | 
 |   EXPECT_EQ(0u, allowed_contacts.size()); | 
 |  | 
 |   settings()->SetAllowedContacts({id1}); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_EQ(1u, observer_.allowed_contacts_.size()); | 
 |   EXPECT_TRUE(base::Contains(observer_.allowed_contacts_, id1)); | 
 |  | 
 |   settings_waiter()->GetAllowedContacts(&allowed_contacts); | 
 |   EXPECT_EQ(1u, allowed_contacts.size()); | 
 |   EXPECT_TRUE(base::Contains(allowed_contacts, id1)); | 
 |  | 
 |   settings()->SetAllowedContacts({}); | 
 |   FlushMojoMessages(); | 
 |   EXPECT_EQ(0u, observer_.allowed_contacts_.size()); | 
 |  | 
 |   settings_waiter()->GetAllowedContacts(&allowed_contacts); | 
 |   EXPECT_EQ(0u, allowed_contacts.size()); | 
 | } | 
 |  | 
 | TEST_F(NearbyShareSettingsTest, QuickShareV2_SomeContacts_ToYourDevices) { | 
 |   feature_list_.InitAndEnableFeature(chromeos::features::kQuickShareV2); | 
 |   pref_service_.SetInteger( | 
 |       prefs::kNearbySharingBackgroundVisibilityName, | 
 |       static_cast<int>(nearby_share::mojom::Visibility::kSelectedContacts)); | 
 |  | 
 |   // Since some contacts -> your devices occurs in constructor, new | 
 |   // NearbyShareSettings object must be created after QuickShareV2 is enabled. | 
 |   NearbyShareSettings nearby_share_settings(&pref_service_, | 
 |                                             &local_device_data_manager_); | 
 |  | 
 |   EXPECT_EQ(nearby_share_settings.GetVisibility(), | 
 |             nearby_share::mojom::Visibility::kYourDevices); | 
 | } |