|  | // Copyright 2025 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <string_view> | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/base_paths.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/run_loop.h" | 
|  | #include "base/test/bind.h" | 
|  | #include "base/test/task_environment.h" | 
|  | #include "components/services/patch/file_patcher_impl.h" | 
|  | #include "components/services/patch/in_process_file_patcher.h" | 
|  | #include "components/services/patch/public/cpp/patch.h" | 
|  | #include "mojo/public/cpp/bindings/remote.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace patch { | 
|  | namespace { | 
|  |  | 
|  | base::FilePath TestFile(std::string_view basename) { | 
|  | base::FilePath path; | 
|  | EXPECT_TRUE(base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &path)); | 
|  | return path.AppendASCII("components") | 
|  | .AppendASCII("test") | 
|  | .AppendASCII("data") | 
|  | .AppendASCII("patch_service") | 
|  | .AppendASCII(basename); | 
|  | } | 
|  |  | 
|  | int DoZucchini(const base::FilePath& old_file, | 
|  | const base::FilePath& patch_file, | 
|  | const base::FilePath& new_file) { | 
|  | base::RunLoop run_loop; | 
|  | zucchini::status::Code result = zucchini::status::kStatusSuccess; | 
|  | base::File old = | 
|  | base::File(old_file, base::File::FLAG_OPEN | base::File::FLAG_READ); | 
|  | base::File patch = | 
|  | base::File(patch_file, base::File::FLAG_OPEN | base::File::FLAG_READ); | 
|  | base::File output = base::File( | 
|  | new_file, base::File::FLAG_CREATE | base::File::FLAG_READ | | 
|  | base::File::FLAG_WRITE | base::File::FLAG_WIN_SHARE_DELETE | | 
|  | base::File::FLAG_CAN_DELETE_ON_CLOSE); | 
|  | EXPECT_TRUE(old.IsValid()); | 
|  | EXPECT_TRUE(patch.IsValid()); | 
|  | EXPECT_TRUE(output.IsValid()); | 
|  | ZucchiniPatch(LaunchInProcessFilePatcher(), std::move(old), std::move(patch), | 
|  | std::move(output), | 
|  | base::BindLambdaForTesting([&](zucchini::status::Code code) { | 
|  | result = code; | 
|  | run_loop.QuitClosure().Run(); | 
|  | })); | 
|  | run_loop.Run(); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class PatchTest : public testing::Test { | 
|  | protected: | 
|  | void SetUp() override { | 
|  | ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 
|  | new_file_ = temp_dir_.GetPath().AppendASCII("new_file"); | 
|  | } | 
|  |  | 
|  | base::test::TaskEnvironment task_environment_; | 
|  | base::ScopedTempDir temp_dir_; | 
|  | base::FilePath new_file_; | 
|  | }; | 
|  |  | 
|  | TEST_F(PatchTest, ZucchiniPatchSuccess) { | 
|  | ASSERT_EQ(DoZucchini(TestFile("old_file"), TestFile("patch_file"), new_file_), | 
|  | 0); | 
|  | EXPECT_EQ(ReadFileToBytes(new_file_), ReadFileToBytes(TestFile("new_file"))); | 
|  | } | 
|  |  | 
|  | TEST_F(PatchTest, ZucchiniPatchFail) { | 
|  | ASSERT_NE(DoZucchini(TestFile("new_file"), TestFile("patch_file"), new_file_), | 
|  | 0); | 
|  | } | 
|  |  | 
|  | TEST_F(PatchTest, ZucchiniPatchMalformed) { | 
|  | ASSERT_NE(DoZucchini(TestFile("old_file"), TestFile("old_file"), new_file_), | 
|  | 0); | 
|  | } | 
|  |  | 
|  | }  // namespace patch |