blob: 6f4ba5cb2946df4cf14ea9a42c33fb9b3ce0bc1d [file] [log] [blame]
// 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 "extensions/browser/file_reader.h"
#include <limits>
#include <optional>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.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_id.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"
namespace extensions {
class FileReaderTest : public testing::Test {
public:
FileReaderTest() {}
FileReaderTest(const FileReaderTest&) = delete;
FileReaderTest& operator=(const FileReaderTest&) = delete;
private:
base::test::TaskEnvironment task_environment_;
};
class Receiver {
public:
explicit Receiver(
std::vector<ExtensionResource> resources,
size_t max_resources_length = std::numeric_limits<size_t>::max())
: file_reader_(base::MakeRefCounted<FileReader>(
std::move(resources),
max_resources_length,
FileReader::OptionalFileSequenceTask(),
base::BindOnce(&Receiver::DidReadFile, base::Unretained(this)))) {}
Receiver(const Receiver&) = delete;
Receiver& operator=(const Receiver&) = delete;
void Run() {
file_reader_->Start();
run_loop_.Run();
}
// Removes the pointer indirection from the read data for use with
// comparators.
std::vector<std::string> GetStringData() const {
std::vector<std::string> string_data;
string_data.reserve(data_.size());
for (const auto& entry : data_) {
EXPECT_TRUE(entry);
string_data.push_back(*entry);
}
return string_data;
}
const std::optional<std::string>& error() const { return error_; }
bool succeeded() const { return !error_; }
const std::vector<std::unique_ptr<std::string>>& data() const {
return data_;
}
private:
void DidReadFile(std::vector<std::unique_ptr<std::string>> data,
std::optional<std::string> error) {
error_ = std::move(error);
data_ = std::move(data);
run_loop_.QuitWhenIdle();
}
std::optional<std::string> error_;
std::vector<std::unique_ptr<std::string>> data_;
scoped_refptr<FileReader> file_reader_;
base::RunLoop run_loop_;
};
void RunBasicTest(const std::vector<std::string>& filenames) {
base::FilePath root_path;
base::PathService::Get(DIR_TEST_DATA, &root_path);
ExtensionId extension_id = crx_file::id_util::GenerateId("test");
std::vector<ExtensionResource> resources;
resources.reserve(filenames.size());
std::vector<std::string> 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);
ExtensionId extension_id = crx_file::id_util::GenerateId("test");
ExtensionResource resource(
extension_id, path,
base::FilePath(FILE_PATH_LITERAL("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());
}
TEST_F(FileReaderTest, AboveSizeLimitFile) {
base::FilePath path;
base::PathService::Get(DIR_TEST_DATA, &path);
ExtensionId extension_id = crx_file::id_util::GenerateId("test");
ExtensionResource resource(extension_id, path,
base::FilePath().AppendASCII("bigfile"));
Receiver receiver({resource}, /*max_resources_length=*/100u);
receiver.Run();
EXPECT_FALSE(receiver.succeeded());
EXPECT_EQ("Could not load file: 'bigfile'. Resource size exceeded.",
*receiver.error());
}
} // namespace extensions