From d8a6b239629f6e7b5e1188e11475917992329125 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Sat, 25 Apr 2015 02:21:39 +0200 Subject: [PATCH] Moved data classes to cpp-utils --- CMakeLists.txt | 2 + biicode.conf | 2 + data/Data.cpp | 96 ++++++++++++++++++ data/Data.h | 46 +++++++++ data/DataBlockFixture.cpp | 91 +++++++++++++++++ data/DataBlockFixture.h | 51 ++++++++++ data/FixedSizeData.h | 112 +++++++++++++++++++++ test/data/DataTest.cpp | 166 ++++++++++++++++++++++++++++++++ test/data/FixedSizeDataTest.cpp | 157 ++++++++++++++++++++++++++++++ 9 files changed, 723 insertions(+) create mode 100644 data/Data.cpp create mode 100644 data/Data.h create mode 100644 data/DataBlockFixture.cpp create mode 100644 data/DataBlockFixture.h create mode 100644 data/FixedSizeData.h create mode 100644 test/data/DataTest.cpp create mode 100644 test/data/FixedSizeDataTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 09990ef4..cbc03a26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ ADD_BII_TARGETS() ACTIVATE_CPP14() +ADD_BOOST(filesystem) + # You can safely delete lines from here... ############################################################################### diff --git a/biicode.conf b/biicode.conf index de64c4dc..77033b7d 100644 --- a/biicode.conf +++ b/biicode.conf @@ -1,8 +1,10 @@ # Biicode configuration file [requirements] + cryptopp/cryptopp: 9 google/gtest: 11 messmer/cmake: 3 + messmer/tempfile: 4 [parent] messmer/cpp-utils: 2 diff --git a/data/Data.cpp b/data/Data.cpp new file mode 100644 index 00000000..9c9f31a1 --- /dev/null +++ b/data/Data.cpp @@ -0,0 +1,96 @@ +#include "Data.h" +#include +#include + +using std::istream; +using std::ofstream; +using std::ifstream; +using std::ios; +using std::unique_ptr; +using std::make_unique; + +namespace bf = boost::filesystem; + +namespace cpputils { + +Data::Data(size_t size) +: _size(size), _data(std::malloc(size)) { + if (nullptr == _data) { + throw std::bad_alloc(); + } +} + +Data::Data(Data &&rhs) +: _size(rhs._size), _data(rhs._data) { + // Make rhs invalid, so the memory doesn't get freed in its destructor. + rhs._data = nullptr; +} + +Data::~Data() { + std::free(_data); + _data = nullptr; +} + +Data Data::copy() const { + Data copy(_size); + std::memcpy(copy._data, _data, _size); + return copy; +} + +void *Data::data() { + return const_cast(const_cast(this)->data()); +} + +const void *Data::data() const { + return _data; +} + +size_t Data::size() const { + return _size; +} + +Data &Data::FillWithZeroes() { + std::memset(_data, 0, _size); + return *this; +} + +void Data::StoreToFile(const bf::path &filepath) const { + ofstream file(filepath.c_str(), ios::binary | ios::trunc); + file.write((const char*)_data, _size); +} + +boost::optional Data::LoadFromFile(const bf::path &filepath) { + ifstream file(filepath.c_str(), ios::binary); + if (!file.good()) { + //TODO Test this path + return boost::none; + } + size_t size = _getStreamSize(file); + + Data result(size); + result._readFromStream(file); + return std::move(result); +} + +size_t Data::_getStreamSize(istream &stream) { + auto current_pos = stream.tellg(); + + //Retrieve length + stream.seekg(0, stream.end); + auto endpos = stream.tellg(); + + //Restore old position + stream.seekg(current_pos, stream.beg); + + return endpos - current_pos; +} + +void Data::_readFromStream(istream &stream) { + stream.read((char*)_data, _size); +} + +bool operator==(const Data &lhs, const Data &rhs) { + return lhs.size() == rhs.size() && 0 == memcmp(lhs.data(), rhs.data(), lhs.size()); +} + +} diff --git a/data/Data.h b/data/Data.h new file mode 100644 index 00000000..8fd6e383 --- /dev/null +++ b/data/Data.h @@ -0,0 +1,46 @@ +#pragma once +#ifndef MESSMER_CPPUTILS_DATA_DATA_H_ +#define MESSMER_CPPUTILS_DATA_DATA_H_ + +#include +#include +#include +#include "../macros.h" +#include + +namespace cpputils { + +class Data { +public: + explicit Data(size_t size); + Data(Data &&rhs); // move constructor + virtual ~Data(); + + Data copy() const; + + void *data(); + const void *data() const; + + size_t size() const; + + Data &FillWithZeroes(); + + void StoreToFile(const boost::filesystem::path &filepath) const; + static boost::optional LoadFromFile(const boost::filesystem::path &filepath); + +private: + size_t _size; + void *_data; + + static size_t _getStreamSize(std::istream &stream); + void _readFromStream(std::istream &stream); + + DISALLOW_COPY_AND_ASSIGN(Data); +}; + +//TODO Test operator== +bool operator==(const Data &lhs, const Data &rhs); + +} + +#endif diff --git a/data/DataBlockFixture.cpp b/data/DataBlockFixture.cpp new file mode 100644 index 00000000..096481e0 --- /dev/null +++ b/data/DataBlockFixture.cpp @@ -0,0 +1,91 @@ +#include "DataBlockFixture.h" +#include +#include + +using std::min; + +namespace cpputils { + +DataBlockFixture::DataBlockFixture(size_t size, long long int IV): _fileData(new char[size]), _size(size) { + fillFileWithRandomData(IV); +} + +DataBlockFixture::~DataBlockFixture() { + delete[] _fileData; +} + +void DataBlockFixture::fillFileWithRandomData(long long int IV) { + long long int val = IV; + for(size_t i=0; i<_size/sizeof(long long int); ++i) { + //MMIX linear congruential generator + val *= 6364136223846793005L; + val += 1442695040888963407; + reinterpret_cast(_fileData)[i] = val; + } + uint64_t alreadyWritten = (_size/sizeof(long long int))*sizeof(long long int); + val *= 6364136223846793005L; + val += 1442695040888963407; + char *remainingBytes = reinterpret_cast(&val); + //Fill remaining bytes + for(size_t i=0; i<_size-alreadyWritten; ++i) { + reinterpret_cast(_fileData)[alreadyWritten + i] = remainingBytes[i]; + } +} + +const char *DataBlockFixture::data() const { + return _fileData; +} + +int DataBlockFixture::read(void *buf, size_t count, off_t offset) { + size_t realCount = min(count, _size - offset); + memcpy(buf, _fileData+offset, realCount); + return realCount; +} + +size_t DataBlockFixture::size() const { + return _size; +} + +bool DataBlockFixture::fileContentEqual(const char *content, size_t count, off_t offset) { + return 0 == memcmp(content, _fileData + offset, count); +} + +DataBlockFixtureWriteable::DataBlockFixtureWriteable(size_t size, long long int IV) + :DataBlockFixture(size, IV), _originalSize(size) { + _originalFileData = new char[size]; + memcpy(_originalFileData, _fileData, size); +} + +DataBlockFixtureWriteable::~DataBlockFixtureWriteable() { + delete[] _originalFileData; +} + +void DataBlockFixtureWriteable::write(const void *buf, size_t count, off_t offset) { + extendFileSizeIfNecessary(count + offset); + + memcpy(_fileData+offset, buf, count); +} + +void DataBlockFixtureWriteable::extendFileSizeIfNecessary(size_t size) { + if (size > _size) { + extendFileSize(size); + } +} + +void DataBlockFixtureWriteable::extendFileSize(size_t size) { + char *newfile = new char[size]; + memcpy(newfile, _fileData, _size); + delete[] _fileData; + _fileData = newfile; + _size = size; +} + +bool DataBlockFixtureWriteable::sizeUnchanged() { + return _size == _originalSize; +} + +bool DataBlockFixtureWriteable::regionUnchanged(off_t offset, size_t count) { + return 0 == memcmp(_fileData+offset, _originalFileData+offset, count); +} + +} diff --git a/data/DataBlockFixture.h b/data/DataBlockFixture.h new file mode 100644 index 00000000..0a50742b --- /dev/null +++ b/data/DataBlockFixture.h @@ -0,0 +1,51 @@ +#pragma once +#ifndef MESSMER_CPPUTILS_DATA_DATABLOCKFIXTURE_H_ +#define MESSMER_CPPUTILS_DATA_DATABLOCKFIXTURE_H_ + +#include + +namespace cpputils { + +class DataBlockFixture { +public: + DataBlockFixture(size_t size, long long int IV = 1); + virtual ~DataBlockFixture(); + + int read(void *buf, size_t count, off_t offset); + + // Return true, iff the given data is equal to the data of the file at the given offset. + bool fileContentEqual(const char *content, size_t count, off_t offset); + + const char *data() const; + + size_t size() const; + +protected: + char *_fileData; + size_t _size; + +private: + void fillFileWithRandomData(long long int IV); +}; + +class DataBlockFixtureWriteable: public DataBlockFixture { +public: + DataBlockFixtureWriteable(size_t size, long long int IV = 1); + virtual ~DataBlockFixtureWriteable(); + + void write(const void *buf, size_t count, off_t offset); + + bool sizeUnchanged(); + bool regionUnchanged(off_t offset, size_t count); + +private: + void extendFileSizeIfNecessary(size_t size); + void extendFileSize(size_t size); + + char *_originalFileData; + size_t _originalSize; +}; + +} + +#endif diff --git a/data/FixedSizeData.h b/data/FixedSizeData.h new file mode 100644 index 00000000..7dc7dcba --- /dev/null +++ b/data/FixedSizeData.h @@ -0,0 +1,112 @@ +#pragma once +#ifndef MESSMER_CPPUTILS_DATA_FIXEDSIZEDATA_H_ +#define MESSMER_CPPUTILS_DATA_FIXEDSIZEDATA_H_ + +#include +#include +#include +#include + +namespace cpputils { + +template +class FixedSizeData { +public: + //Non-virtual destructor because we want objects to be small + ~FixedSizeData() {} + + static constexpr unsigned int BINARY_LENGTH = SIZE; + static constexpr unsigned int STRING_LENGTH = 2 * BINARY_LENGTH; // Hex encoding + + static FixedSizeData CreateRandom(); + + static FixedSizeData FromString(const std::string &data); + std::string ToString() const; + + static FixedSizeData FromBinary(const void *source); + void ToBinary(void *target) const; + + const unsigned char *data() const; + +private: + FixedSizeData() {} + static CryptoPP::AutoSeededRandomPool &RandomPool(); + + unsigned char _data[BINARY_LENGTH]; +}; + +template bool operator==(const FixedSizeData &lhs, const FixedSizeData &rhs); +template bool operator!=(const FixedSizeData &lhs, const FixedSizeData &rhs); + +// ----- Implementation ----- + +template constexpr unsigned int FixedSizeData::BINARY_LENGTH; +template constexpr unsigned int FixedSizeData::STRING_LENGTH; + +template +CryptoPP::AutoSeededRandomPool &FixedSizeData::RandomPool() { + static CryptoPP::AutoSeededRandomPool singleton; + return singleton; +} + +template +FixedSizeData FixedSizeData::CreateRandom() { + FixedSizeData result; + RandomPool().GenerateBlock(result._data, BINARY_LENGTH); + return result; +} + +template +FixedSizeData FixedSizeData::FromString(const std::string &data) { + assert(data.size() == STRING_LENGTH); + FixedSizeData result; + CryptoPP::StringSource(data, true, + new CryptoPP::HexDecoder( + new CryptoPP::ArraySink(result._data, BINARY_LENGTH) + ) + ); + return result; +} + +template +std::string FixedSizeData::ToString() const { + std::string result; + CryptoPP::ArraySource(_data, BINARY_LENGTH, true, + new CryptoPP::HexEncoder( + new CryptoPP::StringSink(result) + ) + ); + assert(result.size() == STRING_LENGTH); + return result; +} + +template +const unsigned char *FixedSizeData::data() const { + return _data; +} + +template +void FixedSizeData::ToBinary(void *target) const { + std::memcpy(target, _data, BINARY_LENGTH); +} + +template +FixedSizeData FixedSizeData::FromBinary(const void *source) { + FixedSizeData result; + std::memcpy(result._data, source, BINARY_LENGTH); + return result; +} + +template +bool operator==(const FixedSizeData &lhs, const FixedSizeData &rhs) { + return 0 == std::memcmp(lhs.data(), rhs.data(), FixedSizeData::BINARY_LENGTH); +} + +template +bool operator!=(const FixedSizeData &lhs, const FixedSizeData &rhs) { + return !operator==(lhs, rhs); +} + +} + +#endif diff --git a/test/data/DataTest.cpp b/test/data/DataTest.cpp new file mode 100644 index 00000000..98e4565d --- /dev/null +++ b/test/data/DataTest.cpp @@ -0,0 +1,166 @@ +#include "../../data/DataBlockFixture.h" +#include "../../data/Data.h" +#include "google/gtest/gtest.h" + +#include "messmer/tempfile/src/TempFile.h" + +#include + +using ::testing::Test; +using ::testing::WithParamInterface; +using ::testing::Values; + +using tempfile::TempFile; + +using std::ifstream; +using std::ofstream; + +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 (((char*)data.data())[i] != 0) { + return false; + } + } + return true; + } + + void FillData(const DataBlockFixture &fillData, Data *data) { + ASSERT_EQ(fillData.size(), data->size()); + std::memcpy(data->data(), fillData.data(), fillData.size()); + } + + void EXPECT_DATA_CORRECT(const DataBlockFixture &expectedData, const Data &data) { + ASSERT_EQ(expectedData.size(), data.size()); + EXPECT_EQ(0, std::memcmp(expectedData.data(), data.data(), expectedData.size())); + } +}; + +class DataTestWithSizeParam: public DataTest, public WithParamInterface { +public: + DataBlockFixture randomData; + + DataTestWithSizeParam(): randomData(GetParam()) {} + + void FillData(Data *data) { + DataTest::FillData(randomData, data); + } + + void StoreData(const bf::path &filepath) { + ofstream file(filepath.c_str(), std::ios::binary | std::ios::trunc); + file.write(randomData.data(), randomData.size()); + } + + void EXPECT_STORED_FILE_DATA_CORRECT(const bf::path &filepath) { + EXPECT_EQ(randomData.size(), bf::file_size(filepath)); + + ifstream file(filepath.c_str(), std::ios::binary); + char *read_data = new char[randomData.size()]; + file.read(read_data, randomData.size()); + + EXPECT_EQ(0, std::memcmp(randomData.data(), read_data, randomData.size())); + delete[] read_data; + } + + void EXPECT_DATA_CORRECT(const Data &data) { + DataTest::EXPECT_DATA_CORRECT(randomData, data); + } +}; + +INSTANTIATE_TEST_CASE_P(DataTestWithSizeParam, DataTestWithSizeParam, Values(0, 1, 2, 1024, 4096, 10*1024*1024)); + +// 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) { + Data data(GetParam()); + + FillData(&data); + EXPECT_DATA_CORRECT(data); +} + +TEST_P(DataTestWithSizeParam, Size) { + Data data(GetParam()); + EXPECT_EQ(GetParam(), data.size()); +} + +TEST_P(DataTestWithSizeParam, CheckStoredFile) { + Data data(GetParam()); + FillData(&data); + + TempFile file; + data.StoreToFile(file.path()); + + EXPECT_STORED_FILE_DATA_CORRECT(file.path()); +} + +TEST_P(DataTestWithSizeParam, CheckLoadedData) { + TempFile file; + StoreData(file.path()); + + Data data = Data::LoadFromFile(file.path()).value(); + + EXPECT_DATA_CORRECT(data); +} + +TEST_P(DataTestWithSizeParam, StoreDoesntChangeData) { + Data data(GetParam()); + FillData(&data); + + TempFile file; + data.StoreToFile(file.path()); + + EXPECT_DATA_CORRECT(data); +} + +TEST_P(DataTestWithSizeParam, StoreAndLoad) { + Data data(GetParam()); + FillData(&data); + + TempFile file; + data.StoreToFile(file.path()); + Data loaded_data = Data::LoadFromFile(file.path()).value(); + + EXPECT_DATA_CORRECT(loaded_data); +} + +TEST_P(DataTestWithSizeParam, Copy) { + Data data(GetParam()); + FillData(&data); + + Data copy = data.copy(); + + EXPECT_DATA_CORRECT(copy); +} + +TEST_F(DataTest, InitializeWithZeroes) { + Data data(10*1024); + data.FillWithZeroes(); + EXPECT_TRUE(DataIsZeroes(data)); +} + +TEST_F(DataTest, FillModifiedDataWithZeroes) { + Data data(10*1024); + DataBlockFixture randomData(10*1024); + FillData(randomData, &data); + EXPECT_FALSE(DataIsZeroes(data)); + + data.FillWithZeroes(); + EXPECT_TRUE(DataIsZeroes(data)); +} + +//Needs 64bit for representation. This value isn't in the size param list, because the list is also used for read/write checks. +TEST_F(DataTest, LargesizeSize) { + size_t size = 10L*1024*1024*1024; + Data data(size); + EXPECT_EQ(size, data.size()); +} + +TEST_F(DataTest, LoadingNonexistingFile) { + TempFile file(false); // Pass false to constructor, so the tempfile is not created + EXPECT_FALSE(Data::LoadFromFile(file.path())); +} diff --git a/test/data/FixedSizeDataTest.cpp b/test/data/FixedSizeDataTest.cpp new file mode 100644 index 00000000..69380911 --- /dev/null +++ b/test/data/FixedSizeDataTest.cpp @@ -0,0 +1,157 @@ +#include "../../data/DataBlockFixture.h" +#include "../../data/FixedSizeData.h" +#include "../../data/Data.h" +#include "google/gtest/gtest.h" + + +using ::testing::Test; +using ::testing::WithParamInterface; +using ::testing::Values; + +using std::string; + +using namespace cpputils; + +class FixedSizeDataTest: public Test { +public: + static constexpr unsigned int SIZE = 16; + + const string DATA1_AS_STRING = "1491BB4932A389EE14BC7090AC772972"; + const string DATA2_AS_STRING = "272EE5517627CFA147A971A8E6E747E0"; + + const DataBlockFixture DATA3_AS_BINARY; + const DataBlockFixture DATA4_AS_BINARY; + + FixedSizeDataTest() : DATA3_AS_BINARY(FixedSizeData::BINARY_LENGTH, 1), DATA4_AS_BINARY(FixedSizeData::BINARY_LENGTH, 2) {} + + void EXPECT_DATA_EQ(const DataBlockFixture &expected, const Data &actual) { + EXPECT_EQ(expected.size(), actual.size()); + EXPECT_EQ(0, std::memcmp(expected.data(), actual.data(), expected.size())); + } + + template + void EXPECT_DATA_EQ(const DataBlockFixture &expected, const FixedSizeData &actual) { + EXPECT_EQ(expected.size(), SIZE); + EXPECT_EQ(0, std::memcmp(expected.data(), actual.data(), SIZE)); + } +}; + +constexpr unsigned int FixedSizeDataTest::SIZE; + +TEST_F(FixedSizeDataTest, CanGenerateRandomDataWithoutCrashing) { + FixedSizeData result = FixedSizeData::CreateRandom(); +} + +TEST_F(FixedSizeDataTest, CreatedRandomDatasHaveCorrectLength) { + FixedSizeData data = FixedSizeData::CreateRandom(); + EXPECT_EQ(FixedSizeData::STRING_LENGTH, data.ToString().size()); +} + +TEST_F(FixedSizeDataTest, EqualsTrue) { + FixedSizeData DATA1_1 = FixedSizeData::FromString(DATA1_AS_STRING); + FixedSizeData DATA1_2 = FixedSizeData::FromString(DATA1_AS_STRING); + + EXPECT_TRUE(DATA1_1 == DATA1_2); + EXPECT_TRUE(DATA1_2 == DATA1_1); +} + +TEST_F(FixedSizeDataTest, EqualsFalse) { + FixedSizeData DATA1_1 = FixedSizeData::FromString(DATA1_AS_STRING); + FixedSizeData DATA2_1 = FixedSizeData::FromString(DATA2_AS_STRING); + + EXPECT_FALSE(DATA1_1 == DATA2_1); + EXPECT_FALSE(DATA2_1 == DATA1_1); +} + +TEST_F(FixedSizeDataTest, NotEqualsFalse) { + FixedSizeData DATA1_1 = FixedSizeData::FromString(DATA1_AS_STRING); + FixedSizeData DATA1_2 = FixedSizeData::FromString(DATA1_AS_STRING); + + EXPECT_FALSE(DATA1_1 != DATA1_2); + EXPECT_FALSE(DATA1_2 != DATA1_1); +} + +TEST_F(FixedSizeDataTest, NotEqualsTrue) { + FixedSizeData DATA1_1 = FixedSizeData::FromString(DATA1_AS_STRING); + FixedSizeData DATA2_1 = FixedSizeData::FromString(DATA2_AS_STRING); + + EXPECT_TRUE(DATA1_1 != DATA2_1); + EXPECT_TRUE(DATA2_1 != DATA1_1); +} + +class FixedSizeDataTestWithStringParam: public FixedSizeDataTest, public WithParamInterface {}; +INSTANTIATE_TEST_CASE_P(FixedSizeDataTestWithStringParam, FixedSizeDataTestWithStringParam, Values("2898B4B8A13CA63CBE0F0278CCE465DB", "6FFEBAD90C0DAA2B79628F0627CE9841")); + +TEST_P(FixedSizeDataTestWithStringParam, FromAndToString) { + FixedSizeData data = FixedSizeData::FromString(GetParam()); + EXPECT_EQ(GetParam(), data.ToString()); +} + +TEST_P(FixedSizeDataTestWithStringParam, ToAndFromString) { + FixedSizeData data = FixedSizeData::FromString(GetParam()); + FixedSizeData data2 = FixedSizeData::FromString(data.ToString()); + EXPECT_EQ(data, data2); +} + +class FixedSizeDataTestWithBinaryParam: public FixedSizeDataTest, public WithParamInterface { +public: + static const DataBlockFixture VALUE1; + static const DataBlockFixture VALUE2; +}; +const DataBlockFixture FixedSizeDataTestWithBinaryParam::VALUE1(FixedSizeData::BINARY_LENGTH, 3); +const DataBlockFixture FixedSizeDataTestWithBinaryParam::VALUE2(FixedSizeData::BINARY_LENGTH, 4); +INSTANTIATE_TEST_CASE_P(FixedSizeDataTestWithBinaryParam, FixedSizeDataTestWithBinaryParam, Values(&FixedSizeDataTestWithBinaryParam::VALUE1, &FixedSizeDataTestWithBinaryParam::VALUE2)); + +TEST_P(FixedSizeDataTestWithBinaryParam, FromBinary) { + FixedSizeData data = FixedSizeData::FromBinary((uint8_t*)GetParam()->data()); + EXPECT_DATA_EQ(*GetParam(), data); +} + +TEST_P(FixedSizeDataTestWithBinaryParam, FromAndToBinary) { + FixedSizeData data = FixedSizeData::FromBinary((uint8_t*)GetParam()->data()); + Data output(FixedSizeData::BINARY_LENGTH); + data.ToBinary(output.data()); + EXPECT_DATA_EQ(*GetParam(), output); +} + +TEST_P(FixedSizeDataTestWithBinaryParam, ToAndFromBinary) { + FixedSizeData data = FixedSizeData::FromBinary((uint8_t*)GetParam()->data()); + Data stored(FixedSizeData::BINARY_LENGTH); + data.ToBinary(stored.data()); + FixedSizeData loaded = FixedSizeData::FromBinary(stored.data()); + EXPECT_EQ(data, loaded); +} + +class FixedSizeDataTestWithParam: public FixedSizeDataTest, public WithParamInterface> {}; +INSTANTIATE_TEST_CASE_P(FixedSizeDataTestWithParam, FixedSizeDataTestWithParam, Values(FixedSizeData::FromString("2898B4B8A13CA63CBE0F0278CCE465DB"), FixedSizeData::FromString("6FFEBAD90C0DAA2B79628F0627CE9841"))); + +TEST_P(FixedSizeDataTestWithParam, CopyConstructor) { + FixedSizeData copy(GetParam()); + EXPECT_EQ(GetParam(), copy); +} + +TEST_F(FixedSizeDataTest, CopyConstructorDoesntChangeSource) { + FixedSizeData data1 = FixedSizeData::FromString(DATA1_AS_STRING); + FixedSizeData data2(data1); + EXPECT_EQ(DATA1_AS_STRING, data1.ToString()); +} + +TEST_P(FixedSizeDataTestWithParam, IsEqualAfterAssignment1) { + FixedSizeData data2 = FixedSizeData::FromString(DATA2_AS_STRING); + EXPECT_NE(GetParam(), data2); + data2 = GetParam(); + EXPECT_EQ(GetParam(), data2); +} + +TEST_F(FixedSizeDataTest, AssignmentDoesntChangeSource) { + FixedSizeData data1 = FixedSizeData::FromString(DATA1_AS_STRING); + FixedSizeData data2 = FixedSizeData::FromString(DATA2_AS_STRING); + data2 = data1; + EXPECT_EQ(DATA1_AS_STRING, data1.ToString()); +} + +// This tests that a FixedSizeData object is very lightweight +// (it is meant to be kept on stack and passed around) +TEST_F(FixedSizeDataTest, IsLightweightObject) { + EXPECT_EQ(FixedSizeData::BINARY_LENGTH, sizeof(FixedSizeData)); +}