chromium/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc

// Copyright 2015 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/safe_browsing/incident_reporting/platform_state_store.h"

#include <windows.h>

#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
#include "build/branding_buildflags.h"
#include "chrome/browser/prefs/browser_prefs.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 "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_notifier_impl.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"

namespace safe_browsing {
namespace platform_state_store {

namespace {

const char kTestData_[] = "comme un poisson";
const DWORD kTestDataSize_ = sizeof(kTestData_) - 1;

}  // namespace

class PlatformStateStoreWinTest : public ::testing::Test {
 protected:
  PlatformStateStoreWinTest()
      : profile_(nullptr),
        profile_manager_(TestingBrowserProcess::GetGlobal()) {}

  PlatformStateStoreWinTest(const PlatformStateStoreWinTest&) = delete;
  PlatformStateStoreWinTest& operator=(const PlatformStateStoreWinTest&) =
      delete;

  void SetUp() override {
    ::testing::Test::SetUp();
    ASSERT_NO_FATAL_FAILURE(
        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
    ASSERT_TRUE(profile_manager_.SetUp());
  }

  // Creates/resets |profile_|. If |new_profile| is true, the profile will
  // believe that it is new (Profile::IsNewProfile() will return true).
  void ResetProfile(bool new_profile) {
    if (profile_) {
      profile_manager_.DeleteTestingProfile(kProfileName_);
      profile_ = nullptr;
    }
    std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs(
        new sync_preferences::TestingPrefServiceSyncable);
    RegisterUserProfilePrefs(prefs->registry());
    profile_ = profile_manager_.CreateTestingProfile(
        kProfileName_, std::move(prefs), base::UTF8ToUTF16(kProfileName_), 0,
        TestingProfile::TestingFactories(), /*is_supervised_profile=*/false,
        std::optional<bool>(new_profile));
    if (new_profile)
      ASSERT_TRUE(profile_->IsNewProfile());
    else
      ASSERT_FALSE(profile_->IsNewProfile());
  }

  void WriteTestData() {
    base::win::RegKey key;
    ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kStoreKeyName_,
                                        KEY_SET_VALUE | KEY_WOW64_32KEY));
    ASSERT_EQ(ERROR_SUCCESS,
              key.WriteValue(base::UTF8ToWide(kProfileName_).c_str(),
                             &kTestData_[0], kTestDataSize_, REG_BINARY));
  }

  void AssertTestDataIsAbsent() {
    base::win::RegKey key;
    ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kStoreKeyName_,
                                      KEY_QUERY_VALUE | KEY_WOW64_32KEY));
    ASSERT_FALSE(key.HasValue(base::UTF8ToWide(kProfileName_).c_str()));
  }

  void AssertTestDataIsPresent() {
    char buffer[kTestDataSize_] = {};
    base::win::RegKey key;
    ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kStoreKeyName_,
                                      KEY_QUERY_VALUE | KEY_WOW64_32KEY));
    DWORD data_size = kTestDataSize_;
    DWORD data_type = REG_NONE;
    ASSERT_EQ(ERROR_SUCCESS,
              key.ReadValue(base::UTF8ToWide(kProfileName_).c_str(), &buffer[0],
                            &data_size, &data_type));
    EXPECT_EQ(static_cast<DWORD>(REG_BINARY), data_type);
    ASSERT_EQ(kTestDataSize_, data_size);
    EXPECT_EQ(std::string(&buffer[0], data_size),
              std::string(&kTestData_[0], kTestDataSize_));
  }

  static const char kProfileName_[];
  static const wchar_t kStoreKeyName_[];
  raw_ptr<TestingProfile, DanglingUntriaged> profile_;

 private:
  content::BrowserTaskEnvironment task_environment_;
  registry_util::RegistryOverrideManager registry_override_manager_;
  TestingProfileManager profile_manager_;
};

// static
const char PlatformStateStoreWinTest::kProfileName_[] = "test_profile";
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
const wchar_t PlatformStateStoreWinTest::kStoreKeyName_[] =
    L"Software\\Google\\Chrome\\IncidentsSent";
#elif BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING)
const wchar_t PlatformStateStoreWinTest::kStoreKeyName_[] =
    L"Software\\Google\\Chrome for Testing\\IncidentsSent";
#else
const wchar_t PlatformStateStoreWinTest::kStoreKeyName_[] =
    L"Software\\Chromium\\IncidentsSent";
#endif

// Tests that store data is written correctly to the proper location.
TEST_F(PlatformStateStoreWinTest, WriteStoreData) {
  ResetProfile(false /* !new_profile */);

  ASSERT_FALSE(base::win::RegKey(HKEY_CURRENT_USER, kStoreKeyName_,
                                 KEY_QUERY_VALUE | KEY_WOW64_32KEY)
                   .HasValue(base::UTF8ToWide(kProfileName_).c_str()));
  WriteStoreData(profile_, kTestData_);
  AssertTestDataIsPresent();
}

// Tests that store data is read from the proper location.
TEST_F(PlatformStateStoreWinTest, ReadStoreData) {
  // Put some data in the registry.
  WriteTestData();

  ResetProfile(false /* !new_profile */);
  std::string data;
  PlatformStateStoreLoadResult result = ReadStoreData(profile_, &data);
  EXPECT_EQ(PlatformStateStoreLoadResult::SUCCESS, result);
  EXPECT_EQ(std::string(&kTestData_[0], kTestDataSize_), data);
}

// Tests that an empty write clears the stored data.
TEST_F(PlatformStateStoreWinTest, WriteEmptyStoreData) {
  // Put some data in the registry.
  WriteTestData();

  ResetProfile(false /* !new_profile */);

  WriteStoreData(profile_, std::string());
  AssertTestDataIsAbsent();
}

// Tests that data in the registry is ignored if the profile is new.
TEST_F(PlatformStateStoreWinTest, ReadNewProfileClearData) {
  ResetProfile(true /* new_profile */);

  // Put some data in the registry.
  WriteTestData();

  std::string data;
  PlatformStateStoreLoadResult result = ReadStoreData(profile_, &data);
  EXPECT_EQ(PlatformStateStoreLoadResult::CLEARED_DATA, result);
  EXPECT_EQ(std::string(), data);
  AssertTestDataIsAbsent();
}

}  // namespace platform_state_store
}  // namespace safe_browsing