blob: 9d5d55fcb9291e7f32b27d986d7eedc219f86740 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "./fuzztest/internal/io.h"
#include <cerrno>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <optional>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/str_cat.h"
#include "./fuzztest/fuzztest.h"
namespace fuzztest::internal {
namespace {
using ::testing::Eq;
using ::testing::FieldsAre;
using ::testing::IsEmpty;
using ::testing::Optional;
using ::testing::SizeIs;
using ::testing::UnorderedElementsAre;
std::string TmpFile(const std::string& name) {
std::string filename = absl::StrCat(testing::TempDir(), "/", name, "XXXXXX");
return mktemp(filename.data());
}
std::string TmpDir(const std::string& name) {
std::string filename = absl::StrCat(testing::TempDir(), "/", name, "XXXXXX");
return mkdtemp(filename.data());
}
// These use a different implementation of read/write.
// Otherwise we are testing the functions with themselves.
std::string TestRead(const std::string& filename) {
FILE* f = fopen(filename.c_str(), "r");
char buf[1024]{};
size_t s = fread(buf, 1, sizeof(buf), f);
fclose(f);
return std::string(buf, s);
}
void TestWrite(const std::string& filename, const std::string& contents) {
FILE* f = fopen(filename.c_str(), "w");
ASSERT_TRUE(f) << strerror(errno);
EXPECT_EQ(fwrite(contents.data(), contents.size(), 1, f), 1)
<< strerror(errno);
EXPECT_EQ(0, fclose(f)) << strerror(errno);
}
TEST(IOTest, WriteFileWorksWhenDirectoryExists) {
const std::string tmp_name = TmpFile("write_test");
EXPECT_TRUE(WriteFile(tmp_name, "Payload1"));
EXPECT_EQ(TestRead(tmp_name), "Payload1");
std::filesystem::remove(tmp_name);
}
TEST(IOTest, WriteFileWorksWhenDirectoryDoesNotExist) {
const std::string tmp_dir = TmpDir("write_test_dir");
const std::string tmp_name = absl::StrCat(tmp_dir, "/doesnt_exist/file");
EXPECT_TRUE(WriteFile(tmp_name, "Payload1"));
EXPECT_EQ(TestRead(tmp_name), "Payload1");
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, WriteDataToDirReturnsWrittenFilePath) {
const std::string tmp_dir = TmpDir("write_test_dir");
const std::string path = WriteDataToDir("data", tmp_dir);
EXPECT_THAT(ReadFile(path), Optional(Eq("data")));
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, WriteDataToDirWritesToSameFileOnSameData) {
const std::string tmp_dir = TmpDir("write_test_dir");
const std::string path = WriteDataToDir("data", tmp_dir);
EXPECT_THAT(WriteDataToDir("data", tmp_dir), Eq(path));
EXPECT_THAT(ReadFile(path), Optional(Eq("data")));
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, ReadFileReturnsNulloptWhenMissing) {
EXPECT_THAT(ReadFile("/doesnt_exist/file"), Eq(std::nullopt));
EXPECT_THAT(ReadFileOrDirectory("/doesnt_exist/file"),
UnorderedElementsAre());
}
TEST(IOTest, ReadFileWorksWhenFileExists) {
const std::string tmp_name = TmpFile("read_test");
TestWrite(tmp_name, "Payload2");
EXPECT_THAT(ReadFile(tmp_name), Optional(Eq("Payload2")));
EXPECT_THAT(ReadFileOrDirectory(tmp_name),
UnorderedElementsAre(FieldsAre(tmp_name, "Payload2")));
std::filesystem::remove(tmp_name);
}
TEST(IOTest, ReadFileOrDirectoryWorks) {
const std::string tmp_dir = TmpDir("write_test_dir");
EXPECT_THAT(ReadFileOrDirectory(tmp_dir), UnorderedElementsAre());
const std::string tmp_file_1 = absl::StrCat(tmp_dir, "/file1");
TestWrite(tmp_file_1, "Payload3.1");
EXPECT_THAT(ReadFileOrDirectory(tmp_dir),
UnorderedElementsAre(FieldsAre(tmp_file_1, "Payload3.1")));
const std::string tmp_file_2 = absl::StrCat(tmp_dir, "/file2");
TestWrite(tmp_file_2, "Payload3.2");
EXPECT_THAT(ReadFileOrDirectory(tmp_dir),
UnorderedElementsAre(FieldsAre(tmp_file_1, "Payload3.1"),
FieldsAre(tmp_file_2, "Payload3.2")));
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, ReadFilesFromDirectoryWorks) {
const std::string tmp_dir = TmpDir("write_test_dir");
EXPECT_THAT(ReadFilesFromDirectory(tmp_dir), UnorderedElementsAre());
EXPECT_THAT(ReadFilesFromDirectory(tmp_dir), SizeIs(0));
const std::string tmp_file_1 = absl::StrCat(tmp_dir, "/file1");
TestWrite(tmp_file_1, "Payload4.1");
EXPECT_THAT(ReadFilesFromDirectory(tmp_dir),
UnorderedElementsAre(FieldsAre("Payload4.1")));
EXPECT_THAT(ReadFilesFromDirectory(tmp_dir), SizeIs(1));
const std::string tmp_file_2 = absl::StrCat(tmp_dir, "/file2");
TestWrite(tmp_file_2, "Payload4.2");
EXPECT_THAT(
ReadFilesFromDirectory(tmp_dir),
UnorderedElementsAre(FieldsAre("Payload4.1"), FieldsAre("Payload4.2")));
EXPECT_THAT(ReadFilesFromDirectory(tmp_dir), SizeIs(2));
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, ReadFilesFromDirectoryReturnsEmptyVectorWhenNoFilesInDir) {
const std::string tmp_dir = TmpDir("empty_dir");
EXPECT_THAT(ReadFilesFromDirectory(tmp_dir), UnorderedElementsAre());
EXPECT_THAT(ReadFileOrDirectory(tmp_dir), SizeIs(0));
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, ReadFilesFromDirectoryReturnsEmptyVectorWhenMissing) {
EXPECT_THAT(ReadFilesFromDirectory("/doesnt_exist/"), UnorderedElementsAre());
EXPECT_THAT(ReadFileOrDirectory("/doesnt_exist/"), SizeIs(0));
}
TEST(IOTest, ListDirectoryReturnsPathsInDirectory) {
const std::string tmp_dir = TmpDir("test_dir");
const std::string tmp_file_1 = absl::StrCat(tmp_dir, "/file1");
TestWrite(tmp_file_1, /*contents=*/"File1");
const std::string tmp_file_2 = absl::StrCat(tmp_dir, "/file2");
TestWrite(tmp_file_2, /*contents=*/"File2");
EXPECT_THAT(ListDirectory(tmp_dir),
UnorderedElementsAre(tmp_file_1, tmp_file_2));
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, ListDirectoryReturnsEmptyVectorWhenDirectoryIsEmpty) {
const std::string tmp_dir = TmpDir("empty_dir");
EXPECT_THAT(ListDirectory(tmp_dir), IsEmpty());
std::filesystem::remove_all(tmp_dir);
}
TEST(IOTest, ListDirectoryReturnsEmptyVectorWhenDirectoryDoesNotExist) {
EXPECT_THAT(ListDirectory("/doesnt_exist/"), IsEmpty());
}
} // namespace
} // namespace fuzztest::internal