chromium/chrome/installer/util/duplicate_tree_detector_unittest.cc

// Copyright 2011 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/util/duplicate_tree_detector.h"

#include <windows.h>

#include <fstream>
#include <string>

#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/string_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class DuplicateTreeDetectorTest : public testing::Test {
 protected:
  void SetUp() override {
    ASSERT_TRUE(temp_source_dir_.CreateUniqueTempDir());
    ASSERT_TRUE(temp_dest_dir_.CreateUniqueTempDir());
  }

  // Simple function to dump some text into a new file.
  void CreateTextFile(const std::string& filename,
                      const std::wstring& contents) {
    std::wofstream file;
    file.open(filename.c_str());
    ASSERT_TRUE(file.is_open());
    file << contents;
    file.close();
  }

  // Creates a two level deep source dir with a file in each in |first_root| and
  // copy it (files properties will be identical) in |second_root|.
  void CreateTwoIdenticalHierarchies(const base::FilePath& first_root,
                                     const base::FilePath& second_root) {
    base::FilePath d1(first_root);
    d1 = d1.AppendASCII("D1");
    base::CreateDirectory(d1);
    ASSERT_TRUE(base::PathExists(d1));

    base::FilePath f1(d1);
    f1 = f1.AppendASCII("F1");
    CreateTextFile(f1.MaybeAsASCII(), text_content_1_);
    ASSERT_TRUE(base::PathExists(f1));

    base::FilePath d2(d1);
    d2 = d2.AppendASCII("D2");
    base::CreateDirectory(d2);
    ASSERT_TRUE(base::PathExists(d2));

    base::FilePath f2(d2);
    f2 = f2.AppendASCII("F2");
    CreateTextFile(f2.MaybeAsASCII(), text_content_2_);
    ASSERT_TRUE(base::PathExists(f2));

    ASSERT_TRUE(base::CopyDirectory(d1, second_root, true));
  }

  base::ScopedTempDir temp_source_dir_;
  base::ScopedTempDir temp_dest_dir_;

  static const wchar_t text_content_1_[];
  static const wchar_t text_content_2_[];
  static const wchar_t text_content_3_[];
};

const wchar_t DuplicateTreeDetectorTest::text_content_1_[] =
    L"Gooooooooooooooooooooogle";
const wchar_t DuplicateTreeDetectorTest::text_content_2_[] = L"Overwrite Me";
const wchar_t DuplicateTreeDetectorTest::text_content_3_[] =
    L"I'd rather see your watermelon and raise you ham and a half.";

}  // namespace

// Test the DuplicateTreeChecker's definition of identity on two identical
// directory structures.
TEST_F(DuplicateTreeDetectorTest, TestIdenticalDirs) {
  CreateTwoIdenticalHierarchies(temp_source_dir_.GetPath(),
                                temp_dest_dir_.GetPath());

  EXPECT_TRUE(installer::IsIdenticalFileHierarchy(temp_source_dir_.GetPath(),
                                                  temp_dest_dir_.GetPath()));
}

// Test when source entirely contains dest but contains other files as well.
// IsIdenticalTo should return false in this case.
TEST_F(DuplicateTreeDetectorTest, TestSourceContainsDest) {
  CreateTwoIdenticalHierarchies(temp_source_dir_.GetPath(),
                                temp_dest_dir_.GetPath());

  base::FilePath new_file(temp_source_dir_.GetPath());
  new_file = new_file.AppendASCII("FNew");
  CreateTextFile(new_file.MaybeAsASCII(), text_content_1_);
  ASSERT_TRUE(base::PathExists(new_file));

  EXPECT_FALSE(installer::IsIdenticalFileHierarchy(temp_source_dir_.GetPath(),
                                                   temp_dest_dir_.GetPath()));
}

// Test when dest entirely contains source but contains other files as well.
// IsIdenticalTo should return true in this case.
TEST_F(DuplicateTreeDetectorTest, TestDestContainsSource) {
  CreateTwoIdenticalHierarchies(temp_source_dir_.GetPath(),
                                temp_dest_dir_.GetPath());

  base::FilePath new_file(temp_dest_dir_.GetPath());
  new_file = new_file.AppendASCII("FNew");
  CreateTextFile(new_file.MaybeAsASCII(), text_content_1_);
  ASSERT_TRUE(base::PathExists(new_file));

  EXPECT_TRUE(installer::IsIdenticalFileHierarchy(temp_source_dir_.GetPath(),
                                                  temp_dest_dir_.GetPath()));
}

// Test when the file hierarchies are the same but one of the files is changed.
TEST_F(DuplicateTreeDetectorTest, TestIdenticalDirsDifferentFiles) {
  CreateTwoIdenticalHierarchies(temp_source_dir_.GetPath(),
                                temp_dest_dir_.GetPath());

  base::FilePath existing_file(temp_dest_dir_.GetPath());
  existing_file =
      existing_file.AppendASCII("D1").AppendASCII("D2").AppendASCII("F2");
  CreateTextFile(existing_file.MaybeAsASCII(), text_content_3_);

  EXPECT_FALSE(installer::IsIdenticalFileHierarchy(temp_source_dir_.GetPath(),
                                                   temp_dest_dir_.GetPath()));
}

// Test when both file hierarchies are empty.
TEST_F(DuplicateTreeDetectorTest, TestEmptyDirs) {
  EXPECT_TRUE(installer::IsIdenticalFileHierarchy(temp_source_dir_.GetPath(),
                                                  temp_dest_dir_.GetPath()));
}

// Test on single files.
TEST_F(DuplicateTreeDetectorTest, TestSingleFiles) {
  // Create a source file.
  base::FilePath source_file(temp_source_dir_.GetPath());
  source_file = source_file.AppendASCII("F1");
  CreateTextFile(source_file.MaybeAsASCII(), text_content_1_);

  // This file should be the same.
  base::FilePath dest_file(temp_dest_dir_.GetPath());
  dest_file = dest_file.AppendASCII("F1");
  ASSERT_TRUE(base::CopyFile(source_file, dest_file));

  // This file should be different.
  base::FilePath other_file(temp_dest_dir_.GetPath());
  other_file = other_file.AppendASCII("F2");
  CreateTextFile(other_file.MaybeAsASCII(), text_content_2_);

  EXPECT_TRUE(installer::IsIdenticalFileHierarchy(source_file, dest_file));
  EXPECT_FALSE(installer::IsIdenticalFileHierarchy(source_file, other_file));
}