chromium/ios/chrome/browser/push_notification/model/push_notification_settings_util_unittest.mm

// Copyright 2024 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/push_notification/model/push_notification_settings_util.h"

#import "base/files/file_path.h"
#import "base/memory/raw_ptr.h"
#import "base/strings/sys_string_conversions.h"
#import "base/test/scoped_feature_list.h"
#import "components/commerce/core/pref_names.h"
#import "components/prefs/pref_service.h"
#import "components/prefs/scoped_user_pref_update.h"
#import "ios/chrome/browser/push_notification/model/constants.h"
#import "ios/chrome/browser/push_notification/model/push_notification_account_context_manager.h"
#import "ios/chrome/browser/push_notification/model/push_notification_client_id.h"
#import "ios/chrome/browser/push_notification/model/push_notification_client_manager.h"
#import "ios/chrome/browser/push_notification/model/push_notification_service.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/model/profile/profile_attributes_ios.h"
#import "ios/chrome/browser/shared/model/profile/profile_attributes_storage_ios.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_manager_ios.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"

namespace push_notification_settings {

class PushNotificationSettingsUtilTest : public PlatformTest {
 public:
  PushNotificationSettingsUtilTest() {
    TestChromeBrowserState* test_chrome_browser_state =
        profile_manager_.AddProfileWithBuilder(
            TestChromeBrowserState::Builder());

    const std::string browser_state_name =
        test_chrome_browser_state->GetBrowserStateName();
    pref_service_ = test_chrome_browser_state->GetPrefs();

    manager_ = [[PushNotificationAccountContextManager alloc]
        initWithProfileManager:&profile_manager_];
    fake_id_ = [FakeSystemIdentity fakeIdentity1];
    // TODO(b/318863934): Remove flag when enabled by default.
    feature_list_.InitWithFeatures(
        {/*enabled=*/kContentNotificationExperiment, kIOSTipsNotifications,
         kSafetyCheckNotifications},
        {/*disabled=*/});
    AddTestCasesToManager(manager_, profile_attributes_storage(),
                          base::SysNSStringToUTF8(fake_id_.gaiaID),
                          browser_state_name);
  }
  ProfileAttributesStorageIOS* profile_attributes_storage() const {
    return GetApplicationContext()
        ->GetProfileManager()
        ->GetProfileAttributesStorage();
  }
  void TurnNotificationForKey(BOOL on,
                              const std::string key,
                              PrefService* pref_service) {
    ScopedDictPrefUpdate update(pref_service,
                                prefs::kFeaturePushNotificationPermissions);
    update->Set(key, on);
  }
  void TurnAppLevelNotificationForKey(BOOL on, const std::string key) {
    PrefService* pref_service = GetApplicationContext()->GetLocalState();
    ScopedDictPrefUpdate update(pref_service,
                                prefs::kAppLevelPushNotificationPermissions);
    update->Set(key, on);
  }

  void TurnEmailNotifications(BOOL on, PrefService* pref_service) {
    pref_service->SetBoolean(commerce::kPriceEmailNotificationsEnabled, on);
  }
  void AddTestCasesToManager(PushNotificationAccountContextManager* manager,
                             ProfileAttributesStorageIOS* storage,
                             const std::string& gaia_id,
                             const std::string browser_state_name) {
    // Construct the BrowserStates with the given gaia id and add the gaia id
    // into the AccountContextManager.
    storage->UpdateAttributesForProfileWithName(
        browser_state_name,
        base::BindOnce(
            [](const std::string& gaia_id, ProfileAttributesIOS attr) {
              attr.SetAuthenticationInfo(gaia_id, /*user_name=*/std::string());
              return attr;
            },
            gaia_id));
    [manager addAccount:gaia_id];
  }

