// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "extensions/browser/file_reader.h" #include "base/bind.h" #include "base/callback_helpers.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/path_service.h" #include "base/run_loop.h" #include "base/test/task_environment.h" #include "components/crx_file/id_util.h" #include "extensions/common/extension_paths.h" #include "extensions/common/extension_resource.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace extensions { class FileReaderTest : public testing::Test { public: FileReaderTest() {} private: base::test::TaskEnvironment task_environment_; DISALLOW_COPY_AND_ASSIGN(FileReaderTest); }; class Receiver { public: explicit Receiver(std::vector resources) : file_reader_(base::MakeRefCounted( std::move(resources), FileReader::OptionalFileSequenceTask(), base::BindOnce(&Receiver::DidReadFile, base::Unretained(this)))) {} void Run() { file_reader_->Start(); run_loop_.Run(); } // Removes the pointer indirection from the read data for use with // comparators. std::vector GetStringData() const { std::vector string_data; string_data.reserve(data_.size()); for (const auto& entry : data_) { EXPECT_TRUE(entry); string_data.push_back(*entry); } return string_data; } const absl::optional& error() const { return error_; } bool succeeded() const { return !error_; } const std::vector>& data() const { return data_; } private: void DidReadFile(std::vector> data, absl::optional error) { error_ = std::move(error); data_ = std::move(data); run_loop_.QuitWhenIdle(); } absl::optional error_; std::vector> data_; scoped_refptr file_reader_; base::RunLoop run_loop_; DISALLOW_COPY_AND_ASSIGN(Receiver); }; void RunBasicTest(const std::vector& filenames) { base::FilePath root_path; base::PathService::Get(DIR_TEST_DATA, &root_path); std::string extension_id = crx_file::id_util::GenerateId("test"); std::vector resources; resources.reserve(filenames.size()); std::vector expected_contents; expected_contents.reserve(filenames.size()); for (const auto& filename : filenames) { resources.emplace_back(extension_id, root_path, base::FilePath().AppendASCII(filename)); base::FilePath path = root_path.AppendASCII(filename); std::string file_contents; ASSERT_TRUE(base::ReadFileToString(path, &file_contents)); expected_contents.push_back(std::move(file_contents)); } Receiver receiver(resources); receiver.Run(); EXPECT_TRUE(receiver.succeeded()) << *receiver.error(); EXPECT_THAT(receiver.GetStringData(), ::testing::ElementsAreArray(expected_contents)); } TEST_F(FileReaderTest, SmallFile) { RunBasicTest({"smallfile"}); } TEST_F(FileReaderTest, BiggerFile) { RunBasicTest({"bigfile"}); } TEST_F(FileReaderTest, MultiFile) { RunBasicTest({"smallfile", "bigfile"}); } TEST_F(FileReaderTest, NonExistentFile) { base::FilePath path; base::PathService::Get(DIR_TEST_DATA, &path); std::string extension_id = crx_file::id_util::GenerateId("test"); ExtensionResource resource(extension_id, path, base::FilePath( FILE_PATH_LITERAL("file_that_does_not_exist"))); path = path.AppendASCII("file_that_does_not_exist"); Receiver receiver({resource}); receiver.Run(); EXPECT_FALSE(receiver.succeeded()); EXPECT_EQ("Could not load file: 'file_that_does_not_exist'.", *receiver.error()); } } // namespace extensions