libcryfs/test/cpp-utils/data/DataTest.cpp

299 lines
9.2 KiB
C++
Raw Normal View History

2016-02-11 12:53:42 +01:00
#include "cpp-utils/data/DataFixture.h"
#include "cpp-utils/data/Data.h"
#include "cpp-utils/data/SerializationHelper.h"
2018-09-11 08:50:02 +02:00
#include <gmock/gmock.h>
2016-02-11 12:53:42 +01:00
#include "cpp-utils/tempfile/TempFile.h"
2015-04-25 02:21:39 +02:00
#include <cstddef>
2015-04-25 02:21:39 +02:00
#include <fstream>
using ::testing::Test;
using ::testing::WithParamInterface;
using ::testing::Values;
2018-09-11 08:50:02 +02:00
using ::testing::Return;
2015-04-25 02:21:39 +02:00
2015-04-25 02:40:02 +02:00
using cpputils::TempFile;
2015-04-25 02:21:39 +02:00
using std::ifstream;
using std::ofstream;
using std::string;
2015-04-25 02:21:39 +02:00
namespace bf = boost::filesystem;
using namespace cpputils;
class DataTest: public Test {
public:
bool DataIsZeroes(const Data &data) {
for (size_t i = 0; i != data.size(); ++ i) {
if (deserialize<uint8_t>(data.dataOffset(i)) != 0) {
2015-04-25 02:21:39 +02:00
return false;
}
}
return true;
}
};
class DataTestWithSizeParam: public DataTest, public WithParamInterface<size_t> {
public:
2015-04-25 17:45:18 +02:00
Data randomData;
2015-04-25 02:21:39 +02:00
2015-04-25 17:45:18 +02:00
DataTestWithSizeParam(): randomData(DataFixture::generate(GetParam())) {}
2015-04-25 02:21:39 +02:00
2015-04-25 17:45:18 +02:00
static void StoreData(const Data &data, const bf::path &filepath) {
ofstream file(filepath.string().c_str(), std::ios::binary | std::ios::trunc);
file.write(static_cast<const char*>(data.data()), data.size());
2015-04-25 02:21:39 +02:00
}
2015-04-25 17:45:18 +02:00
static void EXPECT_STORED_FILE_DATA_CORRECT(const Data &data, const bf::path &filepath) {
EXPECT_EQ(data.size(), bf::file_size(filepath));
2015-04-25 02:21:39 +02:00
ifstream file(filepath.string().c_str(), std::ios::binary);
2015-04-25 17:45:18 +02:00
char *read_data = new char[data.size()];
file.read(read_data, data.size());
2015-04-25 02:21:39 +02:00
2015-04-25 17:45:18 +02:00
EXPECT_EQ(0, std::memcmp(data.data(), read_data, data.size()));
2015-04-25 02:21:39 +02:00
delete[] read_data;
}
};
2019-10-13 14:16:06 +02:00
INSTANTIATE_TEST_SUITE_P(DataTestWithSizeParam, DataTestWithSizeParam, Values(0, 1, 2, 1024, 4096, 10*1024*1024));
2015-04-25 02:21:39 +02:00
2015-04-25 17:45:18 +02:00
TEST_P(DataTestWithSizeParam, ZeroInitializedDataIsDifferentToRandomData) {
if (GetParam() != 0) {
Data data(GetParam());
data.FillWithZeroes();
EXPECT_NE(randomData, data);
}
}
2015-04-25 02:21:39 +02:00
// Working on a large data area without a crash is a good indicator that we
// are actually working on memory that was validly allocated for us.
TEST_P(DataTestWithSizeParam, WriteAndCheck) {
const Data data = randomData.copy();
2015-04-25 17:45:18 +02:00
EXPECT_EQ(randomData, data);
2015-04-25 02:21:39 +02:00
}
TEST_P(DataTestWithSizeParam, Size) {
const Data data(GetParam());
2015-04-25 02:21:39 +02:00
EXPECT_EQ(GetParam(), data.size());
}
TEST_P(DataTestWithSizeParam, CheckStoredFile) {
const TempFile file;
2015-04-25 17:45:18 +02:00
randomData.StoreToFile(file.path());
2015-04-25 02:21:39 +02:00
2015-04-25 17:45:18 +02:00
EXPECT_STORED_FILE_DATA_CORRECT(randomData, file.path());
2015-04-25 02:21:39 +02:00
}
TEST_P(DataTestWithSizeParam, CheckLoadedData) {
const TempFile file;
2015-04-25 17:45:18 +02:00
StoreData(randomData, file.path());
2015-04-25 02:21:39 +02:00
const Data data = Data::LoadFromFile(file.path()).value();
2015-04-25 02:21:39 +02:00
2015-04-25 17:45:18 +02:00
EXPECT_EQ(randomData, data);
2015-04-25 02:21:39 +02:00
}
TEST_P(DataTestWithSizeParam, StoreDoesntChangeData) {
const Data data = randomData.copy();
2015-04-25 02:21:39 +02:00
const TempFile file;
2015-04-25 02:21:39 +02:00
data.StoreToFile(file.path());
2015-04-25 17:45:18 +02:00
EXPECT_EQ(randomData, data);
2015-04-25 02:21:39 +02:00
}
TEST_P(DataTestWithSizeParam, StoreAndLoad) {
const TempFile file;
2015-04-25 17:45:18 +02:00
randomData.StoreToFile(file.path());
const Data loaded_data = Data::LoadFromFile(file.path()).value();
2015-04-25 02:21:39 +02:00
2015-04-25 17:45:18 +02:00
EXPECT_EQ(randomData, loaded_data);
2015-04-25 02:21:39 +02:00
}
TEST_P(DataTestWithSizeParam, Copy) {
const Data copy = randomData.copy();
2015-04-25 17:45:18 +02:00
EXPECT_EQ(randomData, copy);
2015-04-25 02:21:39 +02:00
}
2015-04-26 00:41:29 +02:00
TEST_F(DataTest, ChangingCopyDoesntChangeOriginal) {
const Data original = DataFixture::generate(1024);
2015-04-26 00:41:29 +02:00
Data copy = original.copy();
serialize<uint8_t>(copy.data(), deserialize<uint8_t>(copy.data()) + 1);
2015-04-26 00:41:29 +02:00
EXPECT_EQ(DataFixture::generate(1024), original);
EXPECT_NE(copy, original);
}
2015-04-25 02:21:39 +02:00
TEST_F(DataTest, InitializeWithZeroes) {
Data data(10*1024);
data.FillWithZeroes();
EXPECT_TRUE(DataIsZeroes(data));
}
TEST_F(DataTest, FillModifiedDataWithZeroes) {
2015-04-25 17:45:18 +02:00
Data data = DataFixture::generate(10*1024);
2015-04-25 02:21:39 +02:00
EXPECT_FALSE(DataIsZeroes(data));
data.FillWithZeroes();
EXPECT_TRUE(DataIsZeroes(data));
}
2015-04-26 00:41:29 +02:00
TEST_F(DataTest, MoveConstructor) {
Data original = DataFixture::generate(1024);
const Data copy(std::move(original));
2015-04-26 00:41:29 +02:00
EXPECT_EQ(DataFixture::generate(1024), copy);
EXPECT_EQ(nullptr, original.data()); // NOLINT (intentional use-after-move)
EXPECT_EQ(0u, original.size()); // NOLINT (intentional use-after-move)
2015-04-26 00:41:29 +02:00
}
TEST_F(DataTest, MoveAssignment) {
Data original = DataFixture::generate(1024);
Data copy(0);
copy = std::move(original);
EXPECT_EQ(DataFixture::generate(1024), copy);
EXPECT_EQ(nullptr, original.data()); // NOLINT (intentional use-after-move)
EXPECT_EQ(0u, original.size()); // NOLINT (intentional use-after-move)
2015-04-26 00:41:29 +02:00
}
TEST_F(DataTest, Equality) {
const Data data1 = DataFixture::generate(1024);
const Data data2 = DataFixture::generate(1024);
2015-04-26 00:41:29 +02:00
EXPECT_TRUE(data1 == data2);
EXPECT_FALSE(data1 != data2);
}
TEST_F(DataTest, Inequality_DifferentSize) {
const Data data1 = DataFixture::generate(1024);
const Data data2 = DataFixture::generate(1023);
2015-04-26 00:41:29 +02:00
EXPECT_FALSE(data1 == data2);
EXPECT_TRUE(data1 != data2);
}
TEST_F(DataTest, Inequality_DifferentFirstByte) {
const Data data1 = DataFixture::generate(1024);
2015-04-26 00:41:29 +02:00
Data data2 = DataFixture::generate(1024);
serialize<uint8_t>(data2.data(), deserialize<uint8_t>(data2.data()) + 1);
2015-04-26 00:41:29 +02:00
EXPECT_FALSE(data1 == data2);
EXPECT_TRUE(data1 != data2);
}
TEST_F(DataTest, Inequality_DifferentMiddleByte) {
const Data data1 = DataFixture::generate(1024);
2015-04-26 00:41:29 +02:00
Data data2 = DataFixture::generate(1024);
serialize<uint8_t>(data2.dataOffset(500), deserialize<uint8_t>(data2.dataOffset(500)) + 1);
2015-04-26 00:41:29 +02:00
EXPECT_FALSE(data1 == data2);
EXPECT_TRUE(data1 != data2);
}
TEST_F(DataTest, Inequality_DifferentLastByte) {
const Data data1 = DataFixture::generate(1024);
2015-04-26 00:41:29 +02:00
Data data2 = DataFixture::generate(1024);
serialize<uint8_t>(data2.dataOffset(1023), deserialize<uint8_t>(data2.dataOffset(1023)) + 1);
2015-04-26 00:41:29 +02:00
EXPECT_FALSE(data1 == data2);
EXPECT_TRUE(data1 != data2);
}
2015-11-25 15:39:52 +01:00
#ifdef __x86_64__
2015-04-25 02:21:39 +02:00
TEST_F(DataTest, LargesizeSize) {
2015-11-29 21:32:12 +01:00
//Needs 64bit for representation. This value isn't in the size param list, because the list is also used for read/write checks.
const uint64_t size = static_cast<uint64_t>(4.5L*1024*1024*1024);
const Data data(size);
2015-04-25 02:21:39 +02:00
EXPECT_EQ(size, data.size());
}
2015-11-25 15:39:52 +01:00
#else
2018-07-09 04:34:08 +02:00
#if defined(_MSC_VER)
#pragma message This is not a 64bit architecture. Large size data tests are disabled.
#else
2015-11-25 15:39:52 +01:00
#warning This is not a 64bit architecture. Large size data tests are disabled.
#endif
2018-07-09 04:34:08 +02:00
#endif
2015-04-25 02:21:39 +02:00
TEST_F(DataTest, LoadingNonexistingFile) {
const TempFile file(false); // Pass false to constructor, so the tempfile is not created
2015-04-25 02:21:39 +02:00
EXPECT_FALSE(Data::LoadFromFile(file.path()));
}
class DataTestWithStringParam: public DataTest, public WithParamInterface<string> {};
2019-10-13 14:16:06 +02:00
INSTANTIATE_TEST_SUITE_P(DataTestWithStringParam, DataTestWithStringParam, Values("", "2898B4B8A13C0F0278CCE465DB", "6FFEBAD90C0DAA2B79628F0627CE9841"));
TEST_P(DataTestWithStringParam, FromAndToString) {
const Data data = Data::FromString(GetParam());
EXPECT_EQ(GetParam(), data.ToString());
}
TEST_P(DataTestWithStringParam, ToAndFromString) {
const Data data = Data::FromString(GetParam());
const Data data2 = Data::FromString(data.ToString());
EXPECT_EQ(data, data2);
}
2018-09-11 08:50:02 +02:00
struct MockAllocator final : public Allocator {
MOCK_METHOD(void* , allocate, (size_t), (override));
MOCK_METHOD(void, free, (void*, size_t), (override));
2018-09-11 08:50:02 +02:00
};
class DataTestWithMockAllocator: public DataTest {
public:
2018-10-14 22:26:30 +02:00
char ptr_target{};
2018-09-11 08:50:02 +02:00
unique_ref<MockAllocator> allocator = make_unique_ref<MockAllocator>();
MockAllocator* allocator_ptr = allocator.get();
};
TEST_F(DataTestWithMockAllocator, whenCreatingNewData_thenTakesItFromAllocator) {
EXPECT_CALL(*allocator, allocate(5)).Times(1).WillOnce(Return(&ptr_target));
Data data(5, std::move(allocator));
EXPECT_EQ(&ptr_target, data.data());
}
TEST_F(DataTestWithMockAllocator, whenDestructingData_thenFreesItInAllocator) {
EXPECT_CALL(*allocator, allocate(5)).Times(1).WillOnce(Return(&ptr_target));
const Data data(5, std::move(allocator));
2018-09-11 08:50:02 +02:00
EXPECT_CALL(*allocator_ptr, free(&ptr_target, 5)).Times(1);
}
TEST_F(DataTestWithMockAllocator, whenMoveConstructing_thenOnlyFreesOnce) {
EXPECT_CALL(*allocator, allocate(5)).Times(1).WillOnce(Return(&ptr_target));
Data data(5, std::move(allocator));
const Data data2 = std::move(data);
2018-09-11 08:50:02 +02:00
EXPECT_CALL(*allocator_ptr, free(&ptr_target, 5)).Times(1);
}
TEST_F(DataTestWithMockAllocator, whenMoveAssigning_thenOnlyFreesOnce) {
EXPECT_CALL(*allocator, allocate(5)).Times(1).WillOnce(Return(&ptr_target));
Data data(5, std::move(allocator));
Data data2(3);
data2 = std::move(data);
EXPECT_CALL(*allocator_ptr, free(&ptr_target, 5)).Times(1);
}
TEST_F(DataTestWithMockAllocator, whenMoveConstructing_thenOnlyFreesWhenSecondIsDestructed) {
EXPECT_CALL(*allocator, allocate(5)).Times(1).WillOnce(Return(&ptr_target));
2021-04-21 08:09:00 +02:00
EXPECT_CALL(*allocator_ptr, free(testing::_, testing::_)).Times(0);
2018-09-11 08:50:02 +02:00
auto data = std::make_unique<Data>(5, std::move(allocator));
const Data data2 = std::move(*data);
2018-09-11 08:50:02 +02:00
data.reset();
EXPECT_CALL(*allocator_ptr, free(&ptr_target, 5)).Times(1);
}
TEST_F(DataTestWithMockAllocator, whenMoveAssigning_thenOnlyFreesWhenSecondIsDestructed) {
EXPECT_CALL(*allocator, allocate(5)).Times(1).WillOnce(Return(&ptr_target));
2021-04-21 08:09:00 +02:00
EXPECT_CALL(*allocator_ptr, free(testing::_, testing::_)).Times(0);
2018-09-11 08:50:02 +02:00
auto data = std::make_unique<Data>(5, std::move(allocator));
Data data2(3);
data2 = std::move(*data);
data.reset();
EXPECT_CALL(*allocator_ptr, free(&ptr_target, 5)).Times(1);
}