 protected:
  raw_ptr<PrefService> pref_service_;
  web::WebTaskEnvironment task_environment_;
  IOSChromeScopedTestingLocalState scoped_testing_local_state_;
  TestProfileManagerIOS profile_manager_;
  FakeSystemIdentity* fake_id_;
  PushNotificationAccountContextManager* manager_;
  base::test::ScopedFeatureList feature_list_;
};

#pragma mark - All Clients Test

// Tests the overall permission state, which checks the notification state for
// all clients available on the device. This may include notification types
// other than push notifications.
// When 0 clients are enabled, the state is DISABLED.
// When `enabled` >= 1 AND `disabled` >= 1, the state is INDETERMINANT
// When `enabled` >=1 and `disabled` == 0, then state is ENABLED.
TEST_F(PushNotificationSettingsUtilTest, TestPermissionState) {
  // Enable Notifications in random order.
  ClientPermissionState state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::DISABLED, state);
  TurnNotificationForKey(YES, kCommerceNotificationKey, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnEmailNotifications(YES, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnAppLevelNotificationForKey(YES, kSafetyCheckNotificationKey);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnNotificationForKey(YES, kContentNotificationKey, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnAppLevelNotificationForKey(YES, kTipsNotificationKey);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnNotificationForKey(YES, kSportsNotificationKey, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::ENABLED, state);
  // Start disabling in a different order.
  TurnAppLevelNotificationForKey(NO, kTipsNotificationKey);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnNotificationForKey(NO, kContentNotificationKey, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnAppLevelNotificationForKey(NO, kSafetyCheckNotificationKey);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnNotificationForKey(NO, kCommerceNotificationKey, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnEmailNotifications(NO, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnNotificationForKey(NO, kSportsNotificationKey, pref_service_);
  state = GetNotificationPermissionState(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::DISABLED, state);
}

#pragma mark - Price Tracking Notification Tests

TEST_F(PushNotificationSettingsUtilTest,
       TestMobileNotificationsEnabledForCommerce) {
  BOOL isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_FALSE(isMobileNotificationsEnabled);
  TurnNotificationForKey(YES, kCommerceNotificationKey, pref_service_);
  isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_TRUE(isMobileNotificationsEnabled);
}

TEST_F(PushNotificationSettingsUtilTest,
       TestGetClientPermissionStateForCommerce) {
  ClientPermissionState state = GetClientPermissionState(
      PushNotificationClientId::kCommerce,
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::DISABLED, state);
  TurnNotificationForKey(YES, kCommerceNotificationKey, pref_service_);
  state = GetClientPermissionState(PushNotificationClientId::kCommerce,
                                   base::SysNSStringToUTF8(fake_id_.gaiaID),
                                   pref_service_);
  EXPECT_EQ(ClientPermissionState::INDETERMINANT, state);
  TurnEmailNotifications(YES, pref_service_);
  state = GetClientPermissionState(PushNotificationClientId::kCommerce,
                                   base::SysNSStringToUTF8(fake_id_.gaiaID),
                                   pref_service_);
  EXPECT_EQ(ClientPermissionState::ENABLED, state);
}

#pragma mark - Content Notification Tests

TEST_F(PushNotificationSettingsUtilTest,
       TestMobileNotificationsEnabledForContent) {
  BOOL isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_FALSE(isMobileNotificationsEnabled);
  TurnNotificationForKey(YES, kContentNotificationKey, pref_service_);
  isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_TRUE(isMobileNotificationsEnabled);
}

TEST_F(PushNotificationSettingsUtilTest,
       TestGetClientPermissionStateForContent) {
  ClientPermissionState state = GetClientPermissionState(
      PushNotificationClientId::kContent,
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::DISABLED, state);
  TurnNotificationForKey(YES, kContentNotificationKey, pref_service_);
  state = GetClientPermissionState(PushNotificationClientId::kContent,
                                   base::SysNSStringToUTF8(fake_id_.gaiaID),
                                   pref_service_);
  EXPECT_EQ(ClientPermissionState::ENABLED, state);
}

TEST_F(PushNotificationSettingsUtilTest,
       TestMobileNotificationsEnabledForSports) {
  BOOL isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_FALSE(isMobileNotificationsEnabled);
  TurnNotificationForKey(YES, kSportsNotificationKey, pref_service_);
  isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_TRUE(isMobileNotificationsEnabled);
}

TEST_F(PushNotificationSettingsUtilTest,
       TestGetClientPermissionStateForSports) {
  ClientPermissionState state = GetClientPermissionState(
      PushNotificationClientId::kSports,
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::DISABLED, state);
  TurnNotificationForKey(YES, kSportsNotificationKey, pref_service_);
  state = GetClientPermissionState(PushNotificationClientId::kSports,
                                   base::SysNSStringToUTF8(fake_id_.gaiaID),
                                   pref_service_);
  EXPECT_EQ(ClientPermissionState::ENABLED, state);
}

#pragma mark - Tips Notifications Tests

TEST_F(PushNotificationSettingsUtilTest,
       TestMobileNotificationsEnabledForTips) {
  BOOL isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_FALSE(isMobileNotificationsEnabled);
  TurnAppLevelNotificationForKey(YES, kTipsNotificationKey);
  isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_TRUE(isMobileNotificationsEnabled);
}

TEST_F(PushNotificationSettingsUtilTest, TestGetClientPermissionStateForTips) {
  ClientPermissionState state = GetClientPermissionState(
      PushNotificationClientId::kTips, base::SysNSStringToUTF8(fake_id_.gaiaID),
      pref_service_);
  EXPECT_EQ(ClientPermissionState::DISABLED, state);
  TurnAppLevelNotificationForKey(YES, kTipsNotificationKey);
  state = GetClientPermissionState(PushNotificationClientId::kTips,
                                   base::SysNSStringToUTF8(fake_id_.gaiaID),
                                   pref_service_);
  EXPECT_EQ(ClientPermissionState::ENABLED, state);
}

#pragma mark - Safety Check Notifications Tests

TEST_F(PushNotificationSettingsUtilTest,
       TestMobileNotificationsEnabledForSafetyCheck) {
  BOOL isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_FALSE(isMobileNotificationsEnabled);
  TurnAppLevelNotificationForKey(YES, kSafetyCheckNotificationKey);
  isMobileNotificationsEnabled = IsMobileNotificationsEnabledForAnyClient(
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_TRUE(isMobileNotificationsEnabled);
}

TEST_F(PushNotificationSettingsUtilTest,
       TestGetClientPermissionStateForSafetyCheck) {
  ClientPermissionState state = GetClientPermissionState(
      PushNotificationClientId::kSafetyCheck,
      base::SysNSStringToUTF8(fake_id_.gaiaID), pref_service_);
  EXPECT_EQ(ClientPermissionState::DISABLED, state);
  TurnAppLevelNotificationForKey(YES, kSafetyCheckNotificationKey);
  state = GetClientPermissionState(PushNotificationClientId::kSafetyCheck,
                                   base::SysNSStringToUTF8(fake_id_.gaiaID),
                                   pref_service_);
  EXPECT_EQ(ClientPermissionState::ENABLED, state);
}

}  // namespace push_notification_settings