chromium/chrome/installer/setup/unpack_archive_unittest.cc

// 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.

#include "chrome/installer/setup/unpack_archive.h"

#include <string>

#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/types/expected.h"
#include "chrome/installer/setup/installer_state.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/util_constants.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace installer {

namespace {

base::FilePath GetTestFileRootPath() {
  base::FilePath test_data_root;
  base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &test_data_root);
  return test_data_root.Append(FILE_PATH_LITERAL("chrome"))
      .Append(FILE_PATH_LITERAL("test"))
      .Append(FILE_PATH_LITERAL("data"))
      .Append(FILE_PATH_LITERAL("installer"));
}

}  // namespace

class FakeInstallerState : public InstallerState {
 public:
  FakeInstallerState() { set_level(Level::SYSTEM_LEVEL); }
};

struct UnpackParams {
  UnpackParams(base::FilePath test_file,
               std::string archive_switch,
               bool uncompressed_output_matches_input_file)
      : test_file(test_file),
        archive_switch(archive_switch),
        uncompressed_output_matches_input_file(
            uncompressed_output_matches_input_file) {}

  base::FilePath test_file;
  std::string archive_switch;
  bool uncompressed_output_matches_input_file;
};

class SetupUnpackArchiveTest : public testing::TestWithParam<UnpackParams> {};

INSTANTIATE_TEST_SUITE_P(UnpackCompressedArchive,
                         SetupUnpackArchiveTest,
                         ::testing::Values(UnpackParams(
                             GetTestFileRootPath().Append(
                                 FILE_PATH_LITERAL("test_chrome.packed.7z")),
                             "install-archive",
                             false)));

// In this case, since the uncompressed archive was passed directly, the input
// archive path should match the output archive path.
INSTANTIATE_TEST_SUITE_P(
    UnpackUncompressedArchive,
    SetupUnpackArchiveTest,
    ::testing::Values(UnpackParams(
        GetTestFileRootPath().Append(FILE_PATH_LITERAL("test_chrome.7z")),
        "uncompressed-archive",
        true)));

// Tests that the setup is able to decompress chrome.packed.7z and unpack the
// chrome.7z archive it contains, when specified via the `--install-archive`
// flag.
TEST_P(SetupUnpackArchiveTest, UnpackArchive) {
  base::FilePath chrome_archive = GetParam().test_file;

  base::ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());

  InstallationState original_state;  // Unused when not patching.
  base::CommandLine cmd_line = base::CommandLine::FromString(L"setup.exe");
  cmd_line.AppendSwitchPath(GetParam().archive_switch, chrome_archive);
  FakeInstallerState installer_state;
  ArchiveType archive_type;
  base::FilePath uncompressed_chrome_archive_out;

  base::expected<void, InstallStatus> result = UnpackAndMaybePatchChromeArchive(
      temp_dir.GetPath(), original_state,
      base::FilePath(),  // Unused when archive is provided via cmd_line.
      cmd_line, installer_state, &archive_type,
      uncompressed_chrome_archive_out);
  ASSERT_TRUE(result.has_value()) << result.error();

  // Instead of containing "chrome-bin", the test archives contain this
  // "test_data.txt". Make sure the output file exists and matches the test
  // data.
  std::string actual_installer_data;
  EXPECT_TRUE(base::ReadFileToString(base::FilePath(temp_dir.GetPath().Append(
                                         FILE_PATH_LITERAL("test_data.txt"))),
                                     &actual_installer_data));
  EXPECT_STREQ(actual_installer_data.c_str(), "fakechromiumdata");

  EXPECT_EQ(uncompressed_chrome_archive_out,
            GetParam().uncompressed_output_matches_input_file
                ? chrome_archive
                : temp_dir.GetPath().Append(FILE_PATH_LITERAL("chrome.7z")));
  ASSERT_EQ(archive_type, ArchiveType::FULL_ARCHIVE_TYPE);
}

TEST(SetupUnpackArchiveTest, UnpackFailsWhenCompressedAndUncompressedProvided) {
  base::ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());

  InstallationState original_state;  // Unused when not patching.
  base::CommandLine cmd_line = base::CommandLine::FromString(L"setup.exe");
  cmd_line.AppendSwitchPath(
      "install-archive",
      GetTestFileRootPath().Append(FILE_PATH_LITERAL("test_chrome.packed.7z")));
  cmd_line.AppendSwitchPath(
      "uncompressed-archive",
      GetTestFileRootPath().Append(FILE_PATH_LITERAL("test_chrome.7z")));
  FakeInstallerState installer_state;
  ArchiveType archive_type;
  base::FilePath uncompressed_chrome_archive_out;

  base::expected<void, InstallStatus> result = UnpackAndMaybePatchChromeArchive(
      temp_dir.GetPath(), original_state,
      base::FilePath(),  // Unused when archive is provided via cmd_line.
      cmd_line, installer_state, &archive_type,
      uncompressed_chrome_archive_out);
  ASSERT_FALSE(result.has_value());
  ASSERT_EQ(result.error(), UNSUPPORTED_OPTION);
}

}  // namespace installer