diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 4879389e..00000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -if (BUILD_TESTING) - include_directories(../src) - - add_subdirectory(my-gtest-main) - add_subdirectory(gitversion) - add_subdirectory(cpp-utils) - if (NOT MSVC) - # TODO Make this build on Windows - add_subdirectory(fspp) - endif() - add_subdirectory(parallelaccessstore) - add_subdirectory(blockstore) - add_subdirectory(blobstore) - add_subdirectory(cryfs) - add_subdirectory(cryfs-cli) -endif(BUILD_TESTING) diff --git a/test/blobstore/CMakeLists.txt b/test/blobstore/CMakeLists.txt deleted file mode 100644 index 05e98b8d..00000000 --- a/test/blobstore/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -project (blobstore-test) - -set(SOURCES - implementations/onblocks/utils/MaxZeroSubtractionTest.cpp - implementations/onblocks/utils/CeilDivisionTest.cpp - implementations/onblocks/utils/IntPowTest.cpp - implementations/onblocks/utils/CeilLogTest.cpp - implementations/onblocks/testutils/BlobStoreTest.cpp - implementations/onblocks/BlobStoreTest.cpp - implementations/onblocks/datanodestore/DataLeafNodeTest.cpp - implementations/onblocks/datanodestore/DataInnerNodeTest.cpp - implementations/onblocks/datanodestore/DataNodeViewTest.cpp - implementations/onblocks/datanodestore/DataNodeStoreTest.cpp - implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp - implementations/onblocks/datatreestore/impl/GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest.cpp - implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp - implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp - implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp - implementations/onblocks/datatreestore/DataTreeTest_NumStoredBytes.cpp - implementations/onblocks/datatreestore/DataTreeTest_ResizeNumBytes.cpp - implementations/onblocks/datatreestore/DataTreeStoreTest.cpp - implementations/onblocks/datatreestore/LeafTraverserTest.cpp - implementations/onblocks/BlobSizeTest.cpp - implementations/onblocks/BlobReadWriteTest.cpp - implementations/onblocks/BigBlobsTest.cpp - -) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest blobstore) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/blobstore/implementations/onblocks/BigBlobsTest.cpp b/test/blobstore/implementations/onblocks/BigBlobsTest.cpp deleted file mode 100644 index f65dedc2..00000000 --- a/test/blobstore/implementations/onblocks/BigBlobsTest.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h" -#include "blobstore/implementations/onblocks/BlobOnBlocks.h" - -using namespace blobstore; -using namespace blobstore::onblocks; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::DataFixture; -using cpputils::Data; -using blockstore::inmemory::InMemoryBlockStore2; -using blockstore::lowtohighlevel::LowToHighLevelBlockStore; -using blockstore::compressing::CompressingBlockStore; -using blockstore::compressing::RunLengthEncoding; - -// Test cases, ensuring that big blobs (>4G) work (i.e. testing that we don't use any 32bit variables for blob size, etc.) -class BigBlobsTest : public ::testing::Test { -public: - static constexpr size_t BLOCKSIZE = 32 * 1024; - static constexpr uint64_t SMALL_BLOB_SIZE = UINT64_C(1024)*1024*1024*3.95; // 3.95 GB (<4GB) - static constexpr uint64_t LARGE_BLOB_SIZE = UINT64_C(1024)*1024*1024*4.05; // 4.05 GB (>4GB) - - static constexpr uint64_t max_uint_32 = std::numeric_limits::max(); - static_assert(SMALL_BLOB_SIZE < max_uint_32, "LARGE_BLOB_SIZE should need 64bit or the test case is mute"); - static_assert(LARGE_BLOB_SIZE > max_uint_32, "LARGE_BLOB_SIZE should need 64bit or the test case is mute"); - - unique_ref blobStore = make_unique_ref(make_unique_ref>(make_unique_ref(make_unique_ref())), BLOCKSIZE); - unique_ref blob = blobStore->create(); -}; - -constexpr size_t BigBlobsTest::BLOCKSIZE; -constexpr uint64_t BigBlobsTest::SMALL_BLOB_SIZE; -constexpr uint64_t BigBlobsTest::LARGE_BLOB_SIZE; - -TEST_F(BigBlobsTest, Resize) { - //These operations are in one test case and not in many small ones, because it takes quite long to create a >4GB blob. - - //Resize to >4GB - blob->resize(LARGE_BLOB_SIZE); - EXPECT_EQ(LARGE_BLOB_SIZE, blob->size()); - - //Grow while >4GB - blob->resize(LARGE_BLOB_SIZE + 1024); - EXPECT_EQ(LARGE_BLOB_SIZE + 1024, blob->size()); - - //Shrink while >4GB - blob->resize(LARGE_BLOB_SIZE); - EXPECT_EQ(LARGE_BLOB_SIZE, blob->size()); - - //Shrink to <4GB - blob->resize(SMALL_BLOB_SIZE); - EXPECT_EQ(SMALL_BLOB_SIZE, blob->size()); - - //Grow to >4GB - blob->resize(LARGE_BLOB_SIZE); - EXPECT_EQ(LARGE_BLOB_SIZE, blob->size()); - - //Flush >4GB blob - blob->flush(); - - //Destruct >4GB blob - auto blockId = blob->blockId(); - cpputils::destruct(std::move(blob)); - - //Load >4GB blob - blob = blobStore->load(blockId).value(); - - //Remove >4GB blob - blobStore->remove(std::move(blob)); -} - -TEST_F(BigBlobsTest, GrowByWriting_Crossing4GBBorder) { - Data fixture = DataFixture::generate(2*(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE)); - blob->write(fixture.data(), SMALL_BLOB_SIZE, fixture.size()); - - EXPECT_EQ(LARGE_BLOB_SIZE+(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE), blob->size()); - - Data loaded(fixture.size()); - blob->read(loaded.data(), SMALL_BLOB_SIZE, loaded.size()); - EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size())); -} - -TEST_F(BigBlobsTest, GrowByWriting_Outside4GBBorder_StartingSizeZero) { - Data fixture = DataFixture::generate(1024); - blob->write(fixture.data(), LARGE_BLOB_SIZE, fixture.size()); - - EXPECT_EQ(LARGE_BLOB_SIZE+1024, blob->size()); - - Data loaded(fixture.size()); - blob->read(loaded.data(), LARGE_BLOB_SIZE, loaded.size()); - EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size())); -} - -TEST_F(BigBlobsTest, GrowByWriting_Outside4GBBorder_StartingSizeOutside4GBBorder) { - blob->resize(LARGE_BLOB_SIZE); - Data fixture = DataFixture::generate(1024); - blob->write(fixture.data(), LARGE_BLOB_SIZE+1024, fixture.size()); - - EXPECT_EQ(LARGE_BLOB_SIZE+2048, blob->size()); - - Data loaded(fixture.size()); - blob->read(loaded.data(), LARGE_BLOB_SIZE+1024, loaded.size()); - EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size())); -} - -TEST_F(BigBlobsTest, ReadWriteAfterGrown_Crossing4GBBorder) { - blob->resize(LARGE_BLOB_SIZE+(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE)+1024); - Data fixture = DataFixture::generate(2*(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE)); - blob->write(fixture.data(), SMALL_BLOB_SIZE, fixture.size()); - - EXPECT_EQ(LARGE_BLOB_SIZE+(LARGE_BLOB_SIZE-SMALL_BLOB_SIZE)+1024, blob->size()); - - Data loaded(fixture.size()); - blob->read(loaded.data(), SMALL_BLOB_SIZE, loaded.size()); - EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size())); -} - -TEST_F(BigBlobsTest, ReadWriteAfterGrown_Outside4GBBorder) { - blob->resize(LARGE_BLOB_SIZE+2048); - Data fixture = DataFixture::generate(1024); - blob->write(fixture.data(), LARGE_BLOB_SIZE, fixture.size()); - - EXPECT_EQ(LARGE_BLOB_SIZE+2048, blob->size()); - - Data loaded(fixture.size()); - blob->read(loaded.data(), LARGE_BLOB_SIZE, loaded.size()); - EXPECT_EQ(0, std::memcmp(loaded.data(), fixture.data(), loaded.size())); -} - -//TODO Test Blob::readAll (only on 64bit systems) diff --git a/test/blobstore/implementations/onblocks/BlobReadWriteTest.cpp b/test/blobstore/implementations/onblocks/BlobReadWriteTest.cpp deleted file mode 100644 index 4a6bba48..00000000 --- a/test/blobstore/implementations/onblocks/BlobReadWriteTest.cpp +++ /dev/null @@ -1,256 +0,0 @@ -#include "testutils/BlobStoreTest.h" -#include -#include -#include "blobstore/implementations/onblocks/datanodestore/DataNodeView.h" - -using cpputils::unique_ref; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace blobstore; -using blobstore::onblocks::datanodestore::DataNodeLayout; -using blockstore::BlockId; -using cpputils::Data; -using cpputils::DataFixture; - -namespace { - -class BlobReadWriteTest: public BlobStoreTest { -public: - static constexpr uint32_t LARGE_SIZE = 10 * 1024 * 1024; - static constexpr DataNodeLayout LAYOUT = DataNodeLayout(BLOCKSIZE_BYTES); - - BlobReadWriteTest() - :randomData(DataFixture::generate(LARGE_SIZE)), - blob(blobStore->create()) { - } - - Data readBlob(const Blob &blob) { - Data data(blob.size()); - blob.read(data.data(), 0, data.size()); - return data; - } - - template - void EXPECT_DATA_READS_AS(const DataClass &expected, const Blob &actual, uint64_t offset, uint64_t size) { - Data read(size); - actual.read(read.data(), offset, size); - EXPECT_EQ(0, std::memcmp(expected.data(), read.data(), size)); - } - - Data randomData; - unique_ref blob; -}; -constexpr uint32_t BlobReadWriteTest::LARGE_SIZE; -constexpr DataNodeLayout BlobReadWriteTest::LAYOUT; - -TEST_F(BlobReadWriteTest, WritingImmediatelyFlushes_SmallSize) { - blob->resize(5); - blob->write(randomData.data(), 0, 5); - auto loaded = loadBlob(blob->blockId()); - EXPECT_DATA_READS_AS(randomData, *loaded, 0, 5); -} - -TEST_F(BlobReadWriteTest, WritingImmediatelyFlushes_LargeSize) { - blob->resize(LARGE_SIZE); - blob->write(randomData.data(), 0, LARGE_SIZE); - auto loaded = loadBlob(blob->blockId()); - EXPECT_DATA_READS_AS(randomData, *loaded, 0, LARGE_SIZE); -} - -// Regression test for a strange bug we had -TEST_F(BlobReadWriteTest, WritingCloseTo16ByteLimitDoesntDestroySize) { - blob->resize(1); - blob->write(randomData.data(), 32776, 4); - EXPECT_EQ(32780u, blob->size()); -} - -TEST_F(BlobReadWriteTest, givenEmptyBlob_whenTryReadInFirstLeaf_thenFails) { - Data data(5); - size_t read = blob->tryRead(data.data(), 3, 5); - EXPECT_EQ(0, read); -} - -TEST_F(BlobReadWriteTest, givenEmptyBlob_whenTryReadInLaterLeaf_thenFails) { - Data data(5); - size_t read = blob->tryRead(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5); - EXPECT_EQ(0, read); -} - -TEST_F(BlobReadWriteTest, givenEmptyBlob_whenReadInFirstLeaf_thenFails) { - Data data(5); - EXPECT_ANY_THROW( - blob->read(data.data(), 3, 5) - ); -} - -TEST_F(BlobReadWriteTest, givenEmptyBlob_whenReadInLaterLeaf_thenFails) { - Data data(5); - EXPECT_ANY_THROW( - blob->read(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5) - ); -} - -TEST_F(BlobReadWriteTest, givenEmptyBlob_whenReadAll_thenReturnsZeroSizedData) { - Data data = blob->readAll(); - EXPECT_EQ(0, data.size()); -} - -TEST_F(BlobReadWriteTest, givenEmptyBlob_whenWrite_thenGrows) { - Data data(5); - blob->write(data.data(), 4, 5); - EXPECT_EQ(9, blob->size()); -} - -TEST_F(BlobReadWriteTest, givenEmptyBlob_whenWriteZeroBytes_thenDoesntGrow) { - Data data(5); - blob->write(data.data(), 4, 0); - EXPECT_EQ(0, blob->size());; -} - -TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenTryReadInFirstLeaf_thenFails) { - Data data(5); - size_t read = blob->tryRead(data.data(), 3, 5); - EXPECT_EQ(0, read); -} - -TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenTryReadInLaterLeaf_thenFails) { - Data data(5); - size_t read = blob->tryRead(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5); - EXPECT_EQ(0, read); -} - -TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenReadInFirstLeaf_thenFails) { - Data data(5); - EXPECT_ANY_THROW( - blob->read(data.data(), 3, 5) - ); -} - -TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenReadInLaterLeaf_thenFails) { - Data data(5); - EXPECT_ANY_THROW( - blob->read(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5) - ); -} - -TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenReadAll_thenReturnsZeroSizedData) { - Data data = blob->readAll(); - EXPECT_EQ(0, data.size()); -} - -TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenWrite_thenGrows) { - Data data(5); - blob->write(data.data(), 4, 5); - EXPECT_EQ(9, blob->size()); -} - -TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenWriteZeroBytes_thenDoesntGrow) { - Data data(5); - blob->write(data.data(), 4, 0); - EXPECT_EQ(0, blob->size()); -} - -struct DataRange { - uint64_t blobsize; - uint64_t offset; - uint64_t count; -}; -class BlobReadWriteDataTest: public BlobReadWriteTest, public WithParamInterface { -public: - Data foregroundData; - Data backgroundData; - - BlobReadWriteDataTest() - : foregroundData(DataFixture::generate(GetParam().count, 0)), - backgroundData(DataFixture::generate(GetParam().blobsize, 1)) { - } - - template - void EXPECT_DATA_READS_AS_OUTSIDE_OF(const DataClass &expected, const Blob &blob, uint64_t start, uint64_t count) { - Data begin(start); - Data end(GetParam().blobsize - count - start); - - std::memcpy(begin.data(), expected.data(), start); - std::memcpy(end.data(), expected.dataOffset(start+count), end.size()); - - EXPECT_DATA_READS_AS(begin, blob, 0, start); - EXPECT_DATA_READS_AS(end, blob, start + count, end.size()); - } - - void EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(const Blob &blob, uint64_t start, uint64_t count) { - Data ZEROES(GetParam().blobsize); - ZEROES.FillWithZeroes(); - EXPECT_DATA_READS_AS_OUTSIDE_OF(ZEROES, blob, start, count); - } -}; -INSTANTIATE_TEST_SUITE_P(BlobReadWriteDataTest, BlobReadWriteDataTest, Values( - //Blob with only one leaf - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf(), 0, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()}, // full size leaf, access beginning to end - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf(), 100, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-200}, // full size leaf, access middle to middle - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf(), 0, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-100}, // full size leaf, access beginning to middle - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf(), 100, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-100}, // full size leaf, access middle to end - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-100, 0, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-100}, // non-full size leaf, access beginning to end - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-100, 100, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-300}, // non-full size leaf, access middle to middle - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-100, 0, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-200}, // non-full size leaf, access beginning to middle - DataRange{BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-100, 100, BlobReadWriteDataTest::LAYOUT.maxBytesPerLeaf()-200}, // non-full size leaf, access middle to end - //Larger blob - DataRange{BlobReadWriteDataTest::LARGE_SIZE, 0, BlobReadWriteDataTest::LARGE_SIZE}, // access beginning to end - DataRange{BlobReadWriteDataTest::LARGE_SIZE, 100, BlobReadWriteDataTest::LARGE_SIZE-200}, // access middle first leaf to middle last leaf - DataRange{BlobReadWriteDataTest::LARGE_SIZE, 0, BlobReadWriteDataTest::LARGE_SIZE-100}, // access beginning to middle last leaf - DataRange{BlobReadWriteDataTest::LARGE_SIZE, 100, BlobReadWriteDataTest::LARGE_SIZE-100}, // access middle first leaf to end - DataRange{BlobReadWriteDataTest::LARGE_SIZE, BlobReadWriteDataTest::LARGE_SIZE*1/3, BlobReadWriteDataTest::LARGE_SIZE*1/3}, // access middle to middle - DataRange{BlobReadWriteDataTest::LARGE_SIZE, 0, BlobReadWriteDataTest::LARGE_SIZE*2/3}, // access beginning to middle - DataRange{BlobReadWriteDataTest::LARGE_SIZE, BlobReadWriteDataTest::LARGE_SIZE*1/3, BlobReadWriteDataTest::LARGE_SIZE*2/3} // access middle to end -)); - -TEST_P(BlobReadWriteDataTest, WritingDoesntChangeSize) { - blob->resize(GetParam().blobsize); - blob->write(this->foregroundData.data(), GetParam().offset, GetParam().count); - EXPECT_EQ(GetParam().blobsize, blob->size()); -} - -TEST_P(BlobReadWriteDataTest, WriteAndReadImmediately) { - blob->resize(GetParam().blobsize); - blob->write(this->foregroundData.data(), GetParam().offset, GetParam().count); - - EXPECT_DATA_READS_AS(this->foregroundData, *blob, GetParam().offset, GetParam().count); - EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*blob, GetParam().offset, GetParam().count); -} - -TEST_P(BlobReadWriteDataTest, WriteAndReadAfterLoading) { - blob->resize(GetParam().blobsize); - blob->write(this->foregroundData.data(), GetParam().offset, GetParam().count); - auto loaded = loadBlob(blob->blockId()); - - EXPECT_DATA_READS_AS(this->foregroundData, *loaded, GetParam().offset, GetParam().count); - EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*loaded, GetParam().offset, GetParam().count); -} - -TEST_P(BlobReadWriteDataTest, OverwriteAndRead) { - blob->resize(GetParam().blobsize); - blob->write(this->backgroundData.data(), 0, GetParam().blobsize); - blob->write(this->foregroundData.data(), GetParam().offset, GetParam().count); - EXPECT_DATA_READS_AS(this->foregroundData, *blob, GetParam().offset, GetParam().count); - EXPECT_DATA_READS_AS_OUTSIDE_OF(this->backgroundData, *blob, GetParam().offset, GetParam().count); -} - -TEST_P(BlobReadWriteDataTest, WriteWholeAndReadPart) { - blob->resize(GetParam().blobsize); - blob->write(this->backgroundData.data(), 0, GetParam().blobsize); - Data read(GetParam().count); - blob->read(read.data(), GetParam().offset, GetParam().count); - EXPECT_EQ(0, std::memcmp(read.data(), this->backgroundData.dataOffset(GetParam().offset), GetParam().count)); -} - -TEST_P(BlobReadWriteDataTest, WritePartAndReadWhole) { - blob->resize(GetParam().blobsize); - blob->write(this->backgroundData.data(), 0, GetParam().blobsize); - blob->write(this->foregroundData.data(), GetParam().offset, GetParam().count); - Data read = readBlob(*blob); - EXPECT_EQ(0, std::memcmp(read.data(), this->backgroundData.data(), GetParam().offset)); - EXPECT_EQ(0, std::memcmp(read.dataOffset(GetParam().offset), this->foregroundData.data(), GetParam().count)); - EXPECT_EQ(0, std::memcmp(read.dataOffset(GetParam().offset+GetParam().count), this->backgroundData.dataOffset(GetParam().offset+GetParam().count), GetParam().blobsize-GetParam().count-GetParam().offset)); -} - -} \ No newline at end of file diff --git a/test/blobstore/implementations/onblocks/BlobSizeTest.cpp b/test/blobstore/implementations/onblocks/BlobSizeTest.cpp deleted file mode 100644 index 5e063e5b..00000000 --- a/test/blobstore/implementations/onblocks/BlobSizeTest.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "testutils/BlobStoreTest.h" -#include -#include - -using namespace blobstore; -using blockstore::BlockId; -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::unique_ref; - -class BlobSizeTest: public BlobStoreTest { -public: - BlobSizeTest(): blob(blobStore->create()) {} - - static constexpr uint32_t MEDIUM_SIZE = 5 * 1024 * 1024; - static constexpr uint32_t LARGE_SIZE = 10 * 1024 * 1024; - - unique_ref blob; -}; -constexpr uint32_t BlobSizeTest::MEDIUM_SIZE; -constexpr uint32_t BlobSizeTest::LARGE_SIZE; - -TEST_F(BlobSizeTest, CreatedBlobIsEmpty) { - EXPECT_EQ(0u, blob->size()); -} - -TEST_F(BlobSizeTest, Growing_1Byte) { - blob->resize(1); - EXPECT_EQ(1u, blob->size()); -} - -TEST_F(BlobSizeTest, Growing_Large) { - blob->resize(LARGE_SIZE); - EXPECT_EQ(LARGE_SIZE, blob->size()); -} - -TEST_F(BlobSizeTest, Shrinking_Empty) { - blob->resize(LARGE_SIZE); - blob->resize(0); - EXPECT_EQ(0u, blob->size()); -} - -TEST_F(BlobSizeTest, Shrinking_1Byte) { - blob->resize(LARGE_SIZE); - blob->resize(1); - EXPECT_EQ(1u, blob->size()); -} - -TEST_F(BlobSizeTest, ResizingToItself_Empty) { - blob->resize(0); - EXPECT_EQ(0u, blob->size()); -} - -TEST_F(BlobSizeTest, ResizingToItself_1Byte) { - blob->resize(1); - blob->resize(1); - EXPECT_EQ(1u, blob->size()); -} - -TEST_F(BlobSizeTest, ResizingToItself_Large) { - blob->resize(LARGE_SIZE); - blob->resize(LARGE_SIZE); - EXPECT_EQ(LARGE_SIZE, blob->size()); -} - -TEST_F(BlobSizeTest, EmptyBlobStaysEmptyWhenLoading) { - BlockId blockId = blob->blockId(); - reset(std::move(blob)); - auto loaded = loadBlob(blockId); - EXPECT_EQ(0u, loaded->size()); -} - -TEST_F(BlobSizeTest, BlobSizeStaysIntactWhenLoading) { - blob->resize(LARGE_SIZE); - BlockId blockId = blob->blockId(); - reset(std::move(blob)); - auto loaded = loadBlob(blockId); - EXPECT_EQ(LARGE_SIZE, loaded->size()); -} - -TEST_F(BlobSizeTest, WritingAtEndOfBlobGrowsBlob_Empty) { - int value = 0; - blob->write(&value, 0, 4); - EXPECT_EQ(4u, blob->size()); -} - -TEST_F(BlobSizeTest, WritingAfterEndOfBlobGrowsBlob_Empty) { - int value = 0; - blob->write(&value, 2, 4); - EXPECT_EQ(6u, blob->size()); -} - -TEST_F(BlobSizeTest, WritingOverEndOfBlobGrowsBlob_NonEmpty) { - blob->resize(1); - int value = 0; - blob->write(&value, 0, 4); - EXPECT_EQ(4u, blob->size()); -} - -TEST_F(BlobSizeTest, WritingAtEndOfBlobGrowsBlob_NonEmpty) { - blob->resize(1); - int value = 0; - blob->write(&value, 1, 4); - EXPECT_EQ(5u, blob->size()); -} - -TEST_F(BlobSizeTest, WritingAfterEndOfBlobGrowsBlob_NonEmpty) { - blob->resize(1); - int value = 0; - blob->write(&value, 2, 4); - EXPECT_EQ(6u, blob->size()); -} - -TEST_F(BlobSizeTest, ChangingSizeImmediatelyFlushes) { - blob->resize(LARGE_SIZE); - auto loaded = loadBlob(blob->blockId()); - EXPECT_EQ(LARGE_SIZE, loaded->size()); -} - -class BlobSizeDataTest: public BlobSizeTest { -public: - BlobSizeDataTest() - :ZEROES(LARGE_SIZE), - randomData(DataFixture::generate(LARGE_SIZE)) { - ZEROES.FillWithZeroes(); - } - - Data readBlob(const Blob &blob) { - Data data(blob.size()); - blob.read(data.data(), 0, data.size()); - return data; - } - - Data ZEROES; - Data randomData; -}; - -TEST_F(BlobSizeDataTest, BlobIsZeroedOutAfterGrowing) { - //uint32_t LARGE_SIZE = 2*1024*1024; - blob->resize(LARGE_SIZE); - EXPECT_EQ(0, std::memcmp(readBlob(*blob).data(), ZEROES.data(), LARGE_SIZE)); -} - -TEST_F(BlobSizeDataTest, BlobIsZeroedOutAfterGrowingAndLoading) { - blob->resize(LARGE_SIZE); - auto loaded = loadBlob(blob->blockId()); - EXPECT_EQ(0, std::memcmp(readBlob(*loaded).data(), ZEROES.data(), LARGE_SIZE)); -} - -TEST_F(BlobSizeDataTest, DataStaysIntactWhenGrowing) { - blob->resize(MEDIUM_SIZE); - blob->write(randomData.data(), 0, MEDIUM_SIZE); - blob->resize(LARGE_SIZE); - EXPECT_EQ(0, std::memcmp(readBlob(*blob).data(), randomData.data(), MEDIUM_SIZE)); - EXPECT_EQ(0, std::memcmp(readBlob(*blob).dataOffset(MEDIUM_SIZE), ZEROES.data(), LARGE_SIZE-MEDIUM_SIZE)); -} - -TEST_F(BlobSizeDataTest, DataStaysIntactWhenShrinking) { - blob->resize(LARGE_SIZE); - blob->write(randomData.data(), 0, LARGE_SIZE); - blob->resize(MEDIUM_SIZE); - EXPECT_EQ(0, std::memcmp(readBlob(*blob).data(), randomData.data(), MEDIUM_SIZE)); -} - -TEST_F(BlobSizeDataTest, ChangedAreaIsZeroedOutWhenShrinkingAndRegrowing) { - blob->resize(LARGE_SIZE); - blob->write(randomData.data(), 0, LARGE_SIZE); - blob->resize(MEDIUM_SIZE); - blob->resize(LARGE_SIZE); - EXPECT_EQ(0, std::memcmp(readBlob(*blob).data(), randomData.data(), MEDIUM_SIZE)); - EXPECT_EQ(0, std::memcmp(readBlob(*blob).dataOffset(MEDIUM_SIZE), ZEROES.data(), LARGE_SIZE-MEDIUM_SIZE)); -} diff --git a/test/blobstore/implementations/onblocks/BlobStoreTest.cpp b/test/blobstore/implementations/onblocks/BlobStoreTest.cpp deleted file mode 100644 index aab75fc1..00000000 --- a/test/blobstore/implementations/onblocks/BlobStoreTest.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "testutils/BlobStoreTest.h" -#include - -using blockstore::BlockId; -using boost::none; - -TEST_F(BlobStoreTest, LoadNonexistingKeyOnEmptyBlobstore) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_EQ(none, blobStore->load(blockId)); -} - -TEST_F(BlobStoreTest, LoadNonexistingKeyOnNonEmptyBlobstore) { - blobStore->create(); - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_EQ(none, blobStore->load(blockId)); -} - -TEST_F(BlobStoreTest, TwoCreatedBlobsHaveDifferentKeys) { - auto blob1 = blobStore->create(); - auto blob2 = blobStore->create(); - EXPECT_NE(blob1->blockId(), blob2->blockId()); -} - -TEST_F(BlobStoreTest, BlobIsNotLoadableAfterDeletion_DeleteDirectly) { - auto blob = blobStore->create(); - BlockId blockId = blob->blockId(); - blobStore->remove(std::move(blob)); - EXPECT_FALSE(static_cast(blobStore->load(blockId))); -} - -TEST_F(BlobStoreTest, BlobIsNotLoadableAfterDeletion_DeleteByKey) { - auto blockId = blobStore->create()->blockId(); - blobStore->remove(blockId); - EXPECT_FALSE(static_cast(blobStore->load(blockId))); -} - -TEST_F(BlobStoreTest, BlobIsNotLoadableAfterDeletion_DeleteAfterLoading) { - auto blob = blobStore->create(); - BlockId blockId = blob->blockId(); - reset(std::move(blob)); - blobStore->remove(loadBlob(blockId)); - EXPECT_FALSE(static_cast(blobStore->load(blockId))); -} diff --git a/test/blobstore/implementations/onblocks/datanodestore/DataInnerNodeTest.cpp b/test/blobstore/implementations/onblocks/datanodestore/DataInnerNodeTest.cpp deleted file mode 100644 index 6cb7b86c..00000000 --- a/test/blobstore/implementations/onblocks/datanodestore/DataInnerNodeTest.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include - -#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataNodeStore.h" - -#include -#include - -#include -#include - -using ::testing::Test; - -using cpputils::dynamic_pointer_move; - -using blockstore::BlockId; -using blockstore::testfake::FakeBlockStore; -using blockstore::BlockStore; -using cpputils::Data; -using namespace blobstore; -using namespace blobstore::onblocks; -using namespace blobstore::onblocks::datanodestore; - -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using std::vector; - -class DataInnerNodeTest: public Test { -public: - static constexpr uint32_t BLOCKSIZE_BYTES = 1024; - - DataInnerNodeTest() : - _blockStore(make_unique_ref()), - blockStore(_blockStore.get()), - nodeStore(make_unique_ref(std::move(_blockStore), BLOCKSIZE_BYTES)), - ZEROES(nodeStore->layout().maxBytesPerLeaf()), - leaf(nodeStore->createNewLeafNode(Data(0))), - node(nodeStore->createNewInnerNode(1, {leaf->blockId()})) { - - ZEROES.FillWithZeroes(); - } - - unique_ref LoadInnerNode(const BlockId &blockId) { - auto node = nodeStore->load(blockId).value(); - return dynamic_pointer_move(node).value(); - } - - BlockId CreateNewInnerNodeReturnKey(const DataNode &firstChild) { - return nodeStore->createNewInnerNode(firstChild.depth()+1, {firstChild.blockId()})->blockId(); - } - - unique_ref CreateNewInnerNode() { - auto new_leaf = nodeStore->createNewLeafNode(Data(0)); - return nodeStore->createNewInnerNode(1, {new_leaf->blockId()}); - } - - unique_ref CreateAndLoadNewInnerNode(const DataNode &firstChild) { - auto blockId = CreateNewInnerNodeReturnKey(firstChild); - return LoadInnerNode(blockId); - } - - unique_ref CreateNewInnerNode(uint8_t depth, const vector &children) { - return nodeStore->createNewInnerNode(depth, children); - } - - BlockId CreateNewInnerNodeReturnKey(uint8_t depth, const vector &children) { - return CreateNewInnerNode(depth, children)->blockId(); - } - - unique_ref CreateAndLoadNewInnerNode(uint8_t depth, const vector &children) { - auto blockId = CreateNewInnerNodeReturnKey(depth, children); - return LoadInnerNode(blockId); - } - - BlockId AddALeafTo(DataInnerNode *node) { - auto leaf2 = nodeStore->createNewLeafNode(Data(0)); - node->addChild(*leaf2); - return leaf2->blockId(); - } - - BlockId CreateNodeWithDataConvertItToInnerNodeAndReturnKey() { - auto node = CreateNewInnerNode(); - AddALeafTo(node.get()); - AddALeafTo(node.get()); - auto child = nodeStore->createNewLeafNode(Data(0)); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(node), nodeStore->layout(), *child); - return converted->blockId(); - } - - unique_ref CopyInnerNode(const DataInnerNode &node) { - auto copied = nodeStore->createNewNodeAsCopyFrom(node); - return dynamic_pointer_move(copied).value(); - } - - BlockId InitializeInnerNodeAddLeafReturnKey() { - auto node = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->blockId()}); - AddALeafTo(node.get()); - return node->blockId(); - } - - unique_ref _blockStore; - BlockStore *blockStore; - unique_ref nodeStore; - Data ZEROES; - unique_ref leaf; - unique_ref node; - -private: - - DISALLOW_COPY_AND_ASSIGN(DataInnerNodeTest); -}; - -constexpr uint32_t DataInnerNodeTest::BLOCKSIZE_BYTES; - -TEST_F(DataInnerNodeTest, CorrectKeyReturnedAfterLoading) { - BlockId blockId = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->blockId()})->blockId(); - - auto loaded = nodeStore->load(blockId).value(); - EXPECT_EQ(blockId, loaded->blockId()); -} - -TEST_F(DataInnerNodeTest, InitializesCorrectly) { - auto node = DataInnerNode::CreateNewNode(blockStore, nodeStore->layout(), 1, {leaf->blockId()}); - - EXPECT_EQ(1u, node->numChildren()); - EXPECT_EQ(leaf->blockId(), node->readChild(0).blockId()); -} - -TEST_F(DataInnerNodeTest, ReinitializesCorrectly) { - auto blockId = DataLeafNode::CreateNewNode(blockStore, nodeStore->layout(), Data(0))->blockId(); - auto node = DataInnerNode::InitializeNewNode(blockStore->load(blockId).value(), nodeStore->layout(), 1, {leaf->blockId()}); - - EXPECT_EQ(1u, node->numChildren()); - EXPECT_EQ(leaf->blockId(), node->readChild(0).blockId()); -} - -TEST_F(DataInnerNodeTest, IsCorrectlyInitializedAfterLoading) { - auto loaded = CreateAndLoadNewInnerNode(*leaf); - - EXPECT_EQ(1u, loaded->numChildren()); - EXPECT_EQ(leaf->blockId(), loaded->readChild(0).blockId()); -} - -TEST_F(DataInnerNodeTest, AddingASecondLeaf) { - BlockId leaf2_blockId = AddALeafTo(node.get()); - - EXPECT_EQ(2u, node->numChildren()); - EXPECT_EQ(leaf->blockId(), node->readChild(0).blockId()); - EXPECT_EQ(leaf2_blockId, node->readChild(1).blockId()); -} - -TEST_F(DataInnerNodeTest, AddingASecondLeafAndReload) { - auto leaf2 = nodeStore->createNewLeafNode(Data(0)); - auto loaded = CreateAndLoadNewInnerNode(1, {leaf->blockId(), leaf2->blockId()}); - - EXPECT_EQ(2u, loaded->numChildren()); - EXPECT_EQ(leaf->blockId(), loaded->readChild(0).blockId()); - EXPECT_EQ(leaf2->blockId(), loaded->readChild(1).blockId()); -} - -TEST_F(DataInnerNodeTest, BuildingAThreeLevelTree) { - auto node2 = CreateNewInnerNode(); - auto parent = CreateNewInnerNode(node->depth()+1, {node->blockId(), node2->blockId()}); - - EXPECT_EQ(2u, parent->numChildren()); - EXPECT_EQ(node->blockId(), parent->readChild(0).blockId()); - EXPECT_EQ(node2->blockId(), parent->readChild(1).blockId()); -} - -TEST_F(DataInnerNodeTest, BuildingAThreeLevelTreeAndReload) { - auto node2 = CreateNewInnerNode(); - auto parent = CreateAndLoadNewInnerNode(node->depth()+1, {node->blockId(), node2->blockId()}); - - EXPECT_EQ(2u, parent->numChildren()); - EXPECT_EQ(node->blockId(), parent->readChild(0).blockId()); - EXPECT_EQ(node2->blockId(), parent->readChild(1).blockId()); -} - -TEST_F(DataInnerNodeTest, ConvertToInternalNode) { - auto child = nodeStore->createNewLeafNode(Data(0)); - BlockId node_blockId = node->blockId(); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(node), nodeStore->layout(), *child); - - EXPECT_EQ(1u, converted->numChildren()); - EXPECT_EQ(child->blockId(), converted->readChild(0).blockId()); - EXPECT_EQ(node_blockId, converted->blockId()); -} - -TEST_F(DataInnerNodeTest, ConvertToInternalNodeZeroesOutChildrenRegion) { - BlockId blockId = CreateNodeWithDataConvertItToInnerNodeAndReturnKey(); - - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(0, std::memcmp(ZEROES.data(), static_cast(block->data())+DataNodeLayout::HEADERSIZE_BYTES+sizeof(DataInnerNode::ChildEntry), nodeStore->layout().maxBytesPerLeaf()-sizeof(DataInnerNode::ChildEntry))); -} - -TEST_F(DataInnerNodeTest, CopyingCreatesNewNode) { - auto copied = CopyInnerNode(*node); - EXPECT_NE(node->blockId(), copied->blockId()); -} - -TEST_F(DataInnerNodeTest, CopyInnerNodeWithOneChild) { - auto copied = CopyInnerNode(*node); - - EXPECT_EQ(node->numChildren(), copied->numChildren()); - EXPECT_EQ(node->readChild(0).blockId(), copied->readChild(0).blockId()); -} - -TEST_F(DataInnerNodeTest, CopyInnerNodeWithTwoChildren) { - AddALeafTo(node.get()); - auto copied = CopyInnerNode(*node); - - EXPECT_EQ(node->numChildren(), copied->numChildren()); - EXPECT_EQ(node->readChild(0).blockId(), copied->readChild(0).blockId()); - EXPECT_EQ(node->readChild(1).blockId(), copied->readChild(1).blockId()); -} - -TEST_F(DataInnerNodeTest, LastChildWhenOneChild) { - EXPECT_EQ(leaf->blockId(), node->readLastChild().blockId()); -} - -TEST_F(DataInnerNodeTest, LastChildWhenTwoChildren) { - BlockId blockId = AddALeafTo(node.get()); - EXPECT_EQ(blockId, node->readLastChild().blockId()); -} - -TEST_F(DataInnerNodeTest, LastChildWhenThreeChildren) { - AddALeafTo(node.get()); - BlockId blockId = AddALeafTo(node.get()); - EXPECT_EQ(blockId, node->readLastChild().blockId()); -} diff --git a/test/blobstore/implementations/onblocks/datanodestore/DataLeafNodeTest.cpp b/test/blobstore/implementations/onblocks/datanodestore/DataLeafNodeTest.cpp deleted file mode 100644 index 3c4bd21b..00000000 --- a/test/blobstore/implementations/onblocks/datanodestore/DataLeafNodeTest.cpp +++ /dev/null @@ -1,345 +0,0 @@ -#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataNodeStore.h" -#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h" -#include - -#include - -#include -#include -#include - -using ::testing::Test; -using ::testing::WithParamInterface; -using ::testing::Values; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using std::string; -using cpputils::DataFixture; -using cpputils::deserialize; - -//TODO Split into multiple files - -using cpputils::dynamic_pointer_move; - -using blockstore::BlockStore; -using cpputils::Data; -using blockstore::BlockId; -using blockstore::testfake::FakeBlockStore; -using namespace blobstore; -using namespace blobstore::onblocks; -using namespace blobstore::onblocks::datanodestore; - -namespace { - -#define EXPECT_IS_PTR_TYPE(Type, ptr) EXPECT_NE(nullptr, dynamic_cast(ptr)) << "Given pointer cannot be cast to the given type" - -class DataLeafNodeTest: public Test { -public: - - static constexpr uint32_t BLOCKSIZE_BYTES = 1024; - static constexpr DataNodeLayout LAYOUT = DataNodeLayout(BLOCKSIZE_BYTES); - - DataLeafNodeTest(): - _blockStore(make_unique_ref()), - blockStore(_blockStore.get()), - nodeStore(make_unique_ref(std::move(_blockStore), BLOCKSIZE_BYTES)), - ZEROES(nodeStore->layout().maxBytesPerLeaf()), - randomData(nodeStore->layout().maxBytesPerLeaf()), - leaf(nodeStore->createNewLeafNode(Data(0))) { - - ZEROES.FillWithZeroes(); - - Data dataFixture(DataFixture::generate(nodeStore->layout().maxBytesPerLeaf())); - - std::memcpy(randomData.data(), dataFixture.data(), randomData.size()); - } - - Data loadData(const DataLeafNode &leaf) { - Data data(leaf.numBytes()); - leaf.read(data.data(), 0, leaf.numBytes()); - return data; - } - - BlockId WriteDataToNewLeafBlockAndReturnKey() { - auto newleaf = nodeStore->createNewLeafNode(Data(0)); - newleaf->resize(randomData.size()); - newleaf->write(randomData.data(), 0, randomData.size()); - return newleaf->blockId(); - } - - void FillLeafBlockWithData() { - FillLeafBlockWithData(leaf.get()); - } - - void FillLeafBlockWithData(DataLeafNode *leaf_to_fill) { - leaf_to_fill->resize(randomData.size()); - leaf_to_fill->write(randomData.data(), 0, randomData.size()); - } - - unique_ref LoadLeafNode(const BlockId &blockId) { - auto leaf = nodeStore->load(blockId).value(); - return dynamic_pointer_move(leaf).value(); - } - - void ResizeLeaf(const BlockId &blockId, size_t size) { - auto leaf = LoadLeafNode(blockId); - EXPECT_IS_PTR_TYPE(DataLeafNode, leaf.get()); - leaf->resize(size); - } - - BlockId CreateLeafWithDataConvertItToInnerNodeAndReturnKey() { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - FillLeafBlockWithData(leaf.get()); - auto child = nodeStore->createNewLeafNode(Data(0)); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(leaf), LAYOUT, *child); - return converted->blockId(); - } - - unique_ref CopyLeafNode(const DataLeafNode &node) { - auto copied = nodeStore->createNewNodeAsCopyFrom(node); - return dynamic_pointer_move(copied).value(); - } - - BlockId InitializeLeafGrowAndReturnKey() { - auto leaf = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(LAYOUT.maxBytesPerLeaf())); - leaf->resize(5); - return leaf->blockId(); - } - - unique_ref _blockStore; - BlockStore *blockStore; - unique_ref nodeStore; - Data ZEROES; - Data randomData; - unique_ref leaf; - -private: - DISALLOW_COPY_AND_ASSIGN(DataLeafNodeTest); -}; - -constexpr uint32_t DataLeafNodeTest::BLOCKSIZE_BYTES; -constexpr DataNodeLayout DataLeafNodeTest::LAYOUT; - -TEST_F(DataLeafNodeTest, CorrectKeyReturnedAfterLoading) { - BlockId blockId = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(LAYOUT.maxBytesPerLeaf()))->blockId(); - - auto loaded = nodeStore->load(blockId).value(); - EXPECT_EQ(blockId, loaded->blockId()); -} - -TEST_F(DataLeafNodeTest, InitializesCorrectly) { - auto leaf = DataLeafNode::CreateNewNode(blockStore, LAYOUT, Data(5)); - EXPECT_EQ(5u, leaf->numBytes()); -} - -TEST_F(DataLeafNodeTest, ReadWrittenDataAfterReloadingBlock) { - BlockId blockId = WriteDataToNewLeafBlockAndReturnKey(); - - auto loaded = LoadLeafNode(blockId); - - EXPECT_EQ(randomData.size(), loaded->numBytes()); - EXPECT_EQ(randomData, loadData(*loaded)); -} - -TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero) { - EXPECT_EQ(0u, leaf->numBytes()); -} - -TEST_F(DataLeafNodeTest, NewLeafNodeHasSizeZero_AfterLoading) { - BlockId blockId = nodeStore->createNewLeafNode(Data(0))->blockId(); - auto leaf = LoadLeafNode(blockId); - - EXPECT_EQ(0u, leaf->numBytes()); -} - -class DataLeafNodeSizeTest: public DataLeafNodeTest, public WithParamInterface { -public: - BlockId CreateLeafResizeItAndReturnKey() { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - leaf->resize(GetParam()); - return leaf->blockId(); - } -}; -INSTANTIATE_TEST_SUITE_P(DataLeafNodeSizeTest, DataLeafNodeSizeTest, Values(0, 1, 5, 16, 32, 512, DataNodeLayout(DataLeafNodeTest::BLOCKSIZE_BYTES).maxBytesPerLeaf())); - -TEST_P(DataLeafNodeSizeTest, ResizeNode_ReadSizeImmediately) { - leaf->resize(GetParam()); - EXPECT_EQ(GetParam(), leaf->numBytes()); -} - -TEST_P(DataLeafNodeSizeTest, ResizeNode_ReadSizeAfterLoading) { - BlockId blockId = CreateLeafResizeItAndReturnKey(); - - auto leaf = LoadLeafNode(blockId); - EXPECT_EQ(GetParam(), leaf->numBytes()); -} - -TEST_F(DataLeafNodeTest, SpaceIsZeroFilledWhenGrowing) { - leaf->resize(randomData.size()); - EXPECT_EQ(0, std::memcmp(ZEROES.data(), loadData(*leaf).data(), randomData.size())); -} - -TEST_F(DataLeafNodeTest, SpaceGetsZeroFilledWhenShrinkingAndRegrowing) { - FillLeafBlockWithData(); - // resize it smaller and then back to original size - uint32_t smaller_size = randomData.size() - 100; - leaf->resize(smaller_size); - leaf->resize(randomData.size()); - - //Check that the space was filled with zeroes - EXPECT_EQ(0, std::memcmp(ZEROES.data(), static_cast(loadData(*leaf).data())+smaller_size, 100)); -} - -TEST_F(DataLeafNodeTest, DataGetsZeroFilledWhenShrinking) { - BlockId blockId = WriteDataToNewLeafBlockAndReturnKey(); - uint32_t smaller_size = randomData.size() - 100; - { - //At first, we expect there to be random data in the underlying data block - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(0, std::memcmp(randomData.dataOffset(smaller_size), static_cast(block->data())+DataNodeLayout::HEADERSIZE_BYTES+smaller_size, 100)); - } - - //After shrinking, we expect there to be zeroes in the underlying data block - ResizeLeaf(blockId, smaller_size); - { - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(0, std::memcmp(ZEROES.data(), static_cast(block->data())+DataNodeLayout::HEADERSIZE_BYTES+smaller_size, 100)); - } -} - -TEST_F(DataLeafNodeTest, ShrinkingDoesntDestroyValidDataRegion) { - FillLeafBlockWithData(); - uint32_t smaller_size = randomData.size() - 100; - leaf->resize(smaller_size); - - //Check that the remaining data region is unchanged - EXPECT_EQ(0, std::memcmp(randomData.data(), loadData(*leaf).data(), smaller_size)); -} - -TEST_F(DataLeafNodeTest, ConvertToInternalNode) { - auto child = nodeStore->createNewLeafNode(Data(0)); - BlockId leaf_blockId = leaf->blockId(); - unique_ref converted = DataNode::convertToNewInnerNode(std::move(leaf), LAYOUT, *child); - - EXPECT_EQ(1u, converted->numChildren()); - EXPECT_EQ(child->blockId(), converted->readChild(0).blockId()); - EXPECT_EQ(leaf_blockId, converted->blockId()); -} - -TEST_F(DataLeafNodeTest, ConvertToInternalNodeZeroesOutChildrenRegion) { - BlockId blockId = CreateLeafWithDataConvertItToInnerNodeAndReturnKey(); - - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(0, std::memcmp(ZEROES.data(), static_cast(block->data())+DataNodeLayout::HEADERSIZE_BYTES+sizeof(DataInnerNode::ChildEntry), nodeStore->layout().maxBytesPerLeaf()-sizeof(DataInnerNode::ChildEntry))); -} - -TEST_F(DataLeafNodeTest, CopyingCreatesANewLeaf) { - auto copied = CopyLeafNode(*leaf); - EXPECT_NE(leaf->blockId(), copied->blockId()); -} - -TEST_F(DataLeafNodeTest, CopyEmptyLeaf) { - auto copied = CopyLeafNode(*leaf); - EXPECT_EQ(leaf->numBytes(), copied->numBytes()); -} - -TEST_F(DataLeafNodeTest, CopyDataLeaf) { - FillLeafBlockWithData(); - auto copied = CopyLeafNode(*leaf); - - EXPECT_EQ(leaf->numBytes(), copied->numBytes()); - EXPECT_EQ(0, std::memcmp(loadData(*leaf).data(), loadData(*copied).data(), leaf->numBytes())); - - //Test that they have different data regions (changing the original one doesn't change the copy) - uint8_t data = 0; - leaf->write(&data, 0, 1); - EXPECT_EQ(data, deserialize(loadData(*leaf).data())); - EXPECT_NE(data, deserialize(loadData(*copied).data())); -} - - -struct DataRange { - uint64_t leafsize; - uint64_t offset; - uint64_t count; -}; - -class DataLeafNodeDataTest: public DataLeafNodeTest, public WithParamInterface { -public: - Data foregroundData; - Data backgroundData; - - DataLeafNodeDataTest(): - foregroundData(DataFixture::generate(GetParam().count, 0)), - backgroundData(DataFixture::generate(GetParam().leafsize, 1)) { - } - - BlockId CreateLeafWriteToItAndReturnKey(const Data &to_write) { - auto newleaf = nodeStore->createNewLeafNode(Data(0)); - - newleaf->resize(GetParam().leafsize); - newleaf->write(to_write.data(), GetParam().offset, GetParam().count); - return newleaf->blockId(); - } - - void EXPECT_DATA_READS_AS(const Data &expected, const DataLeafNode &leaf, uint64_t offset, uint64_t count) { - Data read(count); - leaf.read(read.data(), offset, count); - EXPECT_EQ(expected, read); - } - - void EXPECT_DATA_READS_AS_OUTSIDE_OF(const Data &expected, const DataLeafNode &leaf, uint64_t start, uint64_t count) { - Data begin(start); - Data end(GetParam().leafsize - count - start); - - std::memcpy(begin.data(), expected.data(), start); - std::memcpy(end.data(), expected.dataOffset(start+count), end.size()); - - EXPECT_DATA_READS_AS(begin, leaf, 0, start); - EXPECT_DATA_READS_AS(end, leaf, start + count, end.size()); - } - - void EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(const DataLeafNode &leaf, uint64_t start, uint64_t count) { - Data ZEROES(GetParam().leafsize); - ZEROES.FillWithZeroes(); - EXPECT_DATA_READS_AS_OUTSIDE_OF(ZEROES, leaf, start, count); - } -}; -INSTANTIATE_TEST_SUITE_P(DataLeafNodeDataTest, DataLeafNodeDataTest, Values( - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf(), 0, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()}, // full size leaf, access beginning to end - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf(), 100, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-200}, // full size leaf, access middle to middle - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf(), 0, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-100}, // full size leaf, access beginning to middle - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf(), 100, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-100}, // full size leaf, access middle to end - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-100, 0, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-100}, // non-full size leaf, access beginning to end - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-100, 100, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-300}, // non-full size leaf, access middle to middle - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-100, 0, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-200}, // non-full size leaf, access beginning to middle - DataRange{DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-100, 100, DataLeafNodeTest::LAYOUT.maxBytesPerLeaf()-200} // non-full size leaf, access middle to end -)); - -TEST_P(DataLeafNodeDataTest, WriteAndReadImmediately) { - leaf->resize(GetParam().leafsize); - leaf->write(this->foregroundData.data(), GetParam().offset, GetParam().count); - - EXPECT_DATA_READS_AS(this->foregroundData, *leaf, GetParam().offset, GetParam().count); - EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*leaf, GetParam().offset, GetParam().count); -} - -TEST_P(DataLeafNodeDataTest, WriteAndReadAfterLoading) { - BlockId blockId = CreateLeafWriteToItAndReturnKey(this->foregroundData); - - auto loaded_leaf = LoadLeafNode(blockId); - EXPECT_DATA_READS_AS(this->foregroundData, *loaded_leaf, GetParam().offset, GetParam().count); - EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*loaded_leaf, GetParam().offset, GetParam().count); -} - -TEST_P(DataLeafNodeDataTest, OverwriteAndRead) { - leaf->resize(GetParam().leafsize); - leaf->write(this->backgroundData.data(), 0, GetParam().leafsize); - leaf->write(this->foregroundData.data(), GetParam().offset, GetParam().count); - EXPECT_DATA_READS_AS(this->foregroundData, *leaf, GetParam().offset, GetParam().count); - EXPECT_DATA_READS_AS_OUTSIDE_OF(this->backgroundData, *leaf, GetParam().offset, GetParam().count); -} - -} diff --git a/test/blobstore/implementations/onblocks/datanodestore/DataNodeStoreTest.cpp b/test/blobstore/implementations/onblocks/datanodestore/DataNodeStoreTest.cpp deleted file mode 100644 index da24e58b..00000000 --- a/test/blobstore/implementations/onblocks/datanodestore/DataNodeStoreTest.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataNodeStore.h" -#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h" -#include - -#include -#include -#include - -using ::testing::Test; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using std::string; -using boost::none; - -using blockstore::BlockStore; -using blockstore::testfake::FakeBlockStore; -using blockstore::BlockId; -using cpputils::Data; -using namespace blobstore; -using namespace blobstore::onblocks; -using namespace blobstore::onblocks::datanodestore; - -class DataNodeStoreTest: public Test { -public: - static constexpr uint32_t BLOCKSIZE_BYTES = 1024; - - unique_ref _blockStore = make_unique_ref(); - BlockStore *blockStore = _blockStore.get(); - unique_ref nodeStore = make_unique_ref(std::move(_blockStore), BLOCKSIZE_BYTES); -}; - -constexpr uint32_t DataNodeStoreTest::BLOCKSIZE_BYTES; - -#define EXPECT_IS_PTR_TYPE(Type, ptr) EXPECT_NE(nullptr, dynamic_cast(ptr)) << "Given pointer cannot be cast to the given type" - -TEST_F(DataNodeStoreTest, CreateLeafNodeCreatesLeafNode) { - auto node = nodeStore->createNewLeafNode(Data(0)); - EXPECT_IS_PTR_TYPE(DataLeafNode, node.get()); -} - -TEST_F(DataNodeStoreTest, CreateInnerNodeCreatesInnerNode) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - - auto node = nodeStore->createNewInnerNode(1, {leaf->blockId()}); - EXPECT_IS_PTR_TYPE(DataInnerNode, node.get()); -} - -TEST_F(DataNodeStoreTest, LeafNodeIsRecognizedAfterStoreAndLoad) { - BlockId blockId = nodeStore->createNewLeafNode(Data(0))->blockId(); - - auto loaded_node = nodeStore->load(blockId).value(); - - EXPECT_IS_PTR_TYPE(DataLeafNode, loaded_node.get()); -} - -TEST_F(DataNodeStoreTest, InnerNodeWithDepth1IsRecognizedAfterStoreAndLoad) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - BlockId blockId = nodeStore->createNewInnerNode(1, {leaf->blockId()})->blockId(); - - auto loaded_node = nodeStore->load(blockId).value(); - - EXPECT_IS_PTR_TYPE(DataInnerNode, loaded_node.get()); -} - -TEST_F(DataNodeStoreTest, InnerNodeWithDepth2IsRecognizedAfterStoreAndLoad) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto inner = nodeStore->createNewInnerNode(1, {leaf->blockId()}); - BlockId blockId = nodeStore->createNewInnerNode(2, {inner->blockId()})->blockId(); - - auto loaded_node = nodeStore->load(blockId).value(); - - EXPECT_IS_PTR_TYPE(DataInnerNode, loaded_node.get()); -} - -TEST_F(DataNodeStoreTest, DataNodeCrashesOnLoadIfDepthIsTooHigh) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - BlockId blockId = block->blockId(); - { - DataNodeView view(std::move(block)); - view.setDepth(DataNodeStore::MAX_DEPTH + 1); - } - - EXPECT_ANY_THROW( - nodeStore->load(blockId) - ); -} - -TEST_F(DataNodeStoreTest, CreatedInnerNodeIsInitialized) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto node = nodeStore->createNewInnerNode(1, {leaf->blockId()}); - EXPECT_EQ(1u, node->numChildren()); - EXPECT_EQ(leaf->blockId(), node->readChild(0).blockId()); -} - -TEST_F(DataNodeStoreTest, CreatedLeafNodeIsInitialized) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - EXPECT_EQ(0u, leaf->numBytes()); -} - -TEST_F(DataNodeStoreTest, NodeIsNotLoadableAfterDeleting) { - auto nodekey = nodeStore->createNewLeafNode(Data(0))->blockId(); - auto node = nodeStore->load(nodekey); - EXPECT_NE(none, node); - nodeStore->remove(std::move(*node)); - EXPECT_EQ(none, nodeStore->load(nodekey)); -} - -TEST_F(DataNodeStoreTest, NumNodesIsCorrectOnEmptyNodestore) { - EXPECT_EQ(0u, nodeStore->numNodes()); -} - -TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterAddingOneLeafNode) { - nodeStore->createNewLeafNode(Data(0)); - EXPECT_EQ(1u, nodeStore->numNodes()); -} - -TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterRemovingTheLastNode) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - nodeStore->remove(std::move(leaf)); - EXPECT_EQ(0u, nodeStore->numNodes()); -} - -TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterAddingTwoNodes) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto node = nodeStore->createNewInnerNode(1, {leaf->blockId()}); - EXPECT_EQ(2u, nodeStore->numNodes()); -} - -TEST_F(DataNodeStoreTest, NumNodesIsCorrectAfterRemovingANode) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto node = nodeStore->createNewInnerNode(1, {leaf->blockId()}); - nodeStore->remove(std::move(node)); - EXPECT_EQ(1u, nodeStore->numNodes()); -} - -TEST_F(DataNodeStoreTest, PhysicalBlockSize_Leaf) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto block = blockStore->load(leaf->blockId()).value(); - EXPECT_EQ(BLOCKSIZE_BYTES, block->size()); -} - -TEST_F(DataNodeStoreTest, PhysicalBlockSize_Inner) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto node = nodeStore->createNewInnerNode(1, {leaf->blockId()}); - auto block = blockStore->load(node->blockId()).value(); - EXPECT_EQ(BLOCKSIZE_BYTES, block->size()); -} diff --git a/test/blobstore/implementations/onblocks/datanodestore/DataNodeViewTest.cpp b/test/blobstore/implementations/onblocks/datanodestore/DataNodeViewTest.cpp deleted file mode 100644 index d0a59656..00000000 --- a/test/blobstore/implementations/onblocks/datanodestore/DataNodeViewTest.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "blobstore/implementations/onblocks/datanodestore/DataNodeView.h" -#include - -#include -#include -#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h" -#include - -using ::testing::Test; -using ::testing::WithParamInterface; -using ::testing::Values; -using std::string; - -using blockstore::BlockStore; -using blockstore::testfake::FakeBlockStore; -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using namespace blobstore; -using namespace blobstore::onblocks; -using namespace blobstore::onblocks::datanodestore; - -class DataNodeViewTest: public Test { -public: - static constexpr uint32_t BLOCKSIZE_BYTES = 1024; - static constexpr uint32_t DATASIZE_BYTES = DataNodeLayout(DataNodeViewTest::BLOCKSIZE_BYTES).datasizeBytes(); - - unique_ref blockStore = make_unique_ref(); -}; - -class DataNodeViewDepthTest: public DataNodeViewTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(DataNodeViewDepthTest, DataNodeViewDepthTest, Values(0, 1, 3, 10, 100)); - -TEST_P(DataNodeViewDepthTest, DepthIsStored) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - auto blockId = block->blockId(); - { - DataNodeView view(std::move(block)); - view.setDepth(GetParam()); - } - DataNodeView view(blockStore->load(blockId).value()); - EXPECT_EQ(GetParam(), view.Depth()); -} - -class DataNodeViewSizeTest: public DataNodeViewTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(DataNodeViewSizeTest, DataNodeViewSizeTest, Values(0, 50, 64, 1024, 1024*1024*1024)); - -TEST_P(DataNodeViewSizeTest, SizeIsStored) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - auto blockId = block->blockId(); - { - DataNodeView view(std::move(block)); - view.setSize(GetParam()); - } - DataNodeView view(blockStore->load(blockId).value()); - EXPECT_EQ(GetParam(), view.Size()); -} - -TEST_F(DataNodeViewTest, DataIsStored) { - Data randomData = DataFixture::generate(DATASIZE_BYTES); - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - auto blockId = block->blockId(); - { - DataNodeView view(std::move(block)); - view.write(randomData.data(), 0, randomData.size()); - } - DataNodeView view(blockStore->load(blockId).value()); - EXPECT_EQ(0, std::memcmp(view.data(), randomData.data(), randomData.size())); -} - -TEST_F(DataNodeViewTest, HeaderAndBodyDontOverlap) { - Data randomData = DataFixture::generate(DATASIZE_BYTES); - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - auto blockId = block->blockId(); - { - DataNodeView view(std::move(block)); - view.setDepth(3); - view.setSize(1000000000u); - view.write(randomData.data(), 0, DATASIZE_BYTES); - } - DataNodeView view(blockStore->load(blockId).value()); - EXPECT_EQ(3, view.Depth()); - EXPECT_EQ(1000000000u, view.Size()); - EXPECT_EQ(0, std::memcmp(view.data(), randomData.data(), DATASIZE_BYTES)); -} - -TEST_F(DataNodeViewTest, Data) { - auto block = blockStore->create(Data(BLOCKSIZE_BYTES)); - const uint8_t *blockBegin = static_cast(block->data()); - DataNodeView view(std::move(block)); - - EXPECT_EQ(blockBegin+DataNodeLayout::HEADERSIZE_BYTES, static_cast(view.data())); -} - -//TODO Test that header fields (and data) are also stored over reloads diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeStoreTest.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeStoreTest.cpp deleted file mode 100644 index eb279a31..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeStoreTest.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "testutils/DataTreeTest.h" - -#include "blobstore/implementations/onblocks/datanodestore/DataNodeStore.h" -#include "blobstore/implementations/onblocks/datatreestore/DataTreeStore.h" -#include -#include - -using blockstore::BlockId; -using boost::none; - -using namespace blobstore::onblocks::datatreestore; - -class DataTreeStoreTest: public DataTreeTest { -}; - -TEST_F(DataTreeStoreTest, CorrectKeyReturned) { - BlockId blockId = treeStore.createNewTree()->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(blockId, tree->blockId()); -} - -TEST_F(DataTreeStoreTest, CreatedTreeIsLoadable) { - auto blockId = treeStore.createNewTree()->blockId(); - auto loaded = treeStore.load(blockId); - EXPECT_NE(none, loaded); -} - -TEST_F(DataTreeStoreTest, NewTreeIsLeafOnly) { - auto tree = treeStore.createNewTree(); - - EXPECT_IS_LEAF_NODE(tree->blockId()); -} - -TEST_F(DataTreeStoreTest, TreeIsNotLoadableAfterRemove_DeleteByTree) { - BlockId blockId = treeStore.createNewTree()->blockId(); - auto tree = treeStore.load(blockId); - EXPECT_NE(none, tree); - treeStore.remove(std::move(*tree)); - EXPECT_EQ(none, treeStore.load(blockId)); -} - -TEST_F(DataTreeStoreTest, TreeIsNotLoadableAfterRemove_DeleteByKey) { - BlockId blockId = treeStore.createNewTree()->blockId(); - treeStore.remove(blockId); - EXPECT_EQ(none, treeStore.load(blockId)); -} - -TEST_F(DataTreeStoreTest, RemovingTreeRemovesAllNodesOfTheTree_DeleteByTree) { - auto tree1_blockId = CreateThreeLevelMinData()->blockId(); - auto tree2_blockId = treeStore.createNewTree()->blockId(); - - auto tree1 = treeStore.load(tree1_blockId).value(); - treeStore.remove(std::move(tree1)); - - //Check that the only remaining node is tree2 - EXPECT_EQ(1u, nodeStore->numNodes()); - EXPECT_NE(none, treeStore.load(tree2_blockId)); -} - -TEST_F(DataTreeStoreTest, RemovingTreeRemovesAllNodesOfTheTree_DeleteByKey) { - auto tree1_blockId = CreateThreeLevelMinData()->blockId(); - auto tree2_blockId = treeStore.createNewTree()->blockId(); - - treeStore.remove(tree1_blockId); - - //Check that the only remaining node is tree2 - EXPECT_EQ(1u, nodeStore->numNodes()); - EXPECT_NE(none, treeStore.load(tree2_blockId)); -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_NumStoredBytes.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_NumStoredBytes.cpp deleted file mode 100644 index b6537c5a..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_NumStoredBytes.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "testutils/DataTreeTest.h" -#include - -using ::testing::WithParamInterface; -using ::testing::Values; - -using blobstore::onblocks::datanodestore::DataNodeLayout; -using blockstore::BlockId; - -class DataTreeTest_NumStoredBytes: public DataTreeTest { -public: -}; - -TEST_F(DataTreeTest_NumStoredBytes, CreatedTreeIsEmpty) { - auto tree = treeStore.createNewTree(); - EXPECT_EQ(0u, tree->numBytes()); -} - -class DataTreeTest_NumStoredBytes_P: public DataTreeTest_NumStoredBytes, public WithParamInterface {}; -INSTANTIATE_TEST_SUITE_P(EmptyLastLeaf, DataTreeTest_NumStoredBytes_P, Values(0u)); -INSTANTIATE_TEST_SUITE_P(HalfFullLastLeaf, DataTreeTest_NumStoredBytes_P, Values(5u, 10u)); -INSTANTIATE_TEST_SUITE_P(FullLastLeaf, DataTreeTest_NumStoredBytes_P, Values(static_cast(DataNodeLayout(DataTreeTest_NumStoredBytes::BLOCKSIZE_BYTES).maxBytesPerLeaf()))); - -//TODO Test numLeaves() and numNodes() also two configurations with same number of bytes but different number of leaves (last leaf has 0 bytes) - -TEST_P(DataTreeTest_NumStoredBytes_P, SingleLeaf) { - BlockId blockId = CreateLeafWithSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(GetParam(), tree->numBytes()); - EXPECT_EQ(1, tree->numLeaves()); - EXPECT_EQ(1, tree->numNodes()); -} - -TEST_P(DataTreeTest_NumStoredBytes_P, TwoLeafTree) { - BlockId blockId = CreateTwoLeafWithSecondLeafSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); - EXPECT_EQ(2, tree->numLeaves()); - EXPECT_EQ(3, tree->numNodes()); -} - -TEST_P(DataTreeTest_NumStoredBytes_P, FullTwolevelTree) { - BlockId blockId = CreateFullTwoLevelWithLastLeafSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + GetParam(), tree->numBytes()); - EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves()); - EXPECT_EQ(1 + nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes()); -} - -TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithOneChild) { - BlockId blockId = CreateThreeLevelWithOneChildAndLastLeafSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); - EXPECT_EQ(2, tree->numLeaves()); - EXPECT_EQ(4, tree->numNodes()); -} - -TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithTwoChildren) { - BlockId blockId = CreateThreeLevelWithTwoChildrenAndLastLeafSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); - EXPECT_EQ(2 + nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves()); - EXPECT_EQ(5 + nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes()); -} - -TEST_P(DataTreeTest_NumStoredBytes_P, ThreeLevelTreeWithThreeChildren) { - BlockId blockId = CreateThreeLevelWithThreeChildrenAndLastLeafSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(2*nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxBytesPerLeaf() + GetParam(), tree->numBytes()); - EXPECT_EQ(2 + 2*nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves()); - EXPECT_EQ(6 + 2*nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes()); -} - -TEST_P(DataTreeTest_NumStoredBytes_P, FullThreeLevelTree) { - BlockId blockId = CreateFullThreeLevelWithLastLeafSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + nodeStore->layout().maxBytesPerLeaf()*(nodeStore->layout().maxChildrenPerInnerNode()-1) + GetParam(), tree->numBytes()); - EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves()); - EXPECT_EQ(1 + nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes()); -} - -TEST_P(DataTreeTest_NumStoredBytes_P, FourLevelMinDataTree) { - BlockId blockId = CreateFourLevelMinDataWithLastLeafSize(GetParam())->blockId(); - auto tree = treeStore.load(blockId).value(); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf()*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + GetParam(), tree->numBytes()); - EXPECT_EQ(1 + nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numLeaves()); - EXPECT_EQ(5 + nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode(), tree->numNodes()); -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp deleted file mode 100644 index c400917f..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_Performance.cpp +++ /dev/null @@ -1,558 +0,0 @@ -#include "testutils/DataTreeTest.h" - -#include - -using blobstore::onblocks::datatreestore::DataTree; -using blockstore::BlockId; -using cpputils::Data; - -class DataTreeTest_Performance: public DataTreeTest { -public: - void TraverseByWriting(DataTree *tree, uint64_t beginIndex, uint64_t endIndex) { - uint64_t offset = beginIndex * maxBytesPerLeaf; - uint64_t count = endIndex * maxBytesPerLeaf - offset; - Data data(count); - data.FillWithZeroes(); - tree->writeBytes(data.data(), offset, count); - } - - void TraverseByReading(DataTree *tree, uint64_t beginIndex, uint64_t endIndex) { - uint64_t offset = beginIndex * maxBytesPerLeaf; - uint64_t count = endIndex * maxBytesPerLeaf - offset; - Data data(count); - tree->readBytes(data.data(), offset, count); - } - - uint64_t maxChildrenPerInnerNode = nodeStore->layout().maxChildrenPerInnerNode(); - uint64_t maxBytesPerLeaf = nodeStore->layout().maxBytesPerLeaf(); -}; - -TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByTree) { - auto blockId = CreateFullTwoLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - treeStore.remove(std::move(tree)); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Twolevel_DeleteByKey) { - auto blockId = CreateFullTwoLevel()->blockId(); - blockStore->resetCounters(); - - treeStore.remove(blockId); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByTree) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - treeStore.remove(std::move(tree)); - - EXPECT_EQ(maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(1u + maxChildrenPerInnerNode + maxChildrenPerInnerNode*maxChildrenPerInnerNode, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, DeletingDoesntLoadLeaves_Threelevel_DeleteByKey) { - auto blockId = CreateFullThreeLevel()->blockId(); - blockStore->resetCounters(); - - treeStore.remove(blockId); - - EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(1u + maxChildrenPerInnerNode + maxChildrenPerInnerNode*maxChildrenPerInnerNode, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All_ByWriting) { - auto blockId = CreateFullTwoLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 0, maxChildrenPerInnerNode); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Has to load the rightmost leaf once to adapt its size, rest of the leaves aren't loaded but just overwritten - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(maxChildrenPerInnerNode, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_All_ByReading) { - auto blockId = CreateFullTwoLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByReading(tree.get(), 0, maxChildrenPerInnerNode); - - EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Has to read the rightmost leaf an additional time in the beginning to determine size. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some_ByWriting) { - auto blockId = CreateFullTwoLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 3, 5); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Twolevel_Some_ByReading) { - auto blockId = CreateFullTwoLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByReading(tree.get(), 3, 5); - - EXPECT_EQ(3u, blockStore->loadedBlocks().size()); // reads 2 leaves and the rightmost leaf to determine size - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All_ByWriting) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 0, maxChildrenPerInnerNode * maxChildrenPerInnerNode); - - EXPECT_EQ(maxChildrenPerInnerNode + 1, blockStore->loadedBlocks().size()); // Loads inner nodes and has to load the rightmost leaf once to adapt its size, rest of the leaves aren't loaded but just overwritten. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(maxChildrenPerInnerNode*maxChildrenPerInnerNode, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_All_ByReading) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByReading(tree.get(), 0, maxChildrenPerInnerNode * maxChildrenPerInnerNode); - - EXPECT_EQ(maxChildrenPerInnerNode*maxChildrenPerInnerNode + maxChildrenPerInnerNode + 2, blockStore->loadedBlocks().size()); // Loads inner nodes and leaves. Has to load the rightmost inner node and leaf an additional time at the beginning to compute size - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner_ByWriting) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 3, 5); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads inner node. Doesn't load the leaves, they're just overwritten. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InOneInner_ByReading) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByReading(tree.get(), 3, 5); - - EXPECT_EQ(5u, blockStore->loadedBlocks().size()); // reads 2 leaves and the inner node, also has to read the rightmost inner node and leaf additionally at the beginning to determine size - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner_ByWriting) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 3, 3 + maxChildrenPerInnerNode); - - EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Loads both inner node - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(maxChildrenPerInnerNode, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_InTwoInner_ByReading) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByReading(tree.get(), 3, 3 + maxChildrenPerInnerNode); - - EXPECT_EQ(4u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads both inner nodes and the requested leaves. Also has to load rightmost inner node and leaf additionally in the beginning to determine size. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner_ByWriting) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), maxChildrenPerInnerNode, 2*maxChildrenPerInnerNode); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads inner node. Doesn't load the leaves, they're just overwritten. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(maxChildrenPerInnerNode, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_Threelevel_WholeInner_ByReading) { - auto blockId = CreateFullThreeLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByReading(tree.get(), maxChildrenPerInnerNode, 2*maxChildrenPerInnerNode); - - EXPECT_EQ(3u + maxChildrenPerInnerNode, blockStore->loadedBlocks().size()); // Loads inner node and all requested leaves. Also has to load rightmost inner node and leaf additionally in the beginning to determine size. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingInside) { - auto blockId = CreateInner({CreateLeaf(), CreateLeaf()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 1, 4); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old child (for growing it) - EXPECT_EQ(2u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // write the data and add children to inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_TwoLevel) { - auto blockId = CreateInner({CreateLeaf(), CreateLeaf()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 4, 5); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it - EXPECT_EQ(3u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add child to inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingOutside_ThreeLevel) { - auto blockId = CreateInner({CreateFullTwoLevel(), CreateFullTwoLevel()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 2*maxChildrenPerInnerNode+1, 2*maxChildrenPerInnerNode+2); - - EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Loads last old leaf (and its inner node) for growing it - EXPECT_EQ(3u, blockStore->createdBlocks()); // inner node and two leaves - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add children to existing inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTree_StartingAtBeginOfChild) { - auto blockId = CreateInner({CreateFullTwoLevel(), CreateFullTwoLevel()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), maxChildrenPerInnerNode, 3*maxChildrenPerInnerNode); - - EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Loads inner node and one leaf to check whether we have to grow it. Doesn't load the leaves, but returns the keys of the leaves to the callback. - EXPECT_EQ(1u + maxChildrenPerInnerNode, blockStore->createdBlocks()); // Creates an inner node and its leaves - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(maxChildrenPerInnerNode + 1u, blockStore->distinctWrittenBlocks().size()); // write data and add children to existing inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth) { - auto blockId = CreateInner({CreateLeaf(), CreateLeaf()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 4, maxChildrenPerInnerNode+2); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it - EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // Add children to existing inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInOldDepth_ResizeLastLeaf) { - auto blockId = CreateInner({CreateLeaf(), CreateLeafWithSize(5)})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), 4, maxChildrenPerInnerNode+2); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it - EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // Resize last leaf and add children to existing inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth) { - auto blockId = CreateInner({CreateLeaf(), CreateLeaf()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), maxChildrenPerInnerNode, maxChildrenPerInnerNode+2); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it - EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // Add children to existing inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, TraverseLeaves_GrowingTreeDepth_StartingInNewDepth_ResizeLastLeaf) { - auto blockId = CreateInner({CreateLeaf(), CreateLeafWithSize(5)})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - TraverseByWriting(tree.get(), maxChildrenPerInnerNode, maxChildrenPerInnerNode+2); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // Loads last old leaf for growing it - EXPECT_EQ(2u + maxChildrenPerInnerNode, blockStore->createdBlocks()); // 2x new inner node + leaves - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // Resize last leaf and add children to existing inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_ZeroToZero) { - auto blockId = CreateLeafWithSize(0)->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(0); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(0u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_GrowOneLeaf) { - auto blockId = CreateLeafWithSize(0)->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(5); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_ShrinkOneLeaf) { - auto blockId = CreateLeafWithSize(5)->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(2); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_ShrinkOneLeafToZero) { - auto blockId = CreateLeafWithSize(5)->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(0); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_GrowOneLeafInLargerTree) { - auto blockId = CreateInner({CreateFullTwoLevel(), CreateInner({CreateLeaf(), CreateLeafWithSize(5)})})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf*(maxChildrenPerInnerNode+1)+6); // Grow by one byte - - EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // Load inner node and leaf - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_GrowByOneLeaf) { - auto blockId = CreateInner({CreateLeaf(), CreateLeaf()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf*2+1); // Grow by one byte - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); - EXPECT_EQ(1u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // add child to inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_GrowByOneLeaf_GrowLastLeaf) { - auto blockId = CreateInner({CreateLeaf(), CreateLeafWithSize(5)})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf*2+1); // Grow by one byte - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); - EXPECT_EQ(1u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // add child to inner node and resize old last leaf - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_ShrinkByOneLeaf) { - auto blockId = CreateInner({CreateLeaf(), CreateLeaf(), CreateLeaf()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(2*maxBytesPerLeaf-1); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(1u, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // resize new last leaf and remove leaf from inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_IncreaseTreeDepth_0to1) { - auto blockId = CreateLeaf()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf+1); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(2u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // rewrite root node to be an inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_IncreaseTreeDepth_1to2) { - auto blockId = CreateFullTwoLevel()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf*maxChildrenPerInnerNode+1); - - EXPECT_EQ(1u, blockStore->loadedBlocks().size()); // check whether we have to grow last leaf - EXPECT_EQ(3u, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // rewrite root node to be an inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_IncreaseTreeDepth_0to2) { - auto blockId = CreateLeaf()->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf*maxChildrenPerInnerNode+1); - - EXPECT_EQ(0u, blockStore->loadedBlocks().size()); - EXPECT_EQ(3u + maxChildrenPerInnerNode, blockStore->createdBlocks()); - EXPECT_EQ(0u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // rewrite root node to be an inner node - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_DecreaseTreeDepth_1to0) { - auto blockId = CreateInner({CreateLeaf(), CreateLeaf()})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf); - - EXPECT_EQ(2u, blockStore->loadedBlocks().size()); // read content of first leaf and load first leaf to replace root with it - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(2u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // rewrite root node to be a leaf - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_DecreaseTreeDepth_2to1) { - auto blockId = CreateInner({CreateFullTwoLevel(), CreateInner({CreateLeaf()})})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf*maxChildrenPerInnerNode); - - EXPECT_EQ(4u, blockStore->loadedBlocks().size()); // load new last leaf (+inner node), load second inner node to remove its subtree, then load first child of root to replace root with its child. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(3u, blockStore->removedBlocks().size()); - EXPECT_EQ(1u, blockStore->distinctWrittenBlocks().size()); // rewrite root node to be a leaf - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} - -TEST_F(DataTreeTest_Performance, ResizeNumBytes_DecreaseTreeDepth_2to0) { - auto blockId = CreateInner({CreateFullTwoLevel(), CreateInner({CreateLeaf()})})->blockId(); - auto tree = treeStore.load(blockId).value(); - blockStore->resetCounters(); - - tree->resizeNumBytes(maxBytesPerLeaf); - - EXPECT_EQ(5u, blockStore->loadedBlocks().size()); // load new last leaf (+inner node), load second inner node to remove its subtree, then 2x load first child of root to replace root with its child. - EXPECT_EQ(0u, blockStore->createdBlocks()); - EXPECT_EQ(3u + maxChildrenPerInnerNode, blockStore->removedBlocks().size()); - EXPECT_EQ(2u, blockStore->distinctWrittenBlocks().size()); // remove children from inner node and rewrite root node to be a leaf - EXPECT_EQ(0u, blockStore->resizedBlocks().size()); -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp deleted file mode 100644 index 26f8b9bf..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeByTraversing.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include "testutils/DataTreeTest.h" -#include "testutils/TwoLevelDataFixture.h" -#include "blobstore/implementations/onblocks/utils/Math.h" -#include - -#include - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Combine; -using std::tuple; -using std::get; -using std::function; -using std::mem_fn; -using cpputils::dynamic_pointer_move; - -using blobstore::onblocks::datanodestore::DataLeafNode; -using blobstore::onblocks::datanodestore::DataInnerNode; -using blobstore::onblocks::datanodestore::DataNode; -using blobstore::onblocks::datanodestore::DataNodeLayout; -using blobstore::onblocks::datatreestore::DataTree; -using blobstore::onblocks::utils::ceilDivision; -using blockstore::BlockId; -using cpputils::Data; -using boost::none; - -using cpputils::unique_ref; - -class DataTreeTest_ResizeByTraversing: public DataTreeTest { -public: - static constexpr DataNodeLayout LAYOUT = DataNodeLayout(BLOCKSIZE_BYTES); - - unique_ref CreateTree(unique_ref root) { - BlockId blockId = root->blockId(); - cpputils::destruct(std::move(root)); - return treeStore.load(blockId).value(); - } - - unique_ref CreateLeafTreeWithSize(uint32_t size) { - return CreateTree(CreateLeafWithSize(size)); - } - - unique_ref CreateTwoLeafTreeWithSecondLeafSize(uint32_t size) { - return CreateTree(CreateTwoLeafWithSecondLeafSize(size)); - } - - unique_ref CreateFullTwoLevelTreeWithLastLeafSize(uint32_t size) { - return CreateTree(CreateFullTwoLevelWithLastLeafSize(size)); - } - - unique_ref CreateThreeLevelTreeWithTwoChildrenAndLastLeafSize(uint32_t size) { - return CreateTree(CreateThreeLevelWithTwoChildrenAndLastLeafSize(size)); - } - - unique_ref CreateThreeLevelTreeWithThreeChildrenAndLastLeafSize(uint32_t size) { - return CreateTree(CreateThreeLevelWithThreeChildrenAndLastLeafSize(size)); - } - - unique_ref CreateFullThreeLevelTreeWithLastLeafSize(uint32_t size) { - return CreateTree(CreateFullThreeLevelWithLastLeafSize(size)); - } - - unique_ref CreateFourLevelMinDataTreeWithLastLeafSize(uint32_t size) { - return CreateTree(CreateFourLevelMinDataWithLastLeafSize(size)); - } - - // NOLINTNEXTLINE(misc-no-recursion) - void EXPECT_IS_LEFTMAXDATA_TREE(const BlockId &blockId) { - auto root = nodeStore->load(blockId).value(); - DataInnerNode *inner = dynamic_cast(root.get()); - if (inner != nullptr) { - for (uint32_t i = 0; i < inner->numChildren()-1; ++i) { - EXPECT_IS_MAXDATA_TREE(inner->readChild(i).blockId()); - } - EXPECT_IS_LEFTMAXDATA_TREE(inner->readLastChild().blockId()); - } - } - - // NOLINTNEXTLINE(misc-no-recursion) - void EXPECT_IS_MAXDATA_TREE(const BlockId &blockId) { - auto root = nodeStore->load(blockId).value(); - DataInnerNode *inner = dynamic_cast(root.get()); - if (inner != nullptr) { - for (uint32_t i = 0; i < inner->numChildren(); ++i) { - EXPECT_IS_MAXDATA_TREE(inner->readChild(i).blockId()); - } - } else { - DataLeafNode *leaf = dynamic_cast(root.get()); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf->numBytes()); - } - } -}; -constexpr DataNodeLayout DataTreeTest_ResizeByTraversing::LAYOUT; - -class DataTreeTest_ResizeByTraversing_P: public DataTreeTest_ResizeByTraversing, public WithParamInterface(DataTreeTest_ResizeByTraversing*, uint32_t)>, uint32_t, uint32_t, std::function>> { -public: - DataTreeTest_ResizeByTraversing_P() - : oldLastLeafSize(get<1>(GetParam())), - tree(get<0>(GetParam())(this, oldLastLeafSize)), - numberOfLeavesToAdd(get<2>(GetParam())), - newNumberOfLeaves(tree->numLeaves()+numberOfLeavesToAdd), - traversalBeginIndex(get<3>(GetParam())(tree->numLeaves(), newNumberOfLeaves)), - ZEROES(LAYOUT.maxBytesPerLeaf()) - { - ZEROES.FillWithZeroes(); - } - - void GrowTree(const BlockId &blockId) { - auto tree = treeStore.load(blockId); - GrowTree(tree.get().get()); - } - - void GrowTree(DataTree *tree) { - uint64_t maxBytesPerLeaf = tree->maxBytesPerLeaf(); - uint64_t offset = traversalBeginIndex * maxBytesPerLeaf; - uint64_t count = newNumberOfLeaves * maxBytesPerLeaf - offset; - Data data(count); - data.FillWithZeroes(); - tree->writeBytes(data.data(), offset, count); - tree->flush(); - } - - // NOLINTNEXTLINE(misc-no-recursion) - unique_ref LastLeaf(const BlockId &blockId) { - auto root = nodeStore->load(blockId).value(); - auto leaf = dynamic_pointer_move(root); - if (leaf != none) { - return std::move(*leaf); - } - auto inner = dynamic_pointer_move(root).value(); - return LastLeaf(inner->readLastChild().blockId()); - } - - uint32_t oldLastLeafSize; - unique_ref tree; - uint32_t numberOfLeavesToAdd; - uint32_t newNumberOfLeaves; - uint32_t traversalBeginIndex; - Data ZEROES; -}; -INSTANTIATE_TEST_SUITE_P(DataTreeTest_ResizeByTraversing_P, DataTreeTest_ResizeByTraversing_P, - Combine( - //Tree we're starting with - Values(DataTreeTest_ResizeByTraversing*, uint32_t)>>( - mem_fn(&DataTreeTest_ResizeByTraversing::CreateLeafTreeWithSize), - mem_fn(&DataTreeTest_ResizeByTraversing::CreateTwoLeafTreeWithSecondLeafSize), - mem_fn(&DataTreeTest_ResizeByTraversing::CreateFullTwoLevelTreeWithLastLeafSize), - mem_fn(&DataTreeTest_ResizeByTraversing::CreateThreeLevelTreeWithTwoChildrenAndLastLeafSize), - mem_fn(&DataTreeTest_ResizeByTraversing::CreateThreeLevelTreeWithThreeChildrenAndLastLeafSize), - mem_fn(&DataTreeTest_ResizeByTraversing::CreateFullThreeLevelTreeWithLastLeafSize), - mem_fn(&DataTreeTest_ResizeByTraversing::CreateFourLevelMinDataTreeWithLastLeafSize) - ), - //Last leaf size of the start tree - Values( - 0u, - 1u, - 10u, - DataTreeTest_ResizeByTraversing::LAYOUT.maxBytesPerLeaf() - ), - //Number of leaves we're adding - Values( - 1u, - 2u, - DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode(), //Full two level tree - 2* DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode(), //Three level tree with two children - 3* DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode(), //Three level tree with three children - DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode() * DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode(), //Full three level tree - DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode() * DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode() + 1 //Four level mindata tree - ), - //Decide the traversal begin index - Values( - [] (uint32_t /*oldNumberOfLeaves*/, uint32_t newNumberOfLeaves) {return newNumberOfLeaves-1;}, // Traverse last leaf (begin==end-1) - [] (uint32_t oldNumberOfLeaves, uint32_t newNumberOfLeaves) {return (oldNumberOfLeaves+newNumberOfLeaves)/2;}, // Start traversal in middle of new leaves - [] (uint32_t oldNumberOfLeaves, uint32_t /*newNumberOfLeaves*/) {return oldNumberOfLeaves-1;}, // Start traversal with last old leaf - [] (uint32_t oldNumberOfLeaves, uint32_t /*newNumberOfLeaves*/) {return oldNumberOfLeaves;}, // Start traversal with first new leaf - [] (uint32_t /*oldNumberOfLeaves*/, uint32_t /*newNumberOfLeaves*/) {return 0;}, // Traverse full tree - [] (uint32_t /*oldNumberOfLeaves*/, uint32_t /*newNumberOfLeaves*/) {return 1;} // Traverse full tree except first leaf - ) - ) -); - -TEST_P(DataTreeTest_ResizeByTraversing_P, StructureIsValid) { - GrowTree(tree.get()); - EXPECT_IS_LEFTMAXDATA_TREE(tree->blockId()); -} - -TEST_P(DataTreeTest_ResizeByTraversing_P, NumLeavesIsCorrect_FromCache) { - tree->numLeaves(); // fill cache with old value - GrowTree(tree.get()); - // tree->numLeaves() only goes down the right border nodes and expects the tree to be a left max data tree. - // This is what the StructureIsValid test case is for. - EXPECT_EQ(newNumberOfLeaves, tree->numLeaves()); -} - -TEST_P(DataTreeTest_ResizeByTraversing_P, NumLeavesIsCorrect) { - GrowTree(tree.get()); - // tree->forceComputeNumLeaves() only goes down the right border nodes and expects the tree to be a left max data tree. - // This is what the StructureIsValid test case is for. - EXPECT_EQ(newNumberOfLeaves, tree->forceComputeNumLeaves()); -} - -TEST_P(DataTreeTest_ResizeByTraversing_P, DepthFlagsAreCorrect) { - GrowTree(tree.get()); - uint32_t depth = ceil(log(newNumberOfLeaves)/log(DataTreeTest_ResizeByTraversing::LAYOUT.maxChildrenPerInnerNode())); - CHECK_DEPTH(depth, tree->blockId()); -} - -TEST_P(DataTreeTest_ResizeByTraversing_P, KeyDoesntChange) { - BlockId blockId = tree->blockId(); - tree->flush(); - GrowTree(tree.get()); - EXPECT_EQ(blockId, tree->blockId()); -} - -TEST_P(DataTreeTest_ResizeByTraversing_P, DataStaysIntact) { - uint32_t oldNumberOfLeaves = std::max(UINT64_C(1), ceilDivision(tree->numBytes(), static_cast(nodeStore->layout().maxBytesPerLeaf()))); - - TwoLevelDataFixture data(nodeStore, TwoLevelDataFixture::SizePolicy::Unchanged); - BlockId blockId = tree->blockId(); - cpputils::destruct(std::move(tree)); - data.FillInto(nodeStore->load(blockId).get().get()); - - GrowTree(blockId); - - if (traversalBeginIndex < oldNumberOfLeaves) { - // Traversal wrote over part of the pre-existing data, we can only check the data before it. - if (traversalBeginIndex != 0) { - data.EXPECT_DATA_CORRECT(nodeStore->load(blockId).get().get(), static_cast(traversalBeginIndex - 1)); - } - } else { - // Here, traversal was entirely outside the preexisting data, we can check all preexisting data. - data.EXPECT_DATA_CORRECT(nodeStore->load(blockId).get().get(), oldNumberOfLeaves, oldLastLeafSize); - } -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeNumBytes.cpp b/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeNumBytes.cpp deleted file mode 100644 index a3d4e763..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/DataTreeTest_ResizeNumBytes.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include "testutils/DataTreeTest.h" -#include "testutils/TwoLevelDataFixture.h" -#include "blobstore/implementations/onblocks/utils/Math.h" -#include - -#include - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Combine; -using std::tuple; -using std::get; -using std::function; -using std::mem_fn; -using cpputils::dynamic_pointer_move; - -using blobstore::onblocks::datanodestore::DataLeafNode; -using blobstore::onblocks::datanodestore::DataInnerNode; -using blobstore::onblocks::datanodestore::DataNode; -using blobstore::onblocks::datanodestore::DataNodeLayout; -using blobstore::onblocks::datatreestore::DataTree; -using blobstore::onblocks::utils::ceilDivision; -using blockstore::BlockId; -using cpputils::Data; -using boost::none; - -using cpputils::unique_ref; - -class DataTreeTest_ResizeNumBytes: public DataTreeTest { -public: - static constexpr DataNodeLayout LAYOUT = DataNodeLayout(BLOCKSIZE_BYTES); - - unique_ref CreateTree(unique_ref root) { - BlockId blockId = root->blockId(); - cpputils::destruct(std::move(root)); - return treeStore.load(blockId).value(); - } - - unique_ref CreateLeafTreeWithSize(uint32_t size) { - return CreateTree(CreateLeafWithSize(size)); - } - - unique_ref CreateTwoLeafTreeWithSecondLeafSize(uint32_t size) { - return CreateTree(CreateTwoLeafWithSecondLeafSize(size)); - } - - unique_ref CreateFullTwoLevelTreeWithLastLeafSize(uint32_t size) { - return CreateTree(CreateFullTwoLevelWithLastLeafSize(size)); - } - - unique_ref CreateThreeLevelTreeWithTwoChildrenAndLastLeafSize(uint32_t size) { - return CreateTree(CreateThreeLevelWithTwoChildrenAndLastLeafSize(size)); - } - - unique_ref CreateThreeLevelTreeWithThreeChildrenAndLastLeafSize(uint32_t size) { - return CreateTree(CreateThreeLevelWithThreeChildrenAndLastLeafSize(size)); - } - - unique_ref CreateFullThreeLevelTreeWithLastLeafSize(uint32_t size) { - return CreateTree(CreateFullThreeLevelWithLastLeafSize(size)); - } - - unique_ref CreateFourLevelMinDataTreeWithLastLeafSize(uint32_t size) { - return CreateTree(CreateFourLevelMinDataWithLastLeafSize(size)); - } - - // NOLINTNEXTLINE(misc-no-recursion) - void EXPECT_IS_LEFTMAXDATA_TREE(const BlockId &blockId) { - auto root = nodeStore->load(blockId).value(); - DataInnerNode *inner = dynamic_cast(root.get()); - if (inner != nullptr) { - for (uint32_t i = 0; i < inner->numChildren()-1; ++i) { - EXPECT_IS_MAXDATA_TREE(inner->readChild(i).blockId()); - } - EXPECT_IS_LEFTMAXDATA_TREE(inner->readLastChild().blockId()); - } - } - - // NOLINTNEXTLINE(misc-no-recursion) - void EXPECT_IS_MAXDATA_TREE(const BlockId &blockId) { - auto root = nodeStore->load(blockId).value(); - DataInnerNode *inner = dynamic_cast(root.get()); - if (inner != nullptr) { - for (uint32_t i = 0; i < inner->numChildren(); ++i) { - EXPECT_IS_MAXDATA_TREE(inner->readChild(i).blockId()); - } - } else { - DataLeafNode *leaf = dynamic_cast(root.get()); - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf->numBytes()); - } - } -}; -constexpr DataNodeLayout DataTreeTest_ResizeNumBytes::LAYOUT; - -class DataTreeTest_ResizeNumBytes_P: public DataTreeTest_ResizeNumBytes, public WithParamInterface(DataTreeTest_ResizeNumBytes*, uint32_t)>, uint32_t, uint32_t, uint32_t>> { -public: - DataTreeTest_ResizeNumBytes_P() - : oldLastLeafSize(get<1>(GetParam())), - tree(get<0>(GetParam())(this, oldLastLeafSize)), - newNumberOfLeaves(get<2>(GetParam())), - newLastLeafSize(get<3>(GetParam())), - newSize((newNumberOfLeaves-1) * LAYOUT.maxBytesPerLeaf() + newLastLeafSize), - ZEROES(LAYOUT.maxBytesPerLeaf()) - { - ZEROES.FillWithZeroes(); - } - - void ResizeTree(const BlockId &blockId, uint64_t size) { - treeStore.load(blockId).get()->resizeNumBytes(size); - } - - // NOLINTNEXTLINE(misc-no-recursion) - unique_ref LastLeaf(const BlockId &blockId) { - auto root = nodeStore->load(blockId).value(); - auto leaf = dynamic_pointer_move(root); - if (leaf != none) { - return std::move(*leaf); - } - auto inner = dynamic_pointer_move(root).value(); - return LastLeaf(inner->readLastChild().blockId()); - } - - uint32_t oldLastLeafSize; - unique_ref tree; - uint32_t newNumberOfLeaves; - uint32_t newLastLeafSize; - uint64_t newSize; - Data ZEROES; -}; -INSTANTIATE_TEST_SUITE_P(DataTreeTest_ResizeNumBytes_P, DataTreeTest_ResizeNumBytes_P, - Combine( - //Tree we're starting with - Values(DataTreeTest_ResizeNumBytes*, uint32_t)>>( - mem_fn(&DataTreeTest_ResizeNumBytes::CreateLeafTreeWithSize), - mem_fn(&DataTreeTest_ResizeNumBytes::CreateTwoLeafTreeWithSecondLeafSize), - mem_fn(&DataTreeTest_ResizeNumBytes::CreateFullTwoLevelTreeWithLastLeafSize), - mem_fn(&DataTreeTest_ResizeNumBytes::CreateThreeLevelTreeWithTwoChildrenAndLastLeafSize), - mem_fn(&DataTreeTest_ResizeNumBytes::CreateThreeLevelTreeWithThreeChildrenAndLastLeafSize), - mem_fn(&DataTreeTest_ResizeNumBytes::CreateFullThreeLevelTreeWithLastLeafSize), - mem_fn(&DataTreeTest_ResizeNumBytes::CreateFourLevelMinDataTreeWithLastLeafSize) - ), - //Last leaf size of the start tree - Values( - 0u, - 1u, - 10u, - DataTreeTest_ResizeNumBytes::LAYOUT.maxBytesPerLeaf() - ), - //Number of leaves we're resizing to - Values( - 1u, - 2u, - DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode(), //Full two level tree - 2* DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode(), //Three level tree with two children - 3* DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode(), //Three level tree with three children - DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode() * DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode(), //Full three level tree - DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode() * DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode() + 1 //Four level mindata tree - ), - //Last leaf size of the resized tree - Values( - 1u, - 10u, - DataTreeTest_ResizeNumBytes::LAYOUT.maxBytesPerLeaf() - ) - ) -); - -TEST_P(DataTreeTest_ResizeNumBytes_P, StructureIsValid) { - tree->resizeNumBytes(newSize); - tree->flush(); - EXPECT_IS_LEFTMAXDATA_TREE(tree->blockId()); -} - -TEST_P(DataTreeTest_ResizeNumBytes_P, NumBytesIsCorrect) { - tree->resizeNumBytes(newSize); - tree->flush(); - // tree->numBytes() only goes down the right border nodes and expects the tree to be a left max data tree. - // This is what the StructureIsValid test case is for. - EXPECT_EQ(newSize, tree->numBytes()); -} - -TEST_P(DataTreeTest_ResizeNumBytes_P, NumLeavesIsCorrect) { - tree->resizeNumBytes(newSize); - tree->flush(); - // tree->numLeaves() only goes down the right border nodes and expects the tree to be a left max data tree. - // This is what the StructureIsValid test case is for. - EXPECT_EQ(newNumberOfLeaves, tree->forceComputeNumLeaves()); -} - -TEST_P(DataTreeTest_ResizeNumBytes_P, NumLeavesIsCorrect_FromCache) { - tree->numLeaves(); // fill cache with old value - tree->resizeNumBytes(newSize); - tree->flush(); - // tree->numLeaves() only goes down the right border nodes and expects the tree to be a left max data tree. - // This is what the StructureIsValid test case is for. - EXPECT_EQ(newNumberOfLeaves, tree->numLeaves()); -} - -TEST_P(DataTreeTest_ResizeNumBytes_P, DepthFlagsAreCorrect) { - tree->resizeNumBytes(newSize); - tree->flush(); - uint32_t depth = ceil(log(newNumberOfLeaves)/log(DataTreeTest_ResizeNumBytes::LAYOUT.maxChildrenPerInnerNode()) - 0.00000000001); // The subtraction takes care of double inaccuracies if newNumberOfLeaves == maxChildrenPerInnerNode - CHECK_DEPTH(depth, tree->blockId()); -} - -TEST_P(DataTreeTest_ResizeNumBytes_P, KeyDoesntChange) { - BlockId blockId = tree->blockId(); - tree->flush(); - tree->resizeNumBytes(newSize); - EXPECT_EQ(blockId, tree->blockId()); -} - -TEST_P(DataTreeTest_ResizeNumBytes_P, DataStaysIntact) { - uint32_t oldNumberOfLeaves = std::max(UINT64_C(1), ceilDivision(tree->numBytes(), static_cast(nodeStore->layout().maxBytesPerLeaf()))); - TwoLevelDataFixture data(nodeStore, TwoLevelDataFixture::SizePolicy::Unchanged); - BlockId blockId = tree->blockId(); - cpputils::destruct(std::move(tree)); - data.FillInto(nodeStore->load(blockId).get().get()); - - ResizeTree(blockId, newSize); - - if (oldNumberOfLeaves < newNumberOfLeaves || (oldNumberOfLeaves == newNumberOfLeaves && oldLastLeafSize < newLastLeafSize)) { - data.EXPECT_DATA_CORRECT(nodeStore->load(blockId).get().get(), oldNumberOfLeaves, oldLastLeafSize); - } else { - data.EXPECT_DATA_CORRECT(nodeStore->load(blockId).get().get(), newNumberOfLeaves, newLastLeafSize); - } -} - -TEST_P(DataTreeTest_ResizeNumBytes_P, UnneededBlocksGetDeletedWhenShrinking) { - tree->resizeNumBytes(newSize); - tree->flush(); - - uint64_t expectedNumNodes = 1; // 1 for the root node - uint64_t nodesOnCurrentLevel = newNumberOfLeaves; - while (nodesOnCurrentLevel > 1) { - expectedNumNodes += nodesOnCurrentLevel; - nodesOnCurrentLevel = ceilDivision(nodesOnCurrentLevel, nodeStore->layout().maxChildrenPerInnerNode()); - } - EXPECT_EQ(expectedNumNodes, nodeStore->numNodes()); -} - -//Resize to zero is not caught in the parametrized test above, in the following, we test it separately. - -TEST_F(DataTreeTest_ResizeNumBytes, ResizeToZero_NumBytesIsCorrect) { - auto tree = CreateThreeLevelTreeWithThreeChildrenAndLastLeafSize(10u); - tree->resizeNumBytes(0); - BlockId blockId = tree->blockId(); - cpputils::destruct(std::move(tree)); - auto leaf = LoadLeafNode(blockId); - EXPECT_EQ(0u, leaf->numBytes()); -} - -TEST_F(DataTreeTest_ResizeNumBytes, ResizeToZero_blockIdDoesntChange) { - auto tree = CreateThreeLevelTreeWithThreeChildrenAndLastLeafSize(10u); - BlockId blockId = tree->blockId(); - tree->resizeNumBytes(0); - tree->flush(); - EXPECT_EQ(blockId, tree->blockId()); -} - -TEST_F(DataTreeTest_ResizeNumBytes, ResizeToZero_UnneededBlocksGetDeletedWhenShrinking) { - auto tree = CreateThreeLevelTreeWithThreeChildrenAndLastLeafSize(10u); - tree->resizeNumBytes(0); - tree->flush(); - EXPECT_EQ(1u, nodeStore->numNodes()); -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/LeafTraverserTest.cpp b/test/blobstore/implementations/onblocks/datatreestore/LeafTraverserTest.cpp deleted file mode 100644 index 966e3d53..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/LeafTraverserTest.cpp +++ /dev/null @@ -1,449 +0,0 @@ -#include "testutils/DataTreeTest.h" -#include -#include - -using ::testing::Invoke; -using ::testing::Eq; - -using blobstore::onblocks::datanodestore::DataLeafNode; -using blobstore::onblocks::datanodestore::DataInnerNode; -using blobstore::onblocks::datanodestore::DataNode; -using blobstore::onblocks::datatreestore::LeafHandle; -using blobstore::onblocks::datatreestore::LeafTraverser; -using blockstore::BlockId; - -using cpputils::unique_ref; -using cpputils::Data; -using std::shared_ptr; -using std::make_shared; - -class TraversorMock { -public: - MOCK_METHOD(void, calledExistingLeaf, (DataLeafNode*, bool, uint32_t)); - MOCK_METHOD(shared_ptr, calledCreateLeaf, (uint32_t)); -}; - -MATCHER_P(KeyEq, expected, "node blockId equals") { - return arg->blockId() == expected; -} - -class LeafTraverserTest: public DataTreeTest { -public: - LeafTraverserTest() :traversor() {} - - unique_ref CreateThreeLevel() { - return CreateInner({ - CreateFullTwoLevel(), - CreateFullTwoLevel(), - CreateFullTwoLevel(), - CreateFullTwoLevel(), - CreateFullTwoLevel(), - CreateInner({CreateLeaf(), CreateLeaf(), CreateLeaf()})}); - } - - unique_ref CreateFourLevel() { - return CreateInner({ - CreateFullThreeLevel(), - CreateFullThreeLevel(), - CreateInner({CreateFullTwoLevel(), CreateInner({CreateLeaf()})}) - }); - } - - void EXPECT_CREATE_LEAF(uint32_t leafIndex) { - uint64_t maxBytesPerLeaf = nodeStore->layout().maxBytesPerLeaf(); - EXPECT_CALL(traversor, calledCreateLeaf(Eq(leafIndex))).Times(1).WillOnce(Invoke([maxBytesPerLeaf] (uint32_t) { - return make_shared(maxBytesPerLeaf); - })); - } - - void EXPECT_TRAVERSE_LEAF(const BlockId &blockId, bool isRightBorderLeaf, uint32_t leafIndex) { - EXPECT_CALL(traversor, calledExistingLeaf(KeyEq(blockId), isRightBorderLeaf, leafIndex)).Times(1); - } - - void EXPECT_TRAVERSE_ALL_CHILDREN_OF(const DataInnerNode &node, bool isRightBorderNode, uint32_t firstLeafIndex) { - for (unsigned int i = 0; i < node.numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(node.readChild(i).blockId(), isRightBorderNode && i == node.numChildren()-1, firstLeafIndex+i); - } - } - - void EXPECT_DONT_TRAVERSE_ANY_LEAVES() { - EXPECT_CALL(traversor, calledExistingLeaf(testing::_, testing::_, testing::_)).Times(0); - EXPECT_CALL(traversor, calledCreateLeaf(testing::_)).Times(0); - } - - void TraverseLeaves(unique_ref root, uint32_t beginIndex, uint32_t endIndex, bool expectReadOnly) { - root->flush(); - auto tree = treeStore.load(root->blockId()).value(); - auto* old_root = root.get(); - LeafTraverser(nodeStore, expectReadOnly).traverseAndUpdateRoot(&root, beginIndex, endIndex, [this] (uint32_t nodeIndex, bool isRightBorderNode,LeafHandle leaf) { - traversor.calledExistingLeaf(leaf.node(), isRightBorderNode, nodeIndex); - }, [this] (uint32_t nodeIndex) -> Data { - return traversor.calledCreateLeaf(nodeIndex)->copy(); - }, [] (auto) {}); - if (expectReadOnly) { - EXPECT_EQ(old_root, root.get()); - } else { - EXPECT_NE(old_root, root.get()); - } - } - - TraversorMock traversor; -}; - -TEST_F(LeafTraverserTest, TraverseSingleLeafTree) { - unique_ref root = CreateLeaf(); - EXPECT_TRAVERSE_LEAF(root->blockId(), true, 0); - - TraverseLeaves(std::move(root), 0, 1, true); -} - -TEST_F(LeafTraverserTest, TraverseNothingInSingleLeafTree1) { - unique_ref root = CreateLeaf(); - EXPECT_DONT_TRAVERSE_ANY_LEAVES(); - - TraverseLeaves(std::move(root), 0, 0, true); -} - -TEST_F(LeafTraverserTest, TraverseNothingInSingleLeafTree2) { - unique_ref root = CreateLeaf(); - EXPECT_DONT_TRAVERSE_ANY_LEAVES(); - - TraverseLeaves(std::move(root), 1, 1, true); -} - -TEST_F(LeafTraverserTest, TraverseFirstLeafOfFullTwolevelTree) { - auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_LEAF(root->readChild(0).blockId(), false, 0); - - TraverseLeaves(std::move(root), 0, 1, true); -} - -TEST_F(LeafTraverserTest, TraverseMiddleLeafOfFullTwolevelTree) { - auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_LEAF(root->readChild(5).blockId(), false, 5); - - TraverseLeaves(std::move(root), 5, 6, true); -} - -TEST_F(LeafTraverserTest, TraverseLastLeafOfFullTwolevelTree) { - auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_LEAF(root->readChild(nodeStore->layout().maxChildrenPerInnerNode()-1).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode()-1); - - TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode()-1, nodeStore->layout().maxChildrenPerInnerNode(), true); -} - -TEST_F(LeafTraverserTest, TraverseNothingInFullTwolevelTree1) { - auto root = CreateFullTwoLevel(); - EXPECT_DONT_TRAVERSE_ANY_LEAVES(); - - TraverseLeaves(std::move(root), 0, 0, true); -} - -TEST_F(LeafTraverserTest, TraverseNothingInFullTwolevelTree2) { - auto root = CreateFullTwoLevel(); - EXPECT_DONT_TRAVERSE_ANY_LEAVES(); - - TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode(), true); -} - -TEST_F(LeafTraverserTest, TraverseFirstLeafOfThreeLevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(0).blockId())->readChild(0).blockId(), false, 0); - - TraverseLeaves(std::move(root), 0, 1, true); -} - -TEST_F(LeafTraverserTest, TraverseMiddleLeafOfThreeLevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(0).blockId())->readChild(5).blockId(), false, 5); - - TraverseLeaves(std::move(root), 5, 6, true); -} - -TEST_F(LeafTraverserTest, TraverseLastLeafOfThreeLevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(1).blockId())->readChild(0).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode()); - - TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode(), nodeStore->layout().maxChildrenPerInnerNode()+1, true); -} - -TEST_F(LeafTraverserTest, TraverseAllLeavesOfFullTwolevelTree) { - auto root = CreateFullTwoLevel(); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*root, true, 0); - - TraverseLeaves(std::move(root), 0, nodeStore->layout().maxChildrenPerInnerNode(), true); -} - -TEST_F(LeafTraverserTest, TraverseAllLeavesOfThreelevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(0).blockId()), false, 0); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(1).blockId())->readChild(0).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode()); - - TraverseLeaves(std::move(root), 0, nodeStore->layout().maxChildrenPerInnerNode()+1, true); -} - -TEST_F(LeafTraverserTest, TraverseFirstChildOfThreelevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(0).blockId()), false, 0); - - TraverseLeaves(std::move(root), 0, nodeStore->layout().maxChildrenPerInnerNode(), true); -} - -TEST_F(LeafTraverserTest, TraverseFirstPartOfFullTwolevelTree) { - auto root = CreateFullTwoLevel(); - for (unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(root->readChild(i).blockId(), false, i); - } - - TraverseLeaves(std::move(root), 0, 5, true); -} - -TEST_F(LeafTraverserTest, TraverseInnerPartOfFullTwolevelTree) { - auto root = CreateFullTwoLevel(); - for (unsigned int i = 5; i < 10; ++i) { - EXPECT_TRAVERSE_LEAF(root->readChild(i).blockId(), false, i); - } - - TraverseLeaves(std::move(root), 5, 10, true); -} - -TEST_F(LeafTraverserTest, TraverseLastPartOfFullTwolevelTree) { - auto root = CreateFullTwoLevel(); - for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(root->readChild(i).blockId(), i==nodeStore->layout().maxChildrenPerInnerNode()-1, i); - } - - TraverseLeaves(std::move(root), 5, nodeStore->layout().maxChildrenPerInnerNode(), true); -} - -TEST_F(LeafTraverserTest, TraverseFirstPartOfThreelevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - auto node = LoadInnerNode(root->readChild(0).blockId()); - for (unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(node->readChild(i).blockId(), false, i); - } - - TraverseLeaves(std::move(root), 0, 5, true); -} - -TEST_F(LeafTraverserTest, TraverseInnerPartOfThreelevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - auto node = LoadInnerNode(root->readChild(0).blockId()); - for (unsigned int i = 5; i < 10; ++i) { - EXPECT_TRAVERSE_LEAF(node->readChild(i).blockId(), false, i); - } - - TraverseLeaves(std::move(root), 5, 10, true); -} - -TEST_F(LeafTraverserTest, TraverseLastPartOfThreelevelMinDataTree) { - auto root = CreateThreeLevelMinData(); - auto node = LoadInnerNode(root->readChild(0).blockId()); - for (unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(node->readChild(i).blockId(), false, i); - } - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(1).blockId())->readChild(0).blockId(), true, nodeStore->layout().maxChildrenPerInnerNode()); - - TraverseLeaves(std::move(root), 5, nodeStore->layout().maxChildrenPerInnerNode()+1, true); -} - -TEST_F(LeafTraverserTest, TraverseFirstLeafOfThreelevelTree) { - auto root = CreateThreeLevel(); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(0).blockId())->readChild(0).blockId(), false, 0); - - TraverseLeaves(std::move(root), 0, 1, true); -} - -TEST_F(LeafTraverserTest, TraverseLastLeafOfThreelevelTree) { - auto root = CreateThreeLevel(); - uint32_t numLeaves = nodeStore->layout().maxChildrenPerInnerNode() * 5 + 3; - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readLastChild().blockId())->readLastChild().blockId(), true, numLeaves-1); - - TraverseLeaves(std::move(root), numLeaves-1, numLeaves, true); -} - -TEST_F(LeafTraverserTest, TraverseMiddleLeafOfThreelevelTree) { - auto root = CreateThreeLevel(); - uint32_t wantedLeafIndex = nodeStore->layout().maxChildrenPerInnerNode() * 2 + 5; - EXPECT_TRAVERSE_LEAF(LoadInnerNode(root->readChild(2).blockId())->readChild(5).blockId(), false, wantedLeafIndex); - - TraverseLeaves(std::move(root), wantedLeafIndex, wantedLeafIndex+1, true); -} - -TEST_F(LeafTraverserTest, TraverseFirstPartOfThreelevelTree) { - auto root = CreateThreeLevel(); - //Traverse all leaves in the first two children of the root - for(unsigned int i = 0; i < 2; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse some of the leaves in the third child of the root - auto child = LoadInnerNode(root->readChild(2).blockId()); - for(unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() + i); - } - - TraverseLeaves(std::move(root), 0, 2 * nodeStore->layout().maxChildrenPerInnerNode() + 5, true); -} - -TEST_F(LeafTraverserTest, TraverseMiddlePartOfThreelevelTree_OnlyFullChildren) { - auto root = CreateThreeLevel(); - //Traverse some of the leaves in the second child of the root - auto child = LoadInnerNode(root->readChild(1).blockId()); - for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode() + i); - } - //Traverse all leaves in the third and fourth child of the root - for(unsigned int i = 2; i < 4; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()),false, i * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse some of the leaves in the fifth child of the root - child = LoadInnerNode(root->readChild(4).blockId()); - for(unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, 4 * nodeStore->layout().maxChildrenPerInnerNode() + i); - } - - TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode() + 5, 4 * nodeStore->layout().maxChildrenPerInnerNode() + 5, true); -} - -TEST_F(LeafTraverserTest, TraverseMiddlePartOfThreelevelTree_AlsoLastNonfullChild) { - auto root = CreateThreeLevel(); - //Traverse some of the leaves in the second child of the root - auto child = LoadInnerNode(root->readChild(1).blockId()); - for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode() + i); - } - //Traverse all leaves in the third, fourth and fifth child of the root - for(unsigned int i = 2; i < 5; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse some of the leaves in the sixth child of the root - child = LoadInnerNode(root->readChild(5).blockId()); - for(unsigned int i = 0; i < 2; ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); - } - - TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + 2, true); -} - -TEST_F(LeafTraverserTest, TraverseLastPartOfThreelevelTree) { - auto root = CreateThreeLevel(); - //Traverse some of the leaves in the second child of the root - auto child = LoadInnerNode(root->readChild(1).blockId()); - for(unsigned int i = 5; i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode() + i); - } - //Traverse all leaves in the third, fourth and fifth child of the root - for(unsigned int i = 2; i < 5; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse all of the leaves in the sixth child of the root - child = LoadInnerNode(root->readChild(5).blockId()); - for(unsigned int i = 0; i < child->numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), i == child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); - } - - TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode() + 5, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren(), true); -} - -TEST_F(LeafTraverserTest, TraverseAllLeavesOfThreelevelTree) { - auto root = CreateThreeLevel(); - //Traverse all leaves in the third, fourth and fifth child of the root - for(unsigned int i = 0; i < 5; ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(root->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse all of the leaves in the sixth child of the root - auto child = LoadInnerNode(root->readChild(5).blockId()); - for(unsigned int i = 0; i < child->numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(child->readChild(i).blockId(), i==child->numChildren()-1, 5 * nodeStore->layout().maxChildrenPerInnerNode() + i); - } - - TraverseLeaves(std::move(root), 0, 5 * nodeStore->layout().maxChildrenPerInnerNode() + child->numChildren(), true); -} - -TEST_F(LeafTraverserTest, TraverseAllLeavesOfFourLevelTree) { - auto root = CreateFourLevel(); - //Traverse all leaves of the full threelevel tree in the first child - auto firstChild = LoadInnerNode(root->readChild(0).blockId()); - for(unsigned int i = 0; i < firstChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse all leaves of the full threelevel tree in the second child - auto secondChild = LoadInnerNode(root->readChild(1).blockId()); - for(unsigned int i = 0; i < secondChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->readChild(i).blockId()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse all leaves of the non-full threelevel tree in the third child - auto thirdChild = LoadInnerNode(root->readChild(2).blockId()); - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(thirdChild->readChild(0).blockId()), false, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode()); - EXPECT_TRAVERSE_LEAF(LoadInnerNode(thirdChild->readChild(1).blockId())->readChild(0).blockId(), true, 2 * nodeStore->layout().maxChildrenPerInnerNode() * nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode()); - - TraverseLeaves(std::move(root), 0, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() + 1, true); -} - -TEST_F(LeafTraverserTest, TraverseMiddlePartOfFourLevelTree) { - auto root = CreateFourLevel(); - //Traverse some leaves of the full threelevel tree in the first child - auto firstChild = LoadInnerNode(root->readChild(0).blockId()); - auto secondChildOfFirstChild = LoadInnerNode(firstChild->readChild(1).blockId()); - for(unsigned int i = 5; i < secondChildOfFirstChild->numChildren(); ++i) { - EXPECT_TRAVERSE_LEAF(secondChildOfFirstChild->readChild(i).blockId(), false, nodeStore->layout().maxChildrenPerInnerNode()+i); - } - for(unsigned int i = 2; i < firstChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(firstChild->readChild(i).blockId()), false, i * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse all leaves of the full threelevel tree in the second child - auto secondChild = LoadInnerNode(root->readChild(1).blockId()); - for(unsigned int i = 0; i < secondChild->numChildren(); ++i) { - EXPECT_TRAVERSE_ALL_CHILDREN_OF(*LoadInnerNode(secondChild->readChild(i).blockId()), false, (nodeStore->layout().maxChildrenPerInnerNode() + i) * nodeStore->layout().maxChildrenPerInnerNode()); - } - //Traverse some leaves of the non-full threelevel tree in the third child - auto thirdChild = LoadInnerNode(root->readChild(2).blockId()); - auto firstChildOfThirdChild = LoadInnerNode(thirdChild->readChild(0).blockId()); - for(unsigned int i = 0; i < firstChildOfThirdChild->numChildren()-1; ++i) { - EXPECT_TRAVERSE_LEAF(firstChildOfThirdChild->readChild(i).blockId(), false, 2 * nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode()+i); - } - - TraverseLeaves(std::move(root), nodeStore->layout().maxChildrenPerInnerNode()+5, 2*nodeStore->layout().maxChildrenPerInnerNode()*nodeStore->layout().maxChildrenPerInnerNode() + nodeStore->layout().maxChildrenPerInnerNode() -1, true); -} - -TEST_F(LeafTraverserTest, LastLeafIsAlreadyResizedInCallback) { - unique_ref root = CreateLeaf(); - root->flush(); - auto* old_root = root.get(); - auto tree = treeStore.load(root->blockId()).value(); - LeafTraverser(nodeStore, false).traverseAndUpdateRoot(&root, 0, 2, [this] (uint32_t leafIndex, bool /*isRightBorderNode*/, LeafHandle leaf) { - if (leafIndex == 0) { - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes()); - } else { - EXPECT_TRUE(false) << "only two nodes"; - } - }, [] (uint32_t /*nodeIndex*/) -> Data { - return Data(1); - }, [] (auto) {}); - EXPECT_NE(old_root, root.get()); // expect that we grew the tree -} - -TEST_F(LeafTraverserTest, LastLeafIsAlreadyResizedInCallback_TwoLevel) { - unique_ref root = CreateFullTwoLevelWithLastLeafSize(5); - root->flush(); - auto* old_root = root.get(); - auto tree = treeStore.load(root->blockId()).value(); - LeafTraverser(nodeStore, false).traverseAndUpdateRoot(&root, 0, nodeStore->layout().maxChildrenPerInnerNode()+1, [this] (uint32_t /*leafIndex*/, bool /*isRightBorderNode*/, LeafHandle leaf) { - EXPECT_EQ(nodeStore->layout().maxBytesPerLeaf(), leaf.node()->numBytes()); - }, [] (uint32_t /*nodeIndex*/) -> Data { - return Data(1); - }, [] (auto) {}); - EXPECT_NE(old_root, root.get()); // expect that we grew the tree -} - -TEST_F(LeafTraverserTest, ResizeFromOneLeafToMultipleLeaves) { - auto root = CreateLeaf(); - EXPECT_TRAVERSE_LEAF(root->blockId(), false, 0); - //EXPECT_CALL(traversor, calledExistingLeaf(_, false, 0)).Times(1); - for (uint32_t i = 1; i < 10; ++i) { - EXPECT_CREATE_LEAF(i); - } - TraverseLeaves(std::move(root), 0, 10, false); -} - -////TODO Refactor the test cases that are too long diff --git a/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp b/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp deleted file mode 100644 index 69a9ecd9..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include - -#include "../testutils/DataTreeTest.h" -#include "blobstore/implementations/onblocks/datatreestore/DataTree.h" -#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h" -#include -#include "blobstore/implementations/onblocks/datatreestore/impl/algorithms.h" - - -using blockstore::BlockId; -using cpputils::Data; -using namespace blobstore::onblocks::datatreestore::algorithms; - -class GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest: public DataTreeTest { -public: - struct TestData { - BlockId rootNode; - BlockId expectedResult; - }; - - void check(const TestData &testData) { - auto root = nodeStore->load(testData.rootNode).value(); - auto result = GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(nodeStore, root.get()); - EXPECT_EQ(testData.expectedResult, result->blockId()); - } - - TestData CreateTwoRightBorderNodes() { - auto node = CreateInner({CreateLeaf()}); - return TestData{node->blockId(), node->blockId()}; - } - - TestData CreateThreeRightBorderNodes() { - auto node = CreateInner({CreateLeaf()}); - auto root = CreateInner({node.get()}); - return TestData{root->blockId(), node->blockId()}; - } - - TestData CreateThreeRightBorderNodes_LastFull() { - auto root = CreateInner({CreateFullTwoLevel()}); - return TestData{root->blockId(), root->blockId()}; - } - - TestData CreateLargerTree() { - auto node = CreateInner({CreateLeaf(), CreateLeaf()}); - auto root = CreateInner({CreateFullTwoLevel().get(), node.get()}); - return TestData{root->blockId(), node->blockId()}; - } -}; - -TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, Leaf) { - auto leaf = nodeStore->createNewLeafNode(Data(0)); - auto result = GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(nodeStore, leaf.get()); - EXPECT_EQ(nullptr, result.get()); -} - -TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, TwoRightBorderNodes) { - auto testData = CreateTwoRightBorderNodes(); - check(testData); -} - -TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, ThreeRightBorderNodes) { - auto testData = CreateThreeRightBorderNodes(); - check(testData); -} - -TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, ThreeRightBorderNodes_LastFull) { - auto testData = CreateThreeRightBorderNodes_LastFull(); - check(testData); -} - -TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, LargerTree) { - auto testData = CreateLargerTree(); - check(testData); -} - -TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, FullTwoLevelTree) { - auto root = CreateFullTwoLevel(); - auto result = GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(nodeStore, root.get()); - EXPECT_EQ(nullptr, result.get()); -} - -TEST_F(GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNullTest, FullThreeLevelTree) { - auto root = CreateFullThreeLevel(); - auto result = GetLowestInnerRightBorderNodeWithLessThanKChildrenOrNull(nodeStore, root.get()); - EXPECT_EQ(nullptr, result.get()); -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest.cpp b/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest.cpp deleted file mode 100644 index fe6d8747..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/impl/GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include - -#include "../testutils/DataTreeTest.h" -#include "blobstore/implementations/onblocks/datatreestore/DataTree.h" -#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h" -#include -#include "blobstore/implementations/onblocks/datatreestore/impl/algorithms.h" - - -using blockstore::BlockId; -using namespace blobstore::onblocks::datatreestore::algorithms; - -class GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest: public DataTreeTest { -public: - struct TestData { - BlockId rootNode; - BlockId expectedResult; - }; - - void check(const TestData &testData) { - auto root = nodeStore->load(testData.rootNode).value(); - auto result = GetLowestRightBorderNodeWithMoreThanOneChildOrNull(nodeStore, root.get()); - EXPECT_EQ(testData.expectedResult, result->blockId()); - } - - BlockId CreateLeafOnlyTree() { - return CreateLeaf()->blockId(); - } - - BlockId CreateTwoRightBorderNodes() { - return CreateInner({CreateLeaf()})->blockId(); - } - - BlockId CreateThreeRightBorderNodes() { - return CreateInner({CreateInner({CreateLeaf()})})->blockId(); - } - - TestData CreateThreeRightBorderNodes_LastFull() { - auto node = CreateFullTwoLevel(); - auto root = CreateInner({node.get()}); - return TestData{root->blockId(), node->blockId()}; - } - - TestData CreateLargerTree() { - auto node = CreateInner({CreateLeaf(), CreateLeaf()}); - auto root = CreateInner({CreateFullTwoLevel().get(), node.get()}); - return TestData{root->blockId(), node->blockId()}; - } - - TestData CreateThreeLevelTreeWithRightBorderSingleNodeChain() { - auto root = CreateInner({CreateFullTwoLevel(), CreateInner({CreateLeaf()})}); - return TestData{root->blockId(), root->blockId()}; - } - - TestData CreateThreeLevelTree() { - auto node = CreateInner({CreateLeaf(), CreateLeaf()}); - auto root = CreateInner({CreateFullTwoLevel().get(), node.get()}); - return TestData{root->blockId(), node->blockId()}; - } - - TestData CreateFullTwoLevelTree() { - auto node = CreateFullTwoLevel(); - return TestData{node->blockId(), node->blockId()}; - } - - TestData CreateFullThreeLevelTree() { - auto root = CreateFullThreeLevel(); - return TestData{root->blockId(), root->readLastChild().blockId()}; - } -}; - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, Leaf) { - auto leaf = nodeStore->load(CreateLeafOnlyTree()).value(); - auto result = GetLowestRightBorderNodeWithMoreThanOneChildOrNull(nodeStore, leaf.get()); - EXPECT_EQ(nullptr, result.get()); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, TwoRightBorderNodes) { - auto node = nodeStore->load(CreateTwoRightBorderNodes()).value(); - auto result = GetLowestRightBorderNodeWithMoreThanOneChildOrNull(nodeStore, node.get()); - EXPECT_EQ(nullptr, result.get()); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, ThreeRightBorderNodes) { - auto node = nodeStore->load(CreateThreeRightBorderNodes()).value(); - auto result = GetLowestRightBorderNodeWithMoreThanOneChildOrNull(nodeStore, node.get()); - EXPECT_EQ(nullptr, result.get()); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, ThreeRightBorderNodes_LastFull) { - auto testData = CreateThreeRightBorderNodes_LastFull(); - check(testData); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, LargerTree) { - auto testData = CreateLargerTree(); - check(testData); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, FullTwoLevelTree) { - auto testData = CreateFullTwoLevelTree(); - check(testData); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, FullThreeLevelTree) { - auto testData = CreateFullThreeLevelTree(); - check(testData); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, ThreeLevelTreeWithRightBorderSingleNodeChain) { - auto testData = CreateThreeLevelTreeWithRightBorderSingleNodeChain(); - check(testData); -} - -TEST_F(GetLowestRightBorderNodeWithMoreThanOneChildOrNullTest, ThreeLevelTree) { - auto testData = CreateThreeLevelTree(); - check(testData); -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp b/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp deleted file mode 100644 index e3436fba..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "DataTreeTest.h" - -#include -#include -#include - -using blobstore::onblocks::datanodestore::DataNodeStore; -using blobstore::onblocks::datanodestore::DataNode; -using blobstore::onblocks::datanodestore::DataInnerNode; -using blobstore::onblocks::datanodestore::DataLeafNode; -using blobstore::onblocks::datatreestore::DataTree; -using blockstore::mock::MockBlockStore; -using blockstore::BlockId; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using std::initializer_list; -using std::vector; -using boost::none; -using cpputils::dynamic_pointer_move; -using cpputils::Data; - -constexpr uint32_t DataTreeTest::BLOCKSIZE_BYTES; - -DataTreeTest::DataTreeTest() - :_blockStore(make_unique_ref()), - blockStore(_blockStore.get()), - _nodeStore(make_unique_ref(std::move(_blockStore), BLOCKSIZE_BYTES)), - nodeStore(_nodeStore.get()), - treeStore(std::move(_nodeStore)) { -} - -unique_ref DataTreeTest::CreateLeaf() { - return nodeStore->createNewLeafNode(Data(nodeStore->layout().maxBytesPerLeaf())); -} - -unique_ref DataTreeTest::CreateInner(initializer_list> children) { - vector childrenVector(children.size()); - std::transform(children.begin(), children.end(), childrenVector.begin(), [](const unique_ref &ptr) {return ptr.get();}); - return CreateInner(childrenVector); -} - -unique_ref DataTreeTest::CreateInner(initializer_list children) { - return CreateInner(vector(children)); -} - -unique_ref DataTreeTest::CreateInner(vector children) { - ASSERT(children.size() >= 1, "An inner node must have at least one child"); - vector childrenKeys; - childrenKeys.reserve(children.size()); - for (const DataNode *child : children) { - ASSERT(child->depth() == (*children.begin())->depth(), "Children with different depth"); - childrenKeys.push_back(child->blockId()); - } - auto node = nodeStore->createNewInnerNode((*children.begin())->depth()+1, childrenKeys); - return node; -} - -unique_ref DataTreeTest::CreateLeafOnlyTree() { - auto blockId = CreateLeaf()->blockId(); - return treeStore.load(blockId).value(); -} - -void DataTreeTest::FillNode(DataInnerNode *node) { - for(unsigned int i=node->numChildren(); i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - node->addChild(*CreateLeaf()); - } -} - -void DataTreeTest::FillNodeTwoLevel(DataInnerNode *node) { - for(unsigned int i=node->numChildren(); i < nodeStore->layout().maxChildrenPerInnerNode(); ++i) { - node->addChild(*CreateFullTwoLevel()); - } -} - -unique_ref DataTreeTest::CreateFullTwoLevel() { - auto root = CreateInner({CreateLeaf().get()}); - FillNode(root.get()); - return root; -} - -unique_ref DataTreeTest::CreateThreeLevelMinData() { - return CreateInner({ - CreateFullTwoLevel(), - CreateInner({CreateLeaf()}) - }); -} - -unique_ref DataTreeTest::CreateFourLevelMinData() { - return CreateInner({ - CreateFullThreeLevel(), - CreateInner({CreateInner({CreateLeaf()})}) - }); -} - -unique_ref DataTreeTest::CreateFullThreeLevel() { - auto root = CreateInner({CreateFullTwoLevel().get()}); - FillNodeTwoLevel(root.get()); - return root; -} - -unique_ref DataTreeTest::LoadInnerNode(const BlockId &blockId) { - auto node = nodeStore->load(blockId).value(); - auto casted = dynamic_pointer_move(node); - EXPECT_NE(none, casted) << "Is not an inner node"; - return std::move(*casted); -} - -unique_ref DataTreeTest::LoadLeafNode(const BlockId &blockId) { - auto node = nodeStore->load(blockId).value(); - auto casted = dynamic_pointer_move(node); - EXPECT_NE(none, casted) << "Is not a leaf node"; - return std::move(*casted); -} - -unique_ref DataTreeTest::CreateTwoLeaf() { - return CreateInner({CreateLeaf().get(), CreateLeaf().get()}); -} - -unique_ref DataTreeTest::CreateTwoLeafTree() { - auto blockId = CreateTwoLeaf()->blockId(); - return treeStore.load(blockId).value(); -} - -unique_ref DataTreeTest::CreateLeafWithSize(uint32_t size) { - auto leaf = CreateLeaf(); - leaf->resize(size); - return leaf; -} - -unique_ref DataTreeTest::CreateTwoLeafWithSecondLeafSize(uint32_t size) { - return CreateInner({ - CreateLeafWithSize(nodeStore->layout().maxBytesPerLeaf()), - CreateLeafWithSize(size) - }); -} - -unique_ref DataTreeTest::CreateFullTwoLevelWithLastLeafSize(uint32_t size) { - auto root = CreateFullTwoLevel(); - for (uint32_t i = 0; i < root->numChildren()-1; ++i) { - LoadLeafNode(root->readChild(i).blockId())->resize(nodeStore->layout().maxBytesPerLeaf()); - } - LoadLeafNode(root->readLastChild().blockId())->resize(size); - return root; -} - -unique_ref DataTreeTest::CreateThreeLevelWithOneChildAndLastLeafSize(uint32_t size) { - return CreateInner({ - CreateInner({ - CreateLeafWithSize(nodeStore->layout().maxBytesPerLeaf()), - CreateLeafWithSize(size) - }) - }); -} - -unique_ref DataTreeTest::CreateThreeLevelWithTwoChildrenAndLastLeafSize(uint32_t size) { - return CreateInner({ - CreateFullTwoLevelWithLastLeafSize(nodeStore->layout().maxBytesPerLeaf()), - CreateInner({ - CreateLeafWithSize(nodeStore->layout().maxBytesPerLeaf()), - CreateLeafWithSize(size) - }) - }); -} - -unique_ref DataTreeTest::CreateThreeLevelWithThreeChildrenAndLastLeafSize(uint32_t size) { - return CreateInner({ - CreateFullTwoLevelWithLastLeafSize(nodeStore->layout().maxBytesPerLeaf()), - CreateFullTwoLevelWithLastLeafSize(nodeStore->layout().maxBytesPerLeaf()), - CreateInner({ - CreateLeafWithSize(nodeStore->layout().maxBytesPerLeaf()), - CreateLeafWithSize(size) - }) - }); -} - -unique_ref DataTreeTest::CreateFullThreeLevelWithLastLeafSize(uint32_t size) { - auto root = CreateFullThreeLevel(); - for (uint32_t i = 0; i < root->numChildren(); ++i) { - auto node = LoadInnerNode(root->readChild(i).blockId()); - for (uint32_t j = 0; j < node->numChildren(); ++j) { - LoadLeafNode(node->readChild(j).blockId())->resize(nodeStore->layout().maxBytesPerLeaf()); - } - } - LoadLeafNode(LoadInnerNode(root->readLastChild().blockId())->readLastChild().blockId())->resize(size); - return root; -} - -unique_ref DataTreeTest::CreateFourLevelMinDataWithLastLeafSize(uint32_t size) { - return CreateInner({ - CreateFullThreeLevelWithLastLeafSize(nodeStore->layout().maxBytesPerLeaf()), - CreateInner({CreateInner({CreateLeafWithSize(size)})}) - }); -} - -void DataTreeTest::EXPECT_IS_LEAF_NODE(const BlockId &blockId) { - auto node = LoadLeafNode(blockId); - EXPECT_NE(nullptr, node.get()); -} - -void DataTreeTest::EXPECT_IS_INNER_NODE(const BlockId &blockId) { - auto node = LoadInnerNode(blockId); - EXPECT_NE(nullptr, node.get()); -} - -void DataTreeTest::EXPECT_IS_TWONODE_CHAIN(const BlockId &blockId) { - auto node = LoadInnerNode(blockId); - EXPECT_EQ(1u, node->numChildren()); - EXPECT_IS_LEAF_NODE(node->readChild(0).blockId()); -} - -void DataTreeTest::EXPECT_IS_FULL_TWOLEVEL_TREE(const BlockId &blockId) { - auto node = LoadInnerNode(blockId); - EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), node->numChildren()); - for (unsigned int i = 0; i < node->numChildren(); ++i) { - EXPECT_IS_LEAF_NODE(node->readChild(i).blockId()); - } -} - -void DataTreeTest::EXPECT_IS_FULL_THREELEVEL_TREE(const BlockId &blockId) { - auto root = LoadInnerNode(blockId); - EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), root->numChildren()); - for (unsigned int i = 0; i < root->numChildren(); ++i) { - auto node = LoadInnerNode(root->readChild(i).blockId()); - EXPECT_EQ(nodeStore->layout().maxChildrenPerInnerNode(), node->numChildren()); - for (unsigned int j = 0; j < node->numChildren(); ++j) { - EXPECT_IS_LEAF_NODE(node->readChild(j).blockId()); - } - } -} - -// NOLINTNEXTLINE(misc-no-recursion) -void DataTreeTest::CHECK_DEPTH(int depth, const BlockId &blockId) { - if (depth == 0) { - EXPECT_IS_LEAF_NODE(blockId); - } else { - auto node = LoadInnerNode(blockId); - EXPECT_EQ(depth, node->depth()); - for (uint32_t i = 0; i < node->numChildren(); ++i) { - CHECK_DEPTH(depth-1, node->readChild(i).blockId()); - } - } -} diff --git a/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.h b/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.h deleted file mode 100644 index 74ad0e77..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/testutils/DataTreeTest.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_ -#define MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_DATATREETEST_H_ - -#include -#include - -#include "blobstore/implementations/onblocks/datanodestore/DataNodeStore.h" -#include "blobstore/implementations/onblocks/datanodestore/DataInnerNode.h" -#include "blobstore/implementations/onblocks/datanodestore/DataLeafNode.h" -#include "blobstore/implementations/onblocks/datatreestore/DataTree.h" -#include "blobstore/implementations/onblocks/datatreestore/DataTreeStore.h" -#include "blockstore/implementations/mock/MockBlockStore.h" - -class DataTreeTest: public ::testing::Test { -public: - DataTreeTest(); - - static constexpr uint32_t BLOCKSIZE_BYTES = 256; - - cpputils::unique_ref CreateLeaf(); - cpputils::unique_ref CreateInner(std::vector children); - cpputils::unique_ref CreateInner(std::initializer_list children); - cpputils::unique_ref CreateInner(std::initializer_list> children); - - cpputils::unique_ref CreateLeafOnlyTree(); - cpputils::unique_ref CreateTwoLeaf(); - cpputils::unique_ref CreateTwoLeafTree(); - void FillNode(blobstore::onblocks::datanodestore::DataInnerNode *node); - void FillNodeTwoLevel(blobstore::onblocks::datanodestore::DataInnerNode *node); - cpputils::unique_ref CreateFullTwoLevel(); - cpputils::unique_ref CreateFullThreeLevel(); - - cpputils::unique_ref CreateThreeLevelMinData(); - cpputils::unique_ref CreateFourLevelMinData(); - - cpputils::unique_ref LoadInnerNode(const blockstore::BlockId &blockId); - cpputils::unique_ref LoadLeafNode(const blockstore::BlockId &blockId); - - cpputils::unique_ref CreateLeafWithSize(uint32_t size); - cpputils::unique_ref CreateTwoLeafWithSecondLeafSize(uint32_t size); - cpputils::unique_ref CreateFullTwoLevelWithLastLeafSize(uint32_t size); - cpputils::unique_ref CreateThreeLevelWithOneChildAndLastLeafSize(uint32_t size); - cpputils::unique_ref CreateThreeLevelWithTwoChildrenAndLastLeafSize(uint32_t size); - cpputils::unique_ref CreateThreeLevelWithThreeChildrenAndLastLeafSize(uint32_t size); - cpputils::unique_ref CreateFullThreeLevelWithLastLeafSize(uint32_t size); - cpputils::unique_ref CreateFourLevelMinDataWithLastLeafSize(uint32_t size); - - cpputils::unique_ref _blockStore; - blockstore::mock::MockBlockStore *blockStore; - cpputils::unique_ref _nodeStore; - blobstore::onblocks::datanodestore::DataNodeStore *nodeStore; - blobstore::onblocks::datatreestore::DataTreeStore treeStore; - - void EXPECT_IS_LEAF_NODE(const blockstore::BlockId &blockId); - void EXPECT_IS_INNER_NODE(const blockstore::BlockId &blockId); - void EXPECT_IS_TWONODE_CHAIN(const blockstore::BlockId &blockId); - void EXPECT_IS_FULL_TWOLEVEL_TREE(const blockstore::BlockId &blockId); - void EXPECT_IS_FULL_THREELEVEL_TREE(const blockstore::BlockId &blockId); - - void CHECK_DEPTH(int depth, const blockstore::BlockId &blockId); - -private: - DISALLOW_COPY_AND_ASSIGN(DataTreeTest); -}; - - -#endif diff --git a/test/blobstore/implementations/onblocks/datatreestore/testutils/LeafDataFixture.h b/test/blobstore/implementations/onblocks/datatreestore/testutils/LeafDataFixture.h deleted file mode 100644 index a9fdabd9..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/testutils/LeafDataFixture.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_LEAFDATAFIXTURE_H_ -#define MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_LEAFDATAFIXTURE_H_ - -#include - -#include - -// A data fixture containing data for a leaf. -// The class can fill this data into a given leaf -// and check, whether the data stored in a given leaf is correct. -class LeafDataFixture { -public: - LeafDataFixture(int size, int iv = 0): _data(cpputils::DataFixture::generate(size, iv)) {} - - void FillInto(blobstore::onblocks::datanodestore::DataLeafNode *leaf) const { - leaf->resize(_data.size()); - leaf->write(_data.data(), 0, _data.size()); - } - - void EXPECT_DATA_CORRECT(const blobstore::onblocks::datanodestore::DataLeafNode &leaf, int onlyCheckNumBytes = -1) const { - if (onlyCheckNumBytes == -1) { - EXPECT_EQ(_data.size(), leaf.numBytes()); - EXPECT_EQ(0, std::memcmp(_data.data(), loadData(leaf).data(), _data.size())); - } else { - EXPECT_LE(onlyCheckNumBytes, static_cast(leaf.numBytes())); - EXPECT_EQ(0, std::memcmp(_data.data(), loadData(leaf).data(), onlyCheckNumBytes)); - } - } - -private: - static cpputils::Data loadData(const blobstore::onblocks::datanodestore::DataLeafNode &leaf) { - cpputils::Data data(leaf.numBytes()); - leaf.read(data.data(), 0, leaf.numBytes()); - return data; - } - cpputils::Data _data; -}; - -#endif diff --git a/test/blobstore/implementations/onblocks/datatreestore/testutils/TwoLevelDataFixture.h b/test/blobstore/implementations/onblocks/datatreestore/testutils/TwoLevelDataFixture.h deleted file mode 100644 index f757853c..00000000 --- a/test/blobstore/implementations/onblocks/datatreestore/testutils/TwoLevelDataFixture.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_TWOLEVELDATAFIXTURE_H_ -#define MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_DATATREESTORE_GROWING_TESTUTILS_TWOLEVELDATAFIXTURE_H_ - -#include -#include -#include "LeafDataFixture.h" -#include - -//TODO Rename, since we now allow any number of levels -// A data fixture containing data for a two-level tree (one inner node with leaf children). -// The class can fill this data into the leaf children of a given inner node -// and given an inner node can check, whether the data stored is correct. -class TwoLevelDataFixture { -public: - enum class SizePolicy { - Random, - Full, - Unchanged - }; - TwoLevelDataFixture(blobstore::onblocks::datanodestore::DataNodeStore *dataNodeStore, SizePolicy sizePolicy, int iv=0): _dataNodeStore(dataNodeStore), _iv(iv), _sizePolicy(sizePolicy) {} - - void FillInto(blobstore::onblocks::datanodestore::DataNode *node) { - // _iv-1 means there is no endLeafIndex - we fill all leaves. - ForEachLeaf(node, _iv, _iv-1, [this] (blobstore::onblocks::datanodestore::DataLeafNode *leaf, int leafIndex) { - LeafDataFixture(size(leafIndex, leaf), leafIndex).FillInto(leaf); - }); - } - - void EXPECT_DATA_CORRECT(blobstore::onblocks::datanodestore::DataNode *node, int maxCheckedLeaves = 0, int lastLeafMaxCheckedBytes = -1) { - ForEachLeaf(node, _iv, _iv+maxCheckedLeaves, [this, maxCheckedLeaves, lastLeafMaxCheckedBytes] (blobstore::onblocks::datanodestore::DataLeafNode *leaf, int leafIndex) { - if (leafIndex == _iv+maxCheckedLeaves-1) { - // It is the last leaf - LeafDataFixture(size(leafIndex, leaf), leafIndex).EXPECT_DATA_CORRECT(*leaf, lastLeafMaxCheckedBytes); - } else { - LeafDataFixture(size(leafIndex, leaf), leafIndex).EXPECT_DATA_CORRECT(*leaf); - } - }); - } - -private: - // NOLINTNEXTLINE(misc-no-recursion) - int ForEachLeaf(blobstore::onblocks::datanodestore::DataNode *node, int firstLeafIndex, int endLeafIndex, std::function action) { - if (firstLeafIndex == endLeafIndex) { - return firstLeafIndex; - } - auto leaf = dynamic_cast(node); - if (leaf != nullptr) { - action(leaf, firstLeafIndex); - return firstLeafIndex + 1; - } else { - auto inner = dynamic_cast(node); - int leafIndex = firstLeafIndex; - for (uint32_t i = 0; i < inner->numChildren(); ++i) { - auto child = _dataNodeStore->load(inner->readChild(i).blockId()).value(); - leafIndex = ForEachLeaf(child.get(), leafIndex, endLeafIndex, action); - } - return leafIndex; - } - } - - blobstore::onblocks::datanodestore::DataNodeStore *_dataNodeStore; - int _iv; - SizePolicy _sizePolicy; - - int size(int childIndex, blobstore::onblocks::datanodestore::DataLeafNode *leaf) { - switch (_sizePolicy) { - case SizePolicy::Full: - return _dataNodeStore->layout().maxBytesPerLeaf(); - case SizePolicy::Random: - return mod(static_cast(_dataNodeStore->layout().maxBytesPerLeaf() - childIndex), static_cast(_dataNodeStore->layout().maxBytesPerLeaf())); - case SizePolicy::Unchanged: - return leaf->numBytes(); - default: - ASSERT(false, "Unknown size policy"); - } - } - - int mod(int value, int mod) { - while(value < 0) { - value += mod; - } - return value; - } -}; - -#endif diff --git a/test/blobstore/implementations/onblocks/testutils/BlobStoreTest.cpp b/test/blobstore/implementations/onblocks/testutils/BlobStoreTest.cpp deleted file mode 100644 index 70c78947..00000000 --- a/test/blobstore/implementations/onblocks/testutils/BlobStoreTest.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "BlobStoreTest.h" - -#include -#include "blobstore/implementations/onblocks/BlobStoreOnBlocks.h" -#include - -using blobstore::onblocks::BlobStoreOnBlocks; -using blockstore::testfake::FakeBlockStore; -using cpputils::make_unique_ref; - -constexpr uint32_t BlobStoreTest::BLOCKSIZE_BYTES; - -BlobStoreTest::BlobStoreTest() - : blobStore(make_unique_ref(make_unique_ref(), BLOCKSIZE_BYTES)) { -} diff --git a/test/blobstore/implementations/onblocks/testutils/BlobStoreTest.h b/test/blobstore/implementations/onblocks/testutils/BlobStoreTest.h deleted file mode 100644 index 38bc4d33..00000000 --- a/test/blobstore/implementations/onblocks/testutils/BlobStoreTest.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_TESTUTILS_BLOBSTORETEST_H_ -#define MESSMER_BLOBSTORE_TEST_IMPLEMENTATIONS_ONBLOCKS_TESTUTILS_BLOBSTORETEST_H_ - -#include - -#include "blobstore/interface/BlobStore.h" - -class BlobStoreTest: public ::testing::Test { -public: - BlobStoreTest(); - - static constexpr uint32_t BLOCKSIZE_BYTES = 4096; - - cpputils::unique_ref blobStore; - - cpputils::unique_ref loadBlob(const blockstore::BlockId &blockId) { - auto loaded = blobStore->load(blockId); - EXPECT_TRUE(static_cast(loaded)); - return std::move(*loaded); - } - - void reset(cpputils::unique_ref ref) { - UNUSED(ref); - //ref is moved into here and then destructed - } -}; - -#endif diff --git a/test/blobstore/implementations/onblocks/utils/CeilDivisionTest.cpp b/test/blobstore/implementations/onblocks/utils/CeilDivisionTest.cpp deleted file mode 100644 index 959c3b8e..00000000 --- a/test/blobstore/implementations/onblocks/utils/CeilDivisionTest.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include "blobstore/implementations/onblocks/utils/Math.h" - -#include - -using namespace blobstore::onblocks::utils; -using ::testing::Test; -using std::numeric_limits; - -class CeilDivisionTest: public Test {}; - -TEST_F(CeilDivisionTest, Divide0_4) { - EXPECT_EQ(0, ceilDivision(0, 4)); -} - -TEST_F(CeilDivisionTest, Divide1_4) { - EXPECT_EQ(1, ceilDivision(1, 4)); -} - -TEST_F(CeilDivisionTest, Divide2_4) { - EXPECT_EQ(1, ceilDivision(2, 4)); -} - -TEST_F(CeilDivisionTest, Divide3_4) { - EXPECT_EQ(1, ceilDivision(3, 4)); -} - -TEST_F(CeilDivisionTest, Divide4_4) { - EXPECT_EQ(1, ceilDivision(4, 4)); -} - -TEST_F(CeilDivisionTest, Divide5_4) { - EXPECT_EQ(2, ceilDivision(5, 4)); -} - -TEST_F(CeilDivisionTest, Divide6_4) { - EXPECT_EQ(2, ceilDivision(6, 4)); -} - -TEST_F(CeilDivisionTest, Divide7_4) { - EXPECT_EQ(2, ceilDivision(7, 4)); -} - -TEST_F(CeilDivisionTest, Divide8_4) { - EXPECT_EQ(2, ceilDivision(8, 4)); -} - -TEST_F(CeilDivisionTest, Divide9_4) { - EXPECT_EQ(3, ceilDivision(9, 4)); -} - -TEST_F(CeilDivisionTest, Divide0_1) { - EXPECT_EQ(0, ceilDivision(0, 1)); -} - -TEST_F(CeilDivisionTest, Divide5_1) { - EXPECT_EQ(5, ceilDivision(5, 1)); -} - -TEST_F(CeilDivisionTest, Divide7_2) { - EXPECT_EQ(4, ceilDivision(7, 2)); -} - -TEST_F(CeilDivisionTest, Divide8_2) { - EXPECT_EQ(4, ceilDivision(8, 2)); -} - -TEST_F(CeilDivisionTest, Divide9_2) { - EXPECT_EQ(5, ceilDivision(9, 2)); -} - -TEST_F(CeilDivisionTest, Divide1_1) { - EXPECT_EQ(1, ceilDivision(1, 1)); -} - -TEST_F(CeilDivisionTest, Divide5_5) { - EXPECT_EQ(1, ceilDivision(5, 5)); -} - -TEST_F(CeilDivisionTest, DivideLargeByItself) { - EXPECT_EQ(1, ceilDivision(183495303, 183495303)); -} - -TEST_F(CeilDivisionTest, 64bit) { - uint64_t base = UINT64_C(1024)*1024*1024*1024; - EXPECT_GT(base, std::numeric_limits::max()); - EXPECT_EQ(base/1024, ceilDivision(base, UINT64_C(1024))); -} diff --git a/test/blobstore/implementations/onblocks/utils/CeilLogTest.cpp b/test/blobstore/implementations/onblocks/utils/CeilLogTest.cpp deleted file mode 100644 index c5bb67d4..00000000 --- a/test/blobstore/implementations/onblocks/utils/CeilLogTest.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "blobstore/implementations/onblocks/utils/Math.h" - -#include - -using namespace blobstore::onblocks::utils; -using ::testing::Test; -using std::numeric_limits; - -class CeilLogTest: public Test {}; - -TEST_F(CeilLogTest, Log3_1) { - EXPECT_EQ(0, ceilLog(3, 1)); -} - -TEST_F(CeilLogTest, Log3_2) { - EXPECT_EQ(1, ceilLog(3, 2)); -} - -TEST_F(CeilLogTest, Log3_3) { - EXPECT_EQ(1, ceilLog(3, 3)); -} - -TEST_F(CeilLogTest, Log3_4) { - EXPECT_EQ(2, ceilLog(3, 4)); -} - -TEST_F(CeilLogTest, 64bit) { - uint64_t value = UINT64_C(1024)*1024*1024*1024; - EXPECT_GT(value, std::numeric_limits::max()); - EXPECT_EQ(4u, ceilLog(UINT64_C(1024), value)); -} - - -//TODO ... diff --git a/test/blobstore/implementations/onblocks/utils/IntPowTest.cpp b/test/blobstore/implementations/onblocks/utils/IntPowTest.cpp deleted file mode 100644 index c6118209..00000000 --- a/test/blobstore/implementations/onblocks/utils/IntPowTest.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include "blobstore/implementations/onblocks/utils/Math.h" - -using namespace blobstore::onblocks::utils; -using ::testing::Test; - -class IntPowTest: public Test {}; - -TEST_F(IntPowTest, ExponentAndBaseAreZero) { - EXPECT_EQ(1, intPow(0, 0)); -} - -TEST_F(IntPowTest, ExponentIsZero1) { - EXPECT_EQ(1, intPow(1, 0)); -} - -TEST_F(IntPowTest, ExponentIsZero2) { - EXPECT_EQ(1, intPow(1000, 0)); -} - -TEST_F(IntPowTest, BaseIsZero1) { - EXPECT_EQ(0, intPow(0, 1)); -} - -TEST_F(IntPowTest, BaseIsZero2) { - EXPECT_EQ(0, intPow(0, 1000)); -} - -TEST_F(IntPowTest, ExponentIsOne1) { - EXPECT_EQ(0, intPow(0, 1)); -} - -TEST_F(IntPowTest, ExponentIsOne2) { - EXPECT_EQ(2, intPow(2, 1)); -} - -TEST_F(IntPowTest, ExponentIsOne3) { - EXPECT_EQ(1000, intPow(1000, 1)); -} - -TEST_F(IntPowTest, BaseIsTwo1) { - EXPECT_EQ(1024, intPow(2, 10)); -} - -TEST_F(IntPowTest, BaseIsTwo2) { - EXPECT_EQ(1024*1024, intPow(2, 20)); -} - -TEST_F(IntPowTest, BaseIsTwo3) { - EXPECT_EQ(1024*1024*1024, intPow(2, 30)); -} - -TEST_F(IntPowTest, BaseIsTen1) { - EXPECT_EQ(100, intPow(10, 2)); -} - -TEST_F(IntPowTest, BaseIsTen2) { - EXPECT_EQ(1000000, intPow(10, 6)); -} - -TEST_F(IntPowTest, ArbitraryNumbers1) { - EXPECT_EQ(4096, intPow(4, 6)); -} - -TEST_F(IntPowTest, ArbitraryNumbers2) { - EXPECT_EQ(1296, intPow(6, 4)); -} - -TEST_F(IntPowTest, ArbitraryNumbers3) { - EXPECT_EQ(282475249, intPow(7, 10)); -} - -TEST_F(IntPowTest, 64bit) { - uint64_t value = UINT64_C(1024)*1024*1024*1024; - EXPECT_GT(value, std::numeric_limits::max()); - EXPECT_EQ(value*value*value, intPow(value, UINT64_C(3))); -} diff --git a/test/blobstore/implementations/onblocks/utils/MaxZeroSubtractionTest.cpp b/test/blobstore/implementations/onblocks/utils/MaxZeroSubtractionTest.cpp deleted file mode 100644 index 6a3b6fbd..00000000 --- a/test/blobstore/implementations/onblocks/utils/MaxZeroSubtractionTest.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include "blobstore/implementations/onblocks/utils/Math.h" - -#include - -using namespace blobstore::onblocks::utils; -using ::testing::Test; -using std::numeric_limits; - -class MaxZeroSubtractionTest: public Test {}; - -TEST_F(MaxZeroSubtractionTest, SubtractToZero1) { - EXPECT_EQ(0, maxZeroSubtraction(0, 0)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractToZero2) { - EXPECT_EQ(0, maxZeroSubtraction(5, 5)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractToZero3) { - EXPECT_EQ(0, maxZeroSubtraction(184930, 184930)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractToZero4) { - EXPECT_EQ(0u, maxZeroSubtraction(numeric_limits::max()-1, numeric_limits::max()-1)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractToZero5) { - EXPECT_EQ(0u, maxZeroSubtraction(numeric_limits::max(), numeric_limits::max())); -} - -TEST_F(MaxZeroSubtractionTest, SubtractPositive1) { - EXPECT_EQ(1, maxZeroSubtraction(5, 4)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractPositive2) { - EXPECT_EQ(181081, maxZeroSubtraction(184930, 3849)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractPositive3) { - EXPECT_EQ(numeric_limits::max()-1, maxZeroSubtraction(numeric_limits::max(), UINT32_C(1))); -} - -TEST_F(MaxZeroSubtractionTest, SubtractPositive4) { - EXPECT_EQ(5u, maxZeroSubtraction(numeric_limits::max(), numeric_limits::max()-5)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractNegative1) { - EXPECT_EQ(0, maxZeroSubtraction(4, 5)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractNegative2) { - EXPECT_EQ(0, maxZeroSubtraction(3849, 184930)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractNegative3) { - EXPECT_EQ(0u, maxZeroSubtraction(numeric_limits::max()-1, numeric_limits::max())); -} - -TEST_F(MaxZeroSubtractionTest, SubtractNegative4) { - EXPECT_EQ(0u, maxZeroSubtraction(numeric_limits::max()-5, numeric_limits::max())); -} - -TEST_F(MaxZeroSubtractionTest, SubtractNegative5) { - EXPECT_EQ(0u, maxZeroSubtraction(UINT32_C(5), numeric_limits::max())); -} - -TEST_F(MaxZeroSubtractionTest, SubtractFromZero1) { - EXPECT_EQ(0, maxZeroSubtraction(0, 1)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractFromZero2) { - EXPECT_EQ(0, maxZeroSubtraction(0, 184930)); -} - -TEST_F(MaxZeroSubtractionTest, SubtractFromZero3) { - EXPECT_EQ(0u, maxZeroSubtraction(UINT32_C(0), numeric_limits::max())); -} - -TEST_F(MaxZeroSubtractionTest, 64bit_valid) { - uint64_t value = UINT64_C(1024)*1024*1024*1024; - EXPECT_GT(value, std::numeric_limits::max()); - EXPECT_EQ(value*1024-value, maxZeroSubtraction(value*1024, value)); -} - -TEST_F(MaxZeroSubtractionTest, 64bit_zero) { - uint64_t value = UINT64_C(1024)*1024*1024*1024; - EXPECT_GT(value, std::numeric_limits::max()); - EXPECT_EQ(0u, maxZeroSubtraction(value, value*1024)); -} diff --git a/test/blockstore/CMakeLists.txt b/test/blockstore/CMakeLists.txt deleted file mode 100644 index ca63acce..00000000 --- a/test/blockstore/CMakeLists.txt +++ /dev/null @@ -1,49 +0,0 @@ -project (blockstore-test) - -set(SOURCES - utils/BlockStoreUtilsTest.cpp - interface/BlockStoreTest.cpp - interface/BlockStore2Test.cpp - interface/BlockTest.cpp - implementations/testfake/TestFakeBlockStoreTest.cpp - implementations/mock/MockBlockStoreTest.cpp - implementations/inmemory/InMemoryBlockStoreTest.cpp - implementations/parallelaccess/ParallelAccessBlockStoreTest_Generic.cpp - implementations/parallelaccess/ParallelAccessBlockStoreTest_Specific.cpp - implementations/compressing/CompressingBlockStoreTest.cpp - implementations/compressing/compressors/testutils/CompressorTest.cpp - implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp - implementations/encrypted/EncryptedBlockStoreTest_Specific.cpp - implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp - implementations/ondisk/OnDiskBlockStoreTest_Specific.cpp - implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp - implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp - implementations/ondisk/OnDiskBlockTest/OnDiskBlockLoadTest.cpp - implementations/caching/CachingBlockStore2Test_Generic.cpp - implementations/caching/CachingBlockStore2Test_Specific.cpp - implementations/caching/cache/QueueMapTest_Values.cpp - implementations/caching/cache/testutils/MinimalKeyType.cpp - implementations/caching/cache/testutils/CopyableMovableValueType.cpp - implementations/caching/cache/testutils/MinimalValueType.cpp - implementations/caching/cache/testutils/QueueMapTest.cpp - implementations/caching/cache/testutils/CacheTest.cpp - implementations/caching/cache/QueueMapTest_Size.cpp - implementations/caching/cache/CacheTest_MoveConstructor.cpp - implementations/caching/cache/CacheTest_PushAndPop.cpp - implementations/caching/cache/QueueMapTest_MoveConstructor.cpp - implementations/caching/cache/QueueMapTest_MemoryLeak.cpp - implementations/caching/cache/CacheTest_RaceCondition.cpp - implementations/caching/cache/PeriodicTaskTest.cpp - implementations/caching/cache/QueueMapTest_Peek.cpp - implementations/integrity/KnownBlockVersionsTest.cpp - implementations/integrity/IntegrityBlockStoreTest_Generic.cpp - implementations/integrity/IntegrityBlockStoreTest_Specific.cpp - implementations/low2highlevel/LowToHighLevelBlockStoreTest.cpp -) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest blockstore) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/blockstore/implementations/caching/CachingBlockStore2Test_Generic.cpp b/test/blockstore/implementations/caching/CachingBlockStore2Test_Generic.cpp deleted file mode 100644 index 70e51a51..00000000 --- a/test/blockstore/implementations/caching/CachingBlockStore2Test_Generic.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "blockstore/implementations/caching/CachingBlockStore2.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" -#include "../../testutils/BlockStoreTest.h" -#include "../../testutils/BlockStore2Test.h" -#include - - -using blockstore::BlockStore; -using blockstore::BlockStore2; -using blockstore::caching::CachingBlockStore2; -using blockstore::lowtohighlevel::LowToHighLevelBlockStore; -using blockstore::inmemory::InMemoryBlockStore2; - -using cpputils::make_unique_ref; -using cpputils::unique_ref; - -class CachingBlockStoreTestFixture: public BlockStoreTestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref( - make_unique_ref(make_unique_ref()) - ); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(Caching2, BlockStoreTest, CachingBlockStoreTestFixture); - - -class CachingBlockStore2TestFixture: public BlockStore2TestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref(make_unique_ref()); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(Caching, BlockStore2Test, CachingBlockStore2TestFixture); diff --git a/test/blockstore/implementations/caching/CachingBlockStore2Test_Specific.cpp b/test/blockstore/implementations/caching/CachingBlockStore2Test_Specific.cpp deleted file mode 100644 index 17de609f..00000000 --- a/test/blockstore/implementations/caching/CachingBlockStore2Test_Specific.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include "blockstore/implementations/caching/CachingBlockStore2.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" - -using ::testing::Test; - -using cpputils::Data; - -using blockstore::inmemory::InMemoryBlockStore2; - -using namespace blockstore::caching; - -class CachingBlockStore2Test: public Test { -public: - CachingBlockStore2Test(): - baseBlockStore(new InMemoryBlockStore2), - blockStore(std::move(cpputils::nullcheck(std::unique_ptr(baseBlockStore)).value())) { - } - InMemoryBlockStore2 *baseBlockStore; - CachingBlockStore2 blockStore; -}; - -TEST_F(CachingBlockStore2Test, PhysicalBlockSize_zerophysical) { - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(0)); -} - -TEST_F(CachingBlockStore2Test, PhysicalBlockSize_zerovirtual) { - auto blockId = blockStore.create(Data(0)); - blockStore.flush(); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(base.size())); -} - -TEST_F(CachingBlockStore2Test, PhysicalBlockSize_negativeboundaries) { - // This tests that a potential if/else in blockSizeFromPhysicalBlockSize that catches negative values has the - // correct boundary set. We test the highest value that is negative and the smallest value that is positive. - auto blockId = blockStore.create(Data(0)); - blockStore.flush(); - auto physicalSizeForVirtualSizeZero = baseBlockStore->load(blockId).value().size(); - if (physicalSizeForVirtualSizeZero > 0) { - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero - 1)); - } - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero)); - EXPECT_EQ(1u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero + 1)); -} - -TEST_F(CachingBlockStore2Test, PhysicalBlockSize_positive) { - auto blockId = blockStore.create(Data(10*1024u)); - blockStore.flush(); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(10*1024u, blockStore.blockSizeFromPhysicalBlockSize(base.size())); -} - -// TODO Add test cases that flushing the block store doesn't destroy things (i.e. all test cases from BlockStoreTest, but with flushes inbetween) diff --git a/test/blockstore/implementations/caching/cache/CacheTest_MoveConstructor.cpp b/test/blockstore/implementations/caching/cache/CacheTest_MoveConstructor.cpp deleted file mode 100644 index c4377ab0..00000000 --- a/test/blockstore/implementations/caching/cache/CacheTest_MoveConstructor.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include "blockstore/implementations/caching/cache/Cache.h" -#include "testutils/MinimalKeyType.h" -#include "testutils/CopyableMovableValueType.h" - -using namespace blockstore::caching; - -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using ::testing::Test; - -//Test that Cache uses a move constructor for Value if possible -class CacheTest_MoveConstructor: public Test { -public: - CacheTest_MoveConstructor(): cache(make_unique_ref>("test")) { - CopyableMovableValueType::numCopyConstructorCalled = 0; - } - unique_ref> cache; -}; - -TEST_F(CacheTest_MoveConstructor, MoveIntoCache) { - cache->push(MinimalKeyType::create(0), CopyableMovableValueType(2)); - CopyableMovableValueType val = cache->pop(MinimalKeyType::create(0)).value(); - val.value(); //Access it to avoid the compiler optimizing the assignment away - EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled); -} - -TEST_F(CacheTest_MoveConstructor, CopyIntoCache) { - CopyableMovableValueType value(2); - cache->push(MinimalKeyType::create(0), value); - CopyableMovableValueType val = cache->pop(MinimalKeyType::create(0)).value(); - val.value(); //Access it to avoid the compiler optimizing the assignment away - EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled); -} diff --git a/test/blockstore/implementations/caching/cache/CacheTest_PushAndPop.cpp b/test/blockstore/implementations/caching/cache/CacheTest_PushAndPop.cpp deleted file mode 100644 index d4ff8c8a..00000000 --- a/test/blockstore/implementations/caching/cache/CacheTest_PushAndPop.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "testutils/CacheTest.h" - -#include "blockstore/implementations/caching/cache/Cache.h" -#include "testutils/MinimalKeyType.h" -#include "testutils/MinimalValueType.h" -#include - - -using namespace blockstore::caching; - -class CacheTest_PushAndPop: public CacheTest {}; - -TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_EmptyCache) { - EXPECT_EQ(boost::none, pop(10)); -} - -TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_NonEmptyCache) { - push(9, 10); - EXPECT_EQ(boost::none, pop(10)); -} - -TEST_F(CacheTest_PushAndPop, PopNonExistingEntry_FullCache) { - //Add a lot of even numbered keys - for (int i = 0; i < static_cast(MAX_ENTRIES); ++i) { - push(2*i, 2*i); - } - //Request an odd numbered key - EXPECT_EQ(boost::none, pop(9)); -} - -TEST_F(CacheTest_PushAndPop, OneEntry) { - push(10, 20); - EXPECT_EQ(20, pop(10).value()); -} - -TEST_F(CacheTest_PushAndPop, MultipleEntries) { - push(10, 20); - push(20, 30); - push(30, 40); - EXPECT_EQ(30, pop(20).value()); - EXPECT_EQ(20, pop(10).value()); - EXPECT_EQ(40, pop(30).value()); -} - -TEST_F(CacheTest_PushAndPop, FullCache) { - for(int i = 0; i < static_cast(MAX_ENTRIES); ++i) { - push(i, 2*i); - } - for(int i = 0; i < static_cast(MAX_ENTRIES); ++i) { - EXPECT_EQ(2*i, pop(i).value()); - } -} - -TEST_F(CacheTest_PushAndPop, FullCache_PushNonOrdered_PopOrdered) { - for(int i = 1; i < static_cast(MAX_ENTRIES); i += 2) { - push(i, 2*i); - } - for(int i = 0; i < static_cast(MAX_ENTRIES); i += 2) { - push(i, 2*i); - } - for(int i = 0; i < static_cast(MAX_ENTRIES); ++i) { - EXPECT_EQ(2*i, pop(i).value()); - } -} - -TEST_F(CacheTest_PushAndPop, FullCache_PushOrdered_PopNonOrdered) { - for(int i = 0; i < static_cast(MAX_ENTRIES); ++i) { - push(i, 2*i); - } - for(int i = 1; i < static_cast(MAX_ENTRIES); i += 2) { - EXPECT_EQ(2*i, pop(i).value()); - } - for(int i = 0; i < static_cast(MAX_ENTRIES); i += 2) { - EXPECT_EQ(2*i, pop(i).value()); - } -} - -int roundDownToEven(int number) { - if (number % 2 == 0) { - return number; - } else { - return number - 1; - } -} - -int roundDownToOdd(int number) { - if (number % 2 != 0) { - return number; - } else { - return number - 1; - } -} - -TEST_F(CacheTest_PushAndPop, FullCache_PushNonOrdered_PopNonOrdered) { - for(int i = roundDownToEven(MAX_ENTRIES - 1); i >= 0; i -= 2) { - push(i, 2*i); - } - for(int i = 1; i < static_cast(MAX_ENTRIES); i += 2) { - push(i, 2*i); - } - for(int i = roundDownToOdd(MAX_ENTRIES-1); i >= 0; i -= 2) { - EXPECT_EQ(2*i, pop(i).value()); - } - for(int i = 0; i < static_cast(MAX_ENTRIES); i += 2) { - EXPECT_EQ(2*i, pop(i).value()); - } -} - -TEST_F(CacheTest_PushAndPop, MoreThanFullCache) { - for(int i = 0; i < static_cast(MAX_ENTRIES + 2); ++i) { - push(i, 2*i); - } - //Check that the oldest two elements got deleted automatically - EXPECT_EQ(boost::none, pop(0)); - EXPECT_EQ(boost::none, pop(1)); - //Check the other elements are still there - for(int i = 2; i < static_cast(MAX_ENTRIES + 2); ++i) { - EXPECT_EQ(2*i, pop(i).value()); - } -} - -TEST_F(CacheTest_PushAndPop, AfterTimeout) { - constexpr double TIMEOUT1_SEC = Cache::MAX_LIFETIME_SEC * 3/4; - constexpr double TIMEOUT2_SEC = Cache::PURGE_LIFETIME_SEC * 3/4; - static_assert(TIMEOUT1_SEC + TIMEOUT2_SEC > Cache::MAX_LIFETIME_SEC, "Ensure that our chosen timeouts push the first entry out of the cache"); - - push(10, 20); - boost::this_thread::sleep_for(boost::chrono::milliseconds(static_cast(1000 * TIMEOUT1_SEC))); - push(20, 30); - boost::this_thread::sleep_for(boost::chrono::milliseconds(static_cast(1000 * TIMEOUT2_SEC))); - EXPECT_EQ(boost::none, pop(10)); - EXPECT_EQ(30, pop(20).value()); -} diff --git a/test/blockstore/implementations/caching/cache/CacheTest_RaceCondition.cpp b/test/blockstore/implementations/caching/cache/CacheTest_RaceCondition.cpp deleted file mode 100644 index d41fd3cc..00000000 --- a/test/blockstore/implementations/caching/cache/CacheTest_RaceCondition.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "testutils/CacheTest.h" -#include -#include -#include -#include -#include - -using namespace blockstore::caching; -using std::chrono::seconds; -using std::string; -using cpputils::ConditionBarrier; -using std::unique_ptr; -using std::make_unique; -using std::future; - -// Regression tests for a race condition. -// An element could be in the process of being thrown out of the cache and while the destructor is running, another -// thread calls pop() for the element and gets none returned. But since the destructor isn't finished yet, the data from -// the cache element also isn't completely written back yet and an application loading it runs into a race condition. - -class ObjectWithLongDestructor { -public: - ObjectWithLongDestructor(ConditionBarrier *onDestructorStarted, std::atomic *destructorFinished) - : _onDestructorStarted(onDestructorStarted), _destructorFinished(destructorFinished) {} - ~ObjectWithLongDestructor() { - _onDestructorStarted->release(); - std::this_thread::sleep_for(seconds(1)); - *_destructorFinished = true; - } -private: - ConditionBarrier *_onDestructorStarted; - std::atomic *_destructorFinished; - - DISALLOW_COPY_AND_ASSIGN(ObjectWithLongDestructor); -}; - -class CacheTest_RaceCondition: public ::testing::Test { -public: - CacheTest_RaceCondition(): cache("test"), destructorStarted(), destructorFinished(false) {} - - static constexpr unsigned int MAX_ENTRIES = 100; - - Cache, MAX_ENTRIES> cache; - ConditionBarrier destructorStarted; - std::atomic destructorFinished; - - int pushObjectWithLongDestructor() { - cache.push(2, make_unique(&destructorStarted, &destructorFinished)); - return 2; - } - - int pushDummyObject() { - cache.push(3, nullptr); - return 3; - } - - future causeCacheOverflowInOtherThread() { - //Add maximum+1 element in another thread (this causes the cache to flush the first element in another thread) - return std::async(std::launch::async, [this] { - for(unsigned int i = 0; i < MAX_ENTRIES+1; ++i) { - cache.push(MAX_ENTRIES+i, nullptr); - } - }); - } - - void EXPECT_POP_BLOCKS_UNTIL_DESTRUCTOR_FINISHED(int key) { - EXPECT_FALSE(destructorFinished); - cache.pop(key); - EXPECT_TRUE(destructorFinished); - } - - void EXPECT_POP_DOESNT_BLOCK_UNTIL_DESTRUCTOR_FINISHED(int key) { - EXPECT_FALSE(destructorFinished); - cache.pop(key); - EXPECT_FALSE(destructorFinished); - } -}; - -TEST_F(CacheTest_RaceCondition, PopBlocksWhileRequestedElementIsThrownOut_ByAge) { - auto id = pushObjectWithLongDestructor(); - - destructorStarted.wait(); - EXPECT_POP_BLOCKS_UNTIL_DESTRUCTOR_FINISHED(id); -} - -TEST_F(CacheTest_RaceCondition, PopDoesntBlockWhileOtherElementIsThrownOut_ByAge) { - pushObjectWithLongDestructor(); - auto id = pushDummyObject(); - - destructorStarted.wait(); - EXPECT_POP_DOESNT_BLOCK_UNTIL_DESTRUCTOR_FINISHED(id); -} - -TEST_F(CacheTest_RaceCondition, PopBlocksWhileRequestedElementIsThrownOut_ByPush) { - auto id = pushObjectWithLongDestructor(); - - auto future = causeCacheOverflowInOtherThread(); - destructorStarted.wait(); - EXPECT_POP_BLOCKS_UNTIL_DESTRUCTOR_FINISHED(id); -} - -TEST_F(CacheTest_RaceCondition, PopDoesntBlockWhileOtherElementIsThrownOut_ByPush) { - pushObjectWithLongDestructor(); - auto id = pushDummyObject(); - - auto future = causeCacheOverflowInOtherThread(); - destructorStarted.wait(); - EXPECT_POP_DOESNT_BLOCK_UNTIL_DESTRUCTOR_FINISHED(id); -} diff --git a/test/blockstore/implementations/caching/cache/PeriodicTaskTest.cpp b/test/blockstore/implementations/caching/cache/PeriodicTaskTest.cpp deleted file mode 100644 index 5dc7c739..00000000 --- a/test/blockstore/implementations/caching/cache/PeriodicTaskTest.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include - -#include "blockstore/implementations/caching/cache/PeriodicTask.h" - -#include -#include -#include - -using ::testing::Test; -using std::mutex; -using std::unique_lock; -using std::condition_variable; - -using namespace blockstore::caching; - -class AtomicCounter { -public: - AtomicCounter(int count): _mutex(), _cv(), _counter(count) {} - - void decrease() { - unique_lock lock(_mutex); - --_counter; - _cv.notify_all(); - } - - void waitForZero() { - unique_lock lock(_mutex); - _cv.wait(lock, [this] () {return _counter <= 0;}); - } -private: - mutex _mutex; - condition_variable _cv; - int _counter; -}; - -class PeriodicTaskTest: public Test { -}; - -TEST_F(PeriodicTaskTest, DoesntDeadlockInDestructorWhenDestructedImmediately) { - PeriodicTask task([](){}, 1, "test"); -} - -TEST_F(PeriodicTaskTest, CallsCallbackAtLeast10Times) { - AtomicCounter counter(10); - - PeriodicTask task([&counter](){ - counter.decrease(); - }, 0.001, "test"); - - counter.waitForZero(); -} - -TEST_F(PeriodicTaskTest, DoesntCallCallbackAfterDestruction) { - std::atomic callCount(0); - { - PeriodicTask task([&callCount](){ - callCount += 1; - }, 0.001, "test"); - } - int callCountDirectlyAfterDestruction = callCount; - boost::this_thread::sleep_for(boost::chrono::seconds(1)); - EXPECT_EQ(callCountDirectlyAfterDestruction, callCount); -} diff --git a/test/blockstore/implementations/caching/cache/QueueMapTest_MemoryLeak.cpp b/test/blockstore/implementations/caching/cache/QueueMapTest_MemoryLeak.cpp deleted file mode 100644 index 74012fc0..00000000 --- a/test/blockstore/implementations/caching/cache/QueueMapTest_MemoryLeak.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "testutils/QueueMapTest.h" - -// Tests that QueueMap calls destructors correctly. -// This is needed, because QueueMap does its own memory management. -class QueueMapTest_MemoryLeak: public QueueMapTest { -public: - void EXPECT_NUM_INSTANCES(int num) { - EXPECT_EQ(num, MinimalKeyType::instances); - EXPECT_EQ(num, MinimalValueType::instances); - } -}; - -TEST_F(QueueMapTest_MemoryLeak, Empty) { - EXPECT_NUM_INSTANCES(0); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingOne) { - push(2, 3); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_NUM_INSTANCES(2); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwoAndPoppingOldest) { - push(2, 3); - push(3, 4); - pop(); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingTwoAndPoppingLast) { - push(2, 3); - push(3, 4); - pop(3); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOne) { - push(2, 3); - pop(); - EXPECT_NUM_INSTANCES(0); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePerKey) { - push(2, 3); - pop(2); - EXPECT_NUM_INSTANCES(0); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePushingOne) { - push(2, 3); - pop(); - push(3, 4); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePerKeyPushingOne) { - push(2, 3); - pop(2); - push(3, 4); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePushingSame) { - push(2, 3); - pop(); - push(2, 3); - EXPECT_NUM_INSTANCES(1); -} - -TEST_F(QueueMapTest_MemoryLeak, AfterPushingOnePoppingOnePerKeyPushingSame) { - push(2, 3); - pop(2); - push(2, 3); - EXPECT_NUM_INSTANCES(1); -} diff --git a/test/blockstore/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp b/test/blockstore/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp deleted file mode 100644 index 2a0126ec..00000000 --- a/test/blockstore/implementations/caching/cache/QueueMapTest_MoveConstructor.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include "blockstore/implementations/caching/cache/QueueMap.h" -#include "testutils/MinimalKeyType.h" -#include "testutils/CopyableMovableValueType.h" - -using namespace blockstore::caching; - -using ::testing::Test; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -//Test that QueueMap uses a move constructor for Value if possible -class QueueMapTest_MoveConstructor: public Test { -public: - QueueMapTest_MoveConstructor(): map(make_unique_ref>()) { - CopyableMovableValueType::numCopyConstructorCalled = 0; - } - unique_ref> map; -}; - -TEST_F(QueueMapTest_MoveConstructor, PushingAndPopping_MoveIntoMap) { - map->push(MinimalKeyType::create(0), CopyableMovableValueType(2)); - CopyableMovableValueType val = map->pop().value(); - val.value(); //Access it to avoid the compiler optimizing the assignment away - EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled); -} - -TEST_F(QueueMapTest_MoveConstructor, PushingAndPoppingPerKey_MoveIntoMap) { - map->push(MinimalKeyType::create(0), CopyableMovableValueType(2)); - CopyableMovableValueType val = map->pop(MinimalKeyType::create(0)).value(); - val.value(); //Access it to avoid the compiler optimizing the assignment away - EXPECT_EQ(0, CopyableMovableValueType::numCopyConstructorCalled); -} - -TEST_F(QueueMapTest_MoveConstructor, PushingAndPopping_CopyIntoMap) { - CopyableMovableValueType value(2); - map->push(MinimalKeyType::create(0), value); - CopyableMovableValueType val = map->pop().value(); - val.value(); //Access it to avoid the compiler optimizing the assignment away - EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled); -} - -TEST_F(QueueMapTest_MoveConstructor, PushingAndPoppingPerKey_CopyIntoMap) { - CopyableMovableValueType value(2); - map->push(MinimalKeyType::create(0), value); - CopyableMovableValueType val = map->pop(MinimalKeyType::create(0)).value(); - val.value(); //Access it to avoid the compiler optimizing the assignment away - EXPECT_EQ(1, CopyableMovableValueType::numCopyConstructorCalled); -} diff --git a/test/blockstore/implementations/caching/cache/QueueMapTest_Peek.cpp b/test/blockstore/implementations/caching/cache/QueueMapTest_Peek.cpp deleted file mode 100644 index ba3c7ead..00000000 --- a/test/blockstore/implementations/caching/cache/QueueMapTest_Peek.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "testutils/QueueMapTest.h" -#include - -class QueueMapPeekTest: public QueueMapTest {}; - -TEST_F(QueueMapPeekTest, PoppingFromEmpty) { - EXPECT_EQ(boost::none, peek()); -} - -TEST_F(QueueMapPeekTest, PushingOne) { - push(3, 2); - EXPECT_EQ(2, peek().value()); -} - -TEST_F(QueueMapPeekTest, PushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_EQ(3, peek().value()); - EXPECT_EQ(3, peek().value()); - EXPECT_EQ(3, pop().value()); - EXPECT_EQ(4, peek().value()); - EXPECT_EQ(4, peek().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(boost::none, peek()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapPeekTest, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, peek().value()); -} diff --git a/test/blockstore/implementations/caching/cache/QueueMapTest_Size.cpp b/test/blockstore/implementations/caching/cache/QueueMapTest_Size.cpp deleted file mode 100644 index e4d72c9d..00000000 --- a/test/blockstore/implementations/caching/cache/QueueMapTest_Size.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "testutils/QueueMapTest.h" - -class QueueMapTest_Size: public QueueMapTest {}; - -TEST_F(QueueMapTest_Size, Empty) { - EXPECT_EQ(0, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingOne) { - push(2, 3); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_EQ(2, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingTwoAndPoppingOldest) { - push(2, 3); - push(3, 4); - pop(); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingTwoAndPoppingLast) { - push(2, 3); - push(3, 4); - pop(3); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOne) { - push(2, 3); - pop(); - EXPECT_EQ(0, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePerKey) { - push(2, 3); - pop(2); - EXPECT_EQ(0, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePushingOne) { - push(2, 3); - pop(); - push(3, 4); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePerKeyPushingOne) { - push(2, 3); - pop(2); - push(3, 4); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePushingSame) { - push(2, 3); - pop(); - push(2, 3); - EXPECT_EQ(1, size()); -} - -TEST_F(QueueMapTest_Size, AfterPushingOnePoppingOnePerKeyPushingSame) { - push(2, 3); - pop(2); - push(2, 3); - EXPECT_EQ(1, size()); -} diff --git a/test/blockstore/implementations/caching/cache/QueueMapTest_Values.cpp b/test/blockstore/implementations/caching/cache/QueueMapTest_Values.cpp deleted file mode 100644 index 0532c366..00000000 --- a/test/blockstore/implementations/caching/cache/QueueMapTest_Values.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "testutils/QueueMapTest.h" -#include - -class QueueMapTest_Values: public QueueMapTest {}; - -TEST_F(QueueMapTest_Values, PoppingFromEmpty) { - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, PoppingFromEmptyPerKey) { - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapTest_Values, PoppingNonexistingPerKey) { - push(3, 2); - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapTest_Values, PushingOne) { - push(3, 2); - EXPECT_EQ(2, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, PushingTwo) { - push(2, 3); - push(3, 4); - EXPECT_EQ(3, pop().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, AfterPushingTwoAndPoppingFirst) { - push(2, 3); - push(3, 4); - pop(2); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, AfterPushingTwoAndPoppingLast) { - push(2, 3); - push(3, 4); - pop(3); - EXPECT_EQ(boost::none, pop(3)); - EXPECT_EQ(3, pop(2).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOne) { - push(2, 3); - pop(); - EXPECT_EQ(boost::none, pop()); - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOnePerKey) { - push(2, 3); - pop(2); - EXPECT_EQ(boost::none, pop()); - EXPECT_EQ(boost::none, pop(2)); -} - -TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOnePushingOne) { - push(2, 3); - pop(); - push(3, 4); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, AfterPushingOnePoppingOnePerKeyPushingOne) { - push(2, 3); - pop(2); - push(3, 4); - EXPECT_EQ(boost::none, pop(2)); - EXPECT_EQ(4, pop(3).value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, PushingSomePoppingMiddlePerKey) { - push(1, 2); - push(2, 3); - push(3, 4); - push(4, 5); - push(5, 6); - EXPECT_EQ(3, pop(2).value()); - EXPECT_EQ(5, pop(4).value()); - EXPECT_EQ(2, pop().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(6, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, PushingSomePoppingFirstPerKey) { - push(1, 2); - push(2, 3); - push(3, 4); - push(4, 5); - push(5, 6); - EXPECT_EQ(2, pop(1).value()); - EXPECT_EQ(3, pop(2).value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(5, pop().value()); - EXPECT_EQ(6, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -TEST_F(QueueMapTest_Values, PushingSomePoppingLastPerKey) { - push(1, 2); - push(2, 3); - push(3, 4); - push(4, 5); - push(5, 6); - EXPECT_EQ(6, pop(5).value()); - EXPECT_EQ(5, pop(4).value()); - EXPECT_EQ(2, pop().value()); - EXPECT_EQ(3, pop().value()); - EXPECT_EQ(4, pop().value()); - EXPECT_EQ(boost::none, pop()); -} - -//This test forces the underlying datastructure (std::map or std::unordered_map) to grow and reallocate memory. -//So it tests, that QueueMap still works after reallocating memory. -TEST_F(QueueMapTest_Values, ManyValues) { - //Push 1 million entries - for (int i = 0; i < 1000000; ++i) { - push(i, 2*i); - } - //pop every other one by key - for (int i = 0; i < 1000000; i += 2) { - EXPECT_EQ(2*i, pop(i).value()); - } - //pop the rest in queue order - for (int i = 1; i < 1000000; i += 2) { - EXPECT_EQ(2*i, peek().value()); - EXPECT_EQ(2*i, pop().value()); - } - EXPECT_EQ(0, size()); - EXPECT_EQ(boost::none, pop()); - EXPECT_EQ(boost::none, peek()); -} - -TEST_F(QueueMapTest_Values, PushAlreadyExistingValue) { - push(2, 3); - EXPECT_ANY_THROW( - push(2, 4); - ); -} diff --git a/test/blockstore/implementations/caching/cache/testutils/CacheTest.cpp b/test/blockstore/implementations/caching/cache/testutils/CacheTest.cpp deleted file mode 100644 index b93bbccb..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/CacheTest.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "CacheTest.h" - -void CacheTest::push(int key, int value) { - return _cache.push(MinimalKeyType::create(key), MinimalValueType::create(value)); -} - -boost::optional CacheTest::pop(int key) { - boost::optional entry = _cache.pop(MinimalKeyType::create(key)); - if (!entry) { - return boost::none; - } - return entry->value(); -} diff --git a/test/blockstore/implementations/caching/cache/testutils/CacheTest.h b/test/blockstore/implementations/caching/cache/testutils/CacheTest.h deleted file mode 100644 index 937609c9..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/CacheTest.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_ -#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_ - -#include -#include "blockstore/implementations/caching/cache/Cache.h" -#include "MinimalKeyType.h" -#include "MinimalValueType.h" -#include - -// This class is a parent class for tests on QueueMap. -// It offers functions to work with a QueueMap test object which is built using types having only the minimal type requirements. -// Furthermore, the class checks that there are no memory leaks left after destructing the QueueMap (by counting leftover instances of Keys/Values). -class CacheTest: public ::testing::Test { -public: - CacheTest(): _cache("test") {} - - void push(int key, int value); - boost::optional pop(int key); - - static constexpr unsigned int MAX_ENTRIES = 100; - - using Cache = blockstore::caching::Cache; - -private: - Cache _cache; -}; - -#endif diff --git a/test/blockstore/implementations/caching/cache/testutils/CopyableMovableValueType.cpp b/test/blockstore/implementations/caching/cache/testutils/CopyableMovableValueType.cpp deleted file mode 100644 index cf23bd88..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/CopyableMovableValueType.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "CopyableMovableValueType.h" - -int CopyableMovableValueType::numCopyConstructorCalled = 0; diff --git a/test/blockstore/implementations/caching/cache/testutils/CopyableMovableValueType.h b/test/blockstore/implementations/caching/cache/testutils/CopyableMovableValueType.h deleted file mode 100644 index c85872ef..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/CopyableMovableValueType.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_COPYABLEMOVABLEVALUETYPE_H_ -#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_COPYABLEMOVABLEVALUETYPE_H_ - -class CopyableMovableValueType { -public: - static int numCopyConstructorCalled; - CopyableMovableValueType(int value): _value(value) {} - CopyableMovableValueType(const CopyableMovableValueType &rhs): CopyableMovableValueType(rhs._value) { - ++numCopyConstructorCalled; - } - // NOLINTNEXTLINE(cert-oop54-cpp) - CopyableMovableValueType &operator=(const CopyableMovableValueType &rhs) { - _value = rhs._value; - ++numCopyConstructorCalled; - return *this; - } - CopyableMovableValueType(CopyableMovableValueType &&rhs) noexcept: CopyableMovableValueType(rhs._value) { - //Don't increase numCopyConstructorCalled - } - CopyableMovableValueType &operator=(CopyableMovableValueType &&rhs) noexcept { - //Don't increase numCopyConstructorCalled - _value = rhs._value; - return *this; - } - int value() const { - return _value; - } -private: - int _value; -}; - - -#endif diff --git a/test/blockstore/implementations/caching/cache/testutils/MinimalKeyType.cpp b/test/blockstore/implementations/caching/cache/testutils/MinimalKeyType.cpp deleted file mode 100644 index 0b16bdac..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/MinimalKeyType.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "MinimalKeyType.h" - -std::atomic MinimalKeyType::instances(0); diff --git a/test/blockstore/implementations/caching/cache/testutils/MinimalKeyType.h b/test/blockstore/implementations/caching/cache/testutils/MinimalKeyType.h deleted file mode 100644 index 9c66ba90..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/MinimalKeyType.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALKEYTYPE_H_ -#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALKEYTYPE_H_ - -#include -#include - -// This is a not-default-constructible Key type -class MinimalKeyType { -public: - static std::atomic instances; - - static MinimalKeyType create(int value) { - return MinimalKeyType(value); - } - - MinimalKeyType(const MinimalKeyType &rhs): MinimalKeyType(rhs.value()) { - } - - ~MinimalKeyType() { - --instances; - } - - int value() const { - return _value; - } - -private: - MinimalKeyType(int value): _value(value) { - ++instances; - } - - int _value; -}; - -namespace std { -template <> struct hash { - size_t operator()(const MinimalKeyType &obj) const { - return obj.value(); - } -}; -} - -inline bool operator==(const MinimalKeyType &lhs, const MinimalKeyType &rhs) { - return lhs.value() == rhs.value(); -} - -#endif diff --git a/test/blockstore/implementations/caching/cache/testutils/MinimalValueType.cpp b/test/blockstore/implementations/caching/cache/testutils/MinimalValueType.cpp deleted file mode 100644 index 31a63223..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/MinimalValueType.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "MinimalValueType.h" - -std::atomic MinimalValueType::instances(0); diff --git a/test/blockstore/implementations/caching/cache/testutils/MinimalValueType.h b/test/blockstore/implementations/caching/cache/testutils/MinimalValueType.h deleted file mode 100644 index 35e8d8fe..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/MinimalValueType.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALVALUETYPE_H_ -#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_MINIMALVALUETYPE_H_ - -#include -#include -#include -#include - -// This is a not-default-constructible non-copyable but moveable Value type -class MinimalValueType { -public: - static std::atomic instances; - - static MinimalValueType create(int value) { - return MinimalValueType(value); - } - - MinimalValueType(MinimalValueType &&rhs) noexcept: MinimalValueType(rhs.value()) { - rhs._isMoved = true; - } - - MinimalValueType &operator=(MinimalValueType &&rhs) noexcept { - _value = rhs.value(); - _isMoved = false; - rhs._isMoved = true; - return *this; - } - - ~MinimalValueType() { - ASSERT(!_isDestructed, "Object was already destructed before"); - --instances; - _isDestructed = true; - } - - int value() const { - ASSERT(!_isMoved && !_isDestructed, "Object is invalid"); - return _value; - } - -private: - MinimalValueType(int value): _value(value), _isMoved(false), _isDestructed(false) { - ++instances; - } - - int _value; - bool _isMoved; - bool _isDestructed; - - DISALLOW_COPY_AND_ASSIGN(MinimalValueType); -}; - -#endif diff --git a/test/blockstore/implementations/caching/cache/testutils/QueueMapTest.cpp b/test/blockstore/implementations/caching/cache/testutils/QueueMapTest.cpp deleted file mode 100644 index 76fae6fe..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/QueueMapTest.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "QueueMapTest.h" - -QueueMapTest::QueueMapTest(): _map(cpputils::make_unique_ref>()) { - MinimalKeyType::instances = 0; - MinimalValueType::instances = 0; -} - -QueueMapTest::~QueueMapTest() { - cpputils::destruct(std::move(_map)); - EXPECT_EQ(0, MinimalKeyType::instances); - EXPECT_EQ(0, MinimalValueType::instances); -} - -void QueueMapTest::push(int key, int value) { - _map->push(MinimalKeyType::create(key), MinimalValueType::create(value)); -} - -boost::optional QueueMapTest::pop() { - auto elem = _map->pop(); - if (!elem) { - return boost::none; - } - return elem.value().value(); -} - -boost::optional QueueMapTest::pop(int key) { - auto elem = _map->pop(MinimalKeyType::create(key)); - if (!elem) { - return boost::none; - } - return elem.value().value(); -} - -boost::optional QueueMapTest::peek() { - auto elem = _map->peek(); - if (!elem) { - return boost::none; - } - return elem.value().value(); -} - -int QueueMapTest::size() { - return _map->size(); -} diff --git a/test/blockstore/implementations/caching/cache/testutils/QueueMapTest.h b/test/blockstore/implementations/caching/cache/testutils/QueueMapTest.h deleted file mode 100644 index c4d4cf00..00000000 --- a/test/blockstore/implementations/caching/cache/testutils/QueueMapTest.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_ -#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_CACHING_CACHE_TESTUTILS_QUEUEMAPTEST_H_ - -#include -#include -#include "blockstore/implementations/caching/cache/QueueMap.h" -#include "MinimalKeyType.h" -#include "MinimalValueType.h" -#include - -// This class is a parent class for tests on QueueMap. -// It offers functions to work with a QueueMap test object which is built using types having only the minimal type requirements. -// Furthermore, the class checks that there are no memory leaks left after destructing the QueueMap (by counting leftover instances of Keys/Values). -class QueueMapTest: public ::testing::Test { -public: - QueueMapTest(); - ~QueueMapTest(); - - void push(int key, int value); - boost::optional pop(); - boost::optional pop(int key); - boost::optional peek(); - int size(); - -private: - cpputils::unique_ref> _map; -}; - - -#endif diff --git a/test/blockstore/implementations/compressing/CompressingBlockStoreTest.cpp b/test/blockstore/implementations/compressing/CompressingBlockStoreTest.cpp deleted file mode 100644 index 87d33b91..00000000 --- a/test/blockstore/implementations/compressing/CompressingBlockStoreTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "blockstore/implementations/compressing/CompressingBlockStore.h" -#include "blockstore/implementations/compressing/compressors/Gzip.h" -#include "blockstore/implementations/compressing/compressors/RunLengthEncoding.h" -#include "blockstore/implementations/testfake/FakeBlockStore.h" -#include "../../testutils/BlockStoreTest.h" -#include - - -using blockstore::BlockStore; -using blockstore::compressing::CompressingBlockStore; -using blockstore::compressing::Gzip; -using blockstore::compressing::RunLengthEncoding; -using blockstore::testfake::FakeBlockStore; - -using cpputils::make_unique_ref; -using cpputils::unique_ref; - -template -class CompressingBlockStoreTestFixture: public BlockStoreTestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref>(make_unique_ref()); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(Compressing_Gzip, BlockStoreTest, CompressingBlockStoreTestFixture); -INSTANTIATE_TYPED_TEST_SUITE_P(Compressing_RunLengthEncoding, BlockStoreTest, CompressingBlockStoreTestFixture); diff --git a/test/blockstore/implementations/compressing/compressors/testutils/CompressorTest.cpp b/test/blockstore/implementations/compressing/compressors/testutils/CompressorTest.cpp deleted file mode 100644 index 254795e1..00000000 --- a/test/blockstore/implementations/compressing/compressors/testutils/CompressorTest.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include "blockstore/implementations/compressing/compressors/Gzip.h" -#include "blockstore/implementations/compressing/compressors/RunLengthEncoding.h" -#include - -using namespace blockstore::compressing; -using cpputils::Data; -using cpputils::DataFixture; - -template -class CompressorTest: public ::testing::Test { -public: - void EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(const Data &data) { - Data compressed = Compressor::Compress(data); - Data decompressed = Compressor::Decompress(compressed.data(), compressed.size()); - EXPECT_EQ(data, decompressed); - } -}; - -TYPED_TEST_SUITE_P(CompressorTest); - -TYPED_TEST_P(CompressorTest, Empty) { - Data empty(0); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(empty); -} - -TYPED_TEST_P(CompressorTest, ArbitraryData) { - Data fixture = DataFixture::generate(10240); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(fixture); -} - -TYPED_TEST_P(CompressorTest, Zeroes) { - Data zeroes(10240); - zeroes.FillWithZeroes(); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(zeroes); -} - -TYPED_TEST_P(CompressorTest, Runs) { - Data data(4096); - std::memset(data.dataOffset(0), 0xF2, 1024); - std::memset(data.dataOffset(1024), 0x00, 1024); - std::memset(data.dataOffset(2048), 0x01, 2048); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(data); -} - -TYPED_TEST_P(CompressorTest, RunsAndArbitrary) { - Data data(4096); - std::memset(data.dataOffset(0), 0xF2, 1024); - std::memcpy(data.dataOffset(1024), DataFixture::generate(1024).data(), 1024); - std::memset(data.dataOffset(2048), 0x01, 2048); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(data); -} - -TYPED_TEST_P(CompressorTest, LargeData) { - // this is larger than what fits into 16bit (16bit are for example used as run length indicator in RunLengthEncoding) - Data fixture = DataFixture::generate(200000); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(fixture); -} - -TYPED_TEST_P(CompressorTest, LargeRuns) { - // each run is larger than what fits into 16bit (16bit are for example used as run length indicator in RunLengthEncoding) - constexpr size_t RUN_SIZE = 200000; - Data data(3*RUN_SIZE); - std::memset(data.dataOffset(0), 0xF2, RUN_SIZE); - std::memset(data.dataOffset(RUN_SIZE), 0x00, RUN_SIZE); - std::memset(data.dataOffset(2*RUN_SIZE), 0x01, RUN_SIZE); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(data); -} - -TYPED_TEST_P(CompressorTest, LargeRunsAndArbitrary) { - // each run is larger than what fits into 16bit (16bit are for example used as run length indicator in RunLengthEncoding) - constexpr size_t RUN_SIZE = 200000; - Data data(3*RUN_SIZE); - std::memset(data.dataOffset(0), 0xF2, RUN_SIZE); - std::memcpy(data.dataOffset(RUN_SIZE), DataFixture::generate(RUN_SIZE).data(), RUN_SIZE); - std::memset(data.dataOffset(2*RUN_SIZE), 0x01, RUN_SIZE); - this->EXPECT_COMPRESS_AND_DECOMPRESS_IS_IDENTITY(data); -} - -REGISTER_TYPED_TEST_SUITE_P(CompressorTest, - Empty, - ArbitraryData, - Zeroes, - Runs, - RunsAndArbitrary, - LargeData, - LargeRuns, - LargeRunsAndArbitrary -); - -INSTANTIATE_TYPED_TEST_SUITE_P(Gzip, CompressorTest, Gzip); -INSTANTIATE_TYPED_TEST_SUITE_P(RunLengthEncoding, CompressorTest, RunLengthEncoding); diff --git a/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp b/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp deleted file mode 100644 index 4c16bdab..00000000 --- a/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Generic.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include -#include "blockstore/implementations/encrypted/EncryptedBlockStore2.h" -#include "blockstore/implementations/testfake/FakeBlockStore.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" -#include "../../testutils/BlockStoreTest.h" -#include "../../testutils/BlockStore2Test.h" -//TODO Move FakeAuthenticatedCipher out of test folder to normal folder. Dependencies should not point into tests of other modules. -#include "cpp-utils/crypto/symmetric/testutils/FakeAuthenticatedCipher.h" -#include - - -using blockstore::BlockStore; -using blockstore::BlockStore2; -using blockstore::encrypted::EncryptedBlockStore2; -using blockstore::lowtohighlevel::LowToHighLevelBlockStore; -using blockstore::inmemory::InMemoryBlockStore2; -using cpputils::AES256_GCM; -using cpputils::AES256_CFB; -using cpputils::FakeAuthenticatedCipher; - -using cpputils::DataFixture; -using cpputils::make_unique_ref; -using cpputils::unique_ref; - -template -class EncryptedBlockStoreTestFixture: public BlockStoreTestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref( - make_unique_ref>(make_unique_ref(), createKeyFixture()) - ); - } - -private: - static typename Cipher::EncryptionKey createKeyFixture(int seed = 0) { - return Cipher::EncryptionKey::FromString( - DataFixture::generate(Cipher::KEYSIZE, seed).ToString() - ); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(Encrypted_FakeCipher, BlockStoreTest, EncryptedBlockStoreTestFixture); -INSTANTIATE_TYPED_TEST_SUITE_P(Encrypted_AES256_GCM, BlockStoreTest, EncryptedBlockStoreTestFixture); -INSTANTIATE_TYPED_TEST_SUITE_P(Encrypted_AES256_CFB, BlockStoreTest, EncryptedBlockStoreTestFixture); - -template -class EncryptedBlockStore2TestFixture: public BlockStore2TestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref>(make_unique_ref(), createKeyFixture()); - } - -private: - static typename Cipher::EncryptionKey createKeyFixture(int seed = 0) { - return Cipher::EncryptionKey::FromString( - DataFixture::generate(Cipher::KEYSIZE, seed).ToString() - ); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(Encrypted_FakeCipher, BlockStore2Test, EncryptedBlockStore2TestFixture); -INSTANTIATE_TYPED_TEST_SUITE_P(Encrypted_AES256_GCM, BlockStore2Test, EncryptedBlockStore2TestFixture); -INSTANTIATE_TYPED_TEST_SUITE_P(Encrypted_AES256_CFB, BlockStore2Test, EncryptedBlockStore2TestFixture); diff --git a/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Specific.cpp b/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Specific.cpp deleted file mode 100644 index 28101a56..00000000 --- a/test/blockstore/implementations/encrypted/EncryptedBlockStoreTest_Specific.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include "cpp-utils/crypto/symmetric/testutils/FakeAuthenticatedCipher.h" -#include "blockstore/implementations/encrypted/EncryptedBlockStore2.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" -#include "blockstore/utils/BlockStoreUtils.h" -#include "../../testutils/gtest_printers.h" -#include - -using ::testing::Test; - -using cpputils::DataFixture; -using cpputils::Data; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::FakeAuthenticatedCipher; - -using blockstore::inmemory::InMemoryBlockStore2; - -using namespace blockstore::encrypted; - -class EncryptedBlockStoreTest: public Test { -public: - static constexpr unsigned int BLOCKSIZE = 1024; - EncryptedBlockStoreTest(): - baseBlockStore(new InMemoryBlockStore2), - blockStore(make_unique_ref>(std::move(cpputils::nullcheck(std::unique_ptr(baseBlockStore)).value()), FakeAuthenticatedCipher::Key1())), - data(DataFixture::generate(BLOCKSIZE)) { - } - InMemoryBlockStore2 *baseBlockStore; - unique_ref> blockStore; - Data data; - - blockstore::BlockId CreateBlockDirectlyWithFixtureAndReturnKey() { - return CreateBlockReturnKey(data); - } - - blockstore::BlockId CreateBlockReturnKey(const Data &initData) { - return blockStore->create(initData.copy()); - } - - blockstore::BlockId CreateBlockWriteFixtureToItAndReturnKey() { - auto blockId = blockStore->create(Data(data.size())); - blockStore->store(blockId, data); - return blockId; - } - - void ModifyBaseBlock(const blockstore::BlockId &blockId) { - auto block = baseBlockStore->load(blockId).value(); - CryptoPP::byte* middle_byte = static_cast(block.data()) + 10; - *middle_byte = *middle_byte + 1; - baseBlockStore->store(blockId, block); - } - - blockstore::BlockId CopyBaseBlock(const blockstore::BlockId &blockId) { - auto source = baseBlockStore->load(blockId).value(); - return baseBlockStore->create(source); - } - -private: - DISALLOW_COPY_AND_ASSIGN(EncryptedBlockStoreTest); -}; - -TEST_F(EncryptedBlockStoreTest, LoadingWithSameKeyWorks_WriteOnCreate) { - auto blockId = CreateBlockDirectlyWithFixtureAndReturnKey(); - auto loaded = blockStore->load(blockId); - EXPECT_NE(boost::none, loaded); - EXPECT_EQ(data.size(), loaded->size()); - EXPECT_EQ(0, std::memcmp(data.data(), loaded->data(), data.size())); -} - -TEST_F(EncryptedBlockStoreTest, LoadingWithSameKeyWorks_WriteSeparately) { - auto blockId = CreateBlockWriteFixtureToItAndReturnKey(); - auto loaded = blockStore->load(blockId); - EXPECT_NE(boost::none, loaded); - EXPECT_EQ(data.size(), loaded->size()); - EXPECT_EQ(0, std::memcmp(data.data(), loaded->data(), data.size())); -} - -TEST_F(EncryptedBlockStoreTest, LoadingWithDifferentKeyDoesntWork_WriteOnCreate) { - auto blockId = CreateBlockDirectlyWithFixtureAndReturnKey(); - blockStore->_setKey(FakeAuthenticatedCipher::Key2()); - auto loaded = blockStore->load(blockId); - EXPECT_EQ(boost::none, loaded); -} - -TEST_F(EncryptedBlockStoreTest, LoadingWithDifferentKeyDoesntWork_WriteSeparately) { - auto blockId = CreateBlockWriteFixtureToItAndReturnKey(); - blockStore->_setKey(FakeAuthenticatedCipher::Key2()); - auto loaded = blockStore->load(blockId); - EXPECT_EQ(boost::none, loaded); -} - -TEST_F(EncryptedBlockStoreTest, LoadingModifiedBlockFails_WriteOnCreate) { - auto blockId = CreateBlockDirectlyWithFixtureAndReturnKey(); - ModifyBaseBlock(blockId); - auto loaded = blockStore->load(blockId); - EXPECT_EQ(boost::none, loaded); -} - -TEST_F(EncryptedBlockStoreTest, LoadingModifiedBlockFails_WriteSeparately) { - auto blockId = CreateBlockWriteFixtureToItAndReturnKey(); - ModifyBaseBlock(blockId); - auto loaded = blockStore->load(blockId); - EXPECT_EQ(boost::none, loaded); -} - -TEST_F(EncryptedBlockStoreTest, PhysicalBlockSize_zerophysical) { - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(0)); -} - -TEST_F(EncryptedBlockStoreTest, PhysicalBlockSize_zerovirtual) { - auto blockId = CreateBlockReturnKey(Data(0)); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(base.size())); -} - -TEST_F(EncryptedBlockStoreTest, PhysicalBlockSize_negativeboundaries) { - // This tests that a potential if/else in blockSizeFromPhysicalBlockSize that catches negative values has the - // correct boundary set. We test the highest value that is negative and the smallest value that is positive. - auto physicalSizeForVirtualSizeZero = baseBlockStore->load(CreateBlockReturnKey(Data(0))).value().size(); - if (physicalSizeForVirtualSizeZero > 0) { - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero - 1)); - } - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero)); - EXPECT_EQ(1u, blockStore->blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero + 1)); -} - -TEST_F(EncryptedBlockStoreTest, PhysicalBlockSize_positive) { - auto blockId = CreateBlockReturnKey(Data(10*1024)); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(10*1024u, blockStore->blockSizeFromPhysicalBlockSize(base.size())); -} diff --git a/test/blockstore/implementations/inmemory/InMemoryBlockStoreTest.cpp b/test/blockstore/implementations/inmemory/InMemoryBlockStoreTest.cpp deleted file mode 100644 index 7e851ac7..00000000 --- a/test/blockstore/implementations/inmemory/InMemoryBlockStoreTest.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" -#include "../../testutils/BlockStoreTest.h" -#include "../../testutils/BlockStore2Test.h" -#include -#include -#include - - -using blockstore::BlockStore; -using blockstore::BlockStore2; -using blockstore::lowtohighlevel::LowToHighLevelBlockStore; -using blockstore::inmemory::InMemoryBlockStore2; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -class InMemoryBlockStoreTestFixture: public BlockStoreTestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref( - make_unique_ref() - ); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(InMemory, BlockStoreTest, InMemoryBlockStoreTestFixture); - -class InMemoryBlockStore2TestFixture: public BlockStore2TestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref(); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(InMemory, BlockStore2Test, InMemoryBlockStore2TestFixture); diff --git a/test/blockstore/implementations/integrity/IntegrityBlockStoreTest_Generic.cpp b/test/blockstore/implementations/integrity/IntegrityBlockStoreTest_Generic.cpp deleted file mode 100644 index 3f893996..00000000 --- a/test/blockstore/implementations/integrity/IntegrityBlockStoreTest_Generic.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "blockstore/implementations/integrity/IntegrityBlockStore2.h" -#include "blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" -#include "../../testutils/BlockStoreTest.h" -#include "../../testutils/BlockStore2Test.h" -#include -#include - - -using blockstore::BlockStore; -using blockstore::BlockStore2; -using blockstore::integrity::IntegrityBlockStore2; -using blockstore::lowtohighlevel::LowToHighLevelBlockStore; -using blockstore::inmemory::InMemoryBlockStore2; - -using cpputils::make_unique_ref; -using cpputils::unique_ref; -using cpputils::TempFile; - -template -class IntegrityBlockStoreTestFixture: public BlockStoreTestFixture { -public: - IntegrityBlockStoreTestFixture() :stateFile(false) {} - - TempFile stateFile; - unique_ref createBlockStore() override { - return make_unique_ref( - make_unique_ref(make_unique_ref(), stateFile.path(), 0x12345678, AllowIntegrityViolations, MissingBlockIsIntegrityViolation, [] {}) - ); - } -}; - -using IntegrityBlockStoreTestFixture_multiclient = IntegrityBlockStoreTestFixture; -using IntegrityBlockStoreTestFixture_singleclient = IntegrityBlockStoreTestFixture; -using IntegrityBlockStoreTestFixture_multiclient_allowIntegrityViolations = IntegrityBlockStoreTestFixture; -using IntegrityBlockStoreTestFixture_singleclient_allowIntegrityViolations = IntegrityBlockStoreTestFixture; - -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_multiclient, BlockStoreTest, IntegrityBlockStoreTestFixture_multiclient); -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_singleclient, BlockStoreTest, IntegrityBlockStoreTestFixture_singleclient); -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_multiclient_allowIntegrityViolations, BlockStoreTest, IntegrityBlockStoreTestFixture_multiclient_allowIntegrityViolations); -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_singleclient_allowIntegrityViolations, BlockStoreTest, IntegrityBlockStoreTestFixture_singleclient_allowIntegrityViolations); - -template -class IntegrityBlockStore2TestFixture: public BlockStore2TestFixture { -public: - IntegrityBlockStore2TestFixture() :stateFile(false) {} - - TempFile stateFile; - unique_ref createBlockStore() override { - return make_unique_ref(make_unique_ref(), stateFile.path(), 0x12345678, AllowIntegrityViolations, MissingBlockIsIntegrityViolation, [] {}); - } -}; - -using IntegrityBlockStore2TestFixture_multiclient = IntegrityBlockStore2TestFixture; -using IntegrityBlockStore2TestFixture_singleclient = IntegrityBlockStore2TestFixture; -using IntegrityBlockStore2TestFixture_multiclient_allowIntegrityViolations = IntegrityBlockStore2TestFixture; -using IntegrityBlockStore2TestFixture_singleclient_allowIntegrityViolations = IntegrityBlockStore2TestFixture; - -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_multiclient, BlockStore2Test, IntegrityBlockStore2TestFixture_multiclient); -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_singleclient, BlockStore2Test, IntegrityBlockStore2TestFixture_singleclient); -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_multiclient_allowIntegrityViolations, BlockStore2Test, IntegrityBlockStore2TestFixture_multiclient_allowIntegrityViolations); -INSTANTIATE_TYPED_TEST_SUITE_P(Integrity_singleclient_allowIntegrityViolations, BlockStore2Test, IntegrityBlockStore2TestFixture_singleclient_allowIntegrityViolations); diff --git a/test/blockstore/implementations/integrity/IntegrityBlockStoreTest_Specific.cpp b/test/blockstore/implementations/integrity/IntegrityBlockStoreTest_Specific.cpp deleted file mode 100644 index 12aa5cf6..00000000 --- a/test/blockstore/implementations/integrity/IntegrityBlockStoreTest_Specific.cpp +++ /dev/null @@ -1,388 +0,0 @@ -#include -#include "blockstore/implementations/integrity/IntegrityBlockStore2.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" -#include "blockstore/utils/BlockStoreUtils.h" -#include -#include -#include "../../testutils/gtest_printers.h" - -using ::testing::Test; - -using cpputils::DataFixture; -using cpputils::Data; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::TempFile; -using cpputils::serialize; -using cpputils::deserialize; -using boost::none; -using std::unique_ptr; - -using blockstore::inmemory::InMemoryBlockStore2; - -using namespace blockstore::integrity; - -namespace { -class FakeCallback final { -public: - FakeCallback(): wasCalled_(false) {} - - bool wasCalled() const { - return wasCalled_; - } - - std::function callback() { - return [this] () { - wasCalled_ = true; - }; - } - -private: - bool wasCalled_; -}; -} - -template -class IntegrityBlockStoreTest: public Test { -public: - static constexpr unsigned int BLOCKSIZE = 1024; - IntegrityBlockStoreTest(): - stateFile(false), - onIntegrityViolation(), - baseBlockStore(new InMemoryBlockStore2), - blockStore(make_unique_ref(std::move(cpputils::nullcheck(std::unique_ptr(baseBlockStore)).value()), stateFile.path(), myClientId, AllowIntegrityViolations, MissingBlockIsIntegrityViolation, onIntegrityViolation.callback())), - data(DataFixture::generate(BLOCKSIZE)) { - } - static constexpr uint32_t myClientId = 0x12345678; - TempFile stateFile; - FakeCallback onIntegrityViolation; - InMemoryBlockStore2 *baseBlockStore; - unique_ref blockStore; - Data data; - - blockstore::BlockId CreateBlockReturnKey() { - return CreateBlockReturnKey(data); - } - - blockstore::BlockId CreateBlockReturnKey(const Data &initData) { - return blockStore->create(initData.copy()); - } - - Data loadBaseBlock(const blockstore::BlockId &blockId) { - return baseBlockStore->load(blockId).value(); - } - - Data loadBlock(const blockstore::BlockId &blockId) { - return blockStore->load(blockId).value(); - } - - void modifyBlock(const blockstore::BlockId &blockId) { - auto block = blockStore->load(blockId).value(); - CryptoPP::byte* first_byte = static_cast(block.data()); - *first_byte = *first_byte + 1; - blockStore->store(blockId, block); - } - - void rollbackBaseBlock(const blockstore::BlockId &blockId, const Data &data) { - baseBlockStore->store(blockId, data); - } - - void decreaseVersionNumber(const blockstore::BlockId &blockId) { - auto baseBlock = baseBlockStore->load(blockId).value(); - void* versionPtr = static_cast(baseBlock.data()) + IntegrityBlockStore2::VERSION_HEADER_OFFSET; - uint64_t version = deserialize(versionPtr); - ASSERT(version > 1, "Can't decrease the lowest allowed version number"); - serialize(versionPtr, version-1); - baseBlockStore->store(blockId, baseBlock); - } - - void increaseVersionNumber(const blockstore::BlockId &blockId) { - auto baseBlock = baseBlockStore->load(blockId).value(); - void* versionPtr = static_cast(baseBlock.data()) + IntegrityBlockStore2::VERSION_HEADER_OFFSET; - uint64_t version = deserialize(versionPtr); - serialize(versionPtr, version+1); - baseBlockStore->store(blockId, baseBlock); - } - - void changeClientId(const blockstore::BlockId &blockId) { - auto baseBlock = baseBlockStore->load(blockId).value(); - void* clientIdPtr = static_cast(baseBlock.data()) + IntegrityBlockStore2::CLIENTID_HEADER_OFFSET; - uint64_t clientId = deserialize(clientIdPtr); - serialize(clientIdPtr, clientId+1); - baseBlockStore->store(blockId, baseBlock); - } - - void deleteBlock(const blockstore::BlockId &blockId) { - blockStore->remove(blockId); - } - - void insertBaseBlock(const blockstore::BlockId &blockId, Data data) { - EXPECT_TRUE(baseBlockStore->tryCreate(blockId, data)); - } - -private: - DISALLOW_COPY_AND_ASSIGN(IntegrityBlockStoreTest); -}; - -using IntegrityBlockStoreTest_Default = IntegrityBlockStoreTest; -using IntegrityBlockStoreTest_MissingBlockIsIntegrityViolation = IntegrityBlockStoreTest; -using IntegrityBlockStoreTest_AllowIntegrityViolations = IntegrityBlockStoreTest; -using IntegrityBlockStoreTest_AllowIntegrityViolations_MissingBlockIsIntegrityViolation = IntegrityBlockStoreTest; - -template -constexpr uint32_t IntegrityBlockStoreTest::myClientId; - -// Test that a decreasing version number is not allowed -TEST_F(IntegrityBlockStoreTest_Default, RollbackPrevention_DoesntAllowDecreasingVersionNumberForSameClient_1) { - auto blockId = CreateBlockReturnKey(); - Data oldBaseBlock = loadBaseBlock(blockId); - modifyBlock(blockId); - rollbackBaseBlock(blockId, oldBaseBlock); - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_TRUE(onIntegrityViolation.wasCalled()); -} - -// Test that a decreasing version number is allowed if allowIntegrityViolations is set. -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, RollbackPrevention_AllowsDecreasingVersionNumberForSameClient_1) { - auto blockId = CreateBlockReturnKey(); - Data oldBaseBlock = loadBaseBlock(blockId); - modifyBlock(blockId); - rollbackBaseBlock(blockId, oldBaseBlock); - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_Default, RollbackPrevention_DoesntAllowDecreasingVersionNumberForSameClient_2) { - auto blockId = CreateBlockReturnKey(); - // Increase the version number - modifyBlock(blockId); - // Decrease the version number again - decreaseVersionNumber(blockId); - - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_TRUE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, RollbackPrevention_AllowsDecreasingVersionNumberForSameClient_2) { - auto blockId = CreateBlockReturnKey(); - // Increase the version number - modifyBlock(blockId); - // Decrease the version number again - decreaseVersionNumber(blockId); - - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// Test that a different client doesn't need to have a higher version number (i.e. version numbers are per client). -TEST_F(IntegrityBlockStoreTest_Default, RollbackPrevention_DoesAllowDecreasingVersionNumberForDifferentClient) { - auto blockId = CreateBlockReturnKey(); - // Increase the version number - modifyBlock(blockId); - // Fake a modification by a different client with lower version numbers - changeClientId(blockId); - decreaseVersionNumber(blockId); - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, RollbackPrevention_DoesAllowDecreasingVersionNumberForDifferentClient) { - auto blockId = CreateBlockReturnKey(); - // Increase the version number - modifyBlock(blockId); - // Fake a modification by a different client with lower version numbers - changeClientId(blockId); - decreaseVersionNumber(blockId); - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// Test that it doesn't allow a rollback to the "newest" block of a client, when this block was superseded by a version of a different client -TEST_F(IntegrityBlockStoreTest_Default, RollbackPrevention_DoesntAllowSameVersionNumberForOldClient) { - auto blockId = CreateBlockReturnKey(); - // Increase the version number - modifyBlock(blockId); - Data oldBaseBlock = loadBaseBlock(blockId); - // Fake a modification by a different client with lower version numbers - changeClientId(blockId); - loadBlock(blockId); // make the block store know about this other client's modification - // Rollback to old client - rollbackBaseBlock(blockId, oldBaseBlock); - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_TRUE(onIntegrityViolation.wasCalled()); -} - -// Test that it does allow a rollback to the "newest" block of a client, when this block was superseded by a version of a different client, but integrity violations are allowed -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, RollbackPrevention_AllowsSameVersionNumberForOldClient) { - auto blockId = CreateBlockReturnKey(); - // Increase the version number - modifyBlock(blockId); - Data oldBaseBlock = loadBaseBlock(blockId); - // Fake a modification by a different client with lower version numbers - changeClientId(blockId); - loadBlock(blockId); // make the block store know about this other client's modification - // Rollback to old client - rollbackBaseBlock(blockId, oldBaseBlock); - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// Test that deleted blocks cannot be re-introduced -TEST_F(IntegrityBlockStoreTest_Default, RollbackPrevention_DoesntAllowReintroducingDeletedBlocks) { - auto blockId = CreateBlockReturnKey(); - Data oldBaseBlock = loadBaseBlock(blockId); - deleteBlock(blockId); - insertBaseBlock(blockId, std::move(oldBaseBlock)); - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_TRUE(onIntegrityViolation.wasCalled()); -} - -// Test that deleted blocks can be re-introduced if integrity violations are allowed -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, RollbackPrevention_AllowsReintroducingDeletedBlocks) { - auto blockId = CreateBlockReturnKey(); - Data oldBaseBlock = loadBaseBlock(blockId); - deleteBlock(blockId); - insertBaseBlock(blockId, std::move(oldBaseBlock)); - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// This can happen if a client synchronization is delayed. Another client might have won the conflict and pushed a new version for the deleted block. -TEST_F(IntegrityBlockStoreTest_Default, RollbackPrevention_AllowsReintroducingDeletedBlocksWithNewVersionNumber) { - auto blockId = CreateBlockReturnKey(); - Data oldBaseBlock = loadBaseBlock(blockId); - deleteBlock(blockId); - insertBaseBlock(blockId, std::move(oldBaseBlock)); - increaseVersionNumber(blockId); - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, RollbackPrevention_AllowsReintroducingDeletedBlocksWithNewVersionNumber) { - auto blockId = CreateBlockReturnKey(); - Data oldBaseBlock = loadBaseBlock(blockId); - deleteBlock(blockId); - insertBaseBlock(blockId, std::move(oldBaseBlock)); - increaseVersionNumber(blockId); - EXPECT_NE(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// Check that in a multi-client scenario, missing blocks are not integrity errors, because another client might have deleted them. -TEST_F(IntegrityBlockStoreTest_Default, DeletionPrevention_AllowsDeletingBlocksWhenDeactivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, DeletionPrevention_AllowsDeletingBlocksWhenDeactivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// Check that in a single-client scenario, missing blocks are integrity errors. -TEST_F(IntegrityBlockStoreTest_MissingBlockIsIntegrityViolation, DeletionPrevention_DoesntAllowDeletingBlocksWhenActivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_TRUE(onIntegrityViolation.wasCalled()); -} - -// Check that in a single-client scenario, missing blocks don't throw if integrity violations are allowed. -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations_MissingBlockIsIntegrityViolation, DeletionPrevention_AllowsDeletingBlocksWhenActivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - EXPECT_EQ(boost::none, blockStore->load(blockId)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// Check that in a multi-client scenario, missing blocks are not integrity errors, because another client might have deleted them. -TEST_F(IntegrityBlockStoreTest_Default, DeletionPrevention_InForEachBlock_AllowsDeletingBlocksWhenDeactivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - int count = 0; - blockStore->forEachBlock([&count] (const blockstore::BlockId &) { - ++count; - }); - EXPECT_EQ(0, count); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, DeletionPrevention_InForEachBlock_AllowsDeletingBlocksWhenDeactivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - int count = 0; - blockStore->forEachBlock([&count] (const blockstore::BlockId &) { - ++count; - }); - EXPECT_EQ(0, count); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// Check that in a single-client scenario, missing blocks are integrity errors. -TEST_F(IntegrityBlockStoreTest_MissingBlockIsIntegrityViolation, DeletionPrevention_InForEachBlock_DoesntAllowDeletingBlocksWhenActivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - blockStore->forEachBlock([] (const blockstore::BlockId &) {}); - EXPECT_TRUE(onIntegrityViolation.wasCalled()); -} - -// Check that in a single-client scenario, missing blocks don't throw if integrity violations are allowed. -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations_MissingBlockIsIntegrityViolation, DeletionPrevention_InForEachBlock_AllowsDeletingBlocksWhenActivated) { - auto blockId = blockStore->create(Data(0)); - baseBlockStore->remove(blockId); - blockStore->forEachBlock([] (const blockstore::BlockId &) {}); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_Default, LoadingWithDifferentBlockIdFails) { - auto blockId = CreateBlockReturnKey(); - blockstore::BlockId key2 = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - baseBlockStore->store(key2, baseBlockStore->load(blockId).value()); - EXPECT_EQ(boost::none, blockStore->load(key2)); - EXPECT_TRUE(onIntegrityViolation.wasCalled()); -} - -TEST_F(IntegrityBlockStoreTest_AllowIntegrityViolations, LoadingWithDifferentBlockIdDoesntFail) { - auto blockId = CreateBlockReturnKey(); - blockstore::BlockId key2 = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - baseBlockStore->store(key2, baseBlockStore->load(blockId).value()); - EXPECT_NE(boost::none, blockStore->load(key2)); - EXPECT_FALSE(onIntegrityViolation.wasCalled()); -} - -// TODO Test more integrity cases: -// - RollbackPrevention_DoesntAllowReintroducingDeletedBlocks with different client id (i.e. trying to re-introduce the newest block of a different client) -// - RollbackPrevention_AllowsReintroducingDeletedBlocksWithNewVersionNumber with different client id -// - Think about more... -// TODO Test that disabling integrity checks allows all these cases - -TEST_F(IntegrityBlockStoreTest_Default, PhysicalBlockSize_zerophysical) { - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(0)); -} - -TEST_F(IntegrityBlockStoreTest_Default, PhysicalBlockSize_zerovirtual) { - auto blockId = CreateBlockReturnKey(Data(0)); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(base.size())); -} - -TEST_F(IntegrityBlockStoreTest_Default, PhysicalBlockSize_negativeboundaries) { - // This tests that a potential if/else in blockSizeFromPhysicalBlockSize that catches negative values has the - // correct boundary set. We test the highest value that is negative and the smallest value that is positive. - auto physicalSizeForVirtualSizeZero = baseBlockStore->load(CreateBlockReturnKey(Data(0))).value().size(); - if (physicalSizeForVirtualSizeZero > 0) { - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero - 1)); - } - EXPECT_EQ(0u, blockStore->blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero)); - EXPECT_EQ(1u, blockStore->blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero + 1)); -} - -TEST_F(IntegrityBlockStoreTest_Default, PhysicalBlockSize_positive) { - auto blockId = CreateBlockReturnKey(Data(10*1024)); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(10*1024u, blockStore->blockSizeFromPhysicalBlockSize(base.size())); -} diff --git a/test/blockstore/implementations/integrity/KnownBlockVersionsTest.cpp b/test/blockstore/implementations/integrity/KnownBlockVersionsTest.cpp deleted file mode 100644 index 772fb65d..00000000 --- a/test/blockstore/implementations/integrity/KnownBlockVersionsTest.cpp +++ /dev/null @@ -1,354 +0,0 @@ -#include -#include -#include - -using blockstore::integrity::KnownBlockVersions; -using blockstore::BlockId; -using cpputils::TempFile; -using std::unordered_set; - -class KnownBlockVersionsTest : public ::testing::Test { -public: - KnownBlockVersionsTest() :stateFile(false), testobj(stateFile.path(), myClientId) {} - - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - blockstore::BlockId blockId2 = blockstore::BlockId::FromString("C772972491BB4932A1389EE14BC7090A"); - static constexpr uint32_t myClientId = 0x12345678; - static constexpr uint32_t clientId = 0x23456789; - static constexpr uint32_t clientId2 = 0x34567890; - - TempFile stateFile; - KnownBlockVersions testobj; - - void setVersion(KnownBlockVersions *testobj, uint32_t clientId, const blockstore::BlockId &blockId, uint64_t version) { - if (!testobj->checkAndUpdateVersion(clientId, blockId, version)) { - throw std::runtime_error("Couldn't increase version"); - } - } - - void EXPECT_VERSION_IS(uint64_t version, KnownBlockVersions *testobj, blockstore::BlockId &blockId, uint32_t clientId) { - EXPECT_FALSE(testobj->checkAndUpdateVersion(clientId, blockId, version-1)); - EXPECT_TRUE(testobj->checkAndUpdateVersion(clientId, blockId, version+1)); - } -}; - -TEST_F(KnownBlockVersionsTest, setandget) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, setandget_isPerClientId) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId2, blockId, 3); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(3u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, setandget_isPerBlock) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId, blockId2, 3); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(3u, testobj.getBlockVersion(clientId, blockId2)); -} - -TEST_F(KnownBlockVersionsTest, setandget_allowsIncreasing) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId, blockId, 6); - EXPECT_EQ(6u, testobj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, setandget_doesntAllowDecreasing) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_ANY_THROW( - setVersion(&testobj, clientId, blockId, 4); - ); -} - -TEST_F(KnownBlockVersionsTest, myClientId_isConsistent) { - EXPECT_EQ(testobj.myClientId(), testobj.myClientId()); -} - -TEST_F(KnownBlockVersionsTest, incrementVersion_newentry) { - auto version = testobj.incrementVersion(blockId); - EXPECT_EQ(1u, version); - EXPECT_EQ(1u, testobj.getBlockVersion(testobj.myClientId(), blockId)); -} - -TEST_F(KnownBlockVersionsTest, incrementVersion_oldentry) { - setVersion(&testobj, testobj.myClientId(), blockId, 5); - auto version = testobj.incrementVersion(blockId); - EXPECT_EQ(6u, version); - EXPECT_EQ(6u, testobj.getBlockVersion(testobj.myClientId(), blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_newentry) { - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 5)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_sameClientSameVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 5)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_sameClientLowerVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 4)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_sameClientNewerVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 6)); - EXPECT_EQ(6u, testobj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_differentClientSameVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 5)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_differentClientLowerVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 3)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(3u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_differentClientHigherVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 7)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientLowerVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 7)); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 3)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientSameVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 7)); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 5)); // Don't allow rollback to old client's newest block, if it was superseded by another client - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientHigherVersion) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 7)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 6)); - EXPECT_EQ(6u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientLowerVersion_oldClientIsSelf) { - setVersion(&testobj, testobj.myClientId(), blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 7)); - EXPECT_FALSE(testobj.checkAndUpdateVersion(testobj.myClientId(), blockId, 3)); - EXPECT_EQ(5u, testobj.getBlockVersion(testobj.myClientId(), blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientSameVersion_oldClientIsSelf) { - setVersion(&testobj, testobj.myClientId(), blockId, 5); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 7)); - EXPECT_FALSE(testobj.checkAndUpdateVersion(testobj.myClientId(), blockId, 5)); // Don't allow rollback to old client's newest block, if it was superseded by another client - EXPECT_EQ(5u, testobj.getBlockVersion(testobj.myClientId(), blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientHigherVersion_oldClientIsSelf) { - setVersion(&testobj, testobj.myClientId(), blockId, 4); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 7)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(testobj.myClientId(), blockId, 6)); - EXPECT_EQ(6u, testobj.getBlockVersion(testobj.myClientId(), blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(clientId2, blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientLowerVersion_newClientIsSelf) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, testobj.myClientId(), blockId, 7); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 3)); - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(testobj.myClientId(), blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientSameVersion_newClientIsSelf) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, testobj.myClientId(), blockId, 7); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 5)); // Don't allow rollback to old client's newest block, if it was superseded by another client - EXPECT_EQ(5u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(testobj.myClientId(), blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdateVersion_oldentry_oldClientHigherVersion_newClientIsSelf) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, testobj.myClientId(), blockId, 7); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 6)); - EXPECT_EQ(6u, testobj.getBlockVersion(clientId, blockId)); - EXPECT_EQ(7u, testobj.getBlockVersion(testobj.myClientId(), blockId)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdate_twoEntriesDontInfluenceEachOther_differentKeys) { - // Setup - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 100)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId2, 100)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 150)); - - // Checks - EXPECT_VERSION_IS(150, &testobj, blockId, clientId); - EXPECT_VERSION_IS(100, &testobj, blockId2, clientId); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdate_twoEntriesDontInfluenceEachOther_differentClientIds) { - // Setup - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 100)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 100)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 150)); - - EXPECT_VERSION_IS(150, &testobj, blockId, clientId); - EXPECT_VERSION_IS(100, &testobj, blockId, clientId2); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdate_allowsRollbackToSameClientWithSameVersionNumber) { - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 100)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 100)); -} - -TEST_F(KnownBlockVersionsTest, checkAndUpdate_doesntAllowRollbackToOldClientWithSameVersionNumber) { - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId, blockId, 100)); - EXPECT_TRUE(testobj.checkAndUpdateVersion(clientId2, blockId, 10)); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 100)); -} - -TEST_F(KnownBlockVersionsTest, saveAndLoad_empty) { - TempFile stateFile(false); - { - KnownBlockVersions _1(stateFile.path(), myClientId); - } - - EXPECT_TRUE(KnownBlockVersions(stateFile.path(), myClientId).checkAndUpdateVersion(clientId, blockId, 1)); -} - -TEST_F(KnownBlockVersionsTest, saveAndLoad_oneentry) { - TempFile stateFile(false); - EXPECT_TRUE(KnownBlockVersions(stateFile.path(), myClientId).checkAndUpdateVersion(clientId, blockId, 100)); - - KnownBlockVersions obj(stateFile.path(), myClientId); - EXPECT_EQ(100u, obj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, saveAndLoad_threeentries) { - TempFile stateFile(false); - { - KnownBlockVersions obj(stateFile.path(), myClientId); - EXPECT_TRUE(obj.checkAndUpdateVersion(obj.myClientId(), blockId, 100)); - EXPECT_TRUE(obj.checkAndUpdateVersion(obj.myClientId(), blockId2, 50)); - EXPECT_TRUE(obj.checkAndUpdateVersion(clientId, blockId, 150)); - } - - KnownBlockVersions obj(stateFile.path(), myClientId); - EXPECT_EQ(100u, obj.getBlockVersion(obj.myClientId(), blockId)); - EXPECT_EQ(50u, obj.getBlockVersion(obj.myClientId(), blockId2)); - EXPECT_EQ(150u, obj.getBlockVersion(clientId, blockId)); -} - -TEST_F(KnownBlockVersionsTest, saveAndLoad_lastUpdateClientIdIsStored) { - { - KnownBlockVersions obj(stateFile.path(), myClientId); - EXPECT_TRUE(obj.checkAndUpdateVersion(clientId, blockId, 100)); - EXPECT_TRUE(obj.checkAndUpdateVersion(clientId2, blockId, 10)); - } - - KnownBlockVersions obj(stateFile.path(), myClientId); - EXPECT_FALSE(obj.checkAndUpdateVersion(clientId, blockId, 100)); - EXPECT_TRUE(obj.checkAndUpdateVersion(clientId2, blockId, 10)); - EXPECT_TRUE(obj.checkAndUpdateVersion(clientId, blockId, 101)); -} - -TEST_F(KnownBlockVersionsTest, markAsDeleted_doesntAllowReIntroducing_sameClientId) { - setVersion(&testobj, clientId, blockId, 5); - testobj.markBlockAsDeleted(blockId); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 5)); -} - -TEST_F(KnownBlockVersionsTest, markAsDeleted_doesntAllowReIntroducing_oldClientId) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId2, blockId, 5); - testobj.markBlockAsDeleted(blockId); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 5)); -} - -TEST_F(KnownBlockVersionsTest, markAsDeleted_checkAndUpdateDoesntDestroyState) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId2, blockId, 5); - testobj.markBlockAsDeleted(blockId); - EXPECT_FALSE(testobj.checkAndUpdateVersion(clientId, blockId, 5)); - - // Check block is still deleted - EXPECT_FALSE(testobj.blockShouldExist(blockId)); -} - -TEST_F(KnownBlockVersionsTest, blockShouldExist_unknownBlock) { - EXPECT_FALSE(testobj.blockShouldExist(blockId)); -} - -TEST_F(KnownBlockVersionsTest, blockShouldExist_knownBlock) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_TRUE(testobj.blockShouldExist(blockId)); -} - -TEST_F(KnownBlockVersionsTest, blockShouldExist_deletedBlock) { - setVersion(&testobj, clientId, blockId, 5); - testobj.markBlockAsDeleted(blockId); - EXPECT_FALSE(testobj.blockShouldExist(blockId)); -} - -TEST_F(KnownBlockVersionsTest, path) { - KnownBlockVersions obj(stateFile.path(), myClientId); - EXPECT_EQ(stateFile.path(), obj.path()); -} - -TEST_F(KnownBlockVersionsTest, existingBlocks_empty) { - EXPECT_EQ(unordered_set({}), testobj.existingBlocks()); -} - -TEST_F(KnownBlockVersionsTest, existingBlocks_oneentry) { - setVersion(&testobj, clientId, blockId, 5); - EXPECT_EQ(unordered_set({blockId}), testobj.existingBlocks()); -} - -TEST_F(KnownBlockVersionsTest, existingBlocks_twoentries) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId2, blockId2, 5); - EXPECT_EQ(unordered_set({blockId, blockId2}), testobj.existingBlocks()); -} - -TEST_F(KnownBlockVersionsTest, existingBlocks_twoentries_sameKey) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId2, blockId, 5); - EXPECT_EQ(unordered_set({blockId}), testobj.existingBlocks()); -} - -TEST_F(KnownBlockVersionsTest, existingBlocks_deletedEntry) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId2, blockId2, 5); - testobj.markBlockAsDeleted(blockId2); - EXPECT_EQ(unordered_set({blockId}), testobj.existingBlocks()); -} - -TEST_F(KnownBlockVersionsTest, existingBlocks_deletedEntries) { - setVersion(&testobj, clientId, blockId, 5); - setVersion(&testobj, clientId2, blockId2, 5); - testobj.markBlockAsDeleted(blockId); - testobj.markBlockAsDeleted(blockId2); - EXPECT_EQ(unordered_set({}), testobj.existingBlocks()); -} diff --git a/test/blockstore/implementations/low2highlevel/LowToHighLevelBlockStoreTest.cpp b/test/blockstore/implementations/low2highlevel/LowToHighLevelBlockStoreTest.cpp deleted file mode 100644 index 79dc8c98..00000000 --- a/test/blockstore/implementations/low2highlevel/LowToHighLevelBlockStoreTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h" -#include "blockstore/implementations/testfake/FakeBlockStore.h" -#include "blockstore/implementations/inmemory/InMemoryBlockStore2.h" -#include "../../testutils/BlockStoreTest.h" -#include -#include - - -using blockstore::BlockStore; -using blockstore::lowtohighlevel::LowToHighLevelBlockStore; -using blockstore::inmemory::InMemoryBlockStore2; - -using cpputils::make_unique_ref; -using cpputils::unique_ref; - -class LowToHighLevelBlockStoreTestFixture: public BlockStoreTestFixture { -public: - LowToHighLevelBlockStoreTestFixture() {} - - unique_ref createBlockStore() override { - return make_unique_ref(make_unique_ref()); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(LowToHighLevel, BlockStoreTest, LowToHighLevelBlockStoreTestFixture); diff --git a/test/blockstore/implementations/mock/MockBlockStoreTest.cpp b/test/blockstore/implementations/mock/MockBlockStoreTest.cpp deleted file mode 100644 index 73fce64b..00000000 --- a/test/blockstore/implementations/mock/MockBlockStoreTest.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "blockstore/implementations/mock/MockBlock.h" -#include "blockstore/implementations/mock/MockBlockStore.h" -#include "../../testutils/BlockStoreTest.h" -#include -#include - -using blockstore::BlockStore; -using blockstore::mock::MockBlockStore; -using blockstore::testfake::FakeBlockStore; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -class MockBlockStoreTestFixture: public BlockStoreTestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref(make_unique_ref()); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(Mock, BlockStoreTest, MockBlockStoreTestFixture); diff --git a/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp b/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp deleted file mode 100644 index 9a54db8a..00000000 --- a/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Generic.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "blockstore/implementations/low2highlevel/LowToHighLevelBlockStore.h" -#include "blockstore/implementations/ondisk/OnDiskBlockStore2.h" -#include "../../testutils/BlockStoreTest.h" -#include "../../testutils/BlockStore2Test.h" -#include - -#include - - -using blockstore::BlockStore; -using blockstore::ondisk::OnDiskBlockStore2; -using blockstore::BlockStore2; -using blockstore::lowtohighlevel::LowToHighLevelBlockStore; - -using cpputils::TempDir; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -class OnDiskBlockStoreTestFixture: public BlockStoreTestFixture { -public: - OnDiskBlockStoreTestFixture(): tempdir() {} - - unique_ref createBlockStore() override { - return make_unique_ref( - make_unique_ref(tempdir.path()) - ); - } -private: - TempDir tempdir; -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(OnDisk, BlockStoreTest, OnDiskBlockStoreTestFixture); - -class OnDiskBlockStore2TestFixture: public BlockStore2TestFixture { -public: - OnDiskBlockStore2TestFixture(): tempdir() {} - - unique_ref createBlockStore() override { - return make_unique_ref(tempdir.path()); - } -private: - TempDir tempdir; -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(OnDisk, BlockStore2Test, OnDiskBlockStore2TestFixture); diff --git a/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Specific.cpp b/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Specific.cpp deleted file mode 100644 index eac53467..00000000 --- a/test/blockstore/implementations/ondisk/OnDiskBlockStoreTest_Specific.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include "blockstore/implementations/ondisk/OnDiskBlockStore2.h" -#include - -using ::testing::Test; - -using cpputils::TempDir; -using cpputils::Data; -using std::ifstream; -using blockstore::BlockId; - -using namespace blockstore::ondisk; - -class OnDiskBlockStoreTest: public Test { -public: - OnDiskBlockStoreTest(): - baseDir(), - blockStore(baseDir.path()) { - } - TempDir baseDir; - OnDiskBlockStore2 blockStore; - - blockstore::BlockId CreateBlockReturnKey(const Data &initData) { - return blockStore.create(initData.copy()); - } - - uint64_t getPhysicalBlockSize(const BlockId &blockId) { - ifstream stream((baseDir.path() / blockId.ToString().substr(0,3) / blockId.ToString().substr(3)).c_str()); - stream.seekg(0, stream.end); - return stream.tellg(); - } -}; - -TEST_F(OnDiskBlockStoreTest, PhysicalBlockSize_zerophysical) { - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(0)); -} - -TEST_F(OnDiskBlockStoreTest, PhysicalBlockSize_zerovirtual) { - auto blockId = CreateBlockReturnKey(Data(0)); - auto baseSize = getPhysicalBlockSize(blockId); - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(baseSize)); -} - -TEST_F(OnDiskBlockStoreTest, PhysicalBlockSize_negativeboundaries) { - // This tests that a potential if/else in blockSizeFromPhysicalBlockSize that catches negative values has the - // correct boundary set. We test the highest value that is negative and the smallest value that is positive. - auto physicalSizeForVirtualSizeZero = getPhysicalBlockSize(CreateBlockReturnKey(Data(0))); - if (physicalSizeForVirtualSizeZero > 0) { - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero - 1)); - } - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero)); - EXPECT_EQ(1u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero + 1)); -} - -TEST_F(OnDiskBlockStoreTest, PhysicalBlockSize_positive) { - auto blockId = CreateBlockReturnKey(Data(10*1024)); - auto baseSize = getPhysicalBlockSize(blockId); - EXPECT_EQ(10*1024u, blockStore.blockSizeFromPhysicalBlockSize(baseSize)); -} - -TEST_F(OnDiskBlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocksWithSameKeyPrefix) { - const BlockId key1 = BlockId::FromString("4CE72ECDD20877A12ADBF4E3927C0A13"); - const BlockId key2 = BlockId::FromString("4CE72ECDD20877A12ADBF4E3927C0A14"); - EXPECT_TRUE(blockStore.tryCreate(key1, cpputils::Data(0))); - EXPECT_TRUE(blockStore.tryCreate(key2, cpputils::Data(0))); - EXPECT_EQ(2u, blockStore.numBlocks()); -} diff --git a/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp b/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp deleted file mode 100644 index 1ba836aa..00000000 --- a/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockCreateTest.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include - -#include -#include - -// TODO This should be ported to BlockStore2 - -/* -using ::testing::Test; -using ::testing::WithParamInterface; -using ::testing::Values; -using cpputils::Data; -using cpputils::TempFile; -using cpputils::TempDir; -using cpputils::unique_ref; - -using namespace blockstore; -using namespace blockstore::ondisk; - -namespace bf = boost::filesystem; - -class OnDiskBlockCreateTest: public Test { -public: - OnDiskBlockCreateTest() - // Don't create the temp file yet (therefore pass false to the TempFile constructor) - : dir(), - key(BlockId::FromString("1491BB4932A389EE14BC7090AC772972")), - file(dir.path() / blockId.ToString().substr(0,3) / blockId.ToString().substr(3), false) { - } - TempDir dir; - BlockId key; - TempFile file; -}; - -TEST_F(OnDiskBlockCreateTest, CreatingBlockCreatesFile) { - EXPECT_FALSE(bf::exists(file.path())); - - auto block = OnDiskBlock::CreateOnDisk(dir.path(), blockId, Data(0)); - - EXPECT_TRUE(bf::exists(file.path())); - EXPECT_TRUE(bf::is_regular_file(file.path())); -} - -TEST_F(OnDiskBlockCreateTest, CreatingExistingBlockReturnsNull) { - auto block1 = OnDiskBlock::CreateOnDisk(dir.path(), blockId, Data(0)); - auto block2 = OnDiskBlock::CreateOnDisk(dir.path(), blockId, Data(0)); - EXPECT_TRUE((bool)block1); - EXPECT_FALSE((bool)block2); -} - -class OnDiskBlockCreateSizeTest: public OnDiskBlockCreateTest, public WithParamInterface { -public: - unique_ref block; - Data ZEROES; - - OnDiskBlockCreateSizeTest(): - block(OnDiskBlock::CreateOnDisk(dir.path(), blockId, Data(GetParam()).FillWithZeroes()).value()), - ZEROES(block->size()) - { - ZEROES.FillWithZeroes(); - } -}; -INSTANTIATE_TEST_SUITE_P(OnDiskBlockCreateSizeTest, OnDiskBlockCreateSizeTest, Values(0, 1, 5, 1024, 10*1024*1024)); - -TEST_P(OnDiskBlockCreateSizeTest, OnDiskSizeIsCorrect) { - Data fileContent = Data::LoadFromFile(file.path()).value(); - EXPECT_EQ(GetParam() + OnDiskBlock::formatVersionHeaderSize(), fileContent.size()); -} - -TEST_P(OnDiskBlockCreateSizeTest, OnDiskBlockIsZeroedOut) { - Data fileContent = Data::LoadFromFile(file.path()).value(); - Data fileContentWithoutHeader(fileContent.size() - OnDiskBlock::formatVersionHeaderSize()); - std::memcpy(fileContentWithoutHeader.data(), fileContent.dataOffset(OnDiskBlock::formatVersionHeaderSize()), fileContentWithoutHeader.size()); - EXPECT_EQ(ZEROES, fileContentWithoutHeader); -} - -// This test is also tested by OnDiskBlockStoreTest, but there the block is created using the BlockStore interface. -// Here, we create it using OnDiskBlock::CreateOnDisk() -TEST_P(OnDiskBlockCreateSizeTest, InMemorySizeIsCorrect) { - EXPECT_EQ(GetParam(), block->size()); -} - -// This test is also tested by OnDiskBlockStoreTest, but there the block is created using the BlockStore interface. -// Here, we create it using OnDiskBlock::CreateOnDisk() -TEST_P(OnDiskBlockCreateSizeTest, InMemoryBlockIsZeroedOut) { - EXPECT_EQ(0, std::memcmp(ZEROES.data(), block->data(), block->size())); -} -*/ diff --git a/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp b/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp deleted file mode 100644 index 989f3c87..00000000 --- a/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockFlushTest.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include - -#include -#include - -// TODO This should be ported to BlockStore2 -/* -using ::testing::Test; -using ::testing::WithParamInterface; -using ::testing::Values; - -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::TempFile; -using cpputils::TempDir; -using cpputils::unique_ref; - -using namespace blockstore; -using namespace blockstore::ondisk; - -namespace bf = boost::filesystem; - -class OnDiskBlockFlushTest: public Test, public WithParamInterface { -public: - OnDiskBlockFlushTest() - // Don't create the temp file yet (therefore pass false to the TempFile constructor) - : dir(), - key(BlockId::FromString("1491BB4932A389EE14BC7090AC772972")), - file(dir.path() / blockId.ToString().substr(0,3) / blockId.ToString().substr(3), false), - randomData(DataFixture::generate(GetParam())) { - } - TempDir dir; - BlockId key; - TempFile file; - - Data randomData; - - unique_ref CreateBlockAndLoadItFromDisk() { - { - OnDiskBlock::CreateOnDisk(dir.path(), blockId, randomData.copy()).value(); - } - return OnDiskBlock::LoadFromDisk(dir.path(), blockId).value(); - } - - unique_ref CreateBlock() { - return OnDiskBlock::CreateOnDisk(dir.path(), blockId, randomData.copy()).value(); - } - - void WriteDataToBlock(const unique_ref &block) { - block->write(randomData.data(), 0, randomData.size()); - } - - void EXPECT_BLOCK_DATA_CORRECT(const unique_ref &block) { - EXPECT_EQ(randomData.size(), block->size()); - EXPECT_EQ(0, std::memcmp(randomData.data(), block->data(), randomData.size())); - } - - void EXPECT_STORED_FILE_DATA_CORRECT() { - Data fileContent = Data::LoadFromFile(file.path()).value(); - Data fileContentWithoutHeader(fileContent.size() - OnDiskBlock::formatVersionHeaderSize()); - std::memcpy(fileContentWithoutHeader.data(), fileContent.dataOffset(OnDiskBlock::formatVersionHeaderSize()), fileContentWithoutHeader.size()); - EXPECT_EQ(randomData, fileContentWithoutHeader); - } -}; -INSTANTIATE_TEST_SUITE_P(OnDiskBlockFlushTest, OnDiskBlockFlushTest, Values((size_t)0, (size_t)1, (size_t)1024, (size_t)4096, (size_t)10*1024*1024)); - -// This test is also tested by OnDiskBlockStoreTest, but there the block is created using the BlockStore interface. -// Here, we create it using OnDiskBlock::CreateOnDisk() -TEST_P(OnDiskBlockFlushTest, AfterCreate_FlushingDoesntChangeBlock) { - auto block = CreateBlock(); - WriteDataToBlock(block); - - EXPECT_BLOCK_DATA_CORRECT(block); -} - -// This test is also tested by OnDiskBlockStoreTest, but there the block is created using the BlockStore interface. -// Here, we create it using OnDiskBlock::CreateOnDisk() / OnDiskBlock::LoadFromDisk() -TEST_P(OnDiskBlockFlushTest, AfterLoad_FlushingDoesntChangeBlock) { - auto block = CreateBlockAndLoadItFromDisk(); - WriteDataToBlock(block); - - EXPECT_BLOCK_DATA_CORRECT(block); -} - -TEST_P(OnDiskBlockFlushTest, AfterCreate_FlushingWritesCorrectData) { - auto block = CreateBlock(); - WriteDataToBlock(block); - - EXPECT_STORED_FILE_DATA_CORRECT(); -} - -TEST_P(OnDiskBlockFlushTest, AfterLoad_FlushingWritesCorrectData) { - auto block = CreateBlockAndLoadItFromDisk(); - WriteDataToBlock(block); - - EXPECT_STORED_FILE_DATA_CORRECT(); -} - -// This test is also tested by OnDiskBlockStoreTest, but there it can only checks block content by loading it again. -// Here, we check the content on disk. -TEST_P(OnDiskBlockFlushTest, AfterCreate_FlushesWhenDestructed) { - { - auto block = CreateBlock(); - WriteDataToBlock(block); - } - EXPECT_STORED_FILE_DATA_CORRECT(); -} - -// This test is also tested by OnDiskBlockStoreTest, but there it can only checks block content by loading it again. -// Here, we check the content on disk. -TEST_P(OnDiskBlockFlushTest, AfterLoad_FlushesWhenDestructed) { - { - auto block = CreateBlockAndLoadItFromDisk(); - WriteDataToBlock(block); - } - EXPECT_STORED_FILE_DATA_CORRECT(); -} -*/ diff --git a/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockLoadTest.cpp b/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockLoadTest.cpp deleted file mode 100644 index bf117f2e..00000000 --- a/test/blockstore/implementations/ondisk/OnDiskBlockTest/OnDiskBlockLoadTest.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include "blockstore/utils/FileDoesntExistException.h" -#include - -#include -#include -#include -#include -#include - -// TODO This should be ported to BlockStore2 -/* -using ::testing::Test; -using ::testing::WithParamInterface; -using ::testing::Values; - -using std::ofstream; -using std::ios; -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::TempFile; -using cpputils::TempDir; -using cpputils::unique_ref; - -using namespace blockstore; -using namespace blockstore::ondisk; - -namespace bf = boost::filesystem; - -class OnDiskBlockLoadTest: public Test, public WithParamInterface { -public: - OnDiskBlockLoadTest(): - dir(), - key(BlockId::FromString("1491BB4932A389EE14BC7090AC772972")), - file(dir.path() / blockId.ToString(), false) { - } - TempDir dir; - BlockId key; - TempFile file; - - void CreateBlockWithSize(size_t size) { - Data data(size); - OnDiskBlock::CreateOnDisk(dir.path(), blockId, std::move(data)); - } - - void StoreData(Data data) { - OnDiskBlock::CreateOnDisk(dir.path(), blockId, std::move(data)); - } - - unique_ref LoadBlock() { - return OnDiskBlock::LoadFromDisk(dir.path(), blockId).value(); - } - - void EXPECT_BLOCK_DATA_EQ(const Data &expected, const OnDiskBlock &actual) { - EXPECT_EQ(expected.size(), actual.size()); - EXPECT_EQ(0, std::memcmp(expected.data(), actual.data(), expected.size())); - } -}; -INSTANTIATE_TEST_SUITE_P(OnDiskBlockLoadTest, OnDiskBlockLoadTest, Values(0, 1, 5, 1024, 10*1024*1024)); - -TEST_P(OnDiskBlockLoadTest, LoadsCorrectSize) { - CreateBlockWithSize(GetParam()); - - auto block = LoadBlock(); - - EXPECT_EQ(GetParam(), block->size()); -} - -TEST_P(OnDiskBlockLoadTest, LoadedDataIsCorrect) { - Data randomData = DataFixture::generate(GetParam()); - StoreData(randomData.copy()); - - auto block = LoadBlock(); - - EXPECT_BLOCK_DATA_EQ(randomData, *block); -} - -TEST_F(OnDiskBlockLoadTest, LoadNotExistingBlock) { - BlockId key2 = BlockId::FromString("272EE5517627CFA147A971A8E6E747E0"); - EXPECT_EQ(boost::none, OnDiskBlock::LoadFromDisk(dir.path(), key2)); -} -*/ diff --git a/test/blockstore/implementations/parallelaccess/ParallelAccessBlockStoreTest_Generic.cpp b/test/blockstore/implementations/parallelaccess/ParallelAccessBlockStoreTest_Generic.cpp deleted file mode 100644 index ffcdef0e..00000000 --- a/test/blockstore/implementations/parallelaccess/ParallelAccessBlockStoreTest_Generic.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "blockstore/implementations/parallelaccess/ParallelAccessBlockStore.h" -#include "blockstore/implementations/testfake/FakeBlockStore.h" -#include "../../testutils/BlockStoreTest.h" -#include - - -using blockstore::BlockStore; -using blockstore::parallelaccess::ParallelAccessBlockStore; -using blockstore::testfake::FakeBlockStore; - -using cpputils::make_unique_ref; -using cpputils::unique_ref; - -class ParallelAccessBlockStoreTestFixture: public BlockStoreTestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref(make_unique_ref()); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(ParallelAccess, BlockStoreTest, ParallelAccessBlockStoreTestFixture); - -//TODO Add specific tests ensuring that loading the same block twice doesn't load it twice from the underlying blockstore diff --git a/test/blockstore/implementations/parallelaccess/ParallelAccessBlockStoreTest_Specific.cpp b/test/blockstore/implementations/parallelaccess/ParallelAccessBlockStoreTest_Specific.cpp deleted file mode 100644 index b59f7370..00000000 --- a/test/blockstore/implementations/parallelaccess/ParallelAccessBlockStoreTest_Specific.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include "blockstore/implementations/parallelaccess/ParallelAccessBlockStore.h" -#include "blockstore/implementations/testfake/FakeBlockStore.h" - -using ::testing::Test; - -using cpputils::Data; - -using blockstore::testfake::FakeBlockStore; - -using namespace blockstore::parallelaccess; - -class ParallelAccessBlockStoreTest: public Test { -public: - ParallelAccessBlockStoreTest(): - baseBlockStore(new FakeBlockStore), - blockStore(std::move(cpputils::nullcheck(std::unique_ptr(baseBlockStore)).value())) { - } - FakeBlockStore *baseBlockStore; - ParallelAccessBlockStore blockStore; - - blockstore::BlockId CreateBlockReturnKey(const Data &initData) { - return blockStore.create(initData)->blockId(); - } -}; - -TEST_F(ParallelAccessBlockStoreTest, PhysicalBlockSize_zerophysical) { - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(0)); -} - -TEST_F(ParallelAccessBlockStoreTest, PhysicalBlockSize_zerovirtual) { - auto blockId = CreateBlockReturnKey(Data(0)); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(base->size())); -} - -TEST_F(ParallelAccessBlockStoreTest, PhysicalBlockSize_negativeboundaries) { - // This tests that a potential if/else in blockSizeFromPhysicalBlockSize that catches negative values has the - // correct boundary set. We test the highest value that is negative and the smallest value that is positive. - auto physicalSizeForVirtualSizeZero = baseBlockStore->load(CreateBlockReturnKey(Data(0))).value()->size(); - if (physicalSizeForVirtualSizeZero > 0) { - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero - 1)); - } - EXPECT_EQ(0u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero)); - EXPECT_EQ(1u, blockStore.blockSizeFromPhysicalBlockSize(physicalSizeForVirtualSizeZero + 1)); -} - -TEST_F(ParallelAccessBlockStoreTest, PhysicalBlockSize_positive) { - auto blockId = CreateBlockReturnKey(Data(10*1024)); - auto base = baseBlockStore->load(blockId).value(); - EXPECT_EQ(10*1024u, blockStore.blockSizeFromPhysicalBlockSize(base->size())); -} diff --git a/test/blockstore/implementations/testfake/TestFakeBlockStoreTest.cpp b/test/blockstore/implementations/testfake/TestFakeBlockStoreTest.cpp deleted file mode 100644 index eabea809..00000000 --- a/test/blockstore/implementations/testfake/TestFakeBlockStoreTest.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "blockstore/implementations/testfake/FakeBlock.h" -#include "blockstore/implementations/testfake/FakeBlockStore.h" -#include "../../testutils/BlockStoreTest.h" -#include -#include - -using blockstore::BlockStore; -using blockstore::testfake::FakeBlockStore; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -class FakeBlockStoreTestFixture: public BlockStoreTestFixture { -public: - unique_ref createBlockStore() override { - return make_unique_ref(); - } -}; - -INSTANTIATE_TYPED_TEST_SUITE_P(TestFake, BlockStoreTest, FakeBlockStoreTestFixture); diff --git a/test/blockstore/interface/BlockStore2Test.cpp b/test/blockstore/interface/BlockStore2Test.cpp deleted file mode 100644 index d11230a3..00000000 --- a/test/blockstore/interface/BlockStore2Test.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "blockstore/interface/BlockStore2.h" -#include -#include -#include - -using ::testing::Test; -using ::testing::Return; -using ::testing::Invoke; -using ::testing::Eq; -using ::testing::ByRef; - -using std::string; -using cpputils::Data; -using cpputils::DataFixture; -using boost::optional; - -namespace boost { - inline void PrintTo(const optional &, ::std::ostream *os) { - *os << "optional"; - } -} - -using namespace blockstore; - -class BlockStore2Mock: public BlockStore2 { -public: - MOCK_METHOD(BlockId, createBlockId, (), (const, override)); - MOCK_METHOD(bool, tryCreate, (const BlockId &blockId, const cpputils::Data &data), (override)); - MOCK_METHOD(void, store, (const BlockId &, const Data &data), (override)); - MOCK_METHOD(optional, load, (const BlockId &), (const, override)); - MOCK_METHOD(bool, remove, (const BlockId &), (override)); - MOCK_METHOD(uint64_t, numBlocks, (), (const, override)); - MOCK_METHOD(uint64_t, estimateNumFreeBytes, (), (const, override)); - MOCK_METHOD(uint64_t, blockSizeFromPhysicalBlockSize, (uint64_t), (const, override)); - MOCK_METHOD(void, forEachBlock, (std::function), (const, override)); -}; - -class BlockStore2Test: public Test { -public: - BlockStore2Test() :blockStoreMock(), blockStore(blockStoreMock), - blockId1(BlockId::FromString("1491BB4932A389EE14BC7090AC772972")), - blockId2(BlockId::FromString("AC772971491BB4932A389EE14BC7090A")), - blockId3(BlockId::FromString("1BB4932A38AC77C7090A2971499EE14B")) {} - - BlockStore2Mock blockStoreMock; - BlockStore2 &blockStore; - const BlockId blockId1; - const BlockId blockId2; - const BlockId blockId3; - - Data createDataWithSize(size_t size) { - Data fixture(DataFixture::generate(size)); - Data data(size); - std::memcpy(data.data(), fixture.data(), size); - return data; - } -}; - -TEST_F(BlockStore2Test, DataIsPassedThrough0) { - Data data = createDataWithSize(0); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))).WillOnce(Return(true)); - EXPECT_EQ(blockId1, blockStore.create(data)); -} - -TEST_F(BlockStore2Test, DataIsPassedThrough1) { - Data data = createDataWithSize(1); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))).WillOnce(Return(true)); - EXPECT_EQ(blockId1, blockStore.create(data)); -} - -TEST_F(BlockStore2Test, DataIsPassedThrough1024) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))).WillOnce(Return(true)); - EXPECT_EQ(blockId1, blockStore.create(data)); -} - -TEST_F(BlockStore2Test, BlockIdIsCorrect) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(blockId1, testing::_)).WillOnce(Return(true)); - EXPECT_EQ(blockId1, blockStore.create(data)); -} - -TEST_F(BlockStore2Test, TwoBlocksGetDifferentIds) { - EXPECT_CALL(blockStoreMock, createBlockId()) - .WillOnce(Return(blockId1)) - .WillOnce(Return(blockId2)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, testing::_)) - .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { - EXPECT_EQ(blockId1, blockId); - return true; - })) - .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { - EXPECT_EQ(blockId2, blockId); - return true; - })); - - Data data = createDataWithSize(1024); - EXPECT_EQ(blockId1, blockStore.create(data)); - EXPECT_EQ(blockId2, blockStore.create(data)); -} - -TEST_F(BlockStore2Test, WillTryADifferentIdIfKeyAlreadyExists) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()) - .WillOnce(Return(blockId1)) - .WillOnce(Return(blockId2)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))) - .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { - EXPECT_EQ(blockId1, blockId); - return false; - })) - .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { - EXPECT_EQ(blockId2, blockId); - return true; - })); - - EXPECT_EQ(blockId2, blockStore.create(data)); -} - -TEST_F(BlockStore2Test, WillTryADifferentIdIfIdAlreadyExistsTwoTimes) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()) - .WillOnce(Return(blockId1)) - .WillOnce(Return(blockId2)) - .WillOnce(Return(blockId3)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))) - .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { - EXPECT_EQ(blockId1, blockId); - return false; - })) - .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { - EXPECT_EQ(blockId2, blockId); - return false; - })) - .WillOnce(Invoke([this](const BlockId &blockId, const Data &) { - EXPECT_EQ(blockId3, blockId); - return true; - })); - - EXPECT_EQ(blockId3, blockStore.create(data)); -} diff --git a/test/blockstore/interface/BlockStoreTest.cpp b/test/blockstore/interface/BlockStoreTest.cpp deleted file mode 100644 index 65f375d8..00000000 --- a/test/blockstore/interface/BlockStoreTest.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "blockstore/interface/BlockStore.h" -#include -#include -#include -#include - -using ::testing::Test; -using ::testing::Return; -using ::testing::Invoke; -using ::testing::Eq; -using ::testing::ByRef; -using ::testing::Action; - -using std::string; -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using boost::optional; - -using namespace blockstore; - -class BlockStoreMock: public BlockStore { -public: - MOCK_METHOD(BlockId, createBlockId, (), (override)); - MOCK_METHOD(optional>, tryCreate, (const BlockId &, Data data), (override)); - MOCK_METHOD(unique_ref, overwrite, (const BlockId &, Data data), (override)); - MOCK_METHOD(optional>, load, (const BlockId &), (override)); - MOCK_METHOD(void, remove, (unique_ref), (override)); - MOCK_METHOD(void, remove, (const BlockId &), (override)); - MOCK_METHOD(uint64_t, numBlocks, (), (const, override)); - MOCK_METHOD(uint64_t, estimateNumFreeBytes, (), (const, override)); - MOCK_METHOD(uint64_t, blockSizeFromPhysicalBlockSize, (uint64_t), (const, override)); - MOCK_METHOD(void, forEachBlock, (std::function), (const, override)); -}; - -class BlockMock: public Block { -public: - BlockMock(): Block(BlockId::Random()) {} - MOCK_METHOD(const void*, data, (), (const, override)); - MOCK_METHOD(void, write, (const void*, uint64_t, uint64_t), (override)); - MOCK_METHOD(void, flush, (), (override)); - MOCK_METHOD(size_t, size, (), (const, override)); - MOCK_METHOD(void, resize, (size_t), (override)); -}; - -class BlockStoreTest: public Test { -public: - BlockStoreTest() :blockStoreMock(), blockStore(blockStoreMock), - blockId1(BlockId::FromString("1491BB4932A389EE14BC7090AC772972")), - blockId2(BlockId::FromString("AC772971491BB4932A389EE14BC7090A")), - blockId3(BlockId::FromString("1BB4932A38AC77C7090A2971499EE14B")) {} - - BlockStoreMock blockStoreMock; - BlockStore &blockStore; - const BlockId blockId1; - const BlockId blockId2; - const BlockId blockId3; - - Data createDataWithSize(size_t size) { - Data fixture(DataFixture::generate(size)); - Data data(size); - std::memcpy(data.data(), fixture.data(), size); - return data; - } -}; - -const Action>(const BlockId &, cpputils::Data)> ReturnNewBlockMock = Invoke( - [] (const BlockId&, cpputils::Data) { - return optional>(unique_ref(make_unique_ref())); - }); - -TEST_F(BlockStoreTest, DataIsPassedThrough0) { - Data data = createDataWithSize(0); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))).WillOnce(ReturnNewBlockMock); - blockStore.create(data); -} - -TEST_F(BlockStoreTest, DataIsPassedThrough1) { - Data data = createDataWithSize(1); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))).WillOnce(ReturnNewBlockMock); - blockStore.create(data); -} - -TEST_F(BlockStoreTest, DataIsPassedThrough1024) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))).WillOnce(ReturnNewBlockMock); - blockStore.create(data); -} - -TEST_F(BlockStoreTest, BlockIdIsCorrect) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()).WillOnce(Return(blockId1)); - EXPECT_CALL(blockStoreMock, tryCreate(blockId1, testing::_)).WillOnce(ReturnNewBlockMock); - blockStore.create(data); -} - -TEST_F(BlockStoreTest, TwoBlocksGetDifferentIds) { - EXPECT_CALL(blockStoreMock, createBlockId()) - .WillOnce(Return(blockId1)) - .WillOnce(Return(blockId2)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, testing::_)) - .WillOnce(Invoke([this](const BlockId &blockId, Data) { - EXPECT_EQ(blockId1, blockId); - return optional>(unique_ref(make_unique_ref())); - })) - .WillOnce(Invoke([this](const BlockId &blockId, Data) { - EXPECT_EQ(blockId2, blockId); - return optional>(unique_ref(make_unique_ref())); - })); - - Data data = createDataWithSize(1024); - blockStore.create(data); - blockStore.create(data); -} - -TEST_F(BlockStoreTest, WillTryADifferentIdIfKeyAlreadyExists) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()) - .WillOnce(Return(blockId1)) - .WillOnce(Return(blockId2)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))) - .WillOnce(Invoke([this](const BlockId &blockId, Data ) { - EXPECT_EQ(blockId1, blockId); - return boost::none; - })) - .WillOnce(Invoke([this](const BlockId &blockId, Data ) { - EXPECT_EQ(blockId2, blockId); - return optional>(unique_ref(make_unique_ref())); - })); - - blockStore.create(data); -} - -TEST_F(BlockStoreTest, WillTryADifferentIdIfIdAlreadyExistsTwoTimes) { - Data data = createDataWithSize(1024); - EXPECT_CALL(blockStoreMock, createBlockId()) - .WillOnce(Return(blockId1)) - .WillOnce(Return(blockId2)) - .WillOnce(Return(blockId3)); - EXPECT_CALL(blockStoreMock, tryCreate(testing::_, Eq(ByRef(data)))) - .WillOnce(Invoke([this](const BlockId &blockId, Data) { - EXPECT_EQ(blockId1, blockId); - return boost::none; - })) - .WillOnce(Invoke([this](const BlockId &blockId, Data) { - EXPECT_EQ(blockId2, blockId); - return boost::none; - })) - .WillOnce(Invoke([this](const BlockId &blockId, Data) { - EXPECT_EQ(blockId3, blockId); - return optional>(unique_ref(make_unique_ref())); - })); - - blockStore.create(data); -} diff --git a/test/blockstore/interface/BlockTest.cpp b/test/blockstore/interface/BlockTest.cpp deleted file mode 100644 index a2db4214..00000000 --- a/test/blockstore/interface/BlockTest.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Tests that the header can be included without needing additional header includes as dependencies. - */ -#include "blockstore/interface/Block.h" diff --git a/test/blockstore/testutils/BlockStore2Test.h b/test/blockstore/testutils/BlockStore2Test.h deleted file mode 100644 index d6de1b7d..00000000 --- a/test/blockstore/testutils/BlockStore2Test.h +++ /dev/null @@ -1,479 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORE2TEST_H_ -#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORE2TEST_H_ - -#include -#include -#include -#include - -#include "blockstore/interface/BlockStore2.h" - -namespace boost { -inline void PrintTo(const optional &, ::std::ostream *os) { - *os << "optional"; -} -} - -class BlockStore2TestFixture { -public: - virtual ~BlockStore2TestFixture() {} - virtual cpputils::unique_ref createBlockStore() = 0; -}; - -template -class BlockStore2Test: public ::testing::Test { -public: - BlockStore2Test() :fixture(), blockStore(this->fixture.createBlockStore()) {} - - BOOST_STATIC_ASSERT_MSG( - (std::is_base_of::value), - "Given test fixture for instantiating the (type parameterized) BlockStoreTest must inherit from BlockStoreTestFixture" - ); - - ConcreteBlockStoreTestFixture fixture; - cpputils::unique_ref blockStore; - - template - void EXPECT_UNORDERED_EQ(const std::vector &expected, std::vector actual) { - EXPECT_EQ(expected.size(), actual.size()); - for (const Entry &expectedEntry : expected) { - removeOne(&actual, expectedEntry); - } - } - - template - void removeOne(std::vector *entries, const Entry &toRemove) { - auto found = std::find(entries->begin(), entries->end(), toRemove); - if (found != entries->end()) { - entries->erase(found); - return; - } - EXPECT_TRUE(false); - } -}; - -TYPED_TEST_SUITE_P(BlockStore2Test); - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCallingTryCreateOnExistingBlock_thenFails) { - blockstore::BlockId blockId = this->blockStore->create(cpputils::Data(1024)); - EXPECT_FALSE(this->blockStore->tryCreate(blockId, cpputils::Data(1024))); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds) { - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_TRUE(this->blockStore->tryCreate(blockId, cpputils::Data(1024))); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds) { - this->blockStore->create(cpputils::Data(512)); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_TRUE(this->blockStore->tryCreate(blockId, cpputils::Data(1024))); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenLoadExistingBlock_thenSucceeds) { - blockstore::BlockId blockId = this->blockStore->create(cpputils::Data(1024)); - EXPECT_NE(boost::none, this->blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenLoadNonexistingBlock_thenFails) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_EQ(boost::none, this->blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenLoadNonexistingBlock_thenFails) { - this->blockStore->create(cpputils::Data(512)); - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_EQ(boost::none, this->blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringExistingBlock_thenSucceeds) { - blockstore::BlockId blockId = this->blockStore->create(cpputils::Data(1024)); - this->blockStore->store(blockId, cpputils::Data(1024)); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - this->blockStore->store(blockId, cpputils::Data(1024)); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds) { - this->blockStore->create(cpputils::Data(512)); - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - this->blockStore->store(blockId, cpputils::Data(1024)); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCreatingTwoBlocks_thenTheyGetDifferentKeys) { - blockstore::BlockId blockId1 = this->blockStore->create(cpputils::Data(1024)); - blockstore::BlockId blockId2 = this->blockStore->create(cpputils::Data(1024)); - EXPECT_NE(blockId1, blockId2); -} - -TYPED_TEST_P(BlockStore2Test, givenOtherwiseEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore) { - blockstore::BlockId blockId = this->blockStore->create(cpputils::Data(1024)); - EXPECT_NE(boost::none, this->blockStore->load(blockId)); - EXPECT_TRUE(this->blockStore->remove(blockId)); - EXPECT_EQ(boost::none, this->blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore) { - blockstore::BlockId blockId = this->blockStore->create(cpputils::Data(1024)); - this->blockStore->create(cpputils::Data(512)); - EXPECT_NE(boost::none, this->blockStore->load(blockId)); - EXPECT_TRUE(this->blockStore->remove(blockId)); - EXPECT_EQ(boost::none, this->blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenOtherwiseEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds) { - blockstore::BlockId blockId = this->blockStore->create(cpputils::Data(1024)); - EXPECT_TRUE(this->blockStore->remove(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds) { - blockstore::BlockId blockId = this->blockStore->create(cpputils::Data(1024)); - this->blockStore->create(cpputils::Data(512)); - EXPECT_EQ(true, this->blockStore->remove(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenRemovingNonexistingBlock_thenFails) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - auto result = this->blockStore->remove(blockId); - EXPECT_EQ(false, result); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenRemovingNonexistingBlock_thenFails) { - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772973"); - blockstore::BlockId differentKey = blockstore::BlockId::FromString("290AC2C7097274A389EE14B91B72B493"); - ASSERT_TRUE(this->blockStore->tryCreate(blockId, cpputils::Data(1024))); - EXPECT_EQ(false, this->blockStore->remove(differentKey)); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads) { - auto blockId = this->blockStore->create(cpputils::Data(0)); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads) { - this->blockStore->create(cpputils::Data(512)); - auto blockId = this->blockStore->create(cpputils::Data(0)); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads) { - cpputils::Data data = cpputils::DataFixture::generate(1024); - auto blockId = this->blockStore->create(data.copy()); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(loaded, data); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads) { - this->blockStore->create(cpputils::Data(512)); - cpputils::Data data = cpputils::DataFixture::generate(1024); - auto blockId = this->blockStore->create(data.copy()); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(loaded, data); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenTryCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads) { - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772973"); - ASSERT_TRUE(this->blockStore->tryCreate(blockId, cpputils::Data(0))); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenTryCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads) { - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772973"); - this->blockStore->create(cpputils::Data(512)); - ASSERT_TRUE(this->blockStore->tryCreate(blockId, cpputils::Data(0))); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenTryCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads) { - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772973"); - cpputils::Data data = cpputils::DataFixture::generate(1024); - ASSERT_TRUE(this->blockStore->tryCreate(blockId, data.copy())); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(loaded, data); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenTryCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads) { - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772973"); - this->blockStore->create(cpputils::Data(512)); - cpputils::Data data = cpputils::DataFixture::generate(1024); - ASSERT_TRUE(this->blockStore->tryCreate(blockId, data.copy())); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(loaded, data); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - this->blockStore->store(blockId, cpputils::Data(0)); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads) { - this->blockStore->create(cpputils::Data(512)); - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - this->blockStore->store(blockId, cpputils::Data(0)); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - cpputils::Data data = cpputils::DataFixture::generate(1024); - this->blockStore->store(blockId, data.copy()); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(data, loaded); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads) { - this->blockStore->create(cpputils::Data(512)); - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - cpputils::Data data = cpputils::DataFixture::generate(1024); - this->blockStore->store(blockId, data.copy()); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(data, loaded); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads) { - auto blockId = this->blockStore->create(cpputils::Data(512)); - this->blockStore->store(blockId, cpputils::Data(0)); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads) { - this->blockStore->create(cpputils::Data(512)); - auto blockId = this->blockStore->create(cpputils::Data(512)); - this->blockStore->store(blockId, cpputils::Data(0)); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(0u, loaded.size()); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads) { - auto blockId = this->blockStore->create(cpputils::Data(512)); - cpputils::Data data = cpputils::DataFixture::generate(1024); - this->blockStore->store(blockId, data.copy()); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(data, loaded); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads) { - this->blockStore->create(cpputils::Data(512)); - auto blockId = this->blockStore->create(cpputils::Data(512)); - cpputils::Data data = cpputils::DataFixture::generate(1024); - this->blockStore->store(blockId, data.copy()); - auto loaded = this->blockStore->load(blockId).value(); - EXPECT_EQ(data, loaded); -} - -TYPED_TEST_P(BlockStore2Test, givenEmptyBlockStore_whenLoadingNonExistingBlock_thenFails) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_EQ(boost::none, this->blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, givenNonEmptyBlockStore_whenLoadingNonExistingBlock_thenFails) { - this->blockStore->create(cpputils::Data(512)); - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_EQ(boost::none, this->blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStore2Test, NumBlocksIsCorrectOnEmptyBlockstore) { - auto blockStore = this->fixture.createBlockStore(); - EXPECT_EQ(0u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStore2Test, NumBlocksIsCorrectAfterCreatingOneBlock) { - auto blockStore = this->fixture.createBlockStore(); - blockStore->create(cpputils::Data(1)); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStore2Test, NumBlocksIsCorrectAfterRemovingTheLastBlock) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockStore->create(cpputils::Data(1)); - EXPECT_TRUE(blockStore->remove(blockId)); - EXPECT_EQ(0u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStore2Test, NumBlocksIsCorrectAfterCreatingTwoBlocks) { - auto blockStore = this->fixture.createBlockStore(); - blockStore->create(cpputils::Data(1)); - blockStore->create(cpputils::Data(0)); - EXPECT_EQ(2u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStore2Test, NumBlocksIsCorrectAfterRemovingABlock) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockStore->create(cpputils::Data(1)); - blockStore->create(cpputils::Data(1)); - EXPECT_TRUE(blockStore->remove(blockId)); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStore2Test, NumBlocksIsCorrectAfterStoringANewBlock) { - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - auto blockStore = this->fixture.createBlockStore(); - blockStore->store(blockId, cpputils::Data(1)); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStore2Test, NumBlocksIsCorrectAfterStoringAnExistingBlock) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockStore->create(cpputils::Data(1)); - blockStore->store(blockId, cpputils::Data(1)); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStore2Test, ForEachBlock_zeroblocks) { - auto blockStore = this->fixture.createBlockStore(); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStore2Test, ForEachBlock_oneblock) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId = blockStore->create(cpputils::Data(1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({blockId}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStore2Test, ForEachBlock_twoblocks) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId1 = blockStore->create(cpputils::Data(1)); - auto blockId2 = blockStore->create(cpputils::Data(1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({blockId1, blockId2}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStore2Test, ForEachBlock_threeblocks) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId1 = blockStore->create(cpputils::Data(1)); - auto blockId2 = blockStore->create(cpputils::Data(1)); - auto blockId3 = blockStore->create(cpputils::Data(1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({blockId1, blockId2, blockId3}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStore2Test, ForEachBlock_doesntListRemovedBlocks_oneblock) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId1 = blockStore->create(cpputils::Data(1)); - EXPECT_TRUE(blockStore->remove(blockId1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStore2Test, ForEachBlock_doesntListRemovedBlocks_twoblocks) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId1 = blockStore->create(cpputils::Data(1)); - auto blockId2 = blockStore->create(cpputils::Data(1)); - EXPECT_TRUE(blockStore->remove(blockId1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({blockId2}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStore2Test, TryCreateTwoBlocksWithSameBlockIdAndSameSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_TRUE(blockStore->tryCreate(blockId, cpputils::Data(1024))); - EXPECT_FALSE(blockStore->tryCreate(blockId, cpputils::Data(1024))); -} - -TYPED_TEST_P(BlockStore2Test, TryCreateTwoBlocksWithSameBlockIdAndDifferentSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_TRUE(blockStore->tryCreate(blockId, cpputils::Data(1024))); - EXPECT_FALSE(blockStore->tryCreate(blockId, cpputils::Data(4096))); -} - -TYPED_TEST_P(BlockStore2Test, TryCreateTwoBlocksWithSameBlockIdAndFirstNullSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_TRUE(blockStore->tryCreate(blockId, cpputils::Data(0))); - EXPECT_FALSE(blockStore->tryCreate(blockId, cpputils::Data(1024))); -} -/* -TYPED_TEST_P(BlockStore2Test, TryCreateTwoBlocksWithSameBlockIdAndSecondNullSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_TRUE(blockStore->tryCreate(blockId, cpputils::Data(1024))); - EXPECT_FALSE(blockStore->tryCreate(blockId, cpputils::Data(0))); -} - -TYPED_TEST_P(BlockStore2Test, TryCreateTwoBlocksWithSameBlockIdAndBothNullSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - EXPECT_TRUE(blockStore->tryCreate(blockId, cpputils::Data(0))); - EXPECT_FALSE(blockStore->tryCreate(blockId, cpputils::Data(0))); -}*/ - -REGISTER_TYPED_TEST_SUITE_P(BlockStore2Test, - givenNonEmptyBlockStore_whenCallingTryCreateOnExistingBlock_thenFails, - givenEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds, - givenNonEmptyBlockStore_whenCallingTryCreateOnNonExistingBlock_thenSucceeds, - givenNonEmptyBlockStore_whenLoadExistingBlock_thenSucceeds, - givenEmptyBlockStore_whenLoadNonexistingBlock_thenFails, - givenNonEmptyBlockStore_whenLoadNonexistingBlock_thenFails, - givenNonEmptyBlockStore_whenStoringExistingBlock_thenSucceeds, - givenEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds, - givenNonEmptyBlockStore_whenStoringNonexistingBlock_thenSucceeds, - givenEmptyBlockStore_whenCreatingTwoBlocks_thenTheyGetDifferentKeys, - givenOtherwiseEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore, - givenNonEmptyBlockStore_whenRemovingBlock_thenBlockIsNotLoadableAnymore, - givenOtherwiseEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds, - givenNonEmptyBlockStore_whenRemovingExistingBlock_thenSucceeds, - givenEmptyBlockStore_whenRemovingNonexistingBlock_thenFails, - givenNonEmptyBlockStore_whenRemovingNonexistingBlock_thenFails, - givenEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenTryCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenTryCreatingAndLoadingEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenTryCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenTryCreatingAndLoadingNonEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenStoringAndLoadingNonExistingNonEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenStoringAndLoadingExistingEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads, - givenNonEmptyBlockStore_whenStoringAndLoadingExistingNonEmptyBlock_thenCorrectBlockLoads, - givenEmptyBlockStore_whenLoadingNonExistingBlock_thenFails, - givenNonEmptyBlockStore_whenLoadingNonExistingBlock_thenFails, - NumBlocksIsCorrectOnEmptyBlockstore, - NumBlocksIsCorrectAfterCreatingOneBlock, - NumBlocksIsCorrectAfterRemovingTheLastBlock, - NumBlocksIsCorrectAfterCreatingTwoBlocks, - NumBlocksIsCorrectAfterRemovingABlock, - NumBlocksIsCorrectAfterStoringANewBlock, - NumBlocksIsCorrectAfterStoringAnExistingBlock, - ForEachBlock_zeroblocks, - ForEachBlock_oneblock, - ForEachBlock_twoblocks, - ForEachBlock_threeblocks, - ForEachBlock_doesntListRemovedBlocks_oneblock, - ForEachBlock_doesntListRemovedBlocks_twoblocks, - TryCreateTwoBlocksWithSameBlockIdAndSameSize, - TryCreateTwoBlocksWithSameBlockIdAndDifferentSize, - TryCreateTwoBlocksWithSameBlockIdAndFirstNullSize - //TODO Just disabled because gtest doesn't allow more template parameters. Fix and reenable! - // see https://github.com/google/googletest/issues/1267 - //TryCreateTwoBlocksWithSameBlockIdAndSecondNullSize, - //TryCreateTwoBlocksWithSameBlockIdAndBothNullSize -); - - -#endif diff --git a/test/blockstore/testutils/BlockStoreTest.h b/test/blockstore/testutils/BlockStoreTest.h deleted file mode 100644 index 190c9741..00000000 --- a/test/blockstore/testutils/BlockStoreTest.h +++ /dev/null @@ -1,406 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORETEST_H_ -#define MESSMER_BLOCKSTORE_TEST_IMPLEMENTATIONS_TESTUTILS_BLOCKSTORETEST_H_ - -#include -#include -#include -#include - -#include "blockstore/interface/BlockStore.h" - -class MockForEachBlockCallback final { -public: - std::function callback() { - return [this] (const blockstore::BlockId &blockId) { - called_with.push_back(blockId); - }; - } - - std::vector called_with; -}; - -class BlockStoreTestFixture { -public: - virtual ~BlockStoreTestFixture() {} - virtual cpputils::unique_ref createBlockStore() = 0; -}; - -template -class BlockStoreTest: public ::testing::Test { -public: - BlockStoreTest() :fixture() {} - - BOOST_STATIC_ASSERT_MSG( - (std::is_base_of::value), - "Given test fixture for instantiating the (type parameterized) BlockStoreTest must inherit from BlockStoreTestFixture" - ); - - ConcreteBlockStoreTestFixture fixture; - - void TestBlockIsUsable(cpputils::unique_ref block, blockstore::BlockStore *blockStore) { - // Write full block space and check it was correctly written - cpputils::Data fixture = cpputils::DataFixture::generate(block->size()); - block->write(fixture.data(), 0, fixture.size()); - EXPECT_EQ(0, std::memcmp(fixture.data(), block->data(), fixture.size())); - - // Store and reload block and check data is still correct - auto blockId = block->blockId(); - cpputils::destruct(std::move(block)); - block = blockStore->load(blockId).value(); - EXPECT_EQ(0, std::memcmp(fixture.data(), block->data(), fixture.size())); - } - - template - void EXPECT_UNORDERED_EQ(const std::vector &expected, std::vector actual) { - EXPECT_EQ(expected.size(), actual.size()); - for (const Entry &expectedEntry : expected) { - removeOne(&actual, expectedEntry); - } - } - - template - void removeOne(std::vector *entries, const Entry &toRemove) { - auto found = std::find(entries->begin(), entries->end(), toRemove); - if (found != entries->end()) { - entries->erase(found); - return; - } - EXPECT_TRUE(false); - } -}; - -TYPED_TEST_SUITE_P(BlockStoreTest); - -TYPED_TEST_P(BlockStoreTest, TwoCreatedBlocksHaveDifferentBlockIds) { - auto blockStore = this->fixture.createBlockStore(); - auto block1 = blockStore->create(cpputils::Data(1024)); - auto block2 = blockStore->create(cpputils::Data(1024)); - EXPECT_NE(block1->blockId(), block2->blockId()); -} - -TYPED_TEST_P(BlockStoreTest, BlockIsNotLoadableAfterDeleting_DeleteByBlock) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId = blockStore->create(cpputils::Data(1024))->blockId(); - auto block = blockStore->load(blockId); - EXPECT_NE(boost::none, block); - blockStore->remove(std::move(*block)); - EXPECT_EQ(boost::none, blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStoreTest, BlockIsNotLoadableAfterDeleting_DeleteByBlockId) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId = blockStore->create(cpputils::Data(1024))->blockId(); - blockStore->remove(blockId); - EXPECT_EQ(boost::none, blockStore->load(blockId)); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectOnEmptyBlockstore) { - auto blockStore = this->fixture.createBlockStore(); - EXPECT_EQ(0u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(1)); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingOneBlock_AfterClosingBlock) { - auto blockStore = this->fixture.createBlockStore(); - blockStore->create(cpputils::Data(1)); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingTheLastBlock_DeleteByBlock) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(1)); - blockStore->remove(std::move(block)); - EXPECT_EQ(0u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingTheLastBlock_DeleteByBlockId) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId = blockStore->create(cpputils::Data(1))->blockId(); - blockStore->remove(blockId); - EXPECT_EQ(0u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks) { - auto blockStore = this->fixture.createBlockStore(); - auto block1 = blockStore->create(cpputils::Data(1)); - auto block2 = blockStore->create(cpputils::Data(0)); - EXPECT_EQ(2u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingFirstBlock) { - auto blockStore = this->fixture.createBlockStore(); - blockStore->create(cpputils::Data(1)); - auto block2 = blockStore->create(cpputils::Data(0)); - EXPECT_EQ(2u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingSecondBlock) { - auto blockStore = this->fixture.createBlockStore(); - auto block1 = blockStore->create(cpputils::Data(1)); - blockStore->create(cpputils::Data(0)); - EXPECT_EQ(2u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingBothBlocks) { - auto blockStore = this->fixture.createBlockStore(); - blockStore->create(cpputils::Data(1)); - blockStore->create(cpputils::Data(0)); - EXPECT_EQ(2u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock_DeleteByBlock) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(1)); - blockStore->create(cpputils::Data(1)); - blockStore->remove(std::move(block)); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, NumBlocksIsCorrectAfterRemovingABlock_DeleteByBlockId) { - auto blockStore = this->fixture.createBlockStore(); - auto blockId = blockStore->create(cpputils::Data(1))->blockId(); - blockStore->create(cpputils::Data(1)); - blockStore->remove(blockId); - EXPECT_EQ(1u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, CanRemoveModifiedBlock) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(5)); - block->write("data", 0, 4); - blockStore->remove(std::move(block)); - EXPECT_EQ(0u, blockStore->numBlocks()); -} - -TYPED_TEST_P(BlockStoreTest, ForEachBlock_zeroblocks) { - auto blockStore = this->fixture.createBlockStore(); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStoreTest, ForEachBlock_oneblock) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({block->blockId()}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStoreTest, ForEachBlock_twoblocks) { - auto blockStore = this->fixture.createBlockStore(); - auto block1 = blockStore->create(cpputils::Data(1)); - auto block2 = blockStore->create(cpputils::Data(1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({block1->blockId(), block2->blockId()}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStoreTest, ForEachBlock_threeblocks) { - auto blockStore = this->fixture.createBlockStore(); - auto block1 = blockStore->create(cpputils::Data(1)); - auto block2 = blockStore->create(cpputils::Data(1)); - auto block3 = blockStore->create(cpputils::Data(1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({block1->blockId(), block2->blockId(), block3->blockId()}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStoreTest, ForEachBlock_doesntListRemovedBlocks_oneblock) { - auto blockStore = this->fixture.createBlockStore(); - auto block1 = blockStore->create(cpputils::Data(1)); - blockStore->remove(std::move(block1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStoreTest, ForEachBlock_doesntListRemovedBlocks_twoblocks) { - auto blockStore = this->fixture.createBlockStore(); - auto block1 = blockStore->create(cpputils::Data(1)); - auto block2 = blockStore->create(cpputils::Data(1)); - blockStore->remove(std::move(block1)); - MockForEachBlockCallback mockForEachBlockCallback; - blockStore->forEachBlock(mockForEachBlockCallback.callback()); - this->EXPECT_UNORDERED_EQ({block2->blockId()}, mockForEachBlockCallback.called_with); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Larger_FromZero) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(0)); - block->resize(10); - EXPECT_EQ(10u, block->size()); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Larger_FromZero_BlockIsStillUsable) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(0)); - block->resize(10); - this->TestBlockIsUsable(std::move(block), blockStore.get()); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Larger) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(10)); - block->resize(20); - EXPECT_EQ(20u, block->size()); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Larger_BlockIsStillUsable) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(10)); - block->resize(20); - this->TestBlockIsUsable(std::move(block), blockStore.get()); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Smaller) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(10)); - block->resize(5); - EXPECT_EQ(5u, block->size()); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Smaller_BlockIsStillUsable) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(10)); - block->resize(5); - this->TestBlockIsUsable(std::move(block), blockStore.get()); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Smaller_ToZero) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(10)); - block->resize(0); - EXPECT_EQ(0u, block->size()); -} - -TYPED_TEST_P(BlockStoreTest, Resize_Smaller_ToZero_BlockIsStillUsable) { - auto blockStore = this->fixture.createBlockStore(); - auto block = blockStore->create(cpputils::Data(10)); - block->resize(0); - this->TestBlockIsUsable(std::move(block), blockStore.get()); -} -/* -TYPED_TEST_P(BlockStoreTest, TryCreateTwoBlocksWithSameBlockIdAndSameSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - auto block = blockStore->tryCreate(blockId, cpputils::Data(1024)); - (*block)->flush(); //TODO Ideally, flush shouldn't be necessary here. - auto block2 = blockStore->tryCreate(blockId, cpputils::Data(1024)); - EXPECT_NE(boost::none, block); - EXPECT_EQ(boost::none, block2); -} - -TYPED_TEST_P(BlockStoreTest, TryCreateTwoBlocksWithSameBlockIdAndDifferentSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - auto block = blockStore->tryCreate(blockId, cpputils::Data(1024)); - (*block)->flush(); //TODO Ideally, flush shouldn't be necessary here. - auto block2 = blockStore->tryCreate(blockId, cpputils::Data(4096)); - EXPECT_NE(boost::none, block); - EXPECT_EQ(boost::none, block2); -} - -TYPED_TEST_P(BlockStoreTest, TryCreateTwoBlocksWithSameBlockIdAndFirstNullSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - auto block = blockStore->tryCreate(blockId, cpputils::Data(0)); - (*block)->flush(); //TODO Ideally, flush shouldn't be necessary here. - auto block2 = blockStore->tryCreate(blockId, cpputils::Data(1024)); - EXPECT_NE(boost::none, block); - EXPECT_EQ(boost::none, block2); -} - -TYPED_TEST_P(BlockStoreTest, TryCreateTwoBlocksWithSameBlockIdAndSecondNullSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - auto block = blockStore->tryCreate(blockId, cpputils::Data(1024)); - (*block)->flush(); //TODO Ideally, flush shouldn't be necessary here. - auto block2 = blockStore->tryCreate(blockId, cpputils::Data(0)); - EXPECT_NE(boost::none, block); - EXPECT_EQ(boost::none, block2); -} - -TYPED_TEST_P(BlockStoreTest, TryCreateTwoBlocksWithSameBlockIdAndBothNullSize) { - auto blockStore = this->fixture.createBlockStore(); - blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - auto block = blockStore->tryCreate(blockId, cpputils::Data(0)); - (*block)->flush(); //TODO Ideally, flush shouldn't be necessary here. - auto block2 = blockStore->tryCreate(blockId, cpputils::Data(0)); - EXPECT_NE(boost::none, block); - EXPECT_EQ(boost::none, block2); -}*/ - -#include "BlockStoreTest_Size.h" -#include "BlockStoreTest_Data.h" - - -REGISTER_TYPED_TEST_SUITE_P(BlockStoreTest, - CreatedBlockHasCorrectSize, - LoadingUnchangedBlockHasCorrectSize, - CreatedBlockData, - LoadingUnchangedBlockData, - LoadedBlockIsCorrect, -// LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing, - AfterCreate_FlushingDoesntChangeBlock, - AfterLoad_FlushingDoesntChangeBlock, - AfterCreate_FlushesWhenDestructed, - AfterLoad_FlushesWhenDestructed, - LoadNonExistingBlock, - TwoCreatedBlocksHaveDifferentBlockIds, - BlockIsNotLoadableAfterDeleting_DeleteByBlock, - BlockIsNotLoadableAfterDeleting_DeleteByBlockId, - NumBlocksIsCorrectOnEmptyBlockstore, - NumBlocksIsCorrectAfterAddingOneBlock, - NumBlocksIsCorrectAfterAddingOneBlock_AfterClosingBlock, - NumBlocksIsCorrectAfterRemovingTheLastBlock_DeleteByBlock, - NumBlocksIsCorrectAfterRemovingTheLastBlock_DeleteByBlockId, - NumBlocksIsCorrectAfterAddingTwoBlocks, - NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingFirstBlock, - NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingSecondBlock, - NumBlocksIsCorrectAfterAddingTwoBlocks_AfterClosingBothBlocks, - NumBlocksIsCorrectAfterRemovingABlock_DeleteByBlock, - NumBlocksIsCorrectAfterRemovingABlock_DeleteByBlockId, - WriteAndReadImmediately, - WriteAndReadAfterLoading, - WriteTwiceAndRead, - OverwriteSameSizeAndReadImmediately, - OverwriteSameSizeAndReadAfterLoading, - OverwriteSmallerSizeAndReadImmediately, - OverwriteSmallerSizeAndReadAfterLoading, - OverwriteLargerSizeAndReadAfterLoading, - OverwriteLargerSizeAndReadImmediately, - OverwriteNonexistingAndReadAfterLoading, - OverwriteNonexistingAndReadImmediately, - CanRemoveModifiedBlock, - ForEachBlock_zeroblocks, - ForEachBlock_oneblock, - ForEachBlock_twoblocks, - ForEachBlock_threeblocks, - ForEachBlock_doesntListRemovedBlocks_oneblock, - ForEachBlock_doesntListRemovedBlocks_twoblocks, - Resize_Larger_FromZero, - Resize_Larger_FromZero_BlockIsStillUsable, - Resize_Larger, - Resize_Larger_BlockIsStillUsable, - Resize_Smaller, - Resize_Smaller_BlockIsStillUsable, - Resize_Smaller_ToZero, - Resize_Smaller_ToZero_BlockIsStillUsable - //TODO Just disabled because gtest doesn't allow more template parameters. Fix and reenable! - // see https://github.com/google/googletest/issues/1267 - //TryCreateTwoBlocksWithSameBlockIdAndSameSize, - //TryCreateTwoBlocksWithSameBlockIdAndDifferentSize, - //TryCreateTwoBlocksWithSameBlockIdAndFirstNullSize, - //TryCreateTwoBlocksWithSameBlockIdAndSecondNullSize, - //TryCreateTwoBlocksWithSameBlockIdAndBothNullSize, -); - - -#endif diff --git a/test/blockstore/testutils/BlockStoreTest_Data.h b/test/blockstore/testutils/BlockStoreTest_Data.h deleted file mode 100644 index 60b78c85..00000000 --- a/test/blockstore/testutils/BlockStoreTest_Data.h +++ /dev/null @@ -1,175 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_TESTUTILS_BLOCKSTORETEST_DATA_H_ -#define MESSMER_BLOCKSTORE_TEST_TESTUTILS_BLOCKSTORETEST_DATA_H_ - -// This file is meant to be included by BlockStoreTest.h only - -struct DataRange { - uint64_t blocksize; - uint64_t offset; - uint64_t count; -}; - -class BlockStoreDataParametrizedTest { -public: - BlockStoreDataParametrizedTest(cpputils::unique_ref blockStore_, const DataRange &testData_) - : blockStore(std::move(blockStore_)), - testData(testData_), - foregroundData(cpputils::DataFixture::generate(testData.count, 0)), - backgroundData(cpputils::DataFixture::generate(testData.blocksize, 1)) { - } - - void TestWriteAndReadImmediately() { - auto block = blockStore->create(cpputils::Data(testData.blocksize).FillWithZeroes()); - block->write(foregroundData.data(), testData.offset, testData.count); - - EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count); - EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*block, testData.offset, testData.count); - } - - void TestWriteAndReadAfterLoading() { - blockstore::BlockId blockId = CreateBlockWriteToItAndReturnKey(foregroundData); - - auto loaded_block = blockStore->load(blockId).value(); - EXPECT_DATA_READS_AS(foregroundData, *loaded_block, testData.offset, testData.count); - EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(*loaded_block, testData.offset, testData.count); - } - - void TestWriteTwiceAndRead() { - auto block = blockStore->create(cpputils::Data(testData.blocksize)); - block->write(backgroundData.data(), 0, testData.blocksize); - block->write(foregroundData.data(), testData.offset, testData.count); - EXPECT_DATA_READS_AS(foregroundData, *block, testData.offset, testData.count); - EXPECT_DATA_READS_AS_OUTSIDE_OF(backgroundData, *block, testData.offset, testData.count); - } - - void TestOverwriteSameSizeAndReadImmediately() { - auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId(); - auto block = blockStore->overwrite(blockId, backgroundData.copy()); - EXPECT_EQ(testData.blocksize, block->size()); - EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize); - } - - void TestOverwriteSameSizeAndReadAfterLoading() { - auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId(); - blockStore->overwrite(blockId, backgroundData.copy()); - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(testData.blocksize, block->size()); - EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize); - } - - void TestOverwriteSmallerSizeAndReadImmediately() { - auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId(); - auto block = blockStore->overwrite(blockId, foregroundData.copy()); - EXPECT_EQ(testData.count, block->size()); - EXPECT_DATA_READS_AS(foregroundData, *block, 0, testData.count); - } - - void TestOverwriteSmallerSizeAndReadAfterLoading() { - auto blockId = blockStore->create(cpputils::Data(testData.blocksize))->blockId(); - blockStore->overwrite(blockId, foregroundData.copy()); - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(testData.count, block->size()); - EXPECT_DATA_READS_AS(foregroundData, *block, 0, testData.count); - } - - void TestOverwriteLargerSizeAndReadImmediately() { - auto blockId = blockStore->create(cpputils::Data(testData.count))->blockId(); - auto block = blockStore->overwrite(blockId, backgroundData.copy()); - EXPECT_EQ(testData.blocksize, block->size()); - EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize); - } - - void TestOverwriteLargerSizeAndReadAfterLoading() { - auto blockId = blockStore->create(cpputils::Data(testData.count))->blockId(); - blockStore->overwrite(blockId, backgroundData.copy()); - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(testData.blocksize, block->size()); - EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize); - } - - void TestOverwriteNonexistingAndReadImmediately() { - auto blockId = blockStore->createBlockId(); - auto block = blockStore->overwrite(blockId, backgroundData.copy()); - EXPECT_EQ(testData.blocksize, block->size()); - EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize); - } - - void TestOverwriteNonexistingAndReadAfterLoading() { - auto blockId = blockStore->createBlockId(); - blockStore->overwrite(blockId, backgroundData.copy()); - auto block = blockStore->load(blockId).value(); - EXPECT_EQ(testData.blocksize, block->size()); - EXPECT_DATA_READS_AS(backgroundData, *block, 0, testData.blocksize); - } - -private: - cpputils::unique_ref blockStore; - DataRange testData; - cpputils::Data foregroundData; - cpputils::Data backgroundData; - - blockstore::BlockId CreateBlockWriteToItAndReturnKey(const cpputils::Data &to_write) { - auto newblock = blockStore->create(cpputils::Data(testData.blocksize).FillWithZeroes()); - - newblock->write(to_write.data(), testData.offset, testData.count); - return newblock->blockId(); - } - - void EXPECT_DATA_READS_AS(const cpputils::Data &expected, const blockstore::Block &block, uint64_t offset, uint64_t count) { - cpputils::Data read(count); - std::memcpy(read.data(), static_cast(block.data()) + offset, count); - EXPECT_EQ(expected, read); - } - - void EXPECT_DATA_READS_AS_OUTSIDE_OF(const cpputils::Data &expected, const blockstore::Block &block, uint64_t start, uint64_t count) { - cpputils::Data begin(start); - cpputils::Data end(testData.blocksize - count - start); - - std::memcpy(begin.data(), expected.data(), start); - std::memcpy(end.data(), expected.dataOffset(start+count), end.size()); - - EXPECT_DATA_READS_AS(begin, block, 0, start); - EXPECT_DATA_READS_AS(end, block, start + count, end.size()); - } - - void EXPECT_DATA_IS_ZEROES_OUTSIDE_OF(const blockstore::Block &block, uint64_t start, uint64_t count) { - cpputils::Data ZEROES(testData.blocksize); - ZEROES.FillWithZeroes(); - EXPECT_DATA_READS_AS_OUTSIDE_OF(ZEROES, block, start, count); - } -}; - -inline std::vector DATA_RANGES() { - return { - DataRange{1024, 0, 1024}, // full size leaf, access beginning to end - DataRange{1024, 100, 1024 - 200}, // full size leaf, access middle to middle - DataRange{1024, 0, 1024 - 100}, // full size leaf, access beginning to middle - DataRange{1024, 100, 1024 - 100}, // full size leaf, access middle to end - DataRange{1024 - 100, 0, 1024 - 100}, // non-full size leaf, access beginning to end - DataRange{1024 - 100, 100, 1024 - 300}, // non-full size leaf, access middle to middle - DataRange{1024 - 100, 0, 1024 - 200}, // non-full size leaf, access beginning to middle - DataRange{1024 - 100, 100, 1024 - 200} // non-full size leaf, access middle to end - }; -}; -#define TYPED_TEST_P_FOR_ALL_DATA_RANGES(TestName) \ - TYPED_TEST_P(BlockStoreTest, TestName) { \ - for (auto dataRange: DATA_RANGES()) { \ - BlockStoreDataParametrizedTest(this->fixture.createBlockStore(), dataRange) \ - .Test##TestName(); \ - } \ - } - -TYPED_TEST_P_FOR_ALL_DATA_RANGES(WriteAndReadImmediately); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(WriteAndReadAfterLoading); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(WriteTwiceAndRead); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSameSizeAndReadImmediately); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSameSizeAndReadAfterLoading); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSmallerSizeAndReadImmediately); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteSmallerSizeAndReadAfterLoading); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteLargerSizeAndReadImmediately); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteLargerSizeAndReadAfterLoading); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteNonexistingAndReadImmediately); -TYPED_TEST_P_FOR_ALL_DATA_RANGES(OverwriteNonexistingAndReadAfterLoading); - -#endif diff --git a/test/blockstore/testutils/BlockStoreTest_Size.h b/test/blockstore/testutils/BlockStoreTest_Size.h deleted file mode 100644 index ea000091..00000000 --- a/test/blockstore/testutils/BlockStoreTest_Size.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_TESTUTILS_BLOCKSTORETEST_SIZE_H_ -#define MESSMER_BLOCKSTORE_TEST_TESTUTILS_BLOCKSTORETEST_SIZE_H_ - -// This file is meant to be included by BlockStoreTest.h only - -#include -#include - -class BlockStoreSizeParameterizedTest { -public: - BlockStoreSizeParameterizedTest(cpputils::unique_ref blockStore_, size_t size_): blockStore(std::move(blockStore_)), size(size_) {} - - void TestCreatedBlockHasCorrectSize() { - auto block = CreateBlock(); - EXPECT_EQ(size, block->size()); - } - - void TestLoadingUnchangedBlockHasCorrectSize() { - blockstore::BlockId blockId = CreateBlock()->blockId(); - auto loaded_block = blockStore->load(blockId).value(); - EXPECT_EQ(size, loaded_block->size()); - } - - void TestCreatedBlockData() { - cpputils::Data data = cpputils::DataFixture::generate(size); - auto block = blockStore->create(data); - EXPECT_EQ(0, std::memcmp(data.data(), block->data(), size)); - } - - void TestLoadingUnchangedBlockData() { - cpputils::Data data = cpputils::DataFixture::generate(size); - blockstore::BlockId blockId = blockStore->create(data)->blockId(); - auto loaded_block = blockStore->load(blockId).value(); - EXPECT_EQ(0, std::memcmp(data.data(), loaded_block->data(), size)); - } - - void TestLoadedBlockIsCorrect() { - cpputils::Data randomData = cpputils::DataFixture::generate(size); - auto loaded_block = StoreDataToBlockAndLoadIt(randomData); - EXPECT_EQ(size, loaded_block->size()); - EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_block->data(), size)); - } - - void TestLoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing() { - cpputils::Data randomData = cpputils::DataFixture::generate(size); - auto loaded_block = StoreDataToBlockAndLoadItDirectlyAfterFlushing(randomData); - EXPECT_EQ(size, loaded_block->size()); - EXPECT_EQ(0, std::memcmp(randomData.data(), loaded_block->data(), size)); - } - - void TestAfterCreate_FlushingDoesntChangeBlock() { - cpputils::Data randomData = cpputils::DataFixture::generate(size); - auto block = CreateBlock(); - WriteDataToBlock(block.get(), randomData); - block->flush(); - - EXPECT_BLOCK_DATA_CORRECT(*block, randomData); - } - - void TestAfterLoad_FlushingDoesntChangeBlock() { - cpputils::Data randomData = cpputils::DataFixture::generate(size); - auto block = CreateBlockAndLoadIt(); - WriteDataToBlock(block.get(), randomData); - block->flush(); - - EXPECT_BLOCK_DATA_CORRECT(*block, randomData); - } - - void TestAfterCreate_FlushesWhenDestructed() { - cpputils::Data randomData = cpputils::DataFixture::generate(size); - blockstore::BlockId blockId = blockstore::BlockId::Null(); - { - auto block = blockStore->create(cpputils::Data(size)); - blockId = block->blockId(); - WriteDataToBlock(block.get(), randomData); - } - auto loaded_block = blockStore->load(blockId).value(); - EXPECT_BLOCK_DATA_CORRECT(*loaded_block, randomData); - } - - void TestAfterLoad_FlushesWhenDestructed() { - cpputils::Data randomData = cpputils::DataFixture::generate(size); - blockstore::BlockId blockId = blockstore::BlockId::Null(); - { - blockId = CreateBlock()->blockId(); - auto block = blockStore->load(blockId).value(); - WriteDataToBlock(block.get(), randomData); - } - auto loaded_block = blockStore->load(blockId).value(); - EXPECT_BLOCK_DATA_CORRECT(*loaded_block, randomData); - } - - void TestLoadNonExistingBlock() { - EXPECT_EQ(boost::none, blockStore->load(blockId)); - } - -private: - const blockstore::BlockId blockId = blockstore::BlockId::FromString("1491BB4932A389EE14BC7090AC772972"); - cpputils::unique_ref blockStore; - size_t size; - - cpputils::Data ZEROES(size_t size) { - cpputils::Data ZEROES(size); - ZEROES.FillWithZeroes(); - return ZEROES; - } - - cpputils::unique_ref StoreDataToBlockAndLoadIt(const cpputils::Data &data) { - blockstore::BlockId blockId = StoreDataToBlockAndGetKey(data); - return blockStore->load(blockId).value(); - } - - blockstore::BlockId StoreDataToBlockAndGetKey(const cpputils::Data &data) { - return blockStore->create(data)->blockId(); - } - - cpputils::unique_ref StoreDataToBlockAndLoadItDirectlyAfterFlushing(const cpputils::Data &data) { - auto block = blockStore->create(data); - block->flush(); - return blockStore->load(block->blockId()).value(); - } - - cpputils::unique_ref CreateBlockAndLoadIt() { - blockstore::BlockId blockId = CreateBlock()->blockId(); - return blockStore->load(blockId).value(); - } - - cpputils::unique_ref CreateBlock() { - return blockStore->create(cpputils::Data(size)); - } - - void WriteDataToBlock(blockstore::Block *block, const cpputils::Data &randomData) { - block->write(randomData.data(), 0, randomData.size()); - } - - void EXPECT_BLOCK_DATA_CORRECT(const blockstore::Block &block, const cpputils::Data &randomData) { - EXPECT_EQ(randomData.size(), block.size()); - EXPECT_EQ(0, std::memcmp(randomData.data(), block.data(), randomData.size())); - } -}; - -constexpr std::array SIZES = {{0, 1, 1024, 4096, 10*1024*1024}}; -#define TYPED_TEST_P_FOR_ALL_SIZES(TestName) \ - TYPED_TEST_P(BlockStoreTest, TestName) { \ - for (auto size: SIZES) { \ - BlockStoreSizeParameterizedTest(this->fixture.createBlockStore(), size) \ - .Test##TestName(); \ - } \ - } \ - -TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockHasCorrectSize); -TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockHasCorrectSize); -TYPED_TEST_P_FOR_ALL_SIZES(CreatedBlockData); -TYPED_TEST_P_FOR_ALL_SIZES(LoadingUnchangedBlockData); -TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrect); -//TYPED_TEST_P_FOR_ALL_SIZES(LoadedBlockIsCorrectWhenLoadedDirectlyAfterFlushing); -TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushingDoesntChangeBlock); -TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushingDoesntChangeBlock); -TYPED_TEST_P_FOR_ALL_SIZES(AfterCreate_FlushesWhenDestructed); -TYPED_TEST_P_FOR_ALL_SIZES(AfterLoad_FlushesWhenDestructed); -TYPED_TEST_P_FOR_ALL_SIZES(LoadNonExistingBlock); - -#endif diff --git a/test/blockstore/testutils/gtest_printers.h b/test/blockstore/testutils/gtest_printers.h deleted file mode 100644 index 356ac775..00000000 --- a/test/blockstore/testutils/gtest_printers.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#ifndef MESSMER_BLOCKSTORE_TEST_TESTUTILS_GTESTPRINTERS_H_ -#define MESSMER_BLOCKSTORE_TEST_TESTUTILS_GTESTPRINTERS_H_ - -namespace cpputils { - -inline void PrintTo(const Data& /*data*/, ::std::ostream* os) { - *os << "cpputils::Data"; -} - -inline void PrintTo(const boost::optional& data, ::std::ostream* os) { - if (data == boost::none) { - *os << "none"; - } else { - PrintTo(*data, os); - } -} - -} - -#endif diff --git a/test/blockstore/utils/BlockStoreUtilsTest.cpp b/test/blockstore/utils/BlockStoreUtilsTest.cpp deleted file mode 100644 index 0ec31972..00000000 --- a/test/blockstore/utils/BlockStoreUtilsTest.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "blockstore/implementations/testfake/FakeBlockStore.h" -#include -#include "blockstore/utils/BlockStoreUtils.h" -#include - -#include - -using ::testing::Test; - -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -using namespace blockstore; -using namespace blockstore::utils; - -using blockstore::testfake::FakeBlockStore; - -class BlockStoreUtilsTest: public Test { -public: - unsigned int SIZE = 1024 * 1024; - BlockStoreUtilsTest(): - ZEROES(SIZE), - dataFixture(DataFixture::generate(SIZE)), - blockStore(make_unique_ref()) { - ZEROES.FillWithZeroes(); - } - - Data ZEROES; - Data dataFixture; - unique_ref blockStore; -}; - -TEST_F(BlockStoreUtilsTest, FillWithZeroes) { - auto block = blockStore->create(Data(SIZE)); - block->write(dataFixture.data(), 0, SIZE); - EXPECT_NE(0, std::memcmp(ZEROES.data(), block->data(), SIZE)); - fillWithZeroes(block.get()); - EXPECT_EQ(0, std::memcmp(ZEROES.data(), block->data(), SIZE)); -} - -class BlockStoreUtilsTest_CopyToNewBlock: public BlockStoreUtilsTest {}; - -TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyEmptyBlock) { - auto block = blockStore->create(Data(0)); - auto block2 = copyToNewBlock(blockStore.get(), *block); - - EXPECT_EQ(0u, block2->size()); -} - -TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyZeroBlock) { - auto block = blockStore->create(ZEROES); - auto block2 = copyToNewBlock(blockStore.get(), *block); - - EXPECT_EQ(SIZE, block2->size()); - EXPECT_EQ(0, std::memcmp(ZEROES.data(), block2->data(), SIZE)); -} - -TEST_F(BlockStoreUtilsTest_CopyToNewBlock, CopyDataBlock) { - auto block = blockStore->create(Data(SIZE)); - block->write(dataFixture.data(), 0, SIZE); - auto block2 = copyToNewBlock(blockStore.get(), *block); - - EXPECT_EQ(SIZE, block2->size()); - EXPECT_EQ(0, std::memcmp(dataFixture.data(), block2->data(), SIZE)); -} - -TEST_F(BlockStoreUtilsTest_CopyToNewBlock, OriginalBlockUnchanged) { - auto block = blockStore->create(Data(SIZE)); - block->write(dataFixture.data(), 0, SIZE); - auto block2 = copyToNewBlock(blockStore.get(), *block); - - EXPECT_EQ(SIZE, block->size()); - EXPECT_EQ(0, std::memcmp(dataFixture.data(), block->data(), SIZE)); -} - -class BlockStoreUtilsTest_CopyToExistingBlock: public BlockStoreUtilsTest {}; - -TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyEmptyBlock) { - auto block = blockStore->create(Data(0)); - auto block2 = blockStore->create(Data(0)); - copyTo(block2.get(), *block); -} - -TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyZeroBlock) { - auto block = blockStore->create(ZEROES); - auto block2 = blockStore->create(Data(SIZE)); - block2->write(dataFixture.data(), 0, SIZE); - copyTo(block2.get(), *block); - - EXPECT_EQ(0, std::memcmp(ZEROES.data(), block2->data(), SIZE)); -} - -TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, CopyDataBlock) { - auto block = blockStore->create(Data(SIZE)); - block->write(dataFixture.data(), 0, SIZE); - auto block2 = blockStore->create(Data(SIZE)); - copyTo(block2.get(), *block); - - EXPECT_EQ(0, std::memcmp(dataFixture.data(), block2->data(), SIZE)); -} - -TEST_F(BlockStoreUtilsTest_CopyToExistingBlock, OriginalBlockUnchanged) { - auto block = blockStore->create(Data(SIZE)); - block->write(dataFixture.data(), 0, SIZE); - auto block2 = blockStore->create(Data(SIZE)); - copyTo(block2.get(), *block); - - EXPECT_EQ(0, std::memcmp(dataFixture.data(), block->data(), SIZE)); -} diff --git a/test/cpp-utils/CMakeLists.txt b/test/cpp-utils/CMakeLists.txt deleted file mode 100644 index a13ad986..00000000 --- a/test/cpp-utils/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -project (cpp-utils-test) - -set(SOURCES - crypto/symmetric/CipherTest.cpp - crypto/kdf/SCryptTest.cpp - crypto/kdf/SCryptParametersTest.cpp - crypto/hash/HashTest.cpp - MacrosIncludeTest.cpp - pointer/unique_ref_test.cpp - pointer/cast_include_test.cpp - pointer/cast_test.cpp - pointer/unique_ref_boost_optional_gtest_workaround_include_test.cpp - pointer/optional_ownership_ptr_include_test.cpp - pointer/optional_ownership_ptr_test.cpp - pointer/unique_ref_include_test.cpp - process/daemonize_include_test.cpp - process/subprocess_include_test.cpp - process/SubprocessTest.cpp - process/SignalCatcherTest.cpp - process/SignalHandlerTest.cpp - tempfile/TempFileTest.cpp - tempfile/TempFileIncludeTest.cpp - tempfile/TempDirIncludeTest.cpp - tempfile/TempDirTest.cpp - network/CurlHttpClientTest.cpp - network/FakeHttpClientTest.cpp - io/DontEchoStdinToStdoutRAIITest.cpp - io/ConsoleIncludeTest.cpp - io/ConsoleTest_AskYesNo.cpp - io/ConsoleTest_Print.cpp - io/ConsoleTest_Ask.cpp - io/ConsoleTest_AskPassword.cpp - io/ProgressBarTest.cpp - random/RandomIncludeTest.cpp - lock/LockPoolIncludeTest.cpp - lock/ConditionBarrierIncludeTest.cpp - lock/MutexPoolLockIncludeTest.cpp - data/FixedSizeDataTest.cpp - data/DataFixtureIncludeTest.cpp - data/DataFixtureTest.cpp - data/DataTest.cpp - data/FixedSizeDataIncludeTest.cpp - data/SerializationHelperTest.cpp - data/DataIncludeTest.cpp - logging/LoggingLevelTest.cpp - logging/LoggerTest.cpp - logging/LoggingTest.cpp - logging/LoggerIncludeTest.cpp - logging/LoggingIncludeTest.cpp - assert/assert_release_test.cpp - assert/backtrace_test.cpp - assert/assert_debug_test.cpp - system/GetTotalMemoryTest.cpp - system/TimeTest.cpp - system/PathTest.cpp - system/FiletimeTest.cpp - system/MemoryTest.cpp - system/HomedirTest.cpp - system/EnvTest.cpp - thread/debugging_test.cpp - thread/LeftRightTest.cpp - value_type/ValueTypeTest.cpp - either_test.cpp -) - -add_executable(${PROJECT_NAME}_exit_status process/exit_status.cpp) -target_activate_cpp14(${PROJECT_NAME}_exit_status) - -add_executable(${PROJECT_NAME}_exit_signal assert/exit_signal.cpp) -target_activate_cpp14(${PROJECT_NAME}_exit_signal) -target_link_libraries(${PROJECT_NAME}_exit_signal cpp-utils) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest cpp-utils) -add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_exit_status ${PROJECT_NAME}_exit_signal) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/cpp-utils/MacrosIncludeTest.cpp b/test/cpp-utils/MacrosIncludeTest.cpp deleted file mode 100644 index 6e16a15d..00000000 --- a/test/cpp-utils/MacrosIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/macros.h" - -// Test that macros.h can be included without needing additional dependencies diff --git a/test/cpp-utils/assert/assert_debug_test.cpp b/test/cpp-utils/assert/assert_debug_test.cpp deleted file mode 100644 index 9e3a2220..00000000 --- a/test/cpp-utils/assert/assert_debug_test.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include - -#ifdef NDEBUG -#define REAL_NDEBUG_ -#endif - -//Include the ASSERT macro for a debug build -#undef NDEBUG -#include "cpp-utils/assert/assert.h" - - -TEST(AssertTest_DebugBuild, DoesntDieIfTrue) { - ASSERT(true, "bla"); -} - -TEST(AssertTest_DebugBuild, DiesIfFalse) { - EXPECT_DEATH( - ASSERT(false, "bla"), - "" - ); -} - -TEST(AssertTest_DebugBuild, whenDisablingAbort_thenThrowsIfFalse) { - cpputils::_assert::DisableAbortOnFailedAssertionRAII _disableAbort; - EXPECT_THROW( - ASSERT(false, "bla"), - cpputils::AssertFailed - ); -} - -TEST(AssertTest_DebugBuild, AssertMessage) { -#if defined(_MSC_VER) - constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:\d+: my message)"; -#else - constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:[0-9]+: my message)"; -#endif - EXPECT_DEATH( - ASSERT(2==5, "my message"), - EXPECTED - ); -} - -#if !(defined(_MSC_VER) && defined(REAL_NDEBUG_)) -TEST(AssertTest_DebugBuild, AssertMessageContainsBacktrace) { - EXPECT_DEATH( - ASSERT(2==5, "my message"), - "cpputils::" - ); -} -#else -TEST(AssertTest_DebugBuild, AssertMessageContainsBacktrace) { - EXPECT_DEATH( - ASSERT(2==5, "my message"), - "#1" - ); -} -#endif diff --git a/test/cpp-utils/assert/assert_release_test.cpp b/test/cpp-utils/assert/assert_release_test.cpp deleted file mode 100644 index 5dd73824..00000000 --- a/test/cpp-utils/assert/assert_release_test.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include - -#ifdef NDEBUG -#define REAL_NDEBUG_ -#endif - -//Include the ASSERT macro for a release build -#ifndef NDEBUG -#define NDEBUG 1 -#endif -#include "cpp-utils/assert/assert.h" - -using testing::HasSubstr; - -TEST(AssertTest_ReleaseBuild, DoesntThrowIfTrue) { - ASSERT(true, "bla"); -} - -TEST(AssertTest_ReleaseBuild, ThrowsIfFalse) { - EXPECT_THROW( - ASSERT(false, "bla"), - cpputils::AssertFailed - ); -} - -TEST(AssertTest_ReleaseBuild, AssertMessage) { - try { - ASSERT(2==5, "my message"); - FAIL(); - } catch (const cpputils::AssertFailed &e) { - std::string msg = e.what(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - /*EXPECT_THAT(e.what(), MatchesRegex( - R"(Assertion \[2==5\] failed in .*assert_release_test.cpp:27: my message)" - ));*/ - EXPECT_TRUE(std::regex_search(e.what(), std::regex(R"(Assertion \[2==5\] failed in .*assert_release_test.cpp:30: my message)"))); - } -} - -#if !(defined(_MSC_VER) && defined(REAL_NDEBUG_)) -TEST(AssertTest_ReleaseBuild, AssertMessageContainsBacktrace) { - try { - ASSERT(2==5, "my message"); - FAIL(); - } catch (const cpputils::AssertFailed &e) { - EXPECT_THAT(e.what(), HasSubstr( - "cpputils::" - )); - } -} -#else -TEST(AssertTest_ReleaseBuild, AssertMessageContainsBacktrace) { - try { - ASSERT(2==5, "my message"); - FAIL(); - } catch (const cpputils::AssertFailed &e) { - EXPECT_THAT(e.what(), HasSubstr( - "#1" - )); - } -} -#endif diff --git a/test/cpp-utils/assert/backtrace_test.cpp b/test/cpp-utils/assert/backtrace_test.cpp deleted file mode 100644 index 7b0ab9d3..00000000 --- a/test/cpp-utils/assert/backtrace_test.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include -#include -#include "cpp-utils/assert/backtrace.h" -#include "cpp-utils/process/subprocess.h" -#include -#include "my-gtest-main.h" - -using std::string; -using testing::HasSubstr; -namespace bf = boost::filesystem; - -namespace -{ - std::string call_process_exiting_with(const std::string &kind, const std::string &signal = "") - { -#if defined(_MSC_VER) - auto executable = bf::canonical(get_executable().parent_path()) / "cpp-utils-test_exit_signal.exe"; -#else - auto executable = bf::canonical(get_executable().parent_path()) / "cpp-utils-test_exit_signal"; -#endif - if (!bf::exists(executable)) - { - throw std::runtime_error(executable.string() + " not found."); - } - auto result = cpputils::Subprocess::call(executable, {kind, signal}, ""); - return result.output_stderr; - } -} - -#if !(defined(_MSC_VER) && defined(NDEBUG)) - -TEST(BacktraceTest, ContainsTopLevelLine) -{ - string backtrace = cpputils::backtrace(); - EXPECT_THAT(backtrace, HasSubstr("BacktraceTest")); - EXPECT_THAT(backtrace, HasSubstr("ContainsTopLevelLine")); -} -#endif - -namespace -{ - std::string call_process_exiting_with_nullptr_violation() - { - return call_process_exiting_with("nullptr"); - } - std::string call_process_exiting_with_exception(const std::string &message) - { - return call_process_exiting_with("exception", message); - } -} -#if defined(_MSC_VER) -#include -namespace -{ - std::string call_process_exiting_with_sigsegv() - { - return call_process_exiting_with("signal", std::to_string(EXCEPTION_ACCESS_VIOLATION)); - } - std::string call_process_exiting_with_sigill() - { - return call_process_exiting_with("signal", std::to_string(EXCEPTION_ILLEGAL_INSTRUCTION)); - } - std::string call_process_exiting_with_code(DWORD code) - { - return call_process_exiting_with("signal", std::to_string(code)); - } -} -#else -namespace -{ - std::string call_process_exiting_with_sigsegv() - { - return call_process_exiting_with("signal", std::to_string(SIGSEGV)); - } - std::string call_process_exiting_with_sigabrt() - { - return call_process_exiting_with("signal", std::to_string(SIGABRT)); - } - std::string call_process_exiting_with_sigill() - { - return call_process_exiting_with("signal", std::to_string(SIGILL)); - } -} -#endif - -TEST(BacktraceTest, DoesntCrashOnCaughtException) -{ - // This is needed to make sure we don't use some kind of vectored exception handler on Windows - // that ignores the call stack and always jumps on when an exception happens. - cpputils::showBacktraceOnCrash(); - try - { - throw std::logic_error("exception"); - } - catch (const std::logic_error &e) - { - // intentionally empty - } -} - -#if !(defined(_MSC_VER) && defined(NDEBUG)) -TEST(BacktraceTest, ContainsBacktrace) -{ - string backtrace = cpputils::backtrace(); -#if defined(_MSC_VER) - EXPECT_THAT(backtrace, HasSubstr("testing::Test::Run")); -#else - EXPECT_THAT(backtrace, HasSubstr("BacktraceTest_ContainsBacktrace_Test::TestBody")); -#endif -} - -TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) -{ - auto output = call_process_exiting_with_nullptr_violation(); -#if defined(_MSC_VER) - EXPECT_THAT(output, HasSubstr("handle_exit_signal")); -#else - EXPECT_THAT(output, HasSubstr("cpputils::backtrace")); -#endif -} - -TEST(BacktraceTest, ShowBacktraceOnSigSegv) -{ - auto output = call_process_exiting_with_sigsegv(); -#if defined(_MSC_VER) - EXPECT_THAT(output, HasSubstr("handle_exit_signal")); -#else - EXPECT_THAT(output, HasSubstr("cpputils::backtrace")); -#endif -} - -TEST(BacktraceTest, ShowBacktraceOnUnhandledException) -{ - auto output = call_process_exiting_with_exception("my_exception_message"); -#if defined(_MSC_VER) - EXPECT_THAT(output, HasSubstr("handle_exit_signal")); -#else - EXPECT_THAT(output, HasSubstr("cpputils::backtrace")); -#endif -} - -TEST(BacktraceTest, ShowBacktraceOnSigIll) -{ - auto output = call_process_exiting_with_sigill(); -#if defined(_MSC_VER) - EXPECT_THAT(output, HasSubstr("handle_exit_signal")); -#else - EXPECT_THAT(output, HasSubstr("cpputils::backtrace")); -#endif -} -#else -TEST(BacktraceTest, ContainsBacktrace) -{ - string backtrace = cpputils::backtrace(); - EXPECT_THAT(backtrace, HasSubstr("#0")); -} -TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) -{ - auto output = call_process_exiting_with_nullptr_violation(); - EXPECT_THAT(output, HasSubstr("#1")); -} - -TEST(BacktraceTest, ShowBacktraceOnSigSegv) -{ - auto output = call_process_exiting_with_sigsegv(); - EXPECT_THAT(output, HasSubstr("#1")); -} - -TEST(BacktraceTest, ShowBacktraceOnUnhandledException) -{ - auto output = call_process_exiting_with_exception("my_exception_message"); - EXPECT_THAT(output, HasSubstr("#1")); -} - -TEST(BacktraceTest, ShowBacktraceOnSigIll) -{ - auto output = call_process_exiting_with_sigill(); - EXPECT_THAT(output, HasSubstr("#1")); -} -#endif - -#if !defined(_MSC_VER) -TEST(BacktraceTest, ShowBacktraceOnSigAbrt) -{ - auto output = call_process_exiting_with_sigabrt(); - EXPECT_THAT(output, HasSubstr("cpputils::backtrace")); -} - -TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) -{ - auto output = call_process_exiting_with_sigabrt(); - EXPECT_THAT(output, HasSubstr("SIGABRT")); -} -#endif - -#if !defined(_MSC_VER) -constexpr const char *sigsegv_message = "SIGSEGV"; -constexpr const char *sigill_message = "SIGILL"; -#else -constexpr const char *sigsegv_message = "EXCEPTION_ACCESS_VIOLATION"; -constexpr const char *sigill_message = "EXCEPTION_ILLEGAL_INSTRUCTION"; -#endif - -TEST(BacktraceTest, ShowBacktraceOnSigSegv_ShowsCorrectSignalName) -{ - auto output = call_process_exiting_with_sigsegv(); - EXPECT_THAT(output, HasSubstr(sigsegv_message)); -} - -TEST(BacktraceTest, ShowBacktraceOnSigIll_ShowsCorrectSignalName) -{ - auto output = call_process_exiting_with_sigill(); - EXPECT_THAT(output, HasSubstr(sigill_message)); -} - -#if !defined(_MSC_VER) -TEST(BacktraceTest, ShowBacktraceOnUnhandledException_ShowsCorrectExceptionMessage) -{ - auto output = call_process_exiting_with_exception("my_exception_message"); - EXPECT_THAT(output, HasSubstr("my_exception_message")); -} -#endif - -#if defined(_MSC_VER) -TEST(BacktraceTest, UnknownCode_ShowsCorrectSignalName) -{ - auto output = call_process_exiting_with_code(0x1234567); - EXPECT_THAT(output, HasSubstr("UNKNOWN_CODE(0x1234567)")); -} -#endif diff --git a/test/cpp-utils/assert/exit_signal.cpp b/test/cpp-utils/assert/exit_signal.cpp deleted file mode 100644 index cedc9a8d..00000000 --- a/test/cpp-utils/assert/exit_signal.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include - -#if defined(_MSC_VER) -#include -#endif - -void handle_exit_signal(char **argv) { - const std::string kind = argv[1]; - if (kind == "exception") { - throw std::logic_error(argv[2]); - } else if (kind == "nullptr") { - int* ptr = nullptr; - *ptr = 5; // NOLINT - } else if (kind == "signal") { -#if defined(_MSC_VER) - DWORD code = std::atoll(argv[2]); - ::RaiseException(code, EXCEPTION_NONCONTINUABLE, 0, NULL); -#else - int code = static_cast(std::strtol(argv[2], nullptr, 10)); - ::raise(code); -#endif - } -} - - -int main(int /*argc*/, char* argv[]) { - cpputils::showBacktraceOnCrash(); -#if defined(_MSC_VER) - // don't show windows error box - _set_abort_behavior(0, _WRITE_ABORT_MSG); -#endif - handle_exit_signal(argv); - return 0; -} diff --git a/test/cpp-utils/crypto/hash/HashTest.cpp b/test/cpp-utils/crypto/hash/HashTest.cpp deleted file mode 100644 index 20dcee7a..00000000 --- a/test/cpp-utils/crypto/hash/HashTest.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -using namespace cpputils::hash; -using cpputils::DataFixture; -using cpputils::Data; - -TEST(HashTest, generateSalt_isIndeterministic) { - EXPECT_NE(generateSalt(), generateSalt()); -} - -TEST(HashTest, hash_setsSaltCorrectly) { - Salt salt = generateSalt(); - Data data = DataFixture::generate(1024); - EXPECT_EQ(salt, hash(data, salt).salt); -} - -TEST(HashTest, hash_isDeterministicWithSameDataSameSalt) { - Salt salt = generateSalt(); - Data data = DataFixture::generate(1024); - EXPECT_EQ(hash(data, salt).digest, hash(data, salt).digest); -} - -TEST(HashTest, hash_isIndeterministicWithSameDataDifferentSalt) { - Salt salt1 = generateSalt(); - Salt salt2 = generateSalt(); - Data data = DataFixture::generate(1024); - EXPECT_NE(hash(data, salt1).digest, hash(data, salt2).digest); -} - -TEST(HashTest, hash_isIndeterministicWithDifferentDataSameSalt) { - Salt salt = generateSalt(); - Data data1 = DataFixture::generate(1024, 1); - Data data2 = DataFixture::generate(1024, 2); - EXPECT_NE(hash(data1, salt).digest, hash(data2, salt).digest); -} - -TEST(HashTest, hash_isIndeterministicWithDifferentDataDifferentSalt) { - Salt salt1 = generateSalt(); - Salt salt2 = generateSalt(); - Data data1 = DataFixture::generate(1024, 1); - Data data2 = DataFixture::generate(1024, 2); - EXPECT_NE(hash(data1, salt1).digest, hash(data2, salt2).digest); -} diff --git a/test/cpp-utils/crypto/kdf/SCryptParametersTest.cpp b/test/cpp-utils/crypto/kdf/SCryptParametersTest.cpp deleted file mode 100644 index e4353593..00000000 --- a/test/cpp-utils/crypto/kdf/SCryptParametersTest.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include -#include -#include - -using namespace cpputils; - -class SCryptParametersTest : public ::testing::Test { -public: - SCryptParameters SaveAndLoad(const SCryptParameters &source) { - Data serialized = source.serialize(); - return SCryptParameters::deserialize(serialized); - } -}; - -TEST_F(SCryptParametersTest, Salt) { - SCryptParameters cfg(DataFixture::generate(32), 0, 0, 0); - EXPECT_EQ(DataFixture::generate(32), cfg.salt()); -} - -TEST_F(SCryptParametersTest, Salt_Move) { - SCryptParameters cfg(DataFixture::generate(32), 0, 0, 0); - SCryptParameters moved = std::move(cfg); - EXPECT_EQ(DataFixture::generate(32), moved.salt()); -} - -TEST_F(SCryptParametersTest, Salt_SaveAndLoad) { - SCryptParameters cfg(DataFixture::generate(32), 0, 0, 0); - SCryptParameters loaded = SaveAndLoad(cfg); - EXPECT_EQ(DataFixture::generate(32), loaded.salt()); -} - -TEST_F(SCryptParametersTest, N) { - SCryptParameters cfg(Data(0), 1024, 0, 0); - EXPECT_EQ(1024u, cfg.n()); -} - -TEST_F(SCryptParametersTest, N_Move) { - SCryptParameters cfg(Data(0), 1024, 0, 0); - SCryptParameters moved = std::move(cfg); - EXPECT_EQ(1024u, moved.n()); -} - -TEST_F(SCryptParametersTest, N_SaveAndLoad) { - SCryptParameters cfg(Data(0), 1024, 0, 0); - SCryptParameters loaded = SaveAndLoad(cfg); - EXPECT_EQ(1024u, loaded.n()); -} - -TEST_F(SCryptParametersTest, r) { - SCryptParameters cfg(Data(0), 0, 8, 0); - EXPECT_EQ(8u, cfg.r()); -} - -TEST_F(SCryptParametersTest, r_Move) { - SCryptParameters cfg(Data(0), 0, 8, 0); - SCryptParameters moved = std::move(cfg); - EXPECT_EQ(8u, moved.r()); -} - -TEST_F(SCryptParametersTest, r_SaveAndLoad) { - SCryptParameters cfg(Data(0), 0, 8, 0); - SCryptParameters loaded = SaveAndLoad(cfg); - EXPECT_EQ(8u, loaded.r()); -} - -TEST_F(SCryptParametersTest, p) { - SCryptParameters cfg(Data(0), 0, 0, 16); - EXPECT_EQ(16u, cfg.p()); -} - -TEST_F(SCryptParametersTest, p_Move) { - SCryptParameters cfg(Data(0), 0, 0, 16); - SCryptParameters moved = std::move(cfg); - EXPECT_EQ(16u, moved.p()); -} - - -TEST_F(SCryptParametersTest, p_SaveAndLoad) { - SCryptParameters cfg(Data(0), 0, 0, 16); - SCryptParameters loaded = SaveAndLoad(cfg); - EXPECT_EQ(16u, loaded.p()); -} diff --git a/test/cpp-utils/crypto/kdf/SCryptTest.cpp b/test/cpp-utils/crypto/kdf/SCryptTest.cpp deleted file mode 100644 index 4cdfffe2..00000000 --- a/test/cpp-utils/crypto/kdf/SCryptTest.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include "cpp-utils/crypto/kdf/Scrypt.h" - -using namespace cpputils; -using std::string; - -class SCryptTest : public ::testing::Test { -public: - bool keyEquals(const EncryptionKey& lhs, const EncryptionKey& rhs) { - ASSERT(lhs.binaryLength() == rhs.binaryLength(), "Keys must have equal size to be comparable"); - return 0 == std::memcmp(lhs.data(), rhs.data(), lhs.binaryLength()); - } -}; - -TEST_F(SCryptTest, GeneratedKeyIsReproductible_448) { - SCrypt scrypt(SCrypt::TestSettings); - auto derivedKey = scrypt.deriveNewKey(56, "mypassword"); - auto rederivedKey = scrypt.deriveExistingKey(56, "mypassword", derivedKey.kdfParameters); - EXPECT_TRUE(keyEquals(derivedKey.key, rederivedKey)); -} - -TEST_F(SCryptTest, GeneratedKeyIsReproductible_256) { - SCrypt scrypt(SCrypt::TestSettings); - auto derivedKey = scrypt.deriveNewKey(32, "mypassword"); - auto rederivedKey = scrypt.deriveExistingKey(32, "mypassword", derivedKey.kdfParameters); - EXPECT_TRUE(keyEquals(derivedKey.key, rederivedKey)); -} - -TEST_F(SCryptTest, GeneratedKeyIsReproductible_128) { - SCrypt scrypt(SCrypt::TestSettings); - auto derivedKey = scrypt.deriveNewKey(16, "mypassword"); - auto rederivedKey = scrypt.deriveExistingKey(16, "mypassword", derivedKey.kdfParameters); - EXPECT_TRUE(keyEquals(derivedKey.key, rederivedKey)); -} - -TEST_F(SCryptTest, GeneratedKeyIsReproductible_DefaultSettings) { - SCrypt scrypt(SCrypt::TestSettings); - auto derivedKey = scrypt.deriveNewKey(16, "mypassword"); - auto rederivedKey = scrypt.deriveExistingKey(16, "mypassword", derivedKey.kdfParameters); - EXPECT_TRUE(keyEquals(derivedKey.key, rederivedKey)); -} - -TEST_F(SCryptTest, DifferentPasswordResultsInDifferentKey) { - SCrypt scrypt(SCrypt::TestSettings); - auto derivedKey = scrypt.deriveNewKey(16, "mypassword"); - auto rederivedKey = scrypt.deriveExistingKey(16, "mypassword2", derivedKey.kdfParameters); - EXPECT_FALSE(keyEquals(derivedKey.key, rederivedKey)); -} - -TEST_F(SCryptTest, UsesCorrectSettings) { - SCrypt scrypt(SCrypt::TestSettings); - auto derivedKey = scrypt.deriveNewKey(16, "mypassword"); - auto parameters = SCryptParameters::deserialize(derivedKey.kdfParameters); - EXPECT_EQ(SCrypt::TestSettings.SALT_LEN, parameters.salt().size()); - EXPECT_EQ(SCrypt::TestSettings.N, parameters.n()); - EXPECT_EQ(SCrypt::TestSettings.r, parameters.r()); - EXPECT_EQ(SCrypt::TestSettings.p, parameters.p()); -} - -TEST_F(SCryptTest, UsesCorrectDefaultSettings) { - SCrypt scrypt(SCrypt::DefaultSettings); - auto derivedKey = scrypt.deriveNewKey(16, "mypassword"); - auto parameters = SCryptParameters::deserialize(derivedKey.kdfParameters); - EXPECT_EQ(SCrypt::DefaultSettings.SALT_LEN, parameters.salt().size()); - EXPECT_EQ(SCrypt::DefaultSettings.N, parameters.n()); - EXPECT_EQ(SCrypt::DefaultSettings.r, parameters.r()); - EXPECT_EQ(SCrypt::DefaultSettings.p, parameters.p()); -} diff --git a/test/cpp-utils/crypto/symmetric/CipherTest.cpp b/test/cpp-utils/crypto/symmetric/CipherTest.cpp deleted file mode 100644 index 87470da1..00000000 --- a/test/cpp-utils/crypto/symmetric/CipherTest.cpp +++ /dev/null @@ -1,298 +0,0 @@ -#include -#include "cpp-utils/crypto/symmetric/Cipher.h" -#include "cpp-utils/crypto/symmetric/ciphers.h" -#include "cpp-utils/crypto/symmetric/testutils/FakeAuthenticatedCipher.h" - -#include "cpp-utils/data/DataFixture.h" -#include "cpp-utils/data/Data.h" -#include - -using namespace cpputils; -using std::string; - -template -class CipherTest: public ::testing::Test { -public: - BOOST_CONCEPT_ASSERT((CipherConcept)); - typename Cipher::EncryptionKey encKey = createKeyFixture(); - - static typename Cipher::EncryptionKey createKeyFixture(int seed = 0) { - Data data = DataFixture::generate(Cipher::KEYSIZE, seed); - return Cipher::EncryptionKey::FromString(data.ToString()); - } - - void CheckEncryptThenDecryptIsIdentity(const Data &plaintext) { - Data ciphertext = Encrypt(plaintext); - Data decrypted = Decrypt(ciphertext); - EXPECT_EQ(plaintext, decrypted); - } - - void CheckEncryptIsIndeterministic(const Data &plaintext) { - Data ciphertext = Encrypt(plaintext); - Data ciphertext2 = Encrypt(plaintext); - EXPECT_NE(ciphertext, ciphertext2); - } - - void CheckEncryptedSize(const Data &plaintext) { - Data ciphertext = Encrypt(plaintext); - EXPECT_EQ(Cipher::ciphertextSize(plaintext.size()), ciphertext.size()); - } - - void ExpectDoesntDecrypt(const Data &ciphertext) { - auto decrypted = Cipher::decrypt(static_cast(ciphertext.data()), ciphertext.size(), this->encKey); - EXPECT_FALSE(decrypted); - } - - Data Encrypt(const Data &plaintext) { - return Cipher::encrypt(static_cast(plaintext.data()), plaintext.size(), this->encKey); - } - - Data Decrypt(const Data &ciphertext) { - return Cipher::decrypt(static_cast(ciphertext.data()), ciphertext.size(), this->encKey).value(); - } - - static Data CreateZeroes(unsigned int size) { - return Data(size).FillWithZeroes(); - } - - static Data CreateData(unsigned int size, unsigned int seed = 0) { - return DataFixture::generate(size, seed); - } -}; - -TYPED_TEST_SUITE_P(CipherTest); - -constexpr std::array SIZES = {{0, 1, 100, 1024, 5000, 1048576, 20971520}}; - -TYPED_TEST_P(CipherTest, Size) { - for (auto size: SIZES) { - EXPECT_EQ(size, TypeParam::ciphertextSize(TypeParam::plaintextSize(size))); - EXPECT_EQ(size, TypeParam::plaintextSize(TypeParam::ciphertextSize(size))); - } -} - -TYPED_TEST_P(CipherTest, EncryptThenDecrypt_Zeroes) { - for (auto size: SIZES) { - Data plaintext = this->CreateZeroes(size); - this->CheckEncryptThenDecryptIsIdentity(plaintext); - } -} - -TYPED_TEST_P(CipherTest, EncryptThenDecrypt_Data) { - for (auto size: SIZES) { - Data plaintext = this->CreateData(size); - this->CheckEncryptThenDecryptIsIdentity(plaintext); - } -} - -TYPED_TEST_P(CipherTest, EncryptIsIndeterministic_Zeroes) { - for (auto size: SIZES) { - Data plaintext = this->CreateZeroes(size); - this->CheckEncryptIsIndeterministic(plaintext); - } -} - -TYPED_TEST_P(CipherTest, EncryptIsIndeterministic_Data) { - for (auto size: SIZES) { - Data plaintext = this->CreateData(size); - this->CheckEncryptIsIndeterministic(plaintext); - } -} - -TYPED_TEST_P(CipherTest, EncryptedSize) { - for (auto size: SIZES) { - Data plaintext = this->CreateData(size); - this->CheckEncryptedSize(plaintext); - } -} - -TYPED_TEST_P(CipherTest, TryDecryptDataThatIsTooSmall) { - Data tooSmallCiphertext(TypeParam::ciphertextSize(0) - 1); - this->ExpectDoesntDecrypt(tooSmallCiphertext); -} - -TYPED_TEST_P(CipherTest, TryDecryptDataThatIsMuchTooSmall_0) { - static_assert(TypeParam::ciphertextSize(0) > 0, "If this fails, the test case doesn't make sense."); - Data tooSmallCiphertext(0); - this->ExpectDoesntDecrypt(tooSmallCiphertext); -} - -TYPED_TEST_P(CipherTest, TryDecryptDataThatIsMuchTooSmall_1) { - static_assert(TypeParam::ciphertextSize(0) > 1, "If this fails, the test case doesn't make sense."); - Data tooSmallCiphertext(1); - this->ExpectDoesntDecrypt(tooSmallCiphertext); -} - -REGISTER_TYPED_TEST_SUITE_P(CipherTest, - Size, - EncryptThenDecrypt_Zeroes, - EncryptThenDecrypt_Data, - EncryptIsIndeterministic_Zeroes, - EncryptIsIndeterministic_Data, - EncryptedSize, - TryDecryptDataThatIsTooSmall, - TryDecryptDataThatIsMuchTooSmall_0, - TryDecryptDataThatIsMuchTooSmall_1 -); - -template -class AuthenticatedCipherTest: public CipherTest { -public: - Data zeroes1 = CipherTest::CreateZeroes(1); - Data plaintext1 = CipherTest::CreateData(1); - Data zeroes2 = CipherTest::CreateZeroes(100 * 1024); - Data plaintext2 = CipherTest::CreateData(100 * 1024); -}; - -TYPED_TEST_SUITE_P(AuthenticatedCipherTest); - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyFirstByte_Zeroes_Size1) { - Data ciphertext = this->Encrypt(this->zeroes1); - void* firstByte = ciphertext.data(); - serialize(firstByte, deserialize(firstByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyFirstByte_Data_Size1) { - Data ciphertext = this->Encrypt(this->plaintext1); - void* firstByte = ciphertext.data(); - serialize(firstByte, deserialize(firstByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyFirstByte_Zeroes) { - Data ciphertext = this->Encrypt(this->zeroes2); - void* firstByte = ciphertext.data(); - serialize(firstByte, deserialize(firstByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyFirstByte_Data) { - Data ciphertext = this->Encrypt(this->plaintext2); - void* firstByte = ciphertext.data(); - serialize(firstByte, deserialize(firstByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyLastByte_Zeroes) { - Data ciphertext = this->Encrypt(this->zeroes2); - void* lastByte = ciphertext.dataOffset(ciphertext.size() - 1); - serialize(lastByte, deserialize(lastByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyLastByte_Data) { - Data ciphertext = this->Encrypt(this->plaintext2); - void* lastByte = ciphertext.dataOffset(ciphertext.size() - 1); - serialize(lastByte, deserialize(lastByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyMiddleByte_Zeroes) { - Data ciphertext = this->Encrypt(this->zeroes2); - void* middleByte = ciphertext.dataOffset(ciphertext.size()/2); - serialize(middleByte, deserialize(middleByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, ModifyMiddleByte_Data) { - Data ciphertext = this->Encrypt(this->plaintext2); - void* middleByte = ciphertext.dataOffset(ciphertext.size()/2); - serialize(middleByte, deserialize(middleByte) + 1); - this->ExpectDoesntDecrypt(ciphertext); -} - -TYPED_TEST_P(AuthenticatedCipherTest, TryDecryptZeroesData) { - this->ExpectDoesntDecrypt(this->zeroes2); -} - -TYPED_TEST_P(AuthenticatedCipherTest, TryDecryptRandomData) { - this->ExpectDoesntDecrypt(this->plaintext2); -} - -REGISTER_TYPED_TEST_SUITE_P(AuthenticatedCipherTest, - ModifyFirstByte_Zeroes_Size1, - ModifyFirstByte_Zeroes, - ModifyFirstByte_Data_Size1, - ModifyFirstByte_Data, - ModifyLastByte_Zeroes, - ModifyLastByte_Data, - ModifyMiddleByte_Zeroes, - ModifyMiddleByte_Data, - TryDecryptZeroesData, - TryDecryptRandomData -); - - -INSTANTIATE_TYPED_TEST_SUITE_P(Fake, CipherTest, FakeAuthenticatedCipher); -INSTANTIATE_TYPED_TEST_SUITE_P(Fake, AuthenticatedCipherTest, FakeAuthenticatedCipher); - -INSTANTIATE_TYPED_TEST_SUITE_P(XChaCha20Poly1305, CipherTest, XChaCha20Poly1305); -INSTANTIATE_TYPED_TEST_SUITE_P(XChaCha20Poly1305, AuthenticatedCipherTest, XChaCha20Poly1305); - -INSTANTIATE_TYPED_TEST_SUITE_P(AES256_CFB, CipherTest, AES256_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(AES256_GCM, CipherTest, AES256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(AES256_GCM, AuthenticatedCipherTest, AES256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(AES128_CFB, CipherTest, AES128_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(AES128_GCM, CipherTest, AES128_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(AES128_GCM, AuthenticatedCipherTest, AES128_GCM); - -INSTANTIATE_TYPED_TEST_SUITE_P(Twofish256_CFB, CipherTest, Twofish256_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Twofish256_GCM, CipherTest, Twofish256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Twofish256_GCM, AuthenticatedCipherTest, Twofish256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Twofish128_CFB, CipherTest, Twofish128_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Twofish128_GCM, CipherTest, Twofish128_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Twofish128_GCM, AuthenticatedCipherTest, Twofish128_GCM); - -INSTANTIATE_TYPED_TEST_SUITE_P(Serpent256_CFB, CipherTest, Serpent256_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Serpent256_GCM, CipherTest, Serpent256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Serpent256_GCM, AuthenticatedCipherTest, Serpent256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Serpent128_CFB, CipherTest, Serpent128_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Serpent128_GCM, CipherTest, Serpent128_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Serpent128_GCM, AuthenticatedCipherTest, Serpent128_GCM); - -INSTANTIATE_TYPED_TEST_SUITE_P(Cast256_CFB, CipherTest, Cast256_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Cast256_GCM, CipherTest, Cast256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Cast256_GCM, AuthenticatedCipherTest, Cast256_GCM); - -INSTANTIATE_TYPED_TEST_SUITE_P(Mars448_CFB, CipherTest, Mars448_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Mars448_GCM, CipherTest, Mars448_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Mars448_GCM, AuthenticatedCipherTest, Mars448_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Mars256_CFB, CipherTest, Mars256_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Mars256_GCM, CipherTest, Mars256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Mars256_GCM, AuthenticatedCipherTest, Mars256_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Mars128_CFB, CipherTest, Mars128_CFB); //CFB mode is not authenticated -INSTANTIATE_TYPED_TEST_SUITE_P(Mars128_GCM, CipherTest, Mars128_GCM); -INSTANTIATE_TYPED_TEST_SUITE_P(Mars128_GCM, AuthenticatedCipherTest, Mars128_GCM); - - -// Test cipher names -TEST(CipherNameTest, TestCipherNames) { - EXPECT_EQ("xchacha20-poly1305", string(XChaCha20Poly1305::NAME)); - - EXPECT_EQ("aes-256-gcm", string(AES256_GCM::NAME)); - EXPECT_EQ("aes-256-cfb", string(AES256_CFB::NAME)); - EXPECT_EQ("aes-128-gcm", string(AES128_GCM::NAME)); - EXPECT_EQ("aes-128-cfb", string(AES128_CFB::NAME)); - - EXPECT_EQ("twofish-256-gcm", string(Twofish256_GCM::NAME)); - EXPECT_EQ("twofish-256-cfb", string(Twofish256_CFB::NAME)); - EXPECT_EQ("twofish-128-gcm", string(Twofish128_GCM::NAME)); - EXPECT_EQ("twofish-128-cfb", string(Twofish128_CFB::NAME)); - - EXPECT_EQ("serpent-256-gcm", string(Serpent256_GCM::NAME)); - EXPECT_EQ("serpent-256-cfb", string(Serpent256_CFB::NAME)); - EXPECT_EQ("serpent-128-gcm", string(Serpent128_GCM::NAME)); - EXPECT_EQ("serpent-128-cfb", string(Serpent128_CFB::NAME)); - - EXPECT_EQ("cast-256-gcm", string(Cast256_GCM::NAME)); - EXPECT_EQ("cast-256-cfb", string(Cast256_CFB::NAME)); - - - EXPECT_EQ("mars-448-gcm", string(Mars448_GCM::NAME)); - EXPECT_EQ("mars-448-cfb", string(Mars448_CFB::NAME)); - EXPECT_EQ("mars-256-gcm", string(Mars256_GCM::NAME)); - EXPECT_EQ("mars-256-cfb", string(Mars256_CFB::NAME)); - EXPECT_EQ("mars-128-gcm", string(Mars128_GCM::NAME)); - EXPECT_EQ("mars-128-cfb", string(Mars128_CFB::NAME)); -} diff --git a/test/cpp-utils/data/DataFixtureIncludeTest.cpp b/test/cpp-utils/data/DataFixtureIncludeTest.cpp deleted file mode 100644 index 661525ed..00000000 --- a/test/cpp-utils/data/DataFixtureIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/data/DataFixture.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/data/DataFixtureTest.cpp b/test/cpp-utils/data/DataFixtureTest.cpp deleted file mode 100644 index 0fa60cdc..00000000 --- a/test/cpp-utils/data/DataFixtureTest.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include - -#include "cpp-utils/data/Data.h" -#include "cpp-utils/data/DataFixture.h" - -using ::testing::Test; - - -using namespace cpputils; - -class DataFixtureTest: public Test { -}; - -TEST_F(DataFixtureTest, CreateEmptyFixture) { - Data data = DataFixture::generate(0); - EXPECT_EQ(0u, data.size()); -} - -TEST_F(DataFixtureTest, CreateOneByteFixture) { - Data data = DataFixture::generate(1); - EXPECT_EQ(1u, data.size()); -} - -TEST_F(DataFixtureTest, CreateLargerFixture) { - Data data = DataFixture::generate(20 * 1024 * 1024); - EXPECT_EQ(20u * 1024u * 1024u, data.size()); -} - -TEST_F(DataFixtureTest, FixturesAreDeterministic_DefaultSeed) { - Data data1 = DataFixture::generate(1024 * 1024); - Data data2 = DataFixture::generate(1024 * 1024); - EXPECT_EQ(data1, data2); -} - -TEST_F(DataFixtureTest, FixturesAreDeterministic_SeedIs5) { - Data data1 = DataFixture::generate(1024 * 1024, 5); - Data data2 = DataFixture::generate(1024 * 1024, 5); - EXPECT_EQ(data1, data2); -} - -TEST_F(DataFixtureTest, DifferentSeedIsDifferentFixture) { - Data data1 = DataFixture::generate(1024 * 1024, 0); - Data data2 = DataFixture::generate(1024 * 1024, 1); - EXPECT_NE(data1, data2); -} - -TEST_F(DataFixtureTest, FixturesAreDeterministic_DifferentSize_DefaultSeed_1) { - Data data1 = DataFixture::generate(1024); - Data data2 = DataFixture::generate(1); - - EXPECT_EQ(0, std::memcmp(data1.data(), data2.data(), 1)); -} - -TEST_F(DataFixtureTest, FixturesAreDeterministic_DifferentSize_DefaultSeed_2) { - Data data1 = DataFixture::generate(1024); - Data data2 = DataFixture::generate(501); //Intentionally not 64bit-aligned, because the generate() function generates 64bit values for performance - - EXPECT_EQ(0, std::memcmp(data1.data(), data2.data(), 501)); -} - -TEST_F(DataFixtureTest, FixturesAreDeterministic_DifferentSize_SeedIs5_1) { - Data data1 = DataFixture::generate(1024, 5); - Data data2 = DataFixture::generate(1, 5); - - EXPECT_EQ(0, std::memcmp(data1.data(), data2.data(), 1)); -} - -TEST_F(DataFixtureTest, FixturesAreDeterministic_DifferentSize_SeedIs5_2) { - Data data1 = DataFixture::generate(1024, 5); - Data data2 = DataFixture::generate(501, 5); //Intentionally not 64bit-aligned, because the generate() function generates 64bit values for performance - - EXPECT_EQ(0, std::memcmp(data1.data(), data2.data(), 501)); -} diff --git a/test/cpp-utils/data/DataIncludeTest.cpp b/test/cpp-utils/data/DataIncludeTest.cpp deleted file mode 100644 index ff83ca7c..00000000 --- a/test/cpp-utils/data/DataIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/data/Data.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/data/DataTest.cpp b/test/cpp-utils/data/DataTest.cpp deleted file mode 100644 index 76d1b53d..00000000 --- a/test/cpp-utils/data/DataTest.cpp +++ /dev/null @@ -1,297 +0,0 @@ -#include "cpp-utils/data/DataFixture.h" -#include "cpp-utils/data/Data.h" -#include "cpp-utils/data/SerializationHelper.h" -#include -#include "cpp-utils/tempfile/TempFile.h" - -#include - -using ::testing::Test; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Return; - -using cpputils::TempFile; - -using std::ifstream; -using std::ofstream; -using std::string; - -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(data.dataOffset(i)) != 0) { - return false; - } - } - return true; - } -}; - -class DataTestWithSizeParam: public DataTest, public WithParamInterface { -public: - Data randomData; - - DataTestWithSizeParam(): randomData(DataFixture::generate(GetParam())) {} - - 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(data.data()), data.size()); - } - - static void EXPECT_STORED_FILE_DATA_CORRECT(const Data &data, const bf::path &filepath) { - EXPECT_EQ(data.size(), bf::file_size(filepath)); - - ifstream file(filepath.string().c_str(), std::ios::binary); - char *read_data = new char[data.size()]; - file.read(read_data, data.size()); - - EXPECT_EQ(0, std::memcmp(data.data(), read_data, data.size())); - delete[] read_data; - } -}; - -INSTANTIATE_TEST_SUITE_P(DataTestWithSizeParam, DataTestWithSizeParam, Values(0, 1, 2, 1024, 4096, 10*1024*1024)); - -TEST_P(DataTestWithSizeParam, ZeroInitializedDataIsDifferentToRandomData) { - if (GetParam() != 0) { - Data data(GetParam()); - data.FillWithZeroes(); - EXPECT_NE(randomData, data); - } -} - -// 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 = randomData.copy(); - EXPECT_EQ(randomData, data); -} - -TEST_P(DataTestWithSizeParam, Size) { - Data data(GetParam()); - EXPECT_EQ(GetParam(), data.size()); -} - -TEST_P(DataTestWithSizeParam, CheckStoredFile) { - TempFile file; - randomData.StoreToFile(file.path()); - - EXPECT_STORED_FILE_DATA_CORRECT(randomData, file.path()); -} - -TEST_P(DataTestWithSizeParam, CheckLoadedData) { - TempFile file; - StoreData(randomData, file.path()); - - Data data = Data::LoadFromFile(file.path()).value(); - - EXPECT_EQ(randomData, data); -} - -TEST_P(DataTestWithSizeParam, StoreDoesntChangeData) { - Data data = randomData.copy(); - - TempFile file; - data.StoreToFile(file.path()); - - EXPECT_EQ(randomData, data); -} - -TEST_P(DataTestWithSizeParam, StoreAndLoad) { - TempFile file; - randomData.StoreToFile(file.path()); - Data loaded_data = Data::LoadFromFile(file.path()).value(); - - EXPECT_EQ(randomData, loaded_data); -} - -TEST_P(DataTestWithSizeParam, Copy) { - Data copy = randomData.copy(); - EXPECT_EQ(randomData, copy); -} - -TEST_F(DataTest, ChangingCopyDoesntChangeOriginal) { - Data original = DataFixture::generate(1024); - Data copy = original.copy(); - serialize(copy.data(), deserialize(copy.data()) + 1); - EXPECT_EQ(DataFixture::generate(1024), original); - EXPECT_NE(copy, original); -} - -TEST_F(DataTest, InitializeWithZeroes) { - Data data(10*1024); - data.FillWithZeroes(); - EXPECT_TRUE(DataIsZeroes(data)); -} - -TEST_F(DataTest, FillModifiedDataWithZeroes) { - Data data = DataFixture::generate(10*1024); - EXPECT_FALSE(DataIsZeroes(data)); - - data.FillWithZeroes(); - EXPECT_TRUE(DataIsZeroes(data)); -} - -TEST_F(DataTest, MoveConstructor) { - Data original = DataFixture::generate(1024); - Data 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) -} - -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) -} - -TEST_F(DataTest, Equality) { - Data data1 = DataFixture::generate(1024); - Data data2 = DataFixture::generate(1024); - EXPECT_TRUE(data1 == data2); - EXPECT_FALSE(data1 != data2); -} - -TEST_F(DataTest, Inequality_DifferentSize) { - Data data1 = DataFixture::generate(1024); - Data data2 = DataFixture::generate(1023); - EXPECT_FALSE(data1 == data2); - EXPECT_TRUE(data1 != data2); -} - -TEST_F(DataTest, Inequality_DifferentFirstByte) { - Data data1 = DataFixture::generate(1024); - Data data2 = DataFixture::generate(1024); - serialize(data2.data(), deserialize(data2.data()) + 1); - EXPECT_FALSE(data1 == data2); - EXPECT_TRUE(data1 != data2); -} - -TEST_F(DataTest, Inequality_DifferentMiddleByte) { - Data data1 = DataFixture::generate(1024); - Data data2 = DataFixture::generate(1024); - serialize(data2.dataOffset(500), deserialize(data2.dataOffset(500)) + 1); - EXPECT_FALSE(data1 == data2); - EXPECT_TRUE(data1 != data2); -} - -TEST_F(DataTest, Inequality_DifferentLastByte) { - Data data1 = DataFixture::generate(1024); - Data data2 = DataFixture::generate(1024); - serialize(data2.dataOffset(1023), deserialize(data2.dataOffset(1023)) + 1); - EXPECT_FALSE(data1 == data2); - EXPECT_TRUE(data1 != data2); -} - -#ifdef __x86_64__ -TEST_F(DataTest, LargesizeSize) { - //Needs 64bit for representation. This value isn't in the size param list, because the list is also used for read/write checks. - uint64_t size = static_cast(4.5L*1024*1024*1024); - Data data(size); - EXPECT_EQ(size, data.size()); -} -#else -#if defined(_MSC_VER) -#pragma message This is not a 64bit architecture. Large size data tests are disabled. -#else -#warning This is not a 64bit architecture. Large size data tests are disabled. -#endif -#endif - -TEST_F(DataTest, LoadingNonexistingFile) { - TempFile file(false); // Pass false to constructor, so the tempfile is not created - EXPECT_FALSE(Data::LoadFromFile(file.path())); -} - -class DataTestWithStringParam: public DataTest, public WithParamInterface {}; -INSTANTIATE_TEST_SUITE_P(DataTestWithStringParam, DataTestWithStringParam, Values("", "2898B4B8A13C0F0278CCE465DB", "6FFEBAD90C0DAA2B79628F0627CE9841")); - -TEST_P(DataTestWithStringParam, FromAndToString) { - Data data = Data::FromString(GetParam()); - EXPECT_EQ(GetParam(), data.ToString()); -} - -TEST_P(DataTestWithStringParam, ToAndFromString) { - Data data = Data::FromString(GetParam()); - Data data2 = Data::FromString(data.ToString()); - EXPECT_EQ(data, data2); -} - -struct MockAllocator final : public Allocator { - MOCK_METHOD(void* , allocate, (size_t), (override)); - MOCK_METHOD(void, free, (void*, size_t), (override)); -}; - -class DataTestWithMockAllocator: public DataTest { -public: - char ptr_target{}; - - unique_ref allocator = make_unique_ref(); - 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)); - Data data(5, std::move(allocator)); - - 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)); - Data data2 = std::move(data); - - 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)); - EXPECT_CALL(*allocator_ptr, free(testing::_, testing::_)).Times(0); - - auto data = std::make_unique(5, std::move(allocator)); - Data data2 = std::move(*data); - 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)); - EXPECT_CALL(*allocator_ptr, free(testing::_, testing::_)).Times(0); - - auto data = std::make_unique(5, std::move(allocator)); - Data data2(3); - data2 = std::move(*data); - data.reset(); - - EXPECT_CALL(*allocator_ptr, free(&ptr_target, 5)).Times(1); -} diff --git a/test/cpp-utils/data/FixedSizeDataIncludeTest.cpp b/test/cpp-utils/data/FixedSizeDataIncludeTest.cpp deleted file mode 100644 index 9440ebc0..00000000 --- a/test/cpp-utils/data/FixedSizeDataIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/data/FixedSizeData.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/data/FixedSizeDataTest.cpp b/test/cpp-utils/data/FixedSizeDataTest.cpp deleted file mode 100644 index b016a39a..00000000 --- a/test/cpp-utils/data/FixedSizeDataTest.cpp +++ /dev/null @@ -1,192 +0,0 @@ -#include "cpp-utils/data/DataFixture.h" -#include "cpp-utils/data/FixedSizeData.h" -#include "cpp-utils/data/Data.h" -#include - - -using ::testing::Test; -using ::testing::WithParamInterface; -using ::testing::Values; - -using std::string; - -using namespace cpputils; - -class FixedSizeDataTest: public Test { -public: - static constexpr size_t SIZE = 16; - - const string DATA1_AS_STRING = "1491BB4932A389EE14BC7090AC772972"; - const string DATA2_AS_STRING = "272EE5517627CFA147A971A8E6E747E0"; - - const Data DATA3_AS_BINARY; - const Data DATA4_AS_BINARY; - - FixedSizeDataTest() : DATA3_AS_BINARY(DataFixture::generate(SIZE, 1)), DATA4_AS_BINARY(DataFixture::generate(SIZE, 2)) {} - - template - void EXPECT_DATA_EQ(const Data &expected, const FixedSizeData &actual) { - EXPECT_EQ(expected.size(), SIZE); - EXPECT_EQ(0, std::memcmp(expected.data(), actual.data(), SIZE)); - } -}; - -constexpr size_t FixedSizeDataTest::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_SUITE_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 Data VALUE1; - static const Data VALUE2; -}; -const Data FixedSizeDataTestWithBinaryParam::VALUE1(DataFixture::generate(SIZE, 3)); -const Data FixedSizeDataTestWithBinaryParam::VALUE2(DataFixture::generate(SIZE, 4)); -INSTANTIATE_TEST_SUITE_P(FixedSizeDataTestWithBinaryParam, FixedSizeDataTestWithBinaryParam, Values(&FixedSizeDataTestWithBinaryParam::VALUE1, &FixedSizeDataTestWithBinaryParam::VALUE2)); - -TEST_P(FixedSizeDataTestWithBinaryParam, FromBinary) { - FixedSizeData data = FixedSizeData::FromBinary(GetParam()->data()); - EXPECT_DATA_EQ(*GetParam(), data); -} - -TEST_P(FixedSizeDataTestWithBinaryParam, FromAndToBinary) { - FixedSizeData data = FixedSizeData::FromBinary(GetParam()->data()); - Data output(FixedSizeData::BINARY_LENGTH); - data.ToBinary(output.data()); - EXPECT_EQ(*GetParam(), output); -} - -TEST_P(FixedSizeDataTestWithBinaryParam, ToAndFromBinary) { - FixedSizeData data = FixedSizeData::FromBinary(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_SUITE_P(FixedSizeDataTestWithParam, FixedSizeDataTestWithParam, Values(FixedSizeData::FromString("2898B4B8A13CA63CBE0F0278CCE465DB"), FixedSizeData::FromString("6FFEBAD90C0DAA2B79628F0627CE9841"))); - -TEST_P(FixedSizeDataTestWithParam, CopyConstructor) { - FixedSizeData copy(GetParam()); - EXPECT_EQ(GetParam(), copy); -} - -TEST_P(FixedSizeDataTestWithParam, Take_Half) { - FixedSizeData source(GetParam()); - FixedSizeData taken = source.take(); - EXPECT_EQ(0, std::memcmp(source.data(), taken.data(), SIZE/2)); -} - -TEST_P(FixedSizeDataTestWithParam, Drop_Half) { - FixedSizeData source(GetParam()); - FixedSizeData taken = source.drop(); - EXPECT_EQ(0, std::memcmp(source.data() + SIZE/2, taken.data(), SIZE/2)); -} - -TEST_P(FixedSizeDataTestWithParam, Take_One) { - FixedSizeData source(GetParam()); - FixedSizeData<1> taken = source.take<1>(); - EXPECT_EQ(0, std::memcmp(source.data(), taken.data(), 1)); -} - -TEST_P(FixedSizeDataTestWithParam, Drop_One) { - FixedSizeData source(GetParam()); - FixedSizeData taken = source.drop<1>(); - EXPECT_EQ(0, std::memcmp(source.data() + 1, taken.data(), SIZE-1)); -} - -TEST_P(FixedSizeDataTestWithParam, Take_Nothing) { - FixedSizeData source(GetParam()); - FixedSizeData<0> taken = source.take<0>(); - (void)taken; // silence unused variable warning -} - -TEST_P(FixedSizeDataTestWithParam, Drop_Nothing) { - FixedSizeData source(GetParam()); - FixedSizeData taken = source.drop<0>(); - EXPECT_EQ(0, std::memcmp(source.data(), taken.data(), SIZE)); -} - -TEST_P(FixedSizeDataTestWithParam, Take_All) { - FixedSizeData source(GetParam()); - FixedSizeData taken = source.take(); - EXPECT_EQ(0, std::memcmp(source.data(), taken.data(), SIZE)); -} - -TEST_P(FixedSizeDataTestWithParam, Drop_All) { - FixedSizeData source(GetParam()); - FixedSizeData<0> taken = source.drop(); - (void)taken; // silence unused variable warning -} - -TEST_F(FixedSizeDataTest, CopyConstructorDoesntChangeSource) { - FixedSizeData data1 = FixedSizeData::FromString(DATA1_AS_STRING); - FixedSizeData data2(data1); - EXPECT_EQ(DATA1_AS_STRING, data1.ToString()); - (void)data2; // silence unused variable warning -} - -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)); -} diff --git a/test/cpp-utils/data/SerializationHelperTest.cpp b/test/cpp-utils/data/SerializationHelperTest.cpp deleted file mode 100644 index e252ee5f..00000000 --- a/test/cpp-utils/data/SerializationHelperTest.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include -#include -#include - -using cpputils::serialize; -using cpputils::deserialize; -using cpputils::deserializeWithOffset; -using cpputils::Data; - -TEST(SerializationHelperTest, uint8) { - Data data(1); - serialize(data.data(), 5u); - EXPECT_EQ(5u, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int8_positive) { - Data data(1); - serialize(data.data(), 5); - EXPECT_EQ(5, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int8_negative) { - Data data(1); - serialize(data.data(), -5); - EXPECT_EQ(-5, deserialize(data.data())); -} - -TEST(SerializationHelperTest, uint16_aligned) { - Data data(2); - serialize(data.data(), 1000u); - EXPECT_EQ(1000u, deserialize(data.data())); -} - -TEST(SerializationHelperTest, uint16_unaligned) { - Data data(3); - serialize(data.dataOffset(1), 1000u); - EXPECT_EQ(1000u, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, int16_postive_aligned) { - Data data(2); - serialize(data.data(), 1000); - EXPECT_EQ(1000, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int16_positive_unaligned) { - Data data(3); - serialize(data.dataOffset(1), 1000); - EXPECT_EQ(1000, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, int16_negative_aligned) { - Data data(2); - serialize(data.data(), -1000); - EXPECT_EQ(-1000, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int16_negative_unaligned) { - Data data(3); - serialize(data.dataOffset(1), -1000); - EXPECT_EQ(-1000, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, uint32_aligned) { - Data data(4); - serialize(data.data(), 100000u); - EXPECT_EQ(100000u, deserialize(data.data())); -} - -TEST(SerializationHelperTest, uint32_unaligned) { - Data data(5); - serialize(data.dataOffset(1), 100000u); - EXPECT_EQ(100000u, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, int32_positive_aligned) { - Data data(4); - serialize(data.data(), 100000); - EXPECT_EQ(100000, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int32_positive_unaligned) { - Data data(5); - serialize(data.dataOffset(1), 100000); - EXPECT_EQ(100000, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, int32_negative_aligned) { - Data data(4); - serialize(data.data(), -100000); - EXPECT_EQ(-100000, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int32_negative_unaligned) { - Data data(5); - serialize(data.dataOffset(1), -100000); - EXPECT_EQ(-100000, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, uint64_aligned) { - Data data(8); - serialize(data.data(), 10000000000u); - EXPECT_EQ(10000000000u, deserialize(data.data())); -} - -TEST(SerializationHelperTest, uint64_unaligned) { - Data data(9); - serialize(data.dataOffset(1), 10000000000u); - EXPECT_EQ(10000000000u, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, int64_positive_aligned) { - Data data(8); - serialize(data.data(), 10000000000); - EXPECT_EQ(10000000000, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int64_positive_unaligned) { - Data data(9); - serialize(data.dataOffset(1), 10000000000); - EXPECT_EQ(10000000000, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, int64_negative_aligned) { - Data data(8); - serialize(data.data(), -10000000000); - EXPECT_EQ(-10000000000, deserialize(data.data())); -} - -TEST(SerializationHelperTest, int64_negative_unaligned) { - Data data(9); - serialize(data.dataOffset(1), -10000000000); - EXPECT_EQ(-10000000000, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, float_aligned) { - Data data(sizeof(float)); - serialize(data.data(), 3.1415f); - EXPECT_EQ(3.1415f, deserialize(data.data())); -} - -TEST(SerializationHelperTest, float_unaligned) { - Data data(sizeof(float) + 1); - serialize(data.dataOffset(1), 3.1415f); - EXPECT_EQ(3.1415f, deserialize(data.dataOffset(1))); -} - -TEST(SerializationHelperTest, double_aligned) { - Data data(sizeof(double)); - serialize(data.data(), 3.1415); - EXPECT_EQ(3.1415, deserialize(data.data())); -} - -TEST(SerializationHelperTest, double_unaligned) { - Data data(sizeof(double) + 1); - serialize(data.dataOffset(1), 3.1415); - EXPECT_EQ(3.1415, deserialize(data.dataOffset(1))); -} - -namespace { -struct DataStructure final { - uint64_t v1; - uint32_t v2; - uint16_t v3; - uint8_t v4; -}; - -bool operator==(const DataStructure &lhs, const DataStructure &rhs) { - return lhs.v1 == rhs.v1 && lhs.v2 == rhs.v2 && lhs.v3 == rhs.v3 && lhs.v4 == rhs.v4; -} -} - -TEST(SerializationHelperTest, struct_aligned) { - Data data(sizeof(DataStructure)); - const DataStructure fixture {10000000000u, 100000u, 1000u, 5u}; - serialize(data.data(), fixture); - EXPECT_EQ(fixture, deserialize(data.data())); -} - -TEST(SerializationHelperTest, struct_unaligned) { - Data data(sizeof(DataStructure) + 1); - const DataStructure fixture {10000000000u, 100000u, 1000u, 5u}; - serialize(data.dataOffset(1), fixture); - EXPECT_EQ(fixture, deserialize(data.dataOffset(1))); -} - -namespace { -struct OneByteStruct final { - uint8_t v; -}; -static_assert(sizeof(OneByteStruct) == 1, ""); -} - -TEST(SerializationHelperTest, onebytestruct) { - Data data(1); - OneByteStruct fixture {5}; - serialize(data.data(), fixture); - EXPECT_EQ(fixture.v, deserialize(data.data()).v); -} - -TEST(SerializationHelperTest, deserializeWithOffset) { - Data data(5); - serialize(data.dataOffset(1), 1000); - EXPECT_EQ(1000, deserializeWithOffset(data.data(), 1)); -} diff --git a/test/cpp-utils/either_test.cpp b/test/cpp-utils/either_test.cpp deleted file mode 100644 index 4be62014..00000000 --- a/test/cpp-utils/either_test.cpp +++ /dev/null @@ -1,1266 +0,0 @@ -#include -#include -#include -#include -#include -#include - -using std::string; -using std::vector; -using std::pair; -using std::tuple; -using std::ostringstream; -using cpputils::either; -using cpputils::make_left; -using cpputils::make_right; - -// TODO Test noexcept tags are correct - -namespace { -class MovableOnly final { -public: - explicit MovableOnly(int value): _value(value) {} - MovableOnly(const MovableOnly&) = delete; - MovableOnly& operator=(const MovableOnly&) = delete; - - MovableOnly(MovableOnly&& rhs): _value(rhs._value) { - rhs._value = 0; - } - - MovableOnly& operator=(MovableOnly&& rhs) { - _value = rhs._value; - rhs._value = 0; - return *this; - } - - int value() const { - return _value; - } - -private: - int _value; -}; - -bool operator==(const MovableOnly& lhs, const MovableOnly& rhs) { - return lhs.value() == rhs.value(); -} - -std::ostream& operator<<(std::ostream& str, const MovableOnly& v) { - return str << "MovableOnly(" << v.value() << ")"; -} - -template -void test_with_matrix(std::vector)>> setups, std::vector> expectations) { - for (const auto& setup: setups) { - for (const auto& expectation: expectations) { - setup(expectation); - } - } -} - -template -std::vector&)>> EXPECT_IS_LEFT(const Left& expected) { - return { - [&] (auto& obj) { - EXPECT_TRUE(obj.is_left()); - }, [&] (auto& obj) { - EXPECT_FALSE(obj.is_right()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, obj.left()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, std::move(obj).left()); - }, [&] (auto& obj) { - EXPECT_ANY_THROW(obj.right()); - }, [&] (auto& obj) { - EXPECT_ANY_THROW(std::move(obj).right()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, obj.left_opt().value()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, std::move(obj).left_opt().value()); - }, [&] (auto& obj) { - EXPECT_TRUE(boost::none == obj.right_opt()); - }, [&] (auto& obj) { - EXPECT_TRUE(boost::none == std::move(obj).right_opt()); - } - }; -} - -template -std::vector&)>> EXPECT_IS_RIGHT(const Right& expected) { - return { - [&] (auto& obj) { - EXPECT_FALSE(obj.is_left()); - }, [&] (auto& obj) { - EXPECT_TRUE(obj.is_right()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, obj.right()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, std::move(obj).right()); - }, [&] (auto& obj) { - EXPECT_ANY_THROW(obj.left()); - }, [&] (auto& obj) { - EXPECT_ANY_THROW(std::move(obj).left()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, obj.right_opt().value()); - }, [&] (auto& obj) { - EXPECT_EQ(expected, std::move(obj).right_opt().value()); - }, [&] (auto& obj) { - EXPECT_TRUE(boost::none == obj.left_opt()); - }, [&] (auto& obj) { - EXPECT_TRUE(boost::none == std::move(obj).left_opt()); - } - }; -} - -template -std::vector> EXPECT_IS(const Value& v) { - return { - [&] (auto& obj) { - return obj == v; - } - }; -} - -template -struct StoreWith1ByteFlag { - T val; - char flag; -}; - -template -void TestSpaceUsage() { - EXPECT_EQ(std::max(sizeof(StoreWith1ByteFlag), sizeof(StoreWith1ByteFlag)), sizeof(either)); -} -} - -TEST(EitherTest, SpaceUsage) { - TestSpaceUsage(); - TestSpaceUsage(); - TestSpaceUsage(); - TestSpaceUsage(); - TestSpaceUsage>(); -} - -TEST(EitherTest, givenLeft) { - test_with_matrix({ - [] (const auto& test) { - either a(4); - test(a); - }, [] (const auto& test) { - either a = 4; - test(a); - }, - }, - EXPECT_IS_LEFT(4) - ); -} - -TEST(EitherTest, givenRight) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - test(a); - }, [] (const auto& test) { - either a = string("4"); - test(a); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenMakeLeft) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left(4); - test(a); - }, [] (const auto& test) { - auto a = make_left(4); - test(a); - }, - }, - EXPECT_IS_LEFT(4) - ); -} - -TEST(EitherTest, givenMakeLeftWithSameType) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left(4); - test(a); - }, [] (const auto& test) { - auto a = make_left(4); - test(a); - }, - }, - EXPECT_IS_LEFT(4) - ); -} - -TEST(EitherTest, givenMakeRight) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right("4"); - test(a); - }, [] (const auto& test) { - auto a = make_right("4"); - test(a); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenMakeRightWithSameType) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right("4"); - test(a); - }, [] (const auto& test) { - auto a = make_right("4"); - test(a); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenMovableOnlyMakeLeft) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left(3); - test(a); - }, [] (const auto& test) { - auto a = make_left(3); - test(a); - }, - }, - EXPECT_IS_LEFT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenMovableOnlyMakeRight) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right(3); - test(a); - }, [] (const auto& test) { - auto a = make_right(3); - test(a); - } - }, - EXPECT_IS_RIGHT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenMultiParamMakeLeft) { - test_with_matrix({ - [] (const auto& test) { - either, string> a = make_left, string>(5, 6); - test(a); - }, [] (const auto& test) { - auto a = make_left, string>(5, 6); - test(a); - }, - }, - EXPECT_IS_LEFT, string>(pair(5, 6)) - ); -} - -TEST(EitherTest, givenMultiParamMakeRight) { - test_with_matrix({ - [] (const auto& test) { - either> a = make_right>(5, 6); - test(a); - }, [] (const auto& test) { - auto a = make_right>(5, 6); - test(a); - } - }, - EXPECT_IS_RIGHT>(pair(5, 6)) - ); -} - -TEST(EitherTest, givenLeftCopyConstructedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(a); - test(b); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyConstructedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(a); - test(a); - } - }, - EXPECT_IS("4") - ); -} - -TEST(EitherTest, givenRightCopyConstructedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(a); - test(b); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenRightCopyConstructedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(a); - test(a); - } - }, - EXPECT_IS("4") - ); -} - -TEST(EitherTest, givenLeftMoveConstructedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b(std::move(a)); - test(b); - } - }, - EXPECT_IS_LEFT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenLeftMoveConstructedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b(std::move(a)); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenRightMoveConstructedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b(std::move(a)); - test(b); - } - }, - EXPECT_IS_RIGHT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenRightMoveConstructedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b(std::move(a)); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenLeftCopyAssignedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(2); - b = a; - test(b); - }, [] (const auto& test) { - string a = "4"; - either b("2"); - b = a; - test(b); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyAssignedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(2); - b = a; - test(a); - }, [] (const auto& test) { - string a = "4"; - either b("2"); - b = a; - test(a); - } - }, - EXPECT_IS("4") - ); -} - -TEST(EitherTest, givenRightCopyAssignedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(2); - b = a; - test(b); - }, [] (const auto& test) { - string a = "4"; - either b("2"); - b = a; - test(b); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenRightCopyAssignedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - string a = "4"; - either b(2); - b = a; - test(a); - }, [] (const auto& test) { - string a = "4"; - either b("2"); - b = a; - test(a); - } - }, - EXPECT_IS("4") - ); -} - -TEST(EitherTest, givenLeftMoveAssignedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b(2); - b = std::move(a); - test(b); - }, [] (const auto& test) { - MovableOnly a(3); - either b(MovableOnly(2)); - b = std::move(a); - test(b); - } - }, - EXPECT_IS_LEFT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenLeftMoveAssignedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b("2"); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - }, [] (const auto& test) { - MovableOnly a(3); - either b(MovableOnly(0)); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS(MovableOnly(0)) - ); -} - -TEST(EitherTest, givenRightMoveAssignedFromValue_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b("2"); - b = std::move(a); - test(b); - }, [] (const auto& test) { - MovableOnly a(3); - either b(MovableOnly(2)); - b = std::move(a); - test(b); - } - }, - EXPECT_IS_RIGHT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenRightMoveAssignedFromValue_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - MovableOnly a(3); - either b("2"); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - }, [] (const auto& test) { - MovableOnly a(3); - either b(MovableOnly(2)); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenLeftCopyConstructed_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(a); - test(b); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyConstructed_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(a); - test(a); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyConstructed_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left("4"); - either b(a); - test(b); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyConstructed_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left("4"); - either b(a); - test(a); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenRightCopyConstructed_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(a); - test(b); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - - -TEST(EitherTest, givenRightCopyConstructed_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(a); - test(a); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenRightCopyConstructed_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right("4"); - either b(a); - test(b); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - - -TEST(EitherTest, givenRightCopyConstructed_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right("4"); - either b(a); - test(a); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenLeftMoveConstructed_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b(std::move(a)); - test(b); - } - }, - EXPECT_IS_LEFT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenLeftMoveConstructed_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b(std::move(a)); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_LEFT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenLeftMoveConstructed_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left(MovableOnly(3)); - either b(std::move(a)); - test(b); - } - }, - EXPECT_IS_LEFT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenLeftMoveConstructed_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left(MovableOnly(3)); - either b(std::move(a)); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_LEFT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenRightMoveConstructed_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b(std::move(a)); - test(b); - } - }, - EXPECT_IS_RIGHT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenRightMoveConstructed_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b(std::move(a)); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_RIGHT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenRightMoveConstructed_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right(MovableOnly(3)); - either b(std::move(a)); - test(b); - } - }, - EXPECT_IS_RIGHT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenRightMoveConstructed_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right(MovableOnly(3)); - either b(std::move(a)); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_RIGHT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenLeftCopyAssigned_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(2); - b = a; - test(b); - }, [] (const auto& test) { - either a("4"); - either b("2"); - b = a; - test(b); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyAssigned_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(2); - b = a; - test(a); - }, [] (const auto& test) { - either a("4"); - either b("2"); - b = a; - test(a); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyAssigned_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left("4"); - either b = make_right("2"); - b = a; - test(b); - }, [] (const auto& test) { - either a = make_left("4"); - either b = make_left("2"); - b = a; - test(b); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenLeftCopyAssigned_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left("4"); - either b = make_right("2"); - b = a; - test(a); - }, [] (const auto& test) { - either a = make_left("4"); - either b = make_left("2"); - b = a; - test(a); - } - }, - EXPECT_IS_LEFT("4") - ); -} - -TEST(EitherTest, givenRightCopyAssigned_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(2); - b = a; - test(b); - }, [] (const auto& test) { - either a("4"); - either b("2"); - b = a; - test(b); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenRightCopyAssigned_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - either b(2); - b = a; - test(a); - }, [] (const auto& test) { - either a("4"); - either b("2"); - b = a; - test(a); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenRightCopyAssigned_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right("4"); - either b = make_left("2"); - b = a; - test(b); - }, [] (const auto& test) { - either a = make_right("4"); - either b = make_right("2"); - b = a; - test(b); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenRightCopyAssigned_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right("4"); - either b = make_left("2"); - b = a; - test(a); - }, [] (const auto& test) { - either a = make_right("4"); - either b = make_right("2"); - b = a; - test(a); - } - }, - EXPECT_IS_RIGHT("4") - ); -} - -TEST(EitherTest, givenLeftMoveAssigned_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b(2); - b = std::move(a); - test(b); - }, [] (const auto& test) { - either a(MovableOnly(3)); - either b(MovableOnly(2)); - b = std::move(a); - test(b); - } - }, - EXPECT_IS_LEFT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenLeftMoveAssigned_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b(2); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - }, [] (const auto& test) { - either a(MovableOnly(3)); - either b(MovableOnly(2)); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_LEFT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenLeftMoveAssigned_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left(3); - either b = make_right(2); - b = std::move(a); - test(b); - }, [] (const auto& test) { - either a = make_left(3); - either b = make_left(2); - b = std::move(a); - test(b); - } - }, - EXPECT_IS_LEFT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenLeftMoveAssigned_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_left(3); - either b = make_right(2); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - }, [] (const auto& test) { - either a = make_left(3); - either b = make_left(2); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_LEFT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenRightMoveAssigned_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b("2"); - b = std::move(a); - test(b); - }, [] (const auto& test) { - either a(MovableOnly(3)); - either b(MovableOnly(2)); - b = std::move(a); - test(b); - } - }, - EXPECT_IS_RIGHT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenRightMoveAssigned_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a(MovableOnly(3)); - either b("2"); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - }, [] (const auto& test) { - either a(MovableOnly(3)); - either b(MovableOnly(2)); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_RIGHT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenRightMoveAssigned_withSameType_thenNewIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right(3); - either b = make_left(2); - b = std::move(a); - test(b); - }, [] (const auto& test) { - either a = make_right(3); - either b = make_right(2); - b = std::move(a); - test(b); - } - }, - EXPECT_IS_RIGHT(MovableOnly(3)) - ); -} - -TEST(EitherTest, givenRightMoveAssigned_withSameType_thenOldIsCorrect) { - test_with_matrix({ - [] (const auto& test) { - either a = make_right(3); - either b = make_left(2); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - }, [] (const auto& test) { - either a = make_right(3); - either b = make_right(2); - b = std::move(a); - test(a); // NOLINT(bugprone-use-after-move) - } - }, - EXPECT_IS_RIGHT(MovableOnly(0)) // 0 is moved-from value - ); -} - -TEST(EitherTest, givenLeft_whenModified_thenValueIsChanged) { - test_with_matrix({ - [] (const auto& test) { - either a(4); - a.left() = 5; - test(a); - }, [] (const auto& test) { - either a(4); - *a.left_opt() = 5; // NOLINT(clang-analyzer-core.uninitialized.UndefReturn) - test(a); - } - }, - EXPECT_IS_LEFT(5) - ); -} - -TEST(EitherTest, givenRight_whenModified_thenValueIsChanged) { - test_with_matrix({ - [] (const auto& test) { - either a("4"); - a.right() = "5"; - test(a); - }, [] (const auto& test) { - either a("4"); - *a.right_opt() = "5"; // NOLINT(clang-analyzer-core.uninitialized.UndefReturn) - test(a); - } - }, - EXPECT_IS_RIGHT("5") - ); -} - -TEST(EitherTest, canEmplaceConstructLeft) { - test_with_matrix({ - [] (const auto& test) { - either, tuple> a(2, 3); - test(a); - } - }, - EXPECT_IS_LEFT, tuple>(tuple(2, 3)) - ); -} - -TEST(EitherTest, canEmplaceConstructRight) { - test_with_matrix({ - [] (const auto& test) { - either, tuple> a(2, "3", 4); - test(a); - } - }, - EXPECT_IS_RIGHT, tuple>(tuple(2, "3", 4)) - ); -} - -TEST(EitherTest, givenEqualLefts_thenAreEqual) { - either a("3"); - either b("3"); - EXPECT_TRUE(a == b); -} - -TEST(EitherTest, givenEqualLefts_thenAreNotUnequal) { - either a("3"); - either b("3"); - EXPECT_FALSE(a != b); -} - -TEST(EitherTest, givenEqualRights_thenAreEqual) { - either a(3); - either b(3); - EXPECT_TRUE(a == b); -} - -TEST(EitherTest, givenEqualRights_thenAreNotUnequal) { - either a(3); - either b(3); - EXPECT_FALSE(a != b); -} - -TEST(EitherTest, givenLeftAndRight_thenAreNotEqual) { - either a("3"); - either b(3); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); -} - -TEST(EitherTest, givenLeftAndRight_thenAreUnequal) { - either a("3"); - either b(3); - EXPECT_TRUE(a != b); - EXPECT_TRUE(b != a); -} - -TEST(EitherTest, OutputLeft) { - ostringstream str; - str << either("mystring"); - EXPECT_EQ("Left(mystring)", str.str()); -} - -TEST(EitherTest, OutputRight) { - ostringstream str; - str << either("mystring"); - EXPECT_EQ("Right(mystring)", str.str()); -} - -TEST(EitherTest, givenLeftAndRightWithSameType_thenAreNotEqual) { - either a = make_left("3"); - either b = make_right("3"); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); -} - -TEST(EitherTest, givenLeftAndRightWithSameType_thenAreUnequal) { - either a = make_left("3"); - either b = make_right("3"); - EXPECT_TRUE(a != b); - EXPECT_TRUE(b != a); -} - - -namespace { -class DestructorCallback { -public: - MOCK_METHOD(void, call, (), (const)); - - void EXPECT_CALLED(int times = 1) { - EXPECT_CALL(*this, call()).Times(times); - } -}; -class ClassWithDestructorCallback { -public: - ClassWithDestructorCallback(const DestructorCallback *destructorCallback) : _destructorCallback(destructorCallback) {} - ClassWithDestructorCallback(const ClassWithDestructorCallback &rhs): _destructorCallback(rhs._destructorCallback) {} - - ~ClassWithDestructorCallback() { - _destructorCallback->call(); - } - -private: - const DestructorCallback *_destructorCallback; - - ClassWithDestructorCallback &operator=(const ClassWithDestructorCallback &rhs) = delete; -}; -class OnlyMoveableClassWithDestructorCallback { -public: - OnlyMoveableClassWithDestructorCallback(const DestructorCallback *destructorCallback) : _destructorCallback(destructorCallback) { } - OnlyMoveableClassWithDestructorCallback(OnlyMoveableClassWithDestructorCallback &&source): _destructorCallback(source._destructorCallback) {} - - ~OnlyMoveableClassWithDestructorCallback() { - _destructorCallback->call(); - } - -private: - DISALLOW_COPY_AND_ASSIGN(OnlyMoveableClassWithDestructorCallback); - const DestructorCallback *_destructorCallback; -}; - -} - -TEST(EitherTest_Destructor, LeftDestructorIsCalled) { - DestructorCallback destructorCallback; - destructorCallback.EXPECT_CALLED(2); //Once for the temp object, once when the either class destructs - - ClassWithDestructorCallback temp(&destructorCallback); - either var = temp; -} - -TEST(EitherTest_Destructor, RightDestructorIsCalled) { - DestructorCallback destructorCallback; - destructorCallback.EXPECT_CALLED(2); //Once for the temp object, once when the either class destructs - - ClassWithDestructorCallback temp(&destructorCallback); - either var = temp; -} - -TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterCopying) { - DestructorCallback destructorCallback; - destructorCallback.EXPECT_CALLED(3); //Once for the temp object, once for var1 and once for var2 - - ClassWithDestructorCallback temp(&destructorCallback); - either var1 = temp; - either var2 = var1; -} - -TEST(EitherTest_Destructor, RightDestructorIsCalledAfterCopying) { - DestructorCallback destructorCallback; - destructorCallback.EXPECT_CALLED(3); //Once for the temp object, once for var1 and once for var2 - - ClassWithDestructorCallback temp(&destructorCallback); - either var1 = temp; - either var2 = var1; -} - -TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterMoving) { - DestructorCallback destructorCallback; - destructorCallback.EXPECT_CALLED(3); //Once for the temp object, once for var1 and once for var2 - - OnlyMoveableClassWithDestructorCallback temp(&destructorCallback); - either var1 = std::move(temp); - either var2 = std::move(var1); -} - -TEST(EitherTest_Destructor, RightDestructorIsCalledAfterMoving) { - DestructorCallback destructorCallback; - destructorCallback.EXPECT_CALLED(3); //Once for the temp object, once for var1 and once for var2 - - OnlyMoveableClassWithDestructorCallback temp(&destructorCallback); - either var1 = std::move(temp); - either var2 = std::move(var1); -} - -TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterAssignment) { - DestructorCallback destructorCallback1; - DestructorCallback destructorCallback2; - destructorCallback1.EXPECT_CALLED(2); //Once for the temp1 object, once at the assignment - destructorCallback2.EXPECT_CALLED(3); //Once for the temp2 object, once in destructor of var2, once in destructor of var1 - - ClassWithDestructorCallback temp1(&destructorCallback1); - either var1 = temp1; - ClassWithDestructorCallback temp2(&destructorCallback2); - either var2 = temp2; - var1 = var2; -} - -TEST(EitherTest_Destructor, RightDestructorIsCalledAfterAssignment) { - DestructorCallback destructorCallback1; - DestructorCallback destructorCallback2; - destructorCallback1.EXPECT_CALLED(2); //Once for the temp1 object, once at the assignment - destructorCallback2.EXPECT_CALLED(3); //Once for the temp2 object, once in destructor of var2, once in destructor of var1 - - ClassWithDestructorCallback temp1(&destructorCallback1); - either var1 = temp1; - ClassWithDestructorCallback temp2(&destructorCallback2); - either var2 = temp2; - var1 = var2; -} - -TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterMoveAssignment) { - DestructorCallback destructorCallback1; - DestructorCallback destructorCallback2; - destructorCallback1.EXPECT_CALLED(2); //Once for the temp1 object, once at the assignment - destructorCallback2.EXPECT_CALLED(3); //Once for the temp2 object, once in destructor of var2, once in destructor of var1 - - OnlyMoveableClassWithDestructorCallback temp1(&destructorCallback1); - either var1 = std::move(temp1); - OnlyMoveableClassWithDestructorCallback temp2(&destructorCallback2); - either var2 = std::move(temp2); - var1 = std::move(var2); -} - -TEST(EitherTest_Destructor, RightDestructorIsCalledAfterMoveAssignment) { - DestructorCallback destructorCallback1; - DestructorCallback destructorCallback2; - destructorCallback1.EXPECT_CALLED(2); //Once for the temp1 object, once at the assignment - destructorCallback2.EXPECT_CALLED(3); //Once for the temp2 object, once in destructor of var2, once in destructor of var1 - - OnlyMoveableClassWithDestructorCallback temp1(&destructorCallback1); - either var1 = std::move(temp1); - OnlyMoveableClassWithDestructorCallback temp2(&destructorCallback2); - either var2 = std::move(temp2); - var1 = std::move(var2); -} diff --git a/test/cpp-utils/io/ConsoleIncludeTest.cpp b/test/cpp-utils/io/ConsoleIncludeTest.cpp deleted file mode 100644 index 7f24a430..00000000 --- a/test/cpp-utils/io/ConsoleIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/io/Console.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/io/ConsoleTest.h b/test/cpp-utils/io/ConsoleTest.h deleted file mode 100644 index 10a57f49..00000000 --- a/test/cpp-utils/io/ConsoleTest.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once -#ifndef MESSMER_CPPUTILS_TEST_IO_CONSOLETEST_H -#define MESSMER_CPPUTILS_TEST_IO_CONSOLETEST_H - -#include - -#include "cpp-utils/io/IOStreamConsole.h" - -#include -#include -#include "cpp-utils/io/pipestream.h" - -class ConsoleThread { -public: - ConsoleThread(std::ostream &ostr, std::istream &istr): _console(ostr, istr) {} - std::future ask(const std::string &question, const std::vector &options) { - return std::async(std::launch::async, [this, question, options]() { - return _console.ask(question, options); - }); - } - std::future askYesNo(const std::string &question) { - return std::async(std::launch::async, [this, question]() { - return _console.askYesNo(question, true); - }); - } - std::future askPassword(const std::string &question) { - return std::async(std::launch::async, [this, question]() { - return _console.askPassword(question); - }); - } - void print(const std::string &output) { - _console.print(output); - } -private: - cpputils::IOStreamConsole _console; -}; - -class ConsoleTest: public ::testing::Test { -public: - ConsoleTest(): _inputStr(), _outputStr(), _input(&_inputStr), _output(&_outputStr), _console(_output, _input) {} - - void EXPECT_OUTPUT_LINES(std::initializer_list lines) { - for (const std::string &line : lines) { - EXPECT_OUTPUT_LINE(line); - } - } - - void EXPECT_OUTPUT_LINE(const std::string &expected, char delimiter = '\n', const std::string &expected_after_delimiter = "") { - std::string actual; - std::getline(_output, actual, delimiter); - EXPECT_EQ(expected, actual); - for (char expected_char : expected_after_delimiter) { - char actual_char = 0; - _output.get(actual_char); - EXPECT_EQ(expected_char, actual_char); - } - } - - void sendInputLine(const std::string &line) { - _input << line << "\n" << std::flush; - } - - std::future ask(const std::string &question, const std::vector &options) { - return _console.ask(question, options); - } - - std::future askYesNo(const std::string &question) { - return _console.askYesNo(question); - } - - std::future askPassword(const std::string &question) { - return _console.askPassword(question); - } - - void print(const std::string &output) { - _console.print(output); - } - -private: - cpputils::pipestream _inputStr; - cpputils::pipestream _outputStr; - std::iostream _input; - std::iostream _output; - ConsoleThread _console; -}; - -#endif diff --git a/test/cpp-utils/io/ConsoleTest_Ask.cpp b/test/cpp-utils/io/ConsoleTest_Ask.cpp deleted file mode 100644 index ca86fe84..00000000 --- a/test/cpp-utils/io/ConsoleTest_Ask.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "ConsoleTest.h" - -using std::stringstream; -using std::string; -using std::istream; -using std::ostream; - -class ConsoleTest_Ask: public ConsoleTest {}; - -TEST_F(ConsoleTest_Ask, CrashesWithoutOptions) { - EXPECT_THROW( - (ask("My Question?", {}).get()), - std::invalid_argument - ); -} - -TEST_F(ConsoleTest_Ask, OneOption) { - auto chosen = ask("My Question?", {"First Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] First Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-1]", ':', " "); - sendInputLine("1"); - EXPECT_EQ(0u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, TwoOptions_ChooseFirst) { - auto chosen = ask("My Question?", {"First Option", "Second Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] First Option", - " [2] Second Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("1"); - EXPECT_EQ(0u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, TwoOptions_ChooseSecond) { - auto chosen = ask("My Question?", {"First Option", "Second Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] First Option", - " [2] Second Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("2"); - EXPECT_EQ(1u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, ThreeOptions_ChooseFirst) { - auto chosen = ask("My Other Question?", {"1st Option", "2nd Option", "3rd Option"}); - EXPECT_OUTPUT_LINES({ - "My Other Question?", - " [1] 1st Option", - " [2] 2nd Option", - " [3] 3rd Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-3]", ':', " "); - sendInputLine("1"); - EXPECT_EQ(0u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, ThreeOptions_ChooseSecond) { - auto chosen = ask("My Question?", {"1st Option", "2nd Option", "3rd Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] 1st Option", - " [2] 2nd Option", - " [3] 3rd Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-3]", ':', " "); - sendInputLine("2"); - EXPECT_EQ(1u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, ThreeOptions_ChooseThird) { - auto chosen = ask("My Question?", {"1st Option", "2nd Option", "3rd Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] 1st Option", - " [2] 2nd Option", - " [3] 3rd Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-3]", ':', " "); - sendInputLine("3"); - EXPECT_EQ(2u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, InputWithLeadingSpaces) { - auto chosen = ask("My Question?", {"First Option", "Second Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] First Option", - " [2] Second Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine(" 2"); - EXPECT_EQ(1u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, InputWithFollowingSpaces) { - auto chosen = ask("My Question?", {"First Option", "Second Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] First Option", - " [2] Second Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("2 "); - EXPECT_EQ(1u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, InputWithLeadingAndFollowingSpaces) { - auto chosen = ask("My Question?", {"First Option", "Second Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] First Option", - " [2] Second Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine(" 2 "); - EXPECT_EQ(1u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, InputEmptyLine) { - auto chosen = ask("My Question?", {"First Option", "Second Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] First Option", - " [2] Second Option" - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine(""); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine(" "); // empty line with space - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("2"); - EXPECT_EQ(1u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, InputWrongNumbers) { - auto chosen = ask("My Question?", {"1st Option", "2nd Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] 1st Option", - " [2] 2nd Option", - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("0"); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("-1"); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("3"); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("1.5"); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("1,5"); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("2"); - EXPECT_EQ(1u, chosen.get()); -} - -TEST_F(ConsoleTest_Ask, InputNonNumbers) { - auto chosen = ask("My Question?", {"1st Option", "2nd Option"}); - EXPECT_OUTPUT_LINES({ - "My Question?", - " [1] 1st Option", - " [2] 2nd Option", - }); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("abc"); - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("3a"); // Wrong number and string attached - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("1a"); // Right number but string attached - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("a3"); // Wrong number and string attached - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("a1"); // Right number but string attached - EXPECT_OUTPUT_LINE("Your choice [1-2]", ':', " "); - sendInputLine("2"); - EXPECT_EQ(1u, chosen.get()); -} diff --git a/test/cpp-utils/io/ConsoleTest_AskPassword.cpp b/test/cpp-utils/io/ConsoleTest_AskPassword.cpp deleted file mode 100644 index d7db1874..00000000 --- a/test/cpp-utils/io/ConsoleTest_AskPassword.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "ConsoleTest.h" - -using std::stringstream; -using std::string; -using std::istream; -using std::ostream; - -class ConsoleTest_AskPassword: public ConsoleTest {}; - -TEST_F(ConsoleTest_AskPassword, InputSomePassword) { - auto chosen = askPassword("Please enter my password:"); - EXPECT_OUTPUT_LINE("Please enter my password", ':'); - sendInputLine("this is the password"); - EXPECT_EQ("this is the password", chosen.get()); -} - -TEST_F(ConsoleTest_AskPassword, InputEmptyPassword) { - auto chosen = askPassword("Please enter my password:"); - EXPECT_OUTPUT_LINE("Please enter my password", ':'); - sendInputLine(""); - EXPECT_EQ("", chosen.get()); -} diff --git a/test/cpp-utils/io/ConsoleTest_AskYesNo.cpp b/test/cpp-utils/io/ConsoleTest_AskYesNo.cpp deleted file mode 100644 index b1da6a55..00000000 --- a/test/cpp-utils/io/ConsoleTest_AskYesNo.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "ConsoleTest.h" - -using std::string; - -class ConsoleTest_AskYesNo: public ConsoleTest { -public: - void EXPECT_TRUE_ON_INPUT(const string &input) { - EXPECT_RESULT_ON_INPUT(true, input); - } - - void EXPECT_FALSE_ON_INPUT(const string &input) { - EXPECT_RESULT_ON_INPUT(false, input); - } - - void EXPECT_RESULT_ON_INPUT(const bool expected, const string &input) { - auto chosen = askYesNo("Are you sure blablub?"); - EXPECT_OUTPUT_LINES({"Are you sure blablub?"}); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine(input); - EXPECT_EQ(expected, chosen.get()); - } -}; - -TEST_F(ConsoleTest_AskYesNo, Input_Yes) { - EXPECT_TRUE_ON_INPUT("Yes"); -} - -TEST_F(ConsoleTest_AskYesNo, Input_yes) { - EXPECT_TRUE_ON_INPUT("yes"); -} - -TEST_F(ConsoleTest_AskYesNo, Input_Y) { - EXPECT_TRUE_ON_INPUT("Y"); -} - -TEST_F(ConsoleTest_AskYesNo, Input_y) { - EXPECT_TRUE_ON_INPUT("y"); -} - -TEST_F(ConsoleTest_AskYesNo, Input_No) { - EXPECT_FALSE_ON_INPUT("No"); -} - -TEST_F(ConsoleTest_AskYesNo, Input_no) { - EXPECT_FALSE_ON_INPUT("no"); -} - -TEST_F(ConsoleTest_AskYesNo, Input_N) { - EXPECT_FALSE_ON_INPUT("N"); -} - -TEST_F(ConsoleTest_AskYesNo, Input_n) { - EXPECT_FALSE_ON_INPUT("n"); -} - -TEST_F(ConsoleTest_AskYesNo, InputWithLeadingSpaces) { - EXPECT_TRUE_ON_INPUT(" y"); -} - -TEST_F(ConsoleTest_AskYesNo, InputWithFollowingSpaces) { - EXPECT_TRUE_ON_INPUT("y "); -} - -TEST_F(ConsoleTest_AskYesNo, InputWithLeadingAndFollowingSpaces) { - EXPECT_TRUE_ON_INPUT(" y "); -} - -TEST_F(ConsoleTest_AskYesNo, InputEmptyLine) { - auto chosen = askYesNo("My Question?"); - EXPECT_OUTPUT_LINES({"My Question?"}); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine(""); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine(" "); // empty line with space - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("y"); - EXPECT_EQ(true, chosen.get()); -} - -TEST_F(ConsoleTest_AskYesNo, WrongInput) { - auto chosen = askYesNo("My Question?"); - EXPECT_OUTPUT_LINES({"My Question?"}); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("0"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("1"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("bla"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("Y_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("y_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("N_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("n_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("Yes_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("yes_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("No_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("no_andsomethingelse"); - EXPECT_OUTPUT_LINE("Your choice [y/n]", ':', " "); - sendInputLine("y"); - EXPECT_EQ(true, chosen.get()); -} diff --git a/test/cpp-utils/io/ConsoleTest_Print.cpp b/test/cpp-utils/io/ConsoleTest_Print.cpp deleted file mode 100644 index e38585ee..00000000 --- a/test/cpp-utils/io/ConsoleTest_Print.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "ConsoleTest.h" - -TEST_F(ConsoleTest, Print) { - print("Bla Blub"); - EXPECT_OUTPUT_LINE("Bla Blu", 'b'); // 'b' is the delimiter for reading -} diff --git a/test/cpp-utils/io/DontEchoStdinToStdoutRAIITest.cpp b/test/cpp-utils/io/DontEchoStdinToStdoutRAIITest.cpp deleted file mode 100644 index 75dec5f3..00000000 --- a/test/cpp-utils/io/DontEchoStdinToStdoutRAIITest.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -using cpputils::DontEchoStdinToStdoutRAII; - -TEST(DontEchoStdinToStdoutRAIITest, DoesntCrash) { - DontEchoStdinToStdoutRAII a; -} diff --git a/test/cpp-utils/io/ProgressBarTest.cpp b/test/cpp-utils/io/ProgressBarTest.cpp deleted file mode 100644 index 97ca2211..00000000 --- a/test/cpp-utils/io/ProgressBarTest.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include - -using cpputils::ProgressBar; -using std::make_shared; - -class MockConsole final: public cpputils::Console { -public: - void EXPECT_OUTPUT(const char* expected) { - EXPECT_EQ(expected, _output); - _output = ""; - } - - void print(const std::string& text) override { - _output += text; - } - - unsigned int ask(const std::string&, const std::vector&) override { - EXPECT_TRUE(false); - return 0; - } - - bool askYesNo(const std::string&, bool) override { - EXPECT_TRUE(false); - return false; - } - - std::string askPassword(const std::string&) override { - EXPECT_TRUE(false); - return ""; - } - -private: - std::string _output; -}; - -TEST(ProgressBarTest, testProgressBar) { - auto console = make_shared(); - - ProgressBar bar(console, "Preamble", 2000); - console->EXPECT_OUTPUT("\n\rPreamble 0%"); - - // when updating to 0, doesn't reprint - bar.update(0); - console->EXPECT_OUTPUT(""); - - // update to half - bar.update(1000); - console->EXPECT_OUTPUT("\rPreamble 50%"); - - // when updating to same value, doesn't reprint - bar.update(1000); - console->EXPECT_OUTPUT(""); - - // when updating to value with same percentage, doesn't reprint - bar.update(1001); - console->EXPECT_OUTPUT(""); - - // update to 0 - bar.update(0); - console->EXPECT_OUTPUT("\rPreamble 0%"); - - // update to full - bar.update(2000); - console->EXPECT_OUTPUT("\rPreamble 100%"); -} diff --git a/test/cpp-utils/lock/ConditionBarrierIncludeTest.cpp b/test/cpp-utils/lock/ConditionBarrierIncludeTest.cpp deleted file mode 100644 index eb8eb018..00000000 --- a/test/cpp-utils/lock/ConditionBarrierIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/lock/ConditionBarrier.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/lock/LockPoolIncludeTest.cpp b/test/cpp-utils/lock/LockPoolIncludeTest.cpp deleted file mode 100644 index 2b333e36..00000000 --- a/test/cpp-utils/lock/LockPoolIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/lock/LockPool.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/lock/MutexPoolLockIncludeTest.cpp b/test/cpp-utils/lock/MutexPoolLockIncludeTest.cpp deleted file mode 100644 index 6fe2c90d..00000000 --- a/test/cpp-utils/lock/MutexPoolLockIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/lock/MutexPoolLock.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/logging/LoggerIncludeTest.cpp b/test/cpp-utils/logging/LoggerIncludeTest.cpp deleted file mode 100644 index 0f2fc1e5..00000000 --- a/test/cpp-utils/logging/LoggerIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/logging/Logger.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/logging/LoggerTest.cpp b/test/cpp-utils/logging/LoggerTest.cpp deleted file mode 100644 index 120f5331..00000000 --- a/test/cpp-utils/logging/LoggerTest.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "testutils/LoggingTest.h" - -/* - * Contains test cases for the Logger class - */ - -using namespace cpputils::logging; -using std::string; - -class LoggerTest: public LoggingTest {}; - -TEST_F(LoggerTest, IsSingleton) { - ASSERT_EQ(&logger(), &logger()); -} - -TEST_F(LoggerTest, SetLogger) { - logger().setLogger(spdlog::stderr_logger_mt("MyTestLog1")); - EXPECT_EQ("MyTestLog1", logger()->name()); -} diff --git a/test/cpp-utils/logging/LoggingIncludeTest.cpp b/test/cpp-utils/logging/LoggingIncludeTest.cpp deleted file mode 100644 index 0cdeee02..00000000 --- a/test/cpp-utils/logging/LoggingIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/logging/logging.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/logging/LoggingLevelTest.cpp b/test/cpp-utils/logging/LoggingLevelTest.cpp deleted file mode 100644 index 624608f4..00000000 --- a/test/cpp-utils/logging/LoggingLevelTest.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "testutils/LoggingTest.h" -#include - -using namespace cpputils::logging; -using std::string; - -class LoggingLevelTest: public LoggingTest { -public: - void EXPECT_DEBUG_LOG_ENABLED() { - LOG(DEBUG, "My log message"); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*"))); - } - - void EXPECT_DEBUG_LOG_DISABLED() { - LOG(DEBUG, "My log message"); - EXPECT_EQ("", mockLogger.capturedLog()); - } - - void EXPECT_INFO_LOG_ENABLED() { - LOG(INFO, "My log message"); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"))); - } - - void EXPECT_INFO_LOG_DISABLED() { - LOG(INFO, "My log message"); - EXPECT_EQ("", mockLogger.capturedLog()); - } - - void EXPECT_WARNING_LOG_ENABLED() { - LOG(WARN, "My log message"); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*"))); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*")); - } - - void EXPECT_WARNING_LOG_DISABLED() { - LOG(WARN, "My log message"); - EXPECT_EQ("", mockLogger.capturedLog()); - } - - void EXPECT_ERROR_LOG_ENABLED() { - LOG(ERR, "My log message"); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[error\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[error\\].*My log message.*"))); - } - - void EXPECT_ERROR_LOG_DISABLED() { - LOG(ERR, "My log message"); - EXPECT_EQ("", mockLogger.capturedLog()); - } -}; - -TEST_F(LoggingLevelTest, DefaultLevelIsInfo) { - setLogger(mockLogger.get()); - EXPECT_DEBUG_LOG_DISABLED(); - EXPECT_INFO_LOG_ENABLED(); - EXPECT_WARNING_LOG_ENABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, DEBUG_SetBeforeSettingLogger) { - setLevel(DEBUG); - setLogger(mockLogger.get()); - EXPECT_DEBUG_LOG_ENABLED(); - EXPECT_INFO_LOG_ENABLED(); - EXPECT_WARNING_LOG_ENABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, DEBUG_SetAfterSettingLogger) { - setLogger(mockLogger.get()); - setLevel(DEBUG); - EXPECT_DEBUG_LOG_ENABLED(); - EXPECT_INFO_LOG_ENABLED(); - EXPECT_WARNING_LOG_ENABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, INFO_SetBeforeSettingLogger) { - setLevel(INFO); - setLogger(mockLogger.get()); - EXPECT_DEBUG_LOG_DISABLED(); - EXPECT_INFO_LOG_ENABLED(); - EXPECT_WARNING_LOG_ENABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, INFO_SetAfterSettingLogger) { - setLogger(mockLogger.get()); - setLevel(INFO); - EXPECT_DEBUG_LOG_DISABLED(); - EXPECT_INFO_LOG_ENABLED(); - EXPECT_WARNING_LOG_ENABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, WARNING_SetBeforeSettingLogger) { - setLevel(WARN); - setLogger(mockLogger.get()); - EXPECT_DEBUG_LOG_DISABLED(); - EXPECT_INFO_LOG_DISABLED(); - EXPECT_WARNING_LOG_ENABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, WARNING_SetAfterSettingLogger) { - setLogger(mockLogger.get()); - setLevel(WARN); - EXPECT_DEBUG_LOG_DISABLED(); - EXPECT_INFO_LOG_DISABLED(); - EXPECT_WARNING_LOG_ENABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, ERROR_SetBeforeSettingLogger) { - setLevel(ERR); - setLogger(mockLogger.get()); - EXPECT_DEBUG_LOG_DISABLED(); - EXPECT_INFO_LOG_DISABLED(); - EXPECT_WARNING_LOG_DISABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} - -TEST_F(LoggingLevelTest, ERROR_SetAfterSettingLogger) { - setLogger(mockLogger.get()); - setLevel(ERR); - EXPECT_DEBUG_LOG_DISABLED(); - EXPECT_INFO_LOG_DISABLED(); - EXPECT_WARNING_LOG_DISABLED(); - EXPECT_ERROR_LOG_ENABLED(); -} diff --git a/test/cpp-utils/logging/LoggingTest.cpp b/test/cpp-utils/logging/LoggingTest.cpp deleted file mode 100644 index 3539561b..00000000 --- a/test/cpp-utils/logging/LoggingTest.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "testutils/LoggingTest.h" -#include - -/* - * Contains test cases for the following logging interface: - * LOG(INFO, "My log message)" - */ - -using namespace cpputils::logging; -using std::string; - -// Disable the next tests for MSVC debug builds since writing to stderr doesn't seem to work well there -#if !defined(_MSC_VER) || NDEBUG - -TEST_F(LoggingTest, DefaultLoggerIsStderr) { - string output = captureStderr([]{ - LOG(INFO, "My log message"); - cpputils::logging::flush(); - }); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(output, MatchesRegex(".*\\[Log\\].*\\[info\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(output, std::regex(".*\\[Log\\].*\\[info\\].*My log message.*"))); -} - -TEST_F(LoggingTest, SetLogger_NewLoggerIsUsed) { - setLogger(spdlog::stderr_logger_mt("MyTestLog2")); - string output = captureStderr([]{ - LOG(INFO, "My log message"); - cpputils::logging::flush(); - }); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(output, MatchesRegex(".*\\[MyTestLog2\\].*\\[info\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(output, std::regex(".*\\[MyTestLog2\\].*\\[info\\].*My log message.*"))); -} - -#endif - -TEST_F(LoggingTest, SetNonStderrLogger_LogsToNewLogger) { - setLogger(mockLogger.get()); - logger()->info("My log message"); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(output, MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"))); -} - -TEST_F(LoggingTest, SetNonStderrLogger_DoesNotLogToStderr) { - setLogger(mockLogger.get()); - string output = captureStderr([] { - logger()->info("My log message"); - cpputils::logging::flush(); - }); - EXPECT_EQ("", output); -} - -TEST_F(LoggingTest, InfoLog) { - setLogger(mockLogger.get()); - LOG(INFO, "My log message"); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"))); -} - -TEST_F(LoggingTest, WarningLog) { - setLogger(mockLogger.get()); - LOG(WARN, "My log message"); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*"))); -} - -TEST_F(LoggingTest, DebugLog) { - setLevel(DEBUG); - setLogger(mockLogger.get()); - LOG(DEBUG, "My log message"); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*"))); -} - -TEST_F(LoggingTest, ErrorLog) { - setLogger(mockLogger.get()); - LOG(ERR, "My log message"); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[error\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[error\\].*My log message.*"))); -} - -void logAndExit(const string &message) { - LOG(INFO, message); - cpputils::logging::flush(); - exit(1); -} - -// fork() only forks the main thread. This test ensures that logging doesn't depend on threads that suddenly aren't -// there anymore after a fork(). -TEST_F(LoggingTest, LoggingAlsoWorksAfterFork) { - setLogger(spdlog::stderr_logger_mt("StderrLogger")); - EXPECT_EXIT( - logAndExit("My log message"), - ::testing::ExitedWithCode(1), - "My log message" - ); -} - -TEST_F(LoggingTest, MessageIsConstChar) { - setLogger(mockLogger.get()); - LOG(INFO, "My log message"); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"))); -} - -TEST_F(LoggingTest, MessageIsString) { - setLogger(mockLogger.get()); - string msg = "My log message"; - LOG(INFO, msg); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"))); -} - -TEST_F(LoggingTest, FormatWithStringPlaceholder) { - setLogger(mockLogger.get()); - string str = "placeholder"; - LOG(INFO, "My log message: {}", str); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*"))); -} - -TEST_F(LoggingTest, FormatWithConstCharPlaceholder) { - setLogger(mockLogger.get()); - LOG(INFO, "My log message: {}", "placeholder"); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*"))); -} - -TEST_F(LoggingTest, FormatWithIntPlaceholder) { - setLogger(mockLogger.get()); - LOG(INFO, "My log message: {}", 4); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4.*"))); -} - -TEST_F(LoggingTest, FormatWithMultiplePlaceholders) { - setLogger(mockLogger.get()); - LOG(INFO, "My log message: {}, {}, {}", 4, "then", true); - cpputils::logging::flush(); - // For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string? - //EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4, then, true.*")); - EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4, then, true.*"))); -} diff --git a/test/cpp-utils/logging/testutils/LoggingTest.h b/test/cpp-utils/logging/testutils/LoggingTest.h deleted file mode 100644 index b102f234..00000000 --- a/test/cpp-utils/logging/testutils/LoggingTest.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#ifndef MESSMER_CPPUTILS_TEST_LOGGING_TESTUTILS_LOGGINGTEST_H -#define MESSMER_CPPUTILS_TEST_LOGGING_TESTUTILS_LOGGINGTEST_H - -#include -#include -#include "cpp-utils/logging/logging.h" -#include - -class MockLogger final { -public: - MockLogger(): - _capturedLogData(), - _logger(spdlog::create("MockLogger", _capturedLogData, true)) { - } - - ~MockLogger() { - spdlog::drop("MockLogger"); - }; - - std::shared_ptr get() { - return _logger; - } - - std::string capturedLog() const { - return _capturedLogData.str(); - } -private: - std::ostringstream _capturedLogData; - std::shared_ptr _logger; -}; - -class LoggingTest: public ::testing::Test { -public: - LoggingTest(): mockLogger() {} - - std::string captureStderr(std::function func) { - testing::internal::CaptureStderr(); - func(); - return testing::internal::GetCapturedStderr(); - } - - ~LoggingTest() { - cpputils::logging::reset(); - } - - MockLogger mockLogger; -}; - -#endif diff --git a/test/cpp-utils/network/CurlHttpClientTest.cpp b/test/cpp-utils/network/CurlHttpClientTest.cpp deleted file mode 100644 index c3c9252f..00000000 --- a/test/cpp-utils/network/CurlHttpClientTest.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include "cpp-utils/network/CurlHttpClient.h" -#include "cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h" - -using std::string; - -using namespace cpputils; - -// Disable these by default because they depend on network -// and - even if network is available - can fail depending -// on the concrete network setup (e.g. if invalid domains are -// answered with an ISP page instead of HTTP error) -#ifdef CRYFS_ENABLE_NETWORK_TESTS - -TEST(CurlHttpClientTest, InvalidProtocol) { - EXPECT_EQ(none, CurlHttpClient().get("invalid://example.com")); -} - -TEST(CurlHttpClientTest, InvalidTld) { - EXPECT_EQ(none, CurlHttpClient().get("http://example.invalidtld")); -} - -TEST(CurlHttpClientTest, InvalidDomain) { - EXPECT_EQ(none, CurlHttpClient().get("http://this_is_a_not_existing_domain.com")); -} - -TEST(CurlHttpClientTest, ValidHttp) { - string content = CurlHttpClient().get("http://example.com").value(); - EXPECT_THAT(content, MatchesRegex(".*Example Domain.*")); -} - -TEST(CurlHttpClientTest, ValidHttps) { - string content = CurlHttpClient().get("https://example.com").value(); - EXPECT_THAT(content, MatchesRegex(".*Example Domain.*")); -} - -#endif diff --git a/test/cpp-utils/network/FakeHttpClientTest.cpp b/test/cpp-utils/network/FakeHttpClientTest.cpp deleted file mode 100644 index 922578c5..00000000 --- a/test/cpp-utils/network/FakeHttpClientTest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include "cpp-utils/network/FakeHttpClient.h" -#include "cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h" - -using boost::none; - -using namespace cpputils; - -TEST(FakeHttpClientTest, Empty) { - EXPECT_ANY_THROW(FakeHttpClient().get("http://example.com")); -} - -TEST(FakeHttpClientTest, Nonexisting) { - FakeHttpClient client; - client.addWebsite("http://existing.com", "content"); - EXPECT_ANY_THROW(client.get("http://notexisting.com")); -} - -TEST(FakeHttpClientTest, Existing) { - FakeHttpClient client; - client.addWebsite("http://existing.com", "content"); - EXPECT_EQ("content", client.get("http://existing.com")); -} - -TEST(FakeHttpClientTest, TwoExisting) { - FakeHttpClient client; - client.addWebsite("http://firstexisting.com", "first_content"); - client.addWebsite("http://secondexisting.com", "second_content"); - EXPECT_EQ("first_content", client.get("http://firstexisting.com")); - EXPECT_EQ("second_content", client.get("http://secondexisting.com")); - EXPECT_ANY_THROW(client.get("http://notexisting.com")); -} - -TEST(FakeHttpClientTest, Overwriting) { - FakeHttpClient client; - client.addWebsite("http://existing.com", "content"); - client.addWebsite("http://existing.com", "new_content"); - EXPECT_EQ("new_content", client.get("http://existing.com")); -} diff --git a/test/cpp-utils/pointer/cast_include_test.cpp b/test/cpp-utils/pointer/cast_include_test.cpp deleted file mode 100644 index 362558b5..00000000 --- a/test/cpp-utils/pointer/cast_include_test.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/pointer/cast.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/pointer/cast_test.cpp b/test/cpp-utils/pointer/cast_test.cpp deleted file mode 100644 index 937c89f0..00000000 --- a/test/cpp-utils/pointer/cast_test.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include -#include -#include "cpp-utils/pointer/cast.h" -#include "cpp-utils/pointer/unique_ref.h" -#include "cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h" - -//TODO There is a lot of duplication here, because each test case is there twice - once for unique_ptr, once for unique_ref. Remove redundancy by using generic test cases. -//TODO Then also move the unique_ref related test cases there - cast_test.cpp should only contain the unique_ptr related ones. - -using namespace cpputils; -using std::unique_ptr; -using std::make_unique; -using boost::optional; -using boost::none; - -class DestructorCallback { -public: - MOCK_METHOD(void, call, (), (const)); -}; - -class Parent { -public: - virtual ~Parent() { } -}; - -class Child : public Parent { -public: - Child(const DestructorCallback *childDestructorCallback) : _destructorCallback(childDestructorCallback) { } - Child(): Child(nullptr) {} - - ~Child() { - if (_destructorCallback != nullptr) { - _destructorCallback->call(); - } - } - -private: - const DestructorCallback *_destructorCallback; - DISALLOW_COPY_AND_ASSIGN(Child); -}; - -class Child2 : public Parent {}; - - -TEST(UniquePtr_DynamicPointerMoveTest, NullPtrParentToChildCast) { - unique_ptr source(nullptr); - unique_ptr casted = dynamic_pointer_move(source); - EXPECT_EQ(nullptr, source.get()); - EXPECT_EQ(nullptr, casted.get()); -} - -TEST(UniquePtr_DynamicPointerMoveTest, NullPtrChildToParentCast) { - unique_ptr source(nullptr); - unique_ptr casted = dynamic_pointer_move(source); - EXPECT_EQ(nullptr, source.get()); - EXPECT_EQ(nullptr, casted.get()); -} - -TEST(UniquePtr_DynamicPointerMoveTest, NullPtrSelfCast) { - unique_ptr source(nullptr); - unique_ptr casted = dynamic_pointer_move(source); - EXPECT_EQ(nullptr, source.get()); - EXPECT_EQ(nullptr, casted.get()); -} - -TEST(UniqueRef_DynamicPointerMoveTest, ValidParentToChildCast) { - Child *obj = new Child(); - unique_ref source(nullcheck(unique_ptr(obj)).value()); - unique_ref casted = dynamic_pointer_move(source).value(); - EXPECT_FALSE(source.is_valid()); // source lost ownership - EXPECT_EQ(obj, casted.get()); -} - -TEST(UniquePtr_DynamicPointerMoveTest, ValidParentToChildCast) { - Child *obj = new Child(); - unique_ptr source(obj); - unique_ptr casted = dynamic_pointer_move(source); - EXPECT_EQ(nullptr, source.get()); // source lost ownership - EXPECT_EQ(obj, casted.get()); -} - -TEST(UniqueRef_DynamicPointerMoveTest, InvalidParentToChildCast1) { - Parent *obj = new Parent(); - unique_ref source(nullcheck(unique_ptr(obj)).value()); - optional> casted = dynamic_pointer_move(source); - EXPECT_EQ(obj, source.get()); // source still has ownership - EXPECT_EQ(none, casted); -} - -TEST(UniquePtr_DynamicPointerMoveTest, InvalidParentToChildCast1) { - Parent *obj = new Parent(); - unique_ptr source(obj); - unique_ptr casted = dynamic_pointer_move(source); - EXPECT_EQ(obj, source.get()); // source still has ownership - EXPECT_EQ(nullptr, casted.get()); -} - -TEST(UniqueRef_DynamicPointerMoveTest, InvalidParentToChildCast2) { - Child2 *obj = new Child2(); - unique_ref source(nullcheck(unique_ptr(obj)).value()); - optional> casted = dynamic_pointer_move(source); - EXPECT_EQ(obj, source.get()); // source still has ownership - EXPECT_EQ(none, casted); -} - -TEST(UniquePtr_DynamicPointerMoveTest, InvalidParentToChildCast2) { - Child2 *obj = new Child2(); - unique_ptr source(obj); - unique_ptr casted = dynamic_pointer_move(source); - EXPECT_EQ(obj, source.get()); // source still has ownership - EXPECT_EQ(nullptr, casted.get()); -} - -TEST(UniqueRef_DynamicPointerMoveTest, ChildToParentCast) { - Child *obj = new Child(); - unique_ref source(nullcheck(unique_ptr(obj)).value()); - unique_ref casted = dynamic_pointer_move(source).value(); - EXPECT_FALSE(source.is_valid()); // source lost ownership - EXPECT_EQ(obj, casted.get()); -} - -TEST(UniquePtr_DynamicPointerMoveTest, ChildToParentCast) { - Child *obj = new Child(); - unique_ptr source(obj); - unique_ptr casted = dynamic_pointer_move(source); - EXPECT_EQ(nullptr, source.get()); // source lost ownership - EXPECT_EQ(obj, casted.get()); -} - - -class UniqueRef_DynamicPointerMoveDestructorTest: public ::testing::Test { -public: - UniqueRef_DynamicPointerMoveDestructorTest(): childDestructorCallback() {} - - DestructorCallback childDestructorCallback; - unique_ref createChild() { - return make_unique_ref(&childDestructorCallback); - } - void EXPECT_CHILD_DESTRUCTOR_CALLED() { - EXPECT_CALL(childDestructorCallback, call()).Times(1); - } -}; - -class UniquePtr_DynamicPointerMoveDestructorTest: public ::testing::Test { -public: - UniquePtr_DynamicPointerMoveDestructorTest(): childDestructorCallback() {} - - DestructorCallback childDestructorCallback; - unique_ptr createChild() { - return make_unique(&childDestructorCallback); - } - void EXPECT_CHILD_DESTRUCTOR_CALLED() { - EXPECT_CALL(childDestructorCallback, call()).Times(1); - } -}; - -TEST_F(UniqueRef_DynamicPointerMoveDestructorTest, ChildInParentPtr) { - unique_ref parent = createChild(); - EXPECT_CHILD_DESTRUCTOR_CALLED(); -} - -TEST_F(UniquePtr_DynamicPointerMoveDestructorTest, ChildInParentPtr) { - unique_ptr parent = createChild(); - EXPECT_CHILD_DESTRUCTOR_CALLED(); -} - -TEST_F(UniqueRef_DynamicPointerMoveDestructorTest, ChildToParentCast) { - unique_ref child = createChild(); - unique_ref parent = dynamic_pointer_move(child).value(); - EXPECT_CHILD_DESTRUCTOR_CALLED(); -} - -TEST_F(UniquePtr_DynamicPointerMoveDestructorTest, ChildToParentCast) { - unique_ptr child = createChild(); - unique_ptr parent = dynamic_pointer_move(child); - EXPECT_CHILD_DESTRUCTOR_CALLED(); -} - -TEST_F(UniqueRef_DynamicPointerMoveDestructorTest, ParentToChildCast) { - unique_ref parent = createChild(); - unique_ref child = dynamic_pointer_move(parent).value(); - EXPECT_CHILD_DESTRUCTOR_CALLED(); -} - -TEST_F(UniquePtr_DynamicPointerMoveDestructorTest, ParentToChildCast) { - unique_ptr parent = createChild(); - unique_ptr child = dynamic_pointer_move(parent); - EXPECT_CHILD_DESTRUCTOR_CALLED(); -} diff --git a/test/cpp-utils/pointer/optional_ownership_ptr_include_test.cpp b/test/cpp-utils/pointer/optional_ownership_ptr_include_test.cpp deleted file mode 100644 index 3c28e29d..00000000 --- a/test/cpp-utils/pointer/optional_ownership_ptr_include_test.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/pointer/optional_ownership_ptr.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/pointer/optional_ownership_ptr_test.cpp b/test/cpp-utils/pointer/optional_ownership_ptr_test.cpp deleted file mode 100644 index 69fcba55..00000000 --- a/test/cpp-utils/pointer/optional_ownership_ptr_test.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include "cpp-utils/pointer/optional_ownership_ptr.h" -#include "cpp-utils/macros.h" - -using std::unique_ptr; -using std::function; -using ::testing::Test; - -using namespace cpputils; - -class TestObject { -public: - TestObject(function destructorListener) : _destructorListener(destructorListener) {} - virtual ~TestObject() { - _destructorListener(); - } - -private: - function _destructorListener; -}; - -class TestObjectHolder { -public: - TestObjectHolder() - : _isDestructed(false), - _testObject(new TestObject([this]() {_isDestructed = true;})) { - } - - ~TestObjectHolder() { - if (!_isDestructed) { - delete _testObject; - _isDestructed = true; - } - } - - TestObject *get() { - return _testObject; - } - - bool isDestructed() { - return _isDestructed; - } -private: - bool _isDestructed; - TestObject *_testObject; - DISALLOW_COPY_AND_ASSIGN(TestObjectHolder); -}; - -class OptionalOwnershipPointerTest: public Test { -public: - OptionalOwnershipPointerTest(): obj(), obj2() {} - - TestObjectHolder obj; - TestObjectHolder obj2; -}; - -TEST_F(OptionalOwnershipPointerTest, TestIsInitializedCorrectly) { - EXPECT_FALSE(obj.isDestructed()); -} - -TEST_F(OptionalOwnershipPointerTest, DestructsWhenItHasOwnership_UniquePtr) { - { - optional_ownership_ptr ptr = WithOwnership(unique_ptr(obj.get())); - EXPECT_FALSE(obj.isDestructed()); - UNUSED(ptr); - } - EXPECT_TRUE(obj.isDestructed()); -} - -TEST_F(OptionalOwnershipPointerTest, DestructsWhenItHasOwnership_UniqueRef) { - { - optional_ownership_ptr ptr = WithOwnership(cpputils::nullcheck(unique_ptr(obj.get())).value()); - //EXPECT_FALSE(obj.isDestructed()); - //UNUSED(ptr); - } - //EXPECT_TRUE(obj.isDestructed()); -} - - -TEST_F(OptionalOwnershipPointerTest, DestructsWhenItHasOwnershipAfterAssignment) { - { - optional_ownership_ptr ptr = WithoutOwnership(obj.get()); - ptr = WithOwnership(unique_ptr(obj2.get())); - } - EXPECT_FALSE(obj.isDestructed()); - EXPECT_TRUE(obj2.isDestructed()); -} - -TEST_F(OptionalOwnershipPointerTest, DoesntDestructWhenItDoesntHaveOwnership) { - { - optional_ownership_ptr ptr = WithoutOwnership(obj.get()); - UNUSED(ptr); - } - EXPECT_FALSE(obj.isDestructed()); -} - -TEST_F(OptionalOwnershipPointerTest, DoesntDestructWhenItDoesntHaveOwnershipAfterAssignment) { - { - optional_ownership_ptr ptr = WithOwnership(unique_ptr(obj.get())); - ptr = WithoutOwnership(obj2.get()); - EXPECT_TRUE(obj.isDestructed()); - } - EXPECT_FALSE(obj2.isDestructed()); -} - -TEST_F(OptionalOwnershipPointerTest, DestructsOnReassignmentWithNull) { - optional_ownership_ptr ptr = WithOwnership(unique_ptr(obj.get())); - ptr = null(); - EXPECT_TRUE(obj.isDestructed()); -} - -TEST_F(OptionalOwnershipPointerTest, DoesntCrashWhenDestructingNullptr1) { - optional_ownership_ptr ptr = null(); - UNUSED(ptr); -} - -TEST_F(OptionalOwnershipPointerTest, DoesntCrashWhenDestructingNullptrWithoutOwnership) { - optional_ownership_ptr ptr = WithoutOwnership(static_cast(nullptr)); - UNUSED(ptr); -} - -TEST_F(OptionalOwnershipPointerTest, DoesntCrashWhenDestructingNullptrWithOwnership) { - optional_ownership_ptr ptr = WithOwnership(unique_ptr(nullptr)); - UNUSED(ptr); -} diff --git a/test/cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround_include_test.cpp b/test/cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround_include_test.cpp deleted file mode 100644 index a8612a88..00000000 --- a/test/cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround_include_test.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/pointer/unique_ref_include_test.cpp b/test/cpp-utils/pointer/unique_ref_include_test.cpp deleted file mode 100644 index 65342d39..00000000 --- a/test/cpp-utils/pointer/unique_ref_include_test.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/pointer/unique_ref.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/pointer/unique_ref_test.cpp b/test/cpp-utils/pointer/unique_ref_test.cpp deleted file mode 100644 index 27459bc8..00000000 --- a/test/cpp-utils/pointer/unique_ref_test.cpp +++ /dev/null @@ -1,793 +0,0 @@ -#include -#include "cpp-utils/pointer/unique_ref.h" -#include -#include -#include -#include -#include - -using namespace cpputils; - -namespace { -class SomeClass0Parameters {}; -class SomeClass1Parameter { -public: - SomeClass1Parameter(int param_): param(param_) {} - int param; -}; -class SomeClass2Parameters { -public: - SomeClass2Parameters(int param1_, int param2_): param1(param1_), param2(param2_) {} - int param1; - int param2; -}; -using SomeClass = SomeClass0Parameters; -struct SomeBaseClass { - SomeBaseClass(int v_): v(v_) {} - int v; -}; -struct SomeChildClass : SomeBaseClass { - SomeChildClass(int v): SomeBaseClass(v) {} -}; -} - -static_assert(std::is_same::element_type>::value, "unique_ref::element_type is wrong"); -static_assert(std::is_same::element_type>::value, "unique_ref::element_type is wrong"); -static_assert(std::is_same::deleter_type>::value, "unique_ref::deleter_type is wrong"); - -TEST(MakeUniqueRefTest, Primitive) { - unique_ref var = make_unique_ref(3); - EXPECT_EQ(3, *var); -} - -TEST(MakeUniqueRefTest, ClassWith0Parameters) { - unique_ref var = make_unique_ref(); - //Check that the type is correct - EXPECT_EQ(var.get(), dynamic_cast(var.get())); -} - -TEST(MakeUniqueRefTest, ClassWith1Parameter) { - unique_ref var = make_unique_ref(5); - EXPECT_EQ(5, var->param); -} - -TEST(MakeUniqueRefTest, ClassWith2Parameters) { - unique_ref var = make_unique_ref(7,2); - EXPECT_EQ(7, var->param1); - EXPECT_EQ(2, var->param2); -} - -TEST(MakeUniqueRefTest, TypeIsAutoDeductible) { - auto var1 = make_unique_ref(3); - auto var2 = make_unique_ref(); - auto var3 = make_unique_ref(2); - auto var4 = make_unique_ref(2, 3); -} - -TEST(MakeUniqueRefTest, CanAssignToUniquePtr) { - std::unique_ptr var = make_unique_ref(2); - EXPECT_EQ(2, *var); -} - -TEST(MakeUniqueRefTest, CanAssignToSharedPtr) { - std::shared_ptr var = make_unique_ref(2); - EXPECT_EQ(2, *var); - } - - TEST(MakeUniqueRefTest, CanAssignToBaseClassPtr) { - unique_ref var = make_unique_ref(3); - EXPECT_EQ(3, var->v); -} - -TEST(MakeUniqueRefTest, CanAssignToBaseClassUniquePtr) { - std::unique_ptr var = make_unique_ref(3); - EXPECT_EQ(3, var->v); -} - -TEST(MakeUniqueRefTest, CanAssignToBaseClassSharedPtr) { - std::shared_ptr var = make_unique_ref(3); - EXPECT_EQ(3, var->v); -} - -TEST(NullcheckTest, givenUniquePtrToInt_withNullptr_whenNullcheckCalled_thenReturnsNone) { - boost::optional> var = nullcheck(std::unique_ptr(nullptr)); - EXPECT_FALSE(static_cast(var)); -} - -TEST(NullcheckTest, givenUniquePtrToObject_withNullptr_whenNullcheckCalled_thenReturnsNone) { - boost::optional> var = nullcheck(std::unique_ptr(nullptr)); - EXPECT_FALSE(static_cast(var)); -} - -TEST(NullcheckTest, givenUniquePtrToInt_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) { - boost::optional> var = nullcheck(std::make_unique(3)); - EXPECT_TRUE(static_cast(var)); - EXPECT_EQ(3, **var); -} - -TEST(NullcheckTest, givenUniquePtrToObject_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) { - boost::optional> var = nullcheck(std::make_unique()); - EXPECT_TRUE(static_cast(var)); - //Check that the type is correct - EXPECT_EQ(var->get(), dynamic_cast(var->get())); -} - -TEST(NullcheckTest, givenUniquePtrToObjectWith1Parameter_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) { - boost::optional> var = nullcheck(std::make_unique(5)); - EXPECT_TRUE(static_cast(var)); - EXPECT_EQ(5, (*var)->param); -} - -TEST(NullcheckTest, givenUniquePtrToObjectWith2Parameters_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) { - boost::optional> var = nullcheck(std::make_unique(7,2)); - EXPECT_TRUE(static_cast(var)); - EXPECT_EQ(7, (*var)->param1); - EXPECT_EQ(2, (*var)->param2); -} - -TEST(NullcheckTest, givenUniquePtrToInt_withNonNullptr_whenNullcheckCalled_thenCanExtractUniqueRef) { - boost::optional> var = nullcheck(std::make_unique(3)); - unique_ref resolved = std::move(var).value(); -} - -TEST(NullcheckTest, givenUniquePtrToObject_withNonNullptr_whenNullcheckCalled_thenCanExtractUniqueRef) { - boost::optional> var = nullcheck(std::make_unique()); - unique_ref resolved = std::move(var).value(); -} - -TEST(NullcheckTest, givenUniquePtrToInt_whenCallingNullcheck_thenTypesCanBeAutoDeduced) { - auto var = nullcheck(std::make_unique(3)); - auto resolved = std::move(var).value(); -} - -TEST(NullcheckTest, givenUniquePtrToObject_whenCallingNullcheck_thenTypesCanBeAutoDeduced) { - auto var = nullcheck(std::make_unique()); - auto resolved = std::move(var).value(); -} - -class UniqueRefTest: public ::testing::Test { -public: - template void makeInvalid(unique_ref ref) { - UNUSED(ref); - //ref is moved in here and then destructed - } -}; - -TEST_F(UniqueRefTest, givenUniqueRefToInt_whenCallingGet_thenReturnsValue) { - unique_ref obj = make_unique_ref(3); - EXPECT_EQ(3, *obj.get()); -} - -TEST_F(UniqueRefTest, givenUniqueRefToObject_whenCallingGet_thenReturnsObject) { - unique_ref obj = make_unique_ref(5); - EXPECT_EQ(5, obj.get()->param); -} - -TEST_F(UniqueRefTest, givenUniqueRefToInt_whenDereferencing_thenReturnsValue) { - unique_ref obj = make_unique_ref(3); - EXPECT_EQ(3, *obj); -} - -TEST_F(UniqueRefTest, givenUniqueRefToObject_whenDereferencing_thenReturnsObject) { - unique_ref obj = make_unique_ref(5); - EXPECT_EQ(5, (*obj).param); -} - -TEST_F(UniqueRefTest, givenUniqueRefToObject_whenArrowDereferencing_thenReturnsObject) { - unique_ref obj = make_unique_ref(3); - EXPECT_EQ(3, obj->param); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigning_thenPointsToSameObject) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = make_unique_ref(); - SomeClass *obj1ptr = obj1.get(); - obj2 = std::move(obj1); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigning_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = make_unique_ref(); - obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClass_thenPointsToSameObject) { - unique_ref child = make_unique_ref(3); - unique_ref base = make_unique_ref(10); - base = std::move(child); - EXPECT_EQ(3, base->v); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClass_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(3); - unique_ref obj2 = make_unique_ref(10); - obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToUniquePtr_thenPointsToSameObject) { - unique_ref obj1 = make_unique_ref(); - std::unique_ptr obj2 = std::make_unique(); - SomeClass *obj1ptr = obj1.get(); - obj2 = std::move(obj1); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToUniquePtr_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(); - std::unique_ptr obj2 = std::make_unique(); - obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassUniquePtr_thenPointsToSameObject) { - unique_ref child = make_unique_ref(3); - std::unique_ptr base = std::make_unique(10); - base = std::move(child); - EXPECT_EQ(3, base->v); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassUniquePtr_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(3); - std::unique_ptr obj2 = std::make_unique(10); - obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToSharedPtr_thenPointsToSameObject) { - unique_ref obj1 = make_unique_ref(); - std::shared_ptr obj2 = std::make_shared(); - SomeClass *obj1ptr = obj1.get(); - obj2 = std::move(obj1); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToSharedPtr_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(); - std::shared_ptr obj2 = std::make_shared(); - obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassSharedPtr_thenPointsToSameObject) { - unique_ref child = make_unique_ref(3); - std::shared_ptr base = std::make_shared(10); - base = std::move(child); - EXPECT_EQ(3, base->v); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassSharedPtr_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(3); - std::shared_ptr obj2 = std::make_shared(10); - obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructing_thenPointsToSameObject) { - unique_ref obj1 = make_unique_ref(); - SomeClass *obj1ptr = obj1.get(); - unique_ref obj2 = std::move(obj1); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructing_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClass_thenPointsToSameObject) { - unique_ref child = make_unique_ref(3); - unique_ref base = std::move(child); - EXPECT_EQ(3, base->v); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClass_thenOldInstanceInvalid) { - unique_ref child = make_unique_ref(3); - unique_ref base = std::move(child); - EXPECT_FALSE(child.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToUniquePtr_thenPointsToSameObject) { - unique_ref obj1 = make_unique_ref(); - SomeClass *obj1ptr = obj1.get(); - std::unique_ptr obj2 = std::move(obj1); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToUniquePtr_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(); - std::unique_ptr obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassUniquePtr_thenPointsToSameObject) { - unique_ref child = make_unique_ref(3); - std::unique_ptr base = std::move(child); - EXPECT_EQ(3, base->v); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassUniquePtr_thenOldInstanceInvalid) { - unique_ref child = make_unique_ref(3); - std::unique_ptr base = std::move(child); - EXPECT_FALSE(child.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToSharedPtr_thenPointsToSameObject) { - unique_ref obj1 = make_unique_ref(); - SomeClass *obj1ptr = obj1.get(); - std::shared_ptr obj2 = std::move(obj1); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToSharedPtr_thenOldInstanceInvalid) { - unique_ref obj1 = make_unique_ref(); - std::shared_ptr obj2 = std::move(obj1); - EXPECT_FALSE(obj1.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassSharedPtr_thenPointsToSameObject) { - unique_ref child = make_unique_ref(3); - std::shared_ptr base = std::move(child); - EXPECT_EQ(3, base->v); -} - -TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassSharedPtr_thenOldInstanceInvalid) { - unique_ref child = make_unique_ref(3); - std::shared_ptr base = std::move(child); - EXPECT_FALSE(child.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, Swap) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = make_unique_ref(); - SomeClass *obj1ptr = obj1.get(); - SomeClass *obj2ptr = obj2.get(); - std::swap(obj1, obj2); - EXPECT_EQ(obj2ptr, obj1.get()); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, SwapFromInvalid) { - unique_ref obj1 = make_unique_ref(); - makeInvalid(std::move(obj1)); - unique_ref obj2 = make_unique_ref(); - SomeClass *obj2ptr = obj2.get(); - std::swap(obj1, obj2); - EXPECT_EQ(obj2ptr, obj1.get()); - EXPECT_TRUE(obj1.is_valid()); - EXPECT_FALSE(obj2.is_valid()); -} - -TEST_F(UniqueRefTest, SwapWithInvalid) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = make_unique_ref(); - makeInvalid(std::move(obj2)); - SomeClass *obj1ptr = obj1.get(); - std::swap(obj1, obj2); - EXPECT_FALSE(obj1.is_valid()); - EXPECT_TRUE(obj2.is_valid()); - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, SwapInvalidWithInvalid) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = make_unique_ref(); - makeInvalid(std::move(obj1)); - makeInvalid(std::move(obj2)); - std::swap(obj1, obj2); - EXPECT_FALSE(obj1.is_valid()); - EXPECT_FALSE(obj2.is_valid()); -} - -TEST_F(UniqueRefTest, SwapFromRValue) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = make_unique_ref(); - SomeClass *obj1ptr = obj1.get(); - SomeClass *obj2ptr = obj2.get(); - std::swap(std::move(obj1), obj2); - EXPECT_EQ(obj2ptr, obj1.get()); // NOLINT (intentional use-after-move) - EXPECT_EQ(obj1ptr, obj2.get()); -} - -TEST_F(UniqueRefTest, SwapWithRValue) { - unique_ref obj1 = make_unique_ref(); - unique_ref obj2 = make_unique_ref(); - SomeClass *obj1ptr = obj1.get(); - SomeClass *obj2ptr = obj2.get(); - std::swap(obj1, std::move(obj2)); - EXPECT_EQ(obj2ptr, obj1.get()); - EXPECT_EQ(obj1ptr, obj2.get()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, CanBePutInContainer_Primitive) { - std::vector> vec; - vec.push_back(make_unique_ref(3)); - EXPECT_EQ(3, *vec[0]); -} - -TEST_F(UniqueRefTest, CanBePutInContainer_Object) { - std::vector> vec; - vec.push_back(make_unique_ref(5)); - EXPECT_EQ(5, vec[0]->param); -} - -TEST_F(UniqueRefTest, CanBePutInContainer_Nullcheck) { - std::vector> vec; - vec.push_back(*nullcheck(std::make_unique(3))); - EXPECT_EQ(3, *vec[0]); -} - -TEST_F(UniqueRefTest, CanBePutInSet_Primitive) { - std::set> set; - set.insert(make_unique_ref(3)); - EXPECT_EQ(3, **set.begin()); -} - -TEST_F(UniqueRefTest, CanBePutInSet_Object) { - std::set> set; - set.insert(make_unique_ref(5)); - EXPECT_EQ(5, (*set.begin())->param); -} - -TEST_F(UniqueRefTest, CanBePutInSet_Nullcheck) { - std::set> set; - set.insert(*nullcheck(std::make_unique(3))); - EXPECT_EQ(3, **set.begin()); -} - -TEST_F(UniqueRefTest, CanBePutInUnorderedSet_Primitive) { - std::unordered_set> set; - set.insert(make_unique_ref(3)); - EXPECT_EQ(3, **set.begin()); -} - -TEST_F(UniqueRefTest, CanBePutInUnorderedSet_Object) { - std::unordered_set> set; - set.insert(make_unique_ref(5)); - EXPECT_EQ(5, (*set.begin())->param); -} - -TEST_F(UniqueRefTest, CanBePutInUnorderedSet_Nullcheck) { - std::unordered_set> set; - set.insert(*nullcheck(std::make_unique(3))); - EXPECT_EQ(3, **set.begin()); -} - -TEST_F(UniqueRefTest, CanBePutInMap_Primitive) { - std::map, unique_ref> map; - map.insert(std::make_pair(make_unique_ref(3), make_unique_ref(5))); - EXPECT_EQ(3, *map.begin()->first); - EXPECT_EQ(5, *map.begin()->second); -} - -TEST_F(UniqueRefTest, CanBePutInMap_Object) { - std::map, unique_ref> map; - map.insert(std::make_pair(make_unique_ref(5), make_unique_ref(3))); - EXPECT_EQ(5, map.begin()->first->param); - EXPECT_EQ(3, map.begin()->second->param); -} - -TEST_F(UniqueRefTest, CanBePutInMap_Nullcheck) { - std::map, unique_ref> map; - map.insert(std::make_pair(*nullcheck(std::make_unique(3)), *nullcheck(std::make_unique(5)))); - EXPECT_EQ(3, *map.begin()->first); - EXPECT_EQ(5, *map.begin()->second); -} - -TEST_F(UniqueRefTest, CanBePutInUnorderedMap_Primitive) { - std::unordered_map, unique_ref> map; - map.insert(std::make_pair(make_unique_ref(3), make_unique_ref(5))); - EXPECT_EQ(3, *map.begin()->first); - EXPECT_EQ(5, *map.begin()->second); -} - -TEST_F(UniqueRefTest, CanBePutInUnorderedMap_Object) { - std::unordered_map, unique_ref> map; - map.insert(std::make_pair(make_unique_ref(5), make_unique_ref(3))); - EXPECT_EQ(5, map.begin()->first->param); - EXPECT_EQ(3, map.begin()->second->param); -} - -TEST_F(UniqueRefTest, CanBePutInUnorderedMap_Nullcheck) { - std::unordered_map, unique_ref> map; - map.insert(std::make_pair(*nullcheck(std::make_unique(3)), *nullcheck(std::make_unique(5)))); - EXPECT_EQ(3, *map.begin()->first); - EXPECT_EQ(5, *map.begin()->second); -} - -TEST_F(UniqueRefTest, Equality_Nullptr) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(4); - makeInvalid(std::move(var1)); - makeInvalid(std::move(var2)); - EXPECT_TRUE(var1 == var2); // NOLINT (intentional use-after-move) - EXPECT_FALSE(var1 != var2); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, Nonequality) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - EXPECT_TRUE(var1 != var2); - EXPECT_FALSE(var1 == var2); -} - -TEST_F(UniqueRefTest, Nonequality_NullptrLeft) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var1)); - EXPECT_TRUE(var1 != var2); // NOLINT (intentional use-after-move) - EXPECT_FALSE(var1 == var2); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, Nonequality_NullptrRight) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var2)); - EXPECT_TRUE(var1 != var2); // NOLINT (intentional use-after-move) - EXPECT_FALSE(var1 == var2); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, HashIsDifferent) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - EXPECT_NE(std::hash>()(var1), std::hash>()(var2)); -} - -TEST_F(UniqueRefTest, HashIsDifferent_NullptrLeft) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var1)); - EXPECT_NE(std::hash>()(var1), std::hash>()(var2)); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, HashIsDifferent_NullptrRight) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var2)); - EXPECT_NE(std::hash>()(var1), std::hash>()(var2)); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, HashIsSame_BothNullptr) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var1)); - makeInvalid(std::move(var2)); - EXPECT_EQ(std::hash>()(var1), std::hash>()(var2)); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, OneIsLess) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - EXPECT_TRUE(std::less>()(var1, var2) != std::less>()(var2, var1)); -} - -TEST_F(UniqueRefTest, NullptrIsLess1) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var1)); - EXPECT_TRUE(std::less>()(var1, var2)); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, NullptrIsLess2) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var2)); - EXPECT_FALSE(std::less>()(var1, var2)); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, NullptrIsNotLessThanNullptr) { - unique_ref var1 = make_unique_ref(3); - unique_ref var2 = make_unique_ref(3); - makeInvalid(std::move(var1)); - makeInvalid(std::move(var2)); - EXPECT_FALSE(std::less>()(var1, var2)); // NOLINT (intentional use-after-move) -} - -namespace { -class OnlyMoveable { -public: - OnlyMoveable(int value_): value(value_) {} - OnlyMoveable(OnlyMoveable &&source) noexcept: value(source.value) {source.value = -1;} - bool operator==(const OnlyMoveable &rhs) const { - return value == rhs.value; - } - int value; -private: - OnlyMoveable(const OnlyMoveable& rhs) = delete; - OnlyMoveable& operator=(const OnlyMoveable& rhs) = delete; -}; -} - -TEST_F(UniqueRefTest, AllowsDerefOnRvalue) { - OnlyMoveable val = *make_unique_ref(5); - EXPECT_EQ(OnlyMoveable(5), val); -} - -namespace { -class DestructableMock final { -public: - DestructableMock(bool* wasDestructed): wasDestructed_(wasDestructed) {} - - ~DestructableMock() { - *wasDestructed_ = true; - } - -private: - bool* wasDestructed_; -}; -} - -TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenDestructed_thenCallsDefaultDeleter) { - bool wasDestructed = false; - { - auto obj = make_unique_ref(&wasDestructed); - EXPECT_FALSE(wasDestructed); - } - EXPECT_TRUE(wasDestructed); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenMoveConstructed_thenCallsDefaultDeleterAfterSecondDestructed) { - bool wasDestructed = false; - auto obj = make_unique_ref(&wasDestructed); - { - unique_ref obj2 = std::move(obj); - EXPECT_FALSE(wasDestructed); - } - EXPECT_TRUE(wasDestructed); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenMoveAssigned_thenCallDefaultDeleterAfterSecondDestructed) { - bool dummy = false; - bool wasDestructed = false; - unique_ref obj = make_unique_ref(&wasDestructed); - { - unique_ref obj2 = make_unique_ref(&dummy); - obj2 = std::move(obj); - EXPECT_FALSE(wasDestructed); - } - EXPECT_TRUE(wasDestructed); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenDestructCalled_thenCallsDefaultDeleter) { - bool wasDestructed = false; - auto obj = make_unique_ref(&wasDestructed); - destruct(std::move(obj)); - EXPECT_TRUE(wasDestructed); - EXPECT_FALSE(obj.is_valid()); // NOLINT (intentional use-after-move) -} - -namespace { -struct SetToTrueDeleter final { - void operator()(bool* ptr) { - *ptr = true; - } -}; -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenDestructed_thenCallsCustomDeleter) { - bool wasDestructed = false; - { - auto obj = nullcheck(std::unique_ptr(&wasDestructed)).value(); - EXPECT_FALSE(wasDestructed); - } - EXPECT_TRUE(wasDestructed); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenMoveConstructed_thenCallsCustomDeleterAfterSecondDestructed) { - bool wasDestructed = false; - unique_ref obj = nullcheck(std::unique_ptr(&wasDestructed)).value(); - { - unique_ref obj2 = std::move(obj); - EXPECT_FALSE(wasDestructed); - } - EXPECT_TRUE(wasDestructed); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenMoveAssigned_thenCallsCustomDeleterAfterSecondDestructed) { - bool dummy = false; - bool wasDestructed = false; - unique_ref obj = nullcheck(std::unique_ptr(&wasDestructed)).value(); - { - unique_ref obj2 = nullcheck(std::unique_ptr(&dummy)).value(); - obj2 = std::move(obj); - EXPECT_FALSE(wasDestructed); - } - EXPECT_TRUE(wasDestructed); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenDestructCalled_thenCallsCustomDeleter) { - bool wasDestructed = false; - auto obj = nullcheck(std::unique_ptr(&wasDestructed)).value(); - destruct(std::move(obj)); - EXPECT_TRUE(wasDestructed); - EXPECT_FALSE(obj.is_valid()); // NOLINT (intentional use-after-move) -} - -namespace { -struct SetToDeleter final { - SetToDeleter(int value): value_(value) {} - int value_; - - void operator()(int* ptr) { - *ptr = value_; - } -}; -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenDestructed_thenCallsCustomDeleterInstance) { - int value = 0; - { - auto obj = nullcheck(std::unique_ptr(&value, SetToDeleter(4))).value(); - EXPECT_EQ(0, value); - } - EXPECT_EQ(4, value); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveConstructed_thenCallsCustomDeleterInstanceAfterSecondDestructed) { - int value = 0; - unique_ref obj = nullcheck(std::unique_ptr(&value, SetToDeleter(4))).value(); - { - unique_ref obj2 = std::move(obj); - EXPECT_EQ(0, value); - } - EXPECT_EQ(4, value); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveAssigned_thenCallsCustomDeleterInstanceAfterSecondDestructed) { - int dummy = 0; - int value = 0; - unique_ref obj = nullcheck(std::unique_ptr(&value, SetToDeleter(4))).value(); - { - unique_ref obj2 = nullcheck(std::unique_ptr(&dummy, SetToDeleter(0))).value(); - obj2 = std::move(obj); - EXPECT_EQ(0, value); - } - EXPECT_EQ(4, value); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenDestructCalled_thenCallsCustomDeleterInstance) { - int value = 0; - auto obj = nullcheck(std::unique_ptr(&value, SetToDeleter(4))).value(); - destruct(std::move(obj)); - EXPECT_EQ(4, value); - EXPECT_FALSE(obj.is_valid()); // NOLINT (intentional use-after-move) -} - -TEST_F(UniqueRefTest, givenUniquePtrWithCustomDeleterInstance_whenMovedToUniquePtr_thenHasSameDeleterInstance) { - int dummy = 0; - SetToDeleter deleter(4); - auto ptr = std::unique_ptr(&dummy, deleter); - auto ref = nullcheck(std::move(ptr)).value(); - EXPECT_EQ(4, ref.get_deleter().value_); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveConstructing_thenHasSameDeleterInstance) { - int dummy = 0; - SetToDeleter deleter(4); - auto ref = nullcheck(std::unique_ptr(&dummy, deleter)).value(); - unique_ref ref2 = std::move(ref); - EXPECT_EQ(4, ref2.get_deleter().value_); -} - -TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveAssigning_thenHasSameDeleterInstance) { - int dummy = 0; - SetToDeleter deleter(4); - auto ref = nullcheck(std::unique_ptr(&dummy, deleter)).value(); - auto ref2 = nullcheck(std::unique_ptr(&dummy, SetToDeleter(0))).value(); - ref2 = std::move(ref); - EXPECT_EQ(4, ref2.get_deleter().value_); -} - -TEST_F(UniqueRefTest, AllowsMoveConstructingToUniqueRefOfConst) { - unique_ref a = make_unique_ref(3); - unique_ref b = std::move(a); -} - -TEST_F(UniqueRefTest, AllowsMoveAssigningToUniqueRefOfConst) { - unique_ref a = make_unique_ref(3); - unique_ref b = make_unique_ref(10); - b = std::move(a); -} diff --git a/test/cpp-utils/process/SignalCatcherTest.cpp b/test/cpp-utils/process/SignalCatcherTest.cpp deleted file mode 100644 index f0d49fce..00000000 --- a/test/cpp-utils/process/SignalCatcherTest.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include -#include - -using cpputils::SignalCatcher; - -namespace { -void raise_signal(int signal) { - int error = ::raise(signal); - if (error != 0) { - throw std::runtime_error("Error raising signal"); - } -} -} - -TEST(SignalCatcherTest, givenNoSignalCatcher_whenRaisingSigint_thenDies) { - EXPECT_DEATH( - raise_signal(SIGINT), - "" - ); -} - -TEST(SignalCatcherTest, givenNoSignalCatcher_whenRaisingSigterm_thenDies) { - EXPECT_DEATH( - raise_signal(SIGTERM), - "" - ); -} - -TEST(SignalCatcherTest, givenSigIntCatcher_whenRaisingSigInt_thenCatches) { - SignalCatcher catcher({SIGINT}); - - EXPECT_FALSE(catcher.signal_occurred()); - raise_signal(SIGINT); - EXPECT_TRUE(catcher.signal_occurred()); - - // raise again - raise_signal(SIGINT); - EXPECT_TRUE(catcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenSigTermCatcher_whenRaisingSigTerm_thenCatches) { - SignalCatcher catcher({SIGTERM}); - - EXPECT_FALSE(catcher.signal_occurred()); - raise_signal(SIGTERM); - EXPECT_TRUE(catcher.signal_occurred()); - - // raise again - raise_signal(SIGTERM); - EXPECT_TRUE(catcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenSigIntAndSigTermCatcher_whenRaisingSigInt_thenCatches) { - SignalCatcher catcher({SIGINT, SIGTERM}); - - EXPECT_FALSE(catcher.signal_occurred()); - raise_signal(SIGINT); - EXPECT_TRUE(catcher.signal_occurred()); - - // raise again - raise_signal(SIGINT); - EXPECT_TRUE(catcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenSigIntAndSigTermCatcher_whenRaisingSigTerm_thenCatches) { - SignalCatcher catcher({SIGINT, SIGTERM}); - - EXPECT_FALSE(catcher.signal_occurred()); - raise_signal(SIGTERM); - EXPECT_TRUE(catcher.signal_occurred()); - - // raise again - raise_signal(SIGTERM); - EXPECT_TRUE(catcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenSigIntAndSigTermCatcher_whenRaisingSigIntAndSigTerm_thenCatches) { - SignalCatcher catcher({SIGINT, SIGTERM}); - - EXPECT_FALSE(catcher.signal_occurred()); - raise_signal(SIGTERM); - EXPECT_TRUE(catcher.signal_occurred()); - - raise_signal(SIGINT); - EXPECT_TRUE(catcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenSigIntCatcherAndSigTermCatcher_whenRaisingSignalsInOrder_thenCorrectCatcherCatches) { - SignalCatcher sigintCatcher({SIGINT}); - SignalCatcher sigtermCatcher({SIGTERM}); - - EXPECT_FALSE(sigintCatcher.signal_occurred()); - raise_signal(SIGINT); - EXPECT_TRUE(sigintCatcher.signal_occurred()); - - EXPECT_FALSE(sigtermCatcher.signal_occurred()); - raise_signal(SIGTERM); - EXPECT_TRUE(sigtermCatcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenSigIntCatcherAndSigTermCatcher_whenRaisingSignalsInReverseOrder_thenCorrectCatcherCatches) { - SignalCatcher sigintCatcher({SIGINT}); - SignalCatcher sigtermCatcher({SIGTERM}); - - EXPECT_FALSE(sigtermCatcher.signal_occurred()); - raise_signal(SIGTERM); - EXPECT_TRUE(sigtermCatcher.signal_occurred()); - - EXPECT_FALSE(sigintCatcher.signal_occurred()); - raise_signal(SIGINT); - EXPECT_TRUE(sigintCatcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenNestedSigIntCatchers_whenRaisingSignals_thenCorrectCatcherCatches) { - SignalCatcher outerCatcher({SIGINT}); - { - SignalCatcher middleCatcher({SIGINT}); - - EXPECT_FALSE(middleCatcher.signal_occurred()); - raise_signal(SIGINT); - EXPECT_TRUE(middleCatcher.signal_occurred()); - - { - SignalCatcher innerCatcher({SIGINT}); - - EXPECT_FALSE(innerCatcher.signal_occurred()); - raise_signal(SIGINT); - EXPECT_TRUE(innerCatcher.signal_occurred()); - } - } - - EXPECT_FALSE(outerCatcher.signal_occurred()); - raise_signal(SIGINT); - EXPECT_TRUE(outerCatcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenExpiredSigIntCatcher_whenRaisingSigInt_thenDies) { - { - SignalCatcher catcher({SIGINT}); - } - - EXPECT_DEATH( - raise_signal(SIGINT), - "" - ); -} - -TEST(SignalCatcherTest, givenExpiredSigTermCatcher_whenRaisingSigTerm_thenDies) { - { - SignalCatcher catcher({SIGTERM}); - } - - EXPECT_DEATH( - raise_signal(SIGTERM), - "" - ); -} - -TEST(SignalCatcherTest, givenExpiredSigIntCatcherAndSigTermCatcher_whenRaisingSigTerm_thenDies) { - { - SignalCatcher sigIntCatcher({SIGTERM}); - SignalCatcher sigTermCatcer({SIGTERM}); - } - - EXPECT_DEATH( - raise_signal(SIGTERM), - "" - ); -} - -TEST(SignalCatcherTest, givenSigTermCatcherAndExpiredSigIntCatcher_whenRaisingSigTerm_thenCatches) { - SignalCatcher sigTermCatcher({SIGTERM}); - { - SignalCatcher sigIntCatcher({SIGINT}); - } - - EXPECT_FALSE(sigTermCatcher.signal_occurred()); - raise_signal(SIGTERM); - EXPECT_TRUE(sigTermCatcher.signal_occurred()); -} - -TEST(SignalCatcherTest, givenSigTermCatcherAndExpiredSigIntCatcher_whenRaisingSigInt_thenDies) { - SignalCatcher sigTermCacher({SIGTERM}); - { - SignalCatcher sigIntCatcher({SIGINT}); - } - - EXPECT_DEATH( - raise_signal(SIGINT), - "" - ); -} diff --git a/test/cpp-utils/process/SignalHandlerTest.cpp b/test/cpp-utils/process/SignalHandlerTest.cpp deleted file mode 100644 index 194b2550..00000000 --- a/test/cpp-utils/process/SignalHandlerTest.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include -#include - -using namespace cpputils; - -namespace { -std::atomic triggered; - -void trigger(int signal) { - triggered = signal; -} - -void raise_signal(int signal) { - int error = ::raise(signal); - if (error != 0) { - throw std::runtime_error("Error raising signal"); - } -} - -TEST(SignalHandlerTest, givenNoSignalHandler_whenRaisingSigint_thenDies) { - EXPECT_DEATH( - raise_signal(SIGINT), - "" - ); -} - -TEST(SignalHandlerTest, givenNoSignalHandler_whenRaisingSigterm_thenDies) { - EXPECT_DEATH( - raise_signal(SIGTERM), - "" - ); -} - -TEST(SignalHandlerTest, givenSigIntHandler_whenRaisingSigInt_thenCatches) { - triggered = 0; - - SignalHandlerRAII<&trigger> handler(SIGINT); - - raise_signal(SIGINT); - EXPECT_EQ(SIGINT, triggered); -} - -TEST(SignalHandlerTest, givenSigIntHandler_whenRaisingSigTerm_thenDies) { - SignalHandlerRAII<&trigger> handler(SIGINT); - - EXPECT_DEATH( - raise_signal(SIGTERM), - "" - ); -} - -TEST(SignalHandlerTest, givenSigTermHandler_whenRaisingSigTerm_thenCatches) { - triggered = 0; - - SignalHandlerRAII<&trigger> handler(SIGTERM); - - raise_signal(SIGTERM); - EXPECT_EQ(SIGTERM, triggered); -} - -TEST(SignalHandlerTest, givenSigTermHandler_whenRaisingSigInt_thenDies) { - SignalHandlerRAII<&trigger> handler(SIGTERM); - - EXPECT_DEATH( - raise_signal(SIGINT), - "" - ); -} - -TEST(SignalHandlerTest, givenSigIntAndSigTermHandlers_whenRaising_thenCatchesCorrectSignal) { - triggered = 0; - - SignalHandlerRAII<&trigger> handler1(SIGINT); - SignalHandlerRAII<&trigger> handler2(SIGTERM); - - raise_signal(SIGINT); - EXPECT_EQ(SIGINT, triggered); - - raise_signal(SIGTERM); - EXPECT_EQ(SIGTERM, triggered); - - raise_signal(SIGINT); - EXPECT_EQ(SIGINT, triggered); -} - -std::atomic triggered_count_1; -std::atomic triggered_count_2; - -void trigger1(int) { - ++triggered_count_1; -} - -void trigger2(int) { - ++triggered_count_2; -} - -TEST(SignalHandlerTest, givenMultipleSigIntHandlers_whenRaising_thenCatchesCorrectSignal) { - triggered_count_1 = 0; - triggered_count_2 = 0; - - { - SignalHandlerRAII<&trigger1> handler1(SIGINT); - - { - SignalHandlerRAII<&trigger2> handler2(SIGINT); - - raise_signal(SIGINT); - EXPECT_EQ(0, triggered_count_1); - EXPECT_EQ(1, triggered_count_2); - - raise_signal(SIGINT); - EXPECT_EQ(0, triggered_count_1); - EXPECT_EQ(2, triggered_count_2); - } - - raise_signal(SIGINT); - EXPECT_EQ(1, triggered_count_1); - EXPECT_EQ(2, triggered_count_2); - - raise_signal(SIGINT); - EXPECT_EQ(2, triggered_count_1); - EXPECT_EQ(2, triggered_count_2); - - } - - EXPECT_DEATH( - raise_signal(SIGINT), - "" - ); -} - -} diff --git a/test/cpp-utils/process/SubprocessTest.cpp b/test/cpp-utils/process/SubprocessTest.cpp deleted file mode 100644 index dcd3e4be..00000000 --- a/test/cpp-utils/process/SubprocessTest.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include - -#include -#include "my-gtest-main.h" - -using cpputils::Subprocess; -using cpputils::SubprocessError; -using std::string; -namespace bf = boost::filesystem; - -// TODO Test passing input to stdin of processes -// TODO Test stderr - -#if defined(_MSC_VER) -constexpr const char* NEWLINE = "\r\n"; -#else -constexpr const char* NEWLINE = "\n"; -#endif - -namespace -{ - bf::path exit_with_message_and_status() - { -#if defined(_MSC_VER) - auto executable = bf::canonical(get_executable().parent_path()) / "cpp-utils-test_exit_status.exe"; -#else - auto executable = bf::canonical(get_executable().parent_path()) / "cpp-utils-test_exit_status"; -#endif - if (!bf::exists(executable)) - { - throw std::runtime_error(executable.string() + " not found."); - } - return executable; - } -} - -TEST(SubprocessTest, CheckCall_success_output) -{ - EXPECT_EQ(std::string("hello") + NEWLINE, Subprocess::check_call(exit_with_message_and_status(), {"0", "hello"}, "").output_stdout); -} - -TEST(SubprocessTest, CheckCall_successwithemptyoutput_output) -{ - EXPECT_EQ("", Subprocess::check_call(exit_with_message_and_status(), {"0"}, "").output_stdout); -} - -TEST(SubprocessTest, CheckCall_success_exitcode) -{ - EXPECT_EQ(0, Subprocess::check_call(exit_with_message_and_status(), {"0", "hello"}, "").exitcode); -} - -TEST(SubprocessTest, CheckCall_successwithemptyoutput_exitcode) -{ - EXPECT_EQ(0, Subprocess::check_call(exit_with_message_and_status(), {"0"}, "").exitcode); -} - -TEST(SubprocessTest, CheckCall_error) -{ - EXPECT_THROW( - Subprocess::check_call(exit_with_message_and_status(), {"1"}, ""), - SubprocessError); -} - -TEST(SubprocessTest, CheckCall_error5) -{ - EXPECT_THROW( - Subprocess::check_call(exit_with_message_and_status(), {"5"}, ""), - SubprocessError); -} - -TEST(SubprocessTest, CheckCall_errorwithoutput) -{ - EXPECT_THROW( - Subprocess::check_call(exit_with_message_and_status(), {"1", "hello"}, ""), - SubprocessError); -} - -TEST(SubprocessTest, CheckCall_error5withoutput) -{ - EXPECT_THROW( - Subprocess::check_call(exit_with_message_and_status(), {"5", "hello"}, ""), - SubprocessError); -} - -TEST(SubprocessTest, Call_success_exitcode) -{ - EXPECT_EQ(0, Subprocess::call(exit_with_message_and_status(), {"0", "hello"}, "").exitcode); -} - -TEST(SubprocessTest, Call_success_output) -{ - EXPECT_EQ(std::string("hello") + NEWLINE, Subprocess::call(exit_with_message_and_status(), {"0", "hello"}, "").output_stdout); -} - -TEST(SubprocessTest, Call_error_exitcode) -{ - EXPECT_EQ(1, Subprocess::call(exit_with_message_and_status(), {"1"}, "").exitcode); -} - -TEST(SubprocessTest, Call_error_output) -{ - EXPECT_EQ("", Subprocess::call(exit_with_message_and_status(), {"1"}, "").output_stdout); -} - -TEST(SubprocessTest, Call_error5_exitcode) -{ - EXPECT_EQ(5, Subprocess::call(exit_with_message_and_status(), {"5"}, "").exitcode); -} - -TEST(SubprocessTest, Call_error5_output) -{ - EXPECT_EQ("", Subprocess::call(exit_with_message_and_status(), {"1"}, "").output_stdout); -} - -TEST(SubprocessTest, Call_errorwithoutput_output) -{ - EXPECT_EQ(std::string("hello") + NEWLINE, Subprocess::call(exit_with_message_and_status(), {"1", "hello"}, "").output_stdout); -} - -TEST(SubprocessTest, Call_errorwithoutput_exitcode) -{ - EXPECT_EQ(1, Subprocess::call(exit_with_message_and_status(), {"1", "hello"}, "").exitcode); -} - -TEST(SubprocessTest, Call_error5withoutput_output) -{ - EXPECT_EQ(std::string("hello") + NEWLINE, Subprocess::call(exit_with_message_and_status(), {"5", "hello"}, "").output_stdout); -} - -TEST(SubprocessTest, Call_error5withoutput_exitcode) -{ - EXPECT_EQ(5, Subprocess::call(exit_with_message_and_status(), {"5", "hello"}, "").exitcode); -} - -// TODO Move this test to a test suite for ThreadSystem/LoopThread -#include -TEST(SubprocessTest, CallFromThreadSystemThread) -{ - cpputils::ConditionBarrier barrier; - - cpputils::LoopThread thread( - [&barrier]() - { - auto result = Subprocess::check_call(exit_with_message_and_status(), {"0", "hello"}, ""); - EXPECT_EQ(0, result.exitcode); - EXPECT_EQ(std::string("hello") + NEWLINE, result.output_stdout); - - barrier.release(); - - return false; // don't run loop again - }, - "child_thread"); - thread.start(); - barrier.wait(); - thread.stop(); // just to make sure it's stopped before the test exits. Returning false above should already stop it, but we don't know when exactly. thread.stop() will block until it's actually stopped. -} - -TEST(SubprocessTest, Call_argumentwithspaces) -{ - // Test that arguments can have spaces and are still treated as one argument - EXPECT_EQ(std::string("hello world") + NEWLINE, Subprocess::check_call(exit_with_message_and_status(), {"0", "hello world"}, "").output_stdout); - EXPECT_EQ(std::string("hello") + NEWLINE + "world" + NEWLINE, Subprocess::check_call(exit_with_message_and_status(), {"0", "hello", "world"}, "").output_stdout); -} - -#if !defined(_MSC_VER) -TEST(SubprocessTest, Call_withcommandfrompath) -{ - // Test that we can call a system command without specifying the full path - EXPECT_EQ("hello\n", Subprocess::check_call("echo", {"hello"}, "").output_stdout); -} -#endif diff --git a/test/cpp-utils/process/daemonize_include_test.cpp b/test/cpp-utils/process/daemonize_include_test.cpp deleted file mode 100644 index f851c992..00000000 --- a/test/cpp-utils/process/daemonize_include_test.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "cpp-utils/process/daemonize.h" - -// Test the header can be included without needing additional dependencies - diff --git a/test/cpp-utils/process/exit_status.cpp b/test/cpp-utils/process/exit_status.cpp deleted file mode 100644 index b38eb9bd..00000000 --- a/test/cpp-utils/process/exit_status.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// This is a small executable that exits with the exit status in its first argument and before exiting prints all other arguments, each on a separate line. - -#include -#include - -int main(int argc, char *argv[]) -{ - if (argc < 2) - { - std::cerr << "Wrong number of arguments" << std::endl; - std::abort(); - } - - for (int i = 2; i < argc; ++i) - { - std::cout << argv[i] << "\n"; - } - - int exit_status = static_cast(std::strtol(argv[1], nullptr, 10)); - return exit_status; -} diff --git a/test/cpp-utils/process/subprocess_include_test.cpp b/test/cpp-utils/process/subprocess_include_test.cpp deleted file mode 100644 index 186d3ce2..00000000 --- a/test/cpp-utils/process/subprocess_include_test.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "cpp-utils/process/subprocess.h" - -// Test the header can be included without needing additional dependencies - diff --git a/test/cpp-utils/random/RandomIncludeTest.cpp b/test/cpp-utils/random/RandomIncludeTest.cpp deleted file mode 100644 index 6a2e159c..00000000 --- a/test/cpp-utils/random/RandomIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/random/Random.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/system/EnvTest.cpp b/test/cpp-utils/system/EnvTest.cpp deleted file mode 100644 index 802071cc..00000000 --- a/test/cpp-utils/system/EnvTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include -#include - -using std::string; - -TEST(EnvTest, SetAndGetEnv_ValueIsCorrect) { - cpputils::setenv("my_key", "my_value"); - EXPECT_EQ(string("my_value"), string(std::getenv("my_key"))); -} - -TEST(EnvTest, SetAndGetEnvWithSpacedValue_ValueIsCorrect) { - cpputils::setenv("my_key", "my value with spaces"); - EXPECT_EQ(string("my value with spaces"), string(std::getenv("my_key"))); -} - -TEST(EnvTest, UnsetAndGetEnv_ValueIsEmpty) { - cpputils::setenv("my_key", "my_value"); - cpputils::unsetenv("my_key"); - EXPECT_EQ(nullptr, std::getenv("my_key")); -} diff --git a/test/cpp-utils/system/FiletimeTest.cpp b/test/cpp-utils/system/FiletimeTest.cpp deleted file mode 100644 index 09c1b9a7..00000000 --- a/test/cpp-utils/system/FiletimeTest.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include - -using cpputils::TempFile; -using cpputils::set_filetime; -using cpputils::get_filetime; - -TEST(FiletimeTest, SetAndGetTime_ReturnsCorrectTime) { - TempFile file; - struct timespec accessTime { 1535965242, 12345000 }; - struct timespec modificationTime { 1435965242, 98765000 }; - int retval = set_filetime(file.path().string().c_str(), accessTime, modificationTime); - EXPECT_EQ(0, retval); - - struct timespec readAccessTime{}; - struct timespec readModificationTime{}; - retval = get_filetime(file.path().string().c_str(), &readAccessTime, &readModificationTime); - EXPECT_EQ(0, retval); - - EXPECT_EQ(accessTime.tv_sec, readAccessTime.tv_sec); - EXPECT_EQ(modificationTime.tv_sec, readModificationTime.tv_sec); - - // Apple unfortunately doesn't give us nanoseconds at all -#if !defined(__APPLE__) - EXPECT_EQ(accessTime.tv_nsec, readAccessTime.tv_nsec); - EXPECT_EQ(modificationTime.tv_nsec, readModificationTime.tv_nsec); -#endif -} diff --git a/test/cpp-utils/system/GetTotalMemoryTest.cpp b/test/cpp-utils/system/GetTotalMemoryTest.cpp deleted file mode 100644 index 81c57f48..00000000 --- a/test/cpp-utils/system/GetTotalMemoryTest.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -using cpputils::system::get_total_memory; - -TEST(GetTotalMemoryTest, DoesntCrash) { - get_total_memory(); -} - -TEST(GetTotalMemoryTest, IsNotZero) { - uint64_t mem = get_total_memory(); - EXPECT_LT(UINT64_C(0), mem); -} diff --git a/test/cpp-utils/system/HomedirTest.cpp b/test/cpp-utils/system/HomedirTest.cpp deleted file mode 100644 index a19ec867..00000000 --- a/test/cpp-utils/system/HomedirTest.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include - -using cpputils::system::HomeDirectory; -using cpputils::system::FakeHomeDirectoryRAII; -using cpputils::system::FakeTempHomeDirectoryRAII; -using cpputils::TempDir; - -namespace bf = boost::filesystem; - -TEST(HomedirTest, HomedirExists) { - EXPECT_TRUE(bf::exists(HomeDirectory::get())); -} - -TEST(HomedirTest, AppDataDirIsValid) { - auto dir = HomeDirectory::getXDGDataDir(); - EXPECT_FALSE(dir.empty()); - EXPECT_GE(std::distance(dir.begin(), dir.end()), 2u); // has at least two components -} - -TEST(HomedirTest, FakeHomeDirectorySetsHomedirCorrectly) { - TempDir fakeHomeDir, fakeAppDataDir; - FakeHomeDirectoryRAII a(fakeHomeDir.path(), fakeAppDataDir.path()); - - EXPECT_EQ(fakeHomeDir.path(), HomeDirectory::get()); - EXPECT_EQ(fakeAppDataDir.path(), HomeDirectory::getXDGDataDir()); -} - -TEST(HomedirTest, FakeHomeDirectoryResetsHomedirCorrectly) { - bf::path actualHomeDir = HomeDirectory::get(); - bf::path actualAppDataDir = HomeDirectory::getXDGDataDir(); - - { - TempDir fakeHomeDir, fakeAppDataDir; - FakeHomeDirectoryRAII a(fakeHomeDir.path(), fakeAppDataDir.path()); - - EXPECT_NE(actualHomeDir, HomeDirectory::get()); - EXPECT_NE(actualAppDataDir, HomeDirectory::getXDGDataDir()); - } - EXPECT_EQ(actualHomeDir, HomeDirectory::get()); - EXPECT_EQ(actualAppDataDir, HomeDirectory::getXDGDataDir()); -} - -TEST(HomedirTest, FakeTempHomeDirectorySetsHomedirCorrectly) { - bf::path actualHomeDir = HomeDirectory::get(); - bf::path actualAppDataDir = HomeDirectory::getXDGDataDir(); - - FakeTempHomeDirectoryRAII a; - - EXPECT_NE(actualHomeDir, HomeDirectory::get()); - EXPECT_NE(actualAppDataDir, HomeDirectory::getXDGDataDir()); -} - -TEST(HomedirTest, FakeTempHomeDirectoryResetsHomedirCorrectly) { - bf::path actualHomeDir = HomeDirectory::get(); - bf::path actualAppDataDir = HomeDirectory::getXDGDataDir(); - - { - FakeTempHomeDirectoryRAII a; - - EXPECT_NE(actualHomeDir, HomeDirectory::get()); - EXPECT_NE(actualAppDataDir, HomeDirectory::getXDGDataDir()); - } - EXPECT_EQ(actualHomeDir, HomeDirectory::get()); - EXPECT_EQ(actualAppDataDir, HomeDirectory::getXDGDataDir()); -} - -TEST(HomedirTest, FakeTempHomeDirectoryUsesDifferentDirsForHomedirAndAppdataDir) { - FakeTempHomeDirectoryRAII a; - - EXPECT_NE(HomeDirectory::get(), HomeDirectory::getXDGDataDir()); -} diff --git a/test/cpp-utils/system/MemoryTest.cpp b/test/cpp-utils/system/MemoryTest.cpp deleted file mode 100644 index 8459c77b..00000000 --- a/test/cpp-utils/system/MemoryTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include -#include -#include - -using cpputils::UnswappableAllocator; - -TEST(MemoryTest, LockingSmallMemoryDoesntCrash) { - UnswappableAllocator allocator; - void *data = allocator.allocate(5); - allocator.free(data, 5); -} - -TEST(MemoryTest, LockingLargeMemoryDoesntCrash) { - UnswappableAllocator allocator; - void *data = allocator.allocate(10240); - allocator.free(data, 10240); -} diff --git a/test/cpp-utils/system/PathTest.cpp b/test/cpp-utils/system/PathTest.cpp deleted file mode 100644 index 75275b5e..00000000 --- a/test/cpp-utils/system/PathTest.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -using cpputils::path_is_just_drive_letter; - -#if defined(_MSC_VER) - -TEST(PathTest, pathIsJustDriveLetter) { - EXPECT_FALSE(path_is_just_drive_letter("C")); - EXPECT_TRUE(path_is_just_drive_letter("C:")); - EXPECT_FALSE(path_is_just_drive_letter("C:\\")); - EXPECT_FALSE(path_is_just_drive_letter("C:/")); - EXPECT_FALSE(path_is_just_drive_letter("C:\\test")); - EXPECT_FALSE(path_is_just_drive_letter("C:\\test\\")); - EXPECT_FALSE(path_is_just_drive_letter("/")); - EXPECT_FALSE(path_is_just_drive_letter("")); -} - -#else - -TEST(PathTest, onNonWindowsWeDontHaveDriveLetterPaths) { - EXPECT_FALSE(path_is_just_drive_letter("C")); - EXPECT_FALSE(path_is_just_drive_letter("C:")); - EXPECT_FALSE(path_is_just_drive_letter("C:\\")); - EXPECT_FALSE(path_is_just_drive_letter("C:/")); - EXPECT_FALSE(path_is_just_drive_letter("C:\\test")); - EXPECT_FALSE(path_is_just_drive_letter("C:\\test\\")); - EXPECT_FALSE(path_is_just_drive_letter("/")); - EXPECT_FALSE(path_is_just_drive_letter("")); -} - -#endif diff --git a/test/cpp-utils/system/TimeTest.cpp b/test/cpp-utils/system/TimeTest.cpp deleted file mode 100644 index 24b8deb4..00000000 --- a/test/cpp-utils/system/TimeTest.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include -#include -#include - -using cpputils::time::now; - -namespace { - -uint64_t _to_nanos(struct timespec time) { - constexpr uint64_t nanos = UINT64_C(1000000000); - return time.tv_sec * nanos + time.tv_nsec; -} -} - -TEST(TimeTest, DoesntCrash) { - now(); -} - -TEST(TimeTest, IsLaterThanYear2010) { - struct timespec current_time = now(); - constexpr time_t year_2010_timestamp = 1262304000; - EXPECT_LT(year_2010_timestamp, current_time.tv_sec); -} - -TEST(TimeTest, IsNondecreasing) { - uint64_t time1 = _to_nanos(now()); - uint64_t time2 = _to_nanos(now()); - EXPECT_LE(time1, time2); -} - -TEST(TimeTest, IsIncreasedAfterPause) { - uint64_t time1 = _to_nanos(now()); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - uint64_t time2 = _to_nanos(now()); - EXPECT_LT(time1, time2); -} - -constexpr struct timespec time1 {1262304000, 000000000}; -constexpr struct timespec time2 {1262304000, 000000001}; -constexpr struct timespec time3 {1262304000, 100000000}; -constexpr struct timespec time4 {1262304001, 000000001}; - -TEST(TimeTest, LessThan) { - EXPECT_FALSE(time1 < time1); - EXPECT_TRUE(time1 < time2); - EXPECT_TRUE(time1 < time3); - EXPECT_TRUE(time1 < time4); - EXPECT_FALSE(time2 < time1); - EXPECT_FALSE(time2 < time2); - EXPECT_TRUE(time2 < time3); - EXPECT_TRUE(time2 < time4); - EXPECT_FALSE(time3 < time1); - EXPECT_FALSE(time3 < time2); - EXPECT_FALSE(time3 < time3); - EXPECT_TRUE(time3 < time4); - EXPECT_FALSE(time4 < time1); - EXPECT_FALSE(time4 < time2); - EXPECT_FALSE(time4 < time3); - EXPECT_FALSE(time4 < time4); -} - -TEST(TimeTest, GreaterThan) { - EXPECT_FALSE(time1 > time1); - EXPECT_FALSE(time1 > time2); - EXPECT_FALSE(time1 > time3); - EXPECT_FALSE(time1 > time4); - EXPECT_TRUE(time2 > time1); - EXPECT_FALSE(time2 > time2); - EXPECT_FALSE(time2 > time3); - EXPECT_FALSE(time2 > time4); - EXPECT_TRUE(time3 > time1); - EXPECT_TRUE(time3 > time2); - EXPECT_FALSE(time3 > time3); - EXPECT_FALSE(time3 > time4); - EXPECT_TRUE(time4 > time1); - EXPECT_TRUE(time4 > time2); - EXPECT_TRUE(time4 > time3); - EXPECT_FALSE(time4 > time4); -} - -TEST(TimeTest, LessEquals) { - EXPECT_TRUE(time1 <= time1); - EXPECT_TRUE(time1 <= time2); - EXPECT_TRUE(time1 <= time3); - EXPECT_TRUE(time1 <= time4); - EXPECT_FALSE(time2 <= time1); - EXPECT_TRUE(time2 <= time2); - EXPECT_TRUE(time2 <= time3); - EXPECT_TRUE(time2 <= time4); - EXPECT_FALSE(time3 <= time1); - EXPECT_FALSE(time3 <= time2); - EXPECT_TRUE(time3 <= time3); - EXPECT_TRUE(time3 <= time4); - EXPECT_FALSE(time4 <= time1); - EXPECT_FALSE(time4 <= time2); - EXPECT_FALSE(time4 <= time3); - EXPECT_TRUE(time4 <= time4); -} - -TEST(TimeTest, GreaterEquals) { - EXPECT_TRUE(time1 >= time1); - EXPECT_FALSE(time1 >= time2); - EXPECT_FALSE(time1 >= time3); - EXPECT_FALSE(time1 >= time4); - EXPECT_TRUE(time2 >= time1); - EXPECT_TRUE(time2 >= time2); - EXPECT_FALSE(time2 >= time3); - EXPECT_FALSE(time2 >= time4); - EXPECT_TRUE(time3 >= time1); - EXPECT_TRUE(time3 >= time2); - EXPECT_TRUE(time3 >= time3); - EXPECT_FALSE(time3 >= time4); - EXPECT_TRUE(time4 >= time1); - EXPECT_TRUE(time4 >= time2); - EXPECT_TRUE(time4 >= time3); - EXPECT_TRUE(time4 >= time4); -} - -TEST(TimeTest, Equals) { - EXPECT_TRUE(time1 == time1); - EXPECT_FALSE(time1 == time2); - EXPECT_FALSE(time1 == time3); - EXPECT_FALSE(time1 == time4); - EXPECT_FALSE(time2 == time1); - EXPECT_TRUE(time2 == time2); - EXPECT_FALSE(time2 == time3); - EXPECT_FALSE(time2 == time4); - EXPECT_FALSE(time3 == time1); - EXPECT_FALSE(time3 == time2); - EXPECT_TRUE(time3 == time3); - EXPECT_FALSE(time3 == time4); - EXPECT_FALSE(time4 == time1); - EXPECT_FALSE(time4 == time2); - EXPECT_FALSE(time4 == time3); - EXPECT_TRUE(time4 == time4); -} - -TEST(TimeTest, NotEquals) { - EXPECT_FALSE(time1 != time1); - EXPECT_TRUE(time1 != time2); - EXPECT_TRUE(time1 != time3); - EXPECT_TRUE(time1 != time4); - EXPECT_TRUE(time2 != time1); - EXPECT_FALSE(time2 != time2); - EXPECT_TRUE(time2 != time3); - EXPECT_TRUE(time2 != time4); - EXPECT_TRUE(time3 != time1); - EXPECT_TRUE(time3 != time2); - EXPECT_FALSE(time3 != time3); - EXPECT_TRUE(time3 != time4); - EXPECT_TRUE(time4 != time1); - EXPECT_TRUE(time4 != time2); - EXPECT_TRUE(time4 != time3); - EXPECT_FALSE(time4 != time4); -} diff --git a/test/cpp-utils/tempfile/TempDirIncludeTest.cpp b/test/cpp-utils/tempfile/TempDirIncludeTest.cpp deleted file mode 100644 index 43262566..00000000 --- a/test/cpp-utils/tempfile/TempDirIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/tempfile/TempDir.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/tempfile/TempDirTest.cpp b/test/cpp-utils/tempfile/TempDirTest.cpp deleted file mode 100644 index baf68350..00000000 --- a/test/cpp-utils/tempfile/TempDirTest.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include - -#include "cpp-utils/tempfile/TempDir.h" - -#include - -using ::testing::Test; -using std::ofstream; - -using namespace cpputils; - -namespace bf = boost::filesystem; - -class TempDirTest: public Test { -public: - void EXPECT_ENTRY_COUNT(int expected, const bf::path &path) { - int actual = CountEntries(path); - EXPECT_EQ(expected, actual); - } - - int CountEntries(const bf::path &path) { - int count = 0; - for (bf::directory_iterator iter(path); iter != bf::directory_iterator(); ++iter) { - ++count; - } - return count; - } - - void CreateFile(const bf::path &path) { - ofstream file(path.string().c_str()); - } -}; - -TEST_F(TempDirTest, DirIsCreated) { - TempDir dir; - EXPECT_TRUE(bf::exists(dir.path())); - EXPECT_TRUE(bf::is_directory(dir.path())); -} - -TEST_F(TempDirTest, DirIsCreatedEmpty) { - TempDir dir; - EXPECT_ENTRY_COUNT(0, dir.path()); -} - -TEST_F(TempDirTest, DirIsWriteable) { - TempDir dir; - CreateFile(dir.path() / "myfile"); - EXPECT_ENTRY_COUNT(1, dir.path()); -} - -TEST_F(TempDirTest, DirIsDeletedAfterUse) { - bf::path dirpath; - { - TempDir dir; - dirpath = dir.path(); - } - EXPECT_FALSE(bf::exists(dirpath)); -} diff --git a/test/cpp-utils/tempfile/TempFileIncludeTest.cpp b/test/cpp-utils/tempfile/TempFileIncludeTest.cpp deleted file mode 100644 index 63ded6b2..00000000 --- a/test/cpp-utils/tempfile/TempFileIncludeTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "cpp-utils/tempfile/TempFile.h" - -// Test the header can be included without needing additional dependencies diff --git a/test/cpp-utils/tempfile/TempFileTest.cpp b/test/cpp-utils/tempfile/TempFileTest.cpp deleted file mode 100644 index 40d38288..00000000 --- a/test/cpp-utils/tempfile/TempFileTest.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include - -#include "cpp-utils/tempfile/TempFile.h" -#include "cpp-utils/tempfile/TempDir.h" - -#include - -using ::testing::Test; -using std::ifstream; -using std::ofstream; - -using namespace cpputils; - -namespace bf = boost::filesystem; - -class TempFileTest: public Test { -public: - TempFileTest(): tempdir(), filepath_sample(tempdir.path() / "myfile") {} - - TempDir tempdir; - bf::path filepath_sample; - - void CreateFile(const bf::path &path) { - ofstream file(path.string().c_str()); - } -}; - -TEST_F(TempFileTest, FileIsCreated) { - TempFile file; - EXPECT_TRUE(bf::exists(file.path())); - EXPECT_TRUE(bf::is_regular_file(file.path())); -} - -TEST_F(TempFileTest, FileIsReadable) { - TempFile file; - ifstream opened(file.path().string().c_str()); - EXPECT_TRUE(opened.good()); -} - -TEST_F(TempFileTest, FileIsCreatedEmpty) { - TempFile file; - ifstream opened(file.path().string().c_str()); - opened.get(); - EXPECT_TRUE(opened.eof()); -} - -TEST_F(TempFileTest, FileIsWriteable) { - TempFile file; - ofstream opened(file.path().string().c_str()); - EXPECT_TRUE(opened.good()); -} - -TEST_F(TempFileTest, FileIsDeletedAfterUse) { - bf::path filepath; - { - TempFile file; - filepath = file.path(); - } - EXPECT_FALSE(bf::exists(filepath)); -} - -TEST_F(TempFileTest, DontCreateFileSpecified_FileIsNotCreated) { - TempFile file(false); - EXPECT_FALSE(bf::exists(file.path())); -} - -TEST_F(TempFileTest, DontCreateFileSpecified_FileIsCreatable) { - TempFile file(false); - CreateFile(file.path()); - EXPECT_TRUE(bf::exists(file.path())); -} - -TEST_F(TempFileTest, DontCreateFileSpecified_FileIsDeletedAfterUse) { - bf::path filepath; - { - TempFile file(false); - CreateFile(file.path()); - filepath = file.path(); - } - EXPECT_FALSE(bf::exists(filepath)); -} - -TEST_F(TempFileTest, PathGiven_FileIsCreatedAtGivenPath) { - TempFile file(filepath_sample); - EXPECT_EQ(filepath_sample, file.path()); -} - -TEST_F(TempFileTest, PathGiven_FileIsCreatedAndAccessible) { - TempFile file(filepath_sample); - EXPECT_TRUE(bf::exists(filepath_sample)); -} - -TEST_F(TempFileTest, PathGiven_FileIsDeletedAfterUse) { - { - TempFile file(filepath_sample); - } - EXPECT_FALSE(bf::exists(filepath_sample)); -} - -TEST_F(TempFileTest, PathGiven_DontCreateFileSpecified_FileIsNotCreated) { - TempFile file(filepath_sample, false); - EXPECT_FALSE(bf::exists(filepath_sample)); -} - -TEST_F(TempFileTest, PathGiven_DontCreateFileSpecified_FileIsCreatable) { - TempFile file(filepath_sample, false); - CreateFile(filepath_sample); - EXPECT_TRUE(bf::exists(filepath_sample)); -} - -TEST_F(TempFileTest, PathGiven_DontCreateFileSpecified_FileIsDeletedAfterUse) { - { - TempFile file(filepath_sample, false); - CreateFile(filepath_sample); - } - EXPECT_FALSE(bf::exists(filepath_sample)); -} diff --git a/test/cpp-utils/thread/LeftRightTest.cpp b/test/cpp-utils/thread/LeftRightTest.cpp deleted file mode 100644 index 851d2d47..00000000 --- a/test/cpp-utils/thread/LeftRightTest.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include -#include -#include - -using cpputils::LeftRight; -using std::vector; - -TEST(LeftRightTest, givenInt_whenWritingAndReading_thenChangesArePresent) { - LeftRight obj; - - obj.write([] (auto& obj) {obj = 5;}); - int read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ(5, read); - - // check changes are also present in background copy - obj.write([] (auto&) {}); // this switches to the background copy - read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ(5, read); -} - -TEST(LeftRightTest, givenVector_whenWritingAndReading_thenChangesArePresent) { - LeftRight> obj; - - obj.write([] (auto& obj) {obj.push_back(5);}); - vector read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ((vector{5}), read); - - obj.write([] (auto& obj) {obj.push_back(6);}); - read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ((vector{5, 6}), read); -} - -TEST(LeftRightTest, givenVector_whenWritingReturnsValue_thenValueIsReturned) { - LeftRight> obj; - - auto a = obj.write([] (auto&) -> int {return 5;}); - static_assert(std::is_same::value, ""); - EXPECT_EQ(5, a); -} - -TEST(LeftRightTest, readsCanBeConcurrent) { - LeftRight obj; - std::atomic num_running_readers{0}; - - std::thread reader1([&] () { - obj.read([&] (auto&) { - ++num_running_readers; - while(num_running_readers.load() < 2) {} - }); - }); - - std::thread reader2([&] () { - obj.read([&] (auto&) { - ++num_running_readers; - while(num_running_readers.load() < 2) {} - }); - }); - - // the threads only finish after both entered the read function. - // if LeftRight didn't allow concurrency, this would cause a deadlock. - reader1.join(); - reader2.join(); -} - -TEST(LeftRightTest, writesCanBeConcurrentWithReads_readThenWrite) { - LeftRight obj; - std::atomic reader_running{false}; - std::atomic writer_running{false}; - - std::thread reader([&] () { - obj.read([&] (auto&) { - reader_running = true; - while(!writer_running.load()) {} - }); - }); - - std::thread writer([&] () { - // run read first, write second - while (!reader_running.load()) {} - - obj.write([&] (auto&) { - writer_running = true; - }); - }); - - // the threads only finish after both entered the read function. - // if LeftRight didn't allow concurrency, this would cause a deadlock. - reader.join(); - writer.join(); -} - -TEST(LeftRightTest, writesCanBeConcurrentWithReads_writeThenRead) { - LeftRight obj; - std::atomic writer_running{false}; - std::atomic reader_running{false}; - - std::thread writer([&] () { - obj.read([&] (auto&) { - writer_running = true; - while(!reader_running.load()) {} - }); - }); - - std::thread reader([&] () { - // run write first, read second - while (!writer_running.load()) {} - - obj.read([&] (auto&) { - reader_running = true; - }); - }); - - // the threads only finish after both entered the read function. - // if LeftRight didn't allow concurrency, this would cause a deadlock. - writer.join(); - reader.join(); -} - -TEST(LeftRightTest, writesCannotBeConcurrentWithWrites) { - LeftRight obj; - std::atomic first_writer_started{false}; - std::atomic first_writer_finished{false}; - - std::thread writer1([&] () { - obj.write([&] (auto&) { - first_writer_started = true; - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - first_writer_finished = true; - }); - }); - - std::thread writer2([&] () { - // make sure the other writer runs first - while (!first_writer_started.load()) {} - - obj.write([&] (auto&) { - // expect the other writer finished before this one starts - EXPECT_TRUE(first_writer_finished.load()); - }); - }); - - writer1.join(); - writer2.join(); -} - -namespace { -class MyException : std::exception {}; -} - -TEST(LeftRightTest, whenReadThrowsException_thenThrowsThrough) { - LeftRight obj; - - EXPECT_THROW( - obj.read([](auto&) {throw MyException();}), - MyException - ); -} - -TEST(LeftRightTest, whenWriteThrowsException_thenThrowsThrough) { - LeftRight obj; - - EXPECT_THROW( - obj.write([](auto&) {throw MyException();}), - MyException - ); -} - -TEST(LeftRightTest, givenInt_whenWriteThrowsExceptionOnFirstCall_thenResetsToOldState) { - LeftRight obj; - - obj.write([](auto& obj) {obj = 5;}); - - EXPECT_THROW( - obj.write([](auto& obj) { - obj = 6; - throw MyException(); - }), - MyException - ); - - // check reading it returns old value - int read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ(5, read); - - // check changes are also present in background copy - obj.write([] (auto&) {}); // this switches to the background copy - read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ(5, read); -} - -// note: each write is executed twice, on the foreground and background copy. -// We need to test a thrown exception in either call is handled correctly. -TEST(LeftRightTest, givenInt_whenWriteThrowsExceptionOnSecondCall_thenKeepsNewState) { - LeftRight obj; - - obj.write([](auto& obj) {obj = 5;}); - bool write_called = false; - - EXPECT_THROW( - obj.write([&](auto& obj) { - obj = 6; - if (write_called) { - // this is the second time the write callback is executed - throw MyException(); - } else { - write_called = true; - } - }), - MyException - ); - - // check reading it returns new value - int read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ(6, read); - - // check changes are also present in background copy - obj.write([] (auto&) {}); // this switches to the background copy - read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ(6, read); -} - -TEST(LeftRightTest, givenVector_whenWriteThrowsException_thenResetsToOldState) { - LeftRight> obj; - - obj.write([](auto& obj) {obj.push_back(5);}); - - EXPECT_THROW( - obj.write([](auto& obj) { - obj.push_back(6); - throw MyException(); - }), - MyException - ); - - // check reading it returns old value - vector read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ((vector{5}), read); - - // check changes are also present in background copy - obj.write([] (auto&) {}); // this switches to the background copy - read = obj.read([] (auto& obj) {return obj;}); - EXPECT_EQ((vector{5}), read); -} diff --git a/test/cpp-utils/thread/debugging_test.cpp b/test/cpp-utils/thread/debugging_test.cpp deleted file mode 100644 index caf5f458..00000000 --- a/test/cpp-utils/thread/debugging_test.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include - -using namespace cpputils; -using std::string; - -TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenSettingAndGetting_thenDoesntCrash) { - set_thread_name("my_thread_name"); - get_thread_name(); -} - -TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenGettingFromInside_thenIsCorrect) { - set_thread_name("my_thread_name"); - string name = get_thread_name(); - EXPECT_EQ("my_thread_name", name); -} - -TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromInside_thenIsCorrect) { - std::thread child([] { - set_thread_name("my_thread_name"); - string name = get_thread_name(); - EXPECT_EQ("my_thread_name", name); - }); - child.join(); -} - - -#if defined(__GLIBC__) || defined(__APPLE__) || defined(_MSC_VER) -// disabled on musl because getting the thread name for a child thread doesn't work there -TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_thenDoesntCrash) { - ConditionBarrier nameIsChecked; - - bool child_didnt_crash = false; - std::thread child([&] { - set_thread_name("my_thread_name"); - get_thread_name(); - child_didnt_crash = true; - nameIsChecked.wait(); - }); - get_thread_name(&child); - nameIsChecked.release(); // getting the name of a not-running thread would cause errors, so let's make sure we only exit after getting the name - child.join(); - EXPECT_TRUE(child_didnt_crash); -} - -TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromOutside_thenIsCorrect) { - ConditionBarrier nameIsSet; - ConditionBarrier nameIsChecked; - - std::thread child([&] { - set_thread_name("my_thread_name"); - nameIsSet.release(); - nameIsChecked.wait(); - }); - - nameIsSet.wait(); - set_thread_name("outer_thread_name"); // just to make sure the next line doesn't read the outer thread name - string name = get_thread_name(&child); - EXPECT_EQ("my_thread_name", name); - - nameIsChecked.release(); - child.join(); -} -#endif diff --git a/test/cpp-utils/value_type/ValueTypeTest.cpp b/test/cpp-utils/value_type/ValueTypeTest.cpp deleted file mode 100644 index cb984d38..00000000 --- a/test/cpp-utils/value_type/ValueTypeTest.cpp +++ /dev/null @@ -1,481 +0,0 @@ -#include -#include -#include -#include -#include - -// TODO Test with MovableOnly underlying type -// TODO Test that move constructing/assigning actually moves the underlying -// TODO Test that noexcept flags are set correctly - -using cpputils::value_type::IdValueType; -using cpputils::value_type::OrderedIdValueType; -using cpputils::value_type::QuantityValueType; -using cpputils::value_type::FlagsValueType; - -// TODO Test that noexcept flags are set correctly - -namespace { - -struct MyIdValueType : IdValueType { - constexpr explicit MyIdValueType(int64_t val): IdValueType(val) {} -}; - -struct MyOrderedIdValueType : OrderedIdValueType { - constexpr explicit MyOrderedIdValueType(int64_t val): OrderedIdValueType(val) {} -}; - -struct MyQuantityValueType : QuantityValueType { - constexpr explicit MyQuantityValueType(int64_t val): QuantityValueType(val) {} -}; - -struct MyFlagsValueType : FlagsValueType { - constexpr explicit MyFlagsValueType(int64_t val): FlagsValueType(val) {} -}; - -} -DEFINE_HASH_FOR_VALUE_TYPE(MyIdValueType); -DEFINE_HASH_FOR_VALUE_TYPE(MyOrderedIdValueType); -DEFINE_HASH_FOR_VALUE_TYPE(MyQuantityValueType); -DEFINE_HASH_FOR_VALUE_TYPE(MyFlagsValueType); -namespace { - -/** - * Tests for IdValueType - */ - -template -struct IdValueTypeTest_constexpr_test { - static constexpr Type test_constructor = Type(5); - static_assert(Type(5) == test_constructor, ""); - - static constexpr Type test_copy_constructor = test_constructor; - static_assert(Type(5) == test_copy_constructor, ""); - -#if !defined(_MSC_VER) - // These aren't evaluated at compile time on MSVC :( - static constexpr Type test_copy_assignment = (Type(4) = test_copy_constructor); - static_assert(test_copy_assignment == Type(5), ""); - - static constexpr Type test_move_assignment = (Type(4) = Type(3)); - static_assert(test_move_assignment == Type(3), ""); -#endif - - static_assert(Type(5) == Type(5), ""); - static_assert(!(Type(5) != Type(5)), ""); - - static constexpr bool success = true; -}; -static_assert(IdValueTypeTest_constexpr_test::success, ""); -static_assert(IdValueTypeTest_constexpr_test::success, ""); -static_assert(IdValueTypeTest_constexpr_test::success, ""); -static_assert(IdValueTypeTest_constexpr_test::success, ""); - -namespace IdValueTypeTest_constexpr_test_extras { - // For some reason, MSVC crashes when these are part of IdValueTypeTest_constexpr_test. - // so let's define them separately. - static_assert(!(MyIdValueType(5) == MyIdValueType(6)), ""); - static_assert(MyIdValueType(5) != MyIdValueType(6), ""); - static_assert(!(MyOrderedIdValueType(5) == MyOrderedIdValueType(6)), ""); - static_assert(MyOrderedIdValueType(5) != MyOrderedIdValueType(6), ""); - static_assert(!(MyQuantityValueType(5) == MyQuantityValueType(6)), ""); - static_assert(MyQuantityValueType(5) != MyQuantityValueType(6), ""); - static_assert(!(MyFlagsValueType(5) == MyFlagsValueType(6)), ""); - static_assert(MyFlagsValueType(5) != MyFlagsValueType(6), ""); -} - - -template class IdValueTypeTest : public testing::Test { -}; -using IdValueTypeTest_types = testing::Types; -TYPED_TEST_SUITE(IdValueTypeTest, IdValueTypeTest_types); - - -TYPED_TEST(IdValueTypeTest, Equality) { - TypeParam obj1(4); - TypeParam obj2(4); - TypeParam obj3(5); - - EXPECT_TRUE(obj1 == obj2); - EXPECT_TRUE(obj2 == obj1);; - EXPECT_FALSE(obj1 == obj3); - EXPECT_FALSE(obj3 == obj1); - - EXPECT_FALSE(obj1 != obj2); - EXPECT_FALSE(obj2 != obj1); - EXPECT_TRUE(obj1 != obj3); - EXPECT_TRUE(obj3 != obj1); -} - -TYPED_TEST(IdValueTypeTest, Constructor) { - TypeParam obj(4); - EXPECT_TRUE(obj == TypeParam(4)); -} - -TYPED_TEST(IdValueTypeTest, CopyConstructor) { - TypeParam obj(2); - TypeParam obj2(obj); - EXPECT_TRUE(obj2 == TypeParam(2)); - EXPECT_TRUE(obj == obj2); -} - -TYPED_TEST(IdValueTypeTest, MoveConstructor) { - TypeParam obj(2); - TypeParam obj2(std::move(obj)); - EXPECT_TRUE(obj2 == TypeParam(2)); -} - -TYPED_TEST(IdValueTypeTest, CopyAssignment) { - TypeParam obj(3); - TypeParam obj2(2); - obj2 = obj; - EXPECT_TRUE(obj2 == TypeParam(3)); - EXPECT_TRUE(obj == obj2); -} - -TYPED_TEST(IdValueTypeTest, CopyAssignment_Return) { - TypeParam obj(3); - TypeParam obj2(2); - EXPECT_TRUE((obj2 = obj) == TypeParam(3)); -} - -TYPED_TEST(IdValueTypeTest, MoveAssignment) { - TypeParam obj(3); - TypeParam obj2(2); - obj2 = std::move(obj); - EXPECT_TRUE(obj2 == TypeParam(3)); -} - -TYPED_TEST(IdValueTypeTest, MoveAssignment_Return) { - TypeParam obj(3); - TypeParam obj2(2); - EXPECT_TRUE((obj2 = std::move(obj)) == TypeParam(3)); -} - -TYPED_TEST(IdValueTypeTest, Hash) { - TypeParam obj(3); - TypeParam obj2(3); - EXPECT_EQ(std::hash()(obj), std::hash()(obj2)); -} - -TYPED_TEST(IdValueTypeTest, UnorderedSet) { - std::unordered_set set; - set.insert(TypeParam(3)); - EXPECT_EQ(1u, set.count(TypeParam(3))); -} - - - - - -/** - * Tests for OrderedIdValueType - */ - -template -struct OrderedIdValueTypeTest_constexpr_test { - static_assert(!(Type(4) < Type(3)), ""); - static_assert(!(Type(3) < Type(3)), ""); - - static_assert(!(Type(3) > Type(4)), ""); - static_assert(!(Type(3) > Type(3)), ""); - - static_assert(Type(3) <= Type(4), ""); - static_assert(Type(3) <= Type(3), ""); - - static_assert(Type(4) >= Type(3), ""); - static_assert(Type(3) >= Type(3), ""); - - static constexpr bool success = true; -}; -static_assert(OrderedIdValueTypeTest_constexpr_test::success, ""); -static_assert(OrderedIdValueTypeTest_constexpr_test::success, ""); - -namespace OrderedIdValueTypeTest_constexpr_test_extras { - // For some reason, MSVC crashes when these are part of IdValueTypeTest_constexpr_test. - // so let's define them separately. - static_assert(MyOrderedIdValueType(3) < MyOrderedIdValueType(4), ""); - static_assert(MyOrderedIdValueType(4) > MyOrderedIdValueType(3), ""); - static_assert(!(MyOrderedIdValueType(4) <= MyOrderedIdValueType(3)), ""); - static_assert(!(MyOrderedIdValueType(3) >= MyOrderedIdValueType(4)), ""); - static_assert(MyQuantityValueType(3) < MyQuantityValueType(4), ""); - static_assert(MyQuantityValueType(4) > MyQuantityValueType(3), ""); - static_assert(!(MyQuantityValueType(4) <= MyQuantityValueType(3)), ""); - static_assert(!(MyQuantityValueType(3) >= MyQuantityValueType(4)), ""); -} - - -template class OrderedIdValueTypeTest : public testing::Test {}; -using OrderedIdValueTypeTest_types = testing::Types; -TYPED_TEST_SUITE(OrderedIdValueTypeTest, OrderedIdValueTypeTest_types); - -TYPED_TEST(OrderedIdValueTypeTest, LessThan) { - TypeParam a(3); - TypeParam b(3); - TypeParam c(4); - EXPECT_FALSE(a < a); - EXPECT_FALSE(a < b); - EXPECT_TRUE(a < c); - EXPECT_FALSE(b < a); - EXPECT_FALSE(b < b); - EXPECT_TRUE(b < c); - EXPECT_FALSE(c < a); - EXPECT_FALSE(c < b); - EXPECT_FALSE(c < c); -} - -TYPED_TEST(OrderedIdValueTypeTest, GreaterThan) { - TypeParam a(3); - TypeParam b(3); - TypeParam c(4); - EXPECT_FALSE(a > a); - EXPECT_FALSE(a > b); - EXPECT_FALSE(a > c); - EXPECT_FALSE(b > a); - EXPECT_FALSE(b > b); - EXPECT_FALSE(b > c); - EXPECT_TRUE(c > a); - EXPECT_TRUE(c > b); - EXPECT_FALSE(c > c); -} - -TYPED_TEST(OrderedIdValueTypeTest, LessOrEqualThan) { - TypeParam a(3); - TypeParam b(3); - TypeParam c(4); - EXPECT_TRUE(a <= a); - EXPECT_TRUE(a <= b); - EXPECT_TRUE(a <= c); - EXPECT_TRUE(b <= a); - EXPECT_TRUE(b <= b); - EXPECT_TRUE(b <= c); - EXPECT_FALSE(c <= a); - EXPECT_FALSE(c <= b); - EXPECT_TRUE(c <= c); -} - -TYPED_TEST(OrderedIdValueTypeTest, GreaterOrEqualThan) { - TypeParam a(3); - TypeParam b(3); - TypeParam c(4); - EXPECT_TRUE(a >= a); - EXPECT_TRUE(a >= b); - EXPECT_FALSE(a >= c); - EXPECT_TRUE(b >= a); - EXPECT_TRUE(b >= b); - EXPECT_FALSE(b >= c); - EXPECT_TRUE(c >= a); - EXPECT_TRUE(c >= b); - EXPECT_TRUE(c >= c); -} - -TYPED_TEST(OrderedIdValueTypeTest, Set) { - std::set set; - set.insert(TypeParam(3)); - EXPECT_EQ(1u, set.count(TypeParam(3))); -} - - - - - - -/** - * Tests for QuantityValueType - */ - -namespace QuantityValueTypeTest_constexpr_test { - static_assert(++MyQuantityValueType(3) == MyQuantityValueType(4), ""); - static_assert(MyQuantityValueType(3)++ == MyQuantityValueType(3), ""); - static_assert(--MyQuantityValueType(3) == MyQuantityValueType(2), ""); - static_assert(MyQuantityValueType(3)-- == MyQuantityValueType(3), ""); - static_assert((MyQuantityValueType(3) += MyQuantityValueType(2)) == MyQuantityValueType(5), ""); - static_assert((MyQuantityValueType(3) -= MyQuantityValueType(2)) == MyQuantityValueType(1), ""); - static_assert((MyQuantityValueType(3) *= 2) == MyQuantityValueType(6), ""); - static_assert((MyQuantityValueType(6) /= 2) == MyQuantityValueType(3), ""); - static_assert((MyQuantityValueType(7) /= 3) == MyQuantityValueType(2), ""); - static_assert((MyQuantityValueType(7) %= 3) == MyQuantityValueType(1), ""); - static_assert(MyQuantityValueType(3) + MyQuantityValueType(2) == MyQuantityValueType(5), ""); - static_assert(MyQuantityValueType(3) - MyQuantityValueType(2) == MyQuantityValueType(1), ""); - static_assert(MyQuantityValueType(3) * 2 == MyQuantityValueType(6), ""); - static_assert(2 * MyQuantityValueType(3) == MyQuantityValueType(6), ""); - static_assert(MyQuantityValueType(6) / 2 == MyQuantityValueType(3), ""); - static_assert(MyQuantityValueType(6) / MyQuantityValueType(2) == 3, ""); - static_assert(MyQuantityValueType(7) / 3 == MyQuantityValueType(2), ""); - static_assert(MyQuantityValueType(7) / MyQuantityValueType(3) == 2, ""); - static_assert(MyQuantityValueType(7) % 3 == MyQuantityValueType(1), ""); - static_assert(MyQuantityValueType(7) % MyQuantityValueType(3) == 1, ""); -}; - - -template class QuantityValueTypeTest : public testing::Test {}; -using QuantityValueTypeTest_types = testing::Types; -TYPED_TEST_SUITE(QuantityValueTypeTest, QuantityValueTypeTest_types); - -TYPED_TEST(QuantityValueTypeTest, PreIncrement) { - TypeParam a(3); - EXPECT_EQ(TypeParam(4), ++a); - EXPECT_EQ(TypeParam(4), a); -} - -TYPED_TEST(QuantityValueTypeTest, PostIncrement) { - TypeParam a(3); - EXPECT_EQ(TypeParam(3), a++); - EXPECT_EQ(TypeParam(4), a); -} - -TYPED_TEST(QuantityValueTypeTest, PreDecrement) { - TypeParam a(3); - EXPECT_EQ(TypeParam(2), --a); - EXPECT_EQ(TypeParam(2), a); -} - -TYPED_TEST(QuantityValueTypeTest, PostDecrement) { - TypeParam a(3); - EXPECT_EQ(TypeParam(3), a--); - EXPECT_EQ(TypeParam(2), a); -} - -TYPED_TEST(QuantityValueTypeTest, AddAssignment) { - TypeParam a(3); - EXPECT_EQ(TypeParam(5), a += TypeParam(2)); - EXPECT_EQ(TypeParam(5), a); -} - -TYPED_TEST(QuantityValueTypeTest, SubAssignment) { - TypeParam a(3); - EXPECT_EQ(TypeParam(1), a -= TypeParam(2)); - EXPECT_EQ(TypeParam(1), a); -} - -TYPED_TEST(QuantityValueTypeTest, MulAssignment) { - TypeParam a(3); - EXPECT_EQ(TypeParam(6), a *= 2); - EXPECT_EQ(TypeParam(6), a); -} - -TYPED_TEST(QuantityValueTypeTest, DivScalarAssignment) { - TypeParam a(6); - EXPECT_EQ(TypeParam(3), a /= 2); - EXPECT_EQ(TypeParam(3), a); -} - -TYPED_TEST(QuantityValueTypeTest, DivScalarWithRemainderAssignment) { - TypeParam a(7); - EXPECT_EQ(TypeParam(2), a /= 3); - EXPECT_EQ(TypeParam(2), a); -} - -TYPED_TEST(QuantityValueTypeTest, ModScalarAssignment) { - TypeParam a(7); - EXPECT_EQ(TypeParam(1), a %= 3); - EXPECT_EQ(TypeParam(1), a); -} - -TYPED_TEST(QuantityValueTypeTest, Add) { - EXPECT_EQ(TypeParam(5), TypeParam(3) + TypeParam(2)); -} - -TYPED_TEST(QuantityValueTypeTest, Sub) { - EXPECT_EQ(TypeParam(1), TypeParam(3) - TypeParam(2)); -} - -TYPED_TEST(QuantityValueTypeTest, Mul1) { - EXPECT_EQ(TypeParam(6), TypeParam(3) * 2); -} - -TYPED_TEST(QuantityValueTypeTest, Mul2) { - EXPECT_EQ(TypeParam(6), 2 * TypeParam(3)); -} - -TYPED_TEST(QuantityValueTypeTest, DivScalar) { - EXPECT_EQ(TypeParam(3), TypeParam(6) / 2); -} - -TYPED_TEST(QuantityValueTypeTest, DivValue) { - EXPECT_EQ(3, TypeParam(6) / TypeParam(2)); -} - -TYPED_TEST(QuantityValueTypeTest, DivScalarWithRemainder) { - EXPECT_EQ(TypeParam(2), TypeParam(7) / 3); -} - -TYPED_TEST(QuantityValueTypeTest, DivValueWithRemainder) { - EXPECT_EQ(2, TypeParam(7) / TypeParam(3)); -} - -TYPED_TEST(QuantityValueTypeTest, ModScalar) { - EXPECT_EQ(TypeParam(1), TypeParam(7) % 3); -} - -TYPED_TEST(QuantityValueTypeTest, ModValue) { - EXPECT_EQ(1, TypeParam(7) % TypeParam(3)); -} - - - - - -/** - * Tests for FlagsValueType - */ - -namespace FlagsValueTypeTest_constexpr_test { - static_assert(~MyFlagsValueType(3) != MyFlagsValueType(3), ""); - static_assert(~~MyFlagsValueType(3) == MyFlagsValueType(3), ""); - static_assert(~MyFlagsValueType(3) == MyFlagsValueType(~3), ""); - - static_assert((MyFlagsValueType(3) & MyFlagsValueType(5)) == MyFlagsValueType(3 & 5), ""); - static_assert((MyFlagsValueType(3) | MyFlagsValueType(5)) == MyFlagsValueType(3 | 5), ""); - static_assert((MyFlagsValueType(3) ^ MyFlagsValueType(5)) == MyFlagsValueType(3 ^ 5), ""); - - static_assert((MyFlagsValueType(3) &= MyFlagsValueType(5)) == MyFlagsValueType(3 & 5), ""); - static_assert((MyFlagsValueType(3) |= MyFlagsValueType(5)) == MyFlagsValueType(3 | 5), ""); - static_assert((MyFlagsValueType(3) ^= MyFlagsValueType(5)) == MyFlagsValueType(3 ^ 5), ""); -} - - -template class FlagsValueTypeTest : public testing::Test {}; -using FlagsValueType_types = testing::Types; -TYPED_TEST_SUITE(FlagsValueTypeTest, FlagsValueType_types); - -TYPED_TEST(FlagsValueTypeTest, Invert) { - TypeParam a(3); - TypeParam b(~3); - EXPECT_EQ(b, ~a); - - a = ~a; - EXPECT_EQ(b, a); -} - -TYPED_TEST(FlagsValueTypeTest, And) { - TypeParam a(3); - TypeParam b(5); - TypeParam c(3 & 5); - EXPECT_EQ(c, a & b); - - EXPECT_EQ(c, b &= a); - EXPECT_EQ(c, b); -} - -TYPED_TEST(FlagsValueTypeTest, Or) { - TypeParam a(3); - TypeParam b(5); - TypeParam c(3 | 5); - EXPECT_EQ(c, a | b); - - EXPECT_EQ(c, b |= a); - EXPECT_EQ(c, b); -} - -TYPED_TEST(FlagsValueTypeTest, Xor) { - TypeParam a(3); - TypeParam b(5); - TypeParam c(3 ^ 5); - EXPECT_EQ(c, a ^ b); - - EXPECT_EQ(c, b ^= a); - EXPECT_EQ(c, b); -} - -} diff --git a/test/cryfs-cli/CMakeLists.txt b/test/cryfs-cli/CMakeLists.txt deleted file mode 100644 index 2d0b38c5..00000000 --- a/test/cryfs-cli/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -project (cryfs-cli-test) - -set(SOURCES - CallAfterTimeoutTest.cpp - testutils/CliTest.cpp - CliTest_Setup.cpp - CliTest_WrongEnvironment.cpp - program_options/UtilsTest.cpp - program_options/ProgramOptionsTest.cpp - program_options/ParserTest.cpp - CliTest_ShowingHelp.cpp - EnvironmentTest.cpp - VersionCheckerTest.cpp - CliTest_IntegrityCheck.cpp - CryfsUnmountTest.cpp -) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest cryfs-cli cryfs-unmount fspp-fuse) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/cryfs-cli/CallAfterTimeoutTest.cpp b/test/cryfs-cli/CallAfterTimeoutTest.cpp deleted file mode 100644 index 5d11ed0c..00000000 --- a/test/cryfs-cli/CallAfterTimeoutTest.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include -#include - -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using boost::chrono::milliseconds; -using boost::chrono::minutes; -using boost::this_thread::sleep_for; -using namespace cryfs_cli; - -class CallAfterTimeoutTest : public ::testing::Test { -public: - CallAfterTimeoutTest(): called(false) {} - - unique_ref callAfterTimeout(milliseconds timeout) { - return make_unique_ref(timeout, [this] {called = true;}, "test"); - } - - std::atomic called; -}; - -TEST_F(CallAfterTimeoutTest, NoReset_1) { - auto obj = callAfterTimeout(milliseconds(100)); - sleep_for(milliseconds(50)); - EXPECT_FALSE(called); - sleep_for(milliseconds(100)); - EXPECT_TRUE(called); -} - -TEST_F(CallAfterTimeoutTest, NoReset_2) { - auto obj = callAfterTimeout(milliseconds(200)); - sleep_for(milliseconds(150)); - EXPECT_FALSE(called); - sleep_for(milliseconds(100)); - EXPECT_TRUE(called); -} - -TEST_F(CallAfterTimeoutTest, DoesntCallTwice) { - auto obj = callAfterTimeout(milliseconds(50)); - // Wait until it was called - while(!called) { - sleep_for(milliseconds(10)); - } - EXPECT_TRUE(called); - // Test that it isn't called again - called = false; - sleep_for(milliseconds(150)); - EXPECT_FALSE(called); -} - -TEST_F(CallAfterTimeoutTest, OneReset) { - auto obj = callAfterTimeout(milliseconds(200)); - sleep_for(milliseconds(125)); - obj->resetTimer(); - sleep_for(milliseconds(125)); - EXPECT_FALSE(called); - sleep_for(milliseconds(125)); - EXPECT_TRUE(called); -} - -TEST_F(CallAfterTimeoutTest, TwoResets) { - auto obj = callAfterTimeout(milliseconds(200)); - sleep_for(milliseconds(100)); - obj->resetTimer(); - sleep_for(milliseconds(125)); - obj->resetTimer(); - sleep_for(milliseconds(125)); - EXPECT_FALSE(called); - sleep_for(milliseconds(125)); - EXPECT_TRUE(called); -} diff --git a/test/cryfs-cli/CliTest_IntegrityCheck.cpp b/test/cryfs-cli/CliTest_IntegrityCheck.cpp deleted file mode 100644 index 4ac5c30c..00000000 --- a/test/cryfs-cli/CliTest_IntegrityCheck.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "testutils/CliTest.h" -#include -#include -#include -#include -#include -#include -#include - -using std::vector; -using std::string; -using cryfs::CryConfig; -using cryfs::CryConfigFile; -using cryfs::ErrorCode; -using cryfs::CryKeyProvider; -using cpputils::Data; -using cpputils::EncryptionKey; -using cpputils::SCrypt; -using cpputils::TempDir; -namespace bf = boost::filesystem; - -namespace { - -void writeFile(const bf::path& filename, const string& content) { - std::ofstream file(filename.c_str(), std::ios::trunc); - file << content; - ASSERT(file.good(), "Failed writing file to file system"); -} - -bool readingFileIsSuccessful(const bf::path& filename) { - std::ifstream file(filename.c_str()); - std::string content; - file >> content; // just read a little bit so we have a file access - return file.good(); -} - -// NOLINTNEXTLINE(misc-no-recursion) -void recursive_copy(const bf::path &src, const bf::path &dst) { - if (bf::exists(dst)) { - throw std::runtime_error(dst.generic_string() + " already exists"); - } - - if (bf::is_directory(src)) { - bf::create_directories(dst); - for (auto& item : bf::directory_iterator(src)) { - recursive_copy(item.path(), dst / item.path().filename()); - } - } else if (bf::is_regular_file(src)) { - bf::copy_file(src, dst); - } else { - throw std::runtime_error(dst.generic_string() + " neither dir nor file"); - } -} - -class FakeCryKeyProvider final : public CryKeyProvider { - EncryptionKey requestKeyForExistingFilesystem(size_t keySize, const Data &kdfParameters) override { - return SCrypt(SCrypt::TestSettings).deriveExistingKey(keySize, "pass", kdfParameters); - } - - KeyResult requestKeyForNewFilesystem(size_t keySize) override { - auto derived = SCrypt(SCrypt::TestSettings).deriveNewKey(keySize, "pass"); - return { - std::move(derived.key), - std::move(derived.kdfParameters) - }; - } -}; - -class CliTest_IntegrityCheck : public CliTest { -public: - void modifyFilesystemId() { - FakeCryKeyProvider keyProvider; - auto configFile = CryConfigFile::load(basedir / "cryfs.config", &keyProvider, CryConfigFile::Access::ReadWrite).right_opt().value(); - configFile->config()->SetFilesystemId(CryConfig::FilesystemID::FromString("0123456789ABCDEF0123456789ABCDEF")); - configFile->save(); - } - - void modifyFilesystemKey() { - FakeCryKeyProvider keyProvider; - auto configFile = CryConfigFile::load(basedir / "cryfs.config", &keyProvider, CryConfigFile::Access::ReadWrite).right_opt().value(); - configFile->config()->SetEncryptionKey("0123456789ABCDEF0123456789ABCDEF"); - configFile->save(); - } -}; - -TEST_F(CliTest_IntegrityCheck, givenIncorrectFilesystemId_thenFails) { - vector args{basedir.string().c_str(), mountdir.string().c_str(), "--cipher", "aes-256-gcm", "-f"}; - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS(args, mountdir); - modifyFilesystemId(); - EXPECT_RUN_ERROR( - args, - "Error 20: The filesystem id in the config file is different to the last time we loaded a filesystem from this basedir.", - ErrorCode::FilesystemIdChanged - ); -} - -TEST_F(CliTest_IntegrityCheck, givenIncorrectFilesystemKey_thenFails) { - vector args{basedir.string().c_str(), mountdir.string().c_str(), "--cipher", "aes-256-gcm", "-f"}; - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS(args, mountdir); - modifyFilesystemKey(); - EXPECT_RUN_ERROR( - args, - "Error 21: The filesystem encryption key differs from the last time we loaded this filesystem. Did an attacker replace the file system?", - ErrorCode::EncryptionKeyChanged - ); -} - -// TODO Also enable this -TEST_F(CliTest_IntegrityCheck, givenFilesystemWithRolledBackBasedir_whenMounting_thenFails) { - vector args{basedir.string().c_str(), mountdir.string().c_str(), "--cipher", "aes-256-gcm", "-f"}; - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS/EXPECT_RUN_ERROR can handle that - - // create a filesystem with one file - EXPECT_RUN_SUCCESS(args, mountdir, [&] { - writeFile(mountdir / "myfile", "hello world"); - }); - - // backup the base directory - TempDir backup; - recursive_copy(basedir, backup.path() / "basedir"); - - // modify the file system contents - EXPECT_RUN_SUCCESS(args, mountdir, [&] { - writeFile(mountdir / "myfile", "hello world 2"); - }); - - // roll back base directory - bf::remove_all(basedir); - recursive_copy(backup.path() / "basedir", basedir); - - // error code is success because it unmounts normally - EXPECT_RUN_ERROR(args, "Integrity violation detected. Unmounting.", ErrorCode::IntegrityViolation, [&] { - EXPECT_FALSE(readingFileIsSuccessful(mountdir / "myfile")); - }); - - // Test it doesn't mount anymore now because it's marked with an integrity violation - EXPECT_RUN_ERROR(args, "There was an integrity violation detected. Preventing any further access to the file system.", ErrorCode::IntegrityViolationOnPreviousRun); -} - -TEST_F(CliTest_IntegrityCheck, whenRollingBackBasedirWhileMounted_thenUnmounts) { - vector args{basedir.string().c_str(), mountdir.string().c_str(), "--cipher", "aes-256-gcm", "-f"}; - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS/EXPECT_RUN_ERROR can handle that - - // create a filesystem with one file - EXPECT_RUN_SUCCESS(args, mountdir, [&] { - writeFile(mountdir / "myfile", "hello world"); - }); - - // backup the base directory - TempDir backup; - recursive_copy(basedir, backup.path() / "basedir"); - - EXPECT_RUN_ERROR(args, "Integrity violation detected. Unmounting.", ErrorCode::IntegrityViolation, [&] { - // modify the file system contents - writeFile(mountdir / "myfile", "hello world 2"); - ASSERT(readingFileIsSuccessful(mountdir / "myfile"), ""); // just to make sure reading usually works - - // wait for cache timeout (i.e. flush file system to disk) - constexpr auto cache_timeout = blockstore::caching::CachingBlockStore2::MAX_LIFETIME_SEC + cryfs::cachingfsblobstore::CachingFsBlobStore::MAX_LIFETIME_SEC; - boost::this_thread::sleep_for(boost::chrono::seconds(static_cast(std::ceil(cache_timeout * 3)))); - - // roll back base directory - bf::remove_all(basedir); - recursive_copy(backup.path() / "basedir", basedir); - - // expect reading now fails - EXPECT_FALSE(readingFileIsSuccessful(mountdir / "myfile")); - }); - - // Test it doesn't mount anymore now because it's marked with an integrity violation - EXPECT_RUN_ERROR(args, "There was an integrity violation detected. Preventing any further access to the file system.", ErrorCode::IntegrityViolationOnPreviousRun); -} - -} diff --git a/test/cryfs-cli/CliTest_Setup.cpp b/test/cryfs-cli/CliTest_Setup.cpp deleted file mode 100644 index a9457180..00000000 --- a/test/cryfs-cli/CliTest_Setup.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "testutils/CliTest.h" - -using cpputils::TempFile; -using cryfs::ErrorCode; - -namespace bf = boost::filesystem; - -//Tests that cryfs is correctly setup according to the CLI parameters specified -using CliTest_Setup = CliTest; - -TEST_F(CliTest_Setup, NoSpecialOptions) { - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS({basedir.string().c_str(), mountdir.string().c_str(), "--cipher", "aes-256-gcm", "-f"}, mountdir); -} - -TEST_F(CliTest_Setup, NotexistingLogfileGiven) { - TempFile notexisting_logfile(false); - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS({basedir.string().c_str(), mountdir.string().c_str(), "-f", "--cipher", "aes-256-gcm", "--logfile", notexisting_logfile.path().string().c_str()}, mountdir); - //TODO Expect logfile is used (check logfile content) -} - -TEST_F(CliTest_Setup, ExistingLogfileGiven) { - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS({basedir.string().c_str(), mountdir.string().c_str(), "-f", "--cipher", "aes-256-gcm", "--logfile", logfile.path().string().c_str()}, mountdir); - //TODO Expect logfile is used (check logfile content) -} - -TEST_F(CliTest_Setup, ConfigfileGiven) { - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS({basedir.string().c_str(), mountdir.string().c_str(), "-f", "--cipher", "aes-256-gcm", "--config", configfile.path().string().c_str()}, mountdir); -} - -TEST_F(CliTest_Setup, AutocreateBasedir) { - TempFile notexisting_basedir(false); - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS({notexisting_basedir.path().string().c_str(), mountdir.string().c_str(), "-f", "--cipher", "aes-256-gcm", "--create-missing-basedir"}, mountdir); -} - -TEST_F(CliTest_Setup, AutocreateBasedirFail) { - TempFile notexisting_basedir(false); - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_ERROR( - {notexisting_basedir.path().string().c_str(), mountdir.string().c_str(), "-f", "--cipher", "aes-256-gcm"}, - "Error 16: base directory not found.", - ErrorCode::InaccessibleBaseDir - ); -} - -TEST_F(CliTest_Setup, AutocreateMountpoint) { - TempFile notexisting_mountpoint(false); - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS({basedir.string().c_str(), notexisting_mountpoint.path().string().c_str(), "-f", "--cipher", "aes-256-gcm", "--create-missing-mountpoint"}, notexisting_mountpoint.path()); -} - -TEST_F(CliTest_Setup, AutocreateMountdirFail) { - TempFile notexisting_mountdir(false); - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_ERROR( - {basedir.string().c_str(), notexisting_mountdir.path().string().c_str(), "-f", "--cipher", "aes-256-gcm"}, - "Error 17: mount directory not found.", - ErrorCode::InaccessibleMountDir - ); -} - -TEST_F(CliTest_Setup, FuseOptionGiven) { - //Specify --cipher parameter to make it non-interactive - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - EXPECT_RUN_SUCCESS({basedir.string().c_str(), mountdir.string().c_str(), "-f", "--cipher", "aes-256-gcm", "--", "-f"}, mountdir); -} - -TEST_F(CliTest, WorksWithCommasInBasedir) { - // This test makes sure we don't regress on https://github.com/cryfs/cryfs/issues/326 - //TODO Remove "-f" parameter, once EXPECT_RUN_SUCCESS can handle that - auto basedir_ = basedir / "pathname,with,commas"; - bf::create_directory(basedir_); - EXPECT_RUN_SUCCESS({basedir_.string().c_str(), mountdir.string().c_str(), "-f"}, mountdir); -} diff --git a/test/cryfs-cli/CliTest_ShowingHelp.cpp b/test/cryfs-cli/CliTest_ShowingHelp.cpp deleted file mode 100644 index b25eef09..00000000 --- a/test/cryfs-cli/CliTest_ShowingHelp.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "testutils/CliTest.h" - -using CliTest_ShowingHelp = CliTest; - -using cryfs::ErrorCode; - -TEST_F(CliTest_ShowingHelp, HelpLongOption) { - EXPECT_EXIT_WITH_HELP_MESSAGE({"--help"}, "", ErrorCode::Success); -} - -TEST_F(CliTest_ShowingHelp, HelpLongOptionTogetherWithOtherOptions) { - EXPECT_EXIT_WITH_HELP_MESSAGE({basedir.string().c_str(), mountdir.string().c_str(), "--help"}, "", ErrorCode::Success); -} - -TEST_F(CliTest_ShowingHelp, HelpShortOption) { - EXPECT_EXIT_WITH_HELP_MESSAGE({"-h"}, "", ErrorCode::Success); -} - -TEST_F(CliTest_ShowingHelp, HelpShortOptionTogetherWithOtherOptions) { - EXPECT_EXIT_WITH_HELP_MESSAGE({basedir.string().c_str(), mountdir.string().c_str(), "-h"}, "", ErrorCode::Success); -} - -TEST_F(CliTest_ShowingHelp, MissingAllOptions) { - EXPECT_EXIT_WITH_HELP_MESSAGE({}, "Please specify a base directory", ErrorCode::InvalidArguments); -} - -TEST_F(CliTest_ShowingHelp, MissingDir) { - EXPECT_EXIT_WITH_HELP_MESSAGE({basedir.string().c_str()}, "Please specify a mount directory", ErrorCode::InvalidArguments); -} diff --git a/test/cryfs-cli/CliTest_WrongEnvironment.cpp b/test/cryfs-cli/CliTest_WrongEnvironment.cpp deleted file mode 100644 index 7fe5fd09..00000000 --- a/test/cryfs-cli/CliTest_WrongEnvironment.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "testutils/CliTest.h" - -#include - -namespace bf = boost::filesystem; -using ::testing::Values; -using ::testing::WithParamInterface; -using ::testing::Return; -using std::vector; -using cpputils::TempFile; -using cryfs::ErrorCode; - -struct TestConfig { - bool externalConfigfile; - bool logIsNotStderr; - bool runningInForeground; -}; - -//Tests what happens if cryfs is run in the wrong environment, i.e. with a base directory that doesn't exist or similar -class CliTest_WrongEnvironment: public CliTest, public WithParamInterface { -public: - void SetAllPermissions(const bf::path &dir) { - bf::permissions(dir, bf::owner_write|bf::owner_read|bf::owner_exe); - } - - void SetNoReadPermission(const bf::path &dir) { - bf::permissions(dir, bf::owner_write|bf::owner_exe); - } - - void SetNoWritePermission(const bf::path &dir) { - bf::permissions(dir, bf::owner_read|bf::owner_exe); - } - - void SetNoExePermission(const bf::path &dir) { - bf::permissions(dir, bf::owner_read|bf::owner_write); - } - - void SetNoPermission(const bf::path &dir) { - bf::permissions(dir, bf::no_perms); - } - - void Test_Run_Success() { - EXPECT_RUN_SUCCESS(args(), mountdir); - } - - void Test_Run_Error(const char *expectedError, cryfs::ErrorCode errorCode) { - EXPECT_RUN_ERROR( - args(), - expectedError, - errorCode - ); - } - - vector args() { - vector result = {basedir.string(), mountdir.string()}; - if (GetParam().externalConfigfile) { - result.push_back("--config"); - result.push_back(configfile.path().string()); - } - if (GetParam().logIsNotStderr) { - result.push_back("--logfile"); - result.push_back(logfile.path().string()); - } - if (GetParam().runningInForeground) { - result.push_back("-f"); - } - // Test case should be non-interactive, so don't ask for cipher. - result.push_back("--cipher"); - result.push_back("aes-256-gcm"); - return result; - } -}; - -INSTANTIATE_TEST_SUITE_P(DefaultParams, CliTest_WrongEnvironment, Values(TestConfig({false, false, false}))); -INSTANTIATE_TEST_SUITE_P(ExternalConfigfile, CliTest_WrongEnvironment, Values(TestConfig({true, false, false}))); -INSTANTIATE_TEST_SUITE_P(LogIsNotStderr, CliTest_WrongEnvironment, Values(TestConfig({false, true, false}))); -INSTANTIATE_TEST_SUITE_P(ExternalConfigfile_LogIsNotStderr, CliTest_WrongEnvironment, Values(TestConfig({true, true, false}))); -INSTANTIATE_TEST_SUITE_P(RunningInForeground, CliTest_WrongEnvironment, Values(TestConfig({false, false, true}))); -INSTANTIATE_TEST_SUITE_P(RunningInForeground_ExternalConfigfile, CliTest_WrongEnvironment, Values(TestConfig({true, false, true}))); -INSTANTIATE_TEST_SUITE_P(RunningInForeground_LogIsNotStderr, CliTest_WrongEnvironment, Values(TestConfig({false, true, true}))); -INSTANTIATE_TEST_SUITE_P(RunningInForeground_ExternalConfigfile_LogIsNotStderr, CliTest_WrongEnvironment, Values(TestConfig({true, true, true}))); - -//Counter-Test. Test that it doesn't fail if we call it without an error condition. -TEST_P(CliTest_WrongEnvironment, NoErrorCondition) { - if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS) - Test_Run_Success(); -} - -TEST_P(CliTest_WrongEnvironment, MountDirIsBaseDir) { - mountdir = basedir; - Test_Run_Error("Error 18: base directory can't be inside the mount directory", ErrorCode::BaseDirInsideMountDir); -} - -bf::path make_relative(const bf::path &path) { - bf::path result; - bf::path cwd = bf::current_path(); - for(auto iter = ++cwd.begin(); iter!=cwd.end(); ++iter) { - result /= ".."; - } - result /= path.relative_path(); - return result; -} - -TEST_P(CliTest_WrongEnvironment, MountDirIsBaseDir_MountDirRelative) { - mountdir = make_relative(basedir); - Test_Run_Error("Error 18: base directory can't be inside the mount directory", ErrorCode::BaseDirInsideMountDir); -} - -TEST_P(CliTest_WrongEnvironment, MountDirIsBaseDir_BaseDirRelative) { - mountdir = basedir; - basedir = make_relative(basedir); - Test_Run_Error("Error 18: base directory can't be inside the mount directory", ErrorCode::BaseDirInsideMountDir); -} - -TEST_P(CliTest_WrongEnvironment, MountDirIsBaseDir_BothRelative) { - basedir = make_relative(basedir); - mountdir = basedir; - Test_Run_Error("Error 18: base directory can't be inside the mount directory", ErrorCode::BaseDirInsideMountDir); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist) { - _basedir.remove(); - // ON_CALL and not EXPECT_CALL, because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents. - ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?", testing::_)).WillByDefault(Return(false)); - Test_Run_Error("Error 16: base directory not found", ErrorCode::InaccessibleBaseDir); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist_Noninteractive) { - _basedir.remove(); - // We can't set an EXPECT_CALL().Times(0), because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents. - // So we set a default answer that shouldn't crash and check it's not called by checking that it crashes. - ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?", testing::_)).WillByDefault(Return(true)); - cpputils::setenv("CRYFS_FRONTEND", "noninteractive"); - Test_Run_Error("Error 16: base directory not found", ErrorCode::InaccessibleBaseDir); - cpputils::unsetenv("CRYFS_FRONTEND"); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_DoesntExist_Create) { - if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS) - _basedir.remove(); - ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?", testing::_)).WillByDefault(Return(true)); - Test_Run_Success(); - EXPECT_TRUE(bf::exists(_basedir.path()) && bf::is_directory(_basedir.path())); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_IsNotDirectory) { - TempFile basedirfile; - basedir = basedirfile.path(); - Test_Run_Error("Error 16: base directory is not a directory", ErrorCode::InaccessibleBaseDir); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_AllPermissions) { - if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS) - //Counter-Test. Test it doesn't fail if permissions are there. - SetAllPermissions(basedir); - Test_Run_Success(); -} - -// boost::filesystem doesn't set permissions on Windows correctly -#if !defined(_MSC_VER) -TEST_P(CliTest_WrongEnvironment, BaseDir_NoReadPermission) { - SetNoReadPermission(basedir); - Test_Run_Error("Error 16: Could not read from base directory", ErrorCode::InaccessibleBaseDir); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_NoExePermission) { - SetNoExePermission(basedir); - Test_Run_Error("Error 16: Could not write to base directory", ErrorCode::InaccessibleBaseDir); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_NoWritePermission) { - SetNoWritePermission(basedir); - Test_Run_Error("Error 16: Could not write to base directory", ErrorCode::InaccessibleBaseDir); -} - -TEST_P(CliTest_WrongEnvironment, BaseDir_NoPermission) { - SetNoPermission(basedir); - Test_Run_Error("Error 16: Could not write to base directory", ErrorCode::InaccessibleBaseDir); -} -#endif - -TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist) { - _mountdir.remove(); - // ON_CALL and not EXPECT_CALL, because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents. - ON_CALL(*console, askYesNo("Could not find mount directory. Do you want to create it?", testing::_)).WillByDefault(Return(false)); - Test_Run_Error("mount directory not found", ErrorCode::InaccessibleMountDir); -} - -TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist_Noninteractive) { - _mountdir.remove(); - // We can't set an EXPECT_CALL().Times(0), because this is a death test (i.e. it is forked) and gmock EXPECT_CALL in fork children don't report to parents. - // So we set a default answer that shouldn't crash and check it's not called by checking that it crashes. - ON_CALL(*console, askYesNo("Could not find base directory. Do you want to create it?", testing::_)).WillByDefault(Return(true)); - cpputils::setenv("CRYFS_FRONTEND", "noninteractive"); - Test_Run_Error("mount directory not found", ErrorCode::InaccessibleMountDir); - cpputils::unsetenv("CRYFS_FRONTEND"); -} - -TEST_P(CliTest_WrongEnvironment, MountDir_DoesntExist_Create) { - if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS) - _mountdir.remove(); - ON_CALL(*console, askYesNo("Could not find mount directory. Do you want to create it?", testing::_)).WillByDefault(Return(true)); - Test_Run_Success(); - EXPECT_TRUE(bf::exists(_mountdir.path()) && bf::is_directory(_mountdir.path())); -} - -TEST_P(CliTest_WrongEnvironment, MountDir_IsNotDirectory) { - TempFile mountdirfile; - mountdir = mountdirfile.path(); - Test_Run_Error("Error 17: mount directory is not a directory", ErrorCode::InaccessibleMountDir); -} - -TEST_P(CliTest_WrongEnvironment, MountDir_AllPermissions) { - if (!GetParam().runningInForeground) {return;} // TODO Make this work also if run in background (see CliTest::EXPECT_RUN_SUCCESS) - //Counter-Test. Test it doesn't fail if permissions are there. - SetAllPermissions(mountdir); - Test_Run_Success(); -} - -// boost::filesystem doesn't set permissions on Windows correctly -#if !defined(_MSC_VER) -TEST_P(CliTest_WrongEnvironment, MountDir_NoReadPermission) { - SetNoReadPermission(mountdir); - Test_Run_Error("Error 17: Could not read from mount directory", ErrorCode::InaccessibleMountDir); -} - -TEST_P(CliTest_WrongEnvironment, MountDir_NoExePermission) { - SetNoExePermission(mountdir); - Test_Run_Error("Error 17: Could not write to mount directory", ErrorCode::InaccessibleMountDir); -} - -TEST_P(CliTest_WrongEnvironment, MountDir_NoWritePermission) { - SetNoWritePermission(mountdir); - Test_Run_Error("Error 17: Could not write to mount directory", ErrorCode::InaccessibleMountDir); -} - -TEST_P(CliTest_WrongEnvironment, MountDir_NoPermission) { - SetNoPermission(mountdir); - Test_Run_Error("Error 17: Could not write to mount directory", ErrorCode::InaccessibleMountDir); -} -#endif diff --git a/test/cryfs-cli/CryfsUnmountTest.cpp b/test/cryfs-cli/CryfsUnmountTest.cpp deleted file mode 100644 index 0857ec85..00000000 --- a/test/cryfs-cli/CryfsUnmountTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "testutils/CliTest.h" -#include -#include - -using CliTest_Unmount = CliTest; -namespace bf = boost::filesystem; - -namespace { -void unmount(const bf::path& mountdir) { - std::vector _args = {"cryfs-unmount", mountdir.string().c_str()}; - cryfs_unmount::Cli().main(2, _args.data()); -} - -TEST_F(CliTest_Unmount, givenMountedFilesystem_whenUnmounting_thenSucceeds) { - // we're passing in boost::none as mountdir so EXPECT_RUN_SUCCESS doesn't unmount itself. - // if the unmount we're calling here in the onMounted callback wouldn't work, EXPECT_RUN_SUCCESS - // would never return and this would be a deadlock. - EXPECT_RUN_SUCCESS({basedir.string().c_str(), mountdir.string().c_str(), "-f"}, boost::none, [this] () { - unmount(mountdir); - }); -} - -// TODO Test calling with invalid args, valid '--version' or '--help' args, with a non-mounted mountdir and a nonexisting mountdir. - -} diff --git a/test/cryfs-cli/EnvironmentTest.cpp b/test/cryfs-cli/EnvironmentTest.cpp deleted file mode 100644 index 017ce21e..00000000 --- a/test/cryfs-cli/EnvironmentTest.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include -#include -#include - -using namespace cryfs_cli; -using std::string; -using boost::optional; -using boost::none; - -#if defined(_MSC_VER) -constexpr const char* some_local_state_dir = "C:/my/local/state/dir"; -#else -constexpr const char* some_local_state_dir = "/my/local/state/dir"; -#endif - -namespace bf = boost::filesystem; - -class EnvironmentTest : public ::testing::Test { -public: - // WithEnv sets an environment variable while it is in scope. - // Once it leaves scope, the environment is reset. - class WithEnv { - public: - WithEnv(const string &key, const string &value): _key(key) , _oldValue(none) { - char *oldValue = std::getenv(key.c_str()); - if (nullptr != oldValue) { - _oldValue = string(oldValue); - } - cpputils::setenv(key.c_str(), value.c_str()); - } - ~WithEnv() { - if (none == _oldValue) { - cpputils::unsetenv(_key.c_str()); - } else { - cpputils::setenv(_key.c_str(), _oldValue->c_str()); - } - } - - private: - string _key; - optional _oldValue; - }; -}; - -TEST_F(EnvironmentTest, Noninteractive_Unset) { - EXPECT_FALSE(Environment::isNoninteractive()); -} - -TEST_F(EnvironmentTest, Noninteractive_Set) { - WithEnv env("CRYFS_FRONTEND", "noninteractive"); - EXPECT_TRUE(Environment::isNoninteractive()); -} - -TEST_F(EnvironmentTest, Noninteractive_SetToOtherValue) { - WithEnv env("CRYFS_FRONTEND", "someotherfrontend"); - EXPECT_FALSE(Environment::isNoninteractive()); -} - -TEST_F(EnvironmentTest, NoUpdateCheck_Unset) { - EXPECT_FALSE(Environment::noUpdateCheck()); -} - -TEST_F(EnvironmentTest, NoUpdateCheck_Set) { - WithEnv env("CRYFS_NO_UPDATE_CHECK", "true"); - EXPECT_TRUE(Environment::noUpdateCheck()); -} - -TEST_F(EnvironmentTest, NoUpdateCheck_SetToOtherValue) { - WithEnv env("CRYFS_NO_UPDATE_CHECK", "someothervalue"); - // No matter what the value is, setting the environment variable says we don't do update checks. - EXPECT_TRUE(Environment::noUpdateCheck()); -} - -TEST_F(EnvironmentTest, LocalStateDir_NotSet) { - EXPECT_EQ(Environment::defaultLocalStateDir(), Environment::localStateDir()); -} - -TEST_F(EnvironmentTest, LocalStateDir_Set) { - WithEnv env("CRYFS_LOCAL_STATE_DIR", some_local_state_dir); - EXPECT_EQ(some_local_state_dir, Environment::localStateDir().string()); -} - -TEST_F(EnvironmentTest, LocalStateDir_ConvertsRelativeToAbsolutePath_WithDot) { - WithEnv env("CRYFS_LOCAL_STATE_DIR", "./dir"); - EXPECT_EQ((bf::current_path() / "./dir").string(), Environment::localStateDir().string()); -} - -TEST_F(EnvironmentTest, LocalStateDir_ConvertsRelativeToAbsolutePath_WithoutDot) { - WithEnv env("CRYFS_LOCAL_STATE_DIR", "dir"); - EXPECT_EQ((bf::current_path() / "dir").string(), Environment::localStateDir().string()); -} diff --git a/test/cryfs-cli/VersionCheckerTest.cpp b/test/cryfs-cli/VersionCheckerTest.cpp deleted file mode 100644 index 90bb9190..00000000 --- a/test/cryfs-cli/VersionCheckerTest.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include -#include -#include - -using std::string; -using cpputils::FakeHttpClient; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using boost::none; -using namespace cryfs_cli; - -class VersionCheckerTest: public ::testing::Test { -public: - unique_ref versionChecker() { - return make_unique_ref(_http.get()); - } - - void setVersionInfo(const string &versionInfo) { - _http->addWebsite("https://www.cryfs.org/version_info.json", versionInfo); - } - -private: - unique_ref _http = make_unique_ref(); -}; - -TEST_F(VersionCheckerTest, NewestVersion_NoInternet) { - EXPECT_EQ(none, versionChecker()->newestVersion()); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_NoInternet) { - EXPECT_EQ(none, versionChecker()->securityWarningFor("0.8")); -} - -TEST_F(VersionCheckerTest, NewestVersion_NoWarnings_1) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"}}"); - EXPECT_EQ("0.8.2", versionChecker()->newestVersion().value()); -} - -TEST_F(VersionCheckerTest, NewestVersion_NoWarnings_2) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.3\"}}"); - EXPECT_EQ("0.8.3", versionChecker()->newestVersion().value()); -} - -TEST_F(VersionCheckerTest, NewestVersion_EmptyWarnings) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{}}"); - EXPECT_EQ("0.8.2", versionChecker()->newestVersion().value()); -} - -TEST_F(VersionCheckerTest, NewestVersion_WarningsOtherVersion) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{\"0.8.1\": \"warning\"}}"); - EXPECT_EQ("0.8.2", versionChecker()->newestVersion().value()); -} - -TEST_F(VersionCheckerTest, NewestVersion_WarningsSameVersion) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{\"0.8.2\": \"warning\"}}"); - EXPECT_EQ("0.8.2", versionChecker()->newestVersion().value()); -} - -TEST_F(VersionCheckerTest, NewestVersion_WarningsSameAndOtherVersion) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{\"0.8.1\": \"warning1\", \"0.8.2\": \"warning2\", \"0.8.3\": \"warning3\"}}"); - EXPECT_EQ("0.8.2", versionChecker()->newestVersion().value()); -} - -TEST_F(VersionCheckerTest, NewestVersion_BlankVersionInfo) { - setVersionInfo(""); - EXPECT_EQ(none, versionChecker()->newestVersion()); -} - -TEST_F(VersionCheckerTest, NewestVersion_EmptyVersionInfo) { - setVersionInfo("{}"); - EXPECT_EQ(none, versionChecker()->newestVersion()); -} - -TEST_F(VersionCheckerTest, NewestVersion_InvalidVersionInfo) { - setVersionInfo("invalid-json"); - EXPECT_EQ(none, versionChecker()->newestVersion()); -} - -TEST_F(VersionCheckerTest, NewestVersion_MissingKey) { - setVersionInfo("{\"warnings\":{}"); - EXPECT_EQ(none, versionChecker()->newestVersion()); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_NoWarnings) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"}}"); - EXPECT_EQ(none, versionChecker()->securityWarningFor("0.8.2")); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_EmptyWarnings) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{}}"); - EXPECT_EQ(none, versionChecker()->securityWarningFor("0.8.2")); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_WarningsOtherVersion) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{\"0.8.1\": \"warning\"}}"); - EXPECT_EQ(none, versionChecker()->securityWarningFor("0.8.2")); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_WarningsSameVersion) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{\"0.8.2\": \"warning\"}}"); - EXPECT_EQ("warning", versionChecker()->securityWarningFor("0.8.2").value()); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_WarningsSameAndOtherVersion) { - setVersionInfo("{\"version_info\":{\"current\":\"0.8.2\"},\"warnings\":{\"0.8.1\": \"warning1\", \"0.8.2\": \"warning2\", \"0.8.3\": \"warning3\"}}"); - EXPECT_EQ("warning2", versionChecker()->securityWarningFor("0.8.2").value()); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_BlankVersionInfo) { - setVersionInfo(""); - EXPECT_EQ(none, versionChecker()->securityWarningFor("0.8.2")); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_EmptyVersionInfo) { - setVersionInfo("{}"); - EXPECT_EQ(none, versionChecker()->securityWarningFor("0.8.2")); -} - -TEST_F(VersionCheckerTest, SecurityWarningFor_InvalidVersionInfo) { - setVersionInfo("invalid-json"); - EXPECT_EQ(none, versionChecker()->securityWarningFor("0.8.2")); -} diff --git a/test/cryfs-cli/program_options/ParserTest.cpp b/test/cryfs-cli/program_options/ParserTest.cpp deleted file mode 100644 index 245b9148..00000000 --- a/test/cryfs-cli/program_options/ParserTest.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include "testutils/ProgramOptionsTestBase.h" -#include -#include -#include -#include -#include -#include - -using namespace cryfs; -using namespace cryfs_cli::program_options; -using std::vector; -using std::string; -using boost::none; -namespace bf = boost::filesystem; -using cpputils::CaptureStderrRAII; - -#if !defined(_MSC_VER) -constexpr const char *basedir = "/home/user/baseDir"; -constexpr const char *mountdir = "/home/user/mountDir"; -constexpr const char *logfile = "/home/user/logfile"; -constexpr const char *configfile = "/home/user/configfile"; -#else -constexpr const char *basedir = "C:\\basedir"; -constexpr const char *mountdir = "C:\\mountdir"; -constexpr const char *logfile = "C:\\logfile"; -constexpr const char *configfile = "C:\\configfile"; -#endif - -class ProgramOptionsParserTest: public ProgramOptionsTestBase { -public: - ProgramOptions parse(std::initializer_list options) { - vector _options = options; - return Parser(_options.size(), _options.data()).parse(CryCiphers::supportedCipherNames()); - } -}; - -TEST_F(ProgramOptionsParserTest, MissingAllOptions) { - CaptureStderrRAII captureStderr; - try { - parse({"./myExecutable"}); - EXPECT_TRUE(false); // expect throws - } catch (const CryfsException& e) { - EXPECT_EQ(ErrorCode::InvalidArguments, e.errorCode()); - captureStderr.EXPECT_MATCHES("Usage:"); // expect show usage information - } -} - -TEST_F(ProgramOptionsParserTest, MissingDir) { - CaptureStderrRAII captureStderr; - try { - parse({"./myExecutable", basedir}); - EXPECT_TRUE(false); // expect throw - } catch (const CryfsException& e) { - EXPECT_EQ(ErrorCode::InvalidArguments, e.errorCode()); - captureStderr.EXPECT_MATCHES("Usage:"); // expect show usage information - } -} - -TEST_F(ProgramOptionsParserTest, HelpLongOption) { - CaptureStderrRAII captureStderr; - try { - parse({"./myExecutable", "--help"}); - EXPECT_TRUE(false); // expect throw - } catch (const CryfsException& e) { - EXPECT_EQ(ErrorCode::Success, e.errorCode()); - captureStderr.EXPECT_MATCHES("Usage:"); // expect show usage information - } -} - -TEST_F(ProgramOptionsParserTest, HelpShortOption) { - CaptureStderrRAII captureStderr; - try { - parse({"./myExecutable", "-h"}); - EXPECT_TRUE(false); // expect throw - } catch (const CryfsException& e) { - EXPECT_EQ(ErrorCode::Success, e.errorCode()); - captureStderr.EXPECT_MATCHES("Usage:"); // expect show usage information - } -} - -TEST_F(ProgramOptionsParserTest, ShowCiphers) { - CaptureStderrRAII captureStderr; - try { - parse({"./myExecutable", "--show-ciphers"}); - EXPECT_TRUE(false); // expect throw - } catch (const CryfsException& e) { - EXPECT_EQ(ErrorCode::Success, e.errorCode()); - captureStderr.EXPECT_MATCHES("aes-256-gcm"); // expect show ciphers - } -} - -TEST_F(ProgramOptionsParserTest, BaseDir_Absolute) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(basedir, options.baseDir()); -} - -TEST_F(ProgramOptionsParserTest, Basedir_Relative) { - ProgramOptions options = parse({"./myExecutable", "baseDir", mountdir}); - EXPECT_EQ(bf::current_path() / "baseDir", options.baseDir()); -} - -TEST_F(ProgramOptionsParserTest, MountDir_Absolute) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(mountdir, options.mountDir()); -} - -TEST_F(ProgramOptionsParserTest, MountDir_Relative) { - ProgramOptions options = parse({"./myExecutable", basedir, "mountDir"}); - EXPECT_EQ(bf::current_path() / "mountDir", options.mountDir()); -} - -TEST_F(ProgramOptionsParserTest, Foreground_False) { - ProgramOptions options = parse({"./myExecutable", basedir, "mountdir"}); - EXPECT_FALSE(options.foreground()); -} - -TEST_F(ProgramOptionsParserTest, Foreground_True) { - ProgramOptions options = parse({"./myExecutable", "-f", basedir, "mountdir"}); - EXPECT_TRUE(options.foreground()); -} - -TEST_F(ProgramOptionsParserTest, AllowFilesystemUpgrade_False) { - ProgramOptions options = parse({"./myExecutable", basedir, "mountdir"}); - EXPECT_FALSE(options.allowFilesystemUpgrade()); -} - -TEST_F(ProgramOptionsParserTest, AllowFilesystemUpgrade_True) { - ProgramOptions options = parse({"./myExecutable", "--allow-filesystem-upgrade", basedir, "mountdir"}); - EXPECT_TRUE(options.allowFilesystemUpgrade()); -} - -TEST_F(ProgramOptionsParserTest, CreateMissingBasedir_False) { - ProgramOptions options = parse({"./myExecutable", basedir, "mountdir"}); - EXPECT_FALSE(options.createMissingBasedir()); -} - -TEST_F(ProgramOptionsParserTest, CreateMissingBasedir_True) { - ProgramOptions options = parse({"./myExecutable", "--create-missing-basedir", basedir, "mountdir"}); - EXPECT_TRUE(options.createMissingBasedir()); -} - -TEST_F(ProgramOptionsParserTest, CreateMissingMountpoint_False) { - ProgramOptions options = parse({"./myExecutable", basedir, "mountdir"}); - EXPECT_FALSE(options.createMissingMountpoint()); -} - -TEST_F(ProgramOptionsParserTest, CreateMissingMountpoint_True) { - ProgramOptions options = parse({"./myExecutable", "--create-missing-mountpoint", basedir, "mountdir"}); - EXPECT_TRUE(options.createMissingMountpoint()); -} - -TEST_F(ProgramOptionsParserTest, LogfileGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, "--logfile", logfile, mountdir}); - EXPECT_EQ(logfile, options.logFile().value()); -} - -TEST_F(ProgramOptionsParserTest, LogfileGiven_RelativePath) { - ProgramOptions options = parse({"./myExecutable", basedir, "--logfile", "mylogfile", mountdir}); - EXPECT_EQ(bf::current_path() / "mylogfile", options.logFile().value()); -} - -TEST_F(ProgramOptionsParserTest, LogfileNotGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(none, options.logFile()); -} - -TEST_F(ProgramOptionsParserTest, ConfigfileGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, "--config", configfile, mountdir}); - EXPECT_EQ(configfile, options.configFile().value()); -} - -TEST_F(ProgramOptionsParserTest, ConfigfileGiven_RelativePath) { - ProgramOptions options = parse({"./myExecutable", basedir, "--config", "myconfigfile", mountdir}); - EXPECT_EQ(bf::current_path() / "myconfigfile", options.configFile().value()); -} - -TEST_F(ProgramOptionsParserTest, ConfigfileNotGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(none, options.configFile()); -} - -TEST_F(ProgramOptionsParserTest, CipherGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, "--cipher", "aes-256-gcm", mountdir}); - EXPECT_EQ("aes-256-gcm", options.cipher().value()); -} - -TEST_F(ProgramOptionsParserTest, CipherNotGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(none, options.cipher()); -} - -TEST_F(ProgramOptionsParserTest, InvalidCipher) { - try { - parse({"./myExecutable", basedir, "--cipher", "invalid-cipher", mountdir}); - EXPECT_TRUE(false); // expect throw - } catch (const CryfsException& e) { - EXPECT_EQ(ErrorCode::InvalidArguments, e.errorCode()); - EXPECT_THAT(e.what(), testing::MatchesRegex(".*Invalid cipher: invalid-cipher.*")); - } -} - -TEST_F(ProgramOptionsParserTest, UnmountAfterIdleMinutesGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, "--unmount-idle", "10", mountdir}); - EXPECT_EQ(10, options.unmountAfterIdleMinutes().value()); -} - -TEST_F(ProgramOptionsParserTest, UnmountAfterIdleMinutesGiven_Float) { - ProgramOptions options = parse({"./myExecutable", basedir, "--unmount-idle", "0.5", mountdir}); - EXPECT_EQ(0.5, options.unmountAfterIdleMinutes().value()); -} - -TEST_F(ProgramOptionsParserTest, UnmountAfterIdleMinutesNotGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(none, options.unmountAfterIdleMinutes()); -} - -TEST_F(ProgramOptionsParserTest, BlocksizeGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, "--blocksize", "10240", mountdir}); - EXPECT_EQ(10240u, options.blocksizeBytes().value()); -} - -TEST_F(ProgramOptionsParserTest, BlocksizeNotGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(none, options.blocksizeBytes()); -} - -TEST_F(ProgramOptionsParserTest, MissingBlockIsIntegrityViolationGiven_True) { - ProgramOptions options = parse({"./myExecutable", basedir, "--missing-block-is-integrity-violation", "true", mountdir}); - EXPECT_TRUE(options.missingBlockIsIntegrityViolation().value()); -} - -TEST_F(ProgramOptionsParserTest, MissingBlockIsIntegrityViolationGiven_False) { - ProgramOptions options = parse({"./myExecutable", basedir, "--missing-block-is-integrity-violation", "false", mountdir}); - EXPECT_FALSE(options.missingBlockIsIntegrityViolation().value()); -} - -TEST_F(ProgramOptionsParserTest, AllowIntegrityViolations_True) { - ProgramOptions options = parse({"./myExecutable", basedir, "--allow-integrity-violations", mountdir}); - EXPECT_TRUE(options.allowIntegrityViolations()); -} - -TEST_F(ProgramOptionsParserTest, AllowIntegrityViolations_False) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_FALSE(options.allowIntegrityViolations()); -} - -TEST_F(ProgramOptionsParserTest, MissingBlockIsIntegrityViolationNotGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(none, options.missingBlockIsIntegrityViolation()); -} - -TEST_F(ProgramOptionsParserTest, FuseOptionGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir, "--", "-f"}); - EXPECT_EQ(basedir, options.baseDir()); - EXPECT_EQ(mountdir, options.mountDir()); - EXPECT_VECTOR_EQ({"-f"}, options.fuseOptions()); -} - -TEST_F(ProgramOptionsParserTest, FuseOptionGiven_Empty) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir, "--"}); - EXPECT_EQ(basedir, options.baseDir()); - EXPECT_EQ(mountdir, options.mountDir()); - EXPECT_VECTOR_EQ({}, options.fuseOptions()); -} - -TEST_F(ProgramOptionsParserTest, FuseOptionNotGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir}); - EXPECT_EQ(basedir, options.baseDir()); - EXPECT_EQ(mountdir, options.mountDir()); - EXPECT_VECTOR_EQ({}, options.fuseOptions()); -} - -TEST_F(ProgramOptionsParserTest, DirectFuseOptionsGiven_AfterPositionalOptions) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir, "-o", "my_opt"}); - EXPECT_VECTOR_EQ({"-o", "my_opt"}, options.fuseOptions()); -} - -TEST_F(ProgramOptionsParserTest, DirectFuseOptionsGiven_BeforePositionalOptions) { - ProgramOptions options = parse({"./myExecutable", "-o", "my_opt", basedir, mountdir}); - EXPECT_VECTOR_EQ({"-o", "my_opt"}, options.fuseOptions()); -} - -TEST_F(ProgramOptionsParserTest, DirectFuseOptionsGiven_BeforeAndAfterPositionalOptions) { - ProgramOptions options = parse({"./myExecutable", "-o", "first", "-o", "second", basedir, "-o", "third", "-o", "fourth", mountdir, "-o", "fifth", "-o", "sixth"}); - EXPECT_VECTOR_EQ({"-o", "first", "-o", "second", "-o", "third", "-o", "fourth", "-o", "fifth", "-o", "sixth"}, options.fuseOptions()); -} - -TEST_F(ProgramOptionsParserTest, DirectAndIndirectFuseOptionsGiven) { - ProgramOptions options = parse({"./myExecutable", basedir, mountdir, "-o", "my_opt", "--", "-o", "other_opt"}); - EXPECT_VECTOR_EQ({"-o", "other_opt", "-o", "my_opt"}, options.fuseOptions()); -} diff --git a/test/cryfs-cli/program_options/ProgramOptionsTest.cpp b/test/cryfs-cli/program_options/ProgramOptionsTest.cpp deleted file mode 100644 index 6c96dce7..00000000 --- a/test/cryfs-cli/program_options/ProgramOptionsTest.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "testutils/ProgramOptionsTestBase.h" -#include -#include - -using namespace cryfs_cli::program_options; -using boost::none; -using boost::optional; -using std::ostream; -using std::string; -namespace bf = boost::filesystem; - -// This is needed for google test to work with boost::optional -namespace boost { - template<> inline ostream& operator<< , bf::path>(ostream &stream, const optional &path) { - if (path == none) { - return stream << "none"; - } - return stream << *path; - } -} - -class ProgramOptionsTest: public ProgramOptionsTestBase {}; - -TEST_F(ProgramOptionsTest, BaseDir) { - ProgramOptions testobj("/home/user/mydir", "", none, false, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ("/home/user/mydir", testobj.baseDir()); -} - -TEST_F(ProgramOptionsTest, MountDir) { - ProgramOptions testobj("", "/home/user/mydir", none, false, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ("/home/user/mydir", testobj.mountDir()); -} - -TEST_F(ProgramOptionsTest, ConfigfileNone) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ(none, testobj.configFile()); -} - -TEST_F(ProgramOptionsTest, ConfigfileSome) { - ProgramOptions testobj("", "", bf::path("/home/user/configfile"), true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ("/home/user/configfile", testobj.configFile().get()); -} - -TEST_F(ProgramOptionsTest, ForegroundFalse) { - ProgramOptions testobj("", "", none, false, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_FALSE(testobj.foreground()); -} - -TEST_F(ProgramOptionsTest, ForegroundTrue) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_TRUE(testobj.foreground()); -} - -TEST_F(ProgramOptionsTest, AllowFilesystemUpgradeFalse) { - ProgramOptions testobj("", "", none, false, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_FALSE(testobj.allowFilesystemUpgrade()); -} - -TEST_F(ProgramOptionsTest, AllowFilesystemUpgradeTrue) { - ProgramOptions testobj("", "", none, false, true, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_TRUE(testobj.allowFilesystemUpgrade()); -} - -TEST_F(ProgramOptionsTest, CreateMissingBasedirFalse) { - ProgramOptions testobj("", "", none, false, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_FALSE(testobj.createMissingBasedir()); -} - -TEST_F(ProgramOptionsTest, CreateMissingBasedirTrue) { - ProgramOptions testobj("", "", none, false, true, false, true, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_TRUE(testobj.createMissingBasedir()); -} - -TEST_F(ProgramOptionsTest, CreateMissingMountpointFalse) { - ProgramOptions testobj("", "", none, false, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_FALSE(testobj.createMissingMountpoint()); -} - -TEST_F(ProgramOptionsTest, CreateMissingMountpointTrue) { - ProgramOptions testobj("", "", none, false, true, false, false, true, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_TRUE(testobj.createMissingMountpoint()); -} - -TEST_F(ProgramOptionsTest, LogfileNone) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ(none, testobj.logFile()); -} - -TEST_F(ProgramOptionsTest, LogfileSome) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, bf::path("logfile"), none, none, false, none, {"./myExecutable"}); - EXPECT_EQ("logfile", testobj.logFile().get()); -} - -TEST_F(ProgramOptionsTest, UnmountAfterIdleMinutesNone) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ(none, testobj.unmountAfterIdleMinutes()); -} - -TEST_F(ProgramOptionsTest, UnmountAfterIdleMinutesSome) { - ProgramOptions testobj("", "", none, true, false, false, false, false, 10, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ(10, testobj.unmountAfterIdleMinutes().get()); -} - -TEST_F(ProgramOptionsTest, CipherNone) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ(none, testobj.cipher()); -} - -TEST_F(ProgramOptionsTest, CipherSome) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, string("aes-256-gcm"), none, false, none, {"./myExecutable"}); - EXPECT_EQ("aes-256-gcm", testobj.cipher().get()); -} - -TEST_F(ProgramOptionsTest, BlocksizeBytesNone) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ(none, testobj.blocksizeBytes()); -} - -TEST_F(ProgramOptionsTest, BlocksizeBytesSome) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, 10*1024, false, none, {"./myExecutable"}); - EXPECT_EQ(10*1024u, testobj.blocksizeBytes().get()); -} - -TEST_F(ProgramOptionsTest, MissingBlockIsIntegrityViolationTrue) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, true, {"./myExecutable"}); - EXPECT_TRUE(testobj.missingBlockIsIntegrityViolation().value()); -} - -TEST_F(ProgramOptionsTest, MissingBlockIsIntegrityViolationFalse) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, false, {"./myExecutable"}); - EXPECT_FALSE(testobj.missingBlockIsIntegrityViolation().value()); -} - -TEST_F(ProgramOptionsTest, MissingBlockIsIntegrityViolationNone) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_EQ(none, testobj.missingBlockIsIntegrityViolation()); -} - -TEST_F(ProgramOptionsTest, AllowIntegrityViolationsFalse) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, false, none, {"./myExecutable"}); - EXPECT_FALSE(testobj.allowIntegrityViolations()); -} - -TEST_F(ProgramOptionsTest, AllowIntegrityViolationsTrue) { - ProgramOptions testobj("", "", none, true, false, false, false, false, none, none, none, none, true, none, {"./myExecutable"}); - EXPECT_TRUE(testobj.allowIntegrityViolations()); -} - -TEST_F(ProgramOptionsTest, EmptyFuseOptions) { - ProgramOptions testobj("/rootDir", "/home/user/mydir", none, false, false, false, false, false, none, none, none, none, false, none, {}); - //Fuse should have the mount dir as first parameter - EXPECT_VECTOR_EQ({}, testobj.fuseOptions()); -} - -TEST_F(ProgramOptionsTest, SomeFuseOptions) { - ProgramOptions testobj("/rootDir", "/home/user/mydir", none, false, false, false, false, false, none, none, none, none, false, none, {"-f", "--longoption"}); - //Fuse should have the mount dir as first parameter - EXPECT_VECTOR_EQ({"-f", "--longoption"}, testobj.fuseOptions()); -} diff --git a/test/cryfs-cli/program_options/UtilsTest.cpp b/test/cryfs-cli/program_options/UtilsTest.cpp deleted file mode 100644 index b6fe53ed..00000000 --- a/test/cryfs-cli/program_options/UtilsTest.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "testutils/ProgramOptionsTestBase.h" -#include - -using namespace cryfs_cli::program_options; -using std::pair; -using std::vector; -using std::string; - -class ProgramOptionsUtilsTest: public ProgramOptionsTestBase {}; - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_ZeroOptions) { - vector input = {"./executableName"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName"}, result.first); - EXPECT_VECTOR_EQ({}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneShortOption) { - vector input = {"./executableName", "-j"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "-j"}, result.first); - EXPECT_VECTOR_EQ({}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneLongOption) { - vector input = {"./executableName", "--myoption"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "--myoption"}, result.first); - EXPECT_VECTOR_EQ({}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OnePositionalOption) { - vector input = {"./executableName", "mypositionaloption"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption"}, result.first); - EXPECT_VECTOR_EQ({}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneShortOption_DoubleDash) { - vector input = {"./executableName", "-j", "--"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "-j"}, result.first); - EXPECT_VECTOR_EQ({}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneLongOption_DoubleDash) { - vector input = {"./executableName", "--myoption", "--"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "--myoption"}, result.first); - EXPECT_VECTOR_EQ({}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OnePositionalOption_DoubleDash) { - vector input = {"./executableName", "mypositionaloption", "--"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption"}, result.first); - EXPECT_VECTOR_EQ({}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_DoubleDash_OneShortOption) { - vector input = {"./executableName", "--", "-a"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName"}, result.first); - EXPECT_VECTOR_EQ({"-a"}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_DoubleDash_OneLongOption) { - vector input = {"./executableName", "--", "--myoption"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName"}, result.first); - EXPECT_VECTOR_EQ({"--myoption"}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_DoubleDash_OnePositionalOption) { - vector input = {"./executableName", "--", "mypositionaloption"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName"}, result.first); - EXPECT_VECTOR_EQ({"mypositionaloption"}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneShortOption_DoubleDash_OneShortOption) { - vector input = {"./executableName", "-j", "--", "-a"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "-j"}, result.first); - EXPECT_VECTOR_EQ({"-a"}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OneLongOption_DoubleDash_OneLongOption) { - vector input = {"./executableName", "--myoption", "--", "--myotheroption"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "--myoption"}, result.first); - EXPECT_VECTOR_EQ({"--myotheroption"}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_OnePositionalOption_DoubleDash_OnePositionalOption) { - vector input = {"./executableName", "mypositionaloption", "--", "otherpositionaloption"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption"}, result.first); - EXPECT_VECTOR_EQ({"otherpositionaloption"}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_MoreOptions) { - vector input = {"./executableName", "mypositionaloption", "myotherpositionaloption", "-j", "--alpha", "--", "filename", "--beta", "-j3"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "mypositionaloption", "myotherpositionaloption", "-j", "--alpha"}, result.first); - EXPECT_VECTOR_EQ({"filename", "--beta", "-j3"}, result.second); -} - -TEST_F(ProgramOptionsUtilsTest, SplitAtDoubleDash_RealisticCryfsOptions) { - vector input = {"./executableName", "rootDir", "mountDir", "--", "-f"}; - pair,vector> result = splitAtDoubleDash(input); - EXPECT_VECTOR_EQ({"./executableName", "rootDir", "mountDir"}, result.first); - EXPECT_VECTOR_EQ({"-f"}, result.second); -} diff --git a/test/cryfs-cli/program_options/testutils/ProgramOptionsTestBase.h b/test/cryfs-cli/program_options/testutils/ProgramOptionsTestBase.h deleted file mode 100644 index 9526a76d..00000000 --- a/test/cryfs-cli/program_options/testutils/ProgramOptionsTestBase.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#ifndef MESSMER_CRYFS_TEST_PROGRAMOPTIONS_PROGRAMOPTIONSTEST_H -#define MESSMER_CRYFS_TEST_PROGRAMOPTIONS_PROGRAMOPTIONSTEST_H - -#include - -class ProgramOptionsTestBase: public ::testing::Test { -public: - - void EXPECT_VECTOR_EQ(std::initializer_list expected, const std::vector &actual) { - std::vector expectedVec(expected); - ASSERT_EQ(expectedVec.size(), actual.size()); - for(size_t i = 0; i < expectedVec.size(); ++i) { - EXPECT_EQ(expectedVec[i], actual[i]); - } - } -}; - -#endif diff --git a/test/cryfs-cli/testutils/CliTest.cpp b/test/cryfs-cli/testutils/CliTest.cpp deleted file mode 100644 index 1dd63f3b..00000000 --- a/test/cryfs-cli/testutils/CliTest.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CliTest.h" diff --git a/test/cryfs-cli/testutils/CliTest.h b/test/cryfs-cli/testutils/CliTest.h deleted file mode 100644 index 6ec7f374..00000000 --- a/test/cryfs-cli/testutils/CliTest.h +++ /dev/null @@ -1,168 +0,0 @@ -#pragma once -#ifndef MESSMER_CRYFS_TEST_CLI_TESTUTILS_CLITEST_H -#define MESSMER_CRYFS_TEST_CLI_TESTUTILS_CLITEST_H - -#if defined(_MSC_VER) -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../cryfs/impl/testutils/MockConsole.h" -#include "../../cryfs/impl/testutils/TestWithFakeHomeDirectory.h" -#include -#include -#include -#include -#include - -class CliTest : public ::testing::Test, TestWithFakeHomeDirectory { -public: - CliTest(): _basedir(), _mountdir(), basedir(_basedir.path()), mountdir(_mountdir.path()), logfile(), configfile(false), console(std::make_shared()) {} - - cpputils::TempDir _basedir; - cpputils::TempDir _mountdir; - boost::filesystem::path basedir; - boost::filesystem::path mountdir; - cpputils::TempFile logfile; - cpputils::TempFile configfile; - std::shared_ptr console; - - cpputils::unique_ref _httpClient() { - cpputils::unique_ref httpClient = cpputils::make_unique_ref(); - httpClient->addWebsite("https://www.cryfs.org/version_info.json", "{\"version_info\":{\"current\":\"0.8.5\"}}"); - return httpClient; - } - - int run(const std::vector& args, std::function onMounted) { - std::vector _args; - _args.reserve(args.size() + 1); - _args.emplace_back("cryfs"); - for (const std::string& arg : args) { - _args.emplace_back(arg.c_str()); - } - auto &keyGenerator = cpputils::Random::PseudoRandom(); - ON_CALL(*console, askPassword(testing::StrEq("Password: "))).WillByDefault(testing::Return("pass")); - ON_CALL(*console, askPassword(testing::StrEq("Confirm Password: "))).WillByDefault(testing::Return("pass")); - // Run Cryfs - return cryfs_cli::Cli(keyGenerator, cpputils::SCrypt::TestSettings, console).main(_args.size(), _args.data(), _httpClient(), std::move(onMounted)); - } - - void EXPECT_EXIT_WITH_HELP_MESSAGE(const std::vector& args, const std::string &message, cryfs::ErrorCode errorCode) { - EXPECT_RUN_ERROR(args, "Usage:[^\\x00]*"+message, errorCode); - } - - void EXPECT_RUN_ERROR(const std::vector& args, const std::string& message, cryfs::ErrorCode errorCode, std::function onMounted = [] {}) { - FilesystemOutput filesystem_output = run_filesystem(args, boost::none, std::move(onMounted)); - - EXPECT_EQ(exitCode(errorCode), filesystem_output.exit_code); - if (!std::regex_search(filesystem_output.stderr_, std::regex(message))) { - std::cerr << filesystem_output.stderr_ << std::endl; - EXPECT_TRUE(false); - } - } - - void EXPECT_RUN_SUCCESS(const std::vector& args, const boost::optional &mountDir, std::function onMounted = [] {}) { - //TODO Make this work when run in background - ASSERT(std::find(args.begin(), args.end(), string("-f")) != args.end(), "Currently only works if run in foreground"); - - bool successfully_mounted = false; - - FilesystemOutput filesystem_output = run_filesystem(args, mountDir, [&] { - successfully_mounted = true; - onMounted(); - }); - - EXPECT_EQ(0, filesystem_output.exit_code); - if (!std::regex_search(filesystem_output.stdout_, std::regex("Mounting filesystem"))) { - std::cerr << "STDOUT:\n" << filesystem_output.stdout_ << "STDERR:\n" << filesystem_output.stderr_ << std::endl; - EXPECT_TRUE(false) << "Filesystem did not output the 'Mounting filesystem' message, probably wasn't successfully mounted."; - } - - if (!successfully_mounted) { - EXPECT_TRUE(false) << "Filesystem did not call onMounted callback, probably wasn't successfully mounted."; - } - } - - struct FilesystemOutput final { - int exit_code; - std::string stdout_; - std::string stderr_; - }; - - static void _unmount(const boost::filesystem::path &mountDir) { - fspp::fuse::Fuse::unmount(mountDir, true); - } - - FilesystemOutput run_filesystem(const std::vector& args, boost::optional mountDirForUnmounting, std::function onMounted) { - testing::internal::CaptureStdout(); - testing::internal::CaptureStderr(); - - bool exited = false; - cpputils::ConditionBarrier isMountedOrFailedBarrier; - - std::future exit_code = std::async(std::launch::async, [&] { - int exit_code = run(args, [&] { isMountedOrFailedBarrier.release(); }); - // just in case it fails, we also want to release the barrier. - // if it succeeds, this will release it a second time, which doesn't hurt. - exited = true; - isMountedOrFailedBarrier.release(); - return exit_code; - }); - - std::future on_mounted_success = std::async(std::launch::async, [&] { - isMountedOrFailedBarrier.wait(); - if (exited) { - // file system already exited on its own, this indicates an error. It should have stayed mounted. - // while the exit_code from run() will signal an error in this case, we didn't encounter another - // error in the onMounted future, so return true here. - return true; - } - // now we know the filesystem stayed online, so we can call the onMounted callback - onMounted(); - // and unmount it afterwards - if (mountDirForUnmounting.is_initialized()) { - _unmount(*mountDirForUnmounting); - } - return true; - }); - - if(std::future_status::ready != on_mounted_success.wait_for(std::chrono::seconds(1000))) { - testing::internal::GetCapturedStdout(); // stop capturing stdout - testing::internal::GetCapturedStderr(); // stop capturing stderr - - std::cerr << "onMounted thread (e.g. used for unmount) didn't finish" << std::endl; - // The std::future destructor of a future created with std::async blocks until the future is ready. - // so, instead of causing a deadlock, rather abort - exit(EXIT_FAILURE); - } - EXPECT_TRUE(on_mounted_success.get()); // this also re-throws any potential exceptions - - if(std::future_status::ready != exit_code.wait_for(std::chrono::seconds(1000))) { - testing::internal::GetCapturedStdout(); // stop capturing stdout - testing::internal::GetCapturedStderr(); // stop capturing stderr - - std::cerr << "Filesystem thread didn't finish" << std::endl; - // The std::future destructor of a future created with std::async blocks until the future is ready. - // so, instead of causing a deadlock, rather abort - exit(EXIT_FAILURE); - } - - return { - exit_code.get(), // this also re-throws any potential exceptions - testing::internal::GetCapturedStdout(), - testing::internal::GetCapturedStderr() - }; - } -}; - -#endif diff --git a/test/cryfs/CMakeLists.txt b/test/cryfs/CMakeLists.txt deleted file mode 100644 index eb13b273..00000000 --- a/test/cryfs/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -project (cryfs-test) - -set(SOURCES - impl/config/crypto/CryConfigEncryptorFactoryTest.cpp - impl/config/crypto/outer/OuterConfigTest.cpp - impl/config/crypto/outer/OuterEncryptorTest.cpp - impl/config/crypto/inner/ConcreteInnerEncryptorTest.cpp - impl/config/crypto/inner/InnerConfigTest.cpp - impl/config/crypto/CryConfigEncryptorTest.cpp - impl/config/CompatibilityTest.cpp - impl/config/CryConfigCreatorTest.cpp - impl/config/CryConfigFileTest.cpp - impl/config/CryConfigTest.cpp - impl/config/CryCipherTest.cpp - impl/config/CryConfigLoaderTest.cpp - impl/config/CryConfigConsoleTest.cpp - impl/config/CryPasswordBasedKeyProviderTest.cpp - impl/config/CryPresetPasswordBasedKeyProviderTest.cpp - impl/filesystem/CryFsTest.cpp - impl/filesystem/CryNodeTest.cpp - impl/filesystem/FileSystemTest.cpp - impl/localstate/LocalStateMetadataTest.cpp - impl/localstate/BasedirMetadataTest.cpp -) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest cryfs) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/cryfs/impl/config/CompatibilityTest.cpp b/test/cryfs/impl/config/CompatibilityTest.cpp deleted file mode 100644 index 07b931b3..00000000 --- a/test/cryfs/impl/config/CompatibilityTest.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../impl/testutils/MockConsole.h" - -using cpputils::Data; -using cpputils::AES256_GCM; -using cpputils::Serpent128_CFB; -using cpputils::TempFile; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::SCrypt; - -using namespace cryfs; - -// Test that config files created with (old) versions of cryfs are still loadable. -// The config files created with these cryfs versions are included in the test cases in hex code. -// To make tests run fast, the config files should be created using SCrypt::TestSettings. -class CryConfigCompatibilityTest: public ::testing::Test { -public: - TempFile file; - - unique_ref loadConfigFromHex(const string &configFileContentHex) { - storeHexToFile(configFileContentHex); - CryPresetPasswordBasedKeyProvider keyProvider("mypassword", make_unique_ref(SCrypt::DefaultSettings)); - return CryConfigFile::load(file.path(), &keyProvider, CryConfigFile::Access::ReadWrite).right(); - } - -private: - - void storeHexToFile(const string &hex) { - hexToBinary(hex).StoreToFile(file.path()); - } - - Data hexToBinary(const string &hex) { - ASSERT(hex.size()%2 == 0, "Hex codes need to have two characters per byte"); - Data result(hex.size()/2); - { - CryptoPP::StringSource _1(hex, true, - new CryptoPP::HexDecoder( - new CryptoPP::ArraySink(static_cast(result.data()), result.size()) - ) - ); - } - return result; - } - -}; - - -#ifndef CRYFS_NO_COMPATIBILITY - -TEST_F(CryConfigCompatibilityTest, v0_8_1_with_aes_256_gcm) { - auto config = loadConfigFromHex("63727966732e636f6e6669673b303b736372797074000004000000000000010000000100000020000000000000000af023e55f804ad303c1dbdf6a2b2bed8cc1ab3d0b2f3312c073628dc041e6f3b92f54fad63a1d4e0ad47a33e65e08080dd4e5bdec0a95fe777705ad68e88eabcb4b91d4f25c32e3e44d6e893421c9efa6d4b2c56d66d0546a410de489b04160b276184ebe7dd77840ce6e414f829bb4399451e055d3406261b4faf5fb52f27e21823f8073df255f96b37edf2c2e58ecee21ae82e3883341024aff326cc4c0929f0ed90473511cbe801d1e34899b3cdb9556477be0127c35375967bf7c8392ad4d30d81479c7923900f532b195b71cff868fa1643d1f9e0a0d7996260691d7b5b8ef3c319c2f2303f822eac389e1d6822e7ee57df60c922fa10fbc7e5970e723df2fdb2a6529c94ea1d2507f55cb9bc3fecab77bf3102e96c6675a618b54bb18e632dd99d3d47fa9e24392535abc8c76f891df76c2193233d6c93851966f69def3f53108be83b30980c98e377186da71297a1b61df76e9f138a3998577a0c486452f1b6a2d89b1e62d78695ac6a062d5a4cf5972de7bc2775fd27d25337f0666250f19d6fe50fe762371befa26de6a9299d7df362780f59ccc475e28c71cc5af9e817e4e2160005393ec7fb385d467e0915e7169934ea986141101c9e6b9c62b8819c51a4422e7fe58e24c3293c3f12173a4c480334cb67c9313df667c65802fb778e20f5a4d6cfd07fffb35c2ae8fdf235882bf0e6371125509872e73bd1bc3faca72948db76d8179e08bf3391bafdede591d5623240ba072ada17c2444116bf8c08ee32367eb86eda02ecfecc625b4bc974428b8f5024df430c352b9849f48774bac1455e7364f7660abc039d2a1134cde596a1e7c3a1a8d68591e8640a2d308e2ea5f03874ba1fa8e9ffec2d1bc1541d124adcd3e9f4ed23343e2148629317e6304c63c2a5ceeeb572246393c8e50196728e0b604aa9e2d49e65680cc53ee343645412239f82500ef3d70a6b6e3335ef8cbcfe4fd46b84f634f6fe96cd1b79207a2120ac2bad668bcdbc377b98448c9afbbda9fe8164dbb48aaa68b0aaa90e52bc419ea2ea1f5e12bb649831af12f1ef14765f312640e22c5508531bd46e3ab3a7f922a91fb83332104609e385d61d3778bc5acb03bee522ea5b791d27026fd589ec2b32f04caaf2ef2effbd50e12430ef42631fdabd061966fde1489b9a1eff3fe40b295d75e36af19ae0e69559b9c81b3bc47b35fef5c7038b83db6729aac522efee897a44895804ffbeb11317a78586f8a3511905514eee86d7cf0a395f5f0af521c72542e544ff359a69150a5e64f00b020d48c20d5716331c3b0ac314eeceaadf8b73516b4273b48046b5c3a3980bade0cc25baf54afb27755d155d4b94fa556deb30d58b1d920cbe01b13479135ff84d6a9345a0d418075ecc66bd10d8d2a07963450256897018f54b2a88fffe9383913565823dbfb71568f5d9af93e542937ecde25c2d4407ad964ece5c09a1f81a57c18a8bb2aa8d9d062415903c98752d70ad7175d0d30b391da77459e9a68a69825b3bb4061bc2504789fc395"); - EXPECT_EQ(AES256_GCM::NAME, config->config()->Cipher()); - EXPECT_EQ("4A70AD8AC565A5123586D0928B496465", config->config()->RootBlob()); -} - -TEST_F(CryConfigCompatibilityTest, v0_8_1_with_serpent_128_cfb) { - auto config = loadConfigFromHex("63727966732e636f6e6669673b303b736372797074000004000000000000010000000100000020000000000000006496611b94011d03433181e83e80c19888a5607392c2117cd377251978fbbf8d46716bd90dbae3c1728b40e7dc086ee97b8a641f1ea6cc31ccda9a1e4a7a1bf4b6ca3d1d0075acba94017c034e87dfad048c9448df24ea7b89b14d60c9f9e0162cfeb420a85759aaa011232cff99e81b25c456cb13690d5cc735e61ef9b01800961a90488073c5320c14a562f0eccd32383d144476d72d9c61733fb3561f5187c2d6069ce7ff4c43df4fc3f7c1d63df239d05a2b377f70816fb31f7a65d8fa667cd14b62a67e2d67adbf841860af2abed9d4c839c510c7fac7cd58210238830a4926917d663500dd3dc2395845297b3726c00228cb08a2bde648d2e9bc2a3e8655f86bc2f5c2b327e71c75b92894dd43b56dfefeeea598fbae9782dca64cc9676df3a954a9ecedbe3f8fe16e790aeec2ac2336984c8fcce74bfebf310d6fdcc0882ee7f2bdd32928aa53b09084e8035ec235ebe971a0b141e5fcab6ce2207f0f399e683ff4994ed638194cc7d3891019a2a674d14180114494e21270e4234a51e28661d4ac908d4f2b2d7c94ffcb74df8c9f08fb68d9a7167a05fae370e041689cce5fb13fdf3ff14863f6c882e6d302eafe5348362c026853a3717756cefb4657a721efab95f6d949b508a98de86885fe37b2f16f1792411ff47c1074e2c2d301e6401f251854b28c329040c8e55184402648bc79710536390b0f99acd2400734a81e8bd573d9a96971a5ef195d85babbe1092e271a69a146d2d4114b855c89b710908d4a584e598b6dd186709d956fbd8b13b2ba3e9115c7d75416b7ac0e6d9dde83d367af00fa8dae54f03079cdf5fa1bac35ff3fbf6440f4fa41d06278fd8a6c3edc80d4ceee900975db2a345d8eda0ce0260d389a8336134a20945c1dde16e475ae537a4407da7f389dce79b439d0d81fa915a7dc4cb018e0d1bd806101ff53970731876850255dd5b7d78bf817112bc74ebae39ecae0aa1555e2a9e61660f4ba373086492e0561efb3bfa98399f899d6909415f19963cef3dc6d154056403ed1f475cbc78981cc949c23686bd71b420ed7ce654578d322f1eeec7413c77c017479f2e19b0c5ebb25ad76e1af8ec3a6b6ba3e092af8ddd624dfd1fccb4a61cc77f5c001fafdd7d2cc6c7b418c6dac97e840bc027ef9d4b237eebc2d1255bc0f796c3de78e31a9ae346734801e0f51dc47f8279164ab35bad3b06a5f74356deec0296c350aae4da560b8d77782195621dca054703433037f28cac2603cdefe52903f25013ad4cf4f29e0e413f89f950d26b4ef129aabf78abf9acae252bc60db373cfe3963fc87e9532056f2f2a7f9f1ddd1a3cf9d0078a5c9cccdcc60714de967556032283075424446ccda9f62a5e31f2b5efbc2256c742e4a300d5bc797e90b3a65fdffe3c5f22f5a885903331dbbb031e51411facb4e80e1728c5b14c9fce196d7d5f1dfeca2fe9b877f45fc1f1c8ec09dd5335eb89accf38fe0e6dbbe77a59c96a49830ce5279f17f4897c64e2aeaec127d8d06adcefa7ac800c1e8"); - EXPECT_EQ(Serpent128_CFB::NAME, config->config()->Cipher()); - EXPECT_EQ("5821ED3B0739C7EDB6A09590232EA75B", config->config()->RootBlob()); -} - -#endif diff --git a/test/cryfs/impl/config/CryCipherTest.cpp b/test/cryfs/impl/config/CryCipherTest.cpp deleted file mode 100644 index 9c54e225..00000000 --- a/test/cryfs/impl/config/CryCipherTest.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace cryfs; -using namespace blockstore::encrypted; -using namespace blockstore::inmemory; -using namespace blockstore; - -using std::initializer_list; -using std::string; -using std::vector; -using std::find; -using boost::none; -using testing::MatchesRegex; -using namespace cpputils; - -class CryCipherTest : public ::testing::Test { -public: - void EXPECT_FINDS_CORRECT_CIPHERS(initializer_list ciphers) { - for (const string & cipher : ciphers) { - EXPECT_FINDS_CORRECT_CIPHER(cipher); - } - } - - void EXPECT_FINDS_CORRECT_CIPHER(const string &cipherName) { - EXPECT_EQ(cipherName, CryCiphers::find(cipherName).cipherName()); - } - - template - void EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE(const string &cipherName) { - const auto &actualCipher = CryCiphers::find(cipherName); - Data dataFixture = DataFixture::generate(1024); - string encKey = ExpectedCipher::EncryptionKey::CreateKey(Random::PseudoRandom(), ExpectedCipher::KEYSIZE).ToString(); - EXPECT_ENCRYPTS_WITH_ACTUAL_BLOCKSTORE_DECRYPTS_CORRECTLY_WITH_EXPECTED_BLOCKSTORE_(actualCipher, encKey, std::move(dataFixture)); - } - - template - void EXPECT_ENCRYPTS_WITH_ACTUAL_BLOCKSTORE_DECRYPTS_CORRECTLY_WITH_EXPECTED_BLOCKSTORE_(const CryCipher &actualCipher, const std::string &encKey, Data dataFixture) { - blockstore::BlockId blockId = blockstore::BlockId::Random(); - Data encrypted = _encryptUsingEncryptedBlockStoreWithCipher(actualCipher, encKey, blockId, dataFixture.copy()); - Data decrypted = _decryptUsingEncryptedBlockStoreWithCipher(encKey, blockId, std::move(encrypted)); - EXPECT_EQ(dataFixture, decrypted); - } - - Data _encryptUsingEncryptedBlockStoreWithCipher(const CryCipher &cipher, const std::string &encKey, const blockstore::BlockId &blockId, Data data) { - unique_ref _baseStore = make_unique_ref(); - InMemoryBlockStore2 *baseStore = _baseStore.get(); - unique_ref encryptedStore = cipher.createEncryptedBlockstore(std::move(_baseStore), encKey); - bool created = encryptedStore->tryCreate(blockId, data); - EXPECT_TRUE(created); - return _loadBlock(baseStore, blockId); - } - - template - Data _decryptUsingEncryptedBlockStoreWithCipher(const std::string &encKey, const blockstore::BlockId &blockId, Data data) { - unique_ref baseStore = make_unique_ref(); - bool created = baseStore->tryCreate(blockId, data); - EXPECT_TRUE(created); - EncryptedBlockStore2 encryptedStore(std::move(baseStore), Cipher::EncryptionKey::FromString(encKey)); - return _loadBlock(&encryptedStore, blockId); - } - - Data _loadBlock(BlockStore2 *store, const blockstore::BlockId &blockId) { - return store->load(blockId).value(); - } -}; - -TEST_F(CryCipherTest, FindsCorrectCipher) { - EXPECT_FINDS_CORRECT_CIPHERS({ - "aes-256-gcm", "aes-256-cfb", "aes-256-gcm", "aes-256-cfb", - "twofish-256-gcm", "twofish-256-cfb", "twofish-256-gcm", "twofish-256-cfb", - "serpent-256-gcm", "serpent-256-cfb", "serpent-256-gcm", "serpent-256-cfb", - "cast-256-gcm", "cast-256-cfb", "mars-448-gcm", "mars-448-cfb", - "mars-256-gcm", "mars-256-cfb", "mars-256-gcm", "mars-256-cfb" - }); -} - -TEST_F(CryCipherTest, CreatesCorrectEncryptedBlockStore) { - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("aes-256-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("aes-256-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("aes-128-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("aes-128-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("twofish-256-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("twofish-256-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("twofish-128-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("twofish-128-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("serpent-256-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("serpent-256-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("serpent-128-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("serpent-128-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("cast-256-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("cast-256-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("mars-448-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("mars-448-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("mars-256-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("mars-256-cfb"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("mars-128-gcm"); - EXPECT_CREATES_CORRECT_ENCRYPTED_BLOCKSTORE("mars-128-cfb"); -} - -TEST_F(CryCipherTest, SupportedCipherNamesContainsACipher) { - vector supportedCipherNames = CryCiphers::supportedCipherNames(); - EXPECT_NE(supportedCipherNames.end(), find(supportedCipherNames.begin(), supportedCipherNames.end(), "aes-256-gcm")); -} - -TEST_F(CryCipherTest, ThereIsACipherWithoutWarning) { - EXPECT_EQ(none, CryCiphers::find("aes-256-gcm").warning()); -} - -TEST_F(CryCipherTest, ThereIsACipherWithIntegrityWarning) { - EXPECT_THAT(CryCiphers::find("aes-256-cfb").warning().value(), MatchesRegex(".*integrity.*")); -} - -TEST_F(CryCipherTest, EncryptionKeyHasCorrectSize_448) { - EXPECT_EQ(Mars448_GCM::STRING_KEYSIZE, CryCiphers::find("mars-448-gcm").createKey(Random::PseudoRandom()).size()); -} - -TEST_F(CryCipherTest, EncryptionKeyHasCorrectSize_256) { - EXPECT_EQ(AES256_GCM::STRING_KEYSIZE, CryCiphers::find("aes-256-gcm").createKey(Random::PseudoRandom()).size()); -} - -TEST_F(CryCipherTest, EncryptionKeyHasCorrectSize_128) { - EXPECT_EQ(AES128_GCM::STRING_KEYSIZE, CryCiphers::find("aes-128-gcm").createKey(Random::PseudoRandom()).size()); -} diff --git a/test/cryfs/impl/config/CryConfigConsoleTest.cpp b/test/cryfs/impl/config/CryConfigConsoleTest.cpp deleted file mode 100644 index 9d684732..00000000 --- a/test/cryfs/impl/config/CryConfigConsoleTest.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "../../impl/testutils/MockConsole.h" - -using namespace cryfs; - -using boost::optional; -using boost::none; -using cpputils::NoninteractiveConsole; -using std::string; -using std::shared_ptr; -using std::make_shared; -using ::testing::NiceMock; -using ::testing::Return; -using ::testing::ValuesIn; -using ::testing::HasSubstr; -using ::testing::UnorderedElementsAreArray; -using ::testing::WithParamInterface; - -class CryConfigConsoleTest: public ::testing::Test { -public: - CryConfigConsoleTest() - : console(make_shared>()), - cryconsole(console), - noninteractiveCryconsole(make_shared(console)) { - } - shared_ptr> console; - CryConfigConsole cryconsole; - CryConfigConsole noninteractiveCryconsole; -}; - -class CryConfigConsoleTest_Cipher: public CryConfigConsoleTest {}; - -#define EXPECT_ASK_FOR_CIPHER() \ - EXPECT_CALL(*console, askYesNo("Use default settings?", testing::_)).Times(1).WillOnce(Return(false)); \ - EXPECT_CALL(*console, ask(HasSubstr("block cipher"), UnorderedElementsAreArray(CryCiphers::supportedCipherNames()))).Times(1) - -#define EXPECT_ASK_FOR_BLOCKSIZE() \ - EXPECT_CALL(*console, askYesNo("Use default settings?", testing::_)).Times(1).WillOnce(Return(false)); \ - EXPECT_CALL(*console, ask(HasSubstr("block size"), testing::_)).Times(1) - -#define EXPECT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION() \ - EXPECT_CALL(*console, askYesNo("Use default settings?", testing::_)).Times(1).WillOnce(Return(false)); \ - EXPECT_CALL(*console, askYesNo(HasSubstr("missing block"), testing::_)).Times(1) - -TEST_F(CryConfigConsoleTest_Cipher, AsksForCipher) { - EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseAnyCipher()); - cryconsole.askCipher(); -} - -TEST_F(CryConfigConsoleTest_Cipher, ChooseDefaultCipher) { - EXPECT_CALL(*console, askYesNo("Use default settings?", testing::_)).Times(1).WillOnce(Return(true)); - EXPECT_CALL(*console, ask(HasSubstr("block cipher"), testing::_)).Times(0); - string cipher = cryconsole.askCipher(); - EXPECT_EQ(CryConfigConsole::DEFAULT_CIPHER, cipher); -} - -TEST_F(CryConfigConsoleTest_Cipher, ChooseDefaultCipherWhenNoninteractiveEnvironment) { - EXPECT_CALL(*console, askYesNo(HasSubstr("default"), testing::_)).Times(0); - EXPECT_CALL(*console, ask(HasSubstr("block cipher"), testing::_)).Times(0); - string cipher = noninteractiveCryconsole.askCipher(); - EXPECT_EQ(CryConfigConsole::DEFAULT_CIPHER, cipher); -} - -TEST_F(CryConfigConsoleTest_Cipher, AsksForBlocksize) { - EXPECT_ASK_FOR_BLOCKSIZE().WillOnce(Return(0)); - cryconsole.askBlocksizeBytes(); -} - -TEST_F(CryConfigConsoleTest_Cipher, AsksForMissingBlockIsIntegrityViolation) { - EXPECT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION().WillOnce(Return(true)); - cryconsole.askMissingBlockIsIntegrityViolation(); -} - -TEST_F(CryConfigConsoleTest_Cipher, ChooseDefaultBlocksizeWhenNoninteractiveEnvironment) { - EXPECT_CALL(*console, askYesNo(HasSubstr("default"), testing::_)).Times(0); - EXPECT_CALL(*console, ask(HasSubstr("block size"), testing::_)).Times(0); - uint32_t blocksize = noninteractiveCryconsole.askBlocksizeBytes(); - EXPECT_EQ(CryConfigConsole::DEFAULT_BLOCKSIZE_BYTES, blocksize); -} - -class CryConfigConsoleTest_Cipher_Choose: public CryConfigConsoleTest_Cipher, public ::testing::WithParamInterface { -public: - string cipherName = GetParam(); - optional cipherWarning = CryCiphers::find(cipherName).warning(); - - void EXPECT_DONT_SHOW_WARNING() { - EXPECT_CALL(*console, askYesNo(testing::_, testing::_)).Times(0); - } - - void EXPECT_SHOW_WARNING(const string &warning) { - EXPECT_CALL(*console, askYesNo(HasSubstr(warning), testing::_)).WillOnce(Return(true)); - } -}; - -TEST_P(CryConfigConsoleTest_Cipher_Choose, ChoosesCipherCorrectly) { - if (cipherWarning == none) { - EXPECT_DONT_SHOW_WARNING(); - } else { - EXPECT_SHOW_WARNING(*cipherWarning); - } - - EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseCipher(cipherName)); - - string chosenCipher = cryconsole.askCipher(); - EXPECT_EQ(cipherName, chosenCipher); -} - -INSTANTIATE_TEST_SUITE_P(CryConfigConsoleTest_Cipher_Choose, CryConfigConsoleTest_Cipher_Choose, ValuesIn(CryCiphers::supportedCipherNames())); diff --git a/test/cryfs/impl/config/CryConfigCreatorTest.cpp b/test/cryfs/impl/config/CryConfigCreatorTest.cpp deleted file mode 100644 index eeb42c5a..00000000 --- a/test/cryfs/impl/config/CryConfigCreatorTest.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include -#include -#include -#include -#include -#include "../../impl/testutils/MockConsole.h" -#include "../../impl/testutils/TestWithFakeHomeDirectory.h" -#include -#include -#include - -using namespace cryfs; - -using boost::none; -using cpputils::NoninteractiveConsole; -using std::string; -using std::shared_ptr; -using std::make_shared; -using ::testing::Return; -using ::testing::HasSubstr; -using ::testing::UnorderedElementsAreArray; -using ::testing::NiceMock; - -#define EXPECT_ASK_TO_USE_DEFAULT_SETTINGS() \ - EXPECT_CALL(*console, askYesNo("Use default settings?", true)).Times(1) -#define EXPECT_DOES_NOT_ASK_TO_USE_DEFAULT_SETTINGS() \ - EXPECT_CALL(*console, askYesNo("Use default settings?", true)).Times(0) -#define EXPECT_ASK_FOR_CIPHER() \ - EXPECT_CALL(*console, ask(HasSubstr("block cipher"), UnorderedElementsAreArray(CryCiphers::supportedCipherNames()))).Times(1) -#define EXPECT_DOES_NOT_ASK_FOR_CIPHER() \ - EXPECT_CALL(*console, ask(HasSubstr("block cipher"), testing::_)).Times(0) -#define EXPECT_ASK_FOR_BLOCKSIZE() \ - EXPECT_CALL(*console, ask(HasSubstr("block size"), testing::_)).Times(1) -#define EXPECT_DOES_NOT_ASK_FOR_BLOCKSIZE() \ - EXPECT_CALL(*console, ask(HasSubstr("block size"), testing::_)).Times(0) -#define EXPECT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION() \ - EXPECT_CALL(*console, askYesNo(HasSubstr("missing block"), false)).Times(1) -#define EXPECT_DOES_NOT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION() \ - EXPECT_CALL(*console, askYesNo(HasSubstr("missing block"), false)).Times(0) -#define IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION() \ - EXPECT_CALL(*console, askYesNo(HasSubstr("missing block"), false)) - -class CryConfigCreatorTest: public ::testing::Test, TestWithFakeHomeDirectory { -public: - CryConfigCreatorTest() - : console(make_shared>()), - tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), - creator(console, cpputils::Random::PseudoRandom(), localStateDir), - noninteractiveCreator(make_shared(console), cpputils::Random::PseudoRandom(), localStateDir) { - EXPECT_CALL(*console, ask(HasSubstr("block cipher"), testing::_)).WillRepeatedly(ChooseAnyCipher()); - EXPECT_CALL(*console, ask(HasSubstr("block size"), testing::_)).WillRepeatedly(Return(0)); - } - shared_ptr> console; - cpputils::TempDir tempLocalStateDir; - LocalStateDir localStateDir; - CryConfigCreator creator; - CryConfigCreator noninteractiveCreator; - - void AnswerNoToDefaultSettings() { - EXPECT_ASK_TO_USE_DEFAULT_SETTINGS().WillOnce(Return(false)); - } - - void AnswerYesToDefaultSettings() { - EXPECT_ASK_TO_USE_DEFAULT_SETTINGS().WillOnce(Return(true)); - } -}; - -TEST_F(CryConfigCreatorTest, DoesAskForCipherIfNotSpecified) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseAnyCipher()); - CryConfig config = creator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskForCipherIfSpecified) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - EXPECT_DOES_NOT_ASK_FOR_CIPHER(); - CryConfig config = creator.create(string("aes-256-gcm"), none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskForCipherIfUsingDefaultSettings) { - AnswerYesToDefaultSettings(); - EXPECT_DOES_NOT_ASK_FOR_CIPHER(); - CryConfig config = creator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskForCipherIfNoninteractive) { - EXPECT_DOES_NOT_ASK_TO_USE_DEFAULT_SETTINGS(); - EXPECT_DOES_NOT_ASK_FOR_CIPHER(); - CryConfig config = noninteractiveCreator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesAskForBlocksizeIfNotSpecified) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - EXPECT_ASK_FOR_BLOCKSIZE().WillOnce(Return(1)); - CryConfig config = creator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskForBlocksizeIfSpecified) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - EXPECT_DOES_NOT_ASK_FOR_BLOCKSIZE(); - CryConfig config = creator.create(none, 10*1024u, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskForBlocksizeIfNoninteractive) { - EXPECT_DOES_NOT_ASK_TO_USE_DEFAULT_SETTINGS(); - EXPECT_DOES_NOT_ASK_FOR_BLOCKSIZE(); - CryConfig config = noninteractiveCreator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskForBlocksizeIfUsingDefaultSettings) { - AnswerYesToDefaultSettings(); - EXPECT_DOES_NOT_ASK_FOR_BLOCKSIZE(); - CryConfig config = creator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesAskWhetherMissingBlocksAreIntegrityViolationsIfNotSpecified) { - AnswerNoToDefaultSettings(); - EXPECT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION().WillOnce(Return(true)); - CryConfig config = creator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskWhetherMissingBlocksAreIntegrityViolationsIfSpecified_True) { - AnswerNoToDefaultSettings(); - EXPECT_DOES_NOT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - CryConfig config = creator.create(none, none, true, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskWhetherMissingBlocksAreIntegrityViolationsIfSpecified_False) { - AnswerNoToDefaultSettings(); - EXPECT_DOES_NOT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - CryConfig config = creator.create(none, none, false, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskWhetherMissingBlocksAreIntegrityViolationsIfNoninteractive) { - EXPECT_DOES_NOT_ASK_TO_USE_DEFAULT_SETTINGS(); - EXPECT_DOES_NOT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - CryConfig config = noninteractiveCreator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, DoesNotAskWhetherMissingBlocksAreIntegrityViolationsIfUsingDefaultSettings) { - AnswerYesToDefaultSettings(); - EXPECT_DOES_NOT_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - CryConfig config = creator.create(none, none, none, false).config; -} - -TEST_F(CryConfigCreatorTest, ChoosesEmptyRootBlobId) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - CryConfig config = creator.create(none, none, none, false).config; - EXPECT_EQ("", config.RootBlob()); // This tells CryFS to create a new root blob -} - -TEST_F(CryConfigCreatorTest, ChoosesValidEncryptionKey_448) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseCipher("mars-448-gcm")); - CryConfig config = creator.create(none, none, none, false).config; - cpputils::Mars448_GCM::EncryptionKey::FromString(config.EncryptionKey()); // This crashes if invalid -} - -TEST_F(CryConfigCreatorTest, ChoosesValidEncryptionKey_256) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseCipher("aes-256-gcm")); - CryConfig config = creator.create(none, none, none, false).config; - cpputils::AES256_GCM::EncryptionKey::FromString(config.EncryptionKey()); // This crashes if invalid -} - -TEST_F(CryConfigCreatorTest, ChoosesValidEncryptionKey_128) { - AnswerNoToDefaultSettings(); - IGNORE_ASK_FOR_MISSINGBLOCKISINTEGRITYVIOLATION(); - EXPECT_ASK_FOR_CIPHER().WillOnce(ChooseCipher("aes-128-gcm")); - CryConfig config = creator.create(none, none, none, false).config; - cpputils::AES128_GCM::EncryptionKey::FromString(config.EncryptionKey()); // This crashes if invalid -} - -TEST_F(CryConfigCreatorTest, DoesNotAskForAnythingIfEverythingIsSpecified) { - EXPECT_DOES_NOT_ASK_TO_USE_DEFAULT_SETTINGS(); - EXPECT_DOES_NOT_ASK_FOR_CIPHER(); - CryConfig config = noninteractiveCreator.create(string("aes-256-gcm"), 10*1024u, none, false).config; -} - -TEST_F(CryConfigCreatorTest, SetsCorrectCreatedWithVersion) { - CryConfig config = noninteractiveCreator.create(none, none, none, false).config; - EXPECT_EQ(gitversion::VersionString(), config.CreatedWithVersion()); -} - -TEST_F(CryConfigCreatorTest, SetsCorrectLastOpenedWithVersion) { - CryConfig config = noninteractiveCreator.create(none, none, none, false).config; - EXPECT_EQ(gitversion::VersionString(), config.CreatedWithVersion()); -} - -TEST_F(CryConfigCreatorTest, SetsCorrectVersion) { - CryConfig config = noninteractiveCreator.create(none, none, none, false).config; - EXPECT_EQ(CryConfig::FilesystemFormatVersion, config.Version()); -} - -//TODO Add test cases ensuring that the values entered are correctly taken diff --git a/test/cryfs/impl/config/CryConfigFileTest.cpp b/test/cryfs/impl/config/CryConfigFileTest.cpp deleted file mode 100644 index c43ca34c..00000000 --- a/test/cryfs/impl/config/CryConfigFileTest.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include -#include -#include -#include -#include "../../impl/testutils/FakeCryKeyProvider.h" - -using namespace cryfs; -using cpputils::TempFile; -using cpputils::unique_ref; -using std::string; -using boost::optional; -using boost::none; -using cpputils::Data; -namespace bf = boost::filesystem; - -//gtest/boost::optional workaround for working with optional -namespace boost { - inline std::ostream &operator<<(std::ostream &out, const CryConfigFile &file) { - UNUSED(file); - out << "ConfigFile()"; - return out; - } -} -#include - -class CryConfigFileTest: public ::testing::Test { -public: - CryConfigFileTest(): file(false) {} - - TempFile file; - - CryConfig Config() { - CryConfig result; - result.SetCipher("aes-256-gcm"); - return result; - } - - unique_ref CreateAndLoadEmpty(unsigned char keySeed = 0) { - Create(Config(), keySeed); - return Load().value(); - } - - void Create(CryConfig cfg, unsigned int keySeed = 0) { - FakeCryKeyProvider keyProvider(keySeed); - CryConfigFile::create(file.path(), std::move(cfg), &keyProvider); - } - - optional> Load(unsigned char keySeed = 0) { - FakeCryKeyProvider keyProvider(keySeed); - return CryConfigFile::load(file.path(), &keyProvider, CryConfigFile::Access::ReadWrite).right_opt(); - } - - void CreateWithCipher(const string &cipher) { - return CreateWithCipher(cipher, file); - } - - void CreateWithCipher(const string &cipher, const TempFile &tempFile) { - CryConfig cfg; - cfg.SetCipher(cipher); - FakeCryKeyProvider keyProvider(0); - CryConfigFile::create(tempFile.path(), std::move(cfg), &keyProvider); - } -}; - -TEST_F(CryConfigFileTest, DoesntLoadIfWrongPassword) { - const unsigned char pw1 = 0; - const unsigned char pw2 = 1; - Create(Config(), pw1); - auto loaded = Load(pw2); - EXPECT_EQ(none, loaded); -} - -TEST_F(CryConfigFileTest, RootBlob_Init) { - unique_ref created = CreateAndLoadEmpty(); - EXPECT_EQ("", created->config()->RootBlob()); -} - -TEST_F(CryConfigFileTest, RootBlob_CreateAndLoad) { - CryConfig cfg = Config(); - cfg.SetRootBlob("rootblobid"); - Create(std::move(cfg)); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("rootblobid", loaded->config()->RootBlob()); -} - -TEST_F(CryConfigFileTest, RootBlob_SaveAndLoad) { - unique_ref created = CreateAndLoadEmpty(); - created->config()->SetRootBlob("rootblobid"); - created->save(); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("rootblobid", loaded->config()->RootBlob()); -} - -TEST_F(CryConfigFileTest, EncryptionKey_Init) { - unique_ref created = CreateAndLoadEmpty(); - EXPECT_EQ("", created->config()->EncryptionKey()); -} - -TEST_F(CryConfigFileTest, EncryptionKey_CreateAndLoad) { - CryConfig cfg = Config(); - cfg.SetEncryptionKey("encryptionkey"); - Create(std::move(cfg)); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("encryptionkey", loaded->config()->EncryptionKey()); -} - -TEST_F(CryConfigFileTest, EncryptionKey_SaveAndLoad) { - unique_ref created = CreateAndLoadEmpty(); - created->config()->SetEncryptionKey("encryptionkey"); - created->save(); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("encryptionkey", loaded->config()->EncryptionKey()); -} - -TEST_F(CryConfigFileTest, Cipher_Init) { - unique_ref created = CreateAndLoadEmpty(); - EXPECT_EQ("aes-256-gcm", created->config()->Cipher()); -} - -TEST_F(CryConfigFileTest, Cipher_CreateAndLoad) { - CryConfig cfg = Config(); - cfg.SetCipher("twofish-128-cfb"); - Create(std::move(cfg)); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("twofish-128-cfb", loaded->config()->Cipher()); -} - -TEST_F(CryConfigFileTest, Cipher_SaveAndLoad) { - unique_ref created = CreateAndLoadEmpty(); - created->config()->SetCipher("twofish-128-cfb"); - created->save(); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("twofish-128-cfb", loaded->config()->Cipher()); -} - -TEST_F(CryConfigFileTest, Version_Init) { - unique_ref created = CreateAndLoadEmpty(); - EXPECT_EQ("", created->config()->Version()); -} - -TEST_F(CryConfigFileTest, Version_CreateAndLoad) { - CryConfig cfg = Config(); - cfg.SetVersion("0.9.2"); - Create(std::move(cfg)); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("0.9.2", loaded->config()->Version()); -} - -TEST_F(CryConfigFileTest, Version_SaveAndLoad) { - unique_ref created = CreateAndLoadEmpty(); - created->config()->SetVersion("0.9.2"); - created->save(); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("0.9.2", loaded->config()->Version()); -} - -TEST_F(CryConfigFileTest, CreatedWithVersion_Init) { - unique_ref created = CreateAndLoadEmpty(); - EXPECT_EQ("", created->config()->Version()); -} - -TEST_F(CryConfigFileTest, CreatedWithVersion_CreateAndLoad) { - CryConfig cfg = Config(); - cfg.SetCreatedWithVersion("0.9.2"); - Create(std::move(cfg)); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("0.9.2", loaded->config()->CreatedWithVersion()); -} - -TEST_F(CryConfigFileTest, CreatedWithVersion_SaveAndLoad) { - unique_ref created = CreateAndLoadEmpty(); - created->config()->SetCreatedWithVersion("0.9.2"); - created->save(); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("0.9.2", loaded->config()->CreatedWithVersion()); -} - -//Test that the encrypted config file has the same size, no matter how big the plaintext config data. -TEST_F(CryConfigFileTest, ConfigFileHasFixedSize) { - TempFile file1(false); - TempFile file2(false); - //It is important to have different cipher name lengths here, because they're on the outer encryption level. - //So this ensures that there also is a padding happening on the outer encryption level. - CreateWithCipher("aes-128-gcm", file1); // Short cipher name and short key - CreateWithCipher("twofish-256-cfb", file2); // Long cipher name and long key - EXPECT_EQ(bf::file_size(file1.path()), bf::file_size(file2.path())); -} - -TEST_F(CryConfigFileTest, CanSaveAndLoadModififedCipher) { - CreateWithCipher("aes-256-gcm"); - unique_ref created = Load().value(); - EXPECT_EQ("aes-256-gcm", created->config()->Cipher()); - created->config()->SetCipher("twofish-128-cfb"); - created->save(); - unique_ref loaded = std::move(Load().value()); - EXPECT_EQ("twofish-128-cfb", loaded->config()->Cipher()); -} - -TEST_F(CryConfigFileTest, FailsIfConfigFileIsEncryptedWithACipherDifferentToTheOneSpecifiedByTheUser) { - constexpr unsigned char keySeed = 0; - FakeCryKeyProvider keyProvider(keySeed); - auto encryptor = CryConfigEncryptorFactory::deriveNewKey(&keyProvider); - auto config = Config(); - config.SetCipher("aes-256-gcm"); - Data encrypted = encryptor->encrypt(config.save(), "aes-256-cfb"); - encrypted.StoreToFile(file.path()); - auto loaded = Load(keySeed); - EXPECT_EQ(none, loaded); -} diff --git a/test/cryfs/impl/config/CryConfigLoaderTest.cpp b/test/cryfs/impl/config/CryConfigLoaderTest.cpp deleted file mode 100644 index ec1ea1f4..00000000 --- a/test/cryfs/impl/config/CryConfigLoaderTest.cpp +++ /dev/null @@ -1,412 +0,0 @@ -#include - -#include -#include -#include "../../impl/testutils/MockConsole.h" -#include "../../impl/testutils/TestWithFakeHomeDirectory.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using cpputils::TempFile; -using cpputils::SCrypt; -using cpputils::DataFixture; -using cpputils::Data; -using cpputils::NoninteractiveConsole; -using cpputils::unique_ref; -using cpputils::either; -using cpputils::make_unique_ref; -using cpputils::Console; -using cpputils::unique_ref; -using cryfs::CryPresetPasswordBasedKeyProvider; -using boost::optional; -using boost::none; -using std::string; -using std::ostream; -using std::shared_ptr; -using std::make_shared; -using ::testing::Return; -using ::testing::HasSubstr; - -using namespace cryfs; - -// This is needed for google test -namespace boost { - inline ostream &operator<<(ostream &stream, const CryConfigFile &) { - return stream << "CryConfigFile()"; - } -} -namespace cryfs { - inline ostream &operator<<(ostream &stream, const CryConfigLoader::ConfigLoadResult &) { - return stream << "ConfigLoadResult()"; - } -} -#include - -class FakeRandomGenerator final : public cpputils::RandomGenerator { -public: - FakeRandomGenerator(Data output) - : _output(std::move(output)) {} - - void _get(void *target, size_t bytes) override { - ASSERT_EQ(_output.size(), bytes); - std::memcpy(target, _output.data(), bytes); - } - -private: - Data _output; -}; - -class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole, TestWithFakeHomeDirectory { -public: - unique_ref keyProvider(const string& password) { - return make_unique_ref(password, make_unique_ref(SCrypt::TestSettings)); - } - - CryConfigLoaderTest(): file(false), tempLocalStateDir(), localStateDir(tempLocalStateDir.path()) { - console = mockConsole(); - } - - CryConfigLoader loader(const string &password, bool noninteractive, const optional &cipher = none) { - auto _console = noninteractive ? shared_ptr(make_shared(console)) : shared_ptr(console); - return CryConfigLoader(_console, cpputils::Random::PseudoRandom(), keyProvider(password), localStateDir, cipher, none, none); - } - - unique_ref Create(const string &password = "mypassword", const optional &cipher = none, bool noninteractive = false) { - EXPECT_FALSE(file.exists()); - return loader(password, noninteractive, cipher).loadOrCreate(file.path(), false, false).right().configFile; - } - - either> LoadOrCreate(const string &password = "mypassword", const optional &cipher = none, bool noninteractive = false, bool allowFilesystemUpgrade = false) { - EXPECT_TRUE(file.exists()); - auto loadResult = loader(password, noninteractive, cipher).loadOrCreate(file.path(), allowFilesystemUpgrade, false); - if (loadResult.is_left()) { - return loadResult.left(); - } - return std::move(loadResult.right().configFile); - } - - either> Load(CryConfigFile::Access access = CryConfigFile::Access::ReadWrite) { - EXPECT_TRUE(file.exists()); - auto loadResult = loader("mypassword", false, none).load(file.path(), false, false, access); - if (loadResult.is_left()) { - return loadResult.left(); - } - return std::move(loadResult.right().configFile); - } - - void expectLoadingModifiesFile(CryConfigFile::Access access) { - Data contents_before_loading = Data::LoadFromFile(file.path()).value(); - EXPECT_TRUE(Load(access).is_right()); - Data contents_after_loading = Data::LoadFromFile(file.path()).value(); - ASSERT_EQ(contents_before_loading.size(), contents_after_loading.size()); - EXPECT_NE(0, std::memcmp(contents_before_loading.data(), contents_after_loading.data(), contents_before_loading.size())); - } - - void expectLoadingDoesntModifyFile(CryConfigFile::Access access) { - Data contents_before_loading = Data::LoadFromFile(file.path()).value(); - EXPECT_TRUE(Load(access).is_right()); - Data contents_after_loading = Data::LoadFromFile(file.path()).value(); - ASSERT_EQ(contents_before_loading.size(), contents_after_loading.size()); - EXPECT_EQ(0, std::memcmp(contents_before_loading.data(), contents_after_loading.data(), contents_before_loading.size())); - } - - void CreateWithRootBlob(const string &rootBlob, const string &password = "mypassword") { - auto cfg = loader(password, false).loadOrCreate(file.path(), false, false).right().configFile; - cfg->config()->SetRootBlob(rootBlob); - cfg->save(); - } - - void CreateWithCipher(const string &cipher, const string &password = "mypassword") { - auto cfg = loader(password, false).loadOrCreate(file.path(), false, false).right().configFile; - cfg->config()->SetCipher(cipher); - cfg->save(); - } - - void CreateWithEncryptionKey(const string &encKey, const string &password = "mypassword") { - FakeRandomGenerator generator(Data::FromString(encKey)); - auto loader = CryConfigLoader(console, generator, keyProvider(password), localStateDir, none, none, none); - ASSERT_TRUE(loader.loadOrCreate(file.path(), false, false).is_right()); - } - - void ChangeEncryptionKey(const string &encKey, const string& password = "mypassword") { - auto cfg = CryConfigFile::load(file.path(), keyProvider(password).get(), CryConfigFile::Access::ReadWrite).right(); - cfg->config()->SetEncryptionKey(encKey); - cfg->save(); - } - - void CreateWithVersion(const string &version, const string& formatVersion, const string &password = "mypassword") { - auto cfg = loader(password, false).loadOrCreate(file.path(), false, false).right().configFile; - cfg->config()->SetVersion(formatVersion); - cfg->config()->SetLastOpenedWithVersion(version); - cfg->config()->SetCreatedWithVersion(version); - cfg->save(); - } - - void CreateWithFilesystemID(const CryConfig::FilesystemID &filesystemId, const string &password = "mypassword") { - auto cfg = loader(password, false).loadOrCreate(file.path(), false, false).right().configFile; - cfg->config()->SetFilesystemId(filesystemId); - cfg->save(); - } - - void ChangeFilesystemID(const CryConfig::FilesystemID &filesystemId, const string& password = "mypassword") { - auto cfg = CryConfigFile::load(file.path(), keyProvider(password).get(), CryConfigFile::Access::ReadWrite).right(); - cfg->config()->SetFilesystemId(filesystemId); - cfg->save(); - } - - string olderVersion() { - auto versionInfo = gitversion::Parser::parse(CryConfig::FilesystemFormatVersion); - string olderVersion; - if (std::stol(versionInfo.minorVersion) > 0) { - olderVersion = versionInfo.majorVersion + "." + std::to_string(std::stol(versionInfo.minorVersion) - 1) + ".9"; - } else { - olderVersion = std::to_string(std::stol(versionInfo.majorVersion) - 1) + "." + versionInfo.minorVersion; - } - assert(gitversion::VersionCompare::isOlderThan(olderVersion, CryConfig::FilesystemFormatVersion)); - return olderVersion; - } - - string newerVersion() { - string newerVersion = gitversion::MajorVersion()+"."+std::to_string(std::stol(gitversion::MinorVersion())+2); - EXPECT_TRUE(gitversion::VersionCompare::isOlderThan(CryConfig::FilesystemFormatVersion, newerVersion)) - << "Format Version " << CryConfig::FilesystemFormatVersion << " should be older than Git Version " << newerVersion; - return newerVersion; - } - - std::shared_ptr console; - TempFile file; - cpputils::TempDir tempLocalStateDir; - LocalStateDir localStateDir; -}; - -TEST_F(CryConfigLoaderTest, CreatesNewIfNotExisting) { - EXPECT_FALSE(file.exists()); - Create(); - ASSERT_TRUE(file.exists()); -} - -TEST_F(CryConfigLoaderTest, DoesntCrashIfExisting) { - Create(); - LoadOrCreate(); -} - -TEST_F(CryConfigLoaderTest, DoesntLoadIfWrongPassword) { - Create("mypassword"); - auto loaded = LoadOrCreate("mypassword2"); - EXPECT_TRUE(loaded.is_left()); -} - -TEST_F(CryConfigLoaderTest, DoesntLoadIfDifferentCipher) { - Create("mypassword", string("aes-256-gcm"), false); - try { - LoadOrCreate("mypassword", string("aes-256-cfb"), false); - EXPECT_TRUE(false); // Should throw exception - } catch (const std::runtime_error &e) { - EXPECT_EQ(string("Filesystem uses aes-256-gcm cipher and not aes-256-cfb as specified."), e.what()); - } -} - -TEST_F(CryConfigLoaderTest, DoesntLoadIfDifferentCipher_Noninteractive) { - Create("mypassword", string("aes-256-gcm"), true); - try { - LoadOrCreate("mypassword", string("aes-256-cfb"), true); - EXPECT_TRUE(false); // Should throw exception - } catch (const std::runtime_error &e) { - EXPECT_EQ(string("Filesystem uses aes-256-gcm cipher and not aes-256-cfb as specified."), e.what()); - } -} - -TEST_F(CryConfigLoaderTest, DoesLoadIfSameCipher) { - Create("mypassword", string("aes-256-gcm")); - LoadOrCreate("mypassword", string("aes-256-gcm")); -} - -TEST_F(CryConfigLoaderTest, DoesLoadIfSameCipher_Noninteractive) { - Create("mypassword", string("aes-128-gcm"), true); - LoadOrCreate("mypassword", string("aes-128-gcm"), true); -} - -TEST_F(CryConfigLoaderTest, RootBlob_Load) { - CreateWithRootBlob("rootblobid"); - auto loaded = LoadOrCreate().right(); - EXPECT_EQ("rootblobid", loaded->config()->RootBlob()); -} - -TEST_F(CryConfigLoaderTest, RootBlob_Create) { - auto created = Create(); - EXPECT_EQ("", created->config()->RootBlob()); -} - -TEST_F(CryConfigLoaderTest, EncryptionKey_Load) { - CreateWithEncryptionKey("3B4682CF22F3CA199E385729B9F3CA19D325229E385729B9443CA19D325229E3"); - auto loaded = LoadOrCreate().right(); - EXPECT_EQ("3B4682CF22F3CA199E385729B9F3CA19D325229E385729B9443CA19D325229E3", loaded->config()->EncryptionKey()); -} - -TEST_F(CryConfigLoaderTest, EncryptionKey_Load_whenKeyChanged_thenFails) { - CreateWithEncryptionKey("3B4682CF22F3CA199E385729B9F3CA19D325229E385729B9443CA19D325229E3"); - ChangeEncryptionKey("3B4682CF22F3CA199E385729B9F3CA19D325229E385729B9443CA19D325229E4"); - EXPECT_THROW( - LoadOrCreate(), - std::runtime_error - ); -} - -TEST_F(CryConfigLoaderTest, EncryptionKey_Create) { - auto created = Create(); - cpputils::AES256_GCM::EncryptionKey::FromString(created->config()->EncryptionKey()); // This crashes if key is invalid -} - -TEST_F(CryConfigLoaderTest, Cipher_Load) { - CreateWithCipher("twofish-128-cfb"); - auto loaded = LoadOrCreate().right(); - EXPECT_EQ("twofish-128-cfb", loaded->config()->Cipher()); -} - -TEST_F(CryConfigLoaderTest, Cipher_Create) { - auto created = Create(); - //xchacha20-poly1305 is the default cipher chosen by mockConsole() - EXPECT_EQ("xchacha20-poly1305", created->config()->Cipher()); -} - -TEST_F(CryConfigLoaderTest, Version_Load) { - CreateWithVersion("0.9.4", "0.9.4"); - auto loaded = std::move(LoadOrCreate().right()); - EXPECT_EQ(CryConfig::FilesystemFormatVersion, loaded->config()->Version()); - EXPECT_EQ(gitversion::VersionString(), loaded->config()->LastOpenedWithVersion()); - EXPECT_EQ("0.9.4", loaded->config()->CreatedWithVersion()); -} - -TEST_F(CryConfigLoaderTest, Version_Load_IsStoredAndNotOnlyOverwrittenInMemoryOnLoad) { - CreateWithVersion("0.9.4", "0.9.4", "mypassword"); - LoadOrCreate().right(); - auto configFile = CryConfigFile::load(file.path(), keyProvider("mypassword").get(), CryConfigFile::Access::ReadWrite).right(); - EXPECT_EQ(CryConfig::FilesystemFormatVersion, configFile->config()->Version()); - EXPECT_EQ(gitversion::VersionString(), configFile->config()->LastOpenedWithVersion()); - EXPECT_EQ("0.9.4", configFile->config()->CreatedWithVersion()); -} - -TEST_F(CryConfigLoaderTest, Version_Create) { - auto created = Create(); - EXPECT_EQ(CryConfig::FilesystemFormatVersion, created->config()->Version()); - EXPECT_EQ(gitversion::VersionString(), created->config()->LastOpenedWithVersion()); - EXPECT_EQ(gitversion::VersionString(), created->config()->CreatedWithVersion()); -} - -TEST_F(CryConfigLoaderTest, FilesystemID_Load) { - auto fixture = DataFixture::generateFixedSize(); - CreateWithFilesystemID(fixture); - auto loaded = LoadOrCreate().right(); - EXPECT_EQ(fixture, loaded->config()->FilesystemId()); -} - -TEST_F(CryConfigLoaderTest, FilesystemID_Create) { - auto created = Create(); - EXPECT_NE(CryConfig::FilesystemID::Null(), created->config()->FilesystemId()); -} - -TEST_F(CryConfigLoaderTest, AsksWhenLoadingNewerFilesystem_AnswerYes) { - EXPECT_CALL(*console, askYesNo(HasSubstr("should not be opened with older versions"), false)).Times(1).WillOnce(Return(true)); - - string version = newerVersion(); - CreateWithVersion(version, version); - EXPECT_TRUE(LoadOrCreate().is_right()); -} - -TEST_F(CryConfigLoaderTest, AsksWhenLoadingNewerFilesystem_AnswerNo) { - EXPECT_CALL(*console, askYesNo(HasSubstr("should not be opened with older versions"), false)).Times(1).WillOnce(Return(false)); - - string version = newerVersion(); - CreateWithVersion(version, version); - try { - LoadOrCreate(); - EXPECT_TRUE(false); // expect throw - } catch (const std::runtime_error &e) { - EXPECT_THAT(e.what(), HasSubstr("Please update your CryFS version.")); - } -} - -TEST_F(CryConfigLoaderTest, AsksWhenMigratingOlderFilesystem) { - EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to attempt a migration now?"), false)).Times(1).WillOnce(Return(true)); - - string version = olderVersion(); - CreateWithVersion(version, version); - EXPECT_TRUE(LoadOrCreate().is_right()); -} - -TEST_F(CryConfigLoaderTest, DoesNotAskForMigrationWhenCorrectVersion) { - EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to attempt a migration now?"), testing::_)).Times(0); - - CreateWithVersion(gitversion::VersionString(), CryConfig::FilesystemFormatVersion); - EXPECT_TRUE(LoadOrCreate().is_right()); -} - -TEST_F(CryConfigLoaderTest, DontMigrateWhenAnsweredNo) { - EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to attempt a migration now?"), false)).Times(1).WillOnce(Return(false)); - - string version = olderVersion(); - CreateWithVersion(version, version); - try { - LoadOrCreate(); - EXPECT_TRUE(false); // expect throw - } catch (const std::runtime_error &e) { - EXPECT_THAT(e.what(), HasSubstr("It has to be migrated.")); - } -} - -TEST_F(CryConfigLoaderTest, MyClientIdIsIndeterministic) { - TempFile file1(false); - TempFile file2(false); - uint32_t myClientId = loader("mypassword", true).loadOrCreate(file1.path(), false, false).right().myClientId; - EXPECT_NE(myClientId, loader("mypassword", true).loadOrCreate(file2.path(), false, false).right().myClientId); -} - -TEST_F(CryConfigLoaderTest, MyClientIdIsLoadedCorrectly) { - TempFile file(false); - uint32_t myClientId = loader("mypassword", true).loadOrCreate(file.path(), false, false).right().myClientId; - EXPECT_EQ(myClientId, loader("mypassword", true).loadOrCreate(file.path(), false, false).right().myClientId); -} - -TEST_F(CryConfigLoaderTest, DoesNotAskForMigrationWhenUpgradesAllowedByProgramArguments_NoninteractiveMode) { - EXPECT_CALL(*console, askYesNo(HasSubstr("migrate"), testing::_)).Times(0); - - string version = olderVersion(); - CreateWithVersion(version, version); - EXPECT_TRUE(LoadOrCreate("mypassword", none, true, true).is_right()); -} - -TEST_F(CryConfigLoaderTest, DoesNotAskForMigrationWhenUpgradesAllowedByProgramArguments_InteractiveMode) { - EXPECT_CALL(*console, askYesNo(HasSubstr("migrate"), testing::_)).Times(0); - - string version = olderVersion(); - CreateWithVersion(version, version); - EXPECT_TRUE(LoadOrCreate("mypassword", none, false, true).is_right()); -} - -TEST_F(CryConfigLoaderTest, UpdatesConfigFileWithNewVersionWhenMigrated) { - EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to attempt a migration now?"), false)).Times(1).WillOnce(Return(true)); - - string version = olderVersion(); // this triggers a migration which should cause it to modify the config file on load - CreateWithVersion(version, version); - - expectLoadingModifiesFile(CryConfigFile::Access::ReadWrite); - - // If we load it again, it shouldn't modify again because it's already updated - expectLoadingDoesntModifyFile(CryConfigFile::Access::ReadWrite); -} - -TEST_F(CryConfigLoaderTest, DoesntUpdatesConfigFileWithNewVersionWhenLoadingReadOnly) { - EXPECT_CALL(*console, askYesNo(HasSubstr("Do you want to attempt a migration now?"), false)).Times(1).WillOnce(Return(true)); - - string version = olderVersion(); // this triggers a migration which usually would cause it to modify the config file on load - CreateWithVersion(version, version); - - expectLoadingDoesntModifyFile(CryConfigFile::Access::ReadOnly); -} diff --git a/test/cryfs/impl/config/CryConfigTest.cpp b/test/cryfs/impl/config/CryConfigTest.cpp deleted file mode 100644 index 83ef5fc2..00000000 --- a/test/cryfs/impl/config/CryConfigTest.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#include -#include -#include -#include - -using namespace cryfs; -using cpputils::Data; -using cpputils::DataFixture; -using boost::none; - -class CryConfigTest: public ::testing::Test { -public: - CryConfig cfg; - - CryConfig SaveAndLoad(CryConfig cfg) { - Data configData = cfg.save(); - return CryConfig::load(configData); - } -}; - -TEST_F(CryConfigTest, RootBlob_Init) { - EXPECT_EQ("", cfg.RootBlob()); -} - -TEST_F(CryConfigTest, RootBlob) { - cfg.SetRootBlob("rootblobid"); - EXPECT_EQ("rootblobid", cfg.RootBlob()); -} - -TEST_F(CryConfigTest, RootBlob_AfterMove) { - cfg.SetRootBlob("rootblobid"); - CryConfig moved = std::move(cfg); - EXPECT_EQ("rootblobid", moved.RootBlob()); -} - -TEST_F(CryConfigTest, RootBlob_AfterCopy) { - cfg.SetRootBlob("rootblobid"); - CryConfig copy = cfg; - EXPECT_EQ("rootblobid", copy.RootBlob()); -} - -TEST_F(CryConfigTest, RootBlob_AfterSaveAndLoad) { - cfg.SetRootBlob("rootblobid"); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ("rootblobid", loaded.RootBlob()); -} - -TEST_F(CryConfigTest, EncryptionKey_Init) { - EXPECT_EQ("", cfg.EncryptionKey()); -} - -TEST_F(CryConfigTest, EncryptionKey) { - cfg.SetEncryptionKey("enckey"); - EXPECT_EQ("enckey", cfg.EncryptionKey()); -} - -TEST_F(CryConfigTest, EncryptionKey_AfterMove) { - cfg.SetEncryptionKey("enckey"); - CryConfig moved = std::move(cfg); - EXPECT_EQ("enckey", moved.EncryptionKey()); -} - -TEST_F(CryConfigTest, EncryptionKey_AfterCopy) { - cfg.SetEncryptionKey("enckey"); - CryConfig copy = cfg; - EXPECT_EQ("enckey", copy.EncryptionKey()); -} - -TEST_F(CryConfigTest, EncryptionKey_AfterSaveAndLoad) { - cfg.SetEncryptionKey("enckey"); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ("enckey", loaded.EncryptionKey()); -} - -TEST_F(CryConfigTest, Cipher_Init) { - EXPECT_EQ("", cfg.Cipher()); -} - -TEST_F(CryConfigTest, Cipher) { - cfg.SetCipher("mycipher"); - EXPECT_EQ("mycipher", cfg.Cipher()); -} - -TEST_F(CryConfigTest, Cipher_AfterMove) { - cfg.SetCipher("mycipher"); - CryConfig moved = std::move(cfg); - EXPECT_EQ("mycipher", moved.Cipher()); -} - -TEST_F(CryConfigTest, Cipher_AfterCopy) { - cfg.SetCipher("mycipher"); - CryConfig copy = cfg; - EXPECT_EQ("mycipher", copy.Cipher()); -} - -TEST_F(CryConfigTest, Cipher_AfterSaveAndLoad) { - cfg.SetCipher("mycipher"); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ("mycipher", loaded.Cipher()); -} - -TEST_F(CryConfigTest, Version_Init) { - EXPECT_EQ("", cfg.Version()); -} - -TEST_F(CryConfigTest, Version) { - cfg.SetVersion("0.9.1"); - EXPECT_EQ("0.9.1", cfg.Version()); -} - -TEST_F(CryConfigTest, Version_AfterMove) { - cfg.SetVersion("0.9.1"); - CryConfig moved = std::move(cfg); - EXPECT_EQ("0.9.1", moved.Version()); -} - -TEST_F(CryConfigTest, Version_AfterCopy) { - cfg.SetVersion("0.9.1"); - CryConfig copy = cfg; - EXPECT_EQ("0.9.1", copy.Version()); -} - -TEST_F(CryConfigTest, Version_AfterSaveAndLoad) { - cfg.SetVersion("0.9.2"); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ("0.9.2", loaded.Version()); -} - -TEST_F(CryConfigTest, CreatedWithVersion_Init) { - EXPECT_EQ("", cfg.CreatedWithVersion()); -} - -TEST_F(CryConfigTest, CreatedWithVersion) { - cfg.SetCreatedWithVersion("0.9.3"); - EXPECT_EQ("0.9.3", cfg.CreatedWithVersion()); -} - -TEST_F(CryConfigTest, CreatedWithVersion_AfterMove) { - cfg.SetCreatedWithVersion("0.9.3"); - CryConfig moved = std::move(cfg); - EXPECT_EQ("0.9.3", moved.CreatedWithVersion()); -} - -TEST_F(CryConfigTest, CreatedWithVersion_AfterCopy) { - cfg.SetCreatedWithVersion("0.9.3"); - CryConfig copy = cfg; - EXPECT_EQ("0.9.3", copy.CreatedWithVersion()); -} - -TEST_F(CryConfigTest, CreatedWithVersion_AfterSaveAndLoad) { - cfg.SetCreatedWithVersion("0.9.3"); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ("0.9.3", loaded.CreatedWithVersion()); -} - -TEST_F(CryConfigTest, BlocksizeBytes_Init) { - EXPECT_EQ(0u, cfg.BlocksizeBytes()); -} - -TEST_F(CryConfigTest, BlocksizeBytes) { - cfg.SetBlocksizeBytes(4*1024*1024); - EXPECT_EQ(4*1024*1024u, cfg.BlocksizeBytes()); -} - -TEST_F(CryConfigTest, BlocksizeBytes_AfterMove) { - cfg.SetBlocksizeBytes(32*1024); - CryConfig moved = std::move(cfg); - EXPECT_EQ(32*1024u, moved.BlocksizeBytes()); -} - -TEST_F(CryConfigTest, BlocksizeBytes_AfterCopy) { - cfg.SetBlocksizeBytes(32*1024); - CryConfig copy = cfg; - EXPECT_EQ(32*1024u, copy.BlocksizeBytes()); -} - -TEST_F(CryConfigTest, BlocksizeBytes_AfterSaveAndLoad) { - cfg.SetBlocksizeBytes(10*1024); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ(10*1024u, loaded.BlocksizeBytes()); -} - -TEST_F(CryConfigTest, FilesystemID_Init) { - EXPECT_EQ(CryConfig::FilesystemID::Null(), cfg.FilesystemId()); -} - -TEST_F(CryConfigTest, FilesystemID) { - auto fixture = DataFixture::generateFixedSize(); - cfg.SetFilesystemId(fixture); - EXPECT_EQ(fixture, cfg.FilesystemId()); -} - -TEST_F(CryConfigTest, FilesystemID_AfterMove) { - auto fixture = DataFixture::generateFixedSize(); - cfg.SetFilesystemId(fixture); - CryConfig moved = std::move(cfg); - EXPECT_EQ(fixture, moved.FilesystemId()); -} - -TEST_F(CryConfigTest, FilesystemID_AfterSaveAndLoad) { - auto fixture = DataFixture::generateFixedSize(); - cfg.SetFilesystemId(fixture); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ(fixture, loaded.FilesystemId()); -} - -TEST_F(CryConfigTest, ExclusiveClientId_Init) { - EXPECT_EQ(none, cfg.ExclusiveClientId()); -} - -TEST_F(CryConfigTest, ExclusiveClientId_Some) { - cfg.SetExclusiveClientId(0x12345678u); - EXPECT_EQ(0x12345678u, cfg.ExclusiveClientId().value()); -} - -TEST_F(CryConfigTest, ExclusiveClientId_None) { - cfg.SetExclusiveClientId(0x12345678u); - cfg.SetExclusiveClientId(none); - EXPECT_EQ(none, cfg.ExclusiveClientId()); -} - -TEST_F(CryConfigTest, ExclusiveClientId_Some_AfterMove) { - cfg.SetExclusiveClientId(0x12345678u); - CryConfig moved = std::move(cfg); - EXPECT_EQ(0x12345678u, moved.ExclusiveClientId().value()); -} - -TEST_F(CryConfigTest, ExclusiveClientId_None_AfterMove) { - cfg.SetExclusiveClientId(0x12345678u); - cfg.SetExclusiveClientId(none); - CryConfig moved = std::move(cfg); - EXPECT_EQ(none, moved.ExclusiveClientId()); -} - -TEST_F(CryConfigTest, ExclusiveClientId_Some_AfterSaveAndLoad) { - cfg.SetExclusiveClientId(0x12345678u); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ(0x12345678u, loaded.ExclusiveClientId().value()); -} - -TEST_F(CryConfigTest, ExclusiveClientId_None_AfterSaveAndLoad) { - cfg.SetExclusiveClientId(none); - CryConfig loaded = SaveAndLoad(std::move(cfg)); - EXPECT_EQ(none, loaded.ExclusiveClientId()); -} diff --git a/test/cryfs/impl/config/CryPasswordBasedKeyProviderTest.cpp b/test/cryfs/impl/config/CryPasswordBasedKeyProviderTest.cpp deleted file mode 100644 index 2bcde410..00000000 --- a/test/cryfs/impl/config/CryPasswordBasedKeyProviderTest.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include -#include "../../impl/testutils/MockConsole.h" -#include - -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::EncryptionKey; -using cpputils::PasswordBasedKDF; -using cpputils::Data; -using cpputils::DataFixture; -using std::shared_ptr; -using std::make_shared; -using std::string; -using cryfs::CryPasswordBasedKeyProvider; -using testing::Return; -using testing::Invoke; -using testing::Eq; -using testing::StrEq; -using testing::NiceMock; - -namespace { - -class MockCallable { -public: - MOCK_METHOD(std::string, call, ()); -}; - -class MockKDF : public PasswordBasedKDF { -public: - MOCK_METHOD(EncryptionKey, deriveExistingKey, (size_t keySize, const string& password, const Data& kdfParameters), (override)); - MOCK_METHOD(KeyResult, deriveNewKey, (size_t keySize, const string& password), (override)); -}; - -class CryPasswordBasedKeyProviderTest : public ::testing::Test { -public: - CryPasswordBasedKeyProviderTest() - : mockConsole(make_shared>()) - , askPasswordForNewFilesystem() - , askPasswordForExistingFilesystem() - , kdf_(make_unique_ref()) - , kdf(kdf_.get()) - , keyProvider(mockConsole, [this] () {return askPasswordForExistingFilesystem.call();}, [this] () {return askPasswordForNewFilesystem.call(); }, std::move(kdf_)) {} - - shared_ptr> mockConsole; - MockCallable askPasswordForNewFilesystem; - MockCallable askPasswordForExistingFilesystem; - unique_ref kdf_; - MockKDF* kdf; - - CryPasswordBasedKeyProvider keyProvider; -}; - -TEST_F(CryPasswordBasedKeyProviderTest, requestKeyForNewFilesystem) { - constexpr size_t keySize = 512; - constexpr const char* password = "mypassword"; - const EncryptionKey key = EncryptionKey::FromString(DataFixture::generate(keySize).ToString()); - const Data kdfParameters = DataFixture::generate(100); - - EXPECT_CALL(askPasswordForNewFilesystem, call()).Times(1).WillOnce(Return(password)); - EXPECT_CALL(askPasswordForExistingFilesystem, call()).Times(0); - EXPECT_CALL(*kdf, deriveNewKey(Eq(keySize), StrEq(password))).Times(1).WillOnce(Invoke([&] (auto, auto) {return PasswordBasedKDF::KeyResult{key, kdfParameters.copy()};})); - - auto returned_key = keyProvider.requestKeyForNewFilesystem(keySize); - - EXPECT_EQ(key.ToString(), returned_key.key.ToString()); - EXPECT_EQ(kdfParameters, returned_key.kdfParameters); -} - -TEST_F(CryPasswordBasedKeyProviderTest, requestKeyForExistingFilesystem) { - constexpr size_t keySize = 512; - constexpr const char* password = "mypassword"; - const EncryptionKey key = EncryptionKey::FromString(DataFixture::generate(keySize).ToString()); - const Data kdfParameters = DataFixture::generate(100); - - EXPECT_CALL(askPasswordForNewFilesystem, call()).Times(0); - EXPECT_CALL(askPasswordForExistingFilesystem, call()).Times(1).WillOnce(Return(password)); - EXPECT_CALL(*kdf, deriveExistingKey(Eq(keySize), StrEq(password), testing::_)).Times(1).WillOnce(Invoke([&] (auto, auto, const auto& kdfParams) { - EXPECT_EQ(kdfParameters, kdfParams); - return key; - })); - - EncryptionKey returned_key = keyProvider.requestKeyForExistingFilesystem(keySize, kdfParameters); - - EXPECT_EQ(key.ToString(), returned_key.ToString()); -} - -} diff --git a/test/cryfs/impl/config/CryPresetPasswordBasedKeyProviderTest.cpp b/test/cryfs/impl/config/CryPresetPasswordBasedKeyProviderTest.cpp deleted file mode 100644 index b8b7a9d2..00000000 --- a/test/cryfs/impl/config/CryPresetPasswordBasedKeyProviderTest.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include "../../impl/testutils/MockConsole.h" -#include - -using cpputils::make_unique_ref; -using cpputils::EncryptionKey; -using cpputils::PasswordBasedKDF; -using cpputils::Data; -using cpputils::DataFixture; -using std::string; -using cryfs::CryPresetPasswordBasedKeyProvider; -using testing::Invoke; -using testing::Eq; -using testing::StrEq; - -namespace { - -class MockKDF : public PasswordBasedKDF { -public: - MOCK_METHOD(EncryptionKey, deriveExistingKey, (size_t keySize, const string& password, const Data& kdfParameters), (override)); - MOCK_METHOD(KeyResult, deriveNewKey, (size_t keySize, const string& password), (override)); -}; - -TEST(CryPresetPasswordBasedKeyProviderTest, requestKeyForNewFilesystem) { - constexpr size_t keySize = 512; - constexpr const char* password = "mypassword"; - const EncryptionKey key = EncryptionKey::FromString(DataFixture::generate(keySize).ToString()); - auto kdf = make_unique_ref(); - const Data kdfParameters = DataFixture::generate(100); - - EXPECT_CALL(*kdf, deriveNewKey(Eq(keySize), StrEq(password))).Times(1).WillOnce(Invoke([&] (auto, auto) {return PasswordBasedKDF::KeyResult{key, kdfParameters.copy()};})); - - CryPresetPasswordBasedKeyProvider keyProvider(password, std::move(kdf)); - auto returned_key = keyProvider.requestKeyForNewFilesystem(keySize); - - EXPECT_EQ(key.ToString(), returned_key.key.ToString()); - EXPECT_EQ(kdfParameters, returned_key.kdfParameters); -} - -TEST(CryPresetPasswordBasedKeyProviderTest, requestKeyForExistingFilesystem) { - constexpr size_t keySize = 512; - constexpr const char* password = "mypassword"; - const EncryptionKey key = EncryptionKey::FromString(DataFixture::generate(keySize).ToString()); - auto kdf = make_unique_ref(); - const Data kdfParameters = DataFixture::generate(100); - - EXPECT_CALL(*kdf, deriveExistingKey(Eq(keySize), StrEq(password), testing::_)).Times(1).WillOnce(Invoke([&] (auto, auto, const auto& kdfParams) { - EXPECT_EQ(kdfParameters, kdfParams); - return key; - })); - - CryPresetPasswordBasedKeyProvider keyProvider(password, std::move(kdf)); - EncryptionKey returned_key = keyProvider.requestKeyForExistingFilesystem(keySize, kdfParameters); - - EXPECT_EQ(key.ToString(), returned_key.ToString()); -} - -} diff --git a/test/cryfs/impl/config/crypto/CryConfigEncryptorFactoryTest.cpp b/test/cryfs/impl/config/crypto/CryConfigEncryptorFactoryTest.cpp deleted file mode 100644 index 661a3028..00000000 --- a/test/cryfs/impl/config/crypto/CryConfigEncryptorFactoryTest.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include "../../../impl/testutils/FakeCryKeyProvider.h" - -using cpputils::AES256_GCM; -using cpputils::Data; -using cpputils::DataFixture; -using boost::none; -using std::ostream; -using namespace cryfs; - -// This is needed for google test -namespace boost { - inline ostream &operator<<(ostream &stream, const CryConfigEncryptor::Decrypted &) { - return stream << "CryConfigEncryptor::Decrypted()"; - } -} -#include - -class CryConfigEncryptorFactoryTest: public ::testing::Test { -public: -}; - -TEST_F(CryConfigEncryptorFactoryTest, EncryptAndDecrypt_SameEncryptor) { - FakeCryKeyProvider keyProvider; - auto encryptor = CryConfigEncryptorFactory::deriveNewKey(&keyProvider); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); - auto decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(DataFixture::generate(400), decrypted.data); -} - -TEST_F(CryConfigEncryptorFactoryTest, EncryptAndDecrypt_NewEncryptor) { - FakeCryKeyProvider keyProvider1(1); - auto encryptor = CryConfigEncryptorFactory::deriveNewKey(&keyProvider1); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); - - FakeCryKeyProvider keyProvider2(1); - auto loadedEncryptor = CryConfigEncryptorFactory::loadExistingKey(encrypted, &keyProvider2).value(); - auto decrypted = loadedEncryptor->decrypt(encrypted).value(); - EXPECT_EQ(DataFixture::generate(400), decrypted.data); -} - -TEST_F(CryConfigEncryptorFactoryTest, DoesntDecryptWithWrongKey) { - FakeCryKeyProvider keyProvider1(1); - auto encryptor = CryConfigEncryptorFactory::deriveNewKey(&keyProvider1); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); - - FakeCryKeyProvider keyProvider2(2); - auto loadedEncryptor = CryConfigEncryptorFactory::loadExistingKey(encrypted, &keyProvider2).value(); - auto decrypted = loadedEncryptor->decrypt(encrypted); - EXPECT_EQ(none, decrypted); -} - -TEST_F(CryConfigEncryptorFactoryTest, DoesntDecryptWithWrongKey_EmptyData) { - FakeCryKeyProvider keyProvider1(1); - auto encryptor = CryConfigEncryptorFactory::deriveNewKey(&keyProvider1); - Data encrypted = encryptor->encrypt(Data(0), AES256_GCM::NAME); - - FakeCryKeyProvider keyProvider2(2); - auto loadedEncryptor = CryConfigEncryptorFactory::loadExistingKey(encrypted, &keyProvider2).value(); - auto decrypted = loadedEncryptor->decrypt(encrypted); - EXPECT_EQ(none, decrypted); -} - -TEST_F(CryConfigEncryptorFactoryTest, DoesntDecryptInvalidData) { - FakeCryKeyProvider keyProvider; - auto loadedEncryptor = CryConfigEncryptorFactory::loadExistingKey(Data(0), &keyProvider); - EXPECT_EQ(none, loadedEncryptor); -} diff --git a/test/cryfs/impl/config/crypto/CryConfigEncryptorTest.cpp b/test/cryfs/impl/config/crypto/CryConfigEncryptorTest.cpp deleted file mode 100644 index d657ed36..00000000 --- a/test/cryfs/impl/config/crypto/CryConfigEncryptorTest.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include - -using std::ostream; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::DataFixture; -using cpputils::Data; -using cpputils::EncryptionKey; -using cpputils::AES128_CFB; -using cpputils::AES256_GCM; -using cpputils::Twofish256_GCM; -using cpputils::Twofish128_CFB; -using cpputils::serialize; -using cpputils::deserialize; -using boost::none; -using namespace cryfs; - -// This is needed for google test -namespace boost { - inline ostream &operator<<(ostream &stream, const CryConfigEncryptor::Decrypted &) { - return stream << "CryConfigEncryptor::Decrypted()"; - } -} -#include - -class CryConfigEncryptorTest: public ::testing::Test { -public: - - unique_ref makeEncryptor() { - return make_unique_ref(_derivedKey(), _kdfParameters()); - } - - Data changeInnerCipherFieldTo(Data data, const string &newCipherName) { - InnerConfig innerConfig = _decryptInnerConfig(data); - innerConfig.cipherName = newCipherName; - return _encryptInnerConfig(innerConfig); - } - -private: - EncryptionKey _derivedKey() { - return EncryptionKey::FromString( - DataFixture::generateFixedSize(3).ToString() - ); - } - - Data _kdfParameters() { - return DataFixture::generate(128, 2); - } - - unique_ref _outerEncryptor() { - auto outerKey = _derivedKey().take(CryConfigEncryptor::OuterKeySize); - return make_unique_ref(outerKey, _kdfParameters()); - } - - InnerConfig _decryptInnerConfig(const Data &data) { - OuterConfig outerConfig = OuterConfig::deserialize(data).value(); - Data serializedInnerConfig = _outerEncryptor()->decrypt(outerConfig).value(); - return InnerConfig::deserialize(serializedInnerConfig).value(); - } - - Data _encryptInnerConfig(const InnerConfig &innerConfig) { - Data serializedInnerConfig = innerConfig.serialize(); - OuterConfig outerConfig = _outerEncryptor()->encrypt(serializedInnerConfig); - return outerConfig.serialize(); - } -}; - -TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Data_AES) { - auto encryptor = makeEncryptor(); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); - auto decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(DataFixture::generate(400), decrypted.data); -} - -TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Data_Twofish) { - auto encryptor = makeEncryptor(); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), Twofish128_CFB::NAME); - auto decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(DataFixture::generate(400), decrypted.data); -} - -TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Cipher_AES) { - auto encryptor = makeEncryptor(); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); - auto decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(AES256_GCM::NAME, decrypted.cipherName); -} - -TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_Cipher_Twofish) { - auto encryptor = makeEncryptor(); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), Twofish128_CFB::NAME); - auto decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(Twofish128_CFB::NAME, decrypted.cipherName); -} - -TEST_F(CryConfigEncryptorTest, EncryptAndDecrypt_EmptyData) { - auto encryptor = makeEncryptor(); - Data encrypted = encryptor->encrypt(Data(0), AES256_GCM::NAME); - auto decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(Data(0), decrypted.data); -} - -TEST_F(CryConfigEncryptorTest, InvalidCiphertext) { - auto encryptor = makeEncryptor(); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); - serialize(encrypted.data(), deserialize(encrypted.data()) + 1); //Modify ciphertext - auto decrypted = encryptor->decrypt(encrypted); - EXPECT_EQ(none, decrypted); -} - -TEST_F(CryConfigEncryptorTest, DoesntEncryptWhenTooLarge) { - auto encryptor = makeEncryptor(); - EXPECT_THROW( - encryptor->encrypt(DataFixture::generate(2000), AES256_GCM::NAME), - std::runtime_error - ); -} - -TEST_F(CryConfigEncryptorTest, EncryptionIsFixedSize) { - auto encryptor = makeEncryptor(); - Data encrypted1 = encryptor->encrypt(DataFixture::generate(100), AES128_CFB::NAME); - Data encrypted2 = encryptor->encrypt(DataFixture::generate(200), Twofish256_GCM::NAME); - Data encrypted3 = encryptor->encrypt(Data(0), AES256_GCM::NAME); - - EXPECT_EQ(encrypted1.size(), encrypted2.size()); - EXPECT_EQ(encrypted1.size(), encrypted3.size()); -} - -TEST_F(CryConfigEncryptorTest, SpecifiedInnerCipherIsUsed) { - //Tests that it can't be decrypted if the inner cipher field stores the wrong cipher - auto encryptor = makeEncryptor(); - Data encrypted = encryptor->encrypt(DataFixture::generate(400), AES256_GCM::NAME); - encrypted = changeInnerCipherFieldTo(std::move(encrypted), Twofish256_GCM::NAME); - auto decrypted = encryptor->decrypt(encrypted); - EXPECT_EQ(none, decrypted); -} diff --git a/test/cryfs/impl/config/crypto/inner/ConcreteInnerEncryptorTest.cpp b/test/cryfs/impl/config/crypto/inner/ConcreteInnerEncryptorTest.cpp deleted file mode 100644 index 6157e790..00000000 --- a/test/cryfs/impl/config/crypto/inner/ConcreteInnerEncryptorTest.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include - -using std::ostream; -using boost::none; -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::AES256_GCM; -using cpputils::AES256_CFB; -using cpputils::Twofish128_CFB; -using cpputils::serialize; -using cpputils::deserialize; -using namespace cryfs; - -// This is needed for google test -namespace boost { - inline ostream &operator<<(ostream &stream, const Data &) { - return stream << "cpputils::Data()"; - } -} -#include - -class ConcreteInnerEncryptorTest : public ::testing::Test { -public: - template - unique_ref makeInnerEncryptor() { - auto key = Cipher::EncryptionKey::FromString( - DataFixture::generateFixedSize().ToString() - ); - return make_unique_ref>(key); - } -}; - -TEST_F(ConcreteInnerEncryptorTest, EncryptAndDecrypt_AES) { - auto encryptor = makeInnerEncryptor(); - InnerConfig encrypted = encryptor->encrypt(DataFixture::generate(200)); - Data decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(DataFixture::generate(200), decrypted); -} - -TEST_F(ConcreteInnerEncryptorTest, EncryptAndDecrypt_Twofish) { - auto encryptor = makeInnerEncryptor(); - InnerConfig encrypted = encryptor->encrypt(DataFixture::generate(200)); - Data decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(DataFixture::generate(200), decrypted); -} - -TEST_F(ConcreteInnerEncryptorTest, EncryptAndDecrypt_EmptyData) { - auto encryptor = makeInnerEncryptor(); - InnerConfig encrypted = encryptor->encrypt(Data(0)); - Data decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(Data(0), decrypted); -} - -TEST_F(ConcreteInnerEncryptorTest, DoesntDecryptWithWrongCipherName) { - auto encryptor = makeInnerEncryptor(); - InnerConfig encrypted = encryptor->encrypt(Data(0)); - encrypted.cipherName = AES256_CFB::NAME; - auto decrypted = encryptor->decrypt(encrypted); - EXPECT_EQ(none, decrypted); -} - -TEST_F(ConcreteInnerEncryptorTest, InvalidCiphertext) { - auto encryptor = makeInnerEncryptor(); - InnerConfig encrypted = encryptor->encrypt(DataFixture::generate(200)); - serialize(encrypted.encryptedConfig.data(), deserialize(encrypted.encryptedConfig.data()) + 1); //Modify ciphertext - auto decrypted = encryptor->decrypt(encrypted); - EXPECT_EQ(none, decrypted); -} - -TEST_F(ConcreteInnerEncryptorTest, DoesntEncryptWhenTooLarge) { - auto encryptor = makeInnerEncryptor(); - EXPECT_THROW( - encryptor->encrypt(DataFixture::generate(2000)), - std::runtime_error - ); -} - -TEST_F(ConcreteInnerEncryptorTest, EncryptionIsFixedSize) { - auto encryptor = makeInnerEncryptor(); - InnerConfig encrypted1 = encryptor->encrypt(DataFixture::generate(100)); - InnerConfig encrypted2 = encryptor->encrypt(DataFixture::generate(200)); - InnerConfig encrypted3 = encryptor->encrypt(Data(0)); - - EXPECT_EQ(encrypted1.encryptedConfig.size(), encrypted2.encryptedConfig.size()); - EXPECT_EQ(encrypted1.encryptedConfig.size(), encrypted3.encryptedConfig.size()); -} diff --git a/test/cryfs/impl/config/crypto/inner/InnerConfigTest.cpp b/test/cryfs/impl/config/crypto/inner/InnerConfigTest.cpp deleted file mode 100644 index 3f1ebcac..00000000 --- a/test/cryfs/impl/config/crypto/inner/InnerConfigTest.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include - -using cpputils::Data; -using cpputils::DataFixture; -using boost::none; -using std::ostream; -using namespace cryfs; - -// This is needed for google test -namespace boost { - ostream &operator<<(ostream &stream, const InnerConfig &config) { - return stream << "InnerConfig(" << config.cipherName << ", [data])"; - } -} -#include - -TEST(InnerConfigTest, SomeValues) { - Data serialized = InnerConfig{"myciphername", DataFixture::generate(1024)}.serialize(); - InnerConfig deserialized = InnerConfig::deserialize(serialized).value(); - EXPECT_EQ("myciphername", deserialized.cipherName); - EXPECT_EQ(DataFixture::generate(1024), deserialized.encryptedConfig); -} - -TEST(InnerConfigTest, DataEmpty) { - Data serialized = InnerConfig{"myciphername", Data(0)}.serialize(); - InnerConfig deserialized = InnerConfig::deserialize(serialized).value(); - EXPECT_EQ("myciphername", deserialized.cipherName); - EXPECT_EQ(Data(0), deserialized.encryptedConfig); -} - -TEST(InnerConfigTest, CipherNameEmpty) { - Data serialized = InnerConfig{"", DataFixture::generate(1024)}.serialize(); - InnerConfig deserialized = InnerConfig::deserialize(serialized).value(); - EXPECT_EQ("", deserialized.cipherName); - EXPECT_EQ(DataFixture::generate(1024), deserialized.encryptedConfig); -} - -TEST(InnerConfigTest, DataAndCipherNameEmpty) { - Data serialized = InnerConfig{"", Data(0)}.serialize(); - InnerConfig deserialized = InnerConfig::deserialize(serialized).value(); - EXPECT_EQ("", deserialized.cipherName); - EXPECT_EQ(Data(0), deserialized.encryptedConfig); -} - -TEST(InnerConfigTest, InvalidSerialization) { - auto deserialized = InnerConfig::deserialize(DataFixture::generate(1024)); - EXPECT_EQ(none, deserialized); -} diff --git a/test/cryfs/impl/config/crypto/outer/OuterConfigTest.cpp b/test/cryfs/impl/config/crypto/outer/OuterConfigTest.cpp deleted file mode 100644 index ba2068b0..00000000 --- a/test/cryfs/impl/config/crypto/outer/OuterConfigTest.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include - -using cpputils::Data; -using cpputils::DataFixture; -using boost::none; -using std::ostream; -using namespace cryfs; - -// This is needed for google test -namespace boost { - ostream &operator<<(ostream &stream, const OuterConfig &) { - return stream << "OuterConfig()"; - } -} -#include - -class OuterConfigTest: public ::testing::Test { -public: - Data kdfParameters() { - return DataFixture::generate(128, 2); - } -}; - -TEST_F(OuterConfigTest, SomeValues) { - Data serialized = OuterConfig{kdfParameters(), DataFixture::generate(1024), false}.serialize(); - OuterConfig deserialized = OuterConfig::deserialize(serialized).value(); - EXPECT_EQ(kdfParameters(), deserialized.kdfParameters); - EXPECT_EQ(DataFixture::generate(1024), deserialized.encryptedInnerConfig); -} - -TEST_F(OuterConfigTest, DataEmpty) { - Data serialized = OuterConfig{kdfParameters(), Data(0), false}.serialize(); - OuterConfig deserialized = OuterConfig::deserialize(serialized).value(); - EXPECT_EQ(kdfParameters(), deserialized.kdfParameters); - EXPECT_EQ(Data(0), deserialized.encryptedInnerConfig); -} - -TEST_F(OuterConfigTest, KeyConfigEmpty) { - Data serialized = OuterConfig{Data(0), DataFixture::generate(1024), false}.serialize(); - OuterConfig deserialized = OuterConfig::deserialize(serialized).value(); - EXPECT_EQ(Data(0), deserialized.kdfParameters); - EXPECT_EQ(DataFixture::generate(1024), deserialized.encryptedInnerConfig); -} - -TEST_F(OuterConfigTest, DataAndKeyConfigEmpty) { - Data serialized = OuterConfig{Data(0), Data(0), false}.serialize(); - OuterConfig deserialized = OuterConfig::deserialize(serialized).value(); - EXPECT_EQ(Data(0), deserialized.kdfParameters); - EXPECT_EQ(Data(0), deserialized.encryptedInnerConfig); -} - -TEST_F(OuterConfigTest, InvalidSerialization) { - auto deserialized = OuterConfig::deserialize(DataFixture::generate(1024)); - EXPECT_EQ(none, deserialized); -} diff --git a/test/cryfs/impl/config/crypto/outer/OuterEncryptorTest.cpp b/test/cryfs/impl/config/crypto/outer/OuterEncryptorTest.cpp deleted file mode 100644 index 412fc726..00000000 --- a/test/cryfs/impl/config/crypto/outer/OuterEncryptorTest.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include -#include - -using std::ostream; -using boost::none; -using cpputils::Data; -using cpputils::DataFixture; -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::serialize; -using cpputils::deserialize; -using namespace cryfs; - -// This is needed for google test -namespace boost { - inline ostream &operator<<(ostream &stream, const Data &) { - return stream << "cpputils::Data()"; - } -} -#include - -class OuterEncryptorTest : public ::testing::Test { -public: - Data kdfParameters() { - return DataFixture::generate(128); - } - - unique_ref makeOuterEncryptor() { - auto key = OuterEncryptor::Cipher::EncryptionKey::FromString( - DataFixture::generateFixedSize().ToString() - ); - return make_unique_ref(key, kdfParameters()); - } -}; - -TEST_F(OuterEncryptorTest, EncryptAndDecrypt) { - auto encryptor = makeOuterEncryptor(); - OuterConfig encrypted = encryptor->encrypt(DataFixture::generate(200)); - Data decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(DataFixture::generate(200), decrypted); -} - -TEST_F(OuterEncryptorTest, EncryptAndDecrypt_EmptyData) { - auto encryptor = makeOuterEncryptor(); - OuterConfig encrypted = encryptor->encrypt(Data(0)); - Data decrypted = encryptor->decrypt(encrypted).value(); - EXPECT_EQ(Data(0), decrypted); -} - -TEST_F(OuterEncryptorTest, InvalidCiphertext) { - auto encryptor = makeOuterEncryptor(); - OuterConfig encrypted = encryptor->encrypt(DataFixture::generate(200)); - serialize(encrypted.encryptedInnerConfig.data(), deserialize(encrypted.encryptedInnerConfig.data()) + 1); //Modify ciphertext - auto decrypted = encryptor->decrypt(encrypted); - EXPECT_EQ(none, decrypted); -} - -TEST_F(OuterEncryptorTest, DoesntEncryptWhenTooLarge) { - auto encryptor = makeOuterEncryptor(); - EXPECT_THROW( - encryptor->encrypt(DataFixture::generate(2000)), - std::runtime_error - ); -} - -TEST_F(OuterEncryptorTest, EncryptionIsFixedSize) { - auto encryptor = makeOuterEncryptor(); - OuterConfig encrypted1 = encryptor->encrypt(DataFixture::generate(200)); - OuterConfig encrypted2 = encryptor->encrypt(DataFixture::generate(700)); - OuterConfig encrypted3 = encryptor->encrypt(Data(0)); - - EXPECT_EQ(encrypted1.encryptedInnerConfig.size(), encrypted2.encryptedInnerConfig.size()); - EXPECT_EQ(encrypted1.encryptedInnerConfig.size(), encrypted3.encryptedInnerConfig.size()); -} diff --git a/test/cryfs/impl/filesystem/CryFsTest.cpp b/test/cryfs/impl/filesystem/CryFsTest.cpp deleted file mode 100644 index e44e79f0..00000000 --- a/test/cryfs/impl/filesystem/CryFsTest.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../testutils/MockConsole.h" -#include -#include -#include -#include "../testutils/TestWithFakeHomeDirectory.h" -#include - -//TODO (whole project) Make constructors explicit when implicit construction not needed - -using ::testing::Test; -using std::make_shared; -using std::shared_ptr; -using cpputils::TempDir; -using cpputils::TempFile; -using cpputils::make_unique_ref; -using cpputils::unique_ref; -using cpputils::Random; -using cpputils::SCrypt; -using cpputils::Data; -using cpputils::NoninteractiveConsole; -using blockstore::ondisk::OnDiskBlockStore2; -using boost::none; -using cryfs::CryPresetPasswordBasedKeyProvider; - -namespace bf = boost::filesystem; -using namespace cryfs; - -namespace { - -class CryFsTest: public Test, public TestWithMockConsole, public TestWithFakeHomeDirectory { -public: - CryFsTest(): tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), rootdir(), config(false) { - } - - shared_ptr loadOrCreateConfig() { - auto keyProvider = make_unique_ref("mypassword", make_unique_ref(SCrypt::TestSettings)); - return CryConfigLoader(make_shared(mockConsole()), Random::PseudoRandom(), std::move(keyProvider), localStateDir, none, none, none).loadOrCreate(config.path(), false, false).right().configFile; - } - - unique_ref blockStore() { - return make_unique_ref(rootdir.path()); - } - - cpputils::TempDir tempLocalStateDir; - LocalStateDir localStateDir; - TempDir rootdir; - TempFile config; -}; - -auto failOnIntegrityViolation() { - return [] { - EXPECT_TRUE(false); - }; -} - -TEST_F(CryFsTest, CreatedRootdirIsLoadableAfterClosing) { - { - CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation()); - dev.setContext(fspp::Context {fspp::relatime()}); - } - CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation()); - dev.setContext(fspp::Context {fspp::relatime()}); - auto rootDir = dev.LoadDir(bf::path("/")); - rootDir.value()->children(); -} - -TEST_F(CryFsTest, LoadingFilesystemDoesntModifyConfigFile) { - { - CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation()); - dev.setContext(fspp::Context {fspp::relatime()}); - } - Data configAfterCreating = Data::LoadFromFile(config.path()).value(); - { - CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false, failOnIntegrityViolation()); - dev.setContext(fspp::Context {fspp::relatime()}); - } - Data configAfterLoading = Data::LoadFromFile(config.path()).value(); - EXPECT_EQ(configAfterCreating, configAfterLoading); -} - -} diff --git a/test/cryfs/impl/filesystem/CryNodeTest.cpp b/test/cryfs/impl/filesystem/CryNodeTest.cpp deleted file mode 100644 index 7b4b1bc6..00000000 --- a/test/cryfs/impl/filesystem/CryNodeTest.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include "testutils/CryTestBase.h" -#include -#include -#include - -using cpputils::unique_ref; -using cpputils::dynamic_pointer_move; -using namespace cryfs; -namespace bf = boost::filesystem; - -// Many generic (black box) test cases for FsppNode are covered in Fspp fstest. -// This class adds some tests that need insight into how CryFS works. - -class CryNodeTest : public ::testing::Test, public CryTestBase { -public: - static constexpr fspp::mode_t MODE_PUBLIC = fspp::mode_t() - .addUserReadFlag().addUserWriteFlag().addUserExecFlag() - .addGroupReadFlag().addGroupWriteFlag().addGroupExecFlag() - .addOtherReadFlag().addOtherWriteFlag().addOtherExecFlag(); - - unique_ref CreateFile(const bf::path &path) { - auto parentDir = device().LoadDir(path.parent_path()).value(); - parentDir->createAndOpenFile(path.filename().string(), MODE_PUBLIC, fspp::uid_t(0), fspp::gid_t(0)); - auto file = device().Load(path).value(); - return dynamic_pointer_move(file).value(); - } - - unique_ref CreateDir(const bf::path &path) { - auto _parentDir = device().Load(path.parent_path()).value(); - auto parentDir = dynamic_pointer_move(_parentDir).value(); - parentDir->createDir(path.filename().string(), MODE_PUBLIC, fspp::uid_t(0), fspp::gid_t(0)); - auto createdDir = device().Load(path).value(); - return dynamic_pointer_move(createdDir).value(); - } - - unique_ref CreateSymlink(const bf::path &path) { - auto _parentDir = device().Load(path.parent_path()).value(); - auto parentDir = dynamic_pointer_move(_parentDir).value(); - parentDir->createSymlink(path.filename().string(), "/target", fspp::uid_t(0), fspp::gid_t(0)); - auto createdSymlink = device().Load(path).value(); - return dynamic_pointer_move(createdSymlink).value(); - } -}; -constexpr fspp::mode_t CryNodeTest::MODE_PUBLIC; - -TEST_F(CryNodeTest, Rename_DoesntLeaveBlocksOver) { - auto node = CreateFile("/oldname"); - EXPECT_EQ(2u, device().numBlocks()); // In the beginning, there is two blocks (the root block and the created file). If that is not true anymore, we'll have to adapt the test case. - node->rename("/newname"); - EXPECT_EQ(2u, device().numBlocks()); // Still same number of blocks -} - -// TODO Add similar test cases (i.e. checking number of blocks) for other situations in rename, and also for other operations (e.g. deleting files). - -TEST_F(CryNodeTest, Rename_Overwrite_DoesntLeaveBlocksOver) { - auto node = CreateFile("/oldname"); - CreateFile("/newexistingname"); - EXPECT_EQ(3u, device().numBlocks()); // In the beginning, there is three blocks (the root block and the two created files). If that is not true anymore, we'll have to adapt the test case. - node->rename("/newexistingname"); - EXPECT_EQ(2u, device().numBlocks()); // Only the blocks of one file are left -} - -TEST_F(CryNodeTest, Rename_UpdatesParentPointers_File) { - this->CreateDir("/mydir"); - auto node = this->CreateFile("/oldname"); - node->rename("/mydir/newname"); - EXPECT_TRUE(node->checkParentPointer()); -} - -TEST_F(CryNodeTest, Rename_UpdatesParentPointers_Dir) { - this->CreateDir("/mydir"); - auto node = this->CreateDir("/oldname"); - node->rename("/mydir/newname"); - EXPECT_TRUE(node->checkParentPointer()); -} - -TEST_F(CryNodeTest, Rename_UpdatesParentPointers_Symlink) { - this->CreateDir("/mydir"); - auto node = this->CreateSymlink("/oldname"); - node->rename("/mydir/newname"); - EXPECT_TRUE(node->checkParentPointer()); -} diff --git a/test/cryfs/impl/filesystem/FileSystemTest.cpp b/test/cryfs/impl/filesystem/FileSystemTest.cpp deleted file mode 100644 index 45be78da..00000000 --- a/test/cryfs/impl/filesystem/FileSystemTest.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "../testutils/MockConsole.h" -#include "../testutils/TestWithFakeHomeDirectory.h" - -using cpputils::unique_ref; -using cpputils::make_unique_ref; -using cpputils::Random; -using cpputils::SCrypt; -using cpputils::NoninteractiveConsole; -using fspp::Device; -using boost::none; -using std::make_shared; -using blockstore::inmemory::InMemoryBlockStore2; -using cryfs::CryPresetPasswordBasedKeyProvider; - -using namespace cryfs; - -namespace { - -auto failOnIntegrityViolation() { - return [] { - EXPECT_TRUE(false); - }; -} - -class CryFsTestFixture: public FileSystemTestFixture, public TestWithMockConsole, public TestWithFakeHomeDirectory { -public: - CryFsTestFixture() - // Don't create config tempfile yet - : tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), configFile(false) {} - - unique_ref createDevice() override { - auto blockStore = cpputils::make_unique_ref(); - auto _console = make_shared(mockConsole()); - auto keyProvider = make_unique_ref("mypassword", make_unique_ref(SCrypt::TestSettings)); - auto config = CryConfigLoader(_console, Random::PseudoRandom(), std::move(keyProvider), localStateDir, none, none, none) - .loadOrCreate(configFile.path(), false, false).right(); - return make_unique_ref(std::move(config.configFile), std::move(blockStore), localStateDir, config.myClientId, false, false, failOnIntegrityViolation()); - } - - cpputils::TempDir tempLocalStateDir; - LocalStateDir localStateDir; - cpputils::TempFile configFile; -}; - -FSPP_ADD_FILESYTEM_TESTS(CryFS, CryFsTestFixture); -} diff --git a/test/cryfs/impl/filesystem/testutils/CryTestBase.h b/test/cryfs/impl/filesystem/testutils/CryTestBase.h deleted file mode 100644 index 7eb91928..00000000 --- a/test/cryfs/impl/filesystem/testutils/CryTestBase.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef MESSMER_CRYFS_TEST_CRYFS_FILESYSTEM_CRYTESTBASE_H -#define MESSMER_CRYFS_TEST_CRYFS_FILESYSTEM_CRYTESTBASE_H - -#include -#include -#include -#include -#include -#include "../../testutils/TestWithFakeHomeDirectory.h" -#include "../../testutils/MockConsole.h" - -inline auto failOnIntegrityViolation() { - return [] { - EXPECT_TRUE(false); - }; -} - -class CryTestBase : public TestWithFakeHomeDirectory { -public: - CryTestBase(): _tempLocalStateDir(), _localStateDir(_tempLocalStateDir.path()), _configFile(false), _device(nullptr) { - auto fakeBlockStore = cpputils::make_unique_ref(); - _device = std::make_unique(configFile(), std::move(fakeBlockStore), _localStateDir, 0x12345678, false, false, failOnIntegrityViolation()); - _device->setContext(fspp::Context { fspp::relatime() }); - } - - std::shared_ptr configFile() { - cryfs::CryConfig config; - config.SetCipher("aes-256-gcm"); - config.SetEncryptionKey(cpputils::AES256_GCM::EncryptionKey::CreateKey(cpputils::Random::PseudoRandom(), cpputils::AES256_GCM::KEYSIZE).ToString()); - config.SetBlocksizeBytes(10240); - cryfs::CryPresetPasswordBasedKeyProvider keyProvider("mypassword", cpputils::make_unique_ref(cpputils::SCrypt::TestSettings)); - return cryfs::CryConfigFile::create(_configFile.path(), std::move(config), &keyProvider); - } - - cryfs::CryDevice &device() { - return *_device; - } - -private: - cpputils::TempDir _tempLocalStateDir; - cryfs::LocalStateDir _localStateDir; - cpputils::TempFile _configFile; - std::unique_ptr _device; -}; - -#endif diff --git a/test/cryfs/impl/localstate/BasedirMetadataTest.cpp b/test/cryfs/impl/localstate/BasedirMetadataTest.cpp deleted file mode 100644 index f79cb2b1..00000000 --- a/test/cryfs/impl/localstate/BasedirMetadataTest.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include - -#include -#include -#include -#include -#include "../testutils/TestWithFakeHomeDirectory.h" - -using cpputils::TempDir; -using cryfs::BasedirMetadata; -using std::ofstream; -namespace bf = boost::filesystem; -using FilesystemID = cryfs::CryConfig::FilesystemID ; - -class BasedirMetadataTest : public ::testing::Test, TestWithFakeHomeDirectory { -public: - TempDir tempLocalStateDir; - cryfs::LocalStateDir localStateDir; - - TempDir tempdir; - bf::path basedir1; - bf::path basedir2; - const FilesystemID id1; - const FilesystemID id2; - - BasedirMetadataTest() - : tempLocalStateDir() - , localStateDir(tempLocalStateDir.path()) - , tempdir() - , basedir1(tempdir.path() / "my/basedir") - , basedir2(tempdir.path() / "my/other/basedir") - , id1(FilesystemID::FromString("1491BB4932A389EE14BC7090AC772972")) - , id2(FilesystemID::FromString("A1491BB493214BC7090C772972A389EE")) - { - // Create basedirs so bf::canonical() works - bf::create_directories(basedir1); - bf::create_directories(basedir2); - } - -}; - -TEST_F(BasedirMetadataTest, givenEmptyState_whenCalled_thenSucceeds) { - EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); -} - -TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledForDifferentBasedir_thenSucceeds) { - BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir2, id1).save(); - EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); -} - -TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithSameId_thenSucceeds) { - BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save(); - EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); -} - -TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithDifferentId_thenFails) { - BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save(); - EXPECT_FALSE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); -} - -TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithSameId_thenSucceeds) { - BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save(); - BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save(); - EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); -} - -TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithDifferentId_thenFails) { - BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save(); - BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save(); - EXPECT_FALSE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id2)); -} diff --git a/test/cryfs/impl/localstate/LocalStateMetadataTest.cpp b/test/cryfs/impl/localstate/LocalStateMetadataTest.cpp deleted file mode 100644 index c32aa700..00000000 --- a/test/cryfs/impl/localstate/LocalStateMetadataTest.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#include -#include -#include -#include - -using cpputils::TempDir; -using cpputils::Data; -using cryfs::LocalStateMetadata; -using cpputils::DataFixture; -using std::ofstream; - -class LocalStateMetadataTest : public ::testing::Test { -public: - TempDir stateDir; - TempDir stateDir2; -}; - -TEST_F(LocalStateMetadataTest, myClientId_ValueIsConsistent) { - LocalStateMetadata metadata1 = LocalStateMetadata::loadOrGenerate(stateDir.path(), Data(0), false); - LocalStateMetadata metadata2 = LocalStateMetadata::loadOrGenerate(stateDir.path(), Data(0), false); - EXPECT_EQ(metadata1.myClientId(), metadata2.myClientId()); -} - -TEST_F(LocalStateMetadataTest, myClientId_ValueIsRandomForNewClient) { - LocalStateMetadata metadata1 = LocalStateMetadata::loadOrGenerate(stateDir.path(), Data(0), false); - LocalStateMetadata metadata2 = LocalStateMetadata::loadOrGenerate(stateDir2.path(), Data(0), false); - EXPECT_NE(metadata1.myClientId(), metadata2.myClientId()); -} - -#ifndef CRYFS_NO_COMPATIBILITY -TEST_F(LocalStateMetadataTest, myClientId_TakesLegacyValueIfSpecified) { - ofstream file((stateDir.path() / "myClientId").string()); - file << 12345u; - file.close(); - - LocalStateMetadata metadata = LocalStateMetadata::loadOrGenerate(stateDir.path(), Data(0), false); - EXPECT_EQ(12345u, metadata.myClientId()); -} -#endif - -TEST_F(LocalStateMetadataTest, encryptionKeyHash_whenLoadingWithSameKey_thenDoesntCrash) { - LocalStateMetadata::loadOrGenerate(stateDir.path(), DataFixture::generate(1024), false); - LocalStateMetadata::loadOrGenerate(stateDir.path(), DataFixture::generate(1024), false); -} - -TEST_F(LocalStateMetadataTest, encryptionKeyHash_whenLoadingWithDifferentKey_thenCrashes) { - LocalStateMetadata::loadOrGenerate(stateDir.path(), DataFixture::generate(1024, 1), false); - EXPECT_THROW( - LocalStateMetadata::loadOrGenerate(stateDir.path(), DataFixture::generate(1024, 2), false), - std::runtime_error - ); -} diff --git a/test/cryfs/impl/testutils/FakeCryKeyProvider.h b/test/cryfs/impl/testutils/FakeCryKeyProvider.h deleted file mode 100644 index cda4d3cf..00000000 --- a/test/cryfs/impl/testutils/FakeCryKeyProvider.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#ifndef CRYFS_FAKECRYKEYPROVIDER_H -#define CRYFS_FAKECRYKEYPROVIDER_H - -#include -#include - -class FakeCryKeyProvider final : public cryfs::CryKeyProvider { -private: - static constexpr const unsigned char KDF_TEST_PARAMETERS = 5; // test value to check that kdf parameters are passed in correctly -public: - FakeCryKeyProvider(unsigned char keySeed = 0): _keySeed(keySeed) {} - - cpputils::EncryptionKey requestKeyForExistingFilesystem(size_t keySize, const cpputils::Data& kdfParameters) override { - ASSERT(kdfParameters.size() == 1 && *reinterpret_cast(kdfParameters.data()) == KDF_TEST_PARAMETERS, "Wrong kdf parameters"); - - return cpputils::EncryptionKey::FromString(cpputils::DataFixture::generate(keySize, _keySeed).ToString()); - } - - KeyResult requestKeyForNewFilesystem(size_t keySize) override { - cpputils::Data kdfParameters(sizeof(unsigned char)); - *reinterpret_cast(kdfParameters.data()) = KDF_TEST_PARAMETERS; - - auto key = requestKeyForExistingFilesystem(keySize, kdfParameters); - return KeyResult{ - std::move(key), - std::move(kdfParameters) - }; - } - -private: - unsigned char _keySeed; -}; - -#endif diff --git a/test/cryfs/impl/testutils/MockConsole.h b/test/cryfs/impl/testutils/MockConsole.h deleted file mode 100644 index 9b22eac6..00000000 --- a/test/cryfs/impl/testutils/MockConsole.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#ifndef MESSMER_CRYFS_TEST_TESTUTILS_MOCKCONSOLE_H -#define MESSMER_CRYFS_TEST_TESTUTILS_MOCKCONSOLE_H - -#include -#include - -class MockConsole: public cpputils::Console { -public: - MOCK_METHOD(void, print, (const std::string&), (override)); - MOCK_METHOD(unsigned int, ask, (const std::string&, const std::vector&), (override)); - MOCK_METHOD(bool, askYesNo, (const std::string&, bool), (override)); - MOCK_METHOD(std::string, askPassword, (const std::string&), (override)); -}; - -ACTION_P(ChooseCipher, cipherName) { - return std::find(arg1.begin(), arg1.end(), cipherName) - arg1.begin(); -} - -#define ChooseAnyCipher() ChooseCipher("aes-256-gcm") - -class TestWithMockConsole { -public: - // Return a console that chooses a valid cryfs setting - static std::shared_ptr mockConsole() { - auto console = std::make_shared<::testing::NiceMock>(); - EXPECT_CALL(*console, ask(::testing::_, ::testing::_)).WillRepeatedly(ChooseCipher("aes-256-gcm")); - EXPECT_CALL(*console, askYesNo(::testing::_, ::testing::_)).WillRepeatedly(::testing::Return(true)); - return console; - } -}; - -#endif diff --git a/test/cryfs/impl/testutils/MockCryKeyProvider.h b/test/cryfs/impl/testutils/MockCryKeyProvider.h deleted file mode 100644 index 1cfb4ce7..00000000 --- a/test/cryfs/impl/testutils/MockCryKeyProvider.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#ifndef CRYFS_MOCKCRYKEYPROVIDER_H -#define CRYFS_MOCKCRYKEYPROVIDER_H - -#include -#include - -class MockCryKeyProvider: public cryfs::CryKeyProvider { -public: - MOCK_METHOD(cpputils::EncryptionKey, requestKeyForExistingFilesystem, (size_t keySize, const cpputils::Data& kdfParameters), (override)); - MOCK_METHOD(cryfs::CryKeyProvider::KeyResult, requestKeyForNewFilesystem, (size_t keySize), (override)); -}; - -#endif diff --git a/test/cryfs/impl/testutils/TestWithFakeHomeDirectory.h b/test/cryfs/impl/testutils/TestWithFakeHomeDirectory.h deleted file mode 100644 index b2e979ab..00000000 --- a/test/cryfs/impl/testutils/TestWithFakeHomeDirectory.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#ifndef MESSMER_CRYFS_TEST_TESTUTILS_TESTWITHFAKEHOMEDIRECTORY_H -#define MESSMER_CRYFS_TEST_TESTUTILS_TESTWITHFAKEHOMEDIRECTORY_H - -#include -#include - -class TestWithFakeHomeDirectory { -private: - cpputils::system::FakeTempHomeDirectoryRAII fakeHomeDirRAII; -}; - -#endif diff --git a/test/fspp/CMakeLists.txt b/test/fspp/CMakeLists.txt deleted file mode 100644 index c6f2e32c..00000000 --- a/test/fspp/CMakeLists.txt +++ /dev/null @@ -1,110 +0,0 @@ -project (fspp-test) - -set(SOURCES - testutils/FuseTest.cpp - testutils/FuseThread.cpp - testutils/InMemoryFile.cpp - impl/FuseOpenFileListTest.cpp - impl/IdListTest.cpp - fuse/lstat/FuseLstatReturnUidTest.cpp - fuse/lstat/testutils/FuseLstatTest.cpp - fuse/lstat/FuseLstatReturnCtimeTest.cpp - fuse/lstat/FuseLstatReturnGidTest.cpp - fuse/lstat/FuseLstatPathParameterTest.cpp - fuse/lstat/FuseLstatReturnNlinkTest.cpp - fuse/lstat/FuseLstatReturnModeTest.cpp - fuse/lstat/FuseLstatReturnAtimeTest.cpp - fuse/lstat/FuseLstatErrorTest.cpp - fuse/lstat/FuseLstatReturnMtimeTest.cpp - fuse/lstat/FuseLstatReturnSizeTest.cpp - fuse/read/FuseReadFileDescriptorTest.cpp - fuse/read/testutils/FuseReadTest.cpp - fuse/read/FuseReadOverflowTest.cpp - fuse/read/FuseReadErrorTest.cpp - fuse/read/FuseReadReturnedDataTest.cpp - fuse/flush/testutils/FuseFlushTest.cpp - fuse/flush/FuseFlushErrorTest.cpp - fuse/flush/FuseFlushFileDescriptorTest.cpp - fuse/rename/testutils/FuseRenameTest.cpp - fuse/rename/FuseRenameErrorTest.cpp - fuse/rename/FuseRenameFilenameTest.cpp - fuse/utimens/testutils/FuseUtimensTest.cpp - fuse/utimens/FuseUtimensErrorTest.cpp - fuse/utimens/FuseUtimensFilenameTest.cpp - fuse/utimens/FuseUtimensTimeParameterTest.cpp - fuse/unlink/testutils/FuseUnlinkTest.cpp - fuse/unlink/FuseUnlinkErrorTest.cpp - fuse/unlink/FuseUnlinkFilenameTest.cpp - fuse/ftruncate/testutils/FuseFTruncateTest.cpp - fuse/ftruncate/FuseFTruncateFileDescriptorTest.cpp - fuse/ftruncate/FuseFTruncateSizeTest.cpp - fuse/ftruncate/FuseFTruncateErrorTest.cpp - fuse/fstat/testutils/FuseFstatTest.cpp - fuse/fstat/FuseFstatParameterTest.cpp - fuse/fstat/FuseFstatErrorTest.cpp - fuse/truncate/FuseTruncateSizeTest.cpp - fuse/truncate/testutils/FuseTruncateTest.cpp - fuse/truncate/FuseTruncateErrorTest.cpp - fuse/truncate/FuseTruncateFilenameTest.cpp - fuse/statfs/FuseStatfsReturnFilesTest.cpp - fuse/statfs/FuseStatfsReturnFfreeTest.cpp - fuse/statfs/FuseStatfsReturnNamemaxTest.cpp - fuse/statfs/testutils/FuseStatfsTest.cpp - fuse/statfs/FuseStatfsReturnBsizeTest.cpp - fuse/statfs/FuseStatfsErrorTest.cpp - fuse/statfs/FuseStatfsReturnBfreeTest.cpp - fuse/statfs/FuseStatfsReturnBlocksTest.cpp - fuse/statfs/FuseStatfsReturnBavailTest.cpp - fuse/closeFile/FuseCloseTest.cpp - fuse/fsync/testutils/FuseFsyncTest.cpp - fuse/fsync/FuseFsyncFileDescriptorTest.cpp - fuse/fsync/FuseFsyncErrorTest.cpp - fuse/openFile/testutils/FuseOpenTest.cpp - fuse/openFile/FuseOpenFilenameTest.cpp - fuse/openFile/FuseOpenFlagsTest.cpp - fuse/openFile/FuseOpenFileDescriptorTest.cpp - fuse/openFile/FuseOpenErrorTest.cpp - fuse/access/FuseAccessFilenameTest.cpp - fuse/access/testutils/FuseAccessTest.cpp - fuse/access/FuseAccessModeTest.cpp - fuse/access/FuseAccessErrorTest.cpp - fuse/BasicFuseTest.cpp - fuse/TimestampTest.cpp - fuse/rmdir/testutils/FuseRmdirTest.cpp - fuse/rmdir/FuseRmdirErrorTest.cpp - fuse/rmdir/FuseRmdirDirnameTest.cpp - fuse/fdatasync/testutils/FuseFdatasyncTest.cpp - fuse/fdatasync/FuseFdatasyncErrorTest.cpp - fuse/fdatasync/FuseFdatasyncFileDescriptorTest.cpp - fuse/mkdir/testutils/FuseMkdirTest.cpp - fuse/mkdir/FuseMkdirErrorTest.cpp - fuse/mkdir/FuseMkdirModeTest.cpp - fuse/mkdir/FuseMkdirDirnameTest.cpp - fuse/write/FuseWriteErrorTest.cpp - fuse/write/testutils/FuseWriteTest.cpp - fuse/write/FuseWriteOverflowTest.cpp - fuse/write/FuseWriteFileDescriptorTest.cpp - fuse/write/FuseWriteDataTest.cpp - fuse/readDir/testutils/FuseReadDirTest.cpp - fuse/readDir/FuseReadDirDirnameTest.cpp - fuse/readDir/FuseReadDirErrorTest.cpp - fuse/readDir/FuseReadDirReturnTest.cpp - fuse/createAndOpenFile/FuseCreateAndOpenFilenameTest.cpp - fuse/createAndOpenFile/testutils/FuseCreateAndOpenTest.cpp - fuse/createAndOpenFile/FuseCreateAndOpenFlagsTest.cpp - fuse/createAndOpenFile/FuseCreateAndOpenFileDescriptorTest.cpp - fuse/createAndOpenFile/FuseCreateAndOpenErrorTest.cpp - fuse/FilesystemTest.cpp - fs_interface/NodeTest.cpp - fs_interface/FileTest.cpp - fs_interface/DirTest.cpp - fs_interface/DeviceTest.cpp - fs_interface/OpenFileTest.cpp - testutils/OpenFileHandle.cpp testutils/OpenFileHandle.h) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest fspp-interface fspp-fuse) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/fspp/fs_interface/DeviceTest.cpp b/test/fspp/fs_interface/DeviceTest.cpp deleted file mode 100644 index dea9204e..00000000 --- a/test/fspp/fs_interface/DeviceTest.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Tests that the header can be included without needing additional header includes as dependencies. - */ -#include "fspp/fs_interface/Device.h" diff --git a/test/fspp/fs_interface/DirTest.cpp b/test/fspp/fs_interface/DirTest.cpp deleted file mode 100644 index 91a92c24..00000000 --- a/test/fspp/fs_interface/DirTest.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Tests that the header can be included without needing additional header includes as dependencies. - */ -#include "fspp/fs_interface/Dir.h" diff --git a/test/fspp/fs_interface/FileTest.cpp b/test/fspp/fs_interface/FileTest.cpp deleted file mode 100644 index fd4831bb..00000000 --- a/test/fspp/fs_interface/FileTest.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Tests that the header can be included without needing additional header includes as dependencies. - */ -#include "fspp/fs_interface/File.h" diff --git a/test/fspp/fs_interface/NodeTest.cpp b/test/fspp/fs_interface/NodeTest.cpp deleted file mode 100644 index 9b1a03d2..00000000 --- a/test/fspp/fs_interface/NodeTest.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Tests that the header can be included without needing additional header includes as dependencies. - */ -#include "fspp/fs_interface/Node.h" diff --git a/test/fspp/fs_interface/OpenFileTest.cpp b/test/fspp/fs_interface/OpenFileTest.cpp deleted file mode 100644 index 20db933d..00000000 --- a/test/fspp/fs_interface/OpenFileTest.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Tests that the header can be included without needing additional header includes as dependencies. - */ -#include "fspp/fs_interface/OpenFile.h" diff --git a/test/fspp/fuse/BasicFuseTest.cpp b/test/fspp/fuse/BasicFuseTest.cpp deleted file mode 100644 index 07d3c446..00000000 --- a/test/fspp/fuse/BasicFuseTest.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "../testutils/FuseTest.h" - -using namespace fspp::fuse; -using namespace fspp::fuse; - - -typedef FuseTest BasicFuseTest; - -//This test case simply checks whether a filesystem can be setup and teardown without crashing. -TEST_F(BasicFuseTest, setupAndTearDown) { - auto fs = TestFS(); -} diff --git a/test/fspp/fuse/FilesystemTest.cpp b/test/fspp/fuse/FilesystemTest.cpp deleted file mode 100644 index d78cb35d..00000000 --- a/test/fspp/fuse/FilesystemTest.cpp +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Tests that the header can be included without needing additional header includes as dependencies. - */ -#include "fspp/fuse/Filesystem.h" diff --git a/test/fspp/fuse/TimestampTest.cpp b/test/fspp/fuse/TimestampTest.cpp deleted file mode 100644 index 3d6c5ca6..00000000 --- a/test/fspp/fuse/TimestampTest.cpp +++ /dev/null @@ -1,316 +0,0 @@ -#include "../testutils/FuseTest.h" - -#include - -using namespace fspp::fuse; - -typedef FuseTest FuseTimestampTest; - -// Single flag - -TEST_F(FuseTimestampTest, whenCalledWithoutAnyAtimeFlag_thenHasRelatimeBehavior) { - auto fs = TestFS({}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeFlag_thenHasNoatimeBehavior) { - auto fs = TestFS({"-o", "noatime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeFlag_thenHasStrictatimeBehavior) { - auto fs = TestFS({"-o", "strictatime"}); - EXPECT_EQ(fspp::strictatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeFlag_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "relatime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeFlag_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "atime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeFlag_thenHasNoatimeBehavior) { - // note: this behavior is correct because "noatime" is default and adding "nodiratime" doesn't change anything. - auto fs = TestFS({"-o", "nodiratime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - - - -// Flag combinations - -TEST_F(FuseTimestampTest, whenCalledWithAtimeAtimeFlag_withCsv_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "atime,atime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeAtimeFlag_withSeparateFlags_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "atime", "-o", "atime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeNoatimeFlag_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "atime,noatime"}), - "Cannot have both, noatime and atime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeNoatimeFlag_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "atime", "-o", "noatime"}), - "Cannot have both, noatime and atime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeRelatimeFlag_withCsv_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "atime,relatime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeRelatimeFlag_withSeparateFlags_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "atime", "-o", "relatime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeStrictatimeFlag_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "atime,strictatime"}), - "Cannot have both, atime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeStrictatimeFlag_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "atime", "-o", "strictatime"}), - "Cannot have both, atime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeNodiratimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "atime,nodiratime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithAtimeNodiratimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "atime", "-o", "nodiratime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeAtime_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "noatime,atime"}), - "Cannot have both, noatime and atime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeAtime_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "noatime", "-o", "atime"}), - "Cannot have both, noatime and atime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeNoatimeFlag_withCsv_thenHasNoatimeBehavior) { - auto fs = TestFS({"-o", "noatime,noatime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeNoatimeFlag_withSeparateFlags_thenHasNoatimeBehavior) { - auto fs = TestFS({"-o", "noatime", "-o", "noatime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeRelatime_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "noatime,relatime"}), - "Cannot have both, noatime and relatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeRelatime_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "noatime", "-o", "relatime"}), - "Cannot have both, noatime and relatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeStrictatime_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "noatime,strictatime"}), - "Cannot have both, noatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeStrictatime_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "noatime", "-o", "strictatime"}), - "Cannot have both, noatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeNodiratimeFlag_withCsv_thenHasNoatimeBehavior) { - auto fs = TestFS({"-o", "noatime,nodiratime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNoatimeNodiratimeFlag_withSeparateFlags_thenHasNoatimeBehavior) { - auto fs = TestFS({"-o", "noatime", "-o", "nodiratime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeAtimeFlag_withCsv_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "relatime,atime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeAtimeFlag_withSeparateFlags_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "relatime", "-o", "atime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeNoatime_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "relatime,noatime"}), - "Cannot have both, noatime and relatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeNoatime_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "relatime", "-o", "noatime"}), - "Cannot have both, noatime and relatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeRelatimeFlag_withCsv_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "relatime,relatime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeRelatimeFlag_withSeparateFlags_thenHasRelatimeBehavior) { - auto fs = TestFS({"-o", "relatime", "-o", "relatime"}); - EXPECT_EQ(fspp::relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeStrictatime_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "relatime,strictatime"}), - "Cannot have both, relatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeStrictatime_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "relatime", "-o", "strictatime"}), - "Cannot have both, relatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeNodiratimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "relatime,nodiratime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithRelatimeNodiratimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "relatime", "-o", "nodiratime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeAtimeFlag_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "strictatime,atime"}), - "Cannot have both, atime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeAtimeFlag_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "strictatime", "-o", "atime"}), - "Cannot have both, atime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNoatimeFlag_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "strictatime,noatime"}), - "Cannot have both, noatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNoatimeFlag_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "strictatime", "-o", "noatime"}), - "Cannot have both, noatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeRelatimeFlag_withCsv_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "strictatime,relatime"}), - "Cannot have both, relatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeRelatimeFlag_withSeparateFlags_thenFails) { - EXPECT_DEATH( - TestFS({"-o", "strictatime", "-o", "relatime"}), - "Cannot have both, relatime and strictatime flags set."); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeStrictatimeFlag_withCsv_thenHasStrictatimeBehavior) { - auto fs = TestFS({"-o", "strictatime,strictatime"}); - EXPECT_EQ(fspp::strictatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeStrictatimeFlag_withSeparateFlags_thenHasStrictatimeBehavior) { - auto fs = TestFS({"-o", "strictatime", "-o", "strictatime"}); - EXPECT_EQ(fspp::strictatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNodiratimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "strictatime,nodiratime"}); - EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithStrictatimeNodiratimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "strictatime", "-o", "nodiratime"}); - EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeAtimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime,atime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeAtimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime", "-o", "atime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNoatimeFlag_withCsv_thenHasNoatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime,noatime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNoatimeFlag_withSeparateFlags_thenHasNoatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime", "-o", "noatime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeRelatimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime,relatime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeRelatimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime", "-o", "relatime"}); - EXPECT_EQ(fspp::nodiratime_relatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeStrictatimeFlag_withCsv_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime,strictatime"}); - EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeStrictatimeFlag_withSeparateFlags_thenHasNodiratimeRelatimeBehavior) { - auto fs = TestFS({"-o", "nodiratime", "-o", "strictatime"}); - EXPECT_EQ(fspp::nodiratime_strictatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNodiratimeFlag_withCsv_thenHasNoatimeBehavior) { - // note: this behavior is correct because "noatime" is default and adding "nodiratime" doesn't change anything. - auto fs = TestFS({"-o", "nodiratime,nodiratime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} - -TEST_F(FuseTimestampTest, whenCalledWithNodiratimeNodiratimeFlag_withSeparateFlags_thenHasNoatimeBehavior) { - // note: this behavior is correct because "noatime" is default and adding "nodiratime" doesn't change anything. - auto fs = TestFS({"-o", "nodiratime", "-o", "nodiratime"}); - EXPECT_EQ(fspp::noatime().get(), context().timestampUpdateBehavior().get()); -} diff --git a/test/fspp/fuse/access/FuseAccessErrorTest.cpp b/test/fspp/fuse/access/FuseAccessErrorTest.cpp deleted file mode 100644 index e2b47de4..00000000 --- a/test/fspp/fuse/access/FuseAccessErrorTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "testutils/FuseAccessTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::AtLeast; - -using namespace fspp::fuse; - -class FuseAccessErrorTest: public FuseAccessTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseAccessErrorTest, FuseAccessErrorTest, Values(EACCES, ELOOP, ENAMETOOLONG, ENOENT, ENOTDIR, EROFS, EFAULT, EINVAL, EIO, ENOMEM, ETXTBSY)); - -TEST_P(FuseAccessErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, access(Eq(FILENAME), testing::_)) - .Times(AtLeast(1)).WillRepeatedly(Throw(FuseErrnoException(GetParam()))); - - int error = AccessFileReturnError(FILENAME, 0); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/access/FuseAccessFilenameTest.cpp b/test/fspp/fuse/access/FuseAccessFilenameTest.cpp deleted file mode 100644 index 517dc6d2..00000000 --- a/test/fspp/fuse/access/FuseAccessFilenameTest.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "testutils/FuseAccessTest.h" - -using ::testing::Eq; -using ::testing::Return; - -class FuseAccessFilenameTest: public FuseAccessTest { -}; - -TEST_F(FuseAccessFilenameTest, AccessFile) { - ReturnIsFileOnLstat("/myfile"); - EXPECT_CALL(*fsimpl, access(Eq("/myfile"), testing::_)) - .Times(1).WillOnce(Return()); - - AccessFile("/myfile", 0); -} - -TEST_F(FuseAccessFilenameTest, AccessFileNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsFileOnLstat("/mydir/myfile"); - EXPECT_CALL(*fsimpl, access(Eq("/mydir/myfile"), testing::_)) - .Times(1).WillOnce(Return()); - - AccessFile("/mydir/myfile", 0); -} - -TEST_F(FuseAccessFilenameTest, AccessFileNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsFileOnLstat("/mydir/mydir2/myfile"); - EXPECT_CALL(*fsimpl, access(Eq("/mydir/mydir2/myfile"), testing::_)) - .Times(1).WillOnce(Return()); - - AccessFile("/mydir/mydir2/myfile", 0); -} diff --git a/test/fspp/fuse/access/FuseAccessModeTest.cpp b/test/fspp/fuse/access/FuseAccessModeTest.cpp deleted file mode 100644 index f6347d65..00000000 --- a/test/fspp/fuse/access/FuseAccessModeTest.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "testutils/FuseAccessTest.h" - -using ::testing::Eq; -using ::testing::Return; -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseAccessModeTest: public FuseAccessTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseAccessModeTest, FuseAccessModeTest, Values(0, F_OK, R_OK, W_OK, X_OK, R_OK|W_OK, W_OK|X_OK, R_OK|X_OK, R_OK|W_OK|X_OK)); - - -TEST_P(FuseAccessModeTest, AccessFile) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, access(Eq(FILENAME), GetParam())) - .Times(1).WillOnce(Return()); - - AccessFile(FILENAME, GetParam()); -} diff --git a/test/fspp/fuse/access/testutils/FuseAccessTest.cpp b/test/fspp/fuse/access/testutils/FuseAccessTest.cpp deleted file mode 100644 index 5715d946..00000000 --- a/test/fspp/fuse/access/testutils/FuseAccessTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "FuseAccessTest.h" - -void FuseAccessTest::AccessFile(const char *filename, int mode) { - int error = AccessFileReturnError(filename, mode); - EXPECT_EQ(0, error); -} - -int FuseAccessTest::AccessFileReturnError(const char *filename, int mode) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / filename; - int retval = ::access(realpath.string().c_str(), mode); - if (retval == 0) { - return 0; - } else { - return errno; - } -} diff --git a/test/fspp/fuse/access/testutils/FuseAccessTest.h b/test/fspp/fuse/access/testutils/FuseAccessTest.h deleted file mode 100644 index 4b430f10..00000000 --- a/test/fspp/fuse/access/testutils/FuseAccessTest.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_ACCESS_TESTUTILS_FUSEACCESSTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_ACCESS_TESTUTILS_FUSEACCESSTEST_H_ - -#include "../../../testutils/FuseTest.h" - -class FuseAccessTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void AccessFile(const char *filename, int mode); - int AccessFileReturnError(const char *filename, int mode); -}; - -#endif diff --git a/test/fspp/fuse/closeFile/FuseCloseTest.cpp b/test/fspp/fuse/closeFile/FuseCloseTest.cpp deleted file mode 100644 index 80899ef3..00000000 --- a/test/fspp/fuse/closeFile/FuseCloseTest.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "../../testutils/FuseTest.h" -#include "../../testutils/OpenFileHandle.h" -#include - -//TODO Figure out what's wrong and enable this test -//Disabled, because it is flaky. libfuse seems to not send the release() event sometimes. -/* - -using ::testing::WithParamInterface; -using ::testing::Values; - -using std::string; -using std::mutex; -using std::unique_lock; -using std::condition_variable; -using std::chrono::duration; -using std::chrono::seconds; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -// The fuse behaviour is: For each open(), there will be exactly one call to release(). -// Directly before this call to release(), flush() will be called. After flush() returns, -// the ::close() syscall (in the process using the filesystem) returns. So the fuse release() call is -// called asynchronously afterwards. Errors have to be returned in the implementation of flush(). - -// Citing FUSE spec: -// 1) Flush is called on each close() of a file descriptor. -// 2) Filesystems shouldn't assume that flush will always be called after some writes, or that if will be called at all. -// I can't get these sentences together. For the test cases here, I go with the first one and assume that -// flush() will ALWAYS be called on a file close. - -class Barrier { -public: - Barrier(): m(), cv(), finished(false) {} - - template - void WaitAtMost(const duration &atMost) { - unique_lock lock(m); - if (!finished) { - cv.wait_for(lock, atMost, [this] () {return finished;}); - } - } - - void Release() { - unique_lock lock(m); - finished = true; - cv.notify_all(); - } -private: - mutex m; - condition_variable cv; - bool finished; -}; - -class FuseCloseTest: public FuseTest, public WithParamInterface { -public: - const string FILENAME = "/myfile"; - - void OpenAndCloseFile(const string &filename) { - auto fs = TestFS(); - auto fd = OpenFile(fs.get(), filename); - CloseFile(std::move(fd)); - } - - unique_ref OpenFile(const TempTestFS *fs, const string &filename) { - auto real_path = fs->mountDir() / filename; - auto fd = make_unique_ref(real_path.string().c_str(), O_RDONLY); - EXPECT_GE(fd->fd(), 0) << "Opening file failed"; - return fd; - } - - void CloseFile(unique_ref fd) { - int retval = ::close(fd->fd()); - EXPECT_EQ(0, retval); - fd->release(); // don't try closing it again - } -}; -INSTANTIATE_TEST_SUITE_P(FuseCloseTest, FuseCloseTest, Values(0, 1, 2, 100, 1024*1024*1024)); - -TEST_P(FuseCloseTest, CloseFile) { - Barrier barrier; - - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, openFile(Eq(FILENAME), _)).WillOnce(Return(GetParam())); - { - //InSequence fileCloseSequence; - EXPECT_CALL(*fsimpl, flush(Eq(GetParam()))).Times(1); - EXPECT_CALL(*fsimpl, closeFile(Eq(GetParam()))).Times(1).WillOnce(Invoke([&barrier] (int) { - // Release the waiting lock at the end of this test case, because the fuse release() came in now. - barrier.Release(); - })); - } - - OpenAndCloseFile(FILENAME); - - // Wait, until fuse release() was called, so we can check for the function call expectation. - barrier.WaitAtMost(seconds(10)); -}*/ diff --git a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenErrorTest.cpp b/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenErrorTest.cpp deleted file mode 100644 index 6310301c..00000000 --- a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenErrorTest.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "testutils/FuseCreateAndOpenTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Return; -using ::testing::Throw; -using ::testing::Eq; - -using namespace fspp::fuse; - -class FuseCreateAndOpenErrorTest: public FuseCreateAndOpenTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseCreateAndOpenErrorTest, FuseCreateAndOpenErrorTest, Values(EACCES, EDQUOT, EEXIST, EFAULT, EFBIG, EINTR, EOVERFLOW, EINVAL, EISDIR, ELOOP, EMFILE, ENAMETOOLONG, ENFILE, ENODEV, ENOENT, ENOMEM, ENOSPC, ENOTDIR, ENXIO, EOPNOTSUPP, EPERM, EROFS, ETXTBSY, EWOULDBLOCK, EBADF, ENOTDIR)); - -TEST_F(FuseCreateAndOpenErrorTest, ReturnNoError) { - ReturnDoesntExistOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq(FILENAME), testing::_, testing::_, testing::_)).Times(1).WillOnce(Return(1)); - //For the syscall to succeed, we also need to give an fstat implementation. - ReturnIsFileOnFstat(1); - - int error = CreateAndOpenFileReturnError(FILENAME, O_RDONLY); - EXPECT_EQ(0, error); -} - -TEST_P(FuseCreateAndOpenErrorTest, ReturnError) { - ReturnDoesntExistOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq(FILENAME), testing::_, testing::_, testing::_)).Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = CreateAndOpenFileReturnError(FILENAME, O_RDONLY); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFileDescriptorTest.cpp b/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFileDescriptorTest.cpp deleted file mode 100644 index ea931563..00000000 --- a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFileDescriptorTest.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "testutils/FuseCreateAndOpenTest.h" - -using ::testing::Eq; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Return; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -class FuseCreateAndOpenFileDescriptorTest: public FuseCreateAndOpenTest, public WithParamInterface { -public: - void CreateAndOpenAndReadFile(const char *filename) { - auto fs = TestFS(); - - auto fd = CreateAndOpenFile(fs.get(), filename); - ReadFile(fd->fd()); - } - -private: - unique_ref CreateAndOpenFile(const TempTestFS *fs, const char *filename) { - auto realpath = fs->mountDir() / filename; - auto fd = make_unique_ref(realpath.string().c_str(), O_RDONLY | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH); - EXPECT_GE(fd->fd(), 0) << "Creating file failed"; - return fd; - } - void ReadFile(int fd) { - uint8_t buf = 0; - int retval = ::read(fd, &buf, 1); - EXPECT_EQ(1, retval) << "Reading file failed"; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseCreateAndOpenFileDescriptorTest, FuseCreateAndOpenFileDescriptorTest, Values(0, 2, 5, 1000, 1024*1024*1024)); - -TEST_P(FuseCreateAndOpenFileDescriptorTest, TestReturnedFileDescriptor) { - ReturnDoesntExistOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq(FILENAME), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(Return(GetParam())); - EXPECT_CALL(*fsimpl, read(GetParam(), testing::_, testing::_, testing::_)).Times(1).WillOnce(Return(fspp::num_bytes_t(1))); - //For the syscall to succeed, we also need to give an fstat implementation. - ReturnIsFileOnFstatWithSize(GetParam(), fspp::num_bytes_t(1)); - - CreateAndOpenAndReadFile(FILENAME); -} diff --git a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFilenameTest.cpp b/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFilenameTest.cpp deleted file mode 100644 index aa3f9ecd..00000000 --- a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFilenameTest.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "testutils/FuseCreateAndOpenTest.h" - -using ::testing::Eq; -using ::testing::Return; - -class FuseCreateAndOpenFilenameTest: public FuseCreateAndOpenTest { -public: -}; - -TEST_F(FuseCreateAndOpenFilenameTest, CreateAndOpenFile) { - ReturnDoesntExistOnLstat("/myfile"); - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq("/myfile"), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(Return(0)); - //For the syscall to succeed, we also need to give an fstat implementation. - ReturnIsFileOnFstat(0); - - CreateAndOpenFile("/myfile", O_RDONLY); -} - -TEST_F(FuseCreateAndOpenFilenameTest, CreateAndOpenFileNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnDoesntExistOnLstat("/mydir/myfile"); - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq("/mydir/myfile"), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(Return(0)); - //For the syscall to succeed, we also need to give an fstat implementation. - ReturnIsFileOnFstat(0); - - CreateAndOpenFile("/mydir/myfile", O_RDONLY); -} - -TEST_F(FuseCreateAndOpenFilenameTest, CreateAndOpenFileNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnDoesntExistOnLstat("/mydir/mydir2/myfile"); - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq("/mydir/mydir2/myfile"), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(Return(0)); - //For the syscall to succeed, we also need to give an fstat implementation. - ReturnIsFileOnFstat(0); - - CreateAndOpenFile("/mydir/mydir2/myfile", O_RDONLY); -} diff --git a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFlagsTest.cpp b/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFlagsTest.cpp deleted file mode 100644 index d5a516bb..00000000 --- a/test/fspp/fuse/createAndOpenFile/FuseCreateAndOpenFlagsTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "testutils/FuseCreateAndOpenTest.h" - -//TODO Disabled because it doesn't seem to work. Fuse doesn't seem to pass flags to create(). Why? -/* - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseCreateAndOpenFlagsTest: public FuseCreateAndOpenTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseCreateAndOpenFlagsTest, FuseCreateAndOpenFlagsTest, Values(O_RDWR, O_RDONLY, O_WRONLY)); - -TEST_P(FuseCreateAndOpenFlagsTest, testFlags) { - ReturnDoesntExistOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq(FILENAME), OpenFlagsEq(GetParam()), _, _)) - .Times(1).WillOnce(Return(0)); - //For the syscall to succeed, we also need to give an fstat implementation. - ReturnIsFileOnFstat(0); - - CreateAndOpenFile(FILENAME, GetParam()); -}*/ diff --git a/test/fspp/fuse/createAndOpenFile/testutils/FuseCreateAndOpenTest.cpp b/test/fspp/fuse/createAndOpenFile/testutils/FuseCreateAndOpenTest.cpp deleted file mode 100644 index ae24bd75..00000000 --- a/test/fspp/fuse/createAndOpenFile/testutils/FuseCreateAndOpenTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "FuseCreateAndOpenTest.h" - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -void FuseCreateAndOpenTest::CreateAndOpenFile(const std::string &filename, int flags) { - auto fs = TestFS(); - - auto fd = CreateAndOpenFileAllowErrors(fs.get(), filename, flags); - EXPECT_GE(fd->fd(), 0) << "Opening file failed"; -} - -int FuseCreateAndOpenTest::CreateAndOpenFileReturnError(const std::string &filename, int flags) { - auto fs = TestFS(); - - auto fd = CreateAndOpenFileAllowErrors(fs.get(), filename, flags); - return fd->errorcode(); -} - -unique_ref FuseCreateAndOpenTest::CreateAndOpenFileAllowErrors(const TempTestFS *fs, const std::string &filename, int flags) { - auto real_path = fs->mountDir() / filename; - auto fd = make_unique_ref(real_path.string().c_str(), flags | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - return fd; -} diff --git a/test/fspp/fuse/createAndOpenFile/testutils/FuseCreateAndOpenTest.h b/test/fspp/fuse/createAndOpenFile/testutils/FuseCreateAndOpenTest.h deleted file mode 100644 index 74a096b6..00000000 --- a/test/fspp/fuse/createAndOpenFile/testutils/FuseCreateAndOpenTest.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_CREATEANDOPENFILE_TESTUTILS_FUSECREATEANDOPENTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_CREATEANDOPENFILE_TESTUTILS_FUSECREATEANDOPENTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseCreateAndOpenTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void CreateAndOpenFile(const std::string& FILENAME, int flags); - int CreateAndOpenFileReturnError(const std::string& FILENAME, int flags); -private: - cpputils::unique_ref CreateAndOpenFileAllowErrors(const TempTestFS *fs, const std::string &filename, int flags); -}; - -MATCHER_P(OpenFlagsEq, expectedFlags, "") { - return expectedFlags == (O_ACCMODE & arg); -} - -#endif diff --git a/test/fspp/fuse/fdatasync/FuseFdatasyncErrorTest.cpp b/test/fspp/fuse/fdatasync/FuseFdatasyncErrorTest.cpp deleted file mode 100644 index 1c685bdc..00000000 --- a/test/fspp/fuse/fdatasync/FuseFdatasyncErrorTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseFdatasyncTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseFdatasyncErrorTest: public FuseFdatasyncTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFdatasyncErrorTest, FuseFdatasyncErrorTest, Values(EBADF, EIO, EROFS, EINVAL)); - -TEST_P(FuseFdatasyncErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, fdatasync(0)) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = FdatasyncFileReturnError(FILENAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/fdatasync/FuseFdatasyncFileDescriptorTest.cpp b/test/fspp/fuse/fdatasync/FuseFdatasyncFileDescriptorTest.cpp deleted file mode 100644 index e9fe8021..00000000 --- a/test/fspp/fuse/fdatasync/FuseFdatasyncFileDescriptorTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "testutils/FuseFdatasyncTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; -using ::testing::Return; - -using namespace fspp::fuse; - -class FuseFdatasyncFileDescriptorTest: public FuseFdatasyncTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFdatasyncFileDescriptorTest, FuseFdatasyncFileDescriptorTest, Values(0,1,10,1000,1024*1024*1024)); - - -TEST_P(FuseFdatasyncFileDescriptorTest, FileDescriptorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, GetParam()); - EXPECT_CALL(*fsimpl, fdatasync(Eq(GetParam()))) - .Times(1).WillOnce(Return()); - - FdatasyncFile(FILENAME); -} diff --git a/test/fspp/fuse/fdatasync/testutils/FuseFdatasyncTest.cpp b/test/fspp/fuse/fdatasync/testutils/FuseFdatasyncTest.cpp deleted file mode 100644 index 807db48f..00000000 --- a/test/fspp/fuse/fdatasync/testutils/FuseFdatasyncTest.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "FuseFdatasyncTest.h" -#include - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -void FuseFdatasyncTest::FdatasyncFile(const char *filename) { - int error = FdatasyncFileReturnError(filename); - EXPECT_EQ(0, error); -} - -int FuseFdatasyncTest::FdatasyncFileReturnError(const char *filename) { - auto fs = TestFS(); - - auto fd = OpenFile(fs.get(), filename); -#ifdef F_FULLFSYNC - // This is MacOSX, which doesn't know fdatasync - int retval = fcntl(fd->fd(), F_FULLFSYNC); -#else - int retval = ::fdatasync(fd->fd()); -#endif - if (retval != -1) { - return 0; - } else { - return errno; - } -} - -unique_ref FuseFdatasyncTest::OpenFile(const TempTestFS *fs, const char *filename) { - auto realpath = fs->mountDir() / filename; - auto fd = make_unique_ref(realpath.string().c_str(), O_RDWR); - EXPECT_GE(fd->fd(), 0) << "Error opening file"; - return fd; -} diff --git a/test/fspp/fuse/fdatasync/testutils/FuseFdatasyncTest.h b/test/fspp/fuse/fdatasync/testutils/FuseFdatasyncTest.h deleted file mode 100644 index 42eda5dd..00000000 --- a/test/fspp/fuse/fdatasync/testutils/FuseFdatasyncTest.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_FDATASYNC_TESTUTILS_FUSEFDATASYNCTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_FDATASYNC_TESTUTILS_FUSEFDATASYNCTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseFdatasyncTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void FdatasyncFile(const char *filename); - int FdatasyncFileReturnError(const char *filename); - -private: - cpputils::unique_ref OpenFile(const TempTestFS *fs, const char *filename); -}; - -#endif diff --git a/test/fspp/fuse/flush/FuseFlushErrorTest.cpp b/test/fspp/fuse/flush/FuseFlushErrorTest.cpp deleted file mode 100644 index bfa7626d..00000000 --- a/test/fspp/fuse/flush/FuseFlushErrorTest.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "testutils/FuseFlushTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Eq; -using ::testing::Return; -using ::testing::Throw; -using ::testing::Values; - -using fspp::fuse::FuseErrnoException; - -class FuseFlushErrorTest: public FuseFlushTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFlushErrorTest, FuseFlushErrorTest, Values( - EBADF, -#if defined(__GLIBC__) || defined(__APPLE__) - // musl has different handling for EINTR, see https://ewontfix.com/4/ - EINTR, -#endif - EIO)); - -TEST_P(FuseFlushErrorTest, ReturnErrorFromFlush) { - ReturnIsFileOnLstat(FILENAME); - - EXPECT_CALL(*fsimpl, openFile(Eq(FILENAME), testing::_)).WillOnce(Return(GetParam())); - EXPECT_CALL(*fsimpl, flush(Eq(GetParam()))).Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - auto fs = TestFS(); - auto fd = OpenFile(fs.get(), FILENAME); - - int close_result = ::close(fd->fd()); - EXPECT_EQ(GetParam(), errno); - EXPECT_EQ(-1, close_result); - fd->release(); // don't close it again -} diff --git a/test/fspp/fuse/flush/FuseFlushFileDescriptorTest.cpp b/test/fspp/fuse/flush/FuseFlushFileDescriptorTest.cpp deleted file mode 100644 index 7ec4c1a5..00000000 --- a/test/fspp/fuse/flush/FuseFlushFileDescriptorTest.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "testutils/FuseFlushTest.h" - -using ::testing::Eq; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Return; - -using std::string; - -// The fuse behaviour is: For each open(), there will be exactly one call to release(). -// Directly before this call to release(), flush() will be called. After flush() returns, -// the ::close() syscall (in the process using the filesystem) returns. So the fuse release() call is -// called asynchronously afterwards. Errors have to be returned in the implementation of flush(). - -// Citing FUSE spec: -// 1) Flush is called on each close() of a file descriptor. -// 2) Filesystems shouldn't assume that flush will always be called after some writes, or that if will be called at all. -// I can't get these sentences together. For the test cases here, I go with the first one and assume that -// flush() will ALWAYS be called on a file close. - -class FuseFlushFileDescriptorTest: public FuseFlushTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFlushFileDescriptorTest, FuseFlushFileDescriptorTest, Values(0, 1, 2, 100, 1024*1024*1024)); - -TEST_P(FuseFlushFileDescriptorTest, FlushOnCloseFile) { - ReturnIsFileOnLstat(FILENAME); - - EXPECT_CALL(*fsimpl, openFile(Eq(FILENAME), testing::_)).WillOnce(Return(GetParam())); - EXPECT_CALL(*fsimpl, flush(Eq(GetParam()))).Times(1); - - OpenAndCloseFile(FILENAME); -} diff --git a/test/fspp/fuse/flush/testutils/FuseFlushTest.cpp b/test/fspp/fuse/flush/testutils/FuseFlushTest.cpp deleted file mode 100644 index eca52cd7..00000000 --- a/test/fspp/fuse/flush/testutils/FuseFlushTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "FuseFlushTest.h" - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -void FuseFlushTest::OpenAndCloseFile(const std::string &filename) { - auto fs = TestFS(); - auto fd = OpenFile(fs.get(), filename); - CloseFile(fd->fd()); - fd->release(); // don't try to close it again -} - -unique_ref FuseFlushTest::OpenFile(const TempTestFS *fs, const std::string &filename) { - auto real_path = fs->mountDir() / filename; - auto fd = make_unique_ref(real_path.string().c_str(), O_RDONLY); - EXPECT_GE(fd->fd(), 0) << "Opening file failed"; - return fd; -} - -void FuseFlushTest::CloseFile(int fd) { - int retval = ::close(fd); - EXPECT_EQ(0, retval); -} diff --git a/test/fspp/fuse/flush/testutils/FuseFlushTest.h b/test/fspp/fuse/flush/testutils/FuseFlushTest.h deleted file mode 100644 index 6c172bb8..00000000 --- a/test/fspp/fuse/flush/testutils/FuseFlushTest.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_FLUSH_TESTUTILS_FUSEFLUSHTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_FLUSH_TESTUTILS_FUSEFLUSHTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseFlushTest: public FuseTest { -public: - const std::string FILENAME = "/myfile"; - - void OpenAndCloseFile(const std::string &filename); - cpputils::unique_ref OpenFile(const TempTestFS *fs, const std::string &filename); - void CloseFile(int fd); -}; - - -#endif diff --git a/test/fspp/fuse/fstat/FuseFstatErrorTest.cpp b/test/fspp/fuse/fstat/FuseFstatErrorTest.cpp deleted file mode 100644 index 8b75abe5..00000000 --- a/test/fspp/fuse/fstat/FuseFstatErrorTest.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "testutils/FuseFstatTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; -using ::testing::Throw; - - -using namespace fspp::fuse; - -// Cite from FUSE documentation on the fgetattr function: -// "Currently this is only called after the create() method if that is implemented (see above). -// Later it may be called for invocations of fstat() too." -// So we need to issue a create to get our fstat called. - -class FuseFstatErrorTest: public FuseFstatTest, public WithParamInterface { -public: - /*unique_ref CreateFileAllowErrors(const TempTestFS *fs, const std::string &filename) { - auto real_path = fs->mountDir() / filename; - return make_unique_ref(real_path.string().c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - }*/ -}; -INSTANTIATE_TEST_SUITE_P(FuseFstatErrorTest, FuseFstatErrorTest, Values(EACCES, EBADF, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EOVERFLOW)); - -TEST_P(FuseFstatErrorTest, ReturnedErrorCodeIsCorrect) { - ReturnDoesntExistOnLstat(FILENAME); - OnCreateAndOpenReturnFileDescriptor(FILENAME, 0); - - EXPECT_CALL(*fsimpl, fstat(Eq(0), testing::_)).Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - auto fs = TestFS(); - - int error = CreateFileReturnError(fs.get(), FILENAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/fstat/FuseFstatParameterTest.cpp b/test/fspp/fuse/fstat/FuseFstatParameterTest.cpp deleted file mode 100644 index 9009f8d2..00000000 --- a/test/fspp/fuse/fstat/FuseFstatParameterTest.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "testutils/FuseFstatTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; - -using namespace fspp::fuse; - -// Cite from FUSE documentation on the fgetattr function: -// "Currently this is only called after the create() method if that is implemented (see above). -// Later it may be called for invocations of fstat() too." -// So we need to issue a create to get our fstat called. - -class FuseFstatParameterTest: public FuseFstatTest, public WithParamInterface { -public: - void CallFstat(const char *filename) { - auto fs = TestFS(); - CreateFile(fs.get(), filename); - } -}; -INSTANTIATE_TEST_SUITE_P(FuseFstatParameterTest, FuseFstatParameterTest, Values(0,1,10,1000,1024*1024*1024)); - - -TEST_P(FuseFstatParameterTest, FileDescriptorIsCorrect) { - ReturnDoesntExistOnLstat(FILENAME); - OnCreateAndOpenReturnFileDescriptor(FILENAME, GetParam()); - - EXPECT_CALL(*fsimpl, fstat(Eq(GetParam()), testing::_)).Times(1).WillOnce(ReturnIsFileFstat); - - CallFstat(FILENAME); -} diff --git a/test/fspp/fuse/fstat/README b/test/fspp/fuse/fstat/README deleted file mode 100644 index a72352a3..00000000 --- a/test/fspp/fuse/fstat/README +++ /dev/null @@ -1,6 +0,0 @@ -Cite from FUSE documentation on the fgetattr function: - Currently this is only called after the create() method if that is implemented (see above). - Later it may be called for invocations of fstat() too. -So we need to issue a create to get our fstat called. -Since fstat is currently only called after create, we can't call it directly. -So we can't test the returned values. diff --git a/test/fspp/fuse/fstat/testutils/FuseFstatTest.cpp b/test/fspp/fuse/fstat/testutils/FuseFstatTest.cpp deleted file mode 100644 index 6d4b320a..00000000 --- a/test/fspp/fuse/fstat/testutils/FuseFstatTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "FuseFstatTest.h" - -using ::testing::Eq; -using ::testing::Return; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - - -unique_ref FuseFstatTest::CreateFile(const TempTestFS *fs, const std::string &filename) { - auto fd = CreateFileAllowErrors(fs, filename); - EXPECT_GE(fd->fd(), 0) << "Opening file failed"; - return fd; -} - -int FuseFstatTest::CreateFileReturnError(const TempTestFS *fs, const std::string &filename) { - auto fd = CreateFileAllowErrors(fs, filename); - return fd->errorcode(); -} - -unique_ref FuseFstatTest::CreateFileAllowErrors(const TempTestFS *fs, const std::string &filename) { - auto real_path = fs->mountDir() / filename; - auto fd = make_unique_ref(real_path.string().c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - return fd; -} - -void FuseFstatTest::OnCreateAndOpenReturnFileDescriptor(const char *filename, int descriptor) { - EXPECT_CALL(*fsimpl, createAndOpenFile(Eq(filename), testing::_, testing::_, testing::_)).Times(1).WillOnce(Return(descriptor)); -} diff --git a/test/fspp/fuse/fstat/testutils/FuseFstatTest.h b/test/fspp/fuse/fstat/testutils/FuseFstatTest.h deleted file mode 100644 index b15760c1..00000000 --- a/test/fspp/fuse/fstat/testutils/FuseFstatTest.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_FSTAT_TESTUTILS_FUSEFSTATTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_FSTAT_TESTUTILS_FUSEFSTATTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseFstatTest: public FuseTest { -public: - cpputils::unique_ref CreateFile(const TempTestFS *fs, const std::string &filename); - int CreateFileReturnError(const TempTestFS *fs, const std::string &filename); - void OnCreateAndOpenReturnFileDescriptor(const char *filename, int descriptor); -private: - cpputils::unique_ref CreateFileAllowErrors(const TempTestFS *fs, const std::string &filename); -}; - - -#endif diff --git a/test/fspp/fuse/fsync/FuseFsyncErrorTest.cpp b/test/fspp/fuse/fsync/FuseFsyncErrorTest.cpp deleted file mode 100644 index 36a3e17c..00000000 --- a/test/fspp/fuse/fsync/FuseFsyncErrorTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseFsyncTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseFsyncErrorTest: public FuseFsyncTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFsyncErrorTest, FuseFsyncErrorTest, Values(EBADF, EIO, EROFS, EINVAL)); - -TEST_P(FuseFsyncErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, fsync(0)) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = FsyncFileReturnError(FILENAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/fsync/FuseFsyncFileDescriptorTest.cpp b/test/fspp/fuse/fsync/FuseFsyncFileDescriptorTest.cpp deleted file mode 100644 index c2765d89..00000000 --- a/test/fspp/fuse/fsync/FuseFsyncFileDescriptorTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "testutils/FuseFsyncTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; -using ::testing::Return; - -using namespace fspp::fuse; - -class FuseFsyncFileDescriptorTest: public FuseFsyncTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFsyncFileDescriptorTest, FuseFsyncFileDescriptorTest, Values(0,1,10,1000,1024*1024*1024)); - - -TEST_P(FuseFsyncFileDescriptorTest, FileDescriptorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, GetParam()); - EXPECT_CALL(*fsimpl, fsync(Eq(GetParam()))) - .Times(1).WillOnce(Return()); - - FsyncFile(FILENAME); -} diff --git a/test/fspp/fuse/fsync/testutils/FuseFsyncTest.cpp b/test/fspp/fuse/fsync/testutils/FuseFsyncTest.cpp deleted file mode 100644 index c74bbb65..00000000 --- a/test/fspp/fuse/fsync/testutils/FuseFsyncTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "FuseFsyncTest.h" - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -void FuseFsyncTest::FsyncFile(const char *filename) { - int error = FsyncFileReturnError(filename); - EXPECT_EQ(0, error); -} - -int FuseFsyncTest::FsyncFileReturnError(const char *filename) { - auto fs = TestFS(); - - auto fd = OpenFile(fs.get(), filename); - int retval = ::fsync(fd->fd()); - if (retval == 0) { - return 0; - } else { - return errno; - } -} - -unique_ref FuseFsyncTest::OpenFile(const TempTestFS *fs, const char *filename) { - auto realpath = fs->mountDir() / filename; - auto fd = make_unique_ref(realpath.string().c_str(), O_RDWR); - EXPECT_GE(fd->fd(), 0) << "Error opening file"; - return fd; -} diff --git a/test/fspp/fuse/fsync/testutils/FuseFsyncTest.h b/test/fspp/fuse/fsync/testutils/FuseFsyncTest.h deleted file mode 100644 index 25106c98..00000000 --- a/test/fspp/fuse/fsync/testutils/FuseFsyncTest.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_FSYNC_TESTUTILS_FUSEFSYNCTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_FSYNC_TESTUTILS_FUSEFSYNCTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseFsyncTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void FsyncFile(const char *filename); - int FsyncFileReturnError(const char *filename); - -private: - cpputils::unique_ref OpenFile(const TempTestFS *fs, const char *filename); -}; - -#endif diff --git a/test/fspp/fuse/ftruncate/FuseFTruncateErrorTest.cpp b/test/fspp/fuse/ftruncate/FuseFTruncateErrorTest.cpp deleted file mode 100644 index 5832c489..00000000 --- a/test/fspp/fuse/ftruncate/FuseFTruncateErrorTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "testutils/FuseFTruncateTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseFTruncateErrorTest: public FuseFTruncateTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFTruncateErrorTest, FuseFTruncateErrorTest, Values(EACCES, EFAULT, EFBIG, EINTR, EINVAL, EIO, EISDIR, ELOOP, ENAMETOOLONG, ENOENT, ENOTDIR, EPERM, EROFS, ETXTBSY, EBADF)); - -TEST_P(FuseFTruncateErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, ftruncate(0, testing::_)) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - //Needed to make ::ftruncate system call return successfully - ReturnIsFileOnFstat(0); - - int error = FTruncateFileReturnError(FILENAME, fspp::num_bytes_t(0)); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/ftruncate/FuseFTruncateFileDescriptorTest.cpp b/test/fspp/fuse/ftruncate/FuseFTruncateFileDescriptorTest.cpp deleted file mode 100644 index 93f723e8..00000000 --- a/test/fspp/fuse/ftruncate/FuseFTruncateFileDescriptorTest.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "testutils/FuseFTruncateTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; -using ::testing::Return; - -using namespace fspp::fuse; - -class FuseFTruncateFileDescriptorTest: public FuseFTruncateTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFTruncateFileDescriptorTest, FuseFTruncateFileDescriptorTest, Values(0,1,10,1000,1024*1024*1024)); - - -TEST_P(FuseFTruncateFileDescriptorTest, FileDescriptorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, GetParam()); - EXPECT_CALL(*fsimpl, ftruncate(Eq(GetParam()), testing::_)) - .Times(1).WillOnce(Return()); - //Needed to make ::ftruncate system call return successfully - ReturnIsFileOnFstat(GetParam()); - - FTruncateFile(FILENAME, fspp::num_bytes_t(0)); -} diff --git a/test/fspp/fuse/ftruncate/FuseFTruncateSizeTest.cpp b/test/fspp/fuse/ftruncate/FuseFTruncateSizeTest.cpp deleted file mode 100644 index 7560c581..00000000 --- a/test/fspp/fuse/ftruncate/FuseFTruncateSizeTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "testutils/FuseFTruncateTest.h" - -using ::testing::Eq; -using ::testing::Return; -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseFTruncateSizeTest: public FuseFTruncateTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseFTruncateSizeTest, FuseFTruncateSizeTest, Values( - fspp::num_bytes_t(0), - fspp::num_bytes_t(1), - fspp::num_bytes_t(10), - fspp::num_bytes_t(1024), - fspp::num_bytes_t(1024*1024*1024))); - - -TEST_P(FuseFTruncateSizeTest, FTruncateFile) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, ftruncate(Eq(0), GetParam())) - .Times(1).WillOnce(Return()); - //Needed to make ::ftruncate system call return successfully - ReturnIsFileOnFstat(0); - - FTruncateFile(FILENAME, fspp::num_bytes_t(GetParam())); -} diff --git a/test/fspp/fuse/ftruncate/testutils/FuseFTruncateTest.cpp b/test/fspp/fuse/ftruncate/testutils/FuseFTruncateTest.cpp deleted file mode 100644 index caa3a3dd..00000000 --- a/test/fspp/fuse/ftruncate/testutils/FuseFTruncateTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "FuseFTruncateTest.h" - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -void FuseFTruncateTest::FTruncateFile(const char *filename, fspp::num_bytes_t size) { - int error = FTruncateFileReturnError(filename, size); - EXPECT_EQ(0, error); -} - -int FuseFTruncateTest::FTruncateFileReturnError(const char *filename, fspp::num_bytes_t size) { - auto fs = TestFS(); - - auto fd = OpenFile(fs.get(), filename); - int retval = ::ftruncate(fd->fd(), size.value()); - if (0 == retval) { - return 0; - } else { - return errno; - } -} - -unique_ref FuseFTruncateTest::OpenFile(const TempTestFS *fs, const char *filename) { - auto realpath = fs->mountDir() / filename; - auto fd = make_unique_ref(realpath.string().c_str(), O_RDWR); - EXPECT_GE(fd->fd(), 0) << "Error opening file"; - return fd; -} diff --git a/test/fspp/fuse/ftruncate/testutils/FuseFTruncateTest.h b/test/fspp/fuse/ftruncate/testutils/FuseFTruncateTest.h deleted file mode 100644 index a4353d50..00000000 --- a/test/fspp/fuse/ftruncate/testutils/FuseFTruncateTest.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_FTRUNCATE_TESTUTILS_FUSEFTRUNCATETEST_H_ -#define MESSMER_FSPP_TEST_FUSE_FTRUNCATE_TESTUTILS_FUSEFTRUNCATETEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseFTruncateTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void FTruncateFile(const char *filename, fspp::num_bytes_t size); - int FTruncateFileReturnError(const char *filename, fspp::num_bytes_t size); - -private: - cpputils::unique_ref OpenFile(const TempTestFS *fs, const char *filename); -}; - -#endif diff --git a/test/fspp/fuse/lstat/FuseLstatErrorTest.cpp b/test/fspp/fuse/lstat/FuseLstatErrorTest.cpp deleted file mode 100644 index f6dd299b..00000000 --- a/test/fspp/fuse/lstat/FuseLstatErrorTest.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "testutils/FuseLstatTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::AtLeast; - -using fspp::fuse::FuseErrnoException; - -class FuseLstatErrorTest: public FuseLstatTest, public WithParamInterface { -public: -}; -INSTANTIATE_TEST_SUITE_P(LstatErrorCodes, FuseLstatErrorTest, Values(EACCES, EBADF, EFAULT, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EOVERFLOW, EINVAL, ENOTDIR)); - -TEST_F(FuseLstatErrorTest, ReturnNoError) { - EXPECT_CALL(*fsimpl, lstat(Eq(FILENAME), testing::_)).Times(AtLeast(1)).WillRepeatedly(ReturnIsFile); - errno = 0; - int error = LstatPathReturnError(FILENAME); - EXPECT_EQ(0, error); -} - -TEST_P(FuseLstatErrorTest, ReturnError) { - EXPECT_CALL(*fsimpl, lstat(Eq(FILENAME), testing::_)).Times(AtLeast(1)).WillRepeatedly(Throw(FuseErrnoException(GetParam()))); - int error = LstatPathReturnError(FILENAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/lstat/FuseLstatPathParameterTest.cpp b/test/fspp/fuse/lstat/FuseLstatPathParameterTest.cpp deleted file mode 100644 index c6ad885a..00000000 --- a/test/fspp/fuse/lstat/FuseLstatPathParameterTest.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "testutils/FuseLstatTest.h" - -using ::testing::Eq; -using ::testing::AtLeast; - -class FuseLstatPathParameterTest: public FuseLstatTest { -}; - -TEST_F(FuseLstatPathParameterTest, PathParameterIsCorrectRoot) { - EXPECT_CALL(*fsimpl, lstat(Eq("/"), testing::_)).Times(AtLeast(1)).WillRepeatedly(ReturnIsDir); - LstatPath("/"); -} - -TEST_F(FuseLstatPathParameterTest, PathParameterIsCorrectSimpleFile) { - EXPECT_CALL(*fsimpl, lstat(Eq("/myfile"), testing::_)).Times(AtLeast(1)).WillRepeatedly(ReturnIsFile); - LstatPath("/myfile"); -} - -TEST_F(FuseLstatPathParameterTest, PathParameterIsCorrectSimpleDir) { - EXPECT_CALL(*fsimpl, lstat(Eq("/mydir"), testing::_)).Times(AtLeast(1)).WillRepeatedly(ReturnIsDir); - LstatPath("/mydir/"); -} - -TEST_F(FuseLstatPathParameterTest, PathParameterIsCorrectNestedFile) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - EXPECT_CALL(*fsimpl, lstat(Eq("/mydir/mydir2/myfile"), testing::_)).Times(AtLeast(1)).WillRepeatedly(ReturnIsFile); - LstatPath("/mydir/mydir2/myfile"); -} - -TEST_F(FuseLstatPathParameterTest, PathParameterIsCorrectNestedDir) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - EXPECT_CALL(*fsimpl, lstat(Eq("/mydir/mydir2/mydir3"), testing::_)).Times(AtLeast(1)).WillRepeatedly(ReturnIsDir); - LstatPath("/mydir/mydir2/mydir3/"); -} diff --git a/test/fspp/fuse/lstat/FuseLstatReturnAtimeTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnAtimeTest.cpp deleted file mode 100644 index b5f6f5ce..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnAtimeTest.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" -#include - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnATimeTest: public FuseLstatReturnTest, public WithParamInterface { -private: - void set(fspp::fuse::STAT *stat, time_t value) override { - stat->st_atim.tv_sec = value; - stat->st_atim.tv_nsec = 0; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnATimeTest, FuseLstatReturnATimeTest, Values( - 0, - 100, - 1416496809, // current timestamp as of writing the test - 32503680000 // needs a 64bit timestamp -)); - -TEST_P(FuseLstatReturnATimeTest, ReturnedFileAtimeIsCorrect) { - fspp::fuse::STAT result = CallFileLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_atim.tv_sec); - EXPECT_EQ(0, result.st_atim.tv_nsec); -} - -TEST_P(FuseLstatReturnATimeTest, ReturnedDirAtimeIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_atim.tv_sec); - EXPECT_EQ(0, result.st_atim.tv_nsec); -} diff --git a/test/fspp/fuse/lstat/FuseLstatReturnCtimeTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnCtimeTest.cpp deleted file mode 100644 index 051c1487..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnCtimeTest.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" -#include - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnCtimeTest: public FuseLstatReturnTest, public WithParamInterface { -private: - void set(fspp::fuse::STAT *stat, time_t value) override { - stat->st_ctim.tv_sec = value; - stat->st_ctim.tv_nsec = 0; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnCtimeTest, FuseLstatReturnCtimeTest, Values( - 0, - 100, - 1416496809, // current timestamp as of writing the test - 32503680000 // needs a 64bit timestamp -)); - -TEST_P(FuseLstatReturnCtimeTest, ReturnedFileCtimeIsCorrect) { - fspp::fuse::STAT result = CallFileLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_ctim.tv_sec); - EXPECT_EQ(0, result.st_ctim.tv_nsec); -} - -TEST_P(FuseLstatReturnCtimeTest, ReturnedDirCtimeIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_ctim.tv_sec); - EXPECT_EQ(0, result.st_ctim.tv_nsec); -} diff --git a/test/fspp/fuse/lstat/FuseLstatReturnGidTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnGidTest.cpp deleted file mode 100644 index b7721778..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnGidTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnGidTest: public FuseLstatReturnTest, public WithParamInterface { -private: - void set(fspp::fuse::STAT *stat, gid_t value) override { - stat->st_gid = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnGidTest, FuseLstatReturnGidTest, Values( - 0, - 10 -)); - -TEST_P(FuseLstatReturnGidTest, ReturnedFileGidIsCorrect) { - fspp::fuse::STAT result = CallFileLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_gid); -} - -TEST_P(FuseLstatReturnGidTest, ReturnedDirGidIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_gid); -} diff --git a/test/fspp/fuse/lstat/FuseLstatReturnModeTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnModeTest.cpp deleted file mode 100644 index 87d4d28f..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnModeTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnModeTest: public FuseLstatTest, public WithParamInterface { -public: - fspp::fuse::STAT CallLstatWithValue(mode_t mode) { - return CallLstatWithImpl([mode] (fspp::fuse::STAT *stat) { - stat->st_mode = mode; - }); - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnModeTest, FuseLstatReturnModeTest, Values( - S_IFREG, - S_IFDIR, - S_IFREG | S_IRUSR | S_IWGRP | S_IXOTH, // a file with some access bits set - S_IFDIR | S_IWUSR | S_IXGRP | S_IROTH // a dir with some access bits set -)); - -TEST_P(FuseLstatReturnModeTest, ReturnedModeIsCorrect) { - fspp::fuse::STAT result = CallLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_mode); -} diff --git a/test/fspp/fuse/lstat/FuseLstatReturnMtimeTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnMtimeTest.cpp deleted file mode 100644 index a01f3180..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnMtimeTest.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" -#include - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnMtimeTest: public FuseLstatReturnTest, public WithParamInterface { -private: - void set(fspp::fuse::STAT *stat, time_t value) override { - stat->st_mtim.tv_sec = value; - stat->st_mtim.tv_nsec = 0; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnMtimeTest, FuseLstatReturnMtimeTest, Values( - 0, - 100, - 1416496809, // current timestamp as of writing the test - 32503680000 // needs a 64bit timestamp -)); - -TEST_P(FuseLstatReturnMtimeTest, ReturnedFileMtimeIsCorrect) { - fspp::fuse::STAT result = CallFileLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_mtim.tv_sec); - EXPECT_EQ(0, result.st_mtim.tv_nsec); -} - -TEST_P(FuseLstatReturnMtimeTest, ReturnedDirMtimeIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_mtim.tv_sec); - EXPECT_EQ(0, result.st_mtim.tv_nsec); -} diff --git a/test/fspp/fuse/lstat/FuseLstatReturnNlinkTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnNlinkTest.cpp deleted file mode 100644 index cb0e7fc9..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnNlinkTest.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnNlinkTest: public FuseLstatReturnTest, public WithParamInterface { -private: - void set(fspp::fuse::STAT *stat, nlink_t value) override { - stat->st_nlink = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnNlinkTest, FuseLstatReturnNlinkTest, Values( - 1, - 2, - 5, - 100 -)); - -TEST_P(FuseLstatReturnNlinkTest, ReturnedFileNlinkIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_nlink); -} - -TEST_P(FuseLstatReturnNlinkTest, ReturnedDirNlinkIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_nlink); -} - diff --git a/test/fspp/fuse/lstat/FuseLstatReturnSizeTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnSizeTest.cpp deleted file mode 100644 index 40dd7f0d..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnSizeTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnSizeTest: public FuseLstatReturnTest, public WithParamInterface { -private: - void set(fspp::fuse::STAT *stat, fspp::num_bytes_t value) override { - stat->st_size = value.value(); - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnSizeTest, FuseLstatReturnSizeTest, Values( - fspp::num_bytes_t(0), - fspp::num_bytes_t(1), - fspp::num_bytes_t(4096), - fspp::num_bytes_t(1024*1024*1024) -)); - -TEST_P(FuseLstatReturnSizeTest, ReturnedFileSizeIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), fspp::num_bytes_t(result.st_size)); -} - -TEST_P(FuseLstatReturnSizeTest, ReturnedDirSizeIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), fspp::num_bytes_t(result.st_size)); -} diff --git a/test/fspp/fuse/lstat/FuseLstatReturnUidTest.cpp b/test/fspp/fuse/lstat/FuseLstatReturnUidTest.cpp deleted file mode 100644 index 25ca37bb..00000000 --- a/test/fspp/fuse/lstat/FuseLstatReturnUidTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "testutils/FuseLstatReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseLstatReturnUidTest: public FuseLstatReturnTest, public WithParamInterface { -private: - void set(fspp::fuse::STAT *stat, uid_t value) override { - stat->st_uid = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseLstatReturnUidTest, FuseLstatReturnUidTest, Values( - 0, - 10 -)); - -TEST_P(FuseLstatReturnUidTest, ReturnedFileUidIsCorrect) { - fspp::fuse::STAT result = CallFileLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_uid); -} - -TEST_P(FuseLstatReturnUidTest, ReturnedDirUidIsCorrect) { - fspp::fuse::STAT result = CallDirLstatWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.st_uid); -} diff --git a/test/fspp/fuse/lstat/testutils/FuseLstatReturnTest.h b/test/fspp/fuse/lstat/testutils/FuseLstatReturnTest.h deleted file mode 100644 index 832262be..00000000 --- a/test/fspp/fuse/lstat/testutils/FuseLstatReturnTest.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_LSTAT_TESTUTILS_FUSELSTATRETURNTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_LSTAT_TESTUTILS_FUSELSTATRETURNTEST_H_ - -#include "FuseLstatTest.h" - -// This class offers test helpers for testing (fspp::fuse::STAT) entries. We return them from -// our mock filesystem, set up a temporary filesystem, call lstat syscall on it, and -// then check the return value. -template -class FuseLstatReturnTest: public FuseLstatTest { -public: - // Set the specified (fspp::fuse::STAT) entry to the given value, and test whether it is correctly returned from the syscall. - // The CallFile[...] version tests it on a file node of the filesystem, the CallDir[...] version on a dir node. - fspp::fuse::STAT CallFileLstatWithValue(Property value); - fspp::fuse::STAT CallDirLstatWithValue(Property value); - -private: - std::function SetPropertyImpl(Property value); - - // Override this function to specify, how to set the specified (fspp::fuse::STAT) entry on the passed (fspp::fuse::STAT *) object. - virtual void set(fspp::fuse::STAT *stat, Property value) = 0; -}; - -template -fspp::fuse::STAT FuseLstatReturnTest::CallFileLstatWithValue(Property value) { - return CallFileLstatWithImpl(SetPropertyImpl(value)); -} - -template -fspp::fuse::STAT FuseLstatReturnTest::CallDirLstatWithValue(Property value) { - return CallDirLstatWithImpl(SetPropertyImpl(value)); -} - -template -std::function FuseLstatReturnTest::SetPropertyImpl(Property value) { - return [this, value] (fspp::fuse::STAT *stat) { - set(stat, value); - }; -} - - -#endif diff --git a/test/fspp/fuse/lstat/testutils/FuseLstatTest.cpp b/test/fspp/fuse/lstat/testutils/FuseLstatTest.cpp deleted file mode 100644 index d0246eba..00000000 --- a/test/fspp/fuse/lstat/testutils/FuseLstatTest.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "FuseLstatTest.h" - -using std::function; -using ::testing::Eq; -using ::testing::Invoke; - -void FuseLstatTest::LstatPath(const std::string &path) { - fspp::fuse::STAT dummy{}; - LstatPath(path, &dummy); -} - -int FuseLstatTest::LstatPathReturnError(const std::string &path) { - fspp::fuse::STAT dummy{}; - return LstatPathReturnError(path, &dummy); -} - -void FuseLstatTest::LstatPath(const std::string &path, fspp::fuse::STAT *result) { - int error = LstatPathReturnError(path, result); - EXPECT_EQ(0, error) << "lstat syscall failed. errno: " << error; -} - -int FuseLstatTest::LstatPathReturnError(const std::string &path, fspp::fuse::STAT *result) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / path; - int retval = ::lstat(realpath.string().c_str(), result); - if (retval == 0) { - return 0; - } else { - return errno; - } -} - -fspp::fuse::STAT FuseLstatTest::CallFileLstatWithImpl(function implementation) { - return CallLstatWithModeAndImpl(S_IFREG, implementation); -} - -fspp::fuse::STAT FuseLstatTest::CallDirLstatWithImpl(function implementation) { - return CallLstatWithModeAndImpl(S_IFDIR, implementation); -} - -fspp::fuse::STAT FuseLstatTest::CallLstatWithImpl(function implementation) { - EXPECT_CALL(*fsimpl, lstat(Eq(FILENAME), testing::_)).WillRepeatedly(Invoke([implementation](const boost::filesystem::path&, fspp::fuse::STAT *stat) { - implementation(stat); - })); - - fspp::fuse::STAT result{}; - LstatPath(FILENAME, &result); - - return result; -} - -fspp::fuse::STAT FuseLstatTest::CallLstatWithModeAndImpl(mode_t mode, function implementation) { - return CallLstatWithImpl([mode, implementation] (fspp::fuse::STAT *stat) { - stat->st_mode = mode; - implementation(stat); - }); -} diff --git a/test/fspp/fuse/lstat/testutils/FuseLstatTest.h b/test/fspp/fuse/lstat/testutils/FuseLstatTest.h deleted file mode 100644 index ab07ac38..00000000 --- a/test/fspp/fuse/lstat/testutils/FuseLstatTest.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_LSTAT_TESTUTILS_FUSELSTATTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_LSTAT_TESTUTILS_FUSELSTATTEST_H_ - -#include -#include -#include - -#include "../../../testutils/FuseTest.h" - -// This class offers some utility functions for testing lstat(). -class FuseLstatTest: public FuseTest { -protected: - const char *FILENAME = "/myfile"; - - // Set up a temporary filesystem (using the fsimpl mock in FuseTest as filesystem implementation) - // and call the lstat syscall on the given (filesystem-relative) path. - void LstatPath(const std::string &path); - // Same as LstatPath above, but also return the result of the lstat syscall. - void LstatPath(const std::string &path, fspp::fuse::STAT *result); - - // These two functions are the same as LstatPath above, but they don't fail the test when the lstat syscall - // crashes. Instead, they return the value of errno after calling ::lstat. - int LstatPathReturnError(const std::string &path); - int LstatPathReturnError(const std::string &path, fspp::fuse::STAT *result); - - // You can specify an implementation, which can modify the (fspp::fuse::STAT *) result, - // our fuse mock filesystem implementation will then return this to fuse on an lstat call. - // This functions then set up a temporary filesystem with this mock, call lstat on a filesystem node - // and return the (fspp::fuse::STAT) returned from an lstat syscall to this filesystem. - fspp::fuse::STAT CallLstatWithImpl(std::function implementation); - - // These two functions are like CallLstatWithImpl, but they also modify the (fspp::fuse::STAT).st_mode - // field, so the node accessed is specified to be a file/directory. - fspp::fuse::STAT CallFileLstatWithImpl(std::function implementation); - fspp::fuse::STAT CallDirLstatWithImpl(std::function implementation); - -private: - - fspp::fuse::STAT CallLstatWithModeAndImpl(mode_t mode, std::function implementation); -}; - -#endif diff --git a/test/fspp/fuse/mkdir/FuseMkdirDirnameTest.cpp b/test/fspp/fuse/mkdir/FuseMkdirDirnameTest.cpp deleted file mode 100644 index c09bc6f4..00000000 --- a/test/fspp/fuse/mkdir/FuseMkdirDirnameTest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "testutils/FuseMkdirTest.h" - -using ::testing::Eq; - -class FuseMkdirDirnameTest: public FuseMkdirTest { -}; - -TEST_F(FuseMkdirDirnameTest, Mkdir) { - ReturnDoesntExistOnLstat("/mydir"); - EXPECT_CALL(*fsimpl, mkdir(Eq("/mydir"), testing::_, testing::_, testing::_)) - // After mkdir was called, lstat should return that it is a dir. - // This is needed to make the ::mkdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnIsDirOnLstat()); - - Mkdir("/mydir", 0); -} - -TEST_F(FuseMkdirDirnameTest, MkdirNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnDoesntExistOnLstat("/mydir/mysubdir"); - EXPECT_CALL(*fsimpl, mkdir(Eq("/mydir/mysubdir"), testing::_, testing::_, testing::_)) - // After mkdir was called, lstat should return that it is a dir. - // This is needed to make the ::mkdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnIsDirOnLstat()); - - Mkdir("/mydir/mysubdir", 0); -} - -TEST_F(FuseMkdirDirnameTest, MkdirNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnDoesntExistOnLstat("/mydir/mydir2/mydir3"); - EXPECT_CALL(*fsimpl, mkdir(Eq("/mydir/mydir2/mydir3"), testing::_, testing::_, testing::_)) - // After mkdir was called, lstat should return that it is a dir. - // This is needed to make the ::mkdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnIsDirOnLstat()); - - Mkdir("/mydir/mydir2/mydir3", 0); -} diff --git a/test/fspp/fuse/mkdir/FuseMkdirErrorTest.cpp b/test/fspp/fuse/mkdir/FuseMkdirErrorTest.cpp deleted file mode 100644 index e4cb487c..00000000 --- a/test/fspp/fuse/mkdir/FuseMkdirErrorTest.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "testutils/FuseMkdirTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseMkdirErrorTest: public FuseMkdirTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseMkdirErrorTest, FuseMkdirErrorTest, Values(EACCES, EDQUOT, EEXIST, EFAULT, ELOOP, EMLINK, ENAMETOOLONG, ENOENT, ENOMEM, ENOSPC, ENOTDIR, EPERM, EROFS, EBADF)); - -TEST_F(FuseMkdirErrorTest, NoError) { - ReturnDoesntExistOnLstat(DIRNAME); - EXPECT_CALL(*fsimpl, mkdir(Eq(DIRNAME), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(FromNowOnReturnIsDirOnLstat()); - - int error = MkdirReturnError(DIRNAME, 0); - EXPECT_EQ(0, error); -} - -TEST_P(FuseMkdirErrorTest, ReturnedErrorIsCorrect) { - ReturnDoesntExistOnLstat(DIRNAME); - EXPECT_CALL(*fsimpl, mkdir(Eq(DIRNAME), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = MkdirReturnError(DIRNAME, 0); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/mkdir/FuseMkdirModeTest.cpp b/test/fspp/fuse/mkdir/FuseMkdirModeTest.cpp deleted file mode 100644 index 31b0c45f..00000000 --- a/test/fspp/fuse/mkdir/FuseMkdirModeTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "testutils/FuseMkdirTest.h" - -using ::testing::Eq; -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseMkdirModeTest: public FuseMkdirTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseMkdirModeTest, FuseMkdirModeTest, Values(0, S_IRUSR, S_IRGRP, S_IXOTH, S_IRUSR|S_IRGRP|S_IROTH|S_IRGRP)); - - -TEST_P(FuseMkdirModeTest, Mkdir) { - ReturnDoesntExistOnLstat(DIRNAME); - EXPECT_CALL(*fsimpl, mkdir(Eq(DIRNAME), GetParam(), testing::_, testing::_)) - .Times(1).WillOnce(FromNowOnReturnIsDirOnLstat()); - - Mkdir(DIRNAME, GetParam()); -} diff --git a/test/fspp/fuse/mkdir/testutils/FuseMkdirTest.cpp b/test/fspp/fuse/mkdir/testutils/FuseMkdirTest.cpp deleted file mode 100644 index 17c18457..00000000 --- a/test/fspp/fuse/mkdir/testutils/FuseMkdirTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "FuseMkdirTest.h" - -using ::testing::Action; -using ::testing::Invoke; - -void FuseMkdirTest::Mkdir(const char *dirname, mode_t mode) { - int error = MkdirReturnError(dirname, mode); - EXPECT_EQ(0, error); -} - -int FuseMkdirTest::MkdirReturnError(const char *dirname, mode_t mode) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / dirname; - int retval = ::mkdir(realpath.string().c_str(), mode); - if (retval == 0) { - return 0; - } else { - return errno; - } -} - -Action FuseMkdirTest::FromNowOnReturnIsDirOnLstat() { - return Invoke([this](const boost::filesystem::path& dirname, mode_t, uid_t, gid_t) { - ReturnIsDirOnLstat(dirname); - }); -} diff --git a/test/fspp/fuse/mkdir/testutils/FuseMkdirTest.h b/test/fspp/fuse/mkdir/testutils/FuseMkdirTest.h deleted file mode 100644 index 0491113f..00000000 --- a/test/fspp/fuse/mkdir/testutils/FuseMkdirTest.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_MKDIR_TESTUTILS_FUSEMKDIRTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_MKDIR_TESTUTILS_FUSEMKDIRTEST_H_ - -#include "../../../testutils/FuseTest.h" - -class FuseMkdirTest: public FuseTest { -public: - const char *DIRNAME = "/mydir"; - - void Mkdir(const char *dirname, mode_t mode); - int MkdirReturnError(const char *dirname, mode_t mode); - - ::testing::Action FromNowOnReturnIsDirOnLstat(); -}; - -#endif diff --git a/test/fspp/fuse/openFile/FuseOpenErrorTest.cpp b/test/fspp/fuse/openFile/FuseOpenErrorTest.cpp deleted file mode 100644 index ac08f060..00000000 --- a/test/fspp/fuse/openFile/FuseOpenErrorTest.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "testutils/FuseOpenTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Return; -using ::testing::Throw; -using ::testing::Eq; - -using namespace fspp::fuse; - -class FuseOpenErrorTest: public FuseOpenTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseOpenErrorTest, FuseOpenErrorTest, Values(EACCES, EDQUOT, EEXIST, EFAULT, EFBIG, EINTR, EOVERFLOW, EINVAL, EISDIR, ELOOP, EMFILE, ENAMETOOLONG, ENFILE, ENODEV, ENOENT, ENOMEM, ENOSPC, ENOTDIR, ENXIO, EOPNOTSUPP, EPERM, EROFS, ETXTBSY, EWOULDBLOCK, EBADF, ENOTDIR)); - -TEST_F(FuseOpenErrorTest, ReturnNoError) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, openFile(Eq(FILENAME), testing::_)).Times(1).WillOnce(Return(1)); - errno = 0; - int error = OpenFileReturnError(FILENAME, O_RDONLY); - EXPECT_EQ(0, error); -} - -TEST_P(FuseOpenErrorTest, ReturnError) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, openFile(Eq(FILENAME), testing::_)).Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - int error = OpenFileReturnError(FILENAME, O_RDONLY); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/openFile/FuseOpenFileDescriptorTest.cpp b/test/fspp/fuse/openFile/FuseOpenFileDescriptorTest.cpp deleted file mode 100644 index f4ddfa92..00000000 --- a/test/fspp/fuse/openFile/FuseOpenFileDescriptorTest.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "testutils/FuseOpenTest.h" - -using ::testing::Eq; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Return; -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -class FuseOpenFileDescriptorTest: public FuseOpenTest, public WithParamInterface { -public: - void OpenAndReadFile(const char *filename) { - auto fs = TestFS(); - - auto fd = OpenFile(fs.get(), filename); - ReadFile(fd->fd()); - } - -private: - unique_ref OpenFile(const TempTestFS *fs, const char *filename) { - auto realpath = fs->mountDir() / filename; - auto fd = make_unique_ref(realpath.string().c_str(), O_RDONLY); - EXPECT_GE(fd->fd(), 0) << "Opening file failed"; - return fd; - } - void ReadFile(int fd) { - uint8_t buf = 0; - int retval = ::read(fd, &buf, 1); - EXPECT_EQ(1, retval) << "Reading file failed"; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseOpenFileDescriptorTest, FuseOpenFileDescriptorTest, Values(0, 2, 5, 1000, 1024*1024*1024)); - -TEST_P(FuseOpenFileDescriptorTest, TestReturnedFileDescriptor) { - ReturnIsFileOnLstatWithSize(FILENAME, fspp::num_bytes_t(1)); - EXPECT_CALL(*fsimpl, openFile(Eq(FILENAME), testing::_)) - .Times(1).WillOnce(Return(GetParam())); - EXPECT_CALL(*fsimpl, read(GetParam(), testing::_, testing::_, testing::_)).Times(1).WillOnce(Return(fspp::num_bytes_t(1))); - - OpenAndReadFile(FILENAME); -} - diff --git a/test/fspp/fuse/openFile/FuseOpenFilenameTest.cpp b/test/fspp/fuse/openFile/FuseOpenFilenameTest.cpp deleted file mode 100644 index a09a3f20..00000000 --- a/test/fspp/fuse/openFile/FuseOpenFilenameTest.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "testutils/FuseOpenTest.h" - -using ::testing::Eq; -using ::testing::Return; - -class FuseOpenFilenameTest: public FuseOpenTest { -public: -}; - -TEST_F(FuseOpenFilenameTest, OpenFile) { - ReturnIsFileOnLstat("/myfile"); - EXPECT_CALL(*fsimpl, openFile(Eq("/myfile"), testing::_)) - .Times(1).WillOnce(Return(0)); - - OpenFile("/myfile", O_RDONLY); -} - -TEST_F(FuseOpenFilenameTest, OpenFileNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsFileOnLstat("/mydir/myfile"); - EXPECT_CALL(*fsimpl, openFile(Eq("/mydir/myfile"), testing::_)) - .Times(1).WillOnce(Return(0)); - - OpenFile("/mydir/myfile", O_RDONLY); -} - -TEST_F(FuseOpenFilenameTest, OpenFileNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsFileOnLstat("/mydir/mydir2/myfile"); - EXPECT_CALL(*fsimpl, openFile(Eq("/mydir/mydir2/myfile"), testing::_)) - .Times(1).WillOnce(Return(0)); - - OpenFile("/mydir/mydir2/myfile", O_RDONLY); -} diff --git a/test/fspp/fuse/openFile/FuseOpenFlagsTest.cpp b/test/fspp/fuse/openFile/FuseOpenFlagsTest.cpp deleted file mode 100644 index 137634f6..00000000 --- a/test/fspp/fuse/openFile/FuseOpenFlagsTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "testutils/FuseOpenTest.h" - -using ::testing::Eq; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Return; - -class FuseOpenFlagsTest: public FuseOpenTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseOpenFlagsTest, FuseOpenFlagsTest, Values(O_RDWR, O_RDONLY, O_WRONLY)); - -TEST_P(FuseOpenFlagsTest, testFlags) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, openFile(Eq(FILENAME), OpenFlagsEq(GetParam()))) - .Times(1).WillOnce(Return(0)); - - OpenFile(FILENAME, GetParam()); -} diff --git a/test/fspp/fuse/openFile/testutils/FuseOpenTest.cpp b/test/fspp/fuse/openFile/testutils/FuseOpenTest.cpp deleted file mode 100644 index ddb32b6b..00000000 --- a/test/fspp/fuse/openFile/testutils/FuseOpenTest.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "FuseOpenTest.h" - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -void FuseOpenTest::OpenFile(const char *filename, int flags) { - auto fs = TestFS(); - auto fd = OpenFileAllowError(fs.get(), filename, flags); - EXPECT_GE(fd->fd(), 0); -} - -int FuseOpenTest::OpenFileReturnError(const char *filename, int flags) { - auto fs = TestFS(); - auto fd = OpenFileAllowError(fs.get(), filename, flags); - return fd->errorcode(); -} - -unique_ref FuseOpenTest::OpenFileAllowError(const TempTestFS *fs, const char *filename, int flags) { - auto realpath = fs->mountDir() / filename; - return make_unique_ref(realpath.string().c_str(), flags); -} diff --git a/test/fspp/fuse/openFile/testutils/FuseOpenTest.h b/test/fspp/fuse/openFile/testutils/FuseOpenTest.h deleted file mode 100644 index 2c709524..00000000 --- a/test/fspp/fuse/openFile/testutils/FuseOpenTest.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_OPENFILE_TESTUTILS_FUSEOPENTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_OPENFILE_TESTUTILS_FUSEOPENTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseOpenTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void OpenFile(const char *FILENAME, int flags); - int OpenFileReturnError(const char *FILENAME, int flags); -private: - cpputils::unique_ref OpenFileAllowError(const TempTestFS *fs, const char *FILENAME, int flags); -}; - -MATCHER_P(OpenFlagsEq, expectedFlags, "") { - return expectedFlags == (O_ACCMODE & arg); -} - -#endif diff --git a/test/fspp/fuse/read/FuseReadErrorTest.cpp b/test/fspp/fuse/read/FuseReadErrorTest.cpp deleted file mode 100644 index 3772a1c1..00000000 --- a/test/fspp/fuse/read/FuseReadErrorTest.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "testutils/FuseReadTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; -using ::testing::Ne; -using ::testing::Invoke; -using ::testing::Throw; - -using namespace fspp::fuse; - -class FuseReadErrorTest: public FuseReadTest, public WithParamInterface { -public: - fspp::num_bytes_t FILESIZE = fspp::num_bytes_t(64*1024*1024); - fspp::num_bytes_t READCOUNT = fspp::num_bytes_t(32*1024*1024); - - void SetUp() override { - //Make the file size big enough that fuse should issue at least two reads - ReturnIsFileOnLstatWithSize(FILENAME, FILESIZE); - OnOpenReturnFileDescriptor(FILENAME, 0); - } -}; -INSTANTIATE_TEST_SUITE_P(FuseReadErrorTest, FuseReadErrorTest, Values(EAGAIN, EBADF, EFAULT, EINTR, EINVAL, EIO, EISDIR, EOVERFLOW, ESPIPE, ENXIO)); - - -TEST_P(FuseReadErrorTest, ReturnErrorOnFirstReadCall) { - EXPECT_CALL(*fsimpl, read(0, testing::_, testing::_, testing::_)) - .WillRepeatedly(Throw(FuseErrnoException(GetParam()))); - - char *buf = new char[READCOUNT.value()]; - auto retval = ReadFileReturnError(FILENAME, buf, READCOUNT, fspp::num_bytes_t(0)); - EXPECT_EQ(GetParam(), retval.error); - delete[] buf; -} - -TEST_P(FuseReadErrorTest, ReturnErrorOnSecondReadCall) { - // The first read request is from the beginning of the file and works, but the later ones fail. - // We store the number of bytes the first call could successfully read and check later that our - // read syscall returns exactly this number of bytes - fspp::num_bytes_t successfullyReadBytes = fspp::num_bytes_t(-1); - EXPECT_CALL(*fsimpl, read(0, testing::_, testing::_, Eq(fspp::num_bytes_t(0)))) - .Times(1) - .WillOnce(Invoke([&successfullyReadBytes](int, void*, fspp::num_bytes_t count, fspp::num_bytes_t) { - // Store the number of successfully read bytes - successfullyReadBytes = count; - return count; - })); - EXPECT_CALL(*fsimpl, read(0, testing::_, testing::_, Ne(fspp::num_bytes_t(0)))) - .WillRepeatedly(Throw(FuseErrnoException(GetParam()))); - - char *buf = new char[READCOUNT.value()]; - auto retval = ReadFileReturnError(FILENAME, buf, READCOUNT, fspp::num_bytes_t(0)); - EXPECT_EQ(0, retval.error); - EXPECT_EQ(successfullyReadBytes, retval.read_bytes); // Check that we're getting the number of successfully read bytes (the first read call) returned - delete[] buf; -} diff --git a/test/fspp/fuse/read/FuseReadFileDescriptorTest.cpp b/test/fspp/fuse/read/FuseReadFileDescriptorTest.cpp deleted file mode 100644 index 1a5d8d39..00000000 --- a/test/fspp/fuse/read/FuseReadFileDescriptorTest.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "testutils/FuseReadTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; - -using namespace fspp::fuse; - -class FuseReadFileDescriptorTest: public FuseReadTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseReadFileDescriptorTest, FuseReadFileDescriptorTest, Values(0,1,10,1000,1024*1024*1024)); - - -TEST_P(FuseReadFileDescriptorTest, FileDescriptorIsCorrect) { - ReturnIsFileOnLstatWithSize(FILENAME, fspp::num_bytes_t(1)); - OnOpenReturnFileDescriptor(FILENAME, GetParam()); - EXPECT_CALL(*fsimpl, read(Eq(GetParam()), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(ReturnSuccessfulRead); - - std::array buf{}; - ReadFile(FILENAME, buf.data(), fspp::num_bytes_t(1), fspp::num_bytes_t(0)); -} diff --git a/test/fspp/fuse/read/FuseReadOverflowTest.cpp b/test/fspp/fuse/read/FuseReadOverflowTest.cpp deleted file mode 100644 index ef39f6fe..00000000 --- a/test/fspp/fuse/read/FuseReadOverflowTest.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "testutils/FuseReadTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using namespace fspp::fuse; - -class FuseReadOverflowTest: public FuseReadTest { -public: - static constexpr fspp::num_bytes_t FILESIZE = fspp::num_bytes_t(1000); - static constexpr fspp::num_bytes_t READSIZE = fspp::num_bytes_t(2000); - static constexpr fspp::num_bytes_t OFFSET = fspp::num_bytes_t(500); - - void SetUp() override { - ReturnIsFileOnLstatWithSize(FILENAME, FILESIZE); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, read(0, testing::_, testing::_, testing::_)).WillRepeatedly(ReturnSuccessfulReadRegardingSize(FILESIZE)); - } -}; - -constexpr fspp::num_bytes_t FuseReadOverflowTest::FILESIZE; -constexpr fspp::num_bytes_t FuseReadOverflowTest::READSIZE; -constexpr fspp::num_bytes_t FuseReadOverflowTest::OFFSET; - - -TEST_F(FuseReadOverflowTest, ReadMoreThanFileSizeFromBeginning) { - std::array buf{}; - auto retval = ReadFileReturnError(FILENAME, buf.data(), READSIZE, fspp::num_bytes_t(0)); - EXPECT_EQ(FILESIZE, retval.read_bytes); -} - -TEST_F(FuseReadOverflowTest, ReadMoreThanFileSizeFromMiddle) { - std::array buf{}; - auto retval = ReadFileReturnError(FILENAME, buf.data(), READSIZE, OFFSET); - EXPECT_EQ(FILESIZE-OFFSET, retval.read_bytes); -} diff --git a/test/fspp/fuse/read/FuseReadReturnedDataTest.cpp b/test/fspp/fuse/read/FuseReadReturnedDataTest.cpp deleted file mode 100644 index 54d3ed28..00000000 --- a/test/fspp/fuse/read/FuseReadReturnedDataTest.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include -#include "../../testutils/InMemoryFile.h" -#include "testutils/FuseReadTest.h" -#include - -#include "fspp/fs_interface/FuseErrnoException.h" - -#include -#include - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Combine; -using ::testing::Invoke; -using ::testing::Action; - -using std::tuple; -using std::get; -using cpputils::Data; -using cpputils::DataFixture; - -using namespace fspp::fuse; - -// We can't test the count or size parameter directly, because fuse doesn't pass them 1:1. -// It usually asks to read bigger blocks (probably does some caching). -// But we can test that the data returned from the ::read syscall is the correct data region. - -struct TestData { - TestData(): count(0), offset(0), additional_bytes_at_end_of_file(0) {} - TestData(const tuple &data): count(get<0>(data)), offset(get<1>(data)), additional_bytes_at_end_of_file(get<2>(data)) {} - fspp::num_bytes_t count; - fspp::num_bytes_t offset; - //How many more bytes does the file have after the read block? - fspp::num_bytes_t additional_bytes_at_end_of_file; - fspp::num_bytes_t fileSize() { - return count + offset + additional_bytes_at_end_of_file; - } -}; - -// The testcase creates random data in memory, offers a mock read() implementation to read from this -// memory region and check methods to check for data equality of a region. -class FuseReadReturnedDataTest: public FuseReadTest, public WithParamInterface> { -public: - std::unique_ptr testFile; - TestData testData; - - FuseReadReturnedDataTest() - : testFile(nullptr), - testData(GetParam()) { - testFile = std::make_unique(DataFixture::generate(testData.fileSize().value())); - ReturnIsFileOnLstatWithSize(FILENAME, testData.fileSize()); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, read(0, testing::_, testing::_, testing::_)) - .WillRepeatedly(ReadFromFile); - } - - // This read() mock implementation reads from the stored virtual file (testFile). - Action ReadFromFile = Invoke([this](int, void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - return testFile->read(buf, count, offset); - }); -}; -INSTANTIATE_TEST_SUITE_P(FuseReadReturnedDataTest, FuseReadReturnedDataTest, Combine( - Values(fspp::num_bytes_t(0), fspp::num_bytes_t(1), fspp::num_bytes_t(10), fspp::num_bytes_t(1000), fspp::num_bytes_t(1024), fspp::num_bytes_t(10*1024*1024)), - Values(fspp::num_bytes_t(0), fspp::num_bytes_t(1), fspp::num_bytes_t(10), fspp::num_bytes_t(1024), fspp::num_bytes_t(10*1024*1024)), - Values(fspp::num_bytes_t(0), fspp::num_bytes_t(1), fspp::num_bytes_t(10), fspp::num_bytes_t(1024), fspp::num_bytes_t(10*1024*1024)) - )); - - -TEST_P(FuseReadReturnedDataTest, ReturnedDataRangeIsCorrect) { - Data buf(testData.count.value()); - ReadFile(FILENAME, buf.data(), testData.count, testData.offset); - EXPECT_TRUE(testFile->fileContentEquals(buf, testData.offset)); -} diff --git a/test/fspp/fuse/read/testutils/FuseReadTest.cpp b/test/fspp/fuse/read/testutils/FuseReadTest.cpp deleted file mode 100644 index 97d7e94a..00000000 --- a/test/fspp/fuse/read/testutils/FuseReadTest.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "FuseReadTest.h" - -using cpputils::make_unique_ref; -using cpputils::unique_ref; - -void FuseReadTest::ReadFile(const char *filename, void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - auto retval = ReadFileReturnError(filename, buf, count, offset); - EXPECT_EQ(0, retval.error); - EXPECT_EQ(count, retval.read_bytes); -} - -FuseReadTest::ReadError FuseReadTest::ReadFileReturnError(const char *filename, void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - auto fs = TestFS(); - - auto fd = OpenFile(fs.get(), filename); - - ReadError result{}; - errno = 0; - result.read_bytes = fspp::num_bytes_t(::pread(fd->fd(), buf, count.value(), offset.value())); - result.error = errno; - return result; -} - -unique_ref FuseReadTest::OpenFile(const TempTestFS *fs, const char *filename) { - auto realpath = fs->mountDir() / filename; - auto fd = make_unique_ref(realpath.string().c_str(), O_RDONLY); - EXPECT_GE(fd->fd(), 0) << "Error opening file"; - return fd; -} diff --git a/test/fspp/fuse/read/testutils/FuseReadTest.h b/test/fspp/fuse/read/testutils/FuseReadTest.h deleted file mode 100644 index 7827d521..00000000 --- a/test/fspp/fuse/read/testutils/FuseReadTest.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_READ_TESTUTILS_FUSEREADTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_READ_TESTUTILS_FUSEREADTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseReadTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - struct ReadError { - int error{}; - fspp::num_bytes_t read_bytes; - }; - - void ReadFile(const char *filename, void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset); - ReadError ReadFileReturnError(const char *filename, void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset); - - ::testing::Action ReturnSuccessfulRead = - ::testing::Invoke([](int, void *, fspp::num_bytes_t count, fspp::num_bytes_t) { - return count; - }); - - ::testing::Action ReturnSuccessfulReadRegardingSize(fspp::num_bytes_t filesize) { - return ::testing::Invoke([filesize](int, void *, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - fspp::num_bytes_t ableToReadCount = std::min(count, filesize - offset); - return ableToReadCount; - }); - } - -private: - cpputils::unique_ref OpenFile(const TempTestFS *fs, const char *filename); -}; - -#endif diff --git a/test/fspp/fuse/readDir/FuseReadDirDirnameTest.cpp b/test/fspp/fuse/readDir/FuseReadDirDirnameTest.cpp deleted file mode 100644 index f569315c..00000000 --- a/test/fspp/fuse/readDir/FuseReadDirDirnameTest.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "testutils/FuseReadDirTest.h" - -using ::testing::Eq; - -using std::string; - -class FuseReadDirDirnameTest: public FuseReadDirTest { -public: -}; - -TEST_F(FuseReadDirDirnameTest, ReadRootDir) { - EXPECT_CALL(*fsimpl, readDir(Eq("/"))) - .Times(1).WillOnce(ReturnDirEntries({})); - - ReadDir("/"); -} - -TEST_F(FuseReadDirDirnameTest, ReadDir) { - ReturnIsDirOnLstat("/mydir"); - EXPECT_CALL(*fsimpl, readDir(Eq("/mydir"))) - .Times(1).WillOnce(ReturnDirEntries({})); - - ReadDir("/mydir"); -} - -TEST_F(FuseReadDirDirnameTest, ReadDirNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - EXPECT_CALL(*fsimpl, readDir(Eq("/mydir/mydir2"))) - .Times(1).WillOnce(ReturnDirEntries({})); - - ReadDir("/mydir/mydir2"); -} - -TEST_F(FuseReadDirDirnameTest, ReadDirNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsDirOnLstat("/mydir/mydir2/mydir3"); - EXPECT_CALL(*fsimpl, readDir(Eq("/mydir/mydir2/mydir3"))) - .Times(1).WillOnce(ReturnDirEntries({})); - - ReadDir("/mydir/mydir2/mydir3"); -} diff --git a/test/fspp/fuse/readDir/FuseReadDirErrorTest.cpp b/test/fspp/fuse/readDir/FuseReadDirErrorTest.cpp deleted file mode 100644 index ffb96f21..00000000 --- a/test/fspp/fuse/readDir/FuseReadDirErrorTest.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "testutils/FuseReadDirTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using std::string; - -using namespace fspp::fuse; - -class FuseReadDirErrorTest: public FuseReadDirTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseReadDirErrorTest, FuseReadDirErrorTest, Values(EACCES, EBADF, EMFILE, ENFILE, ENOMEM, ENOTDIR, EFAULT, EINVAL)); - -//TODO On ENOENT, libfuse doesn't return the ENOENT error, but returns a success response with an empty directory. Why? - -TEST_F(FuseReadDirErrorTest, NoError) { - ReturnIsDirOnLstat(DIRNAME); - EXPECT_CALL(*fsimpl, readDir(Eq(DIRNAME))) - .Times(1).WillOnce(ReturnDirEntries({})); - - int error = ReadDirReturnError(DIRNAME); - EXPECT_EQ(0, error); -} - -TEST_P(FuseReadDirErrorTest, ReturnedErrorCodeIsCorrect) { - ReturnIsDirOnLstat(DIRNAME); - EXPECT_CALL(*fsimpl, readDir(Eq(DIRNAME))) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = ReadDirReturnError(DIRNAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/readDir/FuseReadDirReturnTest.cpp b/test/fspp/fuse/readDir/FuseReadDirReturnTest.cpp deleted file mode 100644 index 8f1a759c..00000000 --- a/test/fspp/fuse/readDir/FuseReadDirReturnTest.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "testutils/FuseReadDirTest.h" -#include -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::WithParamInterface; -using ::testing::Values; - -using std::vector; -using std::string; - -using namespace fspp::fuse; - -vector LARGE_DIR(int num_entries) { - vector result; - result.reserve(num_entries); - for(int i=0; i> { -public: - void testDirEntriesAreCorrect(const vector &direntries) { - ReturnIsDirOnLstat(DIRNAME); - EXPECT_CALL(*fsimpl, readDir(Eq(DIRNAME))) - .Times(1).WillOnce(ReturnDirEntries(direntries)); - - auto returned_dir_entries = ReadDir(DIRNAME); - EXPECT_EQ(direntries, returned_dir_entries); - } -}; -INSTANTIATE_TEST_SUITE_P(FuseReadDirReturnTest, FuseReadDirReturnTest, Values( - vector({}), - vector({"oneentry"}), - vector({"twoentries_1", "twoentries_2"}), - vector({"file1", "file with spaces"}), - vector({"file1", ".dotfile"}) -)); - -TEST_P(FuseReadDirReturnTest, ReturnedDirEntriesAreCorrect) { - testDirEntriesAreCorrect(GetParam()); -} - -// If using this with GTest Value-Parametrized TEST_P, it breaks some other unrelated tests -// (probably because it is doing a lot of construction work on the start of the test program) -TEST_F(FuseReadDirReturnTest, ReturnedDirEntriesAreCorrect_LargeDir1000) { - auto direntries = LARGE_DIR(1000); - testDirEntriesAreCorrect(direntries); -} - -// If using this with GTest Value-Parametrized TEST_P, it breaks some other unrelated tests -// (probably because it is doing a lot of construction work on the start of the test program) -// DISABLED, because it uses a lot of memory -TEST_F(FuseReadDirReturnTest, DISABLED_ReturnedDirEntriesAreCorrect_LargeDir1000000) { - auto direntries = LARGE_DIR(1000000); - testDirEntriesAreCorrect(direntries); -} diff --git a/test/fspp/fuse/readDir/testutils/FuseReadDirTest.cpp b/test/fspp/fuse/readDir/testutils/FuseReadDirTest.cpp deleted file mode 100644 index 3d15eff2..00000000 --- a/test/fspp/fuse/readDir/testutils/FuseReadDirTest.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "FuseReadDirTest.h" - -using cpputils::make_unique_ref; -using std::vector; -using std::string; - -using ::testing::Action; -using ::testing::Return; - -vector FuseReadDirTest::ReadDir(const char *dirname) { - auto fs = TestFS(); - - DIR *dir = openDir(fs.get(), dirname); - - vector result; - readDirEntries(dir, &result); - closeDir(dir); - return result; -} - -int FuseReadDirTest::ReadDirReturnError(const char *dirname) { - auto fs = TestFS(); - - errno = 0; - DIR *dir = openDirAllowError(fs.get(), dirname); - EXPECT_EQ(errno!=0, dir==nullptr) << "errno should exactly be != 0 if opendir returned nullptr"; - if (errno != 0) { - return errno; - } - - auto result = make_unique_ref>(); - int error = readDirEntriesAllowError(dir, result.get()); - closeDir(dir); - return error; -} - -DIR *FuseReadDirTest::openDir(TempTestFS *fs, const char *dirname) { - DIR *dir = openDirAllowError(fs, dirname); - EXPECT_NE(nullptr, dir) << "Opening directory failed"; - return dir; -} - -DIR *FuseReadDirTest::openDirAllowError(TempTestFS *fs, const char *dirname) { - auto realpath = fs->mountDir() / dirname; - return ::opendir(realpath.string().c_str()); -} - -void FuseReadDirTest::readDirEntries(DIR *dir, vector *result) { - int error = readDirEntriesAllowError(dir, result); - EXPECT_EQ(0, error); -} - -int FuseReadDirTest::readDirEntriesAllowError(DIR *dir, vector *result) { - struct dirent *entry = nullptr; - int error = readNextDirEntryAllowError(dir, &entry); - if (error != 0) { - return error; - } - while(entry != nullptr) { - result->push_back(entry->d_name); - int error = readNextDirEntryAllowError(dir, &entry); - if (error != 0) { - return error; - } - } - return 0; -} - -int FuseReadDirTest::readNextDirEntryAllowError(DIR *dir, struct dirent **result) { - errno = 0; - *result = ::readdir(dir); - return errno; -} - -void FuseReadDirTest::closeDir(DIR *dir) { - int retval = ::closedir(dir); - EXPECT_EQ(0, retval) << "Closing dir failed"; -} - -Action(const boost::filesystem::path&)> FuseReadDirTest::ReturnDirEntries(vector entries) { - vector direntries(entries.size(), fspp::Dir::Entry(fspp::Dir::EntryType::FILE, "")); - for(size_t i = 0; i < entries.size(); ++i) { - direntries[i].name = entries[i]; - } - return Return(std::move(direntries)); -} diff --git a/test/fspp/fuse/readDir/testutils/FuseReadDirTest.h b/test/fspp/fuse/readDir/testutils/FuseReadDirTest.h deleted file mode 100644 index d1b15eb6..00000000 --- a/test/fspp/fuse/readDir/testutils/FuseReadDirTest.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_READDIR_TESTUTILS_FUSEREADDIRTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_READDIR_TESTUTILS_FUSEREADDIRTEST_H_ - -#include "../../../testutils/FuseTest.h" -#include -#include "fspp/fs_interface/Dir.h" - -class FuseReadDirTest: public FuseTest { -public: - const char *DIRNAME = "/mydir"; - - std::vector ReadDir(const char *dirname); - int ReadDirReturnError(const char *dirname); - - static ::testing::Action(const boost::filesystem::path&)> ReturnDirEntries(std::vector entries); - -private: - DIR *openDir(TempTestFS *fs, const char *dirname); - DIR *openDirAllowError(TempTestFS *fs, const char *dirname); - void readDirEntries(DIR *dir, std::vector *result); - int readDirEntriesAllowError(DIR *dir, std::vector *result); - int readNextDirEntryAllowError(DIR *dir, struct dirent **result); - void closeDir(DIR *dir); -}; - -#endif diff --git a/test/fspp/fuse/rename/FuseRenameErrorTest.cpp b/test/fspp/fuse/rename/FuseRenameErrorTest.cpp deleted file mode 100644 index d4c9df85..00000000 --- a/test/fspp/fuse/rename/FuseRenameErrorTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseRenameTest.h" -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseRenameErrorTest: public FuseRenameTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseRenameErrorTest, FuseRenameErrorTest, Values(EACCES, EBUSY, EDQUOT, EFAULT, EINVAL, EISDIR, ELOOP, EMLINK, ENAMETOOLONG, ENOENT, ENOMEM, ENOSPC, ENOTDIR, ENOTEMPTY, EEXIST, EPERM, EROFS, EXDEV, EBADF, ENOTDIR)); - -TEST_P(FuseRenameErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME1); - ReturnDoesntExistOnLstat(FILENAME2); - EXPECT_CALL(*fsimpl, rename(Eq(FILENAME1), Eq(FILENAME2))) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = RenameReturnError(FILENAME1, FILENAME2); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/rename/FuseRenameFilenameTest.cpp b/test/fspp/fuse/rename/FuseRenameFilenameTest.cpp deleted file mode 100644 index 47182f98..00000000 --- a/test/fspp/fuse/rename/FuseRenameFilenameTest.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "testutils/FuseRenameTest.h" - -using ::testing::Eq; -using ::testing::Return; - -class FuseRenameFilenameTest: public FuseRenameTest { -}; - -TEST_F(FuseRenameFilenameTest, RenameFileRootToRoot) { - ReturnIsFileOnLstat("/myfile"); - ReturnDoesntExistOnLstat("/myrenamedfile"); - EXPECT_CALL(*fsimpl, rename(Eq("/myfile"), Eq("/myrenamedfile"))) - .Times(1).WillOnce(Return()); - - Rename("/myfile", "/myrenamedfile"); -} - -TEST_F(FuseRenameFilenameTest, RenameFileRootToNested) { - ReturnIsFileOnLstat("/myfile"); - ReturnIsDirOnLstat("/mydir"); - ReturnDoesntExistOnLstat("/mydir/myrenamedfile"); - EXPECT_CALL(*fsimpl, rename(Eq("/myfile"), Eq("/mydir/myrenamedfile"))) - .Times(1).WillOnce(Return()); - - Rename("/myfile", "/mydir/myrenamedfile"); -} - -TEST_F(FuseRenameFilenameTest, RenameFileNestedToRoot) { - ReturnDoesntExistOnLstat("/myrenamedfile"); - ReturnIsDirOnLstat("/mydir"); - ReturnIsFileOnLstat("/mydir/myfile"); - EXPECT_CALL(*fsimpl, rename(Eq("/mydir/myfile"), Eq("/myrenamedfile"))) - .Times(1).WillOnce(Return()); - - Rename("/mydir/myfile", "/myrenamedfile"); -} - -TEST_F(FuseRenameFilenameTest, RenameFileNestedToNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsFileOnLstat("/mydir/myfile"); - ReturnDoesntExistOnLstat("/mydir/myrenamedfile"); - EXPECT_CALL(*fsimpl, rename(Eq("/mydir/myfile"), Eq("/mydir/myrenamedfile"))) - .Times(1).WillOnce(Return()); - - Rename("/mydir/myfile", "/mydir/myrenamedfile"); -} - -TEST_F(FuseRenameFilenameTest, RenameFileNestedToNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsFileOnLstat("/mydir/mydir2/myfile"); - ReturnDoesntExistOnLstat("/mydir/mydir2/myrenamedfile"); - EXPECT_CALL(*fsimpl, rename(Eq("/mydir/mydir2/myfile"), Eq("/mydir/mydir2/myrenamedfile"))) - .Times(1).WillOnce(Return()); - - Rename("/mydir/mydir2/myfile", "/mydir/mydir2/myrenamedfile"); -} - -TEST_F(FuseRenameFilenameTest, RenameFileNestedToNested_DifferentFolder) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir2"); - ReturnIsFileOnLstat("/mydir/myfile"); - ReturnDoesntExistOnLstat("/mydir2/myrenamedfile"); - EXPECT_CALL(*fsimpl, rename(Eq("/mydir/myfile"), Eq("/mydir2/myrenamedfile"))) - .Times(1).WillOnce(Return()); - - Rename("/mydir/myfile", "/mydir2/myrenamedfile"); -} - -TEST_F(FuseRenameFilenameTest, RenameDirRootToRoot) { - ReturnIsDirOnLstat("/mydir"); - ReturnDoesntExistOnLstat("/myrenameddir"); - EXPECT_CALL(*fsimpl, rename(Eq("/mydir"), Eq("/myrenameddir"))) - .Times(1).WillOnce(Return()); - - Rename("/mydir", "/myrenameddir"); -} - -TEST_F(FuseRenameFilenameTest, RenameDirRootToNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/myrootdir"); - ReturnDoesntExistOnLstat("/myrootdir/myrenameddir"); - EXPECT_CALL(*fsimpl, rename(Eq("/mydir"), Eq("/myrootdir/myrenameddir"))) - .Times(1).WillOnce(Return()); - - Rename("/mydir", "/myrootdir/myrenameddir"); -} - -TEST_F(FuseRenameFilenameTest, RenameDirNestedToRoot) { - ReturnDoesntExistOnLstat("/myrenameddir"); - ReturnIsDirOnLstat("/myrootdir"); - ReturnIsDirOnLstat("/myrootdir/mydir"); - EXPECT_CALL(*fsimpl, rename(Eq("/myrootdir/mydir"), Eq("/myrenameddir"))) - .Times(1).WillOnce(Return()); - - Rename("/myrootdir/mydir", "/myrenameddir"); -} - -TEST_F(FuseRenameFilenameTest, RenameDirNestedToNested) { - ReturnIsDirOnLstat("/myrootdir"); - ReturnIsDirOnLstat("/myrootdir/mydir"); - ReturnDoesntExistOnLstat("/myrootdir/myrenameddir"); - EXPECT_CALL(*fsimpl, rename(Eq("/myrootdir/mydir"), Eq("/myrootdir/myrenameddir"))) - .Times(1).WillOnce(Return()); - - Rename("/myrootdir/mydir", "/myrootdir/myrenameddir"); -} - -TEST_F(FuseRenameFilenameTest, RenameDirNestedToNested2) { - ReturnIsDirOnLstat("/myrootdir"); - ReturnIsDirOnLstat("/myrootdir/myrootdir2"); - ReturnIsDirOnLstat("/myrootdir/myrootdir2/mydir"); - ReturnDoesntExistOnLstat("/myrootdir/myrootdir2/myrenameddir"); - EXPECT_CALL(*fsimpl, rename(Eq("/myrootdir/myrootdir2/mydir"), Eq("/myrootdir/myrootdir2/myrenameddir"))) - .Times(1).WillOnce(Return()); - - Rename("/myrootdir/myrootdir2/mydir", "/myrootdir/myrootdir2/myrenameddir"); -} - -TEST_F(FuseRenameFilenameTest, RenameDirNestedToNested_DifferentFolder) { - ReturnIsDirOnLstat("/myrootdir"); - ReturnIsDirOnLstat("/myrootdir2"); - ReturnIsDirOnLstat("/myrootdir/mydir"); - ReturnDoesntExistOnLstat("/myrootdir2/myrenameddir"); - EXPECT_CALL(*fsimpl, rename(Eq("/myrootdir/mydir"), Eq("/myrootdir2/myrenameddir"))) - .Times(1).WillOnce(Return()); - - Rename("/myrootdir/mydir", "/myrootdir2/myrenameddir"); -} diff --git a/test/fspp/fuse/rename/testutils/FuseRenameTest.cpp b/test/fspp/fuse/rename/testutils/FuseRenameTest.cpp deleted file mode 100644 index e74945b4..00000000 --- a/test/fspp/fuse/rename/testutils/FuseRenameTest.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "FuseRenameTest.h" - - -void FuseRenameTest::Rename(const char *from, const char *to) { - int error = RenameReturnError(from, to); - EXPECT_EQ(0, error); -} - -int FuseRenameTest::RenameReturnError(const char *from, const char *to) { - auto fs = TestFS(); - - auto realfrom = fs->mountDir() / from; - auto realto = fs->mountDir() / to; - int retval = ::rename(realfrom.string().c_str(), realto.string().c_str()); - if (0 == retval) { - return 0; - } else { - return errno; - } -} diff --git a/test/fspp/fuse/rename/testutils/FuseRenameTest.h b/test/fspp/fuse/rename/testutils/FuseRenameTest.h deleted file mode 100644 index 34192915..00000000 --- a/test/fspp/fuse/rename/testutils/FuseRenameTest.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_RENAME_TESTUTILS_FUSERENAMETEST_H_ -#define MESSMER_FSPP_TEST_FUSE_RENAME_TESTUTILS_FUSERENAMETEST_H_ - -#include "../../../testutils/FuseTest.h" - -class FuseRenameTest: public FuseTest { -public: - const char *FILENAME1 = "/myfile1"; - const char *FILENAME2 = "/myfile2"; - - void Rename(const char *from, const char *to); - int RenameReturnError(const char *from, const char *to); -}; - -#endif diff --git a/test/fspp/fuse/rmdir/FuseRmdirDirnameTest.cpp b/test/fspp/fuse/rmdir/FuseRmdirDirnameTest.cpp deleted file mode 100644 index 6adfd2e1..00000000 --- a/test/fspp/fuse/rmdir/FuseRmdirDirnameTest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "testutils/FuseRmdirTest.h" - -using ::testing::Eq; - -class FuseRmdirDirnameTest: public FuseRmdirTest { -}; - -TEST_F(FuseRmdirDirnameTest, Rmdir) { - ReturnIsDirOnLstat("/mydir"); - EXPECT_CALL(*fsimpl, rmdir(Eq("/mydir"))) - // After rmdir was called, lstat should return that it doesn't exist anymore - // This is needed to make the ::rmdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnDoesntExistOnLstat()); - - Rmdir("/mydir"); -} - -TEST_F(FuseRmdirDirnameTest, RmdirNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mysubdir"); - EXPECT_CALL(*fsimpl, rmdir(Eq("/mydir/mysubdir"))) - // After rmdir was called, lstat should return that it doesn't exist anymore - // This is needed to make the ::rmdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnDoesntExistOnLstat()); - - Rmdir("/mydir/mysubdir"); -} - -TEST_F(FuseRmdirDirnameTest, RmdirNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsDirOnLstat("/mydir/mydir2/mydir3"); - EXPECT_CALL(*fsimpl, rmdir(Eq("/mydir/mydir2/mydir3"))) - // After rmdir was called, lstat should return that it doesn't exist anymore - // This is needed to make the ::rmdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnDoesntExistOnLstat()); - - Rmdir("/mydir/mydir2/mydir3"); -} diff --git a/test/fspp/fuse/rmdir/FuseRmdirErrorTest.cpp b/test/fspp/fuse/rmdir/FuseRmdirErrorTest.cpp deleted file mode 100644 index a19d489c..00000000 --- a/test/fspp/fuse/rmdir/FuseRmdirErrorTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "testutils/FuseRmdirTest.h" -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseRmdirErrorTest: public FuseRmdirTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseRmdirErrorTest, FuseRmdirErrorTest, Values(EACCES, EBUSY, EFAULT, EINVAL, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, ENOTEMPTY, EPERM, EROFS)); - -TEST_P(FuseRmdirErrorTest, ReturnedErrorIsCorrect) { - ReturnIsDirOnLstat(DIRNAME); - EXPECT_CALL(*fsimpl, rmdir(Eq(DIRNAME))) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = RmdirReturnError(DIRNAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/rmdir/testutils/FuseRmdirTest.cpp b/test/fspp/fuse/rmdir/testutils/FuseRmdirTest.cpp deleted file mode 100644 index 3b0e1a2a..00000000 --- a/test/fspp/fuse/rmdir/testutils/FuseRmdirTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "FuseRmdirTest.h" - -using ::testing::Action; -using ::testing::Invoke; - -void FuseRmdirTest::Rmdir(const char *dirname) { - int error = RmdirReturnError(dirname); - EXPECT_EQ(0, error); -} - -int FuseRmdirTest::RmdirReturnError(const char *dirname) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / dirname; - int retval = ::rmdir(realpath.string().c_str()); - if (retval == 0) { - return 0; - } else { - return errno; - } -} - -Action FuseRmdirTest::FromNowOnReturnDoesntExistOnLstat() { - return Invoke([this](const boost::filesystem::path& dirname) { - ReturnDoesntExistOnLstat(dirname); - }); -} diff --git a/test/fspp/fuse/rmdir/testutils/FuseRmdirTest.h b/test/fspp/fuse/rmdir/testutils/FuseRmdirTest.h deleted file mode 100644 index de6a6dca..00000000 --- a/test/fspp/fuse/rmdir/testutils/FuseRmdirTest.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_RMDIR_TESTUTILS_FUSERMDIRTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_RMDIR_TESTUTILS_FUSERMDIRTEST_H_ - -#include "../../../testutils/FuseTest.h" - -class FuseRmdirTest: public FuseTest { -public: - const char *DIRNAME = "/mydir"; - - void Rmdir(const char *dirname); - int RmdirReturnError(const char *dirname); - - ::testing::Action FromNowOnReturnDoesntExistOnLstat(); -}; - -#endif diff --git a/test/fspp/fuse/statfs/FuseStatfsErrorTest.cpp b/test/fspp/fuse/statfs/FuseStatfsErrorTest.cpp deleted file mode 100644 index 0ef53749..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsErrorTest.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "testutils/FuseStatfsTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Throw; -using ::testing::Return; -using ::testing::WithParamInterface; -using ::testing::Values; - -using fspp::fuse::FuseErrnoException; - -class FuseStatfsErrorTest: public FuseStatfsTest, public WithParamInterface { -public: -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsErrorTest, FuseStatfsErrorTest, Values(EACCES, EBADF, EFAULT, EINTR, EIO, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS, ENOTDIR, EOVERFLOW)); - -TEST_F(FuseStatfsErrorTest, ReturnNoError) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, statfs(testing::_)).Times(1).WillOnce(Return()); - int error = StatfsReturnError(FILENAME); - EXPECT_EQ(0, error); -} - -TEST_P(FuseStatfsErrorTest, ReturnError) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, statfs(testing::_)).Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - int error = StatfsReturnError(FILENAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/statfs/FuseStatfsReturnBavailTest.cpp b/test/fspp/fuse/statfs/FuseStatfsReturnBavailTest.cpp deleted file mode 100644 index 733fee72..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsReturnBavailTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseStatfsReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseStatfsReturnBavailTest: public FuseStatfsReturnTest, public WithParamInterface { -private: - void set(struct ::statvfs *stat, uint64_t value) override { - stat->f_bavail = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsReturnBavailTest, FuseStatfsReturnBavailTest, Values( - 0, - 10, - 256, - 1024, - 4096 -)); - -TEST_P(FuseStatfsReturnBavailTest, ReturnedBavailIsCorrect) { - struct ::statvfs result = CallStatfsWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.f_bavail); -} diff --git a/test/fspp/fuse/statfs/FuseStatfsReturnBfreeTest.cpp b/test/fspp/fuse/statfs/FuseStatfsReturnBfreeTest.cpp deleted file mode 100644 index 9e3ef5c1..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsReturnBfreeTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseStatfsReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseStatfsReturnBfreeTest: public FuseStatfsReturnTest, public WithParamInterface { -private: - void set(struct ::statvfs *stat, uint64_t value) override { - stat->f_bfree = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsReturnBfreeTest, FuseStatfsReturnBfreeTest, Values( - 0, - 10, - 256, - 1024, - 4096 -)); - -TEST_P(FuseStatfsReturnBfreeTest, ReturnedBfreeIsCorrect) { - struct ::statvfs result = CallStatfsWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.f_bfree); -} diff --git a/test/fspp/fuse/statfs/FuseStatfsReturnBlocksTest.cpp b/test/fspp/fuse/statfs/FuseStatfsReturnBlocksTest.cpp deleted file mode 100644 index f77a80ee..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsReturnBlocksTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseStatfsReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseStatfsReturnBlocksTest: public FuseStatfsReturnTest, public WithParamInterface { -private: - void set(struct ::statvfs *stat, uint64_t value) override { - stat->f_blocks = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsReturnBlocksTest, FuseStatfsReturnBlocksTest, Values( - 0, - 10, - 256, - 1024, - 4096 -)); - -TEST_P(FuseStatfsReturnBlocksTest, ReturnedBlocksIsCorrect) { - struct ::statvfs result = CallStatfsWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.f_blocks); -} diff --git a/test/fspp/fuse/statfs/FuseStatfsReturnBsizeTest.cpp b/test/fspp/fuse/statfs/FuseStatfsReturnBsizeTest.cpp deleted file mode 100644 index bbb84161..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsReturnBsizeTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseStatfsReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseStatfsReturnBsizeTest: public FuseStatfsReturnTest, public WithParamInterface { -private: - void set(struct ::statvfs *stat, unsigned long value) override { - stat->f_bsize = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsReturnBsizeTest, FuseStatfsReturnBsizeTest, Values( - 0, - 10, - 256, - 1024, - 4096 -)); - -TEST_P(FuseStatfsReturnBsizeTest, ReturnedBsizeIsCorrect) { - struct ::statvfs result = CallStatfsWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.f_bsize); -} diff --git a/test/fspp/fuse/statfs/FuseStatfsReturnFfreeTest.cpp b/test/fspp/fuse/statfs/FuseStatfsReturnFfreeTest.cpp deleted file mode 100644 index 9cf015a2..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsReturnFfreeTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseStatfsReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseStatfsReturnFfreeTest: public FuseStatfsReturnTest, public WithParamInterface { -private: - void set(struct ::statvfs *stat, uint64_t value) override { - stat->f_ffree = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsReturnFfreeTest, FuseStatfsReturnFfreeTest, Values( - 0, - 10, - 256, - 1024, - 4096 -)); - -TEST_P(FuseStatfsReturnFfreeTest, ReturnedFfreeIsCorrect) { - struct ::statvfs result = CallStatfsWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.f_ffree); -} diff --git a/test/fspp/fuse/statfs/FuseStatfsReturnFilesTest.cpp b/test/fspp/fuse/statfs/FuseStatfsReturnFilesTest.cpp deleted file mode 100644 index acef1dff..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsReturnFilesTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseStatfsReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseStatfsReturnFilesTest: public FuseStatfsReturnTest, public WithParamInterface { -private: - void set(struct ::statvfs *stat, uint64_t value) override { - stat->f_files = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsReturnFilesTest, FuseStatfsReturnFilesTest, Values( - 0, - 10, - 256, - 1024, - 4096 -)); - -TEST_P(FuseStatfsReturnFilesTest, ReturnedFilesIsCorrect) { - struct ::statvfs result = CallStatfsWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.f_files); -} diff --git a/test/fspp/fuse/statfs/FuseStatfsReturnNamemaxTest.cpp b/test/fspp/fuse/statfs/FuseStatfsReturnNamemaxTest.cpp deleted file mode 100644 index ce180c3a..00000000 --- a/test/fspp/fuse/statfs/FuseStatfsReturnNamemaxTest.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "testutils/FuseStatfsReturnTest.h" - -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseStatfsReturnNamemaxTest: public FuseStatfsReturnTest, public WithParamInterface { -private: - void set(struct ::statvfs *stat, unsigned long value) override { - stat->f_namemax = value; - } -}; -INSTANTIATE_TEST_SUITE_P(FuseStatfsReturnNamemaxTest, FuseStatfsReturnNamemaxTest, Values( - 0, - 10, - 256, - 1024, - 4096 -)); - -TEST_P(FuseStatfsReturnNamemaxTest, ReturnedNamemaxIsCorrect) { - struct ::statvfs result = CallStatfsWithValue(GetParam()); - EXPECT_EQ(GetParam(), result.f_namemax); -} diff --git a/test/fspp/fuse/statfs/testutils/FuseStatfsReturnTest.h b/test/fspp/fuse/statfs/testutils/FuseStatfsReturnTest.h deleted file mode 100644 index a09309f9..00000000 --- a/test/fspp/fuse/statfs/testutils/FuseStatfsReturnTest.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_STATFS_TESTUTILS_FUSESTATFSRETURNTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_STATFS_TESTUTILS_FUSESTATFSRETURNTEST_H_ - -#include "FuseStatfsTest.h" - -// This class offers test helpers for testing (struct statfs) entries. We return them from -// our mock filesystem, set up a temporary filesystem, call statfs syscall on it, and -// then check the return value. -template -class FuseStatfsReturnTest: public FuseStatfsTest { -public: - // Set the specified (struct statfs) entry to the given value, and test whether it is correctly returned from the syscall. - struct ::statvfs CallStatfsWithValue(Property value); - -private: - std::function SetPropertyImpl(Property value); - - // Override this function to specify, how to set the specified (struct statfs) entry on the passed (struct statfs *) object. - virtual void set(struct ::statvfs *statfs, Property value) = 0; -}; - -template -inline struct ::statvfs FuseStatfsReturnTest::CallStatfsWithValue(Property value) { - return CallStatfsWithImpl(SetPropertyImpl(value)); -} - -template -inline std::function FuseStatfsReturnTest::SetPropertyImpl(Property value) { - return [this, value] (struct ::statvfs *stat) { - set(stat, value); - }; -} - - -#endif diff --git a/test/fspp/fuse/statfs/testutils/FuseStatfsTest.cpp b/test/fspp/fuse/statfs/testutils/FuseStatfsTest.cpp deleted file mode 100644 index 651c85d0..00000000 --- a/test/fspp/fuse/statfs/testutils/FuseStatfsTest.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "FuseStatfsTest.h" - -using std::function; -using ::testing::Invoke; - -void FuseStatfsTest::Statfs(const std::string &path) { - struct ::statvfs dummy{}; - Statfs(path, &dummy); -} - -int FuseStatfsTest::StatfsReturnError(const std::string &path) { - struct ::statvfs dummy{}; - return StatfsReturnError(path, &dummy); -} - -void FuseStatfsTest::Statfs(const std::string &path, struct ::statvfs *result) { - int error = StatfsReturnError(path, result); - EXPECT_EQ(0, error) << "lstat syscall failed. errno: " << errno; -} - -int FuseStatfsTest::StatfsReturnError(const std::string &path, struct ::statvfs *result) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / path; - int retval = ::statvfs(realpath.string().c_str(), result); - if (retval == 0) { - return 0; - } else { - return errno; - } -} - -struct ::statvfs FuseStatfsTest::CallStatfsWithImpl(function implementation) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, statfs(testing::_)).WillRepeatedly(Invoke([implementation](struct ::statvfs *stat) { - implementation(stat); - })); - - struct ::statvfs result{}; - Statfs(FILENAME, &result); - - return result; -} - diff --git a/test/fspp/fuse/statfs/testutils/FuseStatfsTest.h b/test/fspp/fuse/statfs/testutils/FuseStatfsTest.h deleted file mode 100644 index 803f46a6..00000000 --- a/test/fspp/fuse/statfs/testutils/FuseStatfsTest.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_STATFS_TESTUTILS_FUSESTATFSTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_STATFS_TESTUTILS_FUSESTATFSTEST_H_ - -#include -#include - -#include "../../../testutils/FuseTest.h" - -// This class offers some utility functions for testing statfs(). -class FuseStatfsTest: public FuseTest { -protected: - const char *FILENAME = "/myfile"; - - // Set up a temporary filesystem (using the fsimpl mock in FuseTest as filesystem implementation) - // and call the statfs syscall on the given (filesystem-relative) path. - void Statfs(const std::string &path); - // Same as Statfs above, but also return the result of the statfs syscall. - void Statfs(const std::string &path, struct ::statvfs *result); - - // These two functions are the same as Statfs above, but they don't fail the test when the statfs syscall - // crashes. Instead, they return the result value of the statfs syscall. - int StatfsReturnError(const std::string &path); - int StatfsReturnError(const std::string &path, struct ::statvfs *result); - - // You can specify an implementation, which can modify the (struct statfs *) result, - // our fuse mock filesystem implementation will then return this to fuse on an statfs call. - // This functions then set up a temporary filesystem with this mock, calls statfs on a filesystem node - // and returns the (struct statfs) returned from an statfs syscall to this filesystem. - struct ::statvfs CallStatfsWithImpl(std::function implementation); -}; - -#endif diff --git a/test/fspp/fuse/truncate/FuseTruncateErrorTest.cpp b/test/fspp/fuse/truncate/FuseTruncateErrorTest.cpp deleted file mode 100644 index 65048974..00000000 --- a/test/fspp/fuse/truncate/FuseTruncateErrorTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "testutils/FuseTruncateTest.h" -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseTruncateErrorTest: public FuseTruncateTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseTruncateErrorTest, FuseTruncateErrorTest, Values(EACCES, EFAULT, EFBIG, EINTR, EINVAL, EIO, EISDIR, ELOOP, ENAMETOOLONG, ENOENT, ENOTDIR, EPERM, EROFS, ETXTBSY)); - -TEST_P(FuseTruncateErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, truncate(Eq(FILENAME), testing::_)) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = TruncateFileReturnError(FILENAME, fspp::num_bytes_t(0)); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/truncate/FuseTruncateFilenameTest.cpp b/test/fspp/fuse/truncate/FuseTruncateFilenameTest.cpp deleted file mode 100644 index 54508d4a..00000000 --- a/test/fspp/fuse/truncate/FuseTruncateFilenameTest.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "testutils/FuseTruncateTest.h" - -using ::testing::Eq; -using ::testing::Return; - -class FuseTruncateFilenameTest: public FuseTruncateTest { -}; - -TEST_F(FuseTruncateFilenameTest, TruncateFile) { - ReturnIsFileOnLstat("/myfile"); - EXPECT_CALL(*fsimpl, truncate(Eq("/myfile"), testing::_)) - .Times(1).WillOnce(Return()); - - TruncateFile("/myfile", fspp::num_bytes_t(0)); -} - -TEST_F(FuseTruncateFilenameTest, TruncateFileNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsFileOnLstat("/mydir/myfile"); - EXPECT_CALL(*fsimpl, truncate(Eq("/mydir/myfile"), testing::_)) - .Times(1).WillOnce(Return()); - - TruncateFile("/mydir/myfile", fspp::num_bytes_t(0)); -} - -TEST_F(FuseTruncateFilenameTest, TruncateFileNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsFileOnLstat("/mydir/mydir2/myfile"); - EXPECT_CALL(*fsimpl, truncate(Eq("/mydir/mydir2/myfile"), testing::_)) - .Times(1).WillOnce(Return()); - - TruncateFile("/mydir/mydir2/myfile", fspp::num_bytes_t(0)); -} diff --git a/test/fspp/fuse/truncate/FuseTruncateSizeTest.cpp b/test/fspp/fuse/truncate/FuseTruncateSizeTest.cpp deleted file mode 100644 index 8a5d67c2..00000000 --- a/test/fspp/fuse/truncate/FuseTruncateSizeTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "testutils/FuseTruncateTest.h" - -using ::testing::Eq; -using ::testing::Return; -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; - -class FuseTruncateSizeTest: public FuseTruncateTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseTruncateSizeTest, FuseTruncateSizeTest, Values( - fspp::num_bytes_t(0), - fspp::num_bytes_t(1), - fspp::num_bytes_t(10), - fspp::num_bytes_t(1024), - fspp::num_bytes_t(1024*1024*1024))); - - -TEST_P(FuseTruncateSizeTest, TruncateFile) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, truncate(Eq(FILENAME), Eq(GetParam()))) - .Times(1).WillOnce(Return()); - - TruncateFile(FILENAME, GetParam()); -} diff --git a/test/fspp/fuse/truncate/testutils/FuseTruncateTest.cpp b/test/fspp/fuse/truncate/testutils/FuseTruncateTest.cpp deleted file mode 100644 index a461547b..00000000 --- a/test/fspp/fuse/truncate/testutils/FuseTruncateTest.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "FuseTruncateTest.h" - -void FuseTruncateTest::TruncateFile(const char *filename, fspp::num_bytes_t size) { - int error = TruncateFileReturnError(filename, size); - EXPECT_EQ(0, error); -} - -int FuseTruncateTest::TruncateFileReturnError(const char *filename, fspp::num_bytes_t size) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / filename; - int retval = ::truncate(realpath.string().c_str(), size.value()); - if (retval == 0) { - return 0; - } else { - return errno; - } -} diff --git a/test/fspp/fuse/truncate/testutils/FuseTruncateTest.h b/test/fspp/fuse/truncate/testutils/FuseTruncateTest.h deleted file mode 100644 index f3e1b624..00000000 --- a/test/fspp/fuse/truncate/testutils/FuseTruncateTest.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_TRUNCATE_TESTUTILS_FUSETRUNCATETEST_H_ -#define MESSMER_FSPP_TEST_FUSE_TRUNCATE_TESTUTILS_FUSETRUNCATETEST_H_ - -#include "../../../testutils/FuseTest.h" - -class FuseTruncateTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void TruncateFile(const char *filename, fspp::num_bytes_t size); - int TruncateFileReturnError(const char *filename, fspp::num_bytes_t size); -}; - -#endif diff --git a/test/fspp/fuse/unlink/FuseUnlinkErrorTest.cpp b/test/fspp/fuse/unlink/FuseUnlinkErrorTest.cpp deleted file mode 100644 index b04dd675..00000000 --- a/test/fspp/fuse/unlink/FuseUnlinkErrorTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "testutils/FuseUnlinkTest.h" -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseUnlinkErrorTest: public FuseUnlinkTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseUnlinkErrorTest, FuseUnlinkErrorTest, Values(EACCES, EBUSY, EFAULT, EIO, EISDIR, ELOOP, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EPERM, EROFS, EINVAL)); - -TEST_P(FuseUnlinkErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, unlink(Eq(FILENAME))) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = UnlinkReturnError(FILENAME); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/unlink/FuseUnlinkFilenameTest.cpp b/test/fspp/fuse/unlink/FuseUnlinkFilenameTest.cpp deleted file mode 100644 index 230a21c8..00000000 --- a/test/fspp/fuse/unlink/FuseUnlinkFilenameTest.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "testutils/FuseUnlinkTest.h" - -using ::testing::Eq; - -class FuseUnlinkFilenameTest: public FuseUnlinkTest { -}; - -TEST_F(FuseUnlinkFilenameTest, Unlink) { - ReturnIsFileOnLstat("/mydir"); - EXPECT_CALL(*fsimpl, unlink(Eq("/mydir"))) - // After rmdir was called, lstat should return that it doesn't exist anymore - // This is needed to make the ::rmdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnDoesntExistOnLstat()); - - Unlink("/mydir"); -} - -TEST_F(FuseUnlinkFilenameTest, UnlinkNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsFileOnLstat("/mydir/mysubdir"); - EXPECT_CALL(*fsimpl, unlink(Eq("/mydir/mysubdir"))) - // After rmdir was called, lstat should return that it doesn't exist anymore - // This is needed to make the ::rmdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnDoesntExistOnLstat()); - - Unlink("/mydir/mysubdir"); -} - -TEST_F(FuseUnlinkFilenameTest, UnlinkNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsFileOnLstat("/mydir/mydir2/mydir3"); - EXPECT_CALL(*fsimpl, unlink(Eq("/mydir/mydir2/mydir3"))) - // After rmdir was called, lstat should return that it doesn't exist anymore - // This is needed to make the ::rmdir() syscall pass. - .Times(1).WillOnce(FromNowOnReturnDoesntExistOnLstat()); - - Unlink("/mydir/mydir2/mydir3"); -} diff --git a/test/fspp/fuse/unlink/testutils/FuseUnlinkTest.cpp b/test/fspp/fuse/unlink/testutils/FuseUnlinkTest.cpp deleted file mode 100644 index 63dedf67..00000000 --- a/test/fspp/fuse/unlink/testutils/FuseUnlinkTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "FuseUnlinkTest.h" - -using ::testing::Action; -using ::testing::Invoke; - -void FuseUnlinkTest::Unlink(const char *filename) { - int error = UnlinkReturnError(filename); - EXPECT_EQ(0, error); -} - -int FuseUnlinkTest::UnlinkReturnError(const char *filename) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / filename; - int retval = ::unlink(realpath.string().c_str()); - if (0 == retval) { - return 0; - } else { - return errno; - } -} - -Action FuseUnlinkTest::FromNowOnReturnDoesntExistOnLstat() { - return Invoke([this](const boost::filesystem::path& filename) { - ReturnDoesntExistOnLstat(filename); - }); -} diff --git a/test/fspp/fuse/unlink/testutils/FuseUnlinkTest.h b/test/fspp/fuse/unlink/testutils/FuseUnlinkTest.h deleted file mode 100644 index 98f2a436..00000000 --- a/test/fspp/fuse/unlink/testutils/FuseUnlinkTest.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_UNLINK_TESTUTILS_FUSEUNLINKTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_UNLINK_TESTUTILS_FUSEUNLINKTEST_H_ - -#include "../../../testutils/FuseTest.h" - -class FuseUnlinkTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - void Unlink(const char *filename); - int UnlinkReturnError(const char *filename); - - ::testing::Action FromNowOnReturnDoesntExistOnLstat(); -}; - -#endif diff --git a/test/fspp/fuse/utimens/FuseUtimensErrorTest.cpp b/test/fspp/fuse/utimens/FuseUtimensErrorTest.cpp deleted file mode 100644 index ad6732fb..00000000 --- a/test/fspp/fuse/utimens/FuseUtimensErrorTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "testutils/FuseUtimensTest.h" -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Eq; -using ::testing::Throw; -using ::testing::WithParamInterface; -using ::testing::Values; - -using namespace fspp::fuse; - -class FuseUtimensErrorTest: public FuseUtimensTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseUtimensErrorTest, FuseUtimensErrorTest, Values(EACCES, ENOENT, EPERM, EROFS)); - -TEST_P(FuseUtimensErrorTest, ReturnedErrorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, utimens(Eq(FILENAME), testing::_, testing::_)) - .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); - - int error = UtimensReturnError(FILENAME, TIMEVALUE, TIMEVALUE); - EXPECT_EQ(GetParam(), error); -} diff --git a/test/fspp/fuse/utimens/FuseUtimensFilenameTest.cpp b/test/fspp/fuse/utimens/FuseUtimensFilenameTest.cpp deleted file mode 100644 index 95885b17..00000000 --- a/test/fspp/fuse/utimens/FuseUtimensFilenameTest.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "testutils/FuseUtimensTest.h" - -using ::testing::Eq; -using ::testing::Return; - -class FuseUtimensFilenameTest: public FuseUtimensTest { -}; - -TEST_F(FuseUtimensFilenameTest, UtimensFile) { - ReturnIsFileOnLstat("/myfile"); - EXPECT_CALL(*fsimpl, utimens(Eq("/myfile"), testing::_, testing::_)) - .Times(1).WillOnce(Return()); - - Utimens("/myfile", TIMEVALUE, TIMEVALUE); -} - -TEST_F(FuseUtimensFilenameTest, UtimensFileNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsFileOnLstat("/mydir/myfile"); - EXPECT_CALL(*fsimpl, utimens(Eq("/mydir/myfile"), testing::_, testing::_)) - .Times(1).WillOnce(Return()); - - Utimens("/mydir/myfile", TIMEVALUE, TIMEVALUE); -} - -TEST_F(FuseUtimensFilenameTest, UtimensFileNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsFileOnLstat("/mydir/mydir2/myfile"); - EXPECT_CALL(*fsimpl, utimens(Eq("/mydir/mydir2/myfile"), testing::_, testing::_)) - .Times(1).WillOnce(Return()); - - Utimens("/mydir/mydir2/myfile", TIMEVALUE, TIMEVALUE); -} - -TEST_F(FuseUtimensFilenameTest, UtimensDir) { - ReturnIsDirOnLstat("/mydir"); - EXPECT_CALL(*fsimpl, utimens(Eq("/mydir"), testing::_, testing::_)) - .Times(1).WillOnce(Return()); - - Utimens("/mydir", TIMEVALUE, TIMEVALUE); -} - -TEST_F(FuseUtimensFilenameTest, UtimensDirNested) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - EXPECT_CALL(*fsimpl, utimens(Eq("/mydir/mydir2"), testing::_, testing::_)) - .Times(1).WillOnce(Return()); - - Utimens("/mydir/mydir2", TIMEVALUE, TIMEVALUE); -} - -TEST_F(FuseUtimensFilenameTest, UtimensDirNested2) { - ReturnIsDirOnLstat("/mydir"); - ReturnIsDirOnLstat("/mydir/mydir2"); - ReturnIsDirOnLstat("/mydir/mydir2/mydir3"); - EXPECT_CALL(*fsimpl, utimens(Eq("/mydir/mydir2/mydir3"), testing::_, testing::_)) - .Times(1).WillOnce(Return()); - - Utimens("/mydir/mydir2/mydir3", TIMEVALUE, TIMEVALUE); -} diff --git a/test/fspp/fuse/utimens/FuseUtimensTimeParameterTest.cpp b/test/fspp/fuse/utimens/FuseUtimensTimeParameterTest.cpp deleted file mode 100644 index 72e95275..00000000 --- a/test/fspp/fuse/utimens/FuseUtimensTimeParameterTest.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "testutils/FuseUtimensTest.h" - -using ::testing::Eq; -using ::testing::Return; -using ::testing::WithParamInterface; -using ::testing::Values; - -class FuseUtimensTimeParameterTest: public FuseUtimensTest, public WithParamInterface> { -}; -const std::array TIMEVAL1 = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(0,0)}; -const std::array TIMEVAL2 = {FuseUtimensTest::makeTimespec(1000,0), FuseUtimensTest::makeTimespec(0,0)}; -const std::array TIMEVAL3 = {FuseUtimensTest::makeTimespec(0,1000), FuseUtimensTest::makeTimespec(0,0)}; -const std::array TIMEVAL4 = {FuseUtimensTest::makeTimespec(1000,1000), FuseUtimensTest::makeTimespec(0,0)}; -const std::array TIMEVAL5 = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(0,0)}; -const std::array TIMEVAL6 = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(1000,0)}; -const std::array TIMEVAL7 = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(0,1000)}; -const std::array TIMEVAL8 = {FuseUtimensTest::makeTimespec(0,0), FuseUtimensTest::makeTimespec(1000,1000)}; -const std::array TIMEVAL9 = {FuseUtimensTest::makeTimespec(1417196126,123000), FuseUtimensTest::makeTimespec(1417109713,321000)}; // current timestamp and the day before as of writing this test case -const std::array TIMEVAL10 = {FuseUtimensTest::makeTimespec(UINT64_C(1024)*1024*1024*1024,999000), FuseUtimensTest::makeTimespec(UINT64_C(2*1024)*1024*1024*1024,321000)}; // needs 64bit for timestamp representation -INSTANTIATE_TEST_SUITE_P(FuseUtimensTimeParameterTest, FuseUtimensTimeParameterTest, - Values(TIMEVAL1, TIMEVAL2, TIMEVAL3, TIMEVAL4, TIMEVAL5, TIMEVAL6, TIMEVAL7, TIMEVAL8, TIMEVAL9, TIMEVAL10)); - - -TEST_P(FuseUtimensTimeParameterTest, Utimens) { - ReturnIsFileOnLstat(FILENAME); - EXPECT_CALL(*fsimpl, utimens(Eq(FILENAME), TimeSpecEq(GetParam()[0]), TimeSpecEq(GetParam()[1]))) - .Times(1).WillOnce(Return()); - - Utimens(FILENAME, GetParam()[0], GetParam()[1]); -} diff --git a/test/fspp/fuse/utimens/testutils/FuseUtimensTest.cpp b/test/fspp/fuse/utimens/testutils/FuseUtimensTest.cpp deleted file mode 100644 index 4ae8368b..00000000 --- a/test/fspp/fuse/utimens/testutils/FuseUtimensTest.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "FuseUtimensTest.h" -#include - -void FuseUtimensTest::Utimens(const char *filename, timespec lastAccessTime, timespec lastModificationTime) { - int error = UtimensReturnError(filename, lastAccessTime, lastModificationTime); - EXPECT_EQ(0, error); -} - -int FuseUtimensTest::UtimensReturnError(const char *filename, timespec lastAccessTime, timespec lastModificationTime) { - auto fs = TestFS(); - - auto realpath = fs->mountDir() / filename; - - return cpputils::set_filetime(realpath.string().c_str(), lastAccessTime, lastModificationTime); -} - -struct timespec FuseUtimensTest::makeTimespec(time_t tv_sec, long tv_nsec) { - struct timespec result{}; - result.tv_sec = tv_sec; - result.tv_nsec = tv_nsec; - return result; -} diff --git a/test/fspp/fuse/utimens/testutils/FuseUtimensTest.h b/test/fspp/fuse/utimens/testutils/FuseUtimensTest.h deleted file mode 100644 index 7306ab53..00000000 --- a/test/fspp/fuse/utimens/testutils/FuseUtimensTest.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_UTIMENS_TESTUTILS_FUSEUTIMENSTEST_H_ -#define MESSMER_FSPP_TEST_FUSE_UTIMENS_TESTUTILS_FUSEUTIMENSTEST_H_ - -#include "../../../testutils/FuseTest.h" - -class FuseUtimensTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - timespec TIMEVALUE = makeTimespec(0,0); - - void Utimens(const char *filename, timespec lastAccessTime, timespec lastModificationTime); - int UtimensReturnError(const char *filename, timespec lastAccessTime, timespec lastModificationTime); - - static struct timespec makeTimespec(time_t tv_sec, long tv_nsec); -}; - -MATCHER_P(TimeSpecEq, expected, "") { - return expected.tv_sec == arg.tv_sec && expected.tv_nsec == arg.tv_nsec; -} - -#endif diff --git a/test/fspp/fuse/write/FuseWriteDataTest.cpp b/test/fspp/fuse/write/FuseWriteDataTest.cpp deleted file mode 100644 index 29c3b827..00000000 --- a/test/fspp/fuse/write/FuseWriteDataTest.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include "testutils/FuseWriteTest.h" -#include "../../testutils/InMemoryFile.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -#include -#include - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Combine; -using ::testing::Invoke; -using ::testing::Action; - -using std::tuple; -using std::get; -using cpputils::Data; -using cpputils::DataFixture; - -using namespace fspp::fuse; - -// We can't test the count or size parameter directly, because fuse doesn't pass them 1:1. -// But we can test that the data passed to the ::write syscall is correctly written. - -struct TestData { - TestData(): count(0), offset(0), additional_bytes_at_end_of_file(0) {} - TestData(const tuple &data): count(get<0>(data)), offset(get<1>(data)), additional_bytes_at_end_of_file(get<2>(data)) {} - fspp::num_bytes_t count; - fspp::num_bytes_t offset; - //How many more bytes does the file have after the read block? - fspp::num_bytes_t additional_bytes_at_end_of_file; - fspp::num_bytes_t fileSize() { - return count + offset + additional_bytes_at_end_of_file; - } -}; - -// The testcase creates random data in memory, offers a mock write() implementation to write to this -// memory region and check methods to check for data equality of a region. -class FuseWriteDataTest: public FuseWriteTest, public WithParamInterface> { -public: - std::unique_ptr testFile; - TestData testData; - - FuseWriteDataTest() - : testFile(nullptr), - testData(GetParam()) { - testFile = std::make_unique(DataFixture::generate(testData.fileSize().value(), 1)); - ReturnIsFileOnLstatWithSize(FILENAME, testData.fileSize()); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, write(0, testing::_, testing::_, testing::_)) - .WillRepeatedly(WriteToFile); - } - - // This write() mock implementation writes to the stored virtual file. - Action WriteToFile = Invoke([this](int, const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - testFile->write(buf, count, offset); - }); -}; -INSTANTIATE_TEST_SUITE_P(FuseWriteDataTest, FuseWriteDataTest, Combine( - Values(fspp::num_bytes_t(0), fspp::num_bytes_t(1), fspp::num_bytes_t(10), fspp::num_bytes_t(1000), fspp::num_bytes_t(1024), fspp::num_bytes_t(10*1024*1024)), - Values(fspp::num_bytes_t(0), fspp::num_bytes_t(1), fspp::num_bytes_t(10), fspp::num_bytes_t(1024), fspp::num_bytes_t(10*1024*1024)), - Values(fspp::num_bytes_t(0), fspp::num_bytes_t(1), fspp::num_bytes_t(10), fspp::num_bytes_t(1024), fspp::num_bytes_t(10*1024*1024)) - )); - - -TEST_P(FuseWriteDataTest, DataWasCorrectlyWritten) { - Data randomWriteData = DataFixture::generate(testData.count.value(), 2); - WriteFile(FILENAME, randomWriteData.data(), testData.count, testData.offset); - - EXPECT_TRUE(testFile->fileContentEquals(randomWriteData, testData.offset)); -} - -TEST_P(FuseWriteDataTest, RestOfFileIsUnchanged) { - Data randomWriteData = DataFixture::generate(testData.count.value(), 2); - WriteFile(FILENAME, randomWriteData.data(), testData.count, testData.offset); - - EXPECT_TRUE(testFile->sizeUnchanged()); - EXPECT_TRUE(testFile->regionUnchanged(fspp::num_bytes_t(0), testData.offset)); - EXPECT_TRUE(testFile->regionUnchanged(testData.offset + testData.count, testData.additional_bytes_at_end_of_file)); -} diff --git a/test/fspp/fuse/write/FuseWriteErrorTest.cpp b/test/fspp/fuse/write/FuseWriteErrorTest.cpp deleted file mode 100644 index 932f384e..00000000 --- a/test/fspp/fuse/write/FuseWriteErrorTest.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "testutils/FuseWriteTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; -using ::testing::Ne; -using ::testing::Invoke; -using ::testing::Throw; - -using namespace fspp::fuse; - -class FuseWriteErrorTest: public FuseWriteTest, public WithParamInterface { -public: - fspp::num_bytes_t FILESIZE = fspp::num_bytes_t(64*1024*1024); - fspp::num_bytes_t WRITECOUNT = fspp::num_bytes_t(32*1024*1024); - - void SetUp() override { - //Make the file size big enough that fuse should issue at least two writes - ReturnIsFileOnLstatWithSize(FILENAME, FILESIZE); - OnOpenReturnFileDescriptor(FILENAME, 0); - } -}; -INSTANTIATE_TEST_SUITE_P(FuseWriteErrorTest, FuseWriteErrorTest, Values(EAGAIN, EBADF, EDESTADDRREQ, EDQUOT, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENOSPC, EPIPE, EOVERFLOW, ESPIPE, ENXIO)); - - -TEST_P(FuseWriteErrorTest, ReturnErrorOnFirstWriteCall) { - EXPECT_CALL(*fsimpl, write(0, testing::_, testing::_, testing::_)) - .WillRepeatedly(Throw(FuseErrnoException(GetParam()))); - - char *buf = new char[WRITECOUNT.value()]; - auto retval = WriteFileReturnError(FILENAME, buf, WRITECOUNT, fspp::num_bytes_t(0)); - EXPECT_EQ(GetParam(), retval.error); - delete[] buf; -} - -TEST_P(FuseWriteErrorTest, ReturnErrorOnSecondWriteCall) { - // The first write request is from the beginning of the file and works, but the later ones fail. - // We store the number of bytes the first call could successfully write and check later that our - // write syscall returns exactly this number of bytes - fspp::num_bytes_t successfullyWrittenBytes = fspp::num_bytes_t(-1); - EXPECT_CALL(*fsimpl, write(0, testing::_, testing::_, Eq(fspp::num_bytes_t(0)))) - .Times(1) - .WillOnce(Invoke([&successfullyWrittenBytes](int, const void*, fspp::num_bytes_t count, fspp::num_bytes_t) { - // Store the number of successfully written bytes - successfullyWrittenBytes = count; - })); - EXPECT_CALL(*fsimpl, write(0, testing::_, testing::_, Ne(fspp::num_bytes_t(0)))) - .WillRepeatedly(Throw(FuseErrnoException(GetParam()))); - - char *buf = new char[WRITECOUNT.value()]; - auto retval = WriteFileReturnError(FILENAME, buf, WRITECOUNT, fspp::num_bytes_t(0)); - EXPECT_EQ(0, retval.error); - EXPECT_EQ(successfullyWrittenBytes, retval.written_bytes); // Check that we're getting the number of successfully written bytes (the first write call) returned - delete[] buf; -} - diff --git a/test/fspp/fuse/write/FuseWriteFileDescriptorTest.cpp b/test/fspp/fuse/write/FuseWriteFileDescriptorTest.cpp deleted file mode 100644 index 714a3876..00000000 --- a/test/fspp/fuse/write/FuseWriteFileDescriptorTest.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "testutils/FuseWriteTest.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::WithParamInterface; -using ::testing::Values; -using ::testing::Eq; -using ::testing::Return; - -using namespace fspp::fuse; - -class FuseWriteFileDescriptorTest: public FuseWriteTest, public WithParamInterface { -}; -INSTANTIATE_TEST_SUITE_P(FuseWriteFileDescriptorTest, FuseWriteFileDescriptorTest, Values(0,1,10,1000,1024*1024*1024)); - - -TEST_P(FuseWriteFileDescriptorTest, FileDescriptorIsCorrect) { - ReturnIsFileOnLstat(FILENAME); - OnOpenReturnFileDescriptor(FILENAME, GetParam()); - EXPECT_CALL(*fsimpl, write(Eq(GetParam()), testing::_, testing::_, testing::_)) - .Times(1).WillOnce(Return()); - - std::array buf{}; - WriteFile(FILENAME, buf.data(), fspp::num_bytes_t(1), fspp::num_bytes_t(0)); -} diff --git a/test/fspp/fuse/write/FuseWriteOverflowTest.cpp b/test/fspp/fuse/write/FuseWriteOverflowTest.cpp deleted file mode 100644 index 73943b82..00000000 --- a/test/fspp/fuse/write/FuseWriteOverflowTest.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include "testutils/FuseWriteTest.h" -#include "../../testutils/InMemoryFile.h" - -#include "fspp/fs_interface/FuseErrnoException.h" - -using ::testing::Invoke; -using ::testing::Action; - -using cpputils::DataFixture; -using cpputils::Data; - -using namespace fspp::fuse; - -class FuseWriteOverflowTest: public FuseWriteTest { -public: - fspp::num_bytes_t FILESIZE; - fspp::num_bytes_t WRITESIZE; - fspp::num_bytes_t OFFSET; - - WriteableInMemoryFile testFile; - Data writeData; - - FuseWriteOverflowTest(fspp::num_bytes_t filesize, fspp::num_bytes_t writesize, fspp::num_bytes_t offset) - : FILESIZE(filesize), WRITESIZE(writesize), OFFSET(offset), testFile(DataFixture::generate(FILESIZE.value())), writeData(DataFixture::generate(WRITESIZE.value())) { - ReturnIsFileOnLstatWithSize(FILENAME, FILESIZE); - OnOpenReturnFileDescriptor(FILENAME, 0); - EXPECT_CALL(*fsimpl, write(0, testing::_, testing::_, testing::_)).WillRepeatedly(WriteToFile); - } - - // This write() mock implementation writes to the stored virtual file. - Action WriteToFile = - Invoke([this](int, const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - testFile.write(buf, count, offset); - }); -}; - -class FuseWriteOverflowTestWithNonemptyFile: public FuseWriteOverflowTest { -public: - FuseWriteOverflowTestWithNonemptyFile(): FuseWriteOverflowTest(fspp::num_bytes_t(1000), fspp::num_bytes_t(2000), fspp::num_bytes_t(500)) {} -}; - -TEST_F(FuseWriteOverflowTestWithNonemptyFile, WriteMoreThanFileSizeFromBeginning) { - WriteFile(FILENAME, writeData.data(), WRITESIZE, fspp::num_bytes_t(0)); - - EXPECT_EQ(WRITESIZE, testFile.size()); - EXPECT_TRUE(testFile.fileContentEquals(writeData, fspp::num_bytes_t(0))); -} - -TEST_F(FuseWriteOverflowTestWithNonemptyFile, WriteMoreThanFileSizeFromMiddle) { - WriteFile(FILENAME, writeData.data(), WRITESIZE, OFFSET); - - EXPECT_EQ(OFFSET + WRITESIZE, testFile.size()); - EXPECT_TRUE(testFile.regionUnchanged(fspp::num_bytes_t(0), OFFSET)); - EXPECT_TRUE(testFile.fileContentEquals(writeData, OFFSET)); -} - -TEST_F(FuseWriteOverflowTestWithNonemptyFile, WriteAfterFileEnd) { - WriteFile(FILENAME, writeData.data(), WRITESIZE, FILESIZE + OFFSET); - - EXPECT_EQ(FILESIZE + OFFSET + WRITESIZE, testFile.size()); - EXPECT_TRUE(testFile.regionUnchanged(fspp::num_bytes_t(0), FILESIZE)); - EXPECT_TRUE(testFile.fileContentEquals(writeData, FILESIZE + OFFSET)); -} - -class FuseWriteOverflowTestWithEmptyFile: public FuseWriteOverflowTest { -public: - FuseWriteOverflowTestWithEmptyFile(): FuseWriteOverflowTest(fspp::num_bytes_t(0), fspp::num_bytes_t(2000), fspp::num_bytes_t(500)) {} -}; - -TEST_F(FuseWriteOverflowTestWithEmptyFile, WriteToBeginOfEmptyFile) { - WriteFile(FILENAME, writeData.data(), WRITESIZE, fspp::num_bytes_t(0)); - - EXPECT_EQ(WRITESIZE, testFile.size()); - EXPECT_TRUE(testFile.fileContentEquals(writeData, fspp::num_bytes_t(0))); -} - -TEST_F(FuseWriteOverflowTestWithEmptyFile, WriteAfterFileEnd) { - WriteFile(FILENAME, writeData.data(), WRITESIZE, OFFSET); - - EXPECT_EQ(OFFSET + WRITESIZE, testFile.size()); - EXPECT_TRUE(testFile.fileContentEquals(writeData, OFFSET)); -} diff --git a/test/fspp/fuse/write/testutils/FuseWriteTest.cpp b/test/fspp/fuse/write/testutils/FuseWriteTest.cpp deleted file mode 100644 index 61ba1fcb..00000000 --- a/test/fspp/fuse/write/testutils/FuseWriteTest.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "FuseWriteTest.h" - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -void FuseWriteTest::WriteFile(const char *filename, const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - auto retval = WriteFileReturnError(filename, buf, count, offset); - EXPECT_EQ(0, retval.error); - EXPECT_EQ(count, retval.written_bytes); -} - -FuseWriteTest::WriteError FuseWriteTest::WriteFileReturnError(const char *filename, const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - auto fs = TestFS(); - - auto fd = OpenFile(fs.get(), filename); - - WriteError result{}; - errno = 0; - result.written_bytes = fspp::num_bytes_t(::pwrite(fd->fd(), buf, count.value(), offset.value())); - result.error = errno; - return result; -} - -unique_ref FuseWriteTest::OpenFile(const TempTestFS *fs, const char *filename) { - auto realpath = fs->mountDir() / filename; - auto fd = make_unique_ref(realpath.string().c_str(), O_WRONLY); - EXPECT_GE(fd->fd(), 0) << "Error opening file"; - return fd; -} diff --git a/test/fspp/fuse/write/testutils/FuseWriteTest.h b/test/fspp/fuse/write/testutils/FuseWriteTest.h deleted file mode 100644 index 97e0d990..00000000 --- a/test/fspp/fuse/write/testutils/FuseWriteTest.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_FUSE_WRITE_TESTUTILS_FUSEWRITETEST_H_ -#define MESSMER_FSPP_TEST_FUSE_WRITE_TESTUTILS_FUSEWRITETEST_H_ - -#include "../../../testutils/FuseTest.h" -#include "../../../testutils/OpenFileHandle.h" - -class FuseWriteTest: public FuseTest { -public: - const char *FILENAME = "/myfile"; - - struct WriteError { - int error{}; - fspp::num_bytes_t written_bytes; - }; - - void WriteFile(const char *filename, const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset); - WriteError WriteFileReturnError(const char *filename, const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset); - -private: - cpputils::unique_ref OpenFile(const TempTestFS *fs, const char *filename); -}; - -#endif diff --git a/test/fspp/impl/FuseOpenFileListTest.cpp b/test/fspp/impl/FuseOpenFileListTest.cpp deleted file mode 100644 index e59fe558..00000000 --- a/test/fspp/impl/FuseOpenFileListTest.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include -#include - -#include "fspp/impl/FuseOpenFileList.h" - -#include - -using cpputils::make_unique_ref; - -using namespace fspp; - -class MockOpenFile: public OpenFile { -public: - MockOpenFile(int fileid_, int flags_): fileid(fileid_), flags(flags_), destructed(false) {} - int fileid, flags; - bool destructed; - - ~MockOpenFile() {destructed = true;} - - MOCK_METHOD(OpenFile::stat_info, stat, (), (const, override)); - MOCK_METHOD(void, truncate, (fspp::num_bytes_t), (const, override)); - MOCK_METHOD(fspp::num_bytes_t, read, (void*, fspp::num_bytes_t, fspp::num_bytes_t), (const, override)); - MOCK_METHOD(void, write, (const void*, fspp::num_bytes_t, fspp::num_bytes_t), (override)); - MOCK_METHOD(void, flush, (), (override)); - MOCK_METHOD(void, fsync, (), (override)); - MOCK_METHOD(void, fdatasync, (), (override)); -}; - -struct FuseOpenFileListTest: public ::testing::Test { - static constexpr int FILEID1 = 4; - static constexpr int FLAGS1 = 5; - static constexpr int FILEID2 = 6; - static constexpr int FLAGS2 = 7; - static constexpr int FILEID3 = 8; - static constexpr int FLAGS3 = 9; - - FuseOpenFileListTest(): list() {} - - FuseOpenFileList list; - - int open(int fileid, int flags) { - return list.open(make_unique_ref(fileid, flags)); - } - int open() { - return open(FILEID1, FILEID2); - } - void check(int id, int fileid, int flags) { - list.load(id, [=](OpenFile* _openFile) { - MockOpenFile *openFile = dynamic_cast(_openFile); - EXPECT_EQ(fileid, openFile->fileid); - EXPECT_EQ(flags, openFile->flags); - }); - } -}; - -TEST_F(FuseOpenFileListTest, EmptyList1) { - ASSERT_THROW(list.load(0, [](OpenFile*) {}), fspp::fuse::FuseErrnoException); -} - -TEST_F(FuseOpenFileListTest, EmptyList2) { - ASSERT_THROW(list.load(3, [](OpenFile*) {}), fspp::fuse::FuseErrnoException); -} - -TEST_F(FuseOpenFileListTest, InvalidId) { - int valid_id = open(); - int invalid_id = valid_id + 1; - ASSERT_THROW(list.load(invalid_id, [](OpenFile*) {}), fspp::fuse::FuseErrnoException); -} - -TEST_F(FuseOpenFileListTest, Open1AndGet) { - int id = open(FILEID1, FLAGS1); - check(id, FILEID1, FLAGS1); -} - -TEST_F(FuseOpenFileListTest, Open2AndGet) { - int id1 = open(FILEID1, FLAGS1); - int id2 = open(FILEID2, FLAGS2); - - check(id1, FILEID1, FLAGS1); - check(id2, FILEID2, FLAGS2); -} - -TEST_F(FuseOpenFileListTest, Open3AndGet) { - int id1 = open(FILEID1, FLAGS1); - int id2 = open(FILEID2, FLAGS2); - int id3 = open(FILEID3, FLAGS3); - - check(id1, FILEID1, FLAGS1); - check(id3, FILEID3, FLAGS3); - check(id2, FILEID2, FLAGS2); -} - -//TODO Test case fails. Disabled it. Figure out why and reenable. -/*TEST_F(FuseOpenFileListTest, DestructOnClose) { - int id = open(); - - MockOpenFile *openFile = dynamic_cast(list.get(id)); - - EXPECT_FALSE(openFile->destructed); - list.close(id); - EXPECT_TRUE(openFile->destructed); -}*/ - -TEST_F(FuseOpenFileListTest, GetClosedItemOnEmptyList) { - int id = open(); - - ASSERT_NO_THROW(list.load(id, [](OpenFile*) {})); - list.close(id); - ASSERT_THROW(list.load(id, [](OpenFile*) {}), fspp::fuse::FuseErrnoException); -} - -TEST_F(FuseOpenFileListTest, GetClosedItemOnNonEmptyList) { - int id = open(); - open(); - - ASSERT_NO_THROW(list.load(id, [](OpenFile*) {})); - list.close(id); - ASSERT_THROW(list.load(id, [](OpenFile*) {}), fspp::fuse::FuseErrnoException); -} - -TEST_F(FuseOpenFileListTest, CloseOnEmptyList1) { - ASSERT_THROW(list.close(0), std::out_of_range); -} - -TEST_F(FuseOpenFileListTest, CloseOnEmptyList2) { - ASSERT_THROW(list.close(4), std::out_of_range); -} - -TEST_F(FuseOpenFileListTest, RemoveInvalidId) { - int valid_id = open(); - int invalid_id = valid_id + 1; - ASSERT_THROW(list.close(invalid_id), std::out_of_range); -} diff --git a/test/fspp/impl/IdListTest.cpp b/test/fspp/impl/IdListTest.cpp deleted file mode 100644 index dc6b289d..00000000 --- a/test/fspp/impl/IdListTest.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#include "fspp/impl/IdList.h" -#include - -using cpputils::make_unique_ref; - -using namespace fspp; - -class MyObj { -public: - MyObj(int val_): val(val_) {} - int val; -}; - -struct IdListTest: public ::testing::Test { - static constexpr int OBJ1 = 3; - static constexpr int OBJ2 = 10; - static constexpr int OBJ3 = 8; - - IdListTest(): list() {} - - IdList list; - - int add(int num) { - return list.add(make_unique_ref(num)); - } - int add() { - return add(OBJ1); - } - void check(int id, int num) { - EXPECT_EQ(num, list.get(id)->val); - } - void checkConst(int id, int num) { - const IdList &constList = list; - EXPECT_EQ(num, constList.get(id)->val); - } -}; - -TEST_F(IdListTest, EmptyList1) { - ASSERT_THROW(list.get(0), std::out_of_range); -} - -TEST_F(IdListTest, EmptyList2) { - ASSERT_THROW(list.get(3), std::out_of_range); -} - -TEST_F(IdListTest, InvalidId) { - int valid_id = add(); - int invalid_id = valid_id + 1; - ASSERT_THROW(list.get(invalid_id), std::out_of_range); -} - -TEST_F(IdListTest, GetRemovedItemOnEmptyList) { - int id = add(); - list.remove(id); - ASSERT_THROW(list.get(id), std::out_of_range); -} - -TEST_F(IdListTest, GetRemovedItemOnNonEmptyList) { - int id = add(); - add(); - list.remove(id); - ASSERT_THROW(list.get(id), std::out_of_range); -} - -TEST_F(IdListTest, RemoveOnEmptyList1) { - ASSERT_THROW(list.remove(0), std::out_of_range); -} - -TEST_F(IdListTest, RemoveOnEmptyList2) { - ASSERT_THROW(list.remove(4), std::out_of_range); -} - -TEST_F(IdListTest, RemoveInvalidId) { - int valid_id = add(); - int invalid_id = valid_id + 1; - ASSERT_THROW(list.remove(invalid_id), std::out_of_range); -} - -TEST_F(IdListTest, Add1AndGet) { - int id = add(OBJ1); - check(id, OBJ1); -} - -TEST_F(IdListTest, Add2AndGet) { - int id1 = add(OBJ1); - int id2 = add(OBJ2); - check(id1, OBJ1); - check(id2, OBJ2); -} - -TEST_F(IdListTest, Add3AndGet) { - int id1 = add(OBJ1); - int id2 = add(OBJ2); - int id3 = add(OBJ3); - check(id1, OBJ1); - check(id3, OBJ3); - check(id2, OBJ2); -} - -TEST_F(IdListTest, Add3AndConstGet) { - int id1 = add(OBJ1); - int id2 = add(OBJ2); - int id3 = add(OBJ3); - checkConst(id1, OBJ1); - checkConst(id3, OBJ3); - checkConst(id2, OBJ2); -} diff --git a/test/fspp/testutils/FuseTest.cpp b/test/fspp/testutils/FuseTest.cpp deleted file mode 100644 index ba44a1e0..00000000 --- a/test/fspp/testutils/FuseTest.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "FuseTest.h" - -using ::testing::Eq; -using ::testing::Return; -using ::testing::Throw; -using ::testing::Action; -using ::testing::Invoke; -using std::make_shared; -using std::shared_ptr; - -using cpputils::unique_ref; -using cpputils::make_unique_ref; - -namespace bf = boost::filesystem; - -using namespace fspp::fuse; - -MockFilesystem::MockFilesystem() {} -MockFilesystem::~MockFilesystem() {} - -FuseTest::FuseTest(): fsimpl(make_shared()), _context(boost::none) { - using ::testing::_; - auto defaultAction = Throw(FuseErrnoException(EIO)); - ON_CALL(*fsimpl, openFile(_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, closeFile(_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, lstat(_,_)).WillByDefault(Throw(FuseErrnoException(ENOENT))); - ON_CALL(*fsimpl, fstat(_,_)).WillByDefault(Throw(FuseErrnoException(ENOENT))); - ON_CALL(*fsimpl, truncate(_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, ftruncate(_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, read(_,_,_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, write(_,_,_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, fsync(_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, fdatasync(_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, access(_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, createAndOpenFile(_,_,_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, mkdir(_,_,_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, rmdir(_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, unlink(_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, rename(_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, readDir(_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, utimens(_,_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, statfs(_)).WillByDefault(Invoke([](struct statvfs *result) { - ::statvfs("/", result); // As dummy value take the values from the root filesystem - })); - ON_CALL(*fsimpl, chmod(_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, chown(_,_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, createSymlink(_,_,_,_)).WillByDefault(defaultAction); - ON_CALL(*fsimpl, readSymlink(_,_,_)).WillByDefault(defaultAction); - - EXPECT_CALL(*fsimpl, access(_,_)).WillRepeatedly(Return()); - - ON_CALL(*fsimpl, setContext(_)).WillByDefault(Invoke([this] (fspp::Context context) { - _context = std::move(context); - })); - - ReturnIsDirOnLstat("/"); -} - -unique_ref FuseTest::TestFS(const std::vector& fuseOptions) { - return make_unique_ref(fsimpl, fuseOptions); -} - -FuseTest::TempTestFS::TempTestFS(shared_ptr fsimpl, const std::vector& fuseOptions) - :_mountDir(), - _fuse([fsimpl] (Fuse*) {return fsimpl;}, []{}, "fusetest", boost::none), _fuse_thread(&_fuse) { - - _fuse_thread.start(_mountDir.path(), fuseOptions); -} - -FuseTest::TempTestFS::~TempTestFS() { - _fuse_thread.stop(); -} - -const bf::path &FuseTest::TempTestFS::mountDir() const { - return _mountDir.path(); -} - -Action FuseTest::ReturnIsFileWithSize(fspp::num_bytes_t size) { - return Invoke([size](const boost::filesystem::path&, fspp::fuse::STAT* result) { - result->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; - result->st_nlink = 1; - result->st_size = size.value(); - }); -} - -//TODO Combine ReturnIsFile and ReturnIsFileFstat. This should be possible in gmock by either (a) using ::testing::Undefined as parameter type or (b) using action macros -Action FuseTest::ReturnIsFile = ReturnIsFileWithSize(fspp::num_bytes_t(0)); - -Action FuseTest::ReturnIsFileFstat = - Invoke([](int, fspp::fuse::STAT* result) { - result->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; - result->st_nlink = 1; - }); - -Action FuseTest::ReturnIsFileFstatWithSize(fspp::num_bytes_t size) { - return Invoke([size](int, struct ::stat *result) { - result->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; - result->st_nlink = 1; - result->st_size = size.value(); - }); -} - -Action FuseTest::ReturnIsDir = - Invoke([](const boost::filesystem::path&, fspp::fuse::STAT* result) { - result->st_mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH; - result->st_nlink = 1; - }); - -Action FuseTest::ReturnDoesntExist = Throw(fspp::fuse::FuseErrnoException(ENOENT)); - -void FuseTest::OnOpenReturnFileDescriptor(const char *filename, int descriptor) { - EXPECT_CALL(*fsimpl, openFile(Eq(filename), testing::_)).Times(1).WillOnce(Return(descriptor)); -} - -void FuseTest::ReturnIsFileOnLstat(const bf::path &path) { - EXPECT_CALL(*fsimpl, lstat(Eq(path), ::testing::_)).WillRepeatedly(ReturnIsFile); -} - -void FuseTest::ReturnIsFileOnLstatWithSize(const bf::path &path, const fspp::num_bytes_t size) { - EXPECT_CALL(*fsimpl, lstat(Eq(path), ::testing::_)).WillRepeatedly(ReturnIsFileWithSize(size)); -} - -void FuseTest::ReturnIsDirOnLstat(const bf::path &path) { - EXPECT_CALL(*fsimpl, lstat(Eq(path), ::testing::_)).WillRepeatedly(ReturnIsDir); -} - -void FuseTest::ReturnDoesntExistOnLstat(const bf::path &path) { - EXPECT_CALL(*fsimpl, lstat(Eq(path), ::testing::_)).WillRepeatedly(ReturnDoesntExist); -} - -void FuseTest::ReturnIsFileOnFstat(int descriptor) { - EXPECT_CALL(*fsimpl, fstat(descriptor, testing::_)).WillRepeatedly(ReturnIsFileFstat); -} - -void FuseTest::ReturnIsFileOnFstatWithSize(int descriptor, fspp::num_bytes_t size) { - EXPECT_CALL(*fsimpl, fstat(descriptor, testing::_)).WillRepeatedly(ReturnIsFileFstatWithSize(size)); -} diff --git a/test/fspp/testutils/FuseTest.h b/test/fspp/testutils/FuseTest.h deleted file mode 100644 index 8430182f..00000000 --- a/test/fspp/testutils/FuseTest.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_TESTUTILS_FUSETEST_H_ -#define MESSMER_FSPP_TEST_TESTUTILS_FUSETEST_H_ - -#include -#include - -#include "fspp/fuse/Filesystem.h" -#include "fspp/fs_interface/FuseErrnoException.h" -#include "fspp/fuse/Fuse.h" -#include "fspp/fs_interface/Dir.h" - -#include - -#include -#include "FuseThread.h" - -class MockFilesystem: public fspp::fuse::Filesystem { -public: - MockFilesystem(); - virtual ~MockFilesystem(); - - MOCK_METHOD(void, setContext, (fspp::Context&&), (override)); - MOCK_METHOD(int, openFile, (const boost::filesystem::path&, int), (override)); - MOCK_METHOD(void, closeFile, (int), (override)); - MOCK_METHOD(void, lstat, (const boost::filesystem::path&, fspp::fuse::STAT*), (override)); - MOCK_METHOD(void, fstat, (int, fspp::fuse::STAT*), (override)); - MOCK_METHOD(void, truncate, (const boost::filesystem::path&, fspp::num_bytes_t), (override)); - MOCK_METHOD(void, ftruncate, (int, fspp::num_bytes_t), (override)); - MOCK_METHOD(fspp::num_bytes_t, read, (int, void*, fspp::num_bytes_t, fspp::num_bytes_t), (override)); - MOCK_METHOD(void, write, (int, const void*, fspp::num_bytes_t, fspp::num_bytes_t), (override)); - MOCK_METHOD(void, flush, (int), (override)); - MOCK_METHOD(void, fsync, (int), (override)); - MOCK_METHOD(void, fdatasync, (int), (override)); - MOCK_METHOD(void, access, (const boost::filesystem::path&, int), (override)); - MOCK_METHOD(int, createAndOpenFile, (const boost::filesystem::path&, mode_t, uid_t, gid_t), (override)); - MOCK_METHOD(void, mkdir, (const boost::filesystem::path&, mode_t, uid_t, gid_t), (override)); - MOCK_METHOD(void, rmdir, (const boost::filesystem::path&), (override)); - MOCK_METHOD(void, unlink, (const boost::filesystem::path&), (override)); - MOCK_METHOD(void, rename, (const boost::filesystem::path&, const boost::filesystem::path&), (override)); - MOCK_METHOD(std::vector, readDir, (const boost::filesystem::path &path), (override)); - MOCK_METHOD(void, utimens, (const boost::filesystem::path&, timespec, timespec), (override)); - MOCK_METHOD(void, statfs, (struct statvfs*), (override)); - MOCK_METHOD(void, chmod, (const boost::filesystem::path&, mode_t), (override)); - MOCK_METHOD(void, chown, (const boost::filesystem::path&, uid_t, gid_t), (override)); - MOCK_METHOD(void, createSymlink, (const boost::filesystem::path&, const boost::filesystem::path&, uid_t, gid_t), (override)); - MOCK_METHOD(void, readSymlink, (const boost::filesystem::path&, char*, fspp::num_bytes_t), (override)); -}; - -class FuseTest: public ::testing::Test { -public: - static constexpr const char* FILENAME = "/myfile"; - - FuseTest(); - - class TempTestFS { - public: - TempTestFS(std::shared_ptr fsimpl, const std::vector& fuseOptions = {}); - virtual ~TempTestFS(); - public: - const boost::filesystem::path &mountDir() const; - private: - cpputils::TempDir _mountDir; - fspp::fuse::Fuse _fuse; - FuseThread _fuse_thread; - }; - - cpputils::unique_ref TestFS(const std::vector& fuseOptions = {}); - - std::shared_ptr fsimpl; - - const fspp::Context& context() const { - ASSERT(_context != boost::none, "Context wasn't correctly initialized"); - return *_context; - } -private: - boost::optional _context; - -public: - - //TODO Combine ReturnIsFile and ReturnIsFileFstat. This should be possible in gmock by either (a) using ::testing::Undefined as parameter type or (b) using action macros - static ::testing::Action ReturnIsFile; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - static ::testing::Action ReturnIsFileWithSize(fspp::num_bytes_t size); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - static ::testing::Action ReturnIsFileFstat; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - static ::testing::Action ReturnIsFileFstatWithSize(fspp::num_bytes_t size); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - static ::testing::Action ReturnIsDir; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - static ::testing::Action ReturnDoesntExist; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) - - void ReturnIsFileOnLstat(const boost::filesystem::path &path); - void ReturnIsFileOnLstatWithSize(const boost::filesystem::path &path, fspp::num_bytes_t size); - void ReturnIsDirOnLstat(const boost::filesystem::path &path); - void ReturnDoesntExistOnLstat(const boost::filesystem::path &path); - void OnOpenReturnFileDescriptor(const char *filename, int descriptor); - void ReturnIsFileOnFstat(int descriptor); - void ReturnIsFileOnFstatWithSize(int descriptor, fspp::num_bytes_t size); -}; - -#endif diff --git a/test/fspp/testutils/FuseThread.cpp b/test/fspp/testutils/FuseThread.cpp deleted file mode 100644 index 32f022df..00000000 --- a/test/fspp/testutils/FuseThread.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "FuseThread.h" -#include -#include -#include "fspp/fuse/Fuse.h" - -using boost::thread; -using boost::chrono::seconds; -using std::string; -using std::vector; -namespace bf = boost::filesystem; - -using fspp::fuse::Fuse; - -FuseThread::FuseThread(Fuse *fuse) - :_fuse(fuse), _child() { -} - -void FuseThread::start(const bf::path &mountDir, const vector &fuseOptions) { - _child = thread([this, mountDir, fuseOptions] () { - _fuse->runInForeground(mountDir, fuseOptions); - }); - //Wait until it is running (busy waiting is simple and doesn't hurt much here) - while(!_fuse->running()) {} -#ifdef __APPLE__ - // On Mac OS X, _fuse->running() returns true too early, because macFUSE calls init() when it's not ready yet. Give it a bit time. - std::this_thread::sleep_for(std::chrono::milliseconds(200)); -#endif -} - -void FuseThread::stop() { - _fuse->stop(); - bool thread_stopped = _child.try_join_for(seconds(10)); - ASSERT(thread_stopped, "FuseThread could not be stopped"); - //Wait until it is properly shutdown (busy waiting is simple and doesn't hurt much here) - while (_fuse->running()) {} -} diff --git a/test/fspp/testutils/FuseThread.h b/test/fspp/testutils/FuseThread.h deleted file mode 100644 index ab52742a..00000000 --- a/test/fspp/testutils/FuseThread.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_TESTUTILS_FUSETHREAD_H_ -#define MESSMER_FSPP_TEST_TESTUTILS_FUSETHREAD_H_ - -#include -#include -#include -#include - -namespace fspp { -namespace fuse { - class Fuse; -} -} - -class FuseThread { -public: - FuseThread(fspp::fuse::Fuse *fuse); - void start(const boost::filesystem::path &mountDir, const std::vector &fuseOptions); - void stop(); - -private: - fspp::fuse::Fuse *_fuse; - boost::thread _child; - - DISALLOW_COPY_AND_ASSIGN(FuseThread); -}; - -#endif diff --git a/test/fspp/testutils/InMemoryFile.cpp b/test/fspp/testutils/InMemoryFile.cpp deleted file mode 100644 index c215ce0e..00000000 --- a/test/fspp/testutils/InMemoryFile.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "InMemoryFile.h" - -using cpputils::Data; - -InMemoryFile::InMemoryFile(Data data): _data(std::move(data)) { -} - -InMemoryFile::~InMemoryFile() { -} - -fspp::num_bytes_t InMemoryFile::read(void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) const { - fspp::num_bytes_t realCount = std::min(count, fspp::num_bytes_t(_data.size()) - offset); - std::memcpy(buf, _data.dataOffset(offset.value()), realCount.value()); - return realCount; -} - -const void *InMemoryFile::data() const { - return _data.data(); -} - -bool InMemoryFile::fileContentEquals(const Data &expected, fspp::num_bytes_t offset) const { - return 0 == std::memcmp(expected.data(), _data.dataOffset(offset.value()), expected.size()); -} - -fspp::num_bytes_t InMemoryFile::size() const { - return fspp::num_bytes_t(_data.size()); -} - -WriteableInMemoryFile::WriteableInMemoryFile(Data data): InMemoryFile(std::move(data)), _originalData(_data.copy()) { -} - -void WriteableInMemoryFile::write(const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) { - _extendFileSizeIfNecessary(count + offset); - - std::memcpy(_data.dataOffset(offset.value()), buf, count.value()); -} - -void WriteableInMemoryFile::_extendFileSizeIfNecessary(fspp::num_bytes_t size) { - if (size > fspp::num_bytes_t(_data.size())) { - _extendFileSize(size); - } -} - -void WriteableInMemoryFile::_extendFileSize(fspp::num_bytes_t size) { - Data newfile(size.value()); - std::memcpy(newfile.data(), _data.data(), _data.size()); - _data = std::move(newfile); -} - -bool WriteableInMemoryFile::sizeUnchanged() const { - return _data.size() == _originalData.size(); -} - -bool WriteableInMemoryFile::regionUnchanged(fspp::num_bytes_t offset, fspp::num_bytes_t count) const { - return 0 == std::memcmp(_data.dataOffset(offset.value()), _originalData.dataOffset(offset.value()), count.value()); -} diff --git a/test/fspp/testutils/InMemoryFile.h b/test/fspp/testutils/InMemoryFile.h deleted file mode 100644 index 1d440e1b..00000000 --- a/test/fspp/testutils/InMemoryFile.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_TESTUTILS_INMEMORYFILE_H_ -#define MESSMER_FSPP_TEST_TESTUTILS_INMEMORYFILE_H_ - -#include -#include - -class InMemoryFile { -public: - InMemoryFile(cpputils::Data data); - virtual ~InMemoryFile(); - - fspp::num_bytes_t read(void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset) const; - - const void *data() const; - fspp::num_bytes_t size() const; - - bool fileContentEquals(const cpputils::Data &expected, fspp::num_bytes_t offset) const; - -protected: - cpputils::Data _data; -}; - -class WriteableInMemoryFile: public InMemoryFile { -public: - WriteableInMemoryFile(cpputils::Data data); - - void write(const void *buf, fspp::num_bytes_t count, fspp::num_bytes_t offset); - - bool sizeUnchanged() const; - bool regionUnchanged(fspp::num_bytes_t offset, fspp::num_bytes_t count) const; - -private: - void _extendFileSizeIfNecessary(fspp::num_bytes_t size); - void _extendFileSize(fspp::num_bytes_t size); - - cpputils::Data _originalData; -}; - - -#endif diff --git a/test/fspp/testutils/OpenFileHandle.cpp b/test/fspp/testutils/OpenFileHandle.cpp deleted file mode 100644 index 875f0446..00000000 --- a/test/fspp/testutils/OpenFileHandle.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "OpenFileHandle.h" diff --git a/test/fspp/testutils/OpenFileHandle.h b/test/fspp/testutils/OpenFileHandle.h deleted file mode 100644 index 3ee24c4a..00000000 --- a/test/fspp/testutils/OpenFileHandle.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#ifndef MESSMER_FSPP_TEST_TESTUTILS_OPENFILEHANDLE_H_ -#define MESSMER_FSPP_TEST_TESTUTILS_OPENFILEHANDLE_H_ - -#include -#include -#include -#include -#include -#if defined(_MSC_VER) -#include -#else -#include -#endif - -class OpenFileHandle final { -public: - OpenFileHandle(const char *path, int flags): fd_(::open(path, flags)), errno_(fd_ >= 0 ? 0 : errno) { - } - - OpenFileHandle(const char *path, int flags, int flags2): fd_(::open(path, flags, flags2)), errno_(fd_ >= 0 ? 0 : errno) { - } - - ~OpenFileHandle() { - if (fd_ >= 0) { - ::close(fd_); -#ifdef __APPLE__ - // On Mac OS X, we might have to give it some time to free up the file - std::this_thread::sleep_for(std::chrono::milliseconds(50)); -#endif - } - } - - int fd() { return fd_; } - int errorcode() { return errno_; } - - void release() { - fd_ = -1; // don't close anymore - } - -private: - int fd_; - const int errno_; - - DISALLOW_COPY_AND_ASSIGN(OpenFileHandle); -}; - - -#endif diff --git a/test/gitversion/CMakeLists.txt b/test/gitversion/CMakeLists.txt deleted file mode 100644 index 51a5ccc1..00000000 --- a/test/gitversion/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -project (gitversion-test) - -set(SOURCES - ParserTest.cpp - VersionCompareTest.cpp -) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest gitversion) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/gitversion/ParserTest.cpp b/test/gitversion/ParserTest.cpp deleted file mode 100644 index 11a3875a..00000000 --- a/test/gitversion/ParserTest.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include -#include - -using namespace gitversion; - -TEST(ParserTest, TestUnknownVersion) { - VersionInfo info = Parser::parse("0+unknown"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("0", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestReleaseVersion_1) { - VersionInfo info = Parser::parse("0.9.2"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("2", info.hotfixVersion); - EXPECT_FALSE( info.isDevVersion); - EXPECT_TRUE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestReleaseVersion_2) { - VersionInfo info = Parser::parse("1.02.3"); - EXPECT_EQ("1", info.majorVersion); - EXPECT_EQ("02", info.minorVersion); - EXPECT_EQ("3", info.hotfixVersion); - EXPECT_FALSE( info.isDevVersion); - EXPECT_TRUE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestReleaseVersion_3) { - VersionInfo info = Parser::parse("01.020.3"); - EXPECT_EQ("01", info.majorVersion); - EXPECT_EQ("020", info.minorVersion); - EXPECT_EQ("3", info.hotfixVersion); - EXPECT_FALSE( info.isDevVersion); - EXPECT_TRUE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyReleaseVersion) { - VersionInfo info = Parser::parse("0.9.0+0.g5753e4f.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("5753e4f", info.gitCommitId); - EXPECT_EQ("", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - - -TEST(ParserTest, TestDevVersion) { - VersionInfo info = Parser::parse("0.9.0+2.g0123abcdef"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("", info.versionTag); - EXPECT_EQ(2u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyDevVersion) { - VersionInfo info = Parser::parse("0.9.0+20.g0123abcdef.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("", info.versionTag); - EXPECT_EQ(20u, info.commitsSinceTag); -} - -TEST(ParserTest, TestReleaseVersion_StableTag) { - VersionInfo info = Parser::parse("0.9.2-stable"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("2", info.hotfixVersion); - EXPECT_FALSE( info.isDevVersion); - EXPECT_TRUE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("stable", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyReleaseVersion_StableTag) { - VersionInfo info = Parser::parse("0.9.0-stable+0.g5753e4f.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("5753e4f", info.gitCommitId); - EXPECT_EQ("stable", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDevVersion_StableTag) { - VersionInfo info = Parser::parse("0.9.0-stable+2.g0123abcdef"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("stable", info.versionTag); - EXPECT_EQ(2u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyDevVersion_StableTag) { - VersionInfo info = Parser::parse("0.9.0-stable+20.g0123abcdef.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("stable", info.versionTag); - EXPECT_EQ(20u, info.commitsSinceTag); -} - -TEST(ParserTest, TestReleaseVersion_AlphaTag) { - VersionInfo info = Parser::parse("0.9.2-alpha"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("2", info.hotfixVersion); - EXPECT_FALSE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("alpha", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyReleaseVersion_AlphaTag) { - VersionInfo info = Parser::parse("0.9.0-alpha+0.g5753e4f.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("5753e4f", info.gitCommitId); - EXPECT_EQ("alpha", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDevVersion_AlphaTag) { - VersionInfo info = Parser::parse("0.9.0-alpha+2.g0123abcdef"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("alpha", info.versionTag); - EXPECT_EQ(2u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyDevVersion_AlphaTag) { - VersionInfo info = Parser::parse("0.9.0-alpha+20.g0123abcdef.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("alpha", info.versionTag); - EXPECT_EQ(20u, info.commitsSinceTag); -} - -TEST(ParserTest, TestReleaseVersion_WithoutHotfixVersion) { - VersionInfo info = Parser::parse("1.0-beta"); - EXPECT_EQ("1", info.majorVersion); - EXPECT_EQ("0", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_FALSE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("beta", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestReleaseVersion_RCTag) { - VersionInfo info = Parser::parse("0.9.2-rc1"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("2", info.hotfixVersion); - EXPECT_FALSE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("", info.gitCommitId); - EXPECT_EQ("rc1", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyReleaseVersion_RCTag) { - VersionInfo info = Parser::parse("0.9.0-rc1+0.g5753e4f.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("5753e4f", info.gitCommitId); - EXPECT_EQ("rc1", info.versionTag); - EXPECT_EQ(0u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDevVersion_RCTag) { - VersionInfo info = Parser::parse("0.9.0-rc1+2.g0123abcdef"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("rc1", info.versionTag); - EXPECT_EQ(2u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyDevVersion_RCTag) { - VersionInfo info = Parser::parse("0.9.0-rc1+20.g0123abcdef.dirty"); - EXPECT_EQ("0", info.majorVersion); - EXPECT_EQ("9", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("rc1", info.versionTag); - EXPECT_EQ(20u, info.commitsSinceTag); -} - -TEST(ParserTest, TestDirtyDevVersion_WithoutMinorVersion) { - VersionInfo info = Parser::parse("1-rc1+20.g0123abcdef.dirty"); - EXPECT_EQ("1", info.majorVersion); - EXPECT_EQ("0", info.minorVersion); - EXPECT_EQ("0", info.hotfixVersion); - EXPECT_TRUE( info.isDevVersion); - EXPECT_FALSE( info.isStableVersion); - EXPECT_EQ("0123abcdef", info.gitCommitId); - EXPECT_EQ("rc1", info.versionTag); - EXPECT_EQ(20u, info.commitsSinceTag); -} diff --git a/test/gitversion/VersionCompareTest.cpp b/test/gitversion/VersionCompareTest.cpp deleted file mode 100644 index b4d010f6..00000000 --- a/test/gitversion/VersionCompareTest.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include - -using namespace gitversion; -using std::string; - -class VersionCompareTest : public ::testing::Test { -public: - void EXPECT_IS_OLDER_THAN(const string &v1, const string &v2) { - EXPECT_TRUE(VersionCompare::isOlderThan(v1, v2)); - EXPECT_FALSE(VersionCompare::isOlderThan(v2, v1)); - } - - void EXPECT_IS_SAME_AGE(const string &v1, const string &v2) { - EXPECT_FALSE(VersionCompare::isOlderThan(v1, v2)); - EXPECT_FALSE(VersionCompare::isOlderThan(v2, v1)); - } -}; - -TEST_F(VersionCompareTest, IsDifferentVersion) { - EXPECT_IS_OLDER_THAN("0.8", "0.8.1"); - EXPECT_IS_OLDER_THAN("0.8", "1.0"); - EXPECT_IS_OLDER_THAN("0.8", "1.0.1"); - EXPECT_IS_OLDER_THAN("0.8.1", "1.0"); - EXPECT_IS_OLDER_THAN("0.7.9", "0.8.0"); - EXPECT_IS_OLDER_THAN("1.0.0", "1.0.1"); - EXPECT_IS_OLDER_THAN("1", "1.0.1"); - EXPECT_IS_OLDER_THAN("1.0.0", "1.1"); -} - -TEST_F(VersionCompareTest, IsSameVersion) { - EXPECT_IS_SAME_AGE("0.8", "0.8"); - EXPECT_IS_SAME_AGE("1.0", "1.0"); - EXPECT_IS_SAME_AGE("1", "1.0"); - EXPECT_IS_SAME_AGE("1.0.0", "1.0.0"); - EXPECT_IS_SAME_AGE("0.8", "0.8.0"); - EXPECT_IS_SAME_AGE("1", "1.0.0.0"); -} - -TEST_F(VersionCompareTest, ZeroPrefix) { - EXPECT_IS_OLDER_THAN("1.00.0", "1.0.01"); - EXPECT_IS_SAME_AGE("1.0.01", "1.0.1"); - EXPECT_IS_SAME_AGE("01.0.01", "1.0.1"); -} - -TEST_F(VersionCompareTest, VersionTags) { - EXPECT_IS_OLDER_THAN("0.9.3-alpha", "0.9.3-beta"); - EXPECT_IS_OLDER_THAN("1.0-beta", "1.0-rc1"); - EXPECT_IS_OLDER_THAN("1.0-rc1", "1.0-rc2"); - EXPECT_IS_OLDER_THAN("1.0-rc2", "1.0"); - EXPECT_IS_OLDER_THAN("0.9.5", "0.10-m1"); - EXPECT_IS_OLDER_THAN("0.10-m1", "0.10.0"); - EXPECT_IS_OLDER_THAN("1.0-alpha", "1.0"); - EXPECT_IS_SAME_AGE("0.9.3-alpha", "0.9.3-alpha"); - EXPECT_IS_SAME_AGE("1-beta", "1-beta"); - EXPECT_IS_SAME_AGE("0.9.3-rc1", "0.9.3-rc1"); -} - -TEST_F(VersionCompareTest, DevVersions) { - EXPECT_IS_OLDER_THAN("0.8", "0.8.1+1.g1234"); - EXPECT_IS_OLDER_THAN("0.8.1", "0.8.2+1.g1234"); - EXPECT_IS_OLDER_THAN("0.8.1+1.g1234", "0.8.2"); - EXPECT_IS_OLDER_THAN("0.8+1.g1234", "0.8.1"); - EXPECT_IS_OLDER_THAN("0.8+1.g1234", "0.9"); - EXPECT_IS_OLDER_THAN("0.9+1.g1234", "0.9+2.g1234"); - EXPECT_IS_SAME_AGE("0.9.1+1.g1234", "0.9.1+1.g3456"); - EXPECT_IS_SAME_AGE("0.9.1+5.g1234", "0.9.1+5.g2345.dirty"); -} - -TEST_F(VersionCompareTest, DevVersions_VersionTags) { - EXPECT_IS_OLDER_THAN("0.9.3-alpha+3.gabcd", "0.9.3-alpha+4.gabcd"); - EXPECT_IS_OLDER_THAN("0.9.3-alpha+5.gabcd", "0.9.3-beta"); - EXPECT_IS_OLDER_THAN("0.9.3-alpha+5.gabcd", "0.9.3-beta+1.gabcd"); - EXPECT_IS_OLDER_THAN("0.9.3-alpha+5.gabcd", "1+0.gabcd.dirty"); - EXPECT_IS_OLDER_THAN("0.9.3-alpha+5.gabcd", "1"); - EXPECT_IS_SAME_AGE("0.9.3-alpha+3.gabcd", "0.9.3-alpha+3.gabcd"); -} diff --git a/test/my-gtest-main/CMakeLists.txt b/test/my-gtest-main/CMakeLists.txt deleted file mode 100644 index 1d1e7e08..00000000 --- a/test/my-gtest-main/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -project (my-gtest-main) - -set(SOURCES - my-gtest-main.cpp -) - -add_library(${PROJECT_NAME} STATIC ${SOURCES}) -target_link_libraries(${PROJECT_NAME} PUBLIC googletest cpp-utils) -target_add_boost(${PROJECT_NAME} filesystem system) -target_include_directories(${PROJECT_NAME} PUBLIC .) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/my-gtest-main/my-gtest-main.cpp b/test/my-gtest-main/my-gtest-main.cpp deleted file mode 100644 index 91d2d942..00000000 --- a/test/my-gtest-main/my-gtest-main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "my-gtest-main.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include -#include - -namespace { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - boost::optional executable; -} - -const boost::filesystem::path& get_executable() { - ASSERT(executable != boost::none, "Executable path not set"); - return *executable; -} - - -int main(int argc, char** argv) { - executable = boost::filesystem::path(argv[0]); - - // Since Google Mock depends on Google Test, InitGoogleMock() is - // also responsible for initializing Google Test. Therefore there's - // no need for calling testing::InitGoogleTest() separately. - testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/my-gtest-main/my-gtest-main.h b/test/my-gtest-main/my-gtest-main.h deleted file mode 100644 index d77b379f..00000000 --- a/test/my-gtest-main/my-gtest-main.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -const boost::filesystem::path& get_executable(); diff --git a/test/parallelaccessstore/CMakeLists.txt b/test/parallelaccessstore/CMakeLists.txt deleted file mode 100644 index 16170d17..00000000 --- a/test/parallelaccessstore/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -project (parallelaccessstore-test) - -set(SOURCES - ParallelAccessBaseStoreTest.cpp - DummyTest.cpp -) - -add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(${PROJECT_NAME} my-gtest-main googletest parallelaccessstore) -add_test(${PROJECT_NAME} ${PROJECT_NAME}) - -target_enable_style_warnings(${PROJECT_NAME}) -target_activate_cpp14(${PROJECT_NAME}) diff --git a/test/parallelaccessstore/DummyTest.cpp b/test/parallelaccessstore/DummyTest.cpp deleted file mode 100644 index bafa57e5..00000000 --- a/test/parallelaccessstore/DummyTest.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -TEST(Dummy, DummyTest) { -} - diff --git a/test/parallelaccessstore/ParallelAccessBaseStoreTest.cpp b/test/parallelaccessstore/ParallelAccessBaseStoreTest.cpp deleted file mode 100644 index 2766b1d7..00000000 --- a/test/parallelaccessstore/ParallelAccessBaseStoreTest.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "parallelaccessstore/ParallelAccessBaseStore.h" - -// Test that ParallelAccessBaseStore.h can be included without errors diff --git a/vendor/googletest/CMakeLists.txt b/vendor/googletest/CMakeLists.txt deleted file mode 100644 index 223ff45f..00000000 --- a/vendor/googletest/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -include(CTest) - -if (BUILD_TESTING) - # Fix how gtest links the C library on windows, see https://github.com/google/googletest/blob/4e4df226fc197c0dda6e37f5c8c3845ca1e73a49/googletest/README.md - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - set(INSTALL_GTEST off CACHE BOOL "" FORCE) - set(INSTALL_GMOCK off CACHE BOOL "" FORCE) - add_subdirectory(gtest EXCLUDE_FROM_ALL) - - add_library(googletest INTERFACE) - target_link_libraries(googletest INTERFACE gtest gmock) - target_include_directories(googletest SYSTEM INTERFACE ${gtest_INCLUDE_DIRS}/include SYSTEM INTERFACE ${gmock_INCLUDE_DIRS}/include) -endif() diff --git a/vendor/googletest/gtest/.clang-format b/vendor/googletest/gtest/.clang-format deleted file mode 100644 index 5b9bfe6d..00000000 --- a/vendor/googletest/gtest/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ -# Run manually to reformat a file: -# clang-format -i --style=file -Language: Cpp -BasedOnStyle: Google diff --git a/vendor/googletest/gtest/.gitignore b/vendor/googletest/gtest/.gitignore deleted file mode 100644 index f08cb72a..00000000 --- a/vendor/googletest/gtest/.gitignore +++ /dev/null @@ -1,84 +0,0 @@ -# Ignore CI build directory -build/ -xcuserdata -cmake-build-debug/ -.idea/ -bazel-bin -bazel-genfiles -bazel-googletest -bazel-out -bazel-testlogs -# python -*.pyc - -# Visual Studio files -.vs -*.sdf -*.opensdf -*.VC.opendb -*.suo -*.user -_ReSharper.Caches/ -Win32-Debug/ -Win32-Release/ -x64-Debug/ -x64-Release/ - -# Ignore autoconf / automake files -Makefile.in -aclocal.m4 -configure -build-aux/ -autom4te.cache/ -googletest/m4/libtool.m4 -googletest/m4/ltoptions.m4 -googletest/m4/ltsugar.m4 -googletest/m4/ltversion.m4 -googletest/m4/lt~obsolete.m4 -googlemock/m4 - -# Ignore generated directories. -googlemock/fused-src/ -googletest/fused-src/ - -# macOS files -.DS_Store -googletest/.DS_Store -googletest/xcode/.DS_Store - -# Ignore cmake generated directories and files. -CMakeFiles -CTestTestfile.cmake -Makefile -cmake_install.cmake -googlemock/CMakeFiles -googlemock/CTestTestfile.cmake -googlemock/Makefile -googlemock/cmake_install.cmake -googlemock/gtest -/bin -/googlemock/gmock.dir -/googlemock/gmock_main.dir -/googlemock/RUN_TESTS.vcxproj.filters -/googlemock/RUN_TESTS.vcxproj -/googlemock/INSTALL.vcxproj.filters -/googlemock/INSTALL.vcxproj -/googlemock/gmock_main.vcxproj.filters -/googlemock/gmock_main.vcxproj -/googlemock/gmock.vcxproj.filters -/googlemock/gmock.vcxproj -/googlemock/gmock.sln -/googlemock/ALL_BUILD.vcxproj.filters -/googlemock/ALL_BUILD.vcxproj -/lib -/Win32 -/ZERO_CHECK.vcxproj.filters -/ZERO_CHECK.vcxproj -/RUN_TESTS.vcxproj.filters -/RUN_TESTS.vcxproj -/INSTALL.vcxproj.filters -/INSTALL.vcxproj -/googletest-distribution.sln -/CMakeCache.txt -/ALL_BUILD.vcxproj.filters -/ALL_BUILD.vcxproj diff --git a/vendor/googletest/gtest/BUILD.bazel b/vendor/googletest/gtest/BUILD.bazel deleted file mode 100644 index 965c518d..00000000 --- a/vendor/googletest/gtest/BUILD.bazel +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright 2017 Google Inc. -# All Rights Reserved. -# -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Bazel Build for Google C++ Testing Framework(Google Test) - -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -exports_files(["LICENSE"]) - -config_setting( - name = "windows", - constraint_values = ["@platforms//os:windows"], -) - -config_setting( - name = "msvc_compiler", - flag_values = { - "@bazel_tools//tools/cpp:compiler": "msvc-cl", - }, - visibility = [":__subpackages__"], -) - -config_setting( - name = "has_absl", - values = {"define": "absl=1"}, -) - -# Library that defines the FRIEND_TEST macro. -cc_library( - name = "gtest_prod", - hdrs = ["googletest/include/gtest/gtest_prod.h"], - includes = ["googletest/include"], -) - -# Google Test including Google Mock -cc_library( - name = "gtest", - srcs = glob( - include = [ - "googletest/src/*.cc", - "googletest/src/*.h", - "googletest/include/gtest/**/*.h", - "googlemock/src/*.cc", - "googlemock/include/gmock/**/*.h", - ], - exclude = [ - "googletest/src/gtest-all.cc", - "googletest/src/gtest_main.cc", - "googlemock/src/gmock-all.cc", - "googlemock/src/gmock_main.cc", - ], - ), - hdrs = glob([ - "googletest/include/gtest/*.h", - "googlemock/include/gmock/*.h", - ]), - copts = select({ - ":windows": [], - "//conditions:default": ["-pthread"], - }), - defines = select({ - ":has_absl": ["GTEST_HAS_ABSL=1"], - "//conditions:default": [], - }), - features = select({ - ":windows": ["windows_export_all_symbols"], - "//conditions:default": [], - }), - includes = [ - "googlemock", - "googlemock/include", - "googletest", - "googletest/include", - ], - linkopts = select({ - ":windows": [], - "//conditions:default": ["-pthread"], - }), - deps = select({ - ":has_absl": [ - "@com_google_absl//absl/debugging:failure_signal_handler", - "@com_google_absl//absl/debugging:stacktrace", - "@com_google_absl//absl/debugging:symbolize", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:any", - "@com_google_absl//absl/types:optional", - "@com_google_absl//absl/types:variant", - ], - "//conditions:default": [], - }), -) - -cc_library( - name = "gtest_main", - srcs = ["googlemock/src/gmock_main.cc"], - features = select({ - ":windows": ["windows_export_all_symbols"], - "//conditions:default": [], - }), - deps = [":gtest"], -) - -# The following rules build samples of how to use gTest. -cc_library( - name = "gtest_sample_lib", - srcs = [ - "googletest/samples/sample1.cc", - "googletest/samples/sample2.cc", - "googletest/samples/sample4.cc", - ], - hdrs = [ - "googletest/samples/prime_tables.h", - "googletest/samples/sample1.h", - "googletest/samples/sample2.h", - "googletest/samples/sample3-inl.h", - "googletest/samples/sample4.h", - ], - features = select({ - ":windows": ["windows_export_all_symbols"], - "//conditions:default": [], - }), -) - -cc_test( - name = "gtest_samples", - size = "small", - # All Samples except: - # sample9 (main) - # sample10 (main and takes a command line option and needs to be separate) - srcs = [ - "googletest/samples/sample1_unittest.cc", - "googletest/samples/sample2_unittest.cc", - "googletest/samples/sample3_unittest.cc", - "googletest/samples/sample4_unittest.cc", - "googletest/samples/sample5_unittest.cc", - "googletest/samples/sample6_unittest.cc", - "googletest/samples/sample7_unittest.cc", - "googletest/samples/sample8_unittest.cc", - ], - linkstatic = 0, - deps = [ - "gtest_sample_lib", - ":gtest_main", - ], -) - -cc_test( - name = "sample9_unittest", - size = "small", - srcs = ["googletest/samples/sample9_unittest.cc"], - deps = [":gtest"], -) - -cc_test( - name = "sample10_unittest", - size = "small", - srcs = ["googletest/samples/sample10_unittest.cc"], - deps = [":gtest"], -) diff --git a/vendor/googletest/gtest/CMakeLists.txt b/vendor/googletest/gtest/CMakeLists.txt deleted file mode 100644 index 12fd7450..00000000 --- a/vendor/googletest/gtest/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Note: CMake support is community-based. The maintainers do not use CMake -# internally. - -cmake_minimum_required(VERSION 2.8.12) - -if (POLICY CMP0048) - cmake_policy(SET CMP0048 NEW) -endif (POLICY CMP0048) - -project(googletest-distribution) -set(GOOGLETEST_VERSION 1.10.0) - -if (CMAKE_VERSION VERSION_GREATER "3.0.2") - if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX) - set(CMAKE_CXX_EXTENSIONS OFF) - endif() -endif() - -enable_testing() - -include(CMakeDependentOption) -include(GNUInstallDirs) - -#Note that googlemock target already builds googletest -option(BUILD_GMOCK "Builds the googlemock subproject" ON) -option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON) - -if(BUILD_GMOCK) - add_subdirectory( googlemock ) -else() - add_subdirectory( googletest ) -endif() diff --git a/vendor/googletest/gtest/CONTRIBUTING.md b/vendor/googletest/gtest/CONTRIBUTING.md deleted file mode 100644 index da45e445..00000000 --- a/vendor/googletest/gtest/CONTRIBUTING.md +++ /dev/null @@ -1,130 +0,0 @@ -# How to become a contributor and submit your own code - -## Contributor License Agreements - -We'd love to accept your patches! Before we can take them, we have to jump a -couple of legal hurdles. - -Please fill out either the individual or corporate Contributor License Agreement -(CLA). - -* If you are an individual writing original source code and you're sure you - own the intellectual property, then you'll need to sign an - [individual CLA](https://developers.google.com/open-source/cla/individual). -* If you work for a company that wants to allow you to contribute your work, - then you'll need to sign a - [corporate CLA](https://developers.google.com/open-source/cla/corporate). - -Follow either of the two links above to access the appropriate CLA and -instructions for how to sign and return it. Once we receive it, we'll be able to -accept your pull requests. - -## Are you a Googler? - -If you are a Googler, please make an attempt to submit an internal change rather -than a GitHub Pull Request. If you are not able to submit an internal change a -PR is acceptable as an alternative. - -## Contributing A Patch - -1. Submit an issue describing your proposed change to the - [issue tracker](https://github.com/google/googletest/issues). -2. Please don't mix more than one logical change per submittal, because it - makes the history hard to follow. If you want to make a change that doesn't - have a corresponding issue in the issue tracker, please create one. -3. Also, coordinate with team members that are listed on the issue in question. - This ensures that work isn't being duplicated and communicating your plan - early also generally leads to better patches. -4. If your proposed change is accepted, and you haven't already done so, sign a - Contributor License Agreement (see details above). -5. Fork the desired repo, develop and test your code changes. -6. Ensure that your code adheres to the existing style in the sample to which - you are contributing. -7. Ensure that your code has an appropriate set of unit tests which all pass. -8. Submit a pull request. - -## The Google Test and Google Mock Communities - -The Google Test community exists primarily through the -[discussion group](http://groups.google.com/group/googletestframework) and the -GitHub repository. Likewise, the Google Mock community exists primarily through -their own [discussion group](http://groups.google.com/group/googlemock). You are -definitely encouraged to contribute to the discussion and you can also help us -to keep the effectiveness of the group high by following and promoting the -guidelines listed here. - -### Please Be Friendly - -Showing courtesy and respect to others is a vital part of the Google culture, -and we strongly encourage everyone participating in Google Test development to -join us in accepting nothing less. Of course, being courteous is not the same as -failing to constructively disagree with each other, but it does mean that we -should be respectful of each other when enumerating the 42 technical reasons -that a particular proposal may not be the best choice. There's never a reason to -be antagonistic or dismissive toward anyone who is sincerely trying to -contribute to a discussion. - -Sure, C++ testing is serious business and all that, but it's also a lot of fun. -Let's keep it that way. Let's strive to be one of the friendliest communities in -all of open source. - -As always, discuss Google Test in the official GoogleTest discussion group. You -don't have to actually submit code in order to sign up. Your participation -itself is a valuable contribution. - -## Style - -To keep the source consistent, readable, diffable and easy to merge, we use a -fairly rigid coding style, as defined by the -[google-styleguide](https://github.com/google/styleguide) project. All patches -will be expected to conform to the style outlined -[here](https://google.github.io/styleguide/cppguide.html). Use -[.clang-format](https://github.com/google/googletest/blob/master/.clang-format) -to check your formatting. - -## Requirements for Contributors - -If you plan to contribute a patch, you need to build Google Test, Google Mock, -and their own tests from a git checkout, which has further requirements: - -* [Python](https://www.python.org/) v2.3 or newer (for running some of the - tests and re-generating certain source files from templates) -* [CMake](https://cmake.org/) v2.8.12 or newer - -## Developing Google Test and Google Mock - -This section discusses how to make your own changes to the Google Test project. - -### Testing Google Test and Google Mock Themselves - -To make sure your changes work as intended and don't break existing -functionality, you'll want to compile and run Google Test and GoogleMock's own -tests. For that you can use CMake: - - mkdir mybuild - cd mybuild - cmake -Dgtest_build_tests=ON -Dgmock_build_tests=ON ${GTEST_REPO_DIR} - -To choose between building only Google Test or Google Mock, you may modify your -cmake command to be one of each - - cmake -Dgtest_build_tests=ON ${GTEST_DIR} # sets up Google Test tests - cmake -Dgmock_build_tests=ON ${GMOCK_DIR} # sets up Google Mock tests - -Make sure you have Python installed, as some of Google Test's tests are written -in Python. If the cmake command complains about not being able to find Python -(`Could NOT find PythonInterp (missing: PYTHON_EXECUTABLE)`), try telling it -explicitly where your Python executable can be found: - - cmake -DPYTHON_EXECUTABLE=path/to/python ... - -Next, you can build Google Test and / or Google Mock and all desired tests. On -\*nix, this is usually done by - - make - -To run the tests, do - - make test - -All tests should pass. diff --git a/vendor/googletest/gtest/CONTRIBUTORS b/vendor/googletest/gtest/CONTRIBUTORS deleted file mode 100644 index 76db0b40..00000000 --- a/vendor/googletest/gtest/CONTRIBUTORS +++ /dev/null @@ -1,63 +0,0 @@ -# This file contains a list of people who've made non-trivial -# contribution to the Google C++ Testing Framework project. People -# who commit code to the project are encouraged to add their names -# here. Please keep the list sorted by first names. - -Ajay Joshi -Balázs Dán -Benoit Sigoure -Bharat Mediratta -Bogdan Piloca -Chandler Carruth -Chris Prince -Chris Taylor -Dan Egnor -Dave MacLachlan -David Anderson -Dean Sturtevant -Eric Roman -Gene Volovich -Hady Zalek -Hal Burch -Jeffrey Yasskin -Jim Keller -Joe Walnes -Jon Wray -Jói Sigurðsson -Keir Mierle -Keith Ray -Kenton Varda -Kostya Serebryany -Krystian Kuzniarek -Lev Makhlis -Manuel Klimek -Mario Tanev -Mark Paskin -Markus Heule -Matthew Simmons -Mika Raento -Mike Bland -Miklós Fazekas -Neal Norwitz -Nermin Ozkiranartli -Owen Carlsen -Paneendra Ba -Pasi Valminen -Patrick Hanna -Patrick Riley -Paul Menage -Peter Kaminski -Piotr Kaminski -Preston Jackson -Rainer Klaffenboeck -Russ Cox -Russ Rufer -Sean Mcafee -Sigurður Ásgeirsson -Sverre Sundsdal -Takeshi Yoshino -Tracy Bialik -Vadim Berman -Vlad Losev -Wolfgang Klier -Zhanyong Wan diff --git a/vendor/googletest/gtest/LICENSE b/vendor/googletest/gtest/LICENSE deleted file mode 100644 index 1941a11f..00000000 --- a/vendor/googletest/gtest/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2008, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/googletest/gtest/README.md b/vendor/googletest/gtest/README.md deleted file mode 100644 index 7d872a57..00000000 --- a/vendor/googletest/gtest/README.md +++ /dev/null @@ -1,140 +0,0 @@ -# GoogleTest - -### Announcements - -#### Live at Head - -GoogleTest now follows the -[Abseil Live at Head philosophy](https://abseil.io/about/philosophy#upgrade-support). -We recommend using the latest commit in the `master` branch in your projects. - -#### Documentation Updates - -Our documentation is now live on GitHub Pages at -https://google.github.io/googletest/. We recommend browsing the documentation on -GitHub Pages rather than directly in the repository. - -#### Release 1.10.x - -[Release 1.10.x](https://github.com/google/googletest/releases/tag/release-1.10.0) -is now available. - -#### Coming Soon - -* We are planning to take a dependency on - [Abseil](https://github.com/abseil/abseil-cpp). -* More documentation improvements are planned. - -## Welcome to **GoogleTest**, Google's C++ test framework! - -This repository is a merger of the formerly separate GoogleTest and GoogleMock -projects. These were so closely related that it makes sense to maintain and -release them together. - -### Getting Started - -See the [GoogleTest User's Guide](https://google.github.io/googletest/) for -documentation. We recommend starting with the -[GoogleTest Primer](https://google.github.io/googletest/primer.html). - -More information about building GoogleTest can be found at -[googletest/README.md](googletest/README.md). - -## Features - -* An [xUnit](https://en.wikipedia.org/wiki/XUnit) test framework. -* Test discovery. -* A rich set of assertions. -* User-defined assertions. -* Death tests. -* Fatal and non-fatal failures. -* Value-parameterized tests. -* Type-parameterized tests. -* Various options for running the tests. -* XML test report generation. - -## Supported Platforms - -GoogleTest requires a codebase and compiler compliant with the C++11 standard or -newer. - -The GoogleTest code is officially supported on the following platforms. -Operating systems or tools not listed below are community-supported. For -community-supported platforms, patches that do not complicate the code may be -considered. - -If you notice any problems on your platform, please file an issue on the -[GoogleTest GitHub Issue Tracker](https://github.com/google/googletest/issues). -Pull requests containing fixes are welcome! - -### Operating Systems - -* Linux -* macOS -* Windows - -### Compilers - -* gcc 5.0+ -* clang 5.0+ -* MSVC 2015+ - -**macOS users:** Xcode 9.3+ provides clang 5.0+. - -### Build Systems - -* [Bazel](https://bazel.build/) -* [CMake](https://cmake.org/) - -**Note:** Bazel is the build system used by the team internally and in tests. -CMake is supported on a best-effort basis and by the community. - -## Who Is Using GoogleTest? - -In addition to many internal projects at Google, GoogleTest is also used by the -following notable projects: - -* The [Chromium projects](http://www.chromium.org/) (behind the Chrome browser - and Chrome OS). -* The [LLVM](http://llvm.org/) compiler. -* [Protocol Buffers](https://github.com/google/protobuf), Google's data - interchange format. -* The [OpenCV](http://opencv.org/) computer vision library. - -## Related Open Source Projects - -[GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based -automated test-runner and Graphical User Interface with powerful features for -Windows and Linux platforms. - -[GoogleTest UI](https://github.com/ospector/gtest-gbar) is a test runner that -runs your test binary, allows you to track its progress via a progress bar, and -displays a list of test failures. Clicking on one shows failure text. Google -Test UI is written in C#. - -[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event -listener for GoogleTest that implements the -[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test -result output. If your test runner understands TAP, you may find it useful. - -[gtest-parallel](https://github.com/google/gtest-parallel) is a test runner that -runs tests from your binary in parallel to provide significant speed-up. - -[GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter) -is a VS Code extension allowing to view GoogleTest in a tree view, and run/debug -your tests. - -[C++ TestMate](https://github.com/matepek/vscode-catch2-test-adapter) is a VS -Code extension allowing to view GoogleTest in a tree view, and run/debug your -tests. - -[Cornichon](https://pypi.org/project/cornichon/) is a small Gherkin DSL parser -that generates stub code for GoogleTest. - -## Contributing Changes - -Please read -[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/master/CONTRIBUTING.md) -for details on how to contribute to this project. - -Happy testing! diff --git a/vendor/googletest/gtest/WORKSPACE b/vendor/googletest/gtest/WORKSPACE deleted file mode 100644 index 3b445173..00000000 --- a/vendor/googletest/gtest/WORKSPACE +++ /dev/null @@ -1,30 +0,0 @@ -workspace(name = "com_google_googletest") - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -http_archive( - name = "com_google_absl", # 2020-10-13T16:49:13Z - sha256 = "00c3707bf9cd5eabd1ec6932cc65b97378c043f22573be3adf7d11bb7af17d06", - strip_prefix = "abseil-cpp-f3f785ab59478dd0312bf1b5df65d380650bf0dc", - urls = [ - "https://github.com/abseil/abseil-cpp/archive/f3f785ab59478dd0312bf1b5df65d380650bf0dc.zip", - ], -) - -http_archive( - name = "rules_cc", # 2020-10-05T06:01:24Z - sha256 = "35ea62c63cd71d4000efe85f9f4f17e8afb23896c37ee9510952db2e9d8fbb70", - strip_prefix = "rules_cc-f055da4ff0cb2b3c73de1fe2f094ebdfb8b3acb9", - urls = [ - "https://github.com/bazelbuild/rules_cc/archive/f055da4ff0cb2b3c73de1fe2f094ebdfb8b3acb9.zip", - ], -) - -http_archive( - name = "rules_python", # 2020-09-30T13:50:21Z - sha256 = "6e49996ad3cf45b2232b8f94ca1e3ead369c28394c51632be8d85fe826383012", - strip_prefix = "rules_python-c064f7008a30f307ea7516cf52358a653011f82b", - urls = [ - "https://github.com/bazelbuild/rules_python/archive/c064f7008a30f307ea7516cf52358a653011f82b.zip", - ], -) diff --git a/vendor/googletest/gtest/ci/linux-presubmit.sh b/vendor/googletest/gtest/ci/linux-presubmit.sh deleted file mode 100644 index d02130c3..00000000 --- a/vendor/googletest/gtest/ci/linux-presubmit.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/bash -# -# Copyright 2020, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -euox pipefail - -readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008" -readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20201015" - -if [[ -z ${GTEST_ROOT:-} ]]; then - GTEST_ROOT="$(realpath $(dirname ${0})/..)" -fi - -if [[ -z ${STD:-} ]]; then - STD="c++11 c++14 c++17 c++20" -fi - -# Test the CMake build -for cc in /usr/local/bin/gcc /opt/llvm/clang/bin/clang; do - for cmake_off_on in OFF ON; do - time docker run \ - --volume="${GTEST_ROOT}:/src:ro" \ - --tmpfs="/build:exec" \ - --workdir="/build" \ - --rm \ - --env="CC=${cc}" \ - --env="CXX_FLAGS=\"-Werror -Wdeprecated\"" \ - ${LINUX_LATEST_CONTAINER} \ - /bin/bash -c " - cmake /src \ - -DCMAKE_CXX_STANDARD=11 \ - -Dgtest_build_samples=ON \ - -Dgtest_build_tests=ON \ - -Dgmock_build_tests=ON \ - -Dcxx_no_exception=${cmake_off_on} \ - -Dcxx_no_rtti=${cmake_off_on} && \ - make -j$(nproc) && \ - ctest -j$(nproc) --output-on-failure" - done -done - -# Do one test with an older version of GCC -time docker run \ - --volume="${GTEST_ROOT}:/src:ro" \ - --workdir="/src" \ - --rm \ - --env="CC=/usr/local/bin/gcc" \ - ${LINUX_GCC_FLOOR_CONTAINER} \ - /usr/local/bin/bazel test ... \ - --copt="-Wall" \ - --copt="-Werror" \ - --copt="-Wno-error=pragmas" \ - --keep_going \ - --show_timestamps \ - --test_output=errors - -# Test GCC -for std in ${STD}; do - for absl in 0 1; do - time docker run \ - --volume="${GTEST_ROOT}:/src:ro" \ - --workdir="/src" \ - --rm \ - --env="CC=/usr/local/bin/gcc" \ - --env="BAZEL_CXXOPTS=-std=${std}" \ - ${LINUX_LATEST_CONTAINER} \ - /usr/local/bin/bazel test ... \ - --copt="-Wall" \ - --copt="-Werror" \ - --define="absl=${absl}" \ - --keep_going \ - --show_timestamps \ - --test_output=errors - done -done - -# Test Clang -for std in ${STD}; do - for absl in 0 1; do - time docker run \ - --volume="${GTEST_ROOT}:/src:ro" \ - --workdir="/src" \ - --rm \ - --env="CC=/opt/llvm/clang/bin/clang" \ - --env="BAZEL_CXXOPTS=-std=${std}" \ - ${LINUX_LATEST_CONTAINER} \ - /usr/local/bin/bazel test ... \ - --copt="--gcc-toolchain=/usr/local" \ - --copt="-Wall" \ - --copt="-Werror" \ - --define="absl=${absl}" \ - --keep_going \ - --linkopt="--gcc-toolchain=/usr/local" \ - --show_timestamps \ - --test_output=errors - done -done diff --git a/vendor/googletest/gtest/ci/macos-presubmit.sh b/vendor/googletest/gtest/ci/macos-presubmit.sh deleted file mode 100644 index d6423faa..00000000 --- a/vendor/googletest/gtest/ci/macos-presubmit.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# -# Copyright 2020, Google Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -euox pipefail - -if [[ -z ${GTEST_ROOT:-} ]]; then - GTEST_ROOT="$(realpath $(dirname ${0})/..)" -fi - -# Test the CMake build -for cmake_off_on in OFF ON; do - BUILD_DIR=$(mktemp -d build_dir.XXXXXXXX) - cd ${BUILD_DIR} - time cmake ${GTEST_ROOT} \ - -DCMAKE_CXX_STANDARD=11 \ - -Dgtest_build_samples=ON \ - -Dgtest_build_tests=ON \ - -Dgmock_build_tests=ON \ - -Dcxx_no_exception=${cmake_off_on} \ - -Dcxx_no_rtti=${cmake_off_on} - time make - time ctest -j$(nproc) --output-on-failure -done - -# Test the Bazel build - -# If we are running on Kokoro, check for a versioned Bazel binary. -KOKORO_GFILE_BAZEL_BIN="bazel-3.7.0-darwin-x86_64" -if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then - BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}" - chmod +x ${BAZEL_BIN} -else - BAZEL_BIN="bazel" -fi - -cd ${GTEST_ROOT} -for absl in 0 1; do - ${BAZEL_BIN} test ... \ - --copt="-Wall" \ - --copt="-Werror" \ - --define="absl=${absl}" \ - --keep_going \ - --show_timestamps \ - --test_output=errors -done diff --git a/vendor/googletest/gtest/docs/_config.yml b/vendor/googletest/gtest/docs/_config.yml deleted file mode 100644 index d12867ea..00000000 --- a/vendor/googletest/gtest/docs/_config.yml +++ /dev/null @@ -1 +0,0 @@ -title: GoogleTest diff --git a/vendor/googletest/gtest/docs/_data/navigation.yml b/vendor/googletest/gtest/docs/_data/navigation.yml deleted file mode 100644 index 355ebc8e..00000000 --- a/vendor/googletest/gtest/docs/_data/navigation.yml +++ /dev/null @@ -1,33 +0,0 @@ -nav: -- section: "Get Started" - items: - - title: "Supported Platforms" - url: "/platforms.html" - - title: "Quickstart: Bazel" - url: "/quickstart-bazel.html" - - title: "Quickstart: CMake" - url: "/quickstart-cmake.html" -- section: "Guides" - items: - - title: "GoogleTest Primer" - url: "/primer.html" - - title: "Advanced Topics" - url: "/advanced.html" - - title: "Mocking for Dummies" - url: "/gmock_for_dummies.html" - - title: "Mocking Cookbook" - url: "/gmock_cook_book.html" - - title: "Mocking Cheat Sheet" - url: "/gmock_cheat_sheet.html" -- section: "References" - items: - - title: "Testing FAQ" - url: "/faq.html" - - title: "Mocking FAQ" - url: "/gmock_faq.html" - - title: "Code Samples" - url: "/samples.html" - - title: "Using pkg-config" - url: "/pkgconfig.html" - - title: "Community Documentation" - url: "/community_created_documentation.html" diff --git a/vendor/googletest/gtest/docs/_layouts/default.html b/vendor/googletest/gtest/docs/_layouts/default.html deleted file mode 100644 index 731042f1..00000000 --- a/vendor/googletest/gtest/docs/_layouts/default.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - -{% seo %} - - - - -
-
- {{ content }} -
-
- - - {% if site.google_analytics %} - - {% endif %} - - diff --git a/vendor/googletest/gtest/docs/_sass/main.scss b/vendor/googletest/gtest/docs/_sass/main.scss deleted file mode 100644 index 91e633bb..00000000 --- a/vendor/googletest/gtest/docs/_sass/main.scss +++ /dev/null @@ -1,193 +0,0 @@ -// Styles for GoogleTest docs website on GitHub Pages. -// Color variables are defined in -// https://github.com/pages-themes/primer/tree/master/_sass/primer-support/lib/variables - -$sidebar-width: 260px; - -body { - display: flex; - margin: 0; -} - -.sidebar { - background: $black; - color: $text-white; - flex-shrink: 0; - height: 100vh; - overflow: auto; - position: sticky; - top: 0; - width: $sidebar-width; -} - -.sidebar h1 { - font-size: 1.5em; -} - -.sidebar h2 { - color: $gray-light; - font-size: 0.8em; - font-weight: normal; - margin-bottom: 0.8em; - padding-left: 2.5em; - text-transform: uppercase; -} - -.sidebar .header { - background: $black; - padding: 2em; - position: sticky; - top: 0; - width: 100%; -} - -.sidebar .header a { - color: $text-white; - text-decoration: none; -} - -.sidebar .nav-toggle { - display: none; -} - -.sidebar .expander { - cursor: pointer; - display: none; - height: 3em; - position: absolute; - right: 1em; - top: 1.5em; - width: 3em; -} - -.sidebar .expander .arrow { - border: solid white; - border-width: 0 3px 3px 0; - display: block; - height: 0.7em; - margin: 1em auto; - transform: rotate(45deg); - transition: transform 0.5s; - width: 0.7em; -} - -.sidebar nav { - width: 100%; -} - -.sidebar nav ul { - list-style-type: none; - margin-bottom: 1em; - padding: 0; - - &:last-child { - margin-bottom: 2em; - } - - a { - text-decoration: none; - } - - li { - color: $text-white; - padding-left: 2em; - text-decoration: none; - } - - li.active { - background: $border-gray-darker; - font-weight: bold; - } - - li:hover { - background: $border-gray-darker; - } -} - -.main { - width: calc(100% - #{$sidebar-width}); -} - -.main .main-inner { - margin: 2em; -} - -.main table th { - text-align: left; -} - -.main .callout { - border-left: 0.25em solid white; - padding: 1em; - - a { - text-decoration: underline; - } - - &.important { - background-color: $bg-yellow-light; - border-color: $bg-yellow; - color: $black; - } - - &.note { - background-color: $bg-blue-light; - border-color: $text-blue; - color: $text-blue; - } - - &.tip { - background-color: $green-000; - border-color: $green-700; - color: $green-700; - } - - &.warning { - background-color: $red-000; - border-color: $text-red; - color: $text-red; - } -} - -.main .good pre { - background-color: $bg-green-light; -} - -.main .bad pre { - background-color: $red-000; -} - -@media all and (max-width: 768px) { - body { - flex-direction: column; - } - - .sidebar { - height: auto; - position: relative; - width: 100%; - } - - .sidebar .expander { - display: block; - } - - .sidebar nav { - height: 0; - overflow: hidden; - } - - .sidebar .nav-toggle:checked { - & ~ nav { - height: auto; - } - - & + .expander .arrow { - transform: rotate(-135deg); - } - } - - .main { - width: 100%; - } -} diff --git a/vendor/googletest/gtest/docs/advanced.md b/vendor/googletest/gtest/docs/advanced.md deleted file mode 100644 index ae4d7ee8..00000000 --- a/vendor/googletest/gtest/docs/advanced.md +++ /dev/null @@ -1,2635 +0,0 @@ -# Advanced googletest Topics - -## Introduction - -Now that you have read the [googletest Primer](primer.md) and learned how to -write tests using googletest, it's time to learn some new tricks. This document -will show you more assertions as well as how to construct complex failure -messages, propagate fatal failures, reuse and speed up your test fixtures, and -use various flags with your tests. - -## More Assertions - -This section covers some less frequently used, but still significant, -assertions. - -### Explicit Success and Failure - -These three assertions do not actually test a value or expression. Instead, they -generate a success or failure directly. Like the macros that actually perform a -test, you may stream a custom failure message into them. - -```c++ -SUCCEED(); -``` - -Generates a success. This does **NOT** make the overall test succeed. A test is -considered successful only if none of its assertions fail during its execution. - -{: .callout .note} -NOTE: `SUCCEED()` is purely documentary and currently doesn't generate any -user-visible output. However, we may add `SUCCEED()` messages to googletest's -output in the future. - -```c++ -FAIL(); -ADD_FAILURE(); -ADD_FAILURE_AT("file_path", line_number); -``` - -`FAIL()` generates a fatal failure, while `ADD_FAILURE()` and `ADD_FAILURE_AT()` -generate a nonfatal failure. These are useful when control flow, rather than a -Boolean expression, determines the test's success or failure. For example, you -might want to write something like: - -```c++ -switch(expression) { - case 1: - ... some checks ... - case 2: - ... some other checks ... - default: - FAIL() << "We shouldn't get here."; -} -``` - -{: .callout .note} -NOTE: you can only use `FAIL()` in functions that return `void`. See the -[Assertion Placement section](#assertion-placement) for more information. - -### Exception Assertions - -These are for verifying that a piece of code throws (or does not throw) an -exception of the given type: - -Fatal assertion | Nonfatal assertion | Verifies ------------------------------------------- | ------------------------------------------ | -------- -`ASSERT_THROW(statement, exception_type);` | `EXPECT_THROW(statement, exception_type);` | `statement` throws an exception of the given type -`ASSERT_ANY_THROW(statement);` | `EXPECT_ANY_THROW(statement);` | `statement` throws an exception of any type -`ASSERT_NO_THROW(statement);` | `EXPECT_NO_THROW(statement);` | `statement` doesn't throw any exception - -Examples: - -```c++ -ASSERT_THROW(Foo(5), bar_exception); - -EXPECT_NO_THROW({ - int n = 5; - Bar(&n); -}); -``` - -**Availability**: requires exceptions to be enabled in the build environment - -### Predicate Assertions for Better Error Messages - -Even though googletest has a rich set of assertions, they can never be complete, -as it's impossible (nor a good idea) to anticipate all scenarios a user might -run into. Therefore, sometimes a user has to use `EXPECT_TRUE()` to check a -complex expression, for lack of a better macro. This has the problem of not -showing you the values of the parts of the expression, making it hard to -understand what went wrong. As a workaround, some users choose to construct the -failure message by themselves, streaming it into `EXPECT_TRUE()`. However, this -is awkward especially when the expression has side-effects or is expensive to -evaluate. - -googletest gives you three different options to solve this problem: - -#### Using an Existing Boolean Function - -If you already have a function or functor that returns `bool` (or a type that -can be implicitly converted to `bool`), you can use it in a *predicate -assertion* to get the function arguments printed for free: - - -| Fatal assertion | Nonfatal assertion | Verifies | -| --------------------------------- | --------------------------------- | --------------------------- | -| `ASSERT_PRED1(pred1, val1)` | `EXPECT_PRED1(pred1, val1)` | `pred1(val1)` is true | -| `ASSERT_PRED2(pred2, val1, val2)` | `EXPECT_PRED2(pred2, val1, val2)` | `pred2(val1, val2)` is true | -| `...` | `...` | `...` | - -In the above, `predn` is an `n`-ary predicate function or functor, where `val1`, -`val2`, ..., and `valn` are its arguments. The assertion succeeds if the -predicate returns `true` when applied to the given arguments, and fails -otherwise. When the assertion fails, it prints the value of each argument. In -either case, the arguments are evaluated exactly once. - -Here's an example. Given - -```c++ -// Returns true if m and n have no common divisors except 1. -bool MutuallyPrime(int m, int n) { ... } - -const int a = 3; -const int b = 4; -const int c = 10; -``` - -the assertion - -```c++ - EXPECT_PRED2(MutuallyPrime, a, b); -``` - -will succeed, while the assertion - -```c++ - EXPECT_PRED2(MutuallyPrime, b, c); -``` - -will fail with the message - -```none -MutuallyPrime(b, c) is false, where -b is 4 -c is 10 -``` - -{: .callout .note} -> NOTE: -> -> 1. If you see a compiler error "no matching function to call" when using -> `ASSERT_PRED*` or `EXPECT_PRED*`, please see -> [this](faq.md#the-compiler-complains-no-matching-function-to-call-when-i-use-assert_pred-how-do-i-fix-it) -> for how to resolve it. - -#### Using a Function That Returns an AssertionResult - -While `EXPECT_PRED*()` and friends are handy for a quick job, the syntax is not -satisfactory: you have to use different macros for different arities, and it -feels more like Lisp than C++. The `::testing::AssertionResult` class solves -this problem. - -An `AssertionResult` object represents the result of an assertion (whether it's -a success or a failure, and an associated message). You can create an -`AssertionResult` using one of these factory functions: - -```c++ -namespace testing { - -// Returns an AssertionResult object to indicate that an assertion has -// succeeded. -AssertionResult AssertionSuccess(); - -// Returns an AssertionResult object to indicate that an assertion has -// failed. -AssertionResult AssertionFailure(); - -} -``` - -You can then use the `<<` operator to stream messages to the `AssertionResult` -object. - -To provide more readable messages in Boolean assertions (e.g. `EXPECT_TRUE()`), -write a predicate function that returns `AssertionResult` instead of `bool`. For -example, if you define `IsEven()` as: - -```c++ -testing::AssertionResult IsEven(int n) { - if ((n % 2) == 0) - return testing::AssertionSuccess(); - else - return testing::AssertionFailure() << n << " is odd"; -} -``` - -instead of: - -```c++ -bool IsEven(int n) { - return (n % 2) == 0; -} -``` - -the failed assertion `EXPECT_TRUE(IsEven(Fib(4)))` will print: - -```none -Value of: IsEven(Fib(4)) - Actual: false (3 is odd) -Expected: true -``` - -instead of a more opaque - -```none -Value of: IsEven(Fib(4)) - Actual: false -Expected: true -``` - -If you want informative messages in `EXPECT_FALSE` and `ASSERT_FALSE` as well -(one third of Boolean assertions in the Google code base are negative ones), and -are fine with making the predicate slower in the success case, you can supply a -success message: - -```c++ -testing::AssertionResult IsEven(int n) { - if ((n % 2) == 0) - return testing::AssertionSuccess() << n << " is even"; - else - return testing::AssertionFailure() << n << " is odd"; -} -``` - -Then the statement `EXPECT_FALSE(IsEven(Fib(6)))` will print - -```none - Value of: IsEven(Fib(6)) - Actual: true (8 is even) - Expected: false -``` - -#### Using a Predicate-Formatter - -If you find the default message generated by `(ASSERT|EXPECT)_PRED*` and -`(ASSERT|EXPECT)_(TRUE|FALSE)` unsatisfactory, or some arguments to your -predicate do not support streaming to `ostream`, you can instead use the -following *predicate-formatter assertions* to *fully* customize how the message -is formatted: - -Fatal assertion | Nonfatal assertion | Verifies ------------------------------------------------- | ------------------------------------------------ | -------- -`ASSERT_PRED_FORMAT1(pred_format1, val1);` | `EXPECT_PRED_FORMAT1(pred_format1, val1);` | `pred_format1(val1)` is successful -`ASSERT_PRED_FORMAT2(pred_format2, val1, val2);` | `EXPECT_PRED_FORMAT2(pred_format2, val1, val2);` | `pred_format2(val1, val2)` is successful -`...` | `...` | ... - -The difference between this and the previous group of macros is that instead of -a predicate, `(ASSERT|EXPECT)_PRED_FORMAT*` take a *predicate-formatter* -(`pred_formatn`), which is a function or functor with the signature: - -```c++ -testing::AssertionResult PredicateFormattern(const char* expr1, - const char* expr2, - ... - const char* exprn, - T1 val1, - T2 val2, - ... - Tn valn); -``` - -where `val1`, `val2`, ..., and `valn` are the values of the predicate arguments, -and `expr1`, `expr2`, ..., and `exprn` are the corresponding expressions as they -appear in the source code. The types `T1`, `T2`, ..., and `Tn` can be either -value types or reference types. For example, if an argument has type `Foo`, you -can declare it as either `Foo` or `const Foo&`, whichever is appropriate. - -As an example, let's improve the failure message in `MutuallyPrime()`, which was -used with `EXPECT_PRED2()`: - -```c++ -// Returns the smallest prime common divisor of m and n, -// or 1 when m and n are mutually prime. -int SmallestPrimeCommonDivisor(int m, int n) { ... } - -// A predicate-formatter for asserting that two integers are mutually prime. -testing::AssertionResult AssertMutuallyPrime(const char* m_expr, - const char* n_expr, - int m, - int n) { - if (MutuallyPrime(m, n)) return testing::AssertionSuccess(); - - return testing::AssertionFailure() << m_expr << " and " << n_expr - << " (" << m << " and " << n << ") are not mutually prime, " - << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); -} -``` - -With this predicate-formatter, we can use - -```c++ - EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); -``` - -to generate the message - -```none -b and c (4 and 10) are not mutually prime, as they have a common divisor 2. -``` - -As you may have realized, many of the built-in assertions we introduced earlier -are special cases of `(EXPECT|ASSERT)_PRED_FORMAT*`. In fact, most of them are -indeed defined using `(EXPECT|ASSERT)_PRED_FORMAT*`. - -### Floating-Point Comparison - -Comparing floating-point numbers is tricky. Due to round-off errors, it is very -unlikely that two floating-points will match exactly. Therefore, `ASSERT_EQ` 's -naive comparison usually doesn't work. And since floating-points can have a wide -value range, no single fixed error bound works. It's better to compare by a -fixed relative error bound, except for values close to 0 due to the loss of -precision there. - -In general, for floating-point comparison to make sense, the user needs to -carefully choose the error bound. If they don't want or care to, comparing in -terms of Units in the Last Place (ULPs) is a good default, and googletest -provides assertions to do this. Full details about ULPs are quite long; if you -want to learn more, see -[here](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/). - -#### Floating-Point Macros - - -| Fatal assertion | Nonfatal assertion | Verifies | -| ------------------------------- | ------------------------------- | ---------------------------------------- | -| `ASSERT_FLOAT_EQ(val1, val2);` | `EXPECT_FLOAT_EQ(val1, val2);` | the two `float` values are almost equal | -| `ASSERT_DOUBLE_EQ(val1, val2);` | `EXPECT_DOUBLE_EQ(val1, val2);` | the two `double` values are almost equal | - - -By "almost equal" we mean the values are within 4 ULP's from each other. - -The following assertions allow you to choose the acceptable error bound: - - -| Fatal assertion | Nonfatal assertion | Verifies | -| ------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------- | -| `ASSERT_NEAR(val1, val2, abs_error);` | `EXPECT_NEAR(val1, val2, abs_error);` | the difference between `val1` and `val2` doesn't exceed the given absolute error | - - -#### Floating-Point Predicate-Format Functions - -Some floating-point operations are useful, but not that often used. In order to -avoid an explosion of new macros, we provide them as predicate-format functions -that can be used in predicate assertion macros (e.g. `EXPECT_PRED_FORMAT2`, -etc). - -```c++ -EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2); -EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2); -``` - -Verifies that `val1` is less than, or almost equal to, `val2`. You can replace -`EXPECT_PRED_FORMAT2` in the above table with `ASSERT_PRED_FORMAT2`. - -### Asserting Using gMock Matchers - -[gMock](gmock_for_dummies.md) comes with -[a library of matchers](gmock_cheat_sheet.md#MatcherList) for -validating arguments passed to mock objects. A gMock *matcher* is basically a -predicate that knows how to describe itself. It can be used in these assertion -macros: - - -| Fatal assertion | Nonfatal assertion | Verifies | -| ------------------------------ | ------------------------------ | --------------------- | -| `ASSERT_THAT(value, matcher);` | `EXPECT_THAT(value, matcher);` | value matches matcher | - - -For example, `StartsWith(prefix)` is a matcher that matches a string starting -with `prefix`, and you can write: - -```c++ -using ::testing::StartsWith; -... - // Verifies that Foo() returns a string starting with "Hello". - EXPECT_THAT(Foo(), StartsWith("Hello")); -``` - -Read this -[recipe](gmock_cook_book.md#using-matchers-in-googletest-assertions) -in the gMock Cookbook for more details. - -gMock has a rich set of matchers. You can do many things googletest cannot do -alone with them. For a list of matchers gMock provides, read -[this](gmock_cook_book.md##using-matchers). It's easy to write -your [own matchers](gmock_cook_book.md#NewMatchers) too. - -gMock is bundled with googletest, so you don't need to add any build dependency -in order to take advantage of this. Just include `"gmock/gmock.h"` -and you're ready to go. - -### More String Assertions - -(Please read the [previous](#asserting-using-gmock-matchers) section first if -you haven't.) - -You can use the gMock -[string matchers](gmock_cheat_sheet.md#string-matchers) with -`EXPECT_THAT()` or `ASSERT_THAT()` to do more string comparison tricks -(sub-string, prefix, suffix, regular expression, and etc). For example, - -```c++ -using ::testing::HasSubstr; -using ::testing::MatchesRegex; -... - ASSERT_THAT(foo_string, HasSubstr("needle")); - EXPECT_THAT(bar_string, MatchesRegex("\\w*\\d+")); -``` - -If the string contains a well-formed HTML or XML document, you can check whether -its DOM tree matches an -[XPath expression](http://www.w3.org/TR/xpath/#contents): - -```c++ -// Currently still in //template/prototemplate/testing:xpath_matcher -#include "template/prototemplate/testing/xpath_matcher.h" -using ::prototemplate::testing::MatchesXPath; -EXPECT_THAT(html_string, MatchesXPath("//a[text()='click here']")); -``` - -### Windows HRESULT assertions - -These assertions test for `HRESULT` success or failure. - -Fatal assertion | Nonfatal assertion | Verifies --------------------------------------- | -------------------------------------- | -------- -`ASSERT_HRESULT_SUCCEEDED(expression)` | `EXPECT_HRESULT_SUCCEEDED(expression)` | `expression` is a success `HRESULT` -`ASSERT_HRESULT_FAILED(expression)` | `EXPECT_HRESULT_FAILED(expression)` | `expression` is a failure `HRESULT` - -The generated output contains the human-readable error message associated with -the `HRESULT` code returned by `expression`. - -You might use them like this: - -```c++ -CComPtr shell; -ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); -CComVariant empty; -ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty)); -``` - -### Type Assertions - -You can call the function - -```c++ -::testing::StaticAssertTypeEq(); -``` - -to assert that types `T1` and `T2` are the same. The function does nothing if -the assertion is satisfied. If the types are different, the function call will -fail to compile, the compiler error message will say that -`T1 and T2 are not the same type` and most likely (depending on the compiler) -show you the actual values of `T1` and `T2`. This is mainly useful inside -template code. - -**Caveat**: When used inside a member function of a class template or a function -template, `StaticAssertTypeEq()` is effective only if the function is -instantiated. For example, given: - -```c++ -template class Foo { - public: - void Bar() { testing::StaticAssertTypeEq(); } -}; -``` - -the code: - -```c++ -void Test1() { Foo foo; } -``` - -will not generate a compiler error, as `Foo::Bar()` is never actually -instantiated. Instead, you need: - -```c++ -void Test2() { Foo foo; foo.Bar(); } -``` - -to cause a compiler error. - -### Assertion Placement - -You can use assertions in any C++ function. In particular, it doesn't have to be -a method of the test fixture class. The one constraint is that assertions that -generate a fatal failure (`FAIL*` and `ASSERT_*`) can only be used in -void-returning functions. This is a consequence of Google's not using -exceptions. By placing it in a non-void function you'll get a confusing compile -error like `"error: void value not ignored as it ought to be"` or `"cannot -initialize return object of type 'bool' with an rvalue of type 'void'"` or -`"error: no viable conversion from 'void' to 'string'"`. - -If you need to use fatal assertions in a function that returns non-void, one -option is to make the function return the value in an out parameter instead. For -example, you can rewrite `T2 Foo(T1 x)` to `void Foo(T1 x, T2* result)`. You -need to make sure that `*result` contains some sensible value even when the -function returns prematurely. As the function now returns `void`, you can use -any assertion inside of it. - -If changing the function's type is not an option, you should just use assertions -that generate non-fatal failures, such as `ADD_FAILURE*` and `EXPECT_*`. - -{: .callout .note} -NOTE: Constructors and destructors are not considered void-returning functions, -according to the C++ language specification, and so you may not use fatal -assertions in them; you'll get a compilation error if you try. Instead, either -call `abort` and crash the entire test executable, or put the fatal assertion in -a `SetUp`/`TearDown` function; see -[constructor/destructor vs. `SetUp`/`TearDown`](faq.md#CtorVsSetUp) - -{: .callout .warning} -WARNING: A fatal assertion in a helper function (private void-returning method) -called from a constructor or destructor does not terminate the current test, as -your intuition might suggest: it merely returns from the constructor or -destructor early, possibly leaving your object in a partially-constructed or -partially-destructed state! You almost certainly want to `abort` or use -`SetUp`/`TearDown` instead. - -## Teaching googletest How to Print Your Values - -When a test assertion such as `EXPECT_EQ` fails, googletest prints the argument -values to help you debug. It does this using a user-extensible value printer. - -This printer knows how to print built-in C++ types, native arrays, STL -containers, and any type that supports the `<<` operator. For other types, it -prints the raw bytes in the value and hopes that you the user can figure it out. - -As mentioned earlier, the printer is *extensible*. That means you can teach it -to do a better job at printing your particular type than to dump the bytes. To -do that, define `<<` for your type: - -```c++ -#include - -namespace foo { - -class Bar { // We want googletest to be able to print instances of this. -... - // Create a free inline friend function. - friend std::ostream& operator<<(std::ostream& os, const Bar& bar) { - return os << bar.DebugString(); // whatever needed to print bar to os - } -}; - -// If you can't declare the function in the class it's important that the -// << operator is defined in the SAME namespace that defines Bar. C++'s look-up -// rules rely on that. -std::ostream& operator<<(std::ostream& os, const Bar& bar) { - return os << bar.DebugString(); // whatever needed to print bar to os -} - -} // namespace foo -``` - -Sometimes, this might not be an option: your team may consider it bad style to -have a `<<` operator for `Bar`, or `Bar` may already have a `<<` operator that -doesn't do what you want (and you cannot change it). If so, you can instead -define a `PrintTo()` function like this: - -```c++ -#include - -namespace foo { - -class Bar { - ... - friend void PrintTo(const Bar& bar, std::ostream* os) { - *os << bar.DebugString(); // whatever needed to print bar to os - } -}; - -// If you can't declare the function in the class it's important that PrintTo() -// is defined in the SAME namespace that defines Bar. C++'s look-up rules rely -// on that. -void PrintTo(const Bar& bar, std::ostream* os) { - *os << bar.DebugString(); // whatever needed to print bar to os -} - -} // namespace foo -``` - -If you have defined both `<<` and `PrintTo()`, the latter will be used when -googletest is concerned. This allows you to customize how the value appears in -googletest's output without affecting code that relies on the behavior of its -`<<` operator. - -If you want to print a value `x` using googletest's value printer yourself, just -call `::testing::PrintToString(x)`, which returns an `std::string`: - -```c++ -vector > bar_ints = GetBarIntVector(); - -EXPECT_TRUE(IsCorrectBarIntVector(bar_ints)) - << "bar_ints = " << testing::PrintToString(bar_ints); -``` - -## Death Tests - -In many applications, there are assertions that can cause application failure if -a condition is not met. These sanity checks, which ensure that the program is in -a known good state, are there to fail at the earliest possible time after some -program state is corrupted. If the assertion checks the wrong condition, then -the program may proceed in an erroneous state, which could lead to memory -corruption, security holes, or worse. Hence it is vitally important to test that -such assertion statements work as expected. - -Since these precondition checks cause the processes to die, we call such tests -_death tests_. More generally, any test that checks that a program terminates -(except by throwing an exception) in an expected fashion is also a death test. - -Note that if a piece of code throws an exception, we don't consider it "death" -for the purpose of death tests, as the caller of the code could catch the -exception and avoid the crash. If you want to verify exceptions thrown by your -code, see [Exception Assertions](#ExceptionAssertions). - -If you want to test `EXPECT_*()/ASSERT_*()` failures in your test code, see -Catching Failures - -### How to Write a Death Test - -googletest has the following macros to support death tests: - -Fatal assertion | Nonfatal assertion | Verifies ------------------------------------------------- | ------------------------------------------------ | -------- -`ASSERT_DEATH(statement, matcher);` | `EXPECT_DEATH(statement, matcher);` | `statement` crashes with the given error -`ASSERT_DEATH_IF_SUPPORTED(statement, matcher);` | `EXPECT_DEATH_IF_SUPPORTED(statement, matcher);` | if death tests are supported, verifies that `statement` crashes with the given error; otherwise verifies nothing -`ASSERT_DEBUG_DEATH(statement, matcher);` | `EXPECT_DEBUG_DEATH(statement, matcher);` | `statement` crashes with the given error **in debug mode**. When not in debug (i.e. `NDEBUG` is defined), this just executes `statement` -`ASSERT_EXIT(statement, predicate, matcher);` | `EXPECT_EXIT(statement, predicate, matcher);` | `statement` exits with the given error, and its exit code matches `predicate` - -where `statement` is a statement that is expected to cause the process to die, -`predicate` is a function or function object that evaluates an integer exit -status, and `matcher` is either a gMock matcher matching a `const std::string&` -or a (Perl) regular expression - either of which is matched against the stderr -output of `statement`. For legacy reasons, a bare string (i.e. with no matcher) -is interpreted as `ContainsRegex(str)`, **not** `Eq(str)`. Note that `statement` -can be *any valid statement* (including *compound statement*) and doesn't have -to be an expression. - -As usual, the `ASSERT` variants abort the current test function, while the -`EXPECT` variants do not. - -{: .callout .note} -> NOTE: We use the word "crash" here to mean that the process terminates with a -> *non-zero* exit status code. There are two possibilities: either the process -> has called `exit()` or `_exit()` with a non-zero value, or it may be killed by -> a signal. -> -> This means that if *`statement`* terminates the process with a 0 exit code, it -> is *not* considered a crash by `EXPECT_DEATH`. Use `EXPECT_EXIT` instead if -> this is the case, or if you want to restrict the exit code more precisely. - -A predicate here must accept an `int` and return a `bool`. The death test -succeeds only if the predicate returns `true`. googletest defines a few -predicates that handle the most common cases: - -```c++ -::testing::ExitedWithCode(exit_code) -``` - -This expression is `true` if the program exited normally with the given exit -code. - -```c++ -testing::KilledBySignal(signal_number) // Not available on Windows. -``` - -This expression is `true` if the program was killed by the given signal. - -The `*_DEATH` macros are convenient wrappers for `*_EXIT` that use a predicate -that verifies the process' exit code is non-zero. - -Note that a death test only cares about three things: - -1. does `statement` abort or exit the process? -2. (in the case of `ASSERT_EXIT` and `EXPECT_EXIT`) does the exit status - satisfy `predicate`? Or (in the case of `ASSERT_DEATH` and `EXPECT_DEATH`) - is the exit status non-zero? And -3. does the stderr output match `matcher`? - -In particular, if `statement` generates an `ASSERT_*` or `EXPECT_*` failure, it -will **not** cause the death test to fail, as googletest assertions don't abort -the process. - -To write a death test, simply use one of the above macros inside your test -function. For example, - -```c++ -TEST(MyDeathTest, Foo) { - // This death test uses a compound statement. - ASSERT_DEATH({ - int n = 5; - Foo(&n); - }, "Error on line .* of Foo()"); -} - -TEST(MyDeathTest, NormalExit) { - EXPECT_EXIT(NormalExit(), testing::ExitedWithCode(0), "Success"); -} - -TEST(MyDeathTest, KillMyself) { - EXPECT_EXIT(KillMyself(), testing::KilledBySignal(SIGKILL), - "Sending myself unblockable signal"); -} -``` - -verifies that: - -* calling `Foo(5)` causes the process to die with the given error message, -* calling `NormalExit()` causes the process to print `"Success"` to stderr and - exit with exit code 0, and -* calling `KillMyself()` kills the process with signal `SIGKILL`. - -The test function body may contain other assertions and statements as well, if -necessary. - -### Death Test Naming - -{: .callout .important} -IMPORTANT: We strongly recommend you to follow the convention of naming your -**test suite** (not test) `*DeathTest` when it contains a death test, as -demonstrated in the above example. The -[Death Tests And Threads](#death-tests-and-threads) section below explains why. - -If a test fixture class is shared by normal tests and death tests, you can use -`using` or `typedef` to introduce an alias for the fixture class and avoid -duplicating its code: - -```c++ -class FooTest : public testing::Test { ... }; - -using FooDeathTest = FooTest; - -TEST_F(FooTest, DoesThis) { - // normal test -} - -TEST_F(FooDeathTest, DoesThat) { - // death test -} -``` - -### Regular Expression Syntax - -On POSIX systems (e.g. Linux, Cygwin, and Mac), googletest uses the -[POSIX extended regular expression](http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) -syntax. To learn about this syntax, you may want to read this -[Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). - -On Windows, googletest uses its own simple regular expression implementation. It -lacks many features. For example, we don't support union (`"x|y"`), grouping -(`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among -others. Below is what we do support (`A` denotes a literal character, period -(`.`), or a single `\\ ` escape sequence; `x` and `y` denote regular -expressions.): - -Expression | Meaning ----------- | -------------------------------------------------------------- -`c` | matches any literal character `c` -`\\d` | matches any decimal digit -`\\D` | matches any character that's not a decimal digit -`\\f` | matches `\f` -`\\n` | matches `\n` -`\\r` | matches `\r` -`\\s` | matches any ASCII whitespace, including `\n` -`\\S` | matches any character that's not a whitespace -`\\t` | matches `\t` -`\\v` | matches `\v` -`\\w` | matches any letter, `_`, or decimal digit -`\\W` | matches any character that `\\w` doesn't match -`\\c` | matches any literal character `c`, which must be a punctuation -`.` | matches any single character except `\n` -`A?` | matches 0 or 1 occurrences of `A` -`A*` | matches 0 or many occurrences of `A` -`A+` | matches 1 or many occurrences of `A` -`^` | matches the beginning of a string (not that of each line) -`$` | matches the end of a string (not that of each line) -`xy` | matches `x` followed by `y` - -To help you determine which capability is available on your system, googletest -defines macros to govern which regular expression it is using. The macros are: -`GTEST_USES_SIMPLE_RE=1` or `GTEST_USES_POSIX_RE=1`. If you want your death -tests to work in all cases, you can either `#if` on these macros or use the more -limited syntax only. - -### How It Works - -Under the hood, `ASSERT_EXIT()` spawns a new process and executes the death test -statement in that process. The details of how precisely that happens depend on -the platform and the variable `::testing::GTEST_FLAG(death_test_style)` (which is -initialized from the command-line flag `--gtest_death_test_style`). - -* On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the - child, after which: - * If the variable's value is `"fast"`, the death test statement is - immediately executed. - * If the variable's value is `"threadsafe"`, the child process re-executes - the unit test binary just as it was originally invoked, but with some - extra flags to cause just the single death test under consideration to - be run. -* On Windows, the child is spawned using the `CreateProcess()` API, and - re-executes the binary to cause just the single death test under - consideration to be run - much like the `threadsafe` mode on POSIX. - -Other values for the variable are illegal and will cause the death test to fail. -Currently, the flag's default value is -**`"fast"`**. - -1. the child's exit status satisfies the predicate, and -2. the child's stderr matches the regular expression. - -If the death test statement runs to completion without dying, the child process -will nonetheless terminate, and the assertion fails. - -### Death Tests And Threads - -The reason for the two death test styles has to do with thread safety. Due to -well-known problems with forking in the presence of threads, death tests should -be run in a single-threaded context. Sometimes, however, it isn't feasible to -arrange that kind of environment. For example, statically-initialized modules -may start threads before main is ever reached. Once threads have been created, -it may be difficult or impossible to clean them up. - -googletest has three features intended to raise awareness of threading issues. - -1. A warning is emitted if multiple threads are running when a death test is - encountered. -2. Test suites with a name ending in "DeathTest" are run before all other - tests. -3. It uses `clone()` instead of `fork()` to spawn the child process on Linux - (`clone()` is not available on Cygwin and Mac), as `fork()` is more likely - to cause the child to hang when the parent process has multiple threads. - -It's perfectly fine to create threads inside a death test statement; they are -executed in a separate process and cannot affect the parent. - -### Death Test Styles - -The "threadsafe" death test style was introduced in order to help mitigate the -risks of testing in a possibly multithreaded environment. It trades increased -test execution time (potentially dramatically so) for improved thread safety. - -The automated testing framework does not set the style flag. You can choose a -particular style of death tests by setting the flag programmatically: - -```c++ -testing::FLAGS_gtest_death_test_style="threadsafe" -``` - -You can do this in `main()` to set the style for all death tests in the binary, -or in individual tests. Recall that flags are saved before running each test and -restored afterwards, so you need not do that yourself. For example: - -```c++ -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - testing::FLAGS_gtest_death_test_style = "fast"; - return RUN_ALL_TESTS(); -} - -TEST(MyDeathTest, TestOne) { - testing::FLAGS_gtest_death_test_style = "threadsafe"; - // This test is run in the "threadsafe" style: - ASSERT_DEATH(ThisShouldDie(), ""); -} - -TEST(MyDeathTest, TestTwo) { - // This test is run in the "fast" style: - ASSERT_DEATH(ThisShouldDie(), ""); -} -``` - -### Caveats - -The `statement` argument of `ASSERT_EXIT()` can be any valid C++ statement. If -it leaves the current function via a `return` statement or by throwing an -exception, the death test is considered to have failed. Some googletest macros -may return from the current function (e.g. `ASSERT_TRUE()`), so be sure to avoid -them in `statement`. - -Since `statement` runs in the child process, any in-memory side effect (e.g. -modifying a variable, releasing memory, etc) it causes will *not* be observable -in the parent process. In particular, if you release memory in a death test, -your program will fail the heap check as the parent process will never see the -memory reclaimed. To solve this problem, you can - -1. try not to free memory in a death test; -2. free the memory again in the parent process; or -3. do not use the heap checker in your program. - -Due to an implementation detail, you cannot place multiple death test assertions -on the same line; otherwise, compilation will fail with an unobvious error -message. - -Despite the improved thread safety afforded by the "threadsafe" style of death -test, thread problems such as deadlock are still possible in the presence of -handlers registered with `pthread_atfork(3)`. - - -## Using Assertions in Sub-routines - -{: .callout .note} -Note: If you want to put a series of test assertions in a subroutine to check -for a complex condition, consider using -[a custom GMock matcher](gmock_cook_book.md#NewMatchers) -instead. This lets you provide a more readable error message in case of failure -and avoid all of the issues described below. - -### Adding Traces to Assertions - -If a test sub-routine is called from several places, when an assertion inside it -fails, it can be hard to tell which invocation of the sub-routine the failure is -from. You can alleviate this problem using extra logging or custom failure -messages, but that usually clutters up your tests. A better solution is to use -the `SCOPED_TRACE` macro or the `ScopedTrace` utility: - -```c++ -SCOPED_TRACE(message); -``` -```c++ -ScopedTrace trace("file_path", line_number, message); -``` - -where `message` can be anything streamable to `std::ostream`. `SCOPED_TRACE` -macro will cause the current file name, line number, and the given message to be -added in every failure message. `ScopedTrace` accepts explicit file name and -line number in arguments, which is useful for writing test helpers. The effect -will be undone when the control leaves the current lexical scope. - -For example, - -```c++ -10: void Sub1(int n) { -11: EXPECT_EQ(Bar(n), 1); -12: EXPECT_EQ(Bar(n + 1), 2); -13: } -14: -15: TEST(FooTest, Bar) { -16: { -17: SCOPED_TRACE("A"); // This trace point will be included in -18: // every failure in this scope. -19: Sub1(1); -20: } -21: // Now it won't. -22: Sub1(9); -23: } -``` - -could result in messages like these: - -```none -path/to/foo_test.cc:11: Failure -Value of: Bar(n) -Expected: 1 - Actual: 2 -Google Test trace: -path/to/foo_test.cc:17: A - -path/to/foo_test.cc:12: Failure -Value of: Bar(n + 1) -Expected: 2 - Actual: 3 -``` - -Without the trace, it would've been difficult to know which invocation of -`Sub1()` the two failures come from respectively. (You could add an extra -message to each assertion in `Sub1()` to indicate the value of `n`, but that's -tedious.) - -Some tips on using `SCOPED_TRACE`: - -1. With a suitable message, it's often enough to use `SCOPED_TRACE` at the - beginning of a sub-routine, instead of at each call site. -2. When calling sub-routines inside a loop, make the loop iterator part of the - message in `SCOPED_TRACE` such that you can know which iteration the failure - is from. -3. Sometimes the line number of the trace point is enough for identifying the - particular invocation of a sub-routine. In this case, you don't have to - choose a unique message for `SCOPED_TRACE`. You can simply use `""`. -4. You can use `SCOPED_TRACE` in an inner scope when there is one in the outer - scope. In this case, all active trace points will be included in the failure - messages, in reverse order they are encountered. -5. The trace dump is clickable in Emacs - hit `return` on a line number and - you'll be taken to that line in the source file! - -### Propagating Fatal Failures - -A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that -when they fail they only abort the _current function_, not the entire test. For -example, the following test will segfault: - -```c++ -void Subroutine() { - // Generates a fatal failure and aborts the current function. - ASSERT_EQ(1, 2); - - // The following won't be executed. - ... -} - -TEST(FooTest, Bar) { - Subroutine(); // The intended behavior is for the fatal failure - // in Subroutine() to abort the entire test. - - // The actual behavior: the function goes on after Subroutine() returns. - int* p = nullptr; - *p = 3; // Segfault! -} -``` - -To alleviate this, googletest provides three different solutions. You could use -either exceptions, the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the -`HasFatalFailure()` function. They are described in the following two -subsections. - -#### Asserting on Subroutines with an exception - -The following code can turn ASSERT-failure into an exception: - -```c++ -class ThrowListener : public testing::EmptyTestEventListener { - void OnTestPartResult(const testing::TestPartResult& result) override { - if (result.type() == testing::TestPartResult::kFatalFailure) { - throw testing::AssertionException(result); - } - } -}; -int main(int argc, char** argv) { - ... - testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener); - return RUN_ALL_TESTS(); -} -``` - -This listener should be added after other listeners if you have any, otherwise -they won't see failed `OnTestPartResult`. - -#### Asserting on Subroutines - -As shown above, if your test calls a subroutine that has an `ASSERT_*` failure -in it, the test will continue after the subroutine returns. This may not be what -you want. - -Often people want fatal failures to propagate like exceptions. For that -googletest offers the following macros: - -Fatal assertion | Nonfatal assertion | Verifies -------------------------------------- | ------------------------------------- | -------- -`ASSERT_NO_FATAL_FAILURE(statement);` | `EXPECT_NO_FATAL_FAILURE(statement);` | `statement` doesn't generate any new fatal failures in the current thread. - -Only failures in the thread that executes the assertion are checked to determine -the result of this type of assertions. If `statement` creates new threads, -failures in these threads are ignored. - -Examples: - -```c++ -ASSERT_NO_FATAL_FAILURE(Foo()); - -int i; -EXPECT_NO_FATAL_FAILURE({ - i = Bar(); -}); -``` - -Assertions from multiple threads are currently not supported on Windows. - -#### Checking for Failures in the Current Test - -`HasFatalFailure()` in the `::testing::Test` class returns `true` if an -assertion in the current test has suffered a fatal failure. This allows -functions to catch fatal failures in a sub-routine and return early. - -```c++ -class Test { - public: - ... - static bool HasFatalFailure(); -}; -``` - -The typical usage, which basically simulates the behavior of a thrown exception, -is: - -```c++ -TEST(FooTest, Bar) { - Subroutine(); - // Aborts if Subroutine() had a fatal failure. - if (HasFatalFailure()) return; - - // The following won't be executed. - ... -} -``` - -If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test -fixture, you must add the `::testing::Test::` prefix, as in: - -```c++ -if (testing::Test::HasFatalFailure()) return; -``` - -Similarly, `HasNonfatalFailure()` returns `true` if the current test has at -least one non-fatal failure, and `HasFailure()` returns `true` if the current -test has at least one failure of either kind. - -## Logging Additional Information - -In your test code, you can call `RecordProperty("key", value)` to log additional -information, where `value` can be either a string or an `int`. The *last* value -recorded for a key will be emitted to the -[XML output](#generating-an-xml-report) if you specify one. For example, the -test - -```c++ -TEST_F(WidgetUsageTest, MinAndMaxWidgets) { - RecordProperty("MaximumWidgets", ComputeMaxUsage()); - RecordProperty("MinimumWidgets", ComputeMinUsage()); -} -``` - -will output XML like this: - -```xml - ... - - ... -``` - -{: .callout .note} -> NOTE: -> -> * `RecordProperty()` is a static member of the `Test` class. Therefore it -> needs to be prefixed with `::testing::Test::` if used outside of the -> `TEST` body and the test fixture class. -> * *`key`* must be a valid XML attribute name, and cannot conflict with the -> ones already used by googletest (`name`, `status`, `time`, `classname`, -> `type_param`, and `value_param`). -> * Calling `RecordProperty()` outside of the lifespan of a test is allowed. -> If it's called outside of a test but between a test suite's -> `SetUpTestSuite()` and `TearDownTestSuite()` methods, it will be -> attributed to the XML element for the test suite. If it's called outside -> of all test suites (e.g. in a test environment), it will be attributed to -> the top-level XML element. - -## Sharing Resources Between Tests in the Same Test Suite - -googletest creates a new test fixture object for each test in order to make -tests independent and easier to debug. However, sometimes tests use resources -that are expensive to set up, making the one-copy-per-test model prohibitively -expensive. - -If the tests don't change the resource, there's no harm in their sharing a -single resource copy. So, in addition to per-test set-up/tear-down, googletest -also supports per-test-suite set-up/tear-down. To use it: - -1. In your test fixture class (say `FooTest` ), declare as `static` some member - variables to hold the shared resources. -2. Outside your test fixture class (typically just below it), define those - member variables, optionally giving them initial values. -3. In the same test fixture class, define a `static void SetUpTestSuite()` - function (remember not to spell it as **`SetupTestSuite`** with a small - `u`!) to set up the shared resources and a `static void TearDownTestSuite()` - function to tear them down. - -That's it! googletest automatically calls `SetUpTestSuite()` before running the -*first test* in the `FooTest` test suite (i.e. before creating the first -`FooTest` object), and calls `TearDownTestSuite()` after running the *last test* -in it (i.e. after deleting the last `FooTest` object). In between, the tests can -use the shared resources. - -Remember that the test order is undefined, so your code can't depend on a test -preceding or following another. Also, the tests must either not modify the state -of any shared resource, or, if they do modify the state, they must restore the -state to its original value before passing control to the next test. - -Here's an example of per-test-suite set-up and tear-down: - -```c++ -class FooTest : public testing::Test { - protected: - // Per-test-suite set-up. - // Called before the first test in this test suite. - // Can be omitted if not needed. - static void SetUpTestSuite() { - shared_resource_ = new ...; - } - - // Per-test-suite tear-down. - // Called after the last test in this test suite. - // Can be omitted if not needed. - static void TearDownTestSuite() { - delete shared_resource_; - shared_resource_ = nullptr; - } - - // You can define per-test set-up logic as usual. - void SetUp() override { ... } - - // You can define per-test tear-down logic as usual. - void TearDown() override { ... } - - // Some expensive resource shared by all tests. - static T* shared_resource_; -}; - -T* FooTest::shared_resource_ = nullptr; - -TEST_F(FooTest, Test1) { - ... you can refer to shared_resource_ here ... -} - -TEST_F(FooTest, Test2) { - ... you can refer to shared_resource_ here ... -} -``` - -{: .callout .note} -NOTE: Though the above code declares `SetUpTestSuite()` protected, it may -sometimes be necessary to declare it public, such as when using it with -`TEST_P`. - -## Global Set-Up and Tear-Down - -Just as you can do set-up and tear-down at the test level and the test suite -level, you can also do it at the test program level. Here's how. - -First, you subclass the `::testing::Environment` class to define a test -environment, which knows how to set-up and tear-down: - -```c++ -class Environment : public ::testing::Environment { - public: - ~Environment() override {} - - // Override this to define how to set up the environment. - void SetUp() override {} - - // Override this to define how to tear down the environment. - void TearDown() override {} -}; -``` - -Then, you register an instance of your environment class with googletest by -calling the `::testing::AddGlobalTestEnvironment()` function: - -```c++ -Environment* AddGlobalTestEnvironment(Environment* env); -``` - -Now, when `RUN_ALL_TESTS()` is called, it first calls the `SetUp()` method of -each environment object, then runs the tests if none of the environments -reported fatal failures and `GTEST_SKIP()` was not called. `RUN_ALL_TESTS()` -always calls `TearDown()` with each environment object, regardless of whether or -not the tests were run. - -It's OK to register multiple environment objects. In this suite, their `SetUp()` -will be called in the order they are registered, and their `TearDown()` will be -called in the reverse order. - -Note that googletest takes ownership of the registered environment objects. -Therefore **do not delete them** by yourself. - -You should call `AddGlobalTestEnvironment()` before `RUN_ALL_TESTS()` is called, -probably in `main()`. If you use `gtest_main`, you need to call this before -`main()` starts for it to take effect. One way to do this is to define a global -variable like this: - -```c++ -testing::Environment* const foo_env = - testing::AddGlobalTestEnvironment(new FooEnvironment); -``` - -However, we strongly recommend you to write your own `main()` and call -`AddGlobalTestEnvironment()` there, as relying on initialization of global -variables makes the code harder to read and may cause problems when you register -multiple environments from different translation units and the environments have -dependencies among them (remember that the compiler doesn't guarantee the order -in which global variables from different translation units are initialized). - -## Value-Parameterized Tests - -*Value-parameterized tests* allow you to test your code with different -parameters without writing multiple copies of the same test. This is useful in a -number of situations, for example: - -* You have a piece of code whose behavior is affected by one or more - command-line flags. You want to make sure your code performs correctly for - various values of those flags. -* You want to test different implementations of an OO interface. -* You want to test your code over various inputs (a.k.a. data-driven testing). - This feature is easy to abuse, so please exercise your good sense when doing - it! - -### How to Write Value-Parameterized Tests - -To write value-parameterized tests, first you should define a fixture class. It -must be derived from both `testing::Test` and `testing::WithParamInterface` -(the latter is a pure interface), where `T` is the type of your parameter -values. For convenience, you can just derive the fixture class from -`testing::TestWithParam`, which itself is derived from both `testing::Test` -and `testing::WithParamInterface`. `T` can be any copyable type. If it's a -raw pointer, you are responsible for managing the lifespan of the pointed -values. - -{: .callout .note} -NOTE: If your test fixture defines `SetUpTestSuite()` or `TearDownTestSuite()` -they must be declared **public** rather than **protected** in order to use -`TEST_P`. - -```c++ -class FooTest : - public testing::TestWithParam { - // You can implement all the usual fixture class members here. - // To access the test parameter, call GetParam() from class - // TestWithParam. -}; - -// Or, when you want to add parameters to a pre-existing fixture class: -class BaseTest : public testing::Test { - ... -}; -class BarTest : public BaseTest, - public testing::WithParamInterface { - ... -}; -``` - -Then, use the `TEST_P` macro to define as many test patterns using this fixture -as you want. The `_P` suffix is for "parameterized" or "pattern", whichever you -prefer to think. - -```c++ -TEST_P(FooTest, DoesBlah) { - // Inside a test, access the test parameter with the GetParam() method - // of the TestWithParam class: - EXPECT_TRUE(foo.Blah(GetParam())); - ... -} - -TEST_P(FooTest, HasBlahBlah) { - ... -} -``` - -Finally, you can use `INSTANTIATE_TEST_SUITE_P` to instantiate the test suite -with any set of parameters you want. googletest defines a number of functions -for generating test parameters. They return what we call (surprise!) *parameter -generators*. Here is a summary of them, which are all in the `testing` -namespace: - - -| Parameter Generator | Behavior | -| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -| `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. | -| `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. | -| `ValuesIn(container)` and `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)` | -| `Bool()` | Yields sequence `{false, true}`. | -| `Combine(g1, g2, ..., gN)` | Yields all combinations (Cartesian product) as std\:\:tuples of the values generated by the `N` generators. | - - -For more details, see the comments at the definitions of these functions. - -The following statement will instantiate tests from the `FooTest` test suite -each with parameter values `"meeny"`, `"miny"`, and `"moe"`. - -```c++ -INSTANTIATE_TEST_SUITE_P(MeenyMinyMoe, - FooTest, - testing::Values("meeny", "miny", "moe")); -``` - -{: .callout .note} -NOTE: The code above must be placed at global or namespace scope, not at -function scope. - -The first argument to `INSTANTIATE_TEST_SUITE_P` is a unique name for the -instantiation of the test suite. The next argument is the name of the test -pattern, and the last is the parameter generator. - -You can instantiate a test pattern more than once, so to distinguish different -instances of the pattern, the instantiation name is added as a prefix to the -actual test suite name. Remember to pick unique prefixes for different -instantiations. The tests from the instantiation above will have these names: - -* `MeenyMinyMoe/FooTest.DoesBlah/0` for `"meeny"` -* `MeenyMinyMoe/FooTest.DoesBlah/1` for `"miny"` -* `MeenyMinyMoe/FooTest.DoesBlah/2` for `"moe"` -* `MeenyMinyMoe/FooTest.HasBlahBlah/0` for `"meeny"` -* `MeenyMinyMoe/FooTest.HasBlahBlah/1` for `"miny"` -* `MeenyMinyMoe/FooTest.HasBlahBlah/2` for `"moe"` - -You can use these names in [`--gtest_filter`](#running-a-subset-of-the-tests). - -The following statement will instantiate all tests from `FooTest` again, each -with parameter values `"cat"` and `"dog"`: - -```c++ -const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_SUITE_P(Pets, FooTest, testing::ValuesIn(pets)); -``` - -The tests from the instantiation above will have these names: - -* `Pets/FooTest.DoesBlah/0` for `"cat"` -* `Pets/FooTest.DoesBlah/1` for `"dog"` -* `Pets/FooTest.HasBlahBlah/0` for `"cat"` -* `Pets/FooTest.HasBlahBlah/1` for `"dog"` - -Please note that `INSTANTIATE_TEST_SUITE_P` will instantiate *all* tests in the -given test suite, whether their definitions come before or *after* the -`INSTANTIATE_TEST_SUITE_P` statement. - -Additionally, by default, every `TEST_P` without a corresponding -`INSTANTIATE_TEST_SUITE_P` causes a failing test in test suite -`GoogleTestVerification`. If you have a test suite where that omission is not an -error, for example it is in a library that may be linked in for other reasons or -where the list of test cases is dynamic and may be empty, then this check can be -suppressed by tagging the test suite: - -```c++ -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FooTest); -``` - -You can see [sample7_unittest.cc] and [sample8_unittest.cc] for more examples. - -[sample7_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample7_unittest.cc "Parameterized Test example" -[sample8_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample8_unittest.cc "Parameterized Test example with multiple parameters" - -### Creating Value-Parameterized Abstract Tests - -In the above, we define and instantiate `FooTest` in the *same* source file. -Sometimes you may want to define value-parameterized tests in a library and let -other people instantiate them later. This pattern is known as *abstract tests*. -As an example of its application, when you are designing an interface you can -write a standard suite of abstract tests (perhaps using a factory function as -the test parameter) that all implementations of the interface are expected to -pass. When someone implements the interface, they can instantiate your suite to -get all the interface-conformance tests for free. - -To define abstract tests, you should organize your code like this: - -1. Put the definition of the parameterized test fixture class (e.g. `FooTest`) - in a header file, say `foo_param_test.h`. Think of this as *declaring* your - abstract tests. -2. Put the `TEST_P` definitions in `foo_param_test.cc`, which includes - `foo_param_test.h`. Think of this as *implementing* your abstract tests. - -Once they are defined, you can instantiate them by including `foo_param_test.h`, -invoking `INSTANTIATE_TEST_SUITE_P()`, and depending on the library target that -contains `foo_param_test.cc`. You can instantiate the same abstract test suite -multiple times, possibly in different source files. - -### Specifying Names for Value-Parameterized Test Parameters - -The optional last argument to `INSTANTIATE_TEST_SUITE_P()` allows the user to -specify a function or functor that generates custom test name suffixes based on -the test parameters. The function should accept one argument of type -`testing::TestParamInfo`, and return `std::string`. - -`testing::PrintToStringParamName` is a builtin test suffix generator that -returns the value of `testing::PrintToString(GetParam())`. It does not work for -`std::string` or C strings. - -{: .callout .note} -NOTE: test names must be non-empty, unique, and may only contain ASCII -alphanumeric characters. In particular, they -[should not contain underscores](faq.md#why-should-test-suite-names-and-test-names-not-contain-underscore) - -```c++ -class MyTestSuite : public testing::TestWithParam {}; - -TEST_P(MyTestSuite, MyTest) -{ - std::cout << "Example Test Param: " << GetParam() << std::endl; -} - -INSTANTIATE_TEST_SUITE_P(MyGroup, MyTestSuite, testing::Range(0, 10), - testing::PrintToStringParamName()); -``` - -Providing a custom functor allows for more control over test parameter name -generation, especially for types where the automatic conversion does not -generate helpful parameter names (e.g. strings as demonstrated above). The -following example illustrates this for multiple parameters, an enumeration type -and a string, and also demonstrates how to combine generators. It uses a lambda -for conciseness: - -```c++ -enum class MyType { MY_FOO = 0, MY_BAR = 1 }; - -class MyTestSuite : public testing::TestWithParam> { -}; - -INSTANTIATE_TEST_SUITE_P( - MyGroup, MyTestSuite, - testing::Combine( - testing::Values(MyType::MY_FOO, MyType::MY_BAR), - testing::Values("A", "B")), - [](const testing::TestParamInfo& info) { - std::string name = absl::StrCat( - std::get<0>(info.param) == MyType::MY_FOO ? "Foo" : "Bar", - std::get<1>(info.param)); - absl::c_replace_if(name, [](char c) { return !std::isalnum(c); }, ''); - return name; - }); -``` - -## Typed Tests - -Suppose you have multiple implementations of the same interface and want to make -sure that all of them satisfy some common requirements. Or, you may have defined -several types that are supposed to conform to the same "concept" and you want to -verify it. In both cases, you want the same test logic repeated for different -types. - -While you can write one `TEST` or `TEST_F` for each type you want to test (and -you may even factor the test logic into a function template that you invoke from -the `TEST`), it's tedious and doesn't scale: if you want `m` tests over `n` -types, you'll end up writing `m*n` `TEST`s. - -*Typed tests* allow you to repeat the same test logic over a list of types. You -only need to write the test logic once, although you must know the type list -when writing typed tests. Here's how you do it: - -First, define a fixture class template. It should be parameterized by a type. -Remember to derive it from `::testing::Test`: - -```c++ -template -class FooTest : public testing::Test { - public: - ... - using List = std::list; - static T shared_; - T value_; -}; -``` - -Next, associate a list of types with the test suite, which will be repeated for -each type in the list: - -```c++ -using MyTypes = ::testing::Types; -TYPED_TEST_SUITE(FooTest, MyTypes); -``` - -The type alias (`using` or `typedef`) is necessary for the `TYPED_TEST_SUITE` -macro to parse correctly. Otherwise the compiler will think that each comma in -the type list introduces a new macro argument. - -Then, use `TYPED_TEST()` instead of `TEST_F()` to define a typed test for this -test suite. You can repeat this as many times as you want: - -```c++ -TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to the special name TypeParam to get the type - // parameter. Since we are inside a derived class template, C++ requires - // us to visit the members of FooTest via 'this'. - TypeParam n = this->value_; - - // To visit static members of the fixture, add the 'TestFixture::' - // prefix. - n += TestFixture::shared_; - - // To refer to typedefs in the fixture, add the 'typename TestFixture::' - // prefix. The 'typename' is required to satisfy the compiler. - typename TestFixture::List values; - - values.push_back(n); - ... -} - -TYPED_TEST(FooTest, HasPropertyA) { ... } -``` - -You can see [sample6_unittest.cc] for a complete example. - -[sample6_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample6_unittest.cc "Typed Test example" - -## Type-Parameterized Tests - -*Type-parameterized tests* are like typed tests, except that they don't require -you to know the list of types ahead of time. Instead, you can define the test -logic first and instantiate it with different type lists later. You can even -instantiate it more than once in the same program. - -If you are designing an interface or concept, you can define a suite of -type-parameterized tests to verify properties that any valid implementation of -the interface/concept should have. Then, the author of each implementation can -just instantiate the test suite with their type to verify that it conforms to -the requirements, without having to write similar tests repeatedly. Here's an -example: - -First, define a fixture class template, as we did with typed tests: - -```c++ -template -class FooTest : public testing::Test { - ... -}; -``` - -Next, declare that you will define a type-parameterized test suite: - -```c++ -TYPED_TEST_SUITE_P(FooTest); -``` - -Then, use `TYPED_TEST_P()` to define a type-parameterized test. You can repeat -this as many times as you want: - -```c++ -TYPED_TEST_P(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - TypeParam n = 0; - ... -} - -TYPED_TEST_P(FooTest, HasPropertyA) { ... } -``` - -Now the tricky part: you need to register all test patterns using the -`REGISTER_TYPED_TEST_SUITE_P` macro before you can instantiate them. The first -argument of the macro is the test suite name; the rest are the names of the -tests in this test suite: - -```c++ -REGISTER_TYPED_TEST_SUITE_P(FooTest, - DoesBlah, HasPropertyA); -``` - -Finally, you are free to instantiate the pattern with the types you want. If you -put the above code in a header file, you can `#include` it in multiple C++ -source files and instantiate it multiple times. - -```c++ -using MyTypes = ::testing::Types; -INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); -``` - -To distinguish different instances of the pattern, the first argument to the -`INSTANTIATE_TYPED_TEST_SUITE_P` macro is a prefix that will be added to the -actual test suite name. Remember to pick unique prefixes for different -instances. - -In the special case where the type list contains only one type, you can write -that type directly without `::testing::Types<...>`, like this: - -```c++ -INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int); -``` - -You can see [sample6_unittest.cc] for a complete example. - -## Testing Private Code - -If you change your software's internal implementation, your tests should not -break as long as the change is not observable by users. Therefore, **per the -black-box testing principle, most of the time you should test your code through -its public interfaces.** - -**If you still find yourself needing to test internal implementation code, -consider if there's a better design.** The desire to test internal -implementation is often a sign that the class is doing too much. Consider -extracting an implementation class, and testing it. Then use that implementation -class in the original class. - -If you absolutely have to test non-public interface code though, you can. There -are two cases to consider: - -* Static functions ( *not* the same as static member functions!) or unnamed - namespaces, and -* Private or protected class members - -To test them, we use the following special techniques: - -* Both static functions and definitions/declarations in an unnamed namespace - are only visible within the same translation unit. To test them, you can - `#include` the entire `.cc` file being tested in your `*_test.cc` file. - (#including `.cc` files is not a good way to reuse code - you should not do - this in production code!) - - However, a better approach is to move the private code into the - `foo::internal` namespace, where `foo` is the namespace your project - normally uses, and put the private declarations in a `*-internal.h` file. - Your production `.cc` files and your tests are allowed to include this - internal header, but your clients are not. This way, you can fully test your - internal implementation without leaking it to your clients. - -* Private class members are only accessible from within the class or by - friends. To access a class' private members, you can declare your test - fixture as a friend to the class and define accessors in your fixture. Tests - using the fixture can then access the private members of your production - class via the accessors in the fixture. Note that even though your fixture - is a friend to your production class, your tests are not automatically - friends to it, as they are technically defined in sub-classes of the - fixture. - - Another way to test private members is to refactor them into an - implementation class, which is then declared in a `*-internal.h` file. Your - clients aren't allowed to include this header but your tests can. Such is - called the - [Pimpl](https://www.gamedev.net/articles/programming/general-and-gameplay-programming/the-c-pimpl-r1794/) - (Private Implementation) idiom. - - Or, you can declare an individual test as a friend of your class by adding - this line in the class body: - - ```c++ - FRIEND_TEST(TestSuiteName, TestName); - ``` - - For example, - - ```c++ - // foo.h - class Foo { - ... - private: - FRIEND_TEST(FooTest, BarReturnsZeroOnNull); - - int Bar(void* x); - }; - - // foo_test.cc - ... - TEST(FooTest, BarReturnsZeroOnNull) { - Foo foo; - EXPECT_EQ(foo.Bar(NULL), 0); // Uses Foo's private member Bar(). - } - ``` - - Pay special attention when your class is defined in a namespace. If you want - your test fixtures and tests to be friends of your class, then they must be - defined in the exact same namespace (no anonymous or inline namespaces). - - For example, if the code to be tested looks like: - - ```c++ - namespace my_namespace { - - class Foo { - friend class FooTest; - FRIEND_TEST(FooTest, Bar); - FRIEND_TEST(FooTest, Baz); - ... definition of the class Foo ... - }; - - } // namespace my_namespace - ``` - - Your test code should be something like: - - ```c++ - namespace my_namespace { - - class FooTest : public testing::Test { - protected: - ... - }; - - TEST_F(FooTest, Bar) { ... } - TEST_F(FooTest, Baz) { ... } - - } // namespace my_namespace - ``` - -## "Catching" Failures - -If you are building a testing utility on top of googletest, you'll want to test -your utility. What framework would you use to test it? googletest, of course. - -The challenge is to verify that your testing utility reports failures correctly. -In frameworks that report a failure by throwing an exception, you could catch -the exception and assert on it. But googletest doesn't use exceptions, so how do -we test that a piece of code generates an expected failure? - -`"gtest/gtest-spi.h"` contains some constructs to do this. After #including this header, -you can use - -```c++ - EXPECT_FATAL_FAILURE(statement, substring); -``` - -to assert that `statement` generates a fatal (e.g. `ASSERT_*`) failure in the -current thread whose message contains the given `substring`, or use - -```c++ - EXPECT_NONFATAL_FAILURE(statement, substring); -``` - -if you are expecting a non-fatal (e.g. `EXPECT_*`) failure. - -Only failures in the current thread are checked to determine the result of this -type of expectations. If `statement` creates new threads, failures in these -threads are also ignored. If you want to catch failures in other threads as -well, use one of the following macros instead: - -```c++ - EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substring); - EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substring); -``` - -{: .callout .note} -NOTE: Assertions from multiple threads are currently not supported on Windows. - -For technical reasons, there are some caveats: - -1. You cannot stream a failure message to either macro. - -2. `statement` in `EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}()` cannot reference - local non-static variables or non-static members of `this` object. - -3. `statement` in `EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}()` cannot return a - value. - -## Registering tests programmatically - -The `TEST` macros handle the vast majority of all use cases, but there are few -where runtime registration logic is required. For those cases, the framework -provides the `::testing::RegisterTest` that allows callers to register arbitrary -tests dynamically. - -This is an advanced API only to be used when the `TEST` macros are insufficient. -The macros should be preferred when possible, as they avoid most of the -complexity of calling this function. - -It provides the following signature: - -```c++ -template -TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, - const char* type_param, const char* value_param, - const char* file, int line, Factory factory); -``` - -The `factory` argument is a factory callable (move-constructible) object or -function pointer that creates a new instance of the Test object. It handles -ownership to the caller. The signature of the callable is `Fixture*()`, where -`Fixture` is the test fixture class for the test. All tests registered with the -same `test_suite_name` must return the same fixture type. This is checked at -runtime. - -The framework will infer the fixture class from the factory and will call the -`SetUpTestSuite` and `TearDownTestSuite` for it. - -Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is -undefined. - -Use case example: - -```c++ -class MyFixture : public testing::Test { - public: - // All of these optional, just like in regular macro usage. - static void SetUpTestSuite() { ... } - static void TearDownTestSuite() { ... } - void SetUp() override { ... } - void TearDown() override { ... } -}; - -class MyTest : public MyFixture { - public: - explicit MyTest(int data) : data_(data) {} - void TestBody() override { ... } - - private: - int data_; -}; - -void RegisterMyTests(const std::vector& values) { - for (int v : values) { - testing::RegisterTest( - "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr, - std::to_string(v).c_str(), - __FILE__, __LINE__, - // Important to use the fixture type as the return type here. - [=]() -> MyFixture* { return new MyTest(v); }); - } -} -... -int main(int argc, char** argv) { - std::vector values_to_test = LoadValuesFromConfig(); - RegisterMyTests(values_to_test); - ... - return RUN_ALL_TESTS(); -} -``` -## Getting the Current Test's Name - -Sometimes a function may need to know the name of the currently running test. -For example, you may be using the `SetUp()` method of your test fixture to set -the golden file name based on which test is running. The `::testing::TestInfo` -class has this information: - -```c++ -namespace testing { - -class TestInfo { - public: - // Returns the test suite name and the test name, respectively. - // - // Do NOT delete or free the return value - it's managed by the - // TestInfo class. - const char* test_suite_name() const; - const char* name() const; -}; - -} -``` - -To obtain a `TestInfo` object for the currently running test, call -`current_test_info()` on the `UnitTest` singleton object: - -```c++ - // Gets information about the currently running test. - // Do NOT delete the returned object - it's managed by the UnitTest class. - const testing::TestInfo* const test_info = - testing::UnitTest::GetInstance()->current_test_info(); - - printf("We are in test %s of test suite %s.\n", - test_info->name(), - test_info->test_suite_name()); -``` - -`current_test_info()` returns a null pointer if no test is running. In -particular, you cannot find the test suite name in `SetUpTestSuite()`, -`TearDownTestSuite()` (where you know the test suite name implicitly), or -functions called from them. - -## Extending googletest by Handling Test Events - -googletest provides an **event listener API** to let you receive notifications -about the progress of a test program and test failures. The events you can -listen to include the start and end of the test program, a test suite, or a test -method, among others. You may use this API to augment or replace the standard -console output, replace the XML output, or provide a completely different form -of output, such as a GUI or a database. You can also use test events as -checkpoints to implement a resource leak checker, for example. - -### Defining Event Listeners - -To define a event listener, you subclass either testing::TestEventListener or -testing::EmptyTestEventListener The former is an (abstract) interface, where -*each pure virtual method can be overridden to handle a test event* (For -example, when a test starts, the `OnTestStart()` method will be called.). The -latter provides an empty implementation of all methods in the interface, such -that a subclass only needs to override the methods it cares about. - -When an event is fired, its context is passed to the handler function as an -argument. The following argument types are used: - -* UnitTest reflects the state of the entire test program, -* TestSuite has information about a test suite, which can contain one or more - tests, -* TestInfo contains the state of a test, and -* TestPartResult represents the result of a test assertion. - -An event handler function can examine the argument it receives to find out -interesting information about the event and the test program's state. - -Here's an example: - -```c++ - class MinimalistPrinter : public testing::EmptyTestEventListener { - // Called before a test starts. - void OnTestStart(const testing::TestInfo& test_info) override { - printf("*** Test %s.%s starting.\n", - test_info.test_suite_name(), test_info.name()); - } - - // Called after a failed assertion or a SUCCESS(). - void OnTestPartResult(const testing::TestPartResult& test_part_result) override { - printf("%s in %s:%d\n%s\n", - test_part_result.failed() ? "*** Failure" : "Success", - test_part_result.file_name(), - test_part_result.line_number(), - test_part_result.summary()); - } - - // Called after a test ends. - void OnTestEnd(const testing::TestInfo& test_info) override { - printf("*** Test %s.%s ending.\n", - test_info.test_suite_name(), test_info.name()); - } - }; -``` - -### Using Event Listeners - -To use the event listener you have defined, add an instance of it to the -googletest event listener list (represented by class TestEventListeners - note -the "s" at the end of the name) in your `main()` function, before calling -`RUN_ALL_TESTS()`: - -```c++ -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - // Gets hold of the event listener list. - testing::TestEventListeners& listeners = - testing::UnitTest::GetInstance()->listeners(); - // Adds a listener to the end. googletest takes the ownership. - listeners.Append(new MinimalistPrinter); - return RUN_ALL_TESTS(); -} -``` - -There's only one problem: the default test result printer is still in effect, so -its output will mingle with the output from your minimalist printer. To suppress -the default printer, just release it from the event listener list and delete it. -You can do so by adding one line: - -```c++ - ... - delete listeners.Release(listeners.default_result_printer()); - listeners.Append(new MinimalistPrinter); - return RUN_ALL_TESTS(); -``` - -Now, sit back and enjoy a completely different output from your tests. For more -details, see [sample9_unittest.cc]. - -[sample9_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample9_unittest.cc "Event listener example" - -You may append more than one listener to the list. When an `On*Start()` or -`OnTestPartResult()` event is fired, the listeners will receive it in the order -they appear in the list (since new listeners are added to the end of the list, -the default text printer and the default XML generator will receive the event -first). An `On*End()` event will be received by the listeners in the *reverse* -order. This allows output by listeners added later to be framed by output from -listeners added earlier. - -### Generating Failures in Listeners - -You may use failure-raising macros (`EXPECT_*()`, `ASSERT_*()`, `FAIL()`, etc) -when processing an event. There are some restrictions: - -1. You cannot generate any failure in `OnTestPartResult()` (otherwise it will - cause `OnTestPartResult()` to be called recursively). -2. A listener that handles `OnTestPartResult()` is not allowed to generate any - failure. - -When you add listeners to the listener list, you should put listeners that -handle `OnTestPartResult()` *before* listeners that can generate failures. This -ensures that failures generated by the latter are attributed to the right test -by the former. - -See [sample10_unittest.cc] for an example of a failure-raising listener. - -[sample10_unittest.cc]: https://github.com/google/googletest/blob/master/googletest/samples/sample10_unittest.cc "Failure-raising listener example" - -## Running Test Programs: Advanced Options - -googletest test programs are ordinary executables. Once built, you can run them -directly and affect their behavior via the following environment variables -and/or command line flags. For the flags to work, your programs must call -`::testing::InitGoogleTest()` before calling `RUN_ALL_TESTS()`. - -To see a list of supported flags and their usage, please run your test program -with the `--help` flag. You can also use `-h`, `-?`, or `/?` for short. - -If an option is specified both by an environment variable and by a flag, the -latter takes precedence. - -### Selecting Tests - -#### Listing Test Names - -Sometimes it is necessary to list the available tests in a program before -running them so that a filter may be applied if needed. Including the flag -`--gtest_list_tests` overrides all other flags and lists tests in the following -format: - -```none -TestSuite1. - TestName1 - TestName2 -TestSuite2. - TestName -``` - -None of the tests listed are actually run if the flag is provided. There is no -corresponding environment variable for this flag. - -#### Running a Subset of the Tests - -By default, a googletest program runs all tests the user has defined. Sometimes, -you want to run only a subset of the tests (e.g. for debugging or quickly -verifying a change). If you set the `GTEST_FILTER` environment variable or the -`--gtest_filter` flag to a filter string, googletest will only run the tests -whose full names (in the form of `TestSuiteName.TestName`) match the filter. - -The format of a filter is a '`:`'-separated list of wildcard patterns (called -the *positive patterns*) optionally followed by a '`-`' and another -'`:`'-separated pattern list (called the *negative patterns*). A test matches -the filter if and only if it matches any of the positive patterns but does not -match any of the negative patterns. - -A pattern may contain `'*'` (matches any string) or `'?'` (matches any single -character). For convenience, the filter `'*-NegativePatterns'` can be also -written as `'-NegativePatterns'`. - -For example: - -* `./foo_test` Has no flag, and thus runs all its tests. -* `./foo_test --gtest_filter=*` Also runs everything, due to the single - match-everything `*` value. -* `./foo_test --gtest_filter=FooTest.*` Runs everything in test suite - `FooTest` . -* `./foo_test --gtest_filter=*Null*:*Constructor*` Runs any test whose full - name contains either `"Null"` or `"Constructor"` . -* `./foo_test --gtest_filter=-*DeathTest.*` Runs all non-death tests. -* `./foo_test --gtest_filter=FooTest.*-FooTest.Bar` Runs everything in test - suite `FooTest` except `FooTest.Bar`. -* `./foo_test --gtest_filter=FooTest.*:BarTest.*-FooTest.Bar:BarTest.Foo` Runs - everything in test suite `FooTest` except `FooTest.Bar` and everything in - test suite `BarTest` except `BarTest.Foo`. - -#### Stop test execution upon first failure - -By default, a googletest program runs all tests the user has defined. In some -cases (e.g. iterative test development & execution) it may be desirable stop -test execution upon first failure (trading improved latency for completeness). -If `GTEST_FAIL_FAST` environment variable or `--gtest_fail_fast` flag is set, -the test runner will stop execution as soon as the first test failure is -found. - -#### Temporarily Disabling Tests - -If you have a broken test that you cannot fix right away, you can add the -`DISABLED_` prefix to its name. This will exclude it from execution. This is -better than commenting out the code or using `#if 0`, as disabled tests are -still compiled (and thus won't rot). - -If you need to disable all tests in a test suite, you can either add `DISABLED_` -to the front of the name of each test, or alternatively add it to the front of -the test suite name. - -For example, the following tests won't be run by googletest, even though they -will still be compiled: - -```c++ -// Tests that Foo does Abc. -TEST(FooTest, DISABLED_DoesAbc) { ... } - -class DISABLED_BarTest : public testing::Test { ... }; - -// Tests that Bar does Xyz. -TEST_F(DISABLED_BarTest, DoesXyz) { ... } -``` - -{: .callout .note} -NOTE: This feature should only be used for temporary pain-relief. You still have -to fix the disabled tests at a later date. As a reminder, googletest will print -a banner warning you if a test program contains any disabled tests. - -{: .callout .tip} -TIP: You can easily count the number of disabled tests you have using -`grep`. This number can be used as a metric for -improving your test quality. - -#### Temporarily Enabling Disabled Tests - -To include disabled tests in test execution, just invoke the test program with -the `--gtest_also_run_disabled_tests` flag or set the -`GTEST_ALSO_RUN_DISABLED_TESTS` environment variable to a value other than `0`. -You can combine this with the `--gtest_filter` flag to further select which -disabled tests to run. - -### Repeating the Tests - -Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it -will fail only 1% of the time, making it rather hard to reproduce the bug under -a debugger. This can be a major source of frustration. - -The `--gtest_repeat` flag allows you to repeat all (or selected) test methods in -a program many times. Hopefully, a flaky test will eventually fail and give you -a chance to debug. Here's how to use it: - -```none -$ foo_test --gtest_repeat=1000 -Repeat foo_test 1000 times and don't stop at failures. - -$ foo_test --gtest_repeat=-1 -A negative count means repeating forever. - -$ foo_test --gtest_repeat=1000 --gtest_break_on_failure -Repeat foo_test 1000 times, stopping at the first failure. This -is especially useful when running under a debugger: when the test -fails, it will drop into the debugger and you can then inspect -variables and stacks. - -$ foo_test --gtest_repeat=1000 --gtest_filter=FooBar.* -Repeat the tests whose name matches the filter 1000 times. -``` - -If your test program contains -[global set-up/tear-down](#global-set-up-and-tear-down) code, it will be -repeated in each iteration as well, as the flakiness may be in it. You can also -specify the repeat count by setting the `GTEST_REPEAT` environment variable. - -### Shuffling the Tests - -You can specify the `--gtest_shuffle` flag (or set the `GTEST_SHUFFLE` -environment variable to `1`) to run the tests in a program in a random order. -This helps to reveal bad dependencies between tests. - -By default, googletest uses a random seed calculated from the current time. -Therefore you'll get a different order every time. The console output includes -the random seed value, such that you can reproduce an order-related test failure -later. To specify the random seed explicitly, use the `--gtest_random_seed=SEED` -flag (or set the `GTEST_RANDOM_SEED` environment variable), where `SEED` is an -integer in the range [0, 99999]. The seed value 0 is special: it tells -googletest to do the default behavior of calculating the seed from the current -time. - -If you combine this with `--gtest_repeat=N`, googletest will pick a different -random seed and re-shuffle the tests in each iteration. - -### Controlling Test Output - -#### Colored Terminal Output - -googletest can use colors in its terminal output to make it easier to spot the -important information: - -
...
-[----------] 1 test from FooTest
-[ RUN      ] FooTest.DoesAbc
-[       OK ] FooTest.DoesAbc
-[----------] 2 tests from BarTest
-[ RUN      ] BarTest.HasXyzProperty
-[       OK ] BarTest.HasXyzProperty
-[ RUN      ] BarTest.ReturnsTrueOnSuccess
-... some error messages ...
-[   FAILED ] BarTest.ReturnsTrueOnSuccess
-...
-[==========] 30 tests from 14 test suites ran.
-[   PASSED ] 28 tests.
-[   FAILED ] 2 tests, listed below:
-[   FAILED ] BarTest.ReturnsTrueOnSuccess
-[   FAILED ] AnotherTest.DoesXyz
-
- 2 FAILED TESTS
-
- -You can set the `GTEST_COLOR` environment variable or the `--gtest_color` -command line flag to `yes`, `no`, or `auto` (the default) to enable colors, -disable colors, or let googletest decide. When the value is `auto`, googletest -will use colors if and only if the output goes to a terminal and (on non-Windows -platforms) the `TERM` environment variable is set to `xterm` or `xterm-color`. - -#### Suppressing test passes - -By default, googletest prints 1 line of output for each test, indicating if it -passed or failed. To show only test failures, run the test program with -`--gtest_brief=1`, or set the GTEST_BRIEF environment variable to `1`. - -#### Suppressing the Elapsed Time - -By default, googletest prints the time it takes to run each test. To disable -that, run the test program with the `--gtest_print_time=0` command line flag, or -set the GTEST_PRINT_TIME environment variable to `0`. - -#### Suppressing UTF-8 Text Output - -In case of assertion failures, googletest prints expected and actual values of -type `string` both as hex-encoded strings as well as in readable UTF-8 text if -they contain valid non-ASCII UTF-8 characters. If you want to suppress the UTF-8 -text because, for example, you don't have an UTF-8 compatible output medium, run -the test program with `--gtest_print_utf8=0` or set the `GTEST_PRINT_UTF8` -environment variable to `0`. - - - -#### Generating an XML Report - -googletest can emit a detailed XML report to a file in addition to its normal -textual output. The report contains the duration of each test, and thus can help -you identify slow tests. - -To generate the XML report, set the `GTEST_OUTPUT` environment variable or the -`--gtest_output` flag to the string `"xml:path_to_output_file"`, which will -create the file at the given location. You can also just use the string `"xml"`, -in which case the output can be found in the `test_detail.xml` file in the -current directory. - -If you specify a directory (for example, `"xml:output/directory/"` on Linux or -`"xml:output\directory\"` on Windows), googletest will create the XML file in -that directory, named after the test executable (e.g. `foo_test.xml` for test -program `foo_test` or `foo_test.exe`). If the file already exists (perhaps left -over from a previous run), googletest will pick a different name (e.g. -`foo_test_1.xml`) to avoid overwriting it. - -The report is based on the `junitreport` Ant task. Since that format was -originally intended for Java, a little interpretation is required to make it -apply to googletest tests, as shown here: - -```xml - - - - - - - - - -``` - -* The root `` element corresponds to the entire test program. -* `` elements correspond to googletest test suites. -* `` elements correspond to googletest test functions. - -For instance, the following program - -```c++ -TEST(MathTest, Addition) { ... } -TEST(MathTest, Subtraction) { ... } -TEST(LogicTest, NonContradiction) { ... } -``` - -could generate this report: - -```xml - - - - - ... - ... - - - - - - - - - -``` - -Things to note: - -* The `tests` attribute of a `` or `` element tells how - many test functions the googletest program or test suite contains, while the - `failures` attribute tells how many of them failed. - -* The `time` attribute expresses the duration of the test, test suite, or - entire test program in seconds. - -* The `timestamp` attribute records the local date and time of the test - execution. - -* Each `` element corresponds to a single failed googletest - assertion. - -#### Generating a JSON Report - -googletest can also emit a JSON report as an alternative format to XML. To -generate the JSON report, set the `GTEST_OUTPUT` environment variable or the -`--gtest_output` flag to the string `"json:path_to_output_file"`, which will -create the file at the given location. You can also just use the string -`"json"`, in which case the output can be found in the `test_detail.json` file -in the current directory. - -The report format conforms to the following JSON Schema: - -```json -{ - "$schema": "http://json-schema.org/schema#", - "type": "object", - "definitions": { - "TestCase": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "tests": { "type": "integer" }, - "failures": { "type": "integer" }, - "disabled": { "type": "integer" }, - "time": { "type": "string" }, - "testsuite": { - "type": "array", - "items": { - "$ref": "#/definitions/TestInfo" - } - } - } - }, - "TestInfo": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "status": { - "type": "string", - "enum": ["RUN", "NOTRUN"] - }, - "time": { "type": "string" }, - "classname": { "type": "string" }, - "failures": { - "type": "array", - "items": { - "$ref": "#/definitions/Failure" - } - } - } - }, - "Failure": { - "type": "object", - "properties": { - "failures": { "type": "string" }, - "type": { "type": "string" } - } - } - }, - "properties": { - "tests": { "type": "integer" }, - "failures": { "type": "integer" }, - "disabled": { "type": "integer" }, - "errors": { "type": "integer" }, - "timestamp": { - "type": "string", - "format": "date-time" - }, - "time": { "type": "string" }, - "name": { "type": "string" }, - "testsuites": { - "type": "array", - "items": { - "$ref": "#/definitions/TestCase" - } - } - } -} -``` - -The report uses the format that conforms to the following Proto3 using the -[JSON encoding](https://developers.google.com/protocol-buffers/docs/proto3#json): - -```proto -syntax = "proto3"; - -package googletest; - -import "google/protobuf/timestamp.proto"; -import "google/protobuf/duration.proto"; - -message UnitTest { - int32 tests = 1; - int32 failures = 2; - int32 disabled = 3; - int32 errors = 4; - google.protobuf.Timestamp timestamp = 5; - google.protobuf.Duration time = 6; - string name = 7; - repeated TestCase testsuites = 8; -} - -message TestCase { - string name = 1; - int32 tests = 2; - int32 failures = 3; - int32 disabled = 4; - int32 errors = 5; - google.protobuf.Duration time = 6; - repeated TestInfo testsuite = 7; -} - -message TestInfo { - string name = 1; - enum Status { - RUN = 0; - NOTRUN = 1; - } - Status status = 2; - google.protobuf.Duration time = 3; - string classname = 4; - message Failure { - string failures = 1; - string type = 2; - } - repeated Failure failures = 5; -} -``` - -For instance, the following program - -```c++ -TEST(MathTest, Addition) { ... } -TEST(MathTest, Subtraction) { ... } -TEST(LogicTest, NonContradiction) { ... } -``` - -could generate this report: - -```json -{ - "tests": 3, - "failures": 1, - "errors": 0, - "time": "0.035s", - "timestamp": "2011-10-31T18:52:42Z", - "name": "AllTests", - "testsuites": [ - { - "name": "MathTest", - "tests": 2, - "failures": 1, - "errors": 0, - "time": "0.015s", - "testsuite": [ - { - "name": "Addition", - "status": "RUN", - "time": "0.007s", - "classname": "", - "failures": [ - { - "message": "Value of: add(1, 1)\n Actual: 3\nExpected: 2", - "type": "" - }, - { - "message": "Value of: add(1, -1)\n Actual: 1\nExpected: 0", - "type": "" - } - ] - }, - { - "name": "Subtraction", - "status": "RUN", - "time": "0.005s", - "classname": "" - } - ] - }, - { - "name": "LogicTest", - "tests": 1, - "failures": 0, - "errors": 0, - "time": "0.005s", - "testsuite": [ - { - "name": "NonContradiction", - "status": "RUN", - "time": "0.005s", - "classname": "" - } - ] - } - ] -} -``` - -{: .callout .important} -IMPORTANT: The exact format of the JSON document is subject to change. - -### Controlling How Failures Are Reported - -#### Detecting Test Premature Exit - -Google Test implements the _premature-exit-file_ protocol for test runners -to catch any kind of unexpected exits of test programs. Upon start, -Google Test creates the file which will be automatically deleted after -all work has been finished. Then, the test runner can check if this file -exists. In case the file remains undeleted, the inspected test has exited -prematurely. - -This feature is enabled only if the `TEST_PREMATURE_EXIT_FILE` environment -variable has been set. - -#### Turning Assertion Failures into Break-Points - -When running test programs under a debugger, it's very convenient if the -debugger can catch an assertion failure and automatically drop into interactive -mode. googletest's *break-on-failure* mode supports this behavior. - -To enable it, set the `GTEST_BREAK_ON_FAILURE` environment variable to a value -other than `0`. Alternatively, you can use the `--gtest_break_on_failure` -command line flag. - -#### Disabling Catching Test-Thrown Exceptions - -googletest can be used either with or without exceptions enabled. If a test -throws a C++ exception or (on Windows) a structured exception (SEH), by default -googletest catches it, reports it as a test failure, and continues with the next -test method. This maximizes the coverage of a test run. Also, on Windows an -uncaught exception will cause a pop-up window, so catching the exceptions allows -you to run the tests automatically. - -When debugging the test failures, however, you may instead want the exceptions -to be handled by the debugger, such that you can examine the call stack when an -exception is thrown. To achieve that, set the `GTEST_CATCH_EXCEPTIONS` -environment variable to `0`, or use the `--gtest_catch_exceptions=0` flag when -running the tests. - -### Sanitizer Integration - -The -[Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html), -[Address Sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer), -and -[Thread Sanitizer](https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual) -all provide weak functions that you can override to trigger explicit failures -when they detect sanitizer errors, such as creating a reference from `nullptr`. -To override these functions, place definitions for them in a source file that -you compile as part of your main binary: - -``` -extern "C" { -void __ubsan_on_report() { - FAIL() << "Encountered an undefined behavior sanitizer error"; -} -void __asan_on_error() { - FAIL() << "Encountered an address sanitizer error"; -} -void __tsan_on_report() { - FAIL() << "Encountered a thread sanitizer error"; -} -} // extern "C" -``` - -After compiling your project with one of the sanitizers enabled, if a particular -test triggers a sanitizer error, googletest will report that it failed. diff --git a/vendor/googletest/gtest/docs/assets/css/style.scss b/vendor/googletest/gtest/docs/assets/css/style.scss deleted file mode 100644 index bb30f418..00000000 --- a/vendor/googletest/gtest/docs/assets/css/style.scss +++ /dev/null @@ -1,5 +0,0 @@ ---- ---- - -@import "jekyll-theme-primer"; -@import "main"; diff --git a/vendor/googletest/gtest/docs/community_created_documentation.md b/vendor/googletest/gtest/docs/community_created_documentation.md deleted file mode 100644 index 4569075f..00000000 --- a/vendor/googletest/gtest/docs/community_created_documentation.md +++ /dev/null @@ -1,7 +0,0 @@ -# Community-Created Documentation - -The following is a list, in no particular order, of links to documentation -created by the Googletest community. - -* [Googlemock Insights](https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/googletest/insights.md), - by [ElectricRCAircraftGuy](https://github.com/ElectricRCAircraftGuy) diff --git a/vendor/googletest/gtest/docs/faq.md b/vendor/googletest/gtest/docs/faq.md deleted file mode 100644 index 40712321..00000000 --- a/vendor/googletest/gtest/docs/faq.md +++ /dev/null @@ -1,756 +0,0 @@ -# Googletest FAQ - -## Why should test suite names and test names not contain underscore? - -{: .callout .note} -Note: Googletest reserves underscore (`_`) for special purpose keywords, such as -[the `DISABLED_` prefix](advanced.md#temporarily-disabling-tests), in addition -to the following rationale. - -Underscore (`_`) is special, as C++ reserves the following to be used by the -compiler and the standard library: - -1. any identifier that starts with an `_` followed by an upper-case letter, and -2. any identifier that contains two consecutive underscores (i.e. `__`) - *anywhere* in its name. - -User code is *prohibited* from using such identifiers. - -Now let's look at what this means for `TEST` and `TEST_F`. - -Currently `TEST(TestSuiteName, TestName)` generates a class named -`TestSuiteName_TestName_Test`. What happens if `TestSuiteName` or `TestName` -contains `_`? - -1. If `TestSuiteName` starts with an `_` followed by an upper-case letter (say, - `_Foo`), we end up with `_Foo_TestName_Test`, which is reserved and thus - invalid. -2. If `TestSuiteName` ends with an `_` (say, `Foo_`), we get - `Foo__TestName_Test`, which is invalid. -3. If `TestName` starts with an `_` (say, `_Bar`), we get - `TestSuiteName__Bar_Test`, which is invalid. -4. If `TestName` ends with an `_` (say, `Bar_`), we get - `TestSuiteName_Bar__Test`, which is invalid. - -So clearly `TestSuiteName` and `TestName` cannot start or end with `_` -(Actually, `TestSuiteName` can start with `_` -- as long as the `_` isn't -followed by an upper-case letter. But that's getting complicated. So for -simplicity we just say that it cannot start with `_`.). - -It may seem fine for `TestSuiteName` and `TestName` to contain `_` in the -middle. However, consider this: - -```c++ -TEST(Time, Flies_Like_An_Arrow) { ... } -TEST(Time_Flies, Like_An_Arrow) { ... } -``` - -Now, the two `TEST`s will both generate the same class -(`Time_Flies_Like_An_Arrow_Test`). That's not good. - -So for simplicity, we just ask the users to avoid `_` in `TestSuiteName` and -`TestName`. The rule is more constraining than necessary, but it's simple and -easy to remember. It also gives googletest some wiggle room in case its -implementation needs to change in the future. - -If you violate the rule, there may not be immediate consequences, but your test -may (just may) break with a new compiler (or a new version of the compiler you -are using) or with a new version of googletest. Therefore it's best to follow -the rule. - -## Why does googletest support `EXPECT_EQ(NULL, ptr)` and `ASSERT_EQ(NULL, ptr)` but not `EXPECT_NE(NULL, ptr)` and `ASSERT_NE(NULL, ptr)`? - -First of all, you can use `nullptr` with each of these macros, e.g. -`EXPECT_EQ(ptr, nullptr)`, `EXPECT_NE(ptr, nullptr)`, `ASSERT_EQ(ptr, nullptr)`, -`ASSERT_NE(ptr, nullptr)`. This is the preferred syntax in the style guide -because `nullptr` does not have the type problems that `NULL` does. - -Due to some peculiarity of C++, it requires some non-trivial template meta -programming tricks to support using `NULL` as an argument of the `EXPECT_XX()` -and `ASSERT_XX()` macros. Therefore we only do it where it's most needed -(otherwise we make the implementation of googletest harder to maintain and more -error-prone than necessary). - -Historically, the `EXPECT_EQ()` macro took the *expected* value as its first -argument and the *actual* value as the second, though this argument order is now -discouraged. It was reasonable that someone wanted -to write `EXPECT_EQ(NULL, some_expression)`, and this indeed was requested -several times. Therefore we implemented it. - -The need for `EXPECT_NE(NULL, ptr)` wasn't nearly as strong. When the assertion -fails, you already know that `ptr` must be `NULL`, so it doesn't add any -information to print `ptr` in this case. That means `EXPECT_TRUE(ptr != NULL)` -works just as well. - -If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'd have to -support `EXPECT_NE(ptr, NULL)` as well. This means using the template meta -programming tricks twice in the implementation, making it even harder to -understand and maintain. We believe the benefit doesn't justify the cost. - -Finally, with the growth of the gMock matcher library, we are encouraging people -to use the unified `EXPECT_THAT(value, matcher)` syntax more often in tests. One -significant advantage of the matcher approach is that matchers can be easily -combined to form new matchers, while the `EXPECT_NE`, etc, macros cannot be -easily combined. Therefore we want to invest more in the matchers than in the -`EXPECT_XX()` macros. - -## I need to test that different implementations of an interface satisfy some common requirements. Should I use typed tests or value-parameterized tests? - -For testing various implementations of the same interface, either typed tests or -value-parameterized tests can get it done. It's really up to you the user to -decide which is more convenient for you, depending on your particular case. Some -rough guidelines: - -* Typed tests can be easier to write if instances of the different - implementations can be created the same way, modulo the type. For example, - if all these implementations have a public default constructor (such that - you can write `new TypeParam`), or if their factory functions have the same - form (e.g. `CreateInstance()`). -* Value-parameterized tests can be easier to write if you need different code - patterns to create different implementations' instances, e.g. `new Foo` vs - `new Bar(5)`. To accommodate for the differences, you can write factory - function wrappers and pass these function pointers to the tests as their - parameters. -* When a typed test fails, the default output includes the name of the type, - which can help you quickly identify which implementation is wrong. - Value-parameterized tests only show the number of the failed iteration by - default. You will need to define a function that returns the iteration name - and pass it as the third parameter to INSTANTIATE_TEST_SUITE_P to have more - useful output. -* When using typed tests, you need to make sure you are testing against the - interface type, not the concrete types (in other words, you want to make - sure `implicit_cast(my_concrete_impl)` works, not just that - `my_concrete_impl` works). It's less likely to make mistakes in this area - when using value-parameterized tests. - -I hope I didn't confuse you more. :-) If you don't mind, I'd suggest you to give -both approaches a try. Practice is a much better way to grasp the subtle -differences between the two tools. Once you have some concrete experience, you -can much more easily decide which one to use the next time. - -## I got some run-time errors about invalid proto descriptors when using `ProtocolMessageEquals`. Help! - -{: .callout .note} -**Note:** `ProtocolMessageEquals` and `ProtocolMessageEquiv` are *deprecated* -now. Please use `EqualsProto`, etc instead. - -`ProtocolMessageEquals` and `ProtocolMessageEquiv` were redefined recently and -are now less tolerant of invalid protocol buffer definitions. In particular, if -you have a `foo.proto` that doesn't fully qualify the type of a protocol message -it references (e.g. `message` where it should be `message`), you -will now get run-time errors like: - -``` -... descriptor.cc:...] Invalid proto descriptor for file "path/to/foo.proto": -... descriptor.cc:...] blah.MyMessage.my_field: ".Bar" is not defined. -``` - -If you see this, your `.proto` file is broken and needs to be fixed by making -the types fully qualified. The new definition of `ProtocolMessageEquals` and -`ProtocolMessageEquiv` just happen to reveal your bug. - -## My death test modifies some state, but the change seems lost after the death test finishes. Why? - -Death tests (`EXPECT_DEATH`, etc) are executed in a sub-process s.t. the -expected crash won't kill the test program (i.e. the parent process). As a -result, any in-memory side effects they incur are observable in their respective -sub-processes, but not in the parent process. You can think of them as running -in a parallel universe, more or less. - -In particular, if you use mocking and the death test statement invokes some mock -methods, the parent process will think the calls have never occurred. Therefore, -you may want to move your `EXPECT_CALL` statements inside the `EXPECT_DEATH` -macro. - -## EXPECT_EQ(htonl(blah), blah_blah) generates weird compiler errors in opt mode. Is this a googletest bug? - -Actually, the bug is in `htonl()`. - -According to `'man htonl'`, `htonl()` is a *function*, which means it's valid to -use `htonl` as a function pointer. However, in opt mode `htonl()` is defined as -a *macro*, which breaks this usage. - -Worse, the macro definition of `htonl()` uses a `gcc` extension and is *not* -standard C++. That hacky implementation has some ad hoc limitations. In -particular, it prevents you from writing `Foo()`, where `Foo` -is a template that has an integral argument. - -The implementation of `EXPECT_EQ(a, b)` uses `sizeof(... a ...)` inside a -template argument, and thus doesn't compile in opt mode when `a` contains a call -to `htonl()`. It is difficult to make `EXPECT_EQ` bypass the `htonl()` bug, as -the solution must work with different compilers on various platforms. - -## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? - -If your class has a static data member: - -```c++ -// foo.h -class Foo { - ... - static const int kBar = 100; -}; -``` - -You also need to define it *outside* of the class body in `foo.cc`: - -```c++ -const int Foo::kBar; // No initializer here. -``` - -Otherwise your code is **invalid C++**, and may break in unexpected ways. In -particular, using it in googletest comparison assertions (`EXPECT_EQ`, etc) will -generate an "undefined reference" linker error. The fact that "it used to work" -doesn't mean it's valid. It just means that you were lucky. :-) - -If the declaration of the static data member is `constexpr` then it is -implicitly an `inline` definition, and a separate definition in `foo.cc` is not -needed: - -```c++ -// foo.h -class Foo { - ... - static constexpr int kBar = 100; // Defines kBar, no need to do it in foo.cc. -}; -``` - -## Can I derive a test fixture from another? - -Yes. - -Each test fixture has a corresponding and same named test suite. This means only -one test suite can use a particular fixture. Sometimes, however, multiple test -cases may want to use the same or slightly different fixtures. For example, you -may want to make sure that all of a GUI library's test suites don't leak -important system resources like fonts and brushes. - -In googletest, you share a fixture among test suites by putting the shared logic -in a base test fixture, then deriving from that base a separate fixture for each -test suite that wants to use this common logic. You then use `TEST_F()` to write -tests using each derived fixture. - -Typically, your code looks like this: - -```c++ -// Defines a base test fixture. -class BaseTest : public ::testing::Test { - protected: - ... -}; - -// Derives a fixture FooTest from BaseTest. -class FooTest : public BaseTest { - protected: - void SetUp() override { - BaseTest::SetUp(); // Sets up the base fixture first. - ... additional set-up work ... - } - - void TearDown() override { - ... clean-up work for FooTest ... - BaseTest::TearDown(); // Remember to tear down the base fixture - // after cleaning up FooTest! - } - - ... functions and variables for FooTest ... -}; - -// Tests that use the fixture FooTest. -TEST_F(FooTest, Bar) { ... } -TEST_F(FooTest, Baz) { ... } - -... additional fixtures derived from BaseTest ... -``` - -If necessary, you can continue to derive test fixtures from a derived fixture. -googletest has no limit on how deep the hierarchy can be. - -For a complete example using derived test fixtures, see -[sample5_unittest.cc](https://github.com/google/googletest/blob/master/googletest/samples/sample5_unittest.cc). - -## My compiler complains "void value not ignored as it ought to be." What does this mean? - -You're probably using an `ASSERT_*()` in a function that doesn't return `void`. -`ASSERT_*()` can only be used in `void` functions, due to exceptions being -disabled by our build system. Please see more details -[here](advanced.md#assertion-placement). - -## My death test hangs (or seg-faults). How do I fix it? - -In googletest, death tests are run in a child process and the way they work is -delicate. To write death tests you really need to understand how they work. -Please make sure you have read [this](advanced.md#how-it-works). - -In particular, death tests don't like having multiple threads in the parent -process. So the first thing you can try is to eliminate creating threads outside -of `EXPECT_DEATH()`. For example, you may want to use mocks or fake objects -instead of real ones in your tests. - -Sometimes this is impossible as some library you must use may be creating -threads before `main()` is even reached. In this case, you can try to minimize -the chance of conflicts by either moving as many activities as possible inside -`EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or -leaving as few things as possible in it. Also, you can try to set the death test -style to `"threadsafe"`, which is safer but slower, and see if it helps. - -If you go with thread-safe death tests, remember that they rerun the test -program from the beginning in the child process. Therefore make sure your -program can run side-by-side with itself and is deterministic. - -In the end, this boils down to good concurrent programming. You have to make -sure that there are no race conditions or deadlocks in your program. No silver -bullet - sorry! - -## Should I use the constructor/destructor of the test fixture or SetUp()/TearDown()? {#CtorVsSetUp} - -The first thing to remember is that googletest does **not** reuse the same test -fixture object across multiple tests. For each `TEST_F`, googletest will create -a **fresh** test fixture object, immediately call `SetUp()`, run the test body, -call `TearDown()`, and then delete the test fixture object. - -When you need to write per-test set-up and tear-down logic, you have the choice -between using the test fixture constructor/destructor or `SetUp()/TearDown()`. -The former is usually preferred, as it has the following benefits: - -* By initializing a member variable in the constructor, we have the option to - make it `const`, which helps prevent accidental changes to its value and - makes the tests more obviously correct. -* In case we need to subclass the test fixture class, the subclass' - constructor is guaranteed to call the base class' constructor *first*, and - the subclass' destructor is guaranteed to call the base class' destructor - *afterward*. With `SetUp()/TearDown()`, a subclass may make the mistake of - forgetting to call the base class' `SetUp()/TearDown()` or call them at the - wrong time. - -You may still want to use `SetUp()/TearDown()` in the following cases: - -* C++ does not allow virtual function calls in constructors and destructors. - You can call a method declared as virtual, but it will not use dynamic - dispatch, it will use the definition from the class the constructor of which - is currently executing. This is because calling a virtual method before the - derived class constructor has a chance to run is very dangerous - the - virtual method might operate on uninitialized data. Therefore, if you need - to call a method that will be overridden in a derived class, you have to use - `SetUp()/TearDown()`. -* In the body of a constructor (or destructor), it's not possible to use the - `ASSERT_xx` macros. Therefore, if the set-up operation could cause a fatal - test failure that should prevent the test from running, it's necessary to - use `abort` and abort the whole test - executable, or to use `SetUp()` instead of a constructor. -* If the tear-down operation could throw an exception, you must use - `TearDown()` as opposed to the destructor, as throwing in a destructor leads - to undefined behavior and usually will kill your program right away. Note - that many standard libraries (like STL) may throw when exceptions are - enabled in the compiler. Therefore you should prefer `TearDown()` if you - want to write portable tests that work with or without exceptions. -* The googletest team is considering making the assertion macros throw on - platforms where exceptions are enabled (e.g. Windows, Mac OS, and Linux - client-side), which will eliminate the need for the user to propagate - failures from a subroutine to its caller. Therefore, you shouldn't use - googletest assertions in a destructor if your code could run on such a - platform. - -## The compiler complains "no matching function to call" when I use ASSERT_PRED*. How do I fix it? - -If the predicate function you use in `ASSERT_PRED*` or `EXPECT_PRED*` is -overloaded or a template, the compiler will have trouble figuring out which -overloaded version it should use. `ASSERT_PRED_FORMAT*` and -`EXPECT_PRED_FORMAT*` don't have this problem. - -If you see this error, you might want to switch to -`(ASSERT|EXPECT)_PRED_FORMAT*`, which will also give you a better failure -message. If, however, that is not an option, you can resolve the problem by -explicitly telling the compiler which version to pick. - -For example, suppose you have - -```c++ -bool IsPositive(int n) { - return n > 0; -} - -bool IsPositive(double x) { - return x > 0; -} -``` - -you will get a compiler error if you write - -```c++ -EXPECT_PRED1(IsPositive, 5); -``` - -However, this will work: - -```c++ -EXPECT_PRED1(static_cast(IsPositive), 5); -``` - -(The stuff inside the angled brackets for the `static_cast` operator is the type -of the function pointer for the `int`-version of `IsPositive()`.) - -As another example, when you have a template function - -```c++ -template -bool IsNegative(T x) { - return x < 0; -} -``` - -you can use it in a predicate assertion like this: - -```c++ -ASSERT_PRED1(IsNegative, -5); -``` - -Things are more interesting if your template has more than one parameter. The -following won't compile: - -```c++ -ASSERT_PRED2(GreaterThan, 5, 0); -``` - -as the C++ pre-processor thinks you are giving `ASSERT_PRED2` 4 arguments, which -is one more than expected. The workaround is to wrap the predicate function in -parentheses: - -```c++ -ASSERT_PRED2((GreaterThan), 5, 0); -``` - -## My compiler complains about "ignoring return value" when I call RUN_ALL_TESTS(). Why? - -Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is, -instead of - -```c++ - return RUN_ALL_TESTS(); -``` - -they write - -```c++ - RUN_ALL_TESTS(); -``` - -This is **wrong and dangerous**. The testing services needs to see the return -value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your -`main()` function ignores it, your test will be considered successful even if it -has a googletest assertion failure. Very bad. - -We have decided to fix this (thanks to Michael Chastain for the idea). Now, your -code will no longer be able to ignore `RUN_ALL_TESTS()` when compiled with -`gcc`. If you do so, you'll get a compiler error. - -If you see the compiler complaining about you ignoring the return value of -`RUN_ALL_TESTS()`, the fix is simple: just make sure its value is used as the -return value of `main()`. - -But how could we introduce a change that breaks existing tests? Well, in this -case, the code was already broken in the first place, so we didn't break it. :-) - -## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? - -Due to a peculiarity of C++, in order to support the syntax for streaming -messages to an `ASSERT_*`, e.g. - -```c++ - ASSERT_EQ(1, Foo()) << "blah blah" << foo; -``` - -we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and -`ADD_FAILURE*`) in constructors and destructors. The workaround is to move the -content of your constructor/destructor to a private void member function, or -switch to `EXPECT_*()` if that works. This -[section](advanced.md#assertion-placement) in the user's guide explains it. - -## My SetUp() function is not called. Why? - -C++ is case-sensitive. Did you spell it as `Setup()`? - -Similarly, sometimes people spell `SetUpTestSuite()` as `SetupTestSuite()` and -wonder why it's never called. - - -## I have several test suites which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious. - -You don't have to. Instead of - -```c++ -class FooTest : public BaseTest {}; - -TEST_F(FooTest, Abc) { ... } -TEST_F(FooTest, Def) { ... } - -class BarTest : public BaseTest {}; - -TEST_F(BarTest, Abc) { ... } -TEST_F(BarTest, Def) { ... } -``` - -you can simply `typedef` the test fixtures: - -```c++ -typedef BaseTest FooTest; - -TEST_F(FooTest, Abc) { ... } -TEST_F(FooTest, Def) { ... } - -typedef BaseTest BarTest; - -TEST_F(BarTest, Abc) { ... } -TEST_F(BarTest, Def) { ... } -``` - -## googletest output is buried in a whole bunch of LOG messages. What do I do? - -The googletest output is meant to be a concise and human-friendly report. If -your test generates textual output itself, it will mix with the googletest -output, making it hard to read. However, there is an easy solution to this -problem. - -Since `LOG` messages go to stderr, we decided to let googletest output go to -stdout. This way, you can easily separate the two using redirection. For -example: - -```shell -$ ./my_test > gtest_output.txt -``` - -## Why should I prefer test fixtures over global variables? - -There are several good reasons: - -1. It's likely your test needs to change the states of its global variables. - This makes it difficult to keep side effects from escaping one test and - contaminating others, making debugging difficult. By using fixtures, each - test has a fresh set of variables that's different (but with the same - names). Thus, tests are kept independent of each other. -2. Global variables pollute the global namespace. -3. Test fixtures can be reused via subclassing, which cannot be done easily - with global variables. This is useful if many test suites have something in - common. - -## What can the statement argument in ASSERT_DEATH() be? - -`ASSERT_DEATH(statement, matcher)` (or any death assertion macro) can be used -wherever *`statement`* is valid. So basically *`statement`* can be any C++ -statement that makes sense in the current context. In particular, it can -reference global and/or local variables, and can be: - -* a simple function call (often the case), -* a complex expression, or -* a compound statement. - -Some examples are shown here: - -```c++ -// A death test can be a simple function call. -TEST(MyDeathTest, FunctionCall) { - ASSERT_DEATH(Xyz(5), "Xyz failed"); -} - -// Or a complex expression that references variables and functions. -TEST(MyDeathTest, ComplexExpression) { - const bool c = Condition(); - ASSERT_DEATH((c ? Func1(0) : object2.Method("test")), - "(Func1|Method) failed"); -} - -// Death assertions can be used anywhere in a function. In -// particular, they can be inside a loop. -TEST(MyDeathTest, InsideLoop) { - // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. - for (int i = 0; i < 5; i++) { - EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors", - ::testing::Message() << "where i is " << i); - } -} - -// A death assertion can contain a compound statement. -TEST(MyDeathTest, CompoundStatement) { - // Verifies that at lease one of Bar(0), Bar(1), ..., and - // Bar(4) dies. - ASSERT_DEATH({ - for (int i = 0; i < 5; i++) { - Bar(i); - } - }, - "Bar has \\d+ errors"); -} -``` - -## I have a fixture class `FooTest`, but `TEST_F(FooTest, Bar)` gives me error ``"no matching function for call to `FooTest::FooTest()'"``. Why? - -Googletest needs to be able to create objects of your test fixture class, so it -must have a default constructor. Normally the compiler will define one for you. -However, there are cases where you have to define your own: - -* If you explicitly declare a non-default constructor for class `FooTest` - (`DISALLOW_EVIL_CONSTRUCTORS()` does this), then you need to define a - default constructor, even if it would be empty. -* If `FooTest` has a const non-static data member, then you have to define the - default constructor *and* initialize the const member in the initializer - list of the constructor. (Early versions of `gcc` doesn't force you to - initialize the const member. It's a bug that has been fixed in `gcc 4`.) - -## Why does ASSERT_DEATH complain about previous threads that were already joined? - -With the Linux pthread library, there is no turning back once you cross the line -from a single thread to multiple threads. The first time you create a thread, a -manager thread is created in addition, so you get 3, not 2, threads. Later when -the thread you create joins the main thread, the thread count decrements by 1, -but the manager thread will never be killed, so you still have 2 threads, which -means you cannot safely run a death test. - -The new NPTL thread library doesn't suffer from this problem, as it doesn't -create a manager thread. However, if you don't control which machine your test -runs on, you shouldn't depend on this. - -## Why does googletest require the entire test suite, instead of individual tests, to be named *DeathTest when it uses ASSERT_DEATH? - -googletest does not interleave tests from different test suites. That is, it -runs all tests in one test suite first, and then runs all tests in the next test -suite, and so on. googletest does this because it needs to set up a test suite -before the first test in it is run, and tear it down afterwards. Splitting up -the test case would require multiple set-up and tear-down processes, which is -inefficient and makes the semantics unclean. - -If we were to determine the order of tests based on test name instead of test -case name, then we would have a problem with the following situation: - -```c++ -TEST_F(FooTest, AbcDeathTest) { ... } -TEST_F(FooTest, Uvw) { ... } - -TEST_F(BarTest, DefDeathTest) { ... } -TEST_F(BarTest, Xyz) { ... } -``` - -Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't -interleave tests from different test suites, we need to run all tests in the -`FooTest` case before running any test in the `BarTest` case. This contradicts -with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`. - -## But I don't like calling my entire test suite \*DeathTest when it contains both death tests and non-death tests. What do I do? - -You don't have to, but if you like, you may split up the test suite into -`FooTest` and `FooDeathTest`, where the names make it clear that they are -related: - -```c++ -class FooTest : public ::testing::Test { ... }; - -TEST_F(FooTest, Abc) { ... } -TEST_F(FooTest, Def) { ... } - -using FooDeathTest = FooTest; - -TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... } -TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... } -``` - -## googletest prints the LOG messages in a death test's child process only when the test fails. How can I see the LOG messages when the death test succeeds? - -Printing the LOG messages generated by the statement inside `EXPECT_DEATH()` -makes it harder to search for real problems in the parent's log. Therefore, -googletest only prints them when the death test has failed. - -If you really need to see such LOG messages, a workaround is to temporarily -break the death test (e.g. by changing the regex pattern it is expected to -match). Admittedly, this is a hack. We'll consider a more permanent solution -after the fork-and-exec-style death tests are implemented. - -## The compiler complains about `no match for 'operator<<'` when I use an assertion. What gives? - -If you use a user-defined type `FooType` in an assertion, you must make sure -there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function -defined such that we can print a value of `FooType`. - -In addition, if `FooType` is declared in a name space, the `<<` operator also -needs to be defined in the *same* name space. See -[Tip of the Week #49](http://abseil.io/tips/49) for details. - -## How do I suppress the memory leak messages on Windows? - -Since the statically initialized googletest singleton requires allocations on -the heap, the Visual C++ memory leak detector will report memory leaks at the -end of the program run. The easiest way to avoid this is to use the -`_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any -statically initialized heap objects. See MSDN for more details and additional -heap check/debug routines. - -## How can my code detect if it is running in a test? - -If you write code that sniffs whether it's running in a test and does different -things accordingly, you are leaking test-only logic into production code and -there is no easy way to ensure that the test-only code paths aren't run by -mistake in production. Such cleverness also leads to -[Heisenbugs](https://en.wikipedia.org/wiki/Heisenbug). Therefore we strongly -advise against the practice, and googletest doesn't provide a way to do it. - -In general, the recommended way to cause the code to behave differently under -test is [Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection). You can inject -different functionality from the test and from the production code. Since your -production code doesn't link in the for-test logic at all (the -[`testonly`](http://docs.bazel.build/versions/master/be/common-definitions.html#common.testonly) attribute for BUILD targets helps to ensure -that), there is no danger in accidentally running it. - -However, if you *really*, *really*, *really* have no choice, and if you follow -the rule of ending your test program names with `_test`, you can use the -*horrible* hack of sniffing your executable name (`argv[0]` in `main()`) to know -whether the code is under test. - -## How do I temporarily disable a test? - -If you have a broken test that you cannot fix right away, you can add the -`DISABLED_` prefix to its name. This will exclude it from execution. This is -better than commenting out the code or using `#if 0`, as disabled tests are -still compiled (and thus won't rot). - -To include disabled tests in test execution, just invoke the test program with -the `--gtest_also_run_disabled_tests` flag. - -## Is it OK if I have two separate `TEST(Foo, Bar)` test methods defined in different namespaces? - -Yes. - -The rule is **all test methods in the same test suite must use the same fixture -class.** This means that the following is **allowed** because both tests use the -same fixture class (`::testing::Test`). - -```c++ -namespace foo { -TEST(CoolTest, DoSomething) { - SUCCEED(); -} -} // namespace foo - -namespace bar { -TEST(CoolTest, DoSomething) { - SUCCEED(); -} -} // namespace bar -``` - -However, the following code is **not allowed** and will produce a runtime error -from googletest because the test methods are using different test fixture -classes with the same test suite name. - -```c++ -namespace foo { -class CoolTest : public ::testing::Test {}; // Fixture foo::CoolTest -TEST_F(CoolTest, DoSomething) { - SUCCEED(); -} -} // namespace foo - -namespace bar { -class CoolTest : public ::testing::Test {}; // Fixture: bar::CoolTest -TEST_F(CoolTest, DoSomething) { - SUCCEED(); -} -} // namespace bar -``` diff --git a/vendor/googletest/gtest/docs/gmock_cheat_sheet.md b/vendor/googletest/gtest/docs/gmock_cheat_sheet.md deleted file mode 100644 index 90be4a3e..00000000 --- a/vendor/googletest/gtest/docs/gmock_cheat_sheet.md +++ /dev/null @@ -1,762 +0,0 @@ -# gMock Cheat Sheet - -## Defining a Mock Class - -### Mocking a Normal Class {#MockClass} - -Given - -```cpp -class Foo { - ... - virtual ~Foo(); - virtual int GetSize() const = 0; - virtual string Describe(const char* name) = 0; - virtual string Describe(int type) = 0; - virtual bool Process(Bar elem, int count) = 0; -}; -``` - -(note that `~Foo()` **must** be virtual) we can define its mock as - -```cpp -#include "gmock/gmock.h" - -class MockFoo : public Foo { - ... - MOCK_METHOD(int, GetSize, (), (const, override)); - MOCK_METHOD(string, Describe, (const char* name), (override)); - MOCK_METHOD(string, Describe, (int type), (override)); - MOCK_METHOD(bool, Process, (Bar elem, int count), (override)); -}; -``` - -To create a "nice" mock, which ignores all uninteresting calls, a "naggy" mock, -which warns on all uninteresting calls, or a "strict" mock, which treats them as -failures: - -```cpp -using ::testing::NiceMock; -using ::testing::NaggyMock; -using ::testing::StrictMock; - -NiceMock nice_foo; // The type is a subclass of MockFoo. -NaggyMock naggy_foo; // The type is a subclass of MockFoo. -StrictMock strict_foo; // The type is a subclass of MockFoo. -``` - -{: .callout .note} -**Note:** A mock object is currently naggy by default. We may make it nice by -default in the future. - -### Mocking a Class Template {#MockTemplate} - -Class templates can be mocked just like any class. - -To mock - -```cpp -template -class StackInterface { - ... - virtual ~StackInterface(); - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; -``` - -(note that all member functions that are mocked, including `~StackInterface()` -**must** be virtual). - -```cpp -template -class MockStack : public StackInterface { - ... - MOCK_METHOD(int, GetSize, (), (const, override)); - MOCK_METHOD(void, Push, (const Elem& x), (override)); -}; -``` - -### Specifying Calling Conventions for Mock Functions - -If your mock function doesn't use the default calling convention, you can -specify it by adding `Calltype(convention)` to `MOCK_METHOD`'s 4th parameter. -For example, - -```cpp - MOCK_METHOD(bool, Foo, (int n), (Calltype(STDMETHODCALLTYPE))); - MOCK_METHOD(int, Bar, (double x, double y), - (const, Calltype(STDMETHODCALLTYPE))); -``` - -where `STDMETHODCALLTYPE` is defined by `` on Windows. - -## Using Mocks in Tests {#UsingMocks} - -The typical work flow is: - -1. Import the gMock names you need to use. All gMock symbols are in the - `testing` namespace unless they are macros or otherwise noted. -2. Create the mock objects. -3. Optionally, set the default actions of the mock objects. -4. Set your expectations on the mock objects (How will they be called? What - will they do?). -5. Exercise code that uses the mock objects; if necessary, check the result - using googletest assertions. -6. When a mock object is destructed, gMock automatically verifies that all - expectations on it have been satisfied. - -Here's an example: - -```cpp -using ::testing::Return; // #1 - -TEST(BarTest, DoesThis) { - MockFoo foo; // #2 - - ON_CALL(foo, GetSize()) // #3 - .WillByDefault(Return(1)); - // ... other default actions ... - - EXPECT_CALL(foo, Describe(5)) // #4 - .Times(3) - .WillRepeatedly(Return("Category 5")); - // ... other expectations ... - - EXPECT_EQ(MyProductionFunction(&foo), "good"); // #5 -} // #6 -``` - -## Setting Default Actions {#OnCall} - -gMock has a **built-in default action** for any function that returns `void`, -`bool`, a numeric value, or a pointer. In C++11, it will additionally returns -the default-constructed value, if one exists for the given type. - -To customize the default action for functions with return type *`T`*: - -```cpp -using ::testing::DefaultValue; - -// Sets the default value to be returned. T must be CopyConstructible. -DefaultValue::Set(value); -// Sets a factory. Will be invoked on demand. T must be MoveConstructible. -// T MakeT(); -DefaultValue::SetFactory(&MakeT); -// ... use the mocks ... -// Resets the default value. -DefaultValue::Clear(); -``` - -Example usage: - -```cpp - // Sets the default action for return type std::unique_ptr to - // creating a new Buzz every time. - DefaultValue>::SetFactory( - [] { return MakeUnique(AccessLevel::kInternal); }); - - // When this fires, the default action of MakeBuzz() will run, which - // will return a new Buzz object. - EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")).Times(AnyNumber()); - - auto buzz1 = mock_buzzer_.MakeBuzz("hello"); - auto buzz2 = mock_buzzer_.MakeBuzz("hello"); - EXPECT_NE(buzz1, nullptr); - EXPECT_NE(buzz2, nullptr); - EXPECT_NE(buzz1, buzz2); - - // Resets the default action for return type std::unique_ptr, - // to avoid interfere with other tests. - DefaultValue>::Clear(); -``` - -To customize the default action for a particular method of a specific mock -object, use `ON_CALL()`. `ON_CALL()` has a similar syntax to `EXPECT_CALL()`, -but it is used for setting default behaviors (when you do not require that the -mock method is called). See [here](gmock_cook_book.md#UseOnCall) for a more -detailed discussion. - -```cpp -ON_CALL(mock-object, method(matchers)) - .With(multi-argument-matcher) ? - .WillByDefault(action); -``` - -## Setting Expectations {#ExpectCall} - -`EXPECT_CALL()` sets **expectations** on a mock method (How will it be called? -What will it do?): - -```cpp -EXPECT_CALL(mock-object, method (matchers)?) - .With(multi-argument-matcher) ? - .Times(cardinality) ? - .InSequence(sequences) * - .After(expectations) * - .WillOnce(action) * - .WillRepeatedly(action) ? - .RetiresOnSaturation(); ? -``` - -For each item above, `?` means it can be used at most once, while `*` means it -can be used any number of times. - -In order to pass, `EXPECT_CALL` must be used before the calls are actually made. - -The `(matchers)` is a comma-separated list of matchers that correspond to each -of the arguments of `method`, and sets the expectation only for calls of -`method` that matches all of the matchers. - -If `(matchers)` is omitted, the expectation is the same as if the matchers were -set to anything matchers (for example, `(_, _, _, _)` for a four-arg method). - -If `Times()` is omitted, the cardinality is assumed to be: - -* `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`; -* `Times(n)` when there are `n` `WillOnce()`s but no `WillRepeatedly()`, where - `n` >= 1; or -* `Times(AtLeast(n))` when there are `n` `WillOnce()`s and a - `WillRepeatedly()`, where `n` >= 0. - -A method with no `EXPECT_CALL()` is free to be invoked *any number of times*, -and the default action will be taken each time. - -## Matchers {#MatcherList} - -A **matcher** matches a *single* argument. You can use it inside `ON_CALL()` or -`EXPECT_CALL()`, or use it to validate a value directly using two macros: - -| Macro | Description | -| :----------------------------------- | :------------------------------------ | -| `EXPECT_THAT(actual_value, matcher)` | Asserts that `actual_value` matches `matcher`. | -| `ASSERT_THAT(actual_value, matcher)` | The same as `EXPECT_THAT(actual_value, matcher)`, except that it generates a **fatal** failure. | - -{: .callout .note} -**Note:** Although equality matching via `EXPECT_THAT(actual_value, -expected_value)` is supported, prefer to make the comparison explicit via -`EXPECT_THAT(actual_value, Eq(expected_value))` or `EXPECT_EQ(actual_value, -expected_value)`. - -Built-in matchers (where `argument` is the function argument, e.g. -`actual_value` in the example above, or when used in the context of -`EXPECT_CALL(mock_object, method(matchers))`, the arguments of `method`) are -divided into several categories: - -### Wildcard - -Matcher | Description -:-------------------------- | :----------------------------------------------- -`_` | `argument` can be any value of the correct type. -`A()` or `An()` | `argument` can be any value of type `type`. - -### Generic Comparison - -| Matcher | Description | -| :--------------------- | :-------------------------------------------------- | -| `Eq(value)` or `value` | `argument == value` | -| `Ge(value)` | `argument >= value` | -| `Gt(value)` | `argument > value` | -| `Le(value)` | `argument <= value` | -| `Lt(value)` | `argument < value` | -| `Ne(value)` | `argument != value` | -| `IsFalse()` | `argument` evaluates to `false` in a Boolean context. | -| `IsTrue()` | `argument` evaluates to `true` in a Boolean context. | -| `IsNull()` | `argument` is a `NULL` pointer (raw or smart). | -| `NotNull()` | `argument` is a non-null pointer (raw or smart). | -| `Optional(m)` | `argument` is `optional<>` that contains a value matching `m`. (For testing whether an `optional<>` is set, check for equality with `nullopt`. You may need to use `Eq(nullopt)` if the inner type doesn't have `==`.)| -| `VariantWith(m)` | `argument` is `variant<>` that holds the alternative of type T with a value matching `m`. | -| `Ref(variable)` | `argument` is a reference to `variable`. | -| `TypedEq(value)` | `argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded. | - -Except `Ref()`, these matchers make a *copy* of `value` in case it's modified or -destructed later. If the compiler complains that `value` doesn't have a public -copy constructor, try wrap it in `std::ref()`, e.g. -`Eq(std::ref(non_copyable_value))`. If you do that, make sure -`non_copyable_value` is not changed afterwards, or the meaning of your matcher -will be changed. - -`IsTrue` and `IsFalse` are useful when you need to use a matcher, or for types -that can be explicitly converted to Boolean, but are not implicitly converted to -Boolean. In other cases, you can use the basic -[`EXPECT_TRUE` and `EXPECT_FALSE`](primer.md#basic-assertions) assertions. - -### Floating-Point Matchers {#FpMatchers} - -| Matcher | Description | -| :------------------------------- | :--------------------------------- | -| `DoubleEq(a_double)` | `argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal. | -| `FloatEq(a_float)` | `argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. | -| `NanSensitiveDoubleEq(a_double)` | `argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. | -| `NanSensitiveFloatEq(a_float)` | `argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. | -| `IsNan()` | `argument` is any floating-point type with a NaN value. | - -The above matchers use ULP-based comparison (the same as used in googletest). -They automatically pick a reasonable error bound based on the absolute value of -the expected value. `DoubleEq()` and `FloatEq()` conform to the IEEE standard, -which requires comparing two NaNs for equality to return false. The -`NanSensitive*` version instead treats two NaNs as equal, which is often what a -user wants. - -| Matcher | Description | -| :------------------------------------------------ | :----------------------- | -| `DoubleNear(a_double, max_abs_error)` | `argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | -| `FloatNear(a_float, max_abs_error)` | `argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. | -| `NanSensitiveDoubleNear(a_double, max_abs_error)` | `argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. | -| `NanSensitiveFloatNear(a_float, max_abs_error)` | `argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. | - -### String Matchers - -The `argument` can be either a C string or a C++ string object: - -| Matcher | Description | -| :---------------------- | :------------------------------------------------- | -| `ContainsRegex(string)` | `argument` matches the given regular expression. | -| `EndsWith(suffix)` | `argument` ends with string `suffix`. | -| `HasSubstr(string)` | `argument` contains `string` as a sub-string. | -| `IsEmpty()` | `argument` is an empty string. | -| `MatchesRegex(string)` | `argument` matches the given regular expression with the match starting at the first character and ending at the last character. | -| `StartsWith(prefix)` | `argument` starts with string `prefix`. | -| `StrCaseEq(string)` | `argument` is equal to `string`, ignoring case. | -| `StrCaseNe(string)` | `argument` is not equal to `string`, ignoring case. | -| `StrEq(string)` | `argument` is equal to `string`. | -| `StrNe(string)` | `argument` is not equal to `string`. | - -`ContainsRegex()` and `MatchesRegex()` take ownership of the `RE` object. They -use the regular expression syntax defined -[here](advanced.md#regular-expression-syntax). All of these matchers, except -`ContainsRegex()` and `MatchesRegex()` work for wide strings as well. - -### Container Matchers - -Most STL-style containers support `==`, so you can use `Eq(expected_container)` -or simply `expected_container` to match a container exactly. If you want to -write the elements in-line, match them more flexibly, or get more informative -messages, you can use: - -| Matcher | Description | -| :---------------------------------------- | :------------------------------- | -| `BeginEndDistanceIs(m)` | `argument` is a container whose `begin()` and `end()` iterators are separated by a number of increments matching `m`. E.g. `BeginEndDistanceIs(2)` or `BeginEndDistanceIs(Lt(2))`. For containers that define a `size()` method, `SizeIs(m)` may be more efficient. | -| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. | -| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. | -| `Each(e)` | `argument` is a container where *every* element matches `e`, which can be either a value or a matcher. | -| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the *i*-th element matches `ei`, which can be a value or a matcher. | -| `ElementsAreArray({e0, e1, ..., en})`, `ElementsAreArray(a_container)`, `ElementsAreArray(begin, end)`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, iterator range, or C-style array. | -| `IsEmpty()` | `argument` is an empty container (`container.empty()`). | -| `IsSubsetOf({e0, e1, ..., en})`, `IsSubsetOf(a_container)`, `IsSubsetOf(begin, end)`, `IsSubsetOf(array)`, or `IsSubsetOf(array, count)` | `argument` matches `UnorderedElementsAre(x0, x1, ..., xk)` for some subset `{x0, x1, ..., xk}` of the expected matchers. | -| `IsSupersetOf({e0, e1, ..., en})`, `IsSupersetOf(a_container)`, `IsSupersetOf(begin, end)`, `IsSupersetOf(array)`, or `IsSupersetOf(array, count)` | Some subset of `argument` matches `UnorderedElementsAre(`expected matchers`)`. | -| `Pointwise(m, container)`, `Pointwise(m, {e0, e1, ..., en})` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. | -| `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. | -| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under *some* permutation of the elements, each element matches an `ei` (for a different `i`), which can be a value or a matcher. | -| `UnorderedElementsAreArray({e0, e1, ..., en})`, `UnorderedElementsAreArray(a_container)`, `UnorderedElementsAreArray(begin, end)`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, iterator range, or C-style array. | -| `UnorderedPointwise(m, container)`, `UnorderedPointwise(m, {e0, e1, ..., en})` | Like `Pointwise(m, container)`, but ignores the order of elements. | -| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(ElementsAre(1, 2, 3))` verifies that `argument` contains elements 1, 2, and 3, ignoring order. | -| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater(), ElementsAre(3, 2, 1))`. | - -**Notes:** - -* These matchers can also match: - 1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), - and - 2. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, - int len)` -- see [Multi-argument Matchers](#MultiArgMatchers)). -* The array being matched may be multi-dimensional (i.e. its elements can be - arrays). -* `m` in `Pointwise(m, ...)` and `UnorderedPointwise(m, ...)` should be a - matcher for `::std::tuple` where `T` and `U` are the element type of - the actual container and the expected container, respectively. For example, - to compare two `Foo` containers where `Foo` doesn't support `operator==`, - one might write: - - ```cpp - using ::std::get; - MATCHER(FooEq, "") { - return std::get<0>(arg).Equals(std::get<1>(arg)); - } - ... - EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos)); - ``` - -### Member Matchers - -| Matcher | Description | -| :------------------------------ | :----------------------------------------- | -| `Field(&class::field, m)` | `argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. | -| `Field(field_name, &class::field, m)` | The same as the two-parameter version, but provides a better error message. | -| `Key(e)` | `argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`. | -| `Pair(m1, m2)` | `argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. | -| `FieldsAre(m...)` | `argument` is a compatible object where each field matches piecewise with the matchers `m...`. A compatible object is any that supports the `std::tuple_size`+`get(obj)` protocol. In C++17 and up this also supports types compatible with structured bindings, like aggregates. | -| `Property(&class::property, m)` | `argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. The method `property()` must take no argument and be declared as `const`. | -| `Property(property_name, &class::property, m)` | The same as the two-parameter version, but provides a better error message. - -**Notes:** - -* You can use `FieldsAre()` to match any type that supports structured - bindings, such as `std::tuple`, `std::pair`, `std::array`, and aggregate - types. For example: - - ```cpp - std::tuple my_tuple{7, "hello world"}; - EXPECT_THAT(my_tuple, FieldsAre(Ge(0), HasSubstr("hello"))); - - struct MyStruct { - int value = 42; - std::string greeting = "aloha"; - }; - MyStruct s; - EXPECT_THAT(s, FieldsAre(42, "aloha")); - ``` - -* Don't use `Property()` against member functions that you do not own, because - taking addresses of functions is fragile and generally not part of the - contract of the function. - -### Matching the Result of a Function, Functor, or Callback - -| Matcher | Description | -| :--------------- | :------------------------------------------------ | -| `ResultOf(f, m)` | `f(argument)` matches matcher `m`, where `f` is a function or functor. | - -### Pointer Matchers - -| Matcher | Description | -| :------------------------ | :---------------------------------------------- | -| `Address(m)` | the result of `std::addressof(argument)` matches `m`. | -| `Pointee(m)` | `argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`. | -| `Pointer(m)` | `argument` (either a smart pointer or a raw pointer) contains a pointer that matches `m`. `m` will match against the raw pointer regardless of the type of `argument`. | -| `WhenDynamicCastTo(m)` | when `argument` is passed through `dynamic_cast()`, it matches matcher `m`. | - -### Multi-argument Matchers {#MultiArgMatchers} - -Technically, all matchers match a *single* value. A "multi-argument" matcher is -just one that matches a *tuple*. The following matchers can be used to match a -tuple `(x, y)`: - -Matcher | Description -:------ | :---------- -`Eq()` | `x == y` -`Ge()` | `x >= y` -`Gt()` | `x > y` -`Le()` | `x <= y` -`Lt()` | `x < y` -`Ne()` | `x != y` - -You can use the following selectors to pick a subset of the arguments (or -reorder them) to participate in the matching: - -| Matcher | Description | -| :------------------------- | :---------------------------------------------- | -| `AllArgs(m)` | Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`. | -| `Args(m)` | The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`. | - -### Composite Matchers - -You can make a matcher from one or more other matchers: - -| Matcher | Description | -| :------------------------------- | :-------------------------------------- | -| `AllOf(m1, m2, ..., mn)` | `argument` matches all of the matchers `m1` to `mn`. | -| `AllOfArray({m0, m1, ..., mn})`, `AllOfArray(a_container)`, `AllOfArray(begin, end)`, `AllOfArray(array)`, or `AllOfArray(array, count)` | The same as `AllOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. | -| `AnyOf(m1, m2, ..., mn)` | `argument` matches at least one of the matchers `m1` to `mn`. | -| `AnyOfArray({m0, m1, ..., mn})`, `AnyOfArray(a_container)`, `AnyOfArray(begin, end)`, `AnyOfArray(array)`, or `AnyOfArray(array, count)` | The same as `AnyOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. | -| `Not(m)` | `argument` doesn't match matcher `m`. | - -### Adapters for Matchers - -| Matcher | Description | -| :---------------------- | :------------------------------------ | -| `MatcherCast(m)` | casts matcher `m` to type `Matcher`. | -| `SafeMatcherCast(m)` | [safely casts](gmock_cook_book.md#casting-matchers) matcher `m` to type `Matcher`. | -| `Truly(predicate)` | `predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor. | - -`AddressSatisfies(callback)` and `Truly(callback)` take ownership of `callback`, -which must be a permanent callback. - -### Using Matchers as Predicates {#MatchersAsPredicatesCheat} - -| Matcher | Description | -| :---------------------------- | :------------------------------------------ | -| `Matches(m)(value)` | evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor. | -| `ExplainMatchResult(m, value, result_listener)` | evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. | -| `Value(value, m)` | evaluates to `true` if `value` matches `m`. | - -### Defining Matchers - -| Matcher | Description | -| :----------------------------------- | :------------------------------------ | -| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. | -| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a matcher `IsDivisibleBy(n)` to match a number divisible by `n`. | -| `MATCHER_P2(IsBetween, a, b, absl::StrCat(negation ? "isn't" : "is", " between ", PrintToString(a), " and ", PrintToString(b))) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. | - -**Notes:** - -1. The `MATCHER*` macros cannot be used inside a function or class. -2. The matcher body must be *purely functional* (i.e. it cannot have any side - effect, and the result must not depend on anything other than the value - being matched and the matcher parameters). -3. You can use `PrintToString(x)` to convert a value `x` of any type to a - string. -4. You can use `ExplainMatchResult()` in a custom matcher to wrap another - matcher, for example: - - ```cpp - MATCHER_P(NestedPropertyMatches, matcher, "") { - return ExplainMatchResult(matcher, arg.nested().property(), result_listener); - } - ``` - -## Actions {#ActionList} - -**Actions** specify what a mock function should do when invoked. - -### Returning a Value - -| | | -| :-------------------------------- | :-------------------------------------------- | -| `Return()` | Return from a `void` mock function. | -| `Return(value)` | Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type at the time the expectation is set, not when the action is executed. | -| `ReturnArg()` | Return the `N`-th (0-based) argument. | -| `ReturnNew(a1, ..., ak)` | Return `new T(a1, ..., ak)`; a different object is created each time. | -| `ReturnNull()` | Return a null pointer. | -| `ReturnPointee(ptr)` | Return the value pointed to by `ptr`. | -| `ReturnRef(variable)` | Return a reference to `variable`. | -| `ReturnRefOfCopy(value)` | Return a reference to a copy of `value`; the copy lives as long as the action. | -| `ReturnRoundRobin({a1, ..., ak})` | Each call will return the next `ai` in the list, starting at the beginning when the end of the list is reached. | - -### Side Effects - -| | | -| :--------------------------------- | :-------------------------------------- | -| `Assign(&variable, value)` | Assign `value` to variable. | -| `DeleteArg()` | Delete the `N`-th (0-based) argument, which must be a pointer. | -| `SaveArg(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | -| `SaveArgPointee(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | -| `SetArgReferee(value)` | Assign `value` to the variable referenced by the `N`-th (0-based) argument. | -| `SetArgPointee(value)` | Assign `value` to the variable pointed by the `N`-th (0-based) argument. | -| `SetArgumentPointee(value)` | Same as `SetArgPointee(value)`. Deprecated. Will be removed in v1.7.0. | -| `SetArrayArgument(first, last)` | Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range. | -| `SetErrnoAndReturn(error, value)` | Set `errno` to `error` and return `value`. | -| `Throw(exception)` | Throws the given exception, which can be any copyable value. Available since v1.1.0. | - -### Using a Function, Functor, or Lambda as an Action - -In the following, by "callable" we mean a free function, `std::function`, -functor, or lambda. - -| | | -| :---------------------------------- | :------------------------------------- | -| `f` | Invoke f with the arguments passed to the mock function, where f is a callable. | -| `Invoke(f)` | Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor. | -| `Invoke(object_pointer, &class::method)` | Invoke the method on the object with the arguments passed to the mock function. | -| `InvokeWithoutArgs(f)` | Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. | -| `InvokeWithoutArgs(object_pointer, &class::method)` | Invoke the method on the object, which takes no arguments. | -| `InvokeArgument(arg1, arg2, ..., argk)` | Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments. | - -The return value of the invoked function is used as the return value of the -action. - -When defining a callable to be used with `Invoke*()`, you can declare any unused -parameters as `Unused`: - -```cpp -using ::testing::Invoke; -double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); } -... -EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance)); -``` - -`Invoke(callback)` and `InvokeWithoutArgs(callback)` take ownership of -`callback`, which must be permanent. The type of `callback` must be a base -callback type instead of a derived one, e.g. - -```cpp - BlockingClosure* done = new BlockingClosure; - ... Invoke(done) ...; // This won't compile! - - Closure* done2 = new BlockingClosure; - ... Invoke(done2) ...; // This works. -``` - -In `InvokeArgument(...)`, if an argument needs to be passed by reference, -wrap it inside `std::ref()`. For example, - -```cpp -using ::testing::InvokeArgument; -... -InvokeArgument<2>(5, string("Hi"), std::ref(foo)) -``` - -calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by -value, and `foo` by reference. - -### Default Action - -| Matcher | Description | -| :------------ | :----------------------------------------------------- | -| `DoDefault()` | Do the default action (specified by `ON_CALL()` or the built-in one). | - -{: .callout .note} -**Note:** due to technical reasons, `DoDefault()` cannot be used inside a -composite action - trying to do so will result in a run-time error. - -### Composite Actions - -| | | -| :----------------------------- | :------------------------------------------ | -| `DoAll(a1, a2, ..., an)` | Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void and will receive a readonly view of the arguments. | -| `IgnoreResult(a)` | Perform action `a` and ignore its result. `a` must not return void. | -| `WithArg(a)` | Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. | -| `WithArgs(a)` | Pass the selected (0-based) arguments of the mock function to action `a` and perform it. | -| `WithoutArgs(a)` | Perform action `a` without any arguments. | - -### Defining Actions - -| | | -| :--------------------------------- | :-------------------------------------- | -| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. | -| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. | -| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. | - -The `ACTION*` macros cannot be used inside a function or class. - -## Cardinalities {#CardinalityList} - -These are used in `Times()` to specify how many times a mock function will be -called: - -| | | -| :---------------- | :----------------------------------------------------- | -| `AnyNumber()` | The function can be called any number of times. | -| `AtLeast(n)` | The call is expected at least `n` times. | -| `AtMost(n)` | The call is expected at most `n` times. | -| `Between(m, n)` | The call is expected between `m` and `n` (inclusive) times. | -| `Exactly(n) or n` | The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0. | - -## Expectation Order - -By default, the expectations can be matched in *any* order. If some or all -expectations must be matched in a given order, there are two ways to specify it. -They can be used either independently or together. - -### The After Clause {#AfterClause} - -```cpp -using ::testing::Expectation; -... -Expectation init_x = EXPECT_CALL(foo, InitX()); -Expectation init_y = EXPECT_CALL(foo, InitY()); -EXPECT_CALL(foo, Bar()) - .After(init_x, init_y); -``` - -says that `Bar()` can be called only after both `InitX()` and `InitY()` have -been called. - -If you don't know how many pre-requisites an expectation has when you write it, -you can use an `ExpectationSet` to collect them: - -```cpp -using ::testing::ExpectationSet; -... -ExpectationSet all_inits; -for (int i = 0; i < element_count; i++) { - all_inits += EXPECT_CALL(foo, InitElement(i)); -} -EXPECT_CALL(foo, Bar()) - .After(all_inits); -``` - -says that `Bar()` can be called only after all elements have been initialized -(but we don't care about which elements get initialized before the others). - -Modifying an `ExpectationSet` after using it in an `.After()` doesn't affect the -meaning of the `.After()`. - -### Sequences {#UsingSequences} - -When you have a long chain of sequential expectations, it's easier to specify -the order using **sequences**, which don't require you to given each expectation -in the chain a different name. *All expected calls* in the same sequence must -occur in the order they are specified. - -```cpp -using ::testing::Return; -using ::testing::Sequence; -Sequence s1, s2; -... -EXPECT_CALL(foo, Reset()) - .InSequence(s1, s2) - .WillOnce(Return(true)); -EXPECT_CALL(foo, GetSize()) - .InSequence(s1) - .WillOnce(Return(1)); -EXPECT_CALL(foo, Describe(A())) - .InSequence(s2) - .WillOnce(Return("dummy")); -``` - -says that `Reset()` must be called before *both* `GetSize()` *and* `Describe()`, -and the latter two can occur in any order. - -To put many expectations in a sequence conveniently: - -```cpp -using ::testing::InSequence; -{ - InSequence seq; - - EXPECT_CALL(...)...; - EXPECT_CALL(...)...; - ... - EXPECT_CALL(...)...; -} -``` - -says that all expected calls in the scope of `seq` must occur in strict order. -The name `seq` is irrelevant. - -## Verifying and Resetting a Mock - -gMock will verify the expectations on a mock object when it is destructed, or -you can do it earlier: - -```cpp -using ::testing::Mock; -... -// Verifies and removes the expectations on mock_obj; -// returns true if and only if successful. -Mock::VerifyAndClearExpectations(&mock_obj); -... -// Verifies and removes the expectations on mock_obj; -// also removes the default actions set by ON_CALL(); -// returns true if and only if successful. -Mock::VerifyAndClear(&mock_obj); -``` - -You can also tell gMock that a mock object can be leaked and doesn't need to be -verified: - -```cpp -Mock::AllowLeak(&mock_obj); -``` - -## Mock Classes - -gMock defines a convenient mock class template - -```cpp -class MockFunction { - public: - MOCK_METHOD(R, Call, (A1, ..., An)); -}; -``` - -See this [recipe](gmock_cook_book.md#using-check-points) for one application of -it. - -## Flags - -| Flag | Description | -| :----------------------------- | :---------------------------------------- | -| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. | -| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. | diff --git a/vendor/googletest/gtest/docs/gmock_cook_book.md b/vendor/googletest/gtest/docs/gmock_cook_book.md deleted file mode 100644 index c6a99912..00000000 --- a/vendor/googletest/gtest/docs/gmock_cook_book.md +++ /dev/null @@ -1,4352 +0,0 @@ -# gMock Cookbook - -You can find recipes for using gMock here. If you haven't yet, please read -[the dummy guide](gmock_for_dummies.md) first to make sure you understand the -basics. - -{: .callout .note} -**Note:** gMock lives in the `testing` name space. For readability, it is -recommended to write `using ::testing::Foo;` once in your file before using the -name `Foo` defined by gMock. We omit such `using` statements in this section for -brevity, but you should do it in your own code. - -## Creating Mock Classes - -Mock classes are defined as normal classes, using the `MOCK_METHOD` macro to -generate mocked methods. The macro gets 3 or 4 parameters: - -```cpp -class MyMock { - public: - MOCK_METHOD(ReturnType, MethodName, (Args...)); - MOCK_METHOD(ReturnType, MethodName, (Args...), (Specs...)); -}; -``` - -The first 3 parameters are simply the method declaration, split into 3 parts. -The 4th parameter accepts a closed list of qualifiers, which affect the -generated method: - -* **`const`** - Makes the mocked method a `const` method. Required if - overriding a `const` method. -* **`override`** - Marks the method with `override`. Recommended if overriding - a `virtual` method. -* **`noexcept`** - Marks the method with `noexcept`. Required if overriding a - `noexcept` method. -* **`Calltype(...)`** - Sets the call type for the method (e.g. to - `STDMETHODCALLTYPE`), useful in Windows. -* **`ref(...)`** - Marks the method with the reference qualification - specified. Required if overriding a method that has reference - qualifications. Eg `ref(&)` or `ref(&&)`. - -### Dealing with unprotected commas - -Unprotected commas, i.e. commas which are not surrounded by parentheses, prevent -`MOCK_METHOD` from parsing its arguments correctly: - -{: .bad} -```cpp -class MockFoo { - public: - MOCK_METHOD(std::pair, GetPair, ()); // Won't compile! - MOCK_METHOD(bool, CheckMap, (std::map, bool)); // Won't compile! -}; -``` - -Solution 1 - wrap with parentheses: - -{: .good} -```cpp -class MockFoo { - public: - MOCK_METHOD((std::pair), GetPair, ()); - MOCK_METHOD(bool, CheckMap, ((std::map), bool)); -}; -``` - -Note that wrapping a return or argument type with parentheses is, in general, -invalid C++. `MOCK_METHOD` removes the parentheses. - -Solution 2 - define an alias: - -{: .good} -```cpp -class MockFoo { - public: - using BoolAndInt = std::pair; - MOCK_METHOD(BoolAndInt, GetPair, ()); - using MapIntDouble = std::map; - MOCK_METHOD(bool, CheckMap, (MapIntDouble, bool)); -}; -``` - -### Mocking Private or Protected Methods - -You must always put a mock method definition (`MOCK_METHOD`) in a `public:` -section of the mock class, regardless of the method being mocked being `public`, -`protected`, or `private` in the base class. This allows `ON_CALL` and -`EXPECT_CALL` to reference the mock function from outside of the mock class. -(Yes, C++ allows a subclass to change the access level of a virtual function in -the base class.) Example: - -```cpp -class Foo { - public: - ... - virtual bool Transform(Gadget* g) = 0; - - protected: - virtual void Resume(); - - private: - virtual int GetTimeOut(); -}; - -class MockFoo : public Foo { - public: - ... - MOCK_METHOD(bool, Transform, (Gadget* g), (override)); - - // The following must be in the public section, even though the - // methods are protected or private in the base class. - MOCK_METHOD(void, Resume, (), (override)); - MOCK_METHOD(int, GetTimeOut, (), (override)); -}; -``` - -### Mocking Overloaded Methods - -You can mock overloaded functions as usual. No special attention is required: - -```cpp -class Foo { - ... - - // Must be virtual as we'll inherit from Foo. - virtual ~Foo(); - - // Overloaded on the types and/or numbers of arguments. - virtual int Add(Element x); - virtual int Add(int times, Element x); - - // Overloaded on the const-ness of this object. - virtual Bar& GetBar(); - virtual const Bar& GetBar() const; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD(int, Add, (Element x), (override)); - MOCK_METHOD(int, Add, (int times, Element x), (override)); - - MOCK_METHOD(Bar&, GetBar, (), (override)); - MOCK_METHOD(const Bar&, GetBar, (), (const, override)); -}; -``` - -{: .callout .note} -**Note:** if you don't mock all versions of the overloaded method, the compiler -will give you a warning about some methods in the base class being hidden. To -fix that, use `using` to bring them in scope: - -```cpp -class MockFoo : public Foo { - ... - using Foo::Add; - MOCK_METHOD(int, Add, (Element x), (override)); - // We don't want to mock int Add(int times, Element x); - ... -}; -``` - -### Mocking Class Templates - -You can mock class templates just like any class. - -```cpp -template -class StackInterface { - ... - // Must be virtual as we'll inherit from StackInterface. - virtual ~StackInterface(); - - virtual int GetSize() const = 0; - virtual void Push(const Elem& x) = 0; -}; - -template -class MockStack : public StackInterface { - ... - MOCK_METHOD(int, GetSize, (), (override)); - MOCK_METHOD(void, Push, (const Elem& x), (override)); -}; -``` - -### Mocking Non-virtual Methods {#MockingNonVirtualMethods} - -gMock can mock non-virtual functions to be used in Hi-perf dependency injection. - -In this case, instead of sharing a common base class with the real class, your -mock class will be *unrelated* to the real class, but contain methods with the -same signatures. The syntax for mocking non-virtual methods is the *same* as -mocking virtual methods (just don't add `override`): - -```cpp -// A simple packet stream class. None of its members is virtual. -class ConcretePacketStream { - public: - void AppendPacket(Packet* new_packet); - const Packet* GetPacket(size_t packet_number) const; - size_t NumberOfPackets() const; - ... -}; - -// A mock packet stream class. It inherits from no other, but defines -// GetPacket() and NumberOfPackets(). -class MockPacketStream { - public: - MOCK_METHOD(const Packet*, GetPacket, (size_t packet_number), (const)); - MOCK_METHOD(size_t, NumberOfPackets, (), (const)); - ... -}; -``` - -Note that the mock class doesn't define `AppendPacket()`, unlike the real class. -That's fine as long as the test doesn't need to call it. - -Next, you need a way to say that you want to use `ConcretePacketStream` in -production code, and use `MockPacketStream` in tests. Since the functions are -not virtual and the two classes are unrelated, you must specify your choice at -*compile time* (as opposed to run time). - -One way to do it is to templatize your code that needs to use a packet stream. -More specifically, you will give your code a template type argument for the type -of the packet stream. In production, you will instantiate your template with -`ConcretePacketStream` as the type argument. In tests, you will instantiate the -same template with `MockPacketStream`. For example, you may write: - -```cpp -template -void CreateConnection(PacketStream* stream) { ... } - -template -class PacketReader { - public: - void ReadPackets(PacketStream* stream, size_t packet_num); -}; -``` - -Then you can use `CreateConnection()` and -`PacketReader` in production code, and use -`CreateConnection()` and `PacketReader` in -tests. - -```cpp - MockPacketStream mock_stream; - EXPECT_CALL(mock_stream, ...)...; - .. set more expectations on mock_stream ... - PacketReader reader(&mock_stream); - ... exercise reader ... -``` - -### Mocking Free Functions - -It is not possible to directly mock a free function (i.e. a C-style function or -a static method). If you need to, you can rewrite your code to use an interface -(abstract class). - -Instead of calling a free function (say, `OpenFile`) directly, introduce an -interface for it and have a concrete subclass that calls the free function: - -```cpp -class FileInterface { - public: - ... - virtual bool Open(const char* path, const char* mode) = 0; -}; - -class File : public FileInterface { - public: - ... - bool Open(const char* path, const char* mode) override { - return OpenFile(path, mode); - } -}; -``` - -Your code should talk to `FileInterface` to open a file. Now it's easy to mock -out the function. - -This may seem like a lot of hassle, but in practice you often have multiple -related functions that you can put in the same interface, so the per-function -syntactic overhead will be much lower. - -If you are concerned about the performance overhead incurred by virtual -functions, and profiling confirms your concern, you can combine this with the -recipe for [mocking non-virtual methods](#MockingNonVirtualMethods). - -### Old-Style `MOCK_METHODn` Macros - -Before the generic `MOCK_METHOD` macro -[was introduced in 2018](https://github.com/google/googletest/commit/c5f08bf91944ce1b19bcf414fa1760e69d20afc2), -mocks where created using a family of macros collectively called `MOCK_METHODn`. -These macros are still supported, though migration to the new `MOCK_METHOD` is -recommended. - -The macros in the `MOCK_METHODn` family differ from `MOCK_METHOD`: - -* The general structure is `MOCK_METHODn(MethodName, ReturnType(Args))`, - instead of `MOCK_METHOD(ReturnType, MethodName, (Args))`. -* The number `n` must equal the number of arguments. -* When mocking a const method, one must use `MOCK_CONST_METHODn`. -* When mocking a class template, the macro name must be suffixed with `_T`. -* In order to specify the call type, the macro name must be suffixed with - `_WITH_CALLTYPE`, and the call type is the first macro argument. - -Old macros and their new equivalents: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simple
OldMOCK_METHOD1(Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int))
Const Method
OldMOCK_CONST_METHOD1(Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int), (const))
Method in a Class Template
OldMOCK_METHOD1_T(Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int))
Const Method in a Class Template
OldMOCK_CONST_METHOD1_T(Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int), (const))
Method with Call Type
OldMOCK_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int), (Calltype(STDMETHODCALLTYPE)))
Const Method with Call Type
OldMOCK_CONST_METHOD1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int), (const, Calltype(STDMETHODCALLTYPE)))
Method with Call Type in a Class Template
OldMOCK_METHOD1_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int), (Calltype(STDMETHODCALLTYPE)))
Const Method with Call Type in a Class Template
OldMOCK_CONST_METHOD1_T_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int))
NewMOCK_METHOD(bool, Foo, (int), (const, Calltype(STDMETHODCALLTYPE)))
- -### The Nice, the Strict, and the Naggy {#NiceStrictNaggy} - -If a mock method has no `EXPECT_CALL` spec but is called, we say that it's an -"uninteresting call", and the default action (which can be specified using -`ON_CALL()`) of the method will be taken. Currently, an uninteresting call will -also by default cause gMock to print a warning. (In the future, we might remove -this warning by default.) - -However, sometimes you may want to ignore these uninteresting calls, and -sometimes you may want to treat them as errors. gMock lets you make the decision -on a per-mock-object basis. - -Suppose your test uses a mock class `MockFoo`: - -```cpp -TEST(...) { - MockFoo mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -If a method of `mock_foo` other than `DoThis()` is called, you will get a -warning. However, if you rewrite your test to use `NiceMock` instead, -you can suppress the warning: - -```cpp -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -`NiceMock` is a subclass of `MockFoo`, so it can be used wherever -`MockFoo` is accepted. - -It also works if `MockFoo`'s constructor takes some arguments, as -`NiceMock` "inherits" `MockFoo`'s constructors: - -```cpp -using ::testing::NiceMock; - -TEST(...) { - NiceMock mock_foo(5, "hi"); // Calls MockFoo(5, "hi"). - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... -} -``` - -The usage of `StrictMock` is similar, except that it makes all uninteresting -calls failures: - -```cpp -using ::testing::StrictMock; - -TEST(...) { - StrictMock mock_foo; - EXPECT_CALL(mock_foo, DoThis()); - ... code that uses mock_foo ... - - // The test will fail if a method of mock_foo other than DoThis() - // is called. -} -``` - -{: .callout .note} -NOTE: `NiceMock` and `StrictMock` only affects *uninteresting* calls (calls of -*methods* with no expectations); they do not affect *unexpected* calls (calls of -methods with expectations, but they don't match). See -[Understanding Uninteresting vs Unexpected Calls](#uninteresting-vs-unexpected). - -There are some caveats though (sadly they are side effects of C++'s -limitations): - -1. `NiceMock` and `StrictMock` only work for mock methods - defined using the `MOCK_METHOD` macro **directly** in the `MockFoo` class. - If a mock method is defined in a **base class** of `MockFoo`, the "nice" or - "strict" modifier may not affect it, depending on the compiler. In - particular, nesting `NiceMock` and `StrictMock` (e.g. - `NiceMock >`) is **not** supported. -2. `NiceMock` and `StrictMock` may not work correctly if the - destructor of `MockFoo` is not virtual. We would like to fix this, but it - requires cleaning up existing tests. - -Finally, you should be **very cautious** about when to use naggy or strict -mocks, as they tend to make tests more brittle and harder to maintain. When you -refactor your code without changing its externally visible behavior, ideally you -shouldn't need to update any tests. If your code interacts with a naggy mock, -however, you may start to get spammed with warnings as the result of your -change. Worse, if your code interacts with a strict mock, your tests may start -to fail and you'll be forced to fix them. Our general recommendation is to use -nice mocks (not yet the default) most of the time, use naggy mocks (the current -default) when developing or debugging tests, and use strict mocks only as the -last resort. - -### Simplifying the Interface without Breaking Existing Code {#SimplerInterfaces} - -Sometimes a method has a long list of arguments that is mostly uninteresting. -For example: - -```cpp -class LogSink { - public: - ... - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct tm* tm_time, - const char* message, size_t message_len) = 0; -}; -``` - -This method's argument list is lengthy and hard to work with (the `message` -argument is not even 0-terminated). If we mock it as is, using the mock will be -awkward. If, however, we try to simplify this interface, we'll need to fix all -clients depending on it, which is often infeasible. - -The trick is to redispatch the method in the mock class: - -```cpp -class ScopedMockLog : public LogSink { - public: - ... - void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, const tm* tm_time, - const char* message, size_t message_len) override { - // We are only interested in the log severity, full file name, and - // log message. - Log(severity, full_filename, std::string(message, message_len)); - } - - // Implements the mock method: - // - // void Log(LogSeverity severity, - // const string& file_path, - // const string& message); - MOCK_METHOD(void, Log, - (LogSeverity severity, const string& file_path, - const string& message)); -}; -``` - -By defining a new mock method with a trimmed argument list, we make the mock -class more user-friendly. - -This technique may also be applied to make overloaded methods more amenable to -mocking. For example, when overloads have been used to implement default -arguments: - -```cpp -class MockTurtleFactory : public TurtleFactory { - public: - Turtle* MakeTurtle(int length, int weight) override { ... } - Turtle* MakeTurtle(int length, int weight, int speed) override { ... } - - // the above methods delegate to this one: - MOCK_METHOD(Turtle*, DoMakeTurtle, ()); -}; -``` - -This allows tests that don't care which overload was invoked to avoid specifying -argument matchers: - -```cpp -ON_CALL(factory, DoMakeTurtle) - .WillByDefault(Return(MakeMockTurtle())); -``` - -### Alternative to Mocking Concrete Classes - -Often you may find yourself using classes that don't implement interfaces. In -order to test your code that uses such a class (let's call it `Concrete`), you -may be tempted to make the methods of `Concrete` virtual and then mock it. - -Try not to do that. - -Making a non-virtual function virtual is a big decision. It creates an extension -point where subclasses can tweak your class' behavior. This weakens your control -on the class because now it's harder to maintain the class invariants. You -should make a function virtual only when there is a valid reason for a subclass -to override it. - -Mocking concrete classes directly is problematic as it creates a tight coupling -between the class and the tests - any small change in the class may invalidate -your tests and make test maintenance a pain. - -To avoid such problems, many programmers have been practicing "coding to -interfaces": instead of talking to the `Concrete` class, your code would define -an interface and talk to it. Then you implement that interface as an adaptor on -top of `Concrete`. In tests, you can easily mock that interface to observe how -your code is doing. - -This technique incurs some overhead: - -* You pay the cost of virtual function calls (usually not a problem). -* There is more abstraction for the programmers to learn. - -However, it can also bring significant benefits in addition to better -testability: - -* `Concrete`'s API may not fit your problem domain very well, as you may not - be the only client it tries to serve. By designing your own interface, you - have a chance to tailor it to your need - you may add higher-level - functionalities, rename stuff, etc instead of just trimming the class. This - allows you to write your code (user of the interface) in a more natural way, - which means it will be more readable, more maintainable, and you'll be more - productive. -* If `Concrete`'s implementation ever has to change, you don't have to rewrite - everywhere it is used. Instead, you can absorb the change in your - implementation of the interface, and your other code and tests will be - insulated from this change. - -Some people worry that if everyone is practicing this technique, they will end -up writing lots of redundant code. This concern is totally understandable. -However, there are two reasons why it may not be the case: - -* Different projects may need to use `Concrete` in different ways, so the best - interfaces for them will be different. Therefore, each of them will have its - own domain-specific interface on top of `Concrete`, and they will not be the - same code. -* If enough projects want to use the same interface, they can always share it, - just like they have been sharing `Concrete`. You can check in the interface - and the adaptor somewhere near `Concrete` (perhaps in a `contrib` - sub-directory) and let many projects use it. - -You need to weigh the pros and cons carefully for your particular problem, but -I'd like to assure you that the Java community has been practicing this for a -long time and it's a proven effective technique applicable in a wide variety of -situations. :-) - -### Delegating Calls to a Fake {#DelegatingToFake} - -Some times you have a non-trivial fake implementation of an interface. For -example: - -```cpp -class Foo { - public: - virtual ~Foo() {} - virtual char DoThis(int n) = 0; - virtual void DoThat(const char* s, int* p) = 0; -}; - -class FakeFoo : public Foo { - public: - char DoThis(int n) override { - return (n > 0) ? '+' : - (n < 0) ? '-' : '0'; - } - - void DoThat(const char* s, int* p) override { - *p = strlen(s); - } -}; -``` - -Now you want to mock this interface such that you can set expectations on it. -However, you also want to use `FakeFoo` for the default behavior, as duplicating -it in the mock object is, well, a lot of work. - -When you define the mock class using gMock, you can have it delegate its default -action to a fake class you already have, using this pattern: - -```cpp -class MockFoo : public Foo { - public: - // Normal mock method definitions using gMock. - MOCK_METHOD(char, DoThis, (int n), (override)); - MOCK_METHOD(void, DoThat, (const char* s, int* p), (override)); - - // Delegates the default actions of the methods to a FakeFoo object. - // This must be called *before* the custom ON_CALL() statements. - void DelegateToFake() { - ON_CALL(*this, DoThis).WillByDefault([this](int n) { - return fake_.DoThis(n); - }); - ON_CALL(*this, DoThat).WillByDefault([this](const char* s, int* p) { - fake_.DoThat(s, p); - }); - } - - private: - FakeFoo fake_; // Keeps an instance of the fake in the mock. -}; -``` - -With that, you can use `MockFoo` in your tests as usual. Just remember that if -you don't explicitly set an action in an `ON_CALL()` or `EXPECT_CALL()`, the -fake will be called upon to do it.: - -```cpp -using ::testing::_; - -TEST(AbcTest, Xyz) { - MockFoo foo; - - foo.DelegateToFake(); // Enables the fake for delegation. - - // Put your ON_CALL(foo, ...)s here, if any. - - // No action specified, meaning to use the default action. - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(foo, DoThat(_, _)); - - int n = 0; - EXPECT_EQ('+', foo.DoThis(5)); // FakeFoo::DoThis() is invoked. - foo.DoThat("Hi", &n); // FakeFoo::DoThat() is invoked. - EXPECT_EQ(2, n); -} -``` - -**Some tips:** - -* If you want, you can still override the default action by providing your own - `ON_CALL()` or using `.WillOnce()` / `.WillRepeatedly()` in `EXPECT_CALL()`. -* In `DelegateToFake()`, you only need to delegate the methods whose fake - implementation you intend to use. - -* The general technique discussed here works for overloaded methods, but - you'll need to tell the compiler which version you mean. To disambiguate a - mock function (the one you specify inside the parentheses of `ON_CALL()`), - use [this technique](#SelectOverload); to disambiguate a fake function (the - one you place inside `Invoke()`), use a `static_cast` to specify the - function's type. For instance, if class `Foo` has methods `char DoThis(int - n)` and `bool DoThis(double x) const`, and you want to invoke the latter, - you need to write `Invoke(&fake_, static_cast(&FakeFoo::DoThis))` instead of `Invoke(&fake_, &FakeFoo::DoThis)` - (The strange-looking thing inside the angled brackets of `static_cast` is - the type of a function pointer to the second `DoThis()` method.). - -* Having to mix a mock and a fake is often a sign of something gone wrong. - Perhaps you haven't got used to the interaction-based way of testing yet. Or - perhaps your interface is taking on too many roles and should be split up. - Therefore, **don't abuse this**. We would only recommend to do it as an - intermediate step when you are refactoring your code. - -Regarding the tip on mixing a mock and a fake, here's an example on why it may -be a bad sign: Suppose you have a class `System` for low-level system -operations. In particular, it does file and I/O operations. And suppose you want -to test how your code uses `System` to do I/O, and you just want the file -operations to work normally. If you mock out the entire `System` class, you'll -have to provide a fake implementation for the file operation part, which -suggests that `System` is taking on too many roles. - -Instead, you can define a `FileOps` interface and an `IOOps` interface and split -`System`'s functionalities into the two. Then you can mock `IOOps` without -mocking `FileOps`. - -### Delegating Calls to a Real Object - -When using testing doubles (mocks, fakes, stubs, and etc), sometimes their -behaviors will differ from those of the real objects. This difference could be -either intentional (as in simulating an error such that you can test the error -handling code) or unintentional. If your mocks have different behaviors than the -real objects by mistake, you could end up with code that passes the tests but -fails in production. - -You can use the *delegating-to-real* technique to ensure that your mock has the -same behavior as the real object while retaining the ability to validate calls. -This technique is very similar to the [delegating-to-fake](#DelegatingToFake) -technique, the difference being that we use a real object instead of a fake. -Here's an example: - -```cpp -using ::testing::AtLeast; - -class MockFoo : public Foo { - public: - MockFoo() { - // By default, all calls are delegated to the real object. - ON_CALL(*this, DoThis).WillByDefault([this](int n) { - return real_.DoThis(n); - }); - ON_CALL(*this, DoThat).WillByDefault([this](const char* s, int* p) { - real_.DoThat(s, p); - }); - ... - } - MOCK_METHOD(char, DoThis, ...); - MOCK_METHOD(void, DoThat, ...); - ... - private: - Foo real_; -}; - -... - MockFoo mock; - EXPECT_CALL(mock, DoThis()) - .Times(3); - EXPECT_CALL(mock, DoThat("Hi")) - .Times(AtLeast(1)); - ... use mock in test ... -``` - -With this, gMock will verify that your code made the right calls (with the right -arguments, in the right order, called the right number of times, etc), and a -real object will answer the calls (so the behavior will be the same as in -production). This gives you the best of both worlds. - -### Delegating Calls to a Parent Class - -Ideally, you should code to interfaces, whose methods are all pure virtual. In -reality, sometimes you do need to mock a virtual method that is not pure (i.e, -it already has an implementation). For example: - -```cpp -class Foo { - public: - virtual ~Foo(); - - virtual void Pure(int n) = 0; - virtual int Concrete(const char* str) { ... } -}; - -class MockFoo : public Foo { - public: - // Mocking a pure method. - MOCK_METHOD(void, Pure, (int n), (override)); - // Mocking a concrete method. Foo::Concrete() is shadowed. - MOCK_METHOD(int, Concrete, (const char* str), (override)); -}; -``` - -Sometimes you may want to call `Foo::Concrete()` instead of -`MockFoo::Concrete()`. Perhaps you want to do it as part of a stub action, or -perhaps your test doesn't need to mock `Concrete()` at all (but it would be -oh-so painful to have to define a new mock class whenever you don't need to mock -one of its methods). - -You can call `Foo::Concrete()` inside an action by: - -```cpp -... - EXPECT_CALL(foo, Concrete).WillOnce([&foo](const char* str) { - return foo.Foo::Concrete(str); - }); -``` - -or tell the mock object that you don't want to mock `Concrete()`: - -```cpp -... - ON_CALL(foo, Concrete).WillByDefault([&foo](const char* str) { - return foo.Foo::Concrete(str); - }); -``` - -(Why don't we just write `{ return foo.Concrete(str); }`? If you do that, -`MockFoo::Concrete()` will be called (and cause an infinite recursion) since -`Foo::Concrete()` is virtual. That's just how C++ works.) - -## Using Matchers - -### Matching Argument Values Exactly - -You can specify exactly which arguments a mock method is expecting: - -```cpp -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(5)) - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", bar)); -``` - -### Using Simple Matchers - -You can use matchers to match arguments that have a certain property: - -```cpp -using ::testing::NotNull; -using ::testing::Return; -... - EXPECT_CALL(foo, DoThis(Ge(5))) // The argument must be >= 5. - .WillOnce(Return('a')); - EXPECT_CALL(foo, DoThat("Hello", NotNull())); - // The second argument must not be NULL. -``` - -A frequently used matcher is `_`, which matches anything: - -```cpp - EXPECT_CALL(foo, DoThat(_, NotNull())); -``` - -### Combining Matchers {#CombiningMatchers} - -You can build complex matchers from existing ones using `AllOf()`, -`AllOfArray()`, `AnyOf()`, `AnyOfArray()` and `Not()`: - -```cpp -using ::testing::AllOf; -using ::testing::Gt; -using ::testing::HasSubstr; -using ::testing::Ne; -using ::testing::Not; -... - // The argument must be > 5 and != 10. - EXPECT_CALL(foo, DoThis(AllOf(Gt(5), - Ne(10)))); - - // The first argument must not contain sub-string "blah". - EXPECT_CALL(foo, DoThat(Not(HasSubstr("blah")), - NULL)); -``` - -Matchers are function objects, and parametrized matchers can be composed just -like any other function. However because their types can be long and rarely -provide meaningful information, it can be easier to express them with C++14 -generic lambdas to avoid specifying types. For example, - -```cpp -using ::testing::Contains; -using ::testing::Property; - -inline constexpr auto HasFoo = [](const auto& f) { - return Property(&MyClass::foo, Contains(f)); -}; -... - EXPECT_THAT(x, HasFoo("blah")); -``` - -### Casting Matchers {#SafeMatcherCast} - -gMock matchers are statically typed, meaning that the compiler can catch your -mistake if you use a matcher of the wrong type (for example, if you use `Eq(5)` -to match a `string` argument). Good for you! - -Sometimes, however, you know what you're doing and want the compiler to give you -some slack. One example is that you have a matcher for `long` and the argument -you want to match is `int`. While the two types aren't exactly the same, there -is nothing really wrong with using a `Matcher` to match an `int` - after -all, we can first convert the `int` argument to a `long` losslessly before -giving it to the matcher. - -To support this need, gMock gives you the `SafeMatcherCast(m)` function. It -casts a matcher `m` to type `Matcher`. To ensure safety, gMock checks that -(let `U` be the type `m` accepts : - -1. Type `T` can be *implicitly* cast to type `U`; -2. When both `T` and `U` are built-in arithmetic types (`bool`, integers, and - floating-point numbers), the conversion from `T` to `U` is not lossy (in - other words, any value representable by `T` can also be represented by `U`); - and -3. When `U` is a reference, `T` must also be a reference (as the underlying - matcher may be interested in the address of the `U` value). - -The code won't compile if any of these conditions isn't met. - -Here's one example: - -```cpp -using ::testing::SafeMatcherCast; - -// A base class and a child class. -class Base { ... }; -class Derived : public Base { ... }; - -class MockFoo : public Foo { - public: - MOCK_METHOD(void, DoThis, (Derived* derived), (override)); -}; - -... - MockFoo foo; - // m is a Matcher we got from somewhere. - EXPECT_CALL(foo, DoThis(SafeMatcherCast(m))); -``` - -If you find `SafeMatcherCast(m)` too limiting, you can use a similar function -`MatcherCast(m)`. The difference is that `MatcherCast` works as long as you -can `static_cast` type `T` to type `U`. - -`MatcherCast` essentially lets you bypass C++'s type system (`static_cast` isn't -always safe as it could throw away information, for example), so be careful not -to misuse/abuse it. - -### Selecting Between Overloaded Functions {#SelectOverload} - -If you expect an overloaded function to be called, the compiler may need some -help on which overloaded version it is. - -To disambiguate functions overloaded on the const-ness of this object, use the -`Const()` argument wrapper. - -```cpp -using ::testing::ReturnRef; - -class MockFoo : public Foo { - ... - MOCK_METHOD(Bar&, GetBar, (), (override)); - MOCK_METHOD(const Bar&, GetBar, (), (const, override)); -}; - -... - MockFoo foo; - Bar bar1, bar2; - EXPECT_CALL(foo, GetBar()) // The non-const GetBar(). - .WillOnce(ReturnRef(bar1)); - EXPECT_CALL(Const(foo), GetBar()) // The const GetBar(). - .WillOnce(ReturnRef(bar2)); -``` - -(`Const()` is defined by gMock and returns a `const` reference to its argument.) - -To disambiguate overloaded functions with the same number of arguments but -different argument types, you may need to specify the exact type of a matcher, -either by wrapping your matcher in `Matcher()`, or using a matcher whose -type is fixed (`TypedEq`, `An()`, etc): - -```cpp -using ::testing::An; -using ::testing::Matcher; -using ::testing::TypedEq; - -class MockPrinter : public Printer { - public: - MOCK_METHOD(void, Print, (int n), (override)); - MOCK_METHOD(void, Print, (char c), (override)); -}; - -TEST(PrinterTest, Print) { - MockPrinter printer; - - EXPECT_CALL(printer, Print(An())); // void Print(int); - EXPECT_CALL(printer, Print(Matcher(Lt(5)))); // void Print(int); - EXPECT_CALL(printer, Print(TypedEq('a'))); // void Print(char); - - printer.Print(3); - printer.Print(6); - printer.Print('a'); -} -``` - -### Performing Different Actions Based on the Arguments - -When a mock method is called, the *last* matching expectation that's still -active will be selected (think "newer overrides older"). So, you can make a -method do different things depending on its argument values like this: - -```cpp -using ::testing::_; -using ::testing::Lt; -using ::testing::Return; -... - // The default case. - EXPECT_CALL(foo, DoThis(_)) - .WillRepeatedly(Return('b')); - // The more specific case. - EXPECT_CALL(foo, DoThis(Lt(5))) - .WillRepeatedly(Return('a')); -``` - -Now, if `foo.DoThis()` is called with a value less than 5, `'a'` will be -returned; otherwise `'b'` will be returned. - -### Matching Multiple Arguments as a Whole - -Sometimes it's not enough to match the arguments individually. For example, we -may want to say that the first argument must be less than the second argument. -The `With()` clause allows us to match all arguments of a mock function as a -whole. For example, - -```cpp -using ::testing::_; -using ::testing::Ne; -using ::testing::Lt; -... - EXPECT_CALL(foo, InRange(Ne(0), _)) - .With(Lt()); -``` - -says that the first argument of `InRange()` must not be 0, and must be less than -the second argument. - -The expression inside `With()` must be a matcher of type `Matcher>`, where `A1`, ..., `An` are the types of the function arguments. - -You can also write `AllArgs(m)` instead of `m` inside `.With()`. The two forms -are equivalent, but `.With(AllArgs(Lt()))` is more readable than `.With(Lt())`. - -You can use `Args(m)` to match the `n` selected arguments (as a -tuple) against `m`. For example, - -```cpp -using ::testing::_; -using ::testing::AllOf; -using ::testing::Args; -using ::testing::Lt; -... - EXPECT_CALL(foo, Blah) - .With(AllOf(Args<0, 1>(Lt()), Args<1, 2>(Lt()))); -``` - -says that `Blah` will be called with arguments `x`, `y`, and `z` where `x < y < -z`. Note that in this example, it wasn't necessary specify the positional -matchers. - -As a convenience and example, gMock provides some matchers for 2-tuples, -including the `Lt()` matcher above. See [here](#MultiArgMatchers) for the -complete list. - -Note that if you want to pass the arguments to a predicate of your own (e.g. -`.With(Args<0, 1>(Truly(&MyPredicate)))`), that predicate MUST be written to -take a `std::tuple` as its argument; gMock will pass the `n` selected arguments -as *one* single tuple to the predicate. - -### Using Matchers as Predicates - -Have you noticed that a matcher is just a fancy predicate that also knows how to -describe itself? Many existing algorithms take predicates as arguments (e.g. -those defined in STL's `` header), and it would be a shame if gMock -matchers were not allowed to participate. - -Luckily, you can use a matcher where a unary predicate functor is expected by -wrapping it inside the `Matches()` function. For example, - -```cpp -#include -#include - -using ::testing::Matches; -using ::testing::Ge; - -vector v; -... -// How many elements in v are >= 10? -const int count = count_if(v.begin(), v.end(), Matches(Ge(10))); -``` - -Since you can build complex matchers from simpler ones easily using gMock, this -gives you a way to conveniently construct composite predicates (doing the same -using STL's `` header is just painful). For example, here's a -predicate that's satisfied by any number that is >= 0, <= 100, and != 50: - -```cpp -using testing::AllOf; -using testing::Ge; -using testing::Le; -using testing::Matches; -using testing::Ne; -... -Matches(AllOf(Ge(0), Le(100), Ne(50))) -``` - -### Using Matchers in googletest Assertions - -Since matchers are basically predicates that also know how to describe -themselves, there is a way to take advantage of them in googletest assertions. -It's called `ASSERT_THAT` and `EXPECT_THAT`: - -```cpp - ASSERT_THAT(value, matcher); // Asserts that value matches matcher. - EXPECT_THAT(value, matcher); // The non-fatal version. -``` - -For example, in a googletest test you can write: - -```cpp -#include "gmock/gmock.h" - -using ::testing::AllOf; -using ::testing::Ge; -using ::testing::Le; -using ::testing::MatchesRegex; -using ::testing::StartsWith; - -... - EXPECT_THAT(Foo(), StartsWith("Hello")); - EXPECT_THAT(Bar(), MatchesRegex("Line \\d+")); - ASSERT_THAT(Baz(), AllOf(Ge(5), Le(10))); -``` - -which (as you can probably guess) executes `Foo()`, `Bar()`, and `Baz()`, and -verifies that: - -* `Foo()` returns a string that starts with `"Hello"`. -* `Bar()` returns a string that matches regular expression `"Line \\d+"`. -* `Baz()` returns a number in the range [5, 10]. - -The nice thing about these macros is that *they read like English*. They -generate informative messages too. For example, if the first `EXPECT_THAT()` -above fails, the message will be something like: - -```cpp -Value of: Foo() - Actual: "Hi, world!" -Expected: starts with "Hello" -``` - -**Credit:** The idea of `(ASSERT|EXPECT)_THAT` was borrowed from Joe Walnes' -Hamcrest project, which adds `assertThat()` to JUnit. - -### Using Predicates as Matchers - -gMock provides a [built-in set](gmock_cheat_sheet.md#MatcherList) of matchers. -In case you find them lacking, you can use an arbitrary unary predicate function -or functor as a matcher - as long as the predicate accepts a value of the type -you want. You do this by wrapping the predicate inside the `Truly()` function, -for example: - -```cpp -using ::testing::Truly; - -int IsEven(int n) { return (n % 2) == 0 ? 1 : 0; } -... - // Bar() must be called with an even number. - EXPECT_CALL(foo, Bar(Truly(IsEven))); -``` - -Note that the predicate function / functor doesn't have to return `bool`. It -works as long as the return value can be used as the condition in in statement -`if (condition) ...`. - -### Matching Arguments that Are Not Copyable - -When you do an `EXPECT_CALL(mock_obj, Foo(bar))`, gMock saves away a copy of -`bar`. When `Foo()` is called later, gMock compares the argument to `Foo()` with -the saved copy of `bar`. This way, you don't need to worry about `bar` being -modified or destroyed after the `EXPECT_CALL()` is executed. The same is true -when you use matchers like `Eq(bar)`, `Le(bar)`, and so on. - -But what if `bar` cannot be copied (i.e. has no copy constructor)? You could -define your own matcher function or callback and use it with `Truly()`, as the -previous couple of recipes have shown. Or, you may be able to get away from it -if you can guarantee that `bar` won't be changed after the `EXPECT_CALL()` is -executed. Just tell gMock that it should save a reference to `bar`, instead of a -copy of it. Here's how: - -```cpp -using ::testing::Eq; -using ::testing::Lt; -... - // Expects that Foo()'s argument == bar. - EXPECT_CALL(mock_obj, Foo(Eq(std::ref(bar)))); - - // Expects that Foo()'s argument < bar. - EXPECT_CALL(mock_obj, Foo(Lt(std::ref(bar)))); -``` - -Remember: if you do this, don't change `bar` after the `EXPECT_CALL()`, or the -result is undefined. - -### Validating a Member of an Object - -Often a mock function takes a reference to object as an argument. When matching -the argument, you may not want to compare the entire object against a fixed -object, as that may be over-specification. Instead, you may need to validate a -certain member variable or the result of a certain getter method of the object. -You can do this with `Field()` and `Property()`. More specifically, - -```cpp -Field(&Foo::bar, m) -``` - -is a matcher that matches a `Foo` object whose `bar` member variable satisfies -matcher `m`. - -```cpp -Property(&Foo::baz, m) -``` - -is a matcher that matches a `Foo` object whose `baz()` method returns a value -that satisfies matcher `m`. - -For example: - -| Expression | Description | -| :--------------------------- | :--------------------------------------- | -| `Field(&Foo::number, Ge(3))` | Matches `x` where `x.number >= 3`. | -| `Property(&Foo::name, StartsWith("John "))` | Matches `x` where `x.name()` starts with `"John "`. | - -Note that in `Property(&Foo::baz, ...)`, method `baz()` must take no argument -and be declared as `const`. Don't use `Property()` against member functions that -you do not own, because taking addresses of functions is fragile and generally -not part of the contract of the function. - -`Field()` and `Property()` can also match plain pointers to objects. For -instance, - -```cpp -using ::testing::Field; -using ::testing::Ge; -... -Field(&Foo::number, Ge(3)) -``` - -matches a plain pointer `p` where `p->number >= 3`. If `p` is `NULL`, the match -will always fail regardless of the inner matcher. - -What if you want to validate more than one members at the same time? Remember -that there are [`AllOf()` and `AllOfArray()`](#CombiningMatchers). - -Finally `Field()` and `Property()` provide overloads that take the field or -property names as the first argument to include it in the error message. This -can be useful when creating combined matchers. - -```cpp -using ::testing::AllOf; -using ::testing::Field; -using ::testing::Matcher; -using ::testing::SafeMatcherCast; - -Matcher IsFoo(const Foo& foo) { - return AllOf(Field("some_field", &Foo::some_field, foo.some_field), - Field("other_field", &Foo::other_field, foo.other_field), - Field("last_field", &Foo::last_field, foo.last_field)); -} -``` - -### Validating the Value Pointed to by a Pointer Argument - -C++ functions often take pointers as arguments. You can use matchers like -`IsNull()`, `NotNull()`, and other comparison matchers to match a pointer, but -what if you want to make sure the value *pointed to* by the pointer, instead of -the pointer itself, has a certain property? Well, you can use the `Pointee(m)` -matcher. - -`Pointee(m)` matches a pointer if and only if `m` matches the value the pointer -points to. For example: - -```cpp -using ::testing::Ge; -using ::testing::Pointee; -... - EXPECT_CALL(foo, Bar(Pointee(Ge(3)))); -``` - -expects `foo.Bar()` to be called with a pointer that points to a value greater -than or equal to 3. - -One nice thing about `Pointee()` is that it treats a `NULL` pointer as a match -failure, so you can write `Pointee(m)` instead of - -```cpp -using ::testing::AllOf; -using ::testing::NotNull; -using ::testing::Pointee; -... - AllOf(NotNull(), Pointee(m)) -``` - -without worrying that a `NULL` pointer will crash your test. - -Also, did we tell you that `Pointee()` works with both raw pointers **and** -smart pointers (`std::unique_ptr`, `std::shared_ptr`, etc)? - -What if you have a pointer to pointer? You guessed it - you can use nested -`Pointee()` to probe deeper inside the value. For example, -`Pointee(Pointee(Lt(3)))` matches a pointer that points to a pointer that points -to a number less than 3 (what a mouthful...). - -### Testing a Certain Property of an Object - -Sometimes you want to specify that an object argument has a certain property, -but there is no existing matcher that does this. If you want good error -messages, you should [define a matcher](#NewMatchers). If you want to do it -quick and dirty, you could get away with writing an ordinary function. - -Let's say you have a mock function that takes an object of type `Foo`, which has -an `int bar()` method and an `int baz()` method, and you want to constrain that -the argument's `bar()` value plus its `baz()` value is a given number. Here's -how you can define a matcher to do it: - -```cpp -using ::testing::Matcher; - -class BarPlusBazEqMatcher { - public: - explicit BarPlusBazEqMatcher(int expected_sum) - : expected_sum_(expected_sum) {} - - bool MatchAndExplain(const Foo& foo, - std::ostream* /* listener */) const { - return (foo.bar() + foo.baz()) == expected_sum_; - } - - void DescribeTo(std::ostream& os) const { - os << "bar() + baz() equals " << expected_sum_; - } - - void DescribeNegationTo(std::ostream& os) const { - os << "bar() + baz() does not equal " << expected_sum_; - } - private: - const int expected_sum_; -}; - -Matcher BarPlusBazEq(int expected_sum) { - return BarPlusBazEqMatcher(expected_sum); -} - -... - EXPECT_CALL(..., DoThis(BarPlusBazEq(5)))...; -``` - -### Matching Containers - -Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock -function and you may want to validate it. Since most STL containers support the -`==` operator, you can write `Eq(expected_container)` or simply -`expected_container` to match a container exactly. - -Sometimes, though, you may want to be more flexible (for example, the first -element must be an exact match, but the second element can be any positive -number, and so on). Also, containers used in tests often have a small number of -elements, and having to define the expected container out-of-line is a bit of a -hassle. - -You can use the `ElementsAre()` or `UnorderedElementsAre()` matcher in such -cases: - -```cpp -using ::testing::_; -using ::testing::ElementsAre; -using ::testing::Gt; -... - MOCK_METHOD(void, Foo, (const vector& numbers), (override)); -... - EXPECT_CALL(mock, Foo(ElementsAre(1, Gt(0), _, 5))); -``` - -The above matcher says that the container must have 4 elements, which must be 1, -greater than 0, anything, and 5 respectively. - -If you instead write: - -```cpp -using ::testing::_; -using ::testing::Gt; -using ::testing::UnorderedElementsAre; -... - MOCK_METHOD(void, Foo, (const vector& numbers), (override)); -... - EXPECT_CALL(mock, Foo(UnorderedElementsAre(1, Gt(0), _, 5))); -``` - -It means that the container must have 4 elements, which (under some permutation) -must be 1, greater than 0, anything, and 5 respectively. - -As an alternative you can place the arguments in a C-style array and use -`ElementsAreArray()` or `UnorderedElementsAreArray()` instead: - -```cpp -using ::testing::ElementsAreArray; -... - // ElementsAreArray accepts an array of element values. - const int expected_vector1[] = {1, 5, 2, 4, ...}; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector1))); - - // Or, an array of element matchers. - Matcher expected_vector2[] = {1, Gt(2), _, 3, ...}; - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector2))); -``` - -In case the array needs to be dynamically created (and therefore the array size -cannot be inferred by the compiler), you can give `ElementsAreArray()` an -additional argument to specify the array size: - -```cpp -using ::testing::ElementsAreArray; -... - int* const expected_vector3 = new int[count]; - ... fill expected_vector3 with values ... - EXPECT_CALL(mock, Foo(ElementsAreArray(expected_vector3, count))); -``` - -Use `Pair` when comparing maps or other associative containers. - -{% raw %} - -```cpp -using testing::ElementsAre; -using testing::Pair; -... - std::map m = {{"a", 1}, {"b", 2}, {"c", 3}}; - EXPECT_THAT(m, ElementsAre(Pair("a", 1), Pair("b", 2), Pair("c", 3))); -``` - -{% endraw %} - -**Tips:** - -* `ElementsAre*()` can be used to match *any* container that implements the - STL iterator pattern (i.e. it has a `const_iterator` type and supports - `begin()/end()`), not just the ones defined in STL. It will even work with - container types yet to be written - as long as they follows the above - pattern. -* You can use nested `ElementsAre*()` to match nested (multi-dimensional) - containers. -* If the container is passed by pointer instead of by reference, just write - `Pointee(ElementsAre*(...))`. -* The order of elements *matters* for `ElementsAre*()`. If you are using it - with containers whose element order are undefined (e.g. `hash_map`) you - should use `WhenSorted` around `ElementsAre`. - -### Sharing Matchers - -Under the hood, a gMock matcher object consists of a pointer to a ref-counted -implementation object. Copying matchers is allowed and very efficient, as only -the pointer is copied. When the last matcher that references the implementation -object dies, the implementation object will be deleted. - -Therefore, if you have some complex matcher that you want to use again and -again, there is no need to build it everytime. Just assign it to a matcher -variable and use that variable repeatedly! For example, - -```cpp -using ::testing::AllOf; -using ::testing::Gt; -using ::testing::Le; -using ::testing::Matcher; -... - Matcher in_range = AllOf(Gt(5), Le(10)); - ... use in_range as a matcher in multiple EXPECT_CALLs ... -``` - -### Matchers must have no side-effects {#PureMatchers} - -{: .callout .warning} -WARNING: gMock does not guarantee when or how many times a matcher will be -invoked. Therefore, all matchers must be *purely functional*: they cannot have -any side effects, and the match result must not depend on anything other than -the matcher's parameters and the value being matched. - -This requirement must be satisfied no matter how a matcher is defined (e.g., if -it is one of the standard matchers, or a custom matcher). In particular, a -matcher can never call a mock function, as that will affect the state of the -mock object and gMock. - -## Setting Expectations - -### Knowing When to Expect {#UseOnCall} - -**`ON_CALL`** is likely the *single most under-utilized construct* in gMock. - -There are basically two constructs for defining the behavior of a mock object: -`ON_CALL` and `EXPECT_CALL`. The difference? `ON_CALL` defines what happens when -a mock method is called, but doesn't imply any expectation on the method -being called. `EXPECT_CALL` not only defines the behavior, but also sets an -expectation that the method will be called with the given arguments, for the -given number of times (and *in the given order* when you specify the order -too). - -Since `EXPECT_CALL` does more, isn't it better than `ON_CALL`? Not really. Every -`EXPECT_CALL` adds a constraint on the behavior of the code under test. Having -more constraints than necessary is *baaad* - even worse than not having enough -constraints. - -This may be counter-intuitive. How could tests that verify more be worse than -tests that verify less? Isn't verification the whole point of tests? - -The answer lies in *what* a test should verify. **A good test verifies the -contract of the code.** If a test over-specifies, it doesn't leave enough -freedom to the implementation. As a result, changing the implementation without -breaking the contract (e.g. refactoring and optimization), which should be -perfectly fine to do, can break such tests. Then you have to spend time fixing -them, only to see them broken again the next time the implementation is changed. - -Keep in mind that one doesn't have to verify more than one property in one test. -In fact, **it's a good style to verify only one thing in one test.** If you do -that, a bug will likely break only one or two tests instead of dozens (which -case would you rather debug?). If you are also in the habit of giving tests -descriptive names that tell what they verify, you can often easily guess what's -wrong just from the test log itself. - -So use `ON_CALL` by default, and only use `EXPECT_CALL` when you actually intend -to verify that the call is made. For example, you may have a bunch of `ON_CALL`s -in your test fixture to set the common mock behavior shared by all tests in the -same group, and write (scarcely) different `EXPECT_CALL`s in different `TEST_F`s -to verify different aspects of the code's behavior. Compared with the style -where each `TEST` has many `EXPECT_CALL`s, this leads to tests that are more -resilient to implementational changes (and thus less likely to require -maintenance) and makes the intent of the tests more obvious (so they are easier -to maintain when you do need to maintain them). - -If you are bothered by the "Uninteresting mock function call" message printed -when a mock method without an `EXPECT_CALL` is called, you may use a `NiceMock` -instead to suppress all such messages for the mock object, or suppress the -message for specific methods by adding `EXPECT_CALL(...).Times(AnyNumber())`. DO -NOT suppress it by blindly adding an `EXPECT_CALL(...)`, or you'll have a test -that's a pain to maintain. - -### Ignoring Uninteresting Calls - -If you are not interested in how a mock method is called, just don't say -anything about it. In this case, if the method is ever called, gMock will -perform its default action to allow the test program to continue. If you are not -happy with the default action taken by gMock, you can override it using -`DefaultValue::Set()` (described [here](#DefaultValue)) or `ON_CALL()`. - -Please note that once you expressed interest in a particular mock method (via -`EXPECT_CALL()`), all invocations to it must match some expectation. If this -function is called but the arguments don't match any `EXPECT_CALL()` statement, -it will be an error. - -### Disallowing Unexpected Calls - -If a mock method shouldn't be called at all, explicitly say so: - -```cpp -using ::testing::_; -... - EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -If some calls to the method are allowed, but the rest are not, just list all the -expected calls: - -```cpp -using ::testing::AnyNumber; -using ::testing::Gt; -... - EXPECT_CALL(foo, Bar(5)); - EXPECT_CALL(foo, Bar(Gt(10))) - .Times(AnyNumber()); -``` - -A call to `foo.Bar()` that doesn't match any of the `EXPECT_CALL()` statements -will be an error. - -### Understanding Uninteresting vs Unexpected Calls {#uninteresting-vs-unexpected} - -*Uninteresting* calls and *unexpected* calls are different concepts in gMock. -*Very* different. - -A call `x.Y(...)` is **uninteresting** if there's *not even a single* -`EXPECT_CALL(x, Y(...))` set. In other words, the test isn't interested in the -`x.Y()` method at all, as evident in that the test doesn't care to say anything -about it. - -A call `x.Y(...)` is **unexpected** if there are *some* `EXPECT_CALL(x, -Y(...))`s set, but none of them matches the call. Put another way, the test is -interested in the `x.Y()` method (therefore it explicitly sets some -`EXPECT_CALL` to verify how it's called); however, the verification fails as the -test doesn't expect this particular call to happen. - -**An unexpected call is always an error,** as the code under test doesn't behave -the way the test expects it to behave. - -**By default, an uninteresting call is not an error,** as it violates no -constraint specified by the test. (gMock's philosophy is that saying nothing -means there is no constraint.) However, it leads to a warning, as it *might* -indicate a problem (e.g. the test author might have forgotten to specify a -constraint). - -In gMock, `NiceMock` and `StrictMock` can be used to make a mock class "nice" or -"strict". How does this affect uninteresting calls and unexpected calls? - -A **nice mock** suppresses uninteresting call *warnings*. It is less chatty than -the default mock, but otherwise is the same. If a test fails with a default -mock, it will also fail using a nice mock instead. And vice versa. Don't expect -making a mock nice to change the test's result. - -A **strict mock** turns uninteresting call warnings into errors. So making a -mock strict may change the test's result. - -Let's look at an example: - -```cpp -TEST(...) { - NiceMock mock_registry; - EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) - .WillRepeatedly(Return("Larry Page")); - - // Use mock_registry in code under test. - ... &mock_registry ... -} -``` - -The sole `EXPECT_CALL` here says that all calls to `GetDomainOwner()` must have -`"google.com"` as the argument. If `GetDomainOwner("yahoo.com")` is called, it -will be an unexpected call, and thus an error. *Having a nice mock doesn't -change the severity of an unexpected call.* - -So how do we tell gMock that `GetDomainOwner()` can be called with some other -arguments as well? The standard technique is to add a "catch all" `EXPECT_CALL`: - -```cpp - EXPECT_CALL(mock_registry, GetDomainOwner(_)) - .Times(AnyNumber()); // catches all other calls to this method. - EXPECT_CALL(mock_registry, GetDomainOwner("google.com")) - .WillRepeatedly(Return("Larry Page")); -``` - -Remember that `_` is the wildcard matcher that matches anything. With this, if -`GetDomainOwner("google.com")` is called, it will do what the second -`EXPECT_CALL` says; if it is called with a different argument, it will do what -the first `EXPECT_CALL` says. - -Note that the order of the two `EXPECT_CALL`s is important, as a newer -`EXPECT_CALL` takes precedence over an older one. - -For more on uninteresting calls, nice mocks, and strict mocks, read -["The Nice, the Strict, and the Naggy"](#NiceStrictNaggy). - -### Ignoring Uninteresting Arguments {#ParameterlessExpectations} - -If your test doesn't care about the parameters (it only cares about the number -or order of calls), you can often simply omit the parameter list: - -```cpp - // Expect foo.Bar( ... ) twice with any arguments. - EXPECT_CALL(foo, Bar).Times(2); - - // Delegate to the given method whenever the factory is invoked. - ON_CALL(foo_factory, MakeFoo) - .WillByDefault(&BuildFooForTest); -``` - -This functionality is only available when a method is not overloaded; to prevent -unexpected behavior it is a compilation error to try to set an expectation on a -method where the specific overload is ambiguous. You can work around this by -supplying a [simpler mock interface](#SimplerInterfaces) than the mocked class -provides. - -This pattern is also useful when the arguments are interesting, but match logic -is substantially complex. You can leave the argument list unspecified and use -SaveArg actions to [save the values for later verification](#SaveArgVerify). If -you do that, you can easily differentiate calling the method the wrong number of -times from calling it with the wrong arguments. - -### Expecting Ordered Calls {#OrderedCalls} - -Although an `EXPECT_CALL()` statement defined later takes precedence when gMock -tries to match a function call with an expectation, by default calls don't have -to happen in the order `EXPECT_CALL()` statements are written. For example, if -the arguments match the matchers in the second `EXPECT_CALL()`, but not those in -the first and third, then the second expectation will be used. - -If you would rather have all calls occur in the order of the expectations, put -the `EXPECT_CALL()` statements in a block where you define a variable of type -`InSequence`: - -```cpp -using ::testing::_; -using ::testing::InSequence; - - { - InSequence s; - - EXPECT_CALL(foo, DoThis(5)); - EXPECT_CALL(bar, DoThat(_)) - .Times(2); - EXPECT_CALL(foo, DoThis(6)); - } -``` - -In this example, we expect a call to `foo.DoThis(5)`, followed by two calls to -`bar.DoThat()` where the argument can be anything, which are in turn followed by -a call to `foo.DoThis(6)`. If a call occurred out-of-order, gMock will report an -error. - -### Expecting Partially Ordered Calls {#PartialOrder} - -Sometimes requiring everything to occur in a predetermined order can lead to -brittle tests. For example, we may care about `A` occurring before both `B` and -`C`, but aren't interested in the relative order of `B` and `C`. In this case, -the test should reflect our real intent, instead of being overly constraining. - -gMock allows you to impose an arbitrary DAG (directed acyclic graph) on the -calls. One way to express the DAG is to use the -[After](gmock_cheat_sheet.md#AfterClause) clause of `EXPECT_CALL`. - -Another way is via the `InSequence()` clause (not the same as the `InSequence` -class), which we borrowed from jMock 2. It's less flexible than `After()`, but -more convenient when you have long chains of sequential calls, as it doesn't -require you to come up with different names for the expectations in the chains. -Here's how it works: - -If we view `EXPECT_CALL()` statements as nodes in a graph, and add an edge from -node A to node B wherever A must occur before B, we can get a DAG. We use the -term "sequence" to mean a directed path in this DAG. Now, if we decompose the -DAG into sequences, we just need to know which sequences each `EXPECT_CALL()` -belongs to in order to be able to reconstruct the original DAG. - -So, to specify the partial order on the expectations we need to do two things: -first to define some `Sequence` objects, and then for each `EXPECT_CALL()` say -which `Sequence` objects it is part of. - -Expectations in the same sequence must occur in the order they are written. For -example, - -```cpp -using ::testing::Sequence; -... - Sequence s1, s2; - - EXPECT_CALL(foo, A()) - .InSequence(s1, s2); - EXPECT_CALL(bar, B()) - .InSequence(s1); - EXPECT_CALL(bar, C()) - .InSequence(s2); - EXPECT_CALL(foo, D()) - .InSequence(s2); -``` - -specifies the following DAG (where `s1` is `A -> B`, and `s2` is `A -> C -> D`): - -```text - +---> B - | - A ---| - | - +---> C ---> D -``` - -This means that A must occur before B and C, and C must occur before D. There's -no restriction about the order other than these. - -### Controlling When an Expectation Retires - -When a mock method is called, gMock only considers expectations that are still -active. An expectation is active when created, and becomes inactive (aka -*retires*) when a call that has to occur later has occurred. For example, in - -```cpp -using ::testing::_; -using ::testing::Sequence; -... - Sequence s1, s2; - - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #1 - .Times(AnyNumber()) - .InSequence(s1, s2); - EXPECT_CALL(log, Log(WARNING, _, "Data set is empty.")) // #2 - .InSequence(s1); - EXPECT_CALL(log, Log(WARNING, _, "User not found.")) // #3 - .InSequence(s2); -``` - -as soon as either #2 or #3 is matched, #1 will retire. If a warning `"File too -large."` is logged after this, it will be an error. - -Note that an expectation doesn't retire automatically when it's saturated. For -example, - -```cpp -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")); // #2 -``` - -says that there will be exactly one warning with the message `"File too -large."`. If the second warning contains this message too, #2 will match again -and result in an upper-bound-violated error. - -If this is not what you want, you can ask an expectation to retire as soon as it -becomes saturated: - -```cpp -using ::testing::_; -... - EXPECT_CALL(log, Log(WARNING, _, _)); // #1 - EXPECT_CALL(log, Log(WARNING, _, "File too large.")) // #2 - .RetiresOnSaturation(); -``` - -Here #2 can be used only once, so if you have two warnings with the message -`"File too large."`, the first will match #2 and the second will match #1 - -there will be no error. - -## Using Actions - -### Returning References from Mock Methods - -If a mock function's return type is a reference, you need to use `ReturnRef()` -instead of `Return()` to return a result: - -```cpp -using ::testing::ReturnRef; - -class MockFoo : public Foo { - public: - MOCK_METHOD(Bar&, GetBar, (), (override)); -}; -... - MockFoo foo; - Bar bar; - EXPECT_CALL(foo, GetBar()) - .WillOnce(ReturnRef(bar)); -... -``` - -### Returning Live Values from Mock Methods - -The `Return(x)` action saves a copy of `x` when the action is created, and -always returns the same value whenever it's executed. Sometimes you may want to -instead return the *live* value of `x` (i.e. its value at the time when the -action is *executed*.). Use either `ReturnRef()` or `ReturnPointee()` for this -purpose. - -If the mock function's return type is a reference, you can do it using -`ReturnRef(x)`, as shown in the previous recipe ("Returning References from Mock -Methods"). However, gMock doesn't let you use `ReturnRef()` in a mock function -whose return type is not a reference, as doing that usually indicates a user -error. So, what shall you do? - -Though you may be tempted, DO NOT use `std::ref()`: - -```cpp -using testing::Return; - -class MockFoo : public Foo { - public: - MOCK_METHOD(int, GetValue, (), (override)); -}; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(Return(std::ref(x))); // Wrong! - x = 42; - EXPECT_EQ(42, foo.GetValue()); -``` - -Unfortunately, it doesn't work here. The above code will fail with error: - -```text -Value of: foo.GetValue() - Actual: 0 -Expected: 42 -``` - -The reason is that `Return(*value*)` converts `value` to the actual return type -of the mock function at the time when the action is *created*, not when it is -*executed*. (This behavior was chosen for the action to be safe when `value` is -a proxy object that references some temporary objects.) As a result, -`std::ref(x)` is converted to an `int` value (instead of a `const int&`) when -the expectation is set, and `Return(std::ref(x))` will always return 0. - -`ReturnPointee(pointer)` was provided to solve this problem specifically. It -returns the value pointed to by `pointer` at the time the action is *executed*: - -```cpp -using testing::ReturnPointee; -... - int x = 0; - MockFoo foo; - EXPECT_CALL(foo, GetValue()) - .WillRepeatedly(ReturnPointee(&x)); // Note the & here. - x = 42; - EXPECT_EQ(42, foo.GetValue()); // This will succeed now. -``` - -### Combining Actions - -Want to do more than one thing when a function is called? That's fine. `DoAll()` -allow you to do sequence of actions every time. Only the return value of the -last action in the sequence will be used. - -```cpp -using ::testing::_; -using ::testing::DoAll; - -class MockFoo : public Foo { - public: - MOCK_METHOD(bool, Bar, (int n), (override)); -}; -... - EXPECT_CALL(foo, Bar(_)) - .WillOnce(DoAll(action_1, - action_2, - ... - action_n)); -``` - -### Verifying Complex Arguments {#SaveArgVerify} - -If you want to verify that a method is called with a particular argument but the -match criteria is complex, it can be difficult to distinguish between -cardinality failures (calling the method the wrong number of times) and argument -match failures. Similarly, if you are matching multiple parameters, it may not -be easy to distinguishing which argument failed to match. For example: - -```cpp - // Not ideal: this could fail because of a problem with arg1 or arg2, or maybe - // just the method wasn't called. - EXPECT_CALL(foo, SendValues(_, ElementsAre(1, 4, 4, 7), EqualsProto( ... ))); -``` - -You can instead save the arguments and test them individually: - -```cpp - EXPECT_CALL(foo, SendValues) - .WillOnce(DoAll(SaveArg<1>(&actual_array), SaveArg<2>(&actual_proto))); - ... run the test - EXPECT_THAT(actual_array, ElementsAre(1, 4, 4, 7)); - EXPECT_THAT(actual_proto, EqualsProto( ... )); -``` - -### Mocking Side Effects {#MockingSideEffects} - -Sometimes a method exhibits its effect not via returning a value but via side -effects. For example, it may change some global state or modify an output -argument. To mock side effects, in general you can define your own action by -implementing `::testing::ActionInterface`. - -If all you need to do is to change an output argument, the built-in -`SetArgPointee()` action is convenient: - -```cpp -using ::testing::_; -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - MOCK_METHOD(void, Mutate, (bool mutate, int* value), (override)); - ... -} -... - MockMutator mutator; - EXPECT_CALL(mutator, Mutate(true, _)) - .WillOnce(SetArgPointee<1>(5)); -``` - -In this example, when `mutator.Mutate()` is called, we will assign 5 to the -`int` variable pointed to by argument #1 (0-based). - -`SetArgPointee()` conveniently makes an internal copy of the value you pass to -it, removing the need to keep the value in scope and alive. The implication -however is that the value must have a copy constructor and assignment operator. - -If the mock method also needs to return a value as well, you can chain -`SetArgPointee()` with `Return()` using `DoAll()`, remembering to put the -`Return()` statement last: - -```cpp -using ::testing::_; -using ::testing::Return; -using ::testing::SetArgPointee; - -class MockMutator : public Mutator { - public: - ... - MOCK_METHOD(bool, MutateInt, (int* value), (override)); -} -... - MockMutator mutator; - EXPECT_CALL(mutator, MutateInt(_)) - .WillOnce(DoAll(SetArgPointee<0>(5), - Return(true))); -``` - -Note, however, that if you use the `ReturnOKWith()` method, it will override the -values provided by `SetArgPointee()` in the response parameters of your function -call. - -If the output argument is an array, use the `SetArrayArgument(first, last)` -action instead. It copies the elements in source range `[first, last)` to the -array pointed to by the `N`-th (0-based) argument: - -```cpp -using ::testing::NotNull; -using ::testing::SetArrayArgument; - -class MockArrayMutator : public ArrayMutator { - public: - MOCK_METHOD(void, Mutate, (int* values, int num_values), (override)); - ... -} -... - MockArrayMutator mutator; - int values[5] = {1, 2, 3, 4, 5}; - EXPECT_CALL(mutator, Mutate(NotNull(), 5)) - .WillOnce(SetArrayArgument<0>(values, values + 5)); -``` - -This also works when the argument is an output iterator: - -```cpp -using ::testing::_; -using ::testing::SetArrayArgument; - -class MockRolodex : public Rolodex { - public: - MOCK_METHOD(void, GetNames, (std::back_insert_iterator>), - (override)); - ... -} -... - MockRolodex rolodex; - vector names; - names.push_back("George"); - names.push_back("John"); - names.push_back("Thomas"); - EXPECT_CALL(rolodex, GetNames(_)) - .WillOnce(SetArrayArgument<0>(names.begin(), names.end())); -``` - -### Changing a Mock Object's Behavior Based on the State - -If you expect a call to change the behavior of a mock object, you can use -`::testing::InSequence` to specify different behaviors before and after the -call: - -```cpp -using ::testing::InSequence; -using ::testing::Return; - -... - { - InSequence seq; - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(true)); - EXPECT_CALL(my_mock, Flush()); - EXPECT_CALL(my_mock, IsDirty()) - .WillRepeatedly(Return(false)); - } - my_mock.FlushIfDirty(); -``` - -This makes `my_mock.IsDirty()` return `true` before `my_mock.Flush()` is called -and return `false` afterwards. - -If the behavior change is more complex, you can store the effects in a variable -and make a mock method get its return value from that variable: - -```cpp -using ::testing::_; -using ::testing::SaveArg; -using ::testing::Return; - -ACTION_P(ReturnPointee, p) { return *p; } -... - int previous_value = 0; - EXPECT_CALL(my_mock, GetPrevValue) - .WillRepeatedly(ReturnPointee(&previous_value)); - EXPECT_CALL(my_mock, UpdateValue) - .WillRepeatedly(SaveArg<0>(&previous_value)); - my_mock.DoSomethingToUpdateValue(); -``` - -Here `my_mock.GetPrevValue()` will always return the argument of the last -`UpdateValue()` call. - -### Setting the Default Value for a Return Type {#DefaultValue} - -If a mock method's return type is a built-in C++ type or pointer, by default it -will return 0 when invoked. Also, in C++ 11 and above, a mock method whose -return type has a default constructor will return a default-constructed value by -default. You only need to specify an action if this default value doesn't work -for you. - -Sometimes, you may want to change this default value, or you may want to specify -a default value for types gMock doesn't know about. You can do this using the -`::testing::DefaultValue` class template: - -```cpp -using ::testing::DefaultValue; - -class MockFoo : public Foo { - public: - MOCK_METHOD(Bar, CalculateBar, (), (override)); -}; - - -... - Bar default_bar; - // Sets the default return value for type Bar. - DefaultValue::Set(default_bar); - - MockFoo foo; - - // We don't need to specify an action here, as the default - // return value works for us. - EXPECT_CALL(foo, CalculateBar()); - - foo.CalculateBar(); // This should return default_bar. - - // Unsets the default return value. - DefaultValue::Clear(); -``` - -Please note that changing the default value for a type can make your tests hard -to understand. We recommend you to use this feature judiciously. For example, -you may want to make sure the `Set()` and `Clear()` calls are right next to the -code that uses your mock. - -### Setting the Default Actions for a Mock Method - -You've learned how to change the default value of a given type. However, this -may be too coarse for your purpose: perhaps you have two mock methods with the -same return type and you want them to have different behaviors. The `ON_CALL()` -macro allows you to customize your mock's behavior at the method level: - -```cpp -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::Gt; -using ::testing::Return; -... - ON_CALL(foo, Sign(_)) - .WillByDefault(Return(-1)); - ON_CALL(foo, Sign(0)) - .WillByDefault(Return(0)); - ON_CALL(foo, Sign(Gt(0))) - .WillByDefault(Return(1)); - - EXPECT_CALL(foo, Sign(_)) - .Times(AnyNumber()); - - foo.Sign(5); // This should return 1. - foo.Sign(-9); // This should return -1. - foo.Sign(0); // This should return 0. -``` - -As you may have guessed, when there are more than one `ON_CALL()` statements, -the newer ones in the order take precedence over the older ones. In other words, -the **last** one that matches the function arguments will be used. This matching -order allows you to set up the common behavior in a mock object's constructor or -the test fixture's set-up phase and specialize the mock's behavior later. - -Note that both `ON_CALL` and `EXPECT_CALL` have the same "later statements take -precedence" rule, but they don't interact. That is, `EXPECT_CALL`s have their -own precedence order distinct from the `ON_CALL` precedence order. - -### Using Functions/Methods/Functors/Lambdas as Actions {#FunctionsAsActions} - -If the built-in actions don't suit you, you can use an existing callable -(function, `std::function`, method, functor, lambda) as an action. - -```cpp -using ::testing::_; using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MOCK_METHOD(int, Sum, (int x, int y), (override)); - MOCK_METHOD(bool, ComplexJob, (int x), (override)); -}; - -int CalculateSum(int x, int y) { return x + y; } -int Sum3(int x, int y, int z) { return x + y + z; } - -class Helper { - public: - bool ComplexJob(int x); -}; - -... - MockFoo foo; - Helper helper; - EXPECT_CALL(foo, Sum(_, _)) - .WillOnce(&CalculateSum) - .WillRepeatedly(Invoke(NewPermanentCallback(Sum3, 1))); - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce(Invoke(&helper, &Helper::ComplexJob)) - .WillOnce([] { return true; }) - .WillRepeatedly([](int x) { return x > 0; }); - - foo.Sum(5, 6); // Invokes CalculateSum(5, 6). - foo.Sum(2, 3); // Invokes Sum3(1, 2, 3). - foo.ComplexJob(10); // Invokes helper.ComplexJob(10). - foo.ComplexJob(-1); // Invokes the inline lambda. -``` - -The only requirement is that the type of the function, etc must be *compatible* -with the signature of the mock function, meaning that the latter's arguments (if -it takes any) can be implicitly converted to the corresponding arguments of the -former, and the former's return type can be implicitly converted to that of the -latter. So, you can invoke something whose type is *not* exactly the same as the -mock function, as long as it's safe to do so - nice, huh? - -Note that: - -* The action takes ownership of the callback and will delete it when the - action itself is destructed. -* If the type of a callback is derived from a base callback type `C`, you need - to implicitly cast it to `C` to resolve the overloading, e.g. - - ```cpp - using ::testing::Invoke; - ... - ResultCallback* is_ok = ...; - ... Invoke(is_ok) ...; // This works. - - BlockingClosure* done = new BlockingClosure; - ... Invoke(implicit_cast(done)) ...; // The cast is necessary. - ``` - -### Using Functions with Extra Info as Actions - -The function or functor you call using `Invoke()` must have the same number of -arguments as the mock function you use it for. Sometimes you may have a function -that takes more arguments, and you are willing to pass in the extra arguments -yourself to fill the gap. You can do this in gMock using callbacks with -pre-bound arguments. Here's an example: - -```cpp -using ::testing::Invoke; - -class MockFoo : public Foo { - public: - MOCK_METHOD(char, DoThis, (int n), (override)); -}; - -char SignOfSum(int x, int y) { - const int sum = x + y; - return (sum > 0) ? '+' : (sum < 0) ? '-' : '0'; -} - -TEST_F(FooTest, Test) { - MockFoo foo; - - EXPECT_CALL(foo, DoThis(2)) - .WillOnce(Invoke(NewPermanentCallback(SignOfSum, 5))); - EXPECT_EQ('+', foo.DoThis(2)); // Invokes SignOfSum(5, 2). -} -``` - -### Invoking a Function/Method/Functor/Lambda/Callback Without Arguments - -`Invoke()` passes the mock function's arguments to the function, etc being -invoked such that the callee has the full context of the call to work with. If -the invoked function is not interested in some or all of the arguments, it can -simply ignore them. - -Yet, a common pattern is that a test author wants to invoke a function without -the arguments of the mock function. She could do that using a wrapper function -that throws away the arguments before invoking an underlining nullary function. -Needless to say, this can be tedious and obscures the intent of the test. - -There are two solutions to this problem. First, you can pass any callable of -zero args as an action. Alternatively, use `InvokeWithoutArgs()`, which is like -`Invoke()` except that it doesn't pass the mock function's arguments to the -callee. Here's an example of each: - -```cpp -using ::testing::_; -using ::testing::InvokeWithoutArgs; - -class MockFoo : public Foo { - public: - MOCK_METHOD(bool, ComplexJob, (int n), (override)); -}; - -bool Job1() { ... } -bool Job2(int n, char c) { ... } - -... - MockFoo foo; - EXPECT_CALL(foo, ComplexJob(_)) - .WillOnce([] { Job1(); }); - .WillOnce(InvokeWithoutArgs(NewPermanentCallback(Job2, 5, 'a'))); - - foo.ComplexJob(10); // Invokes Job1(). - foo.ComplexJob(20); // Invokes Job2(5, 'a'). -``` - -Note that: - -* The action takes ownership of the callback and will delete it when the - action itself is destructed. -* If the type of a callback is derived from a base callback type `C`, you need - to implicitly cast it to `C` to resolve the overloading, e.g. - - ```cpp - using ::testing::InvokeWithoutArgs; - ... - ResultCallback* is_ok = ...; - ... InvokeWithoutArgs(is_ok) ...; // This works. - - BlockingClosure* done = ...; - ... InvokeWithoutArgs(implicit_cast(done)) ...; - // The cast is necessary. - ``` - -### Invoking an Argument of the Mock Function - -Sometimes a mock function will receive a function pointer, a functor (in other -words, a "callable") as an argument, e.g. - -```cpp -class MockFoo : public Foo { - public: - MOCK_METHOD(bool, DoThis, (int n, (ResultCallback1* callback)), - (override)); -}; -``` - -and you may want to invoke this callable argument: - -```cpp -using ::testing::_; -... - MockFoo foo; - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(...); - // Will execute callback->Run(5), where callback is the - // second argument DoThis() receives. -``` - -{: .callout .note} -NOTE: The section below is legacy documentation from before C++ had lambdas: - -Arghh, you need to refer to a mock function argument but C++ has no lambda -(yet), so you have to define your own action. :-( Or do you really? - -Well, gMock has an action to solve *exactly* this problem: - -```cpp -InvokeArgument(arg_1, arg_2, ..., arg_m) -``` - -will invoke the `N`-th (0-based) argument the mock function receives, with -`arg_1`, `arg_2`, ..., and `arg_m`. No matter if the argument is a function -pointer, a functor, or a callback. gMock handles them all. - -With that, you could write: - -```cpp -using ::testing::_; -using ::testing::InvokeArgument; -... - EXPECT_CALL(foo, DoThis(_, _)) - .WillOnce(InvokeArgument<1>(5)); - // Will execute callback->Run(5), where callback is the - // second argument DoThis() receives. -``` - -What if the callable takes an argument by reference? No problem - just wrap it -inside `std::ref()`: - -```cpp - ... - MOCK_METHOD(bool, Bar, - ((ResultCallback2* callback)), - (override)); - ... - using ::testing::_; - using ::testing::InvokeArgument; - ... - MockFoo foo; - Helper helper; - ... - EXPECT_CALL(foo, Bar(_)) - .WillOnce(InvokeArgument<0>(5, std::ref(helper))); - // std::ref(helper) guarantees that a reference to helper, not a copy of - // it, will be passed to the callback. -``` - -What if the callable takes an argument by reference and we do **not** wrap the -argument in `std::ref()`? Then `InvokeArgument()` will *make a copy* of the -argument, and pass a *reference to the copy*, instead of a reference to the -original value, to the callable. This is especially handy when the argument is a -temporary value: - -```cpp - ... - MOCK_METHOD(bool, DoThat, (bool (*f)(const double& x, const string& s)), - (override)); - ... - using ::testing::_; - using ::testing::InvokeArgument; - ... - MockFoo foo; - ... - EXPECT_CALL(foo, DoThat(_)) - .WillOnce(InvokeArgument<0>(5.0, string("Hi"))); - // Will execute (*f)(5.0, string("Hi")), where f is the function pointer - // DoThat() receives. Note that the values 5.0 and string("Hi") are - // temporary and dead once the EXPECT_CALL() statement finishes. Yet - // it's fine to perform this action later, since a copy of the values - // are kept inside the InvokeArgument action. -``` - -### Ignoring an Action's Result - -Sometimes you have an action that returns *something*, but you need an action -that returns `void` (perhaps you want to use it in a mock function that returns -`void`, or perhaps it needs to be used in `DoAll()` and it's not the last in the -list). `IgnoreResult()` lets you do that. For example: - -```cpp -using ::testing::_; -using ::testing::DoAll; -using ::testing::IgnoreResult; -using ::testing::Return; - -int Process(const MyData& data); -string DoSomething(); - -class MockFoo : public Foo { - public: - MOCK_METHOD(void, Abc, (const MyData& data), (override)); - MOCK_METHOD(bool, Xyz, (), (override)); -}; - - ... - MockFoo foo; - EXPECT_CALL(foo, Abc(_)) - // .WillOnce(Invoke(Process)); - // The above line won't compile as Process() returns int but Abc() needs - // to return void. - .WillOnce(IgnoreResult(Process)); - EXPECT_CALL(foo, Xyz()) - .WillOnce(DoAll(IgnoreResult(DoSomething), - // Ignores the string DoSomething() returns. - Return(true))); -``` - -Note that you **cannot** use `IgnoreResult()` on an action that already returns -`void`. Doing so will lead to ugly compiler errors. - -### Selecting an Action's Arguments {#SelectingArgs} - -Say you have a mock function `Foo()` that takes seven arguments, and you have a -custom action that you want to invoke when `Foo()` is called. Trouble is, the -custom action only wants three arguments: - -```cpp -using ::testing::_; -using ::testing::Invoke; -... - MOCK_METHOD(bool, Foo, - (bool visible, const string& name, int x, int y, - (const map>), double& weight, double min_weight, - double max_wight)); -... -bool IsVisibleInQuadrant1(bool visible, int x, int y) { - return visible && x >= 0 && y >= 0; -} -... - EXPECT_CALL(mock, Foo) - .WillOnce(Invoke(IsVisibleInQuadrant1)); // Uh, won't compile. :-( -``` - -To please the compiler God, you need to define an "adaptor" that has the same -signature as `Foo()` and calls the custom action with the right arguments: - -```cpp -using ::testing::_; -using ::testing::Invoke; -... -bool MyIsVisibleInQuadrant1(bool visible, const string& name, int x, int y, - const map, double>& weight, - double min_weight, double max_wight) { - return IsVisibleInQuadrant1(visible, x, y); -} -... - EXPECT_CALL(mock, Foo) - .WillOnce(Invoke(MyIsVisibleInQuadrant1)); // Now it works. -``` - -But isn't this awkward? - -gMock provides a generic *action adaptor*, so you can spend your time minding -more important business than writing your own adaptors. Here's the syntax: - -```cpp -WithArgs(action) -``` - -creates an action that passes the arguments of the mock function at the given -indices (0-based) to the inner `action` and performs it. Using `WithArgs`, our -original example can be written as: - -```cpp -using ::testing::_; -using ::testing::Invoke; -using ::testing::WithArgs; -... - EXPECT_CALL(mock, Foo) - .WillOnce(WithArgs<0, 2, 3>(Invoke(IsVisibleInQuadrant1))); // No need to define your own adaptor. -``` - -For better readability, gMock also gives you: - -* `WithoutArgs(action)` when the inner `action` takes *no* argument, and -* `WithArg(action)` (no `s` after `Arg`) when the inner `action` takes - *one* argument. - -As you may have realized, `InvokeWithoutArgs(...)` is just syntactic sugar for -`WithoutArgs(Invoke(...))`. - -Here are more tips: - -* The inner action used in `WithArgs` and friends does not have to be - `Invoke()` -- it can be anything. -* You can repeat an argument in the argument list if necessary, e.g. - `WithArgs<2, 3, 3, 5>(...)`. -* You can change the order of the arguments, e.g. `WithArgs<3, 2, 1>(...)`. -* The types of the selected arguments do *not* have to match the signature of - the inner action exactly. It works as long as they can be implicitly - converted to the corresponding arguments of the inner action. For example, - if the 4-th argument of the mock function is an `int` and `my_action` takes - a `double`, `WithArg<4>(my_action)` will work. - -### Ignoring Arguments in Action Functions - -The [selecting-an-action's-arguments](#SelectingArgs) recipe showed us one way -to make a mock function and an action with incompatible argument lists fit -together. The downside is that wrapping the action in `WithArgs<...>()` can get -tedious for people writing the tests. - -If you are defining a function (or method, functor, lambda, callback) to be used -with `Invoke*()`, and you are not interested in some of its arguments, an -alternative to `WithArgs` is to declare the uninteresting arguments as `Unused`. -This makes the definition less cluttered and less fragile in case the types of -the uninteresting arguments change. It could also increase the chance the action -function can be reused. For example, given - -```cpp - public: - MOCK_METHOD(double, Foo, double(const string& label, double x, double y), - (override)); - MOCK_METHOD(double, Bar, (int index, double x, double y), (override)); -``` - -instead of - -```cpp -using ::testing::_; -using ::testing::Invoke; - -double DistanceToOriginWithLabel(const string& label, double x, double y) { - return sqrt(x*x + y*y); -} -double DistanceToOriginWithIndex(int index, double x, double y) { - return sqrt(x*x + y*y); -} -... - EXPECT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOriginWithLabel)); - EXPECT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOriginWithIndex)); -``` - -you could write - -```cpp -using ::testing::_; -using ::testing::Invoke; -using ::testing::Unused; - -double DistanceToOrigin(Unused, double x, double y) { - return sqrt(x*x + y*y); -} -... - EXPECT_CALL(mock, Foo("abc", _, _)) - .WillOnce(Invoke(DistanceToOrigin)); - EXPECT_CALL(mock, Bar(5, _, _)) - .WillOnce(Invoke(DistanceToOrigin)); -``` - -### Sharing Actions - -Just like matchers, a gMock action object consists of a pointer to a ref-counted -implementation object. Therefore copying actions is also allowed and very -efficient. When the last action that references the implementation object dies, -the implementation object will be deleted. - -If you have some complex action that you want to use again and again, you may -not have to build it from scratch everytime. If the action doesn't have an -internal state (i.e. if it always does the same thing no matter how many times -it has been called), you can assign it to an action variable and use that -variable repeatedly. For example: - -```cpp -using ::testing::Action; -using ::testing::DoAll; -using ::testing::Return; -using ::testing::SetArgPointee; -... - Action set_flag = DoAll(SetArgPointee<0>(5), - Return(true)); - ... use set_flag in .WillOnce() and .WillRepeatedly() ... -``` - -However, if the action has its own state, you may be surprised if you share the -action object. Suppose you have an action factory `IncrementCounter(init)` which -creates an action that increments and returns a counter whose initial value is -`init`, using two actions created from the same expression and using a shared -action will exhibit different behaviors. Example: - -```cpp - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(IncrementCounter(0)); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(IncrementCounter(0)); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 1 - Blah() uses a different - // counter than Bar()'s. -``` - -versus - -```cpp -using ::testing::Action; -... - Action increment = IncrementCounter(0); - EXPECT_CALL(foo, DoThis()) - .WillRepeatedly(increment); - EXPECT_CALL(foo, DoThat()) - .WillRepeatedly(increment); - foo.DoThis(); // Returns 1. - foo.DoThis(); // Returns 2. - foo.DoThat(); // Returns 3 - the counter is shared. -``` - -### Testing Asynchronous Behavior - -One oft-encountered problem with gMock is that it can be hard to test -asynchronous behavior. Suppose you had a `EventQueue` class that you wanted to -test, and you created a separate `EventDispatcher` interface so that you could -easily mock it out. However, the implementation of the class fired all the -events on a background thread, which made test timings difficult. You could just -insert `sleep()` statements and hope for the best, but that makes your test -behavior nondeterministic. A better way is to use gMock actions and -`Notification` objects to force your asynchronous test to behave synchronously. - -```cpp -class MockEventDispatcher : public EventDispatcher { - MOCK_METHOD(bool, DispatchEvent, (int32), (override)); -}; - -TEST(EventQueueTest, EnqueueEventTest) { - MockEventDispatcher mock_event_dispatcher; - EventQueue event_queue(&mock_event_dispatcher); - - const int32 kEventId = 321; - absl::Notification done; - EXPECT_CALL(mock_event_dispatcher, DispatchEvent(kEventId)) - .WillOnce([&done] { done.Notify(); }); - - event_queue.EnqueueEvent(kEventId); - done.WaitForNotification(); -} -``` - -In the example above, we set our normal gMock expectations, but then add an -additional action to notify the `Notification` object. Now we can just call -`Notification::WaitForNotification()` in the main thread to wait for the -asynchronous call to finish. After that, our test suite is complete and we can -safely exit. - -{: .callout .note} -Note: this example has a downside: namely, if the expectation is not satisfied, -our test will run forever. It will eventually time-out and fail, but it will -take longer and be slightly harder to debug. To alleviate this problem, you can -use `WaitForNotificationWithTimeout(ms)` instead of `WaitForNotification()`. - -## Misc Recipes on Using gMock - -### Mocking Methods That Use Move-Only Types - -C++11 introduced *move-only types*. A move-only-typed value can be moved from -one object to another, but cannot be copied. `std::unique_ptr` is probably -the most commonly used move-only type. - -Mocking a method that takes and/or returns move-only types presents some -challenges, but nothing insurmountable. This recipe shows you how you can do it. -Note that the support for move-only method arguments was only introduced to -gMock in April 2017; in older code, you may find more complex -[workarounds](#LegacyMoveOnly) for lack of this feature. - -Let’s say we are working on a fictional project that lets one post and share -snippets called “buzzes”. Your code uses these types: - -```cpp -enum class AccessLevel { kInternal, kPublic }; - -class Buzz { - public: - explicit Buzz(AccessLevel access) { ... } - ... -}; - -class Buzzer { - public: - virtual ~Buzzer() {} - virtual std::unique_ptr MakeBuzz(StringPiece text) = 0; - virtual bool ShareBuzz(std::unique_ptr buzz, int64_t timestamp) = 0; - ... -}; -``` - -A `Buzz` object represents a snippet being posted. A class that implements the -`Buzzer` interface is capable of creating and sharing `Buzz`es. Methods in -`Buzzer` may return a `unique_ptr` or take a `unique_ptr`. Now we -need to mock `Buzzer` in our tests. - -To mock a method that accepts or returns move-only types, you just use the -familiar `MOCK_METHOD` syntax as usual: - -```cpp -class MockBuzzer : public Buzzer { - public: - MOCK_METHOD(std::unique_ptr, MakeBuzz, (StringPiece text), (override)); - MOCK_METHOD(bool, ShareBuzz, (std::unique_ptr buzz, int64_t timestamp), - (override)); -}; -``` - -Now that we have the mock class defined, we can use it in tests. In the -following code examples, we assume that we have defined a `MockBuzzer` object -named `mock_buzzer_`: - -```cpp - MockBuzzer mock_buzzer_; -``` - -First let’s see how we can set expectations on the `MakeBuzz()` method, which -returns a `unique_ptr`. - -As usual, if you set an expectation without an action (i.e. the `.WillOnce()` or -`.WillRepeatedly()` clause), when that expectation fires, the default action for -that method will be taken. Since `unique_ptr<>` has a default constructor that -returns a null `unique_ptr`, that’s what you’ll get if you don’t specify an -action: - -```cpp - // Use the default action. - EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")); - - // Triggers the previous EXPECT_CALL. - EXPECT_EQ(nullptr, mock_buzzer_.MakeBuzz("hello")); -``` - -If you are not happy with the default action, you can tweak it as usual; see -[Setting Default Actions](#OnCall). - -If you just need to return a pre-defined move-only value, you can use the -`Return(ByMove(...))` action: - -```cpp - // When this fires, the unique_ptr<> specified by ByMove(...) will - // be returned. - EXPECT_CALL(mock_buzzer_, MakeBuzz("world")) - .WillOnce(Return(ByMove(MakeUnique(AccessLevel::kInternal)))); - - EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("world")); -``` - -Note that `ByMove()` is essential here - if you drop it, the code won’t compile. - -Quiz time! What do you think will happen if a `Return(ByMove(...))` action is -performed more than once (e.g. you write `... -.WillRepeatedly(Return(ByMove(...)));`)? Come think of it, after the first time -the action runs, the source value will be consumed (since it’s a move-only -value), so the next time around, there’s no value to move from -- you’ll get a -run-time error that `Return(ByMove(...))` can only be run once. - -If you need your mock method to do more than just moving a pre-defined value, -remember that you can always use a lambda or a callable object, which can do -pretty much anything you want: - -```cpp - EXPECT_CALL(mock_buzzer_, MakeBuzz("x")) - .WillRepeatedly([](StringPiece text) { - return MakeUnique(AccessLevel::kInternal); - }); - - EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); - EXPECT_NE(nullptr, mock_buzzer_.MakeBuzz("x")); -``` - -Every time this `EXPECT_CALL` fires, a new `unique_ptr` will be created -and returned. You cannot do this with `Return(ByMove(...))`. - -That covers returning move-only values; but how do we work with methods -accepting move-only arguments? The answer is that they work normally, although -some actions will not compile when any of method's arguments are move-only. You -can always use `Return`, or a [lambda or functor](#FunctionsAsActions): - -```cpp - using ::testing::Unused; - - EXPECT_CALL(mock_buzzer_, ShareBuzz(NotNull(), _)).WillOnce(Return(true)); - EXPECT_TRUE(mock_buzzer_.ShareBuzz(MakeUnique(AccessLevel::kInternal)), - 0); - - EXPECT_CALL(mock_buzzer_, ShareBuzz(_, _)).WillOnce( - [](std::unique_ptr buzz, Unused) { return buzz != nullptr; }); - EXPECT_FALSE(mock_buzzer_.ShareBuzz(nullptr, 0)); -``` - -Many built-in actions (`WithArgs`, `WithoutArgs`,`DeleteArg`, `SaveArg`, ...) -could in principle support move-only arguments, but the support for this is not -implemented yet. If this is blocking you, please file a bug. - -A few actions (e.g. `DoAll`) copy their arguments internally, so they can never -work with non-copyable objects; you'll have to use functors instead. - -#### Legacy workarounds for move-only types {#LegacyMoveOnly} - -Support for move-only function arguments was only introduced to gMock in April -of 2017. In older code, you may encounter the following workaround for the lack -of this feature (it is no longer necessary - we're including it just for -reference): - -```cpp -class MockBuzzer : public Buzzer { - public: - MOCK_METHOD(bool, DoShareBuzz, (Buzz* buzz, Time timestamp)); - bool ShareBuzz(std::unique_ptr buzz, Time timestamp) override { - return DoShareBuzz(buzz.get(), timestamp); - } -}; -``` - -The trick is to delegate the `ShareBuzz()` method to a mock method (let’s call -it `DoShareBuzz()`) that does not take move-only parameters. Then, instead of -setting expectations on `ShareBuzz()`, you set them on the `DoShareBuzz()` mock -method: - -```cpp - MockBuzzer mock_buzzer_; - EXPECT_CALL(mock_buzzer_, DoShareBuzz(NotNull(), _)); - - // When one calls ShareBuzz() on the MockBuzzer like this, the call is - // forwarded to DoShareBuzz(), which is mocked. Therefore this statement - // will trigger the above EXPECT_CALL. - mock_buzzer_.ShareBuzz(MakeUnique(AccessLevel::kInternal), 0); -``` - -### Making the Compilation Faster - -Believe it or not, the *vast majority* of the time spent on compiling a mock -class is in generating its constructor and destructor, as they perform -non-trivial tasks (e.g. verification of the expectations). What's more, mock -methods with different signatures have different types and thus their -constructors/destructors need to be generated by the compiler separately. As a -result, if you mock many different types of methods, compiling your mock class -can get really slow. - -If you are experiencing slow compilation, you can move the definition of your -mock class' constructor and destructor out of the class body and into a `.cc` -file. This way, even if you `#include` your mock class in N files, the compiler -only needs to generate its constructor and destructor once, resulting in a much -faster compilation. - -Let's illustrate the idea using an example. Here's the definition of a mock -class before applying this recipe: - -```cpp -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // Since we don't declare the constructor or the destructor, - // the compiler will generate them in every translation unit - // where this mock class is used. - - MOCK_METHOD(int, DoThis, (), (override)); - MOCK_METHOD(bool, DoThat, (const char* str), (override)); - ... more mock methods ... -}; -``` - -After the change, it would look like: - -```cpp -// File mock_foo.h. -... -class MockFoo : public Foo { - public: - // The constructor and destructor are declared, but not defined, here. - MockFoo(); - virtual ~MockFoo(); - - MOCK_METHOD(int, DoThis, (), (override)); - MOCK_METHOD(bool, DoThat, (const char* str), (override)); - ... more mock methods ... -}; -``` - -and - -```cpp -// File mock_foo.cc. -#include "path/to/mock_foo.h" - -// The definitions may appear trivial, but the functions actually do a -// lot of things through the constructors/destructors of the member -// variables used to implement the mock methods. -MockFoo::MockFoo() {} -MockFoo::~MockFoo() {} -``` - -### Forcing a Verification - -When it's being destroyed, your friendly mock object will automatically verify -that all expectations on it have been satisfied, and will generate googletest -failures if not. This is convenient as it leaves you with one less thing to -worry about. That is, unless you are not sure if your mock object will be -destroyed. - -How could it be that your mock object won't eventually be destroyed? Well, it -might be created on the heap and owned by the code you are testing. Suppose -there's a bug in that code and it doesn't delete the mock object properly - you -could end up with a passing test when there's actually a bug. - -Using a heap checker is a good idea and can alleviate the concern, but its -implementation is not 100% reliable. So, sometimes you do want to *force* gMock -to verify a mock object before it is (hopefully) destructed. You can do this -with `Mock::VerifyAndClearExpectations(&mock_object)`: - -```cpp -TEST(MyServerTest, ProcessesRequest) { - using ::testing::Mock; - - MockFoo* const foo = new MockFoo; - EXPECT_CALL(*foo, ...)...; - // ... other expectations ... - - // server now owns foo. - MyServer server(foo); - server.ProcessRequest(...); - - // In case that server's destructor will forget to delete foo, - // this will verify the expectations anyway. - Mock::VerifyAndClearExpectations(foo); -} // server is destroyed when it goes out of scope here. -``` - -{: .callout .tip} -**Tip:** The `Mock::VerifyAndClearExpectations()` function returns a `bool` to -indicate whether the verification was successful (`true` for yes), so you can -wrap that function call inside a `ASSERT_TRUE()` if there is no point going -further when the verification has failed. - -### Using Check Points {#UsingCheckPoints} - -Sometimes you may want to "reset" a mock object at various check points in your -test: at each check point, you verify that all existing expectations on the mock -object have been satisfied, and then you set some new expectations on it as if -it's newly created. This allows you to work with a mock object in "phases" whose -sizes are each manageable. - -One such scenario is that in your test's `SetUp()` function, you may want to put -the object you are testing into a certain state, with the help from a mock -object. Once in the desired state, you want to clear all expectations on the -mock, such that in the `TEST_F` body you can set fresh expectations on it. - -As you may have figured out, the `Mock::VerifyAndClearExpectations()` function -we saw in the previous recipe can help you here. Or, if you are using -`ON_CALL()` to set default actions on the mock object and want to clear the -default actions as well, use `Mock::VerifyAndClear(&mock_object)` instead. This -function does what `Mock::VerifyAndClearExpectations(&mock_object)` does and -returns the same `bool`, **plus** it clears the `ON_CALL()` statements on -`mock_object` too. - -Another trick you can use to achieve the same effect is to put the expectations -in sequences and insert calls to a dummy "check-point" function at specific -places. Then you can verify that the mock function calls do happen at the right -time. For example, if you are exercising code: - -```cpp - Foo(1); - Foo(2); - Foo(3); -``` - -and want to verify that `Foo(1)` and `Foo(3)` both invoke `mock.Bar("a")`, but -`Foo(2)` doesn't invoke anything. You can write: - -```cpp -using ::testing::MockFunction; - -TEST(FooTest, InvokesBarCorrectly) { - MyMock mock; - // Class MockFunction has exactly one mock method. It is named - // Call() and has type F. - MockFunction check; - { - InSequence s; - - EXPECT_CALL(mock, Bar("a")); - EXPECT_CALL(check, Call("1")); - EXPECT_CALL(check, Call("2")); - EXPECT_CALL(mock, Bar("a")); - } - Foo(1); - check.Call("1"); - Foo(2); - check.Call("2"); - Foo(3); -} -``` - -The expectation spec says that the first `Bar("a")` must happen before check -point "1", the second `Bar("a")` must happen after check point "2", and nothing -should happen between the two check points. The explicit check points make it -easy to tell which `Bar("a")` is called by which call to `Foo()`. - -### Mocking Destructors - -Sometimes you want to make sure a mock object is destructed at the right time, -e.g. after `bar->A()` is called but before `bar->B()` is called. We already know -that you can specify constraints on the [order](#OrderedCalls) of mock function -calls, so all we need to do is to mock the destructor of the mock function. - -This sounds simple, except for one problem: a destructor is a special function -with special syntax and special semantics, and the `MOCK_METHOD` macro doesn't -work for it: - -```cpp -MOCK_METHOD(void, ~MockFoo, ()); // Won't compile! -``` - -The good news is that you can use a simple pattern to achieve the same effect. -First, add a mock function `Die()` to your mock class and call it in the -destructor, like this: - -```cpp -class MockFoo : public Foo { - ... - // Add the following two lines to the mock class. - MOCK_METHOD(void, Die, ()); - ~MockFoo() override { Die(); } -}; -``` - -(If the name `Die()` clashes with an existing symbol, choose another name.) Now, -we have translated the problem of testing when a `MockFoo` object dies to -testing when its `Die()` method is called: - -```cpp - MockFoo* foo = new MockFoo; - MockBar* bar = new MockBar; - ... - { - InSequence s; - - // Expects *foo to die after bar->A() and before bar->B(). - EXPECT_CALL(*bar, A()); - EXPECT_CALL(*foo, Die()); - EXPECT_CALL(*bar, B()); - } -``` - -And that's that. - -### Using gMock and Threads {#UsingThreads} - -In a **unit** test, it's best if you could isolate and test a piece of code in a -single-threaded context. That avoids race conditions and dead locks, and makes -debugging your test much easier. - -Yet most programs are multi-threaded, and sometimes to test something we need to -pound on it from more than one thread. gMock works for this purpose too. - -Remember the steps for using a mock: - -1. Create a mock object `foo`. -2. Set its default actions and expectations using `ON_CALL()` and - `EXPECT_CALL()`. -3. The code under test calls methods of `foo`. -4. Optionally, verify and reset the mock. -5. Destroy the mock yourself, or let the code under test destroy it. The - destructor will automatically verify it. - -If you follow the following simple rules, your mocks and threads can live -happily together: - -* Execute your *test code* (as opposed to the code being tested) in *one* - thread. This makes your test easy to follow. -* Obviously, you can do step #1 without locking. -* When doing step #2 and #5, make sure no other thread is accessing `foo`. - Obvious too, huh? -* #3 and #4 can be done either in one thread or in multiple threads - anyway - you want. gMock takes care of the locking, so you don't have to do any - - unless required by your test logic. - -If you violate the rules (for example, if you set expectations on a mock while -another thread is calling its methods), you get undefined behavior. That's not -fun, so don't do it. - -gMock guarantees that the action for a mock function is done in the same thread -that called the mock function. For example, in - -```cpp - EXPECT_CALL(mock, Foo(1)) - .WillOnce(action1); - EXPECT_CALL(mock, Foo(2)) - .WillOnce(action2); -``` - -if `Foo(1)` is called in thread 1 and `Foo(2)` is called in thread 2, gMock will -execute `action1` in thread 1 and `action2` in thread 2. - -gMock does *not* impose a sequence on actions performed in different threads -(doing so may create deadlocks as the actions may need to cooperate). This means -that the execution of `action1` and `action2` in the above example *may* -interleave. If this is a problem, you should add proper synchronization logic to -`action1` and `action2` to make the test thread-safe. - -Also, remember that `DefaultValue` is a global resource that potentially -affects *all* living mock objects in your program. Naturally, you won't want to -mess with it from multiple threads or when there still are mocks in action. - -### Controlling How Much Information gMock Prints - -When gMock sees something that has the potential of being an error (e.g. a mock -function with no expectation is called, a.k.a. an uninteresting call, which is -allowed but perhaps you forgot to explicitly ban the call), it prints some -warning messages, including the arguments of the function, the return value, and -the stack trace. Hopefully this will remind you to take a look and see if there -is indeed a problem. - -Sometimes you are confident that your tests are correct and may not appreciate -such friendly messages. Some other times, you are debugging your tests or -learning about the behavior of the code you are testing, and wish you could -observe every mock call that happens (including argument values, the return -value, and the stack trace). Clearly, one size doesn't fit all. - -You can control how much gMock tells you using the `--gmock_verbose=LEVEL` -command-line flag, where `LEVEL` is a string with three possible values: - -* `info`: gMock will print all informational messages, warnings, and errors - (most verbose). At this setting, gMock will also log any calls to the - `ON_CALL/EXPECT_CALL` macros. It will include a stack trace in - "uninteresting call" warnings. -* `warning`: gMock will print both warnings and errors (less verbose); it will - omit the stack traces in "uninteresting call" warnings. This is the default. -* `error`: gMock will print errors only (least verbose). - -Alternatively, you can adjust the value of that flag from within your tests like -so: - -```cpp - ::testing::FLAGS_gmock_verbose = "error"; -``` - -If you find gMock printing too many stack frames with its informational or -warning messages, remember that you can control their amount with the -`--gtest_stack_trace_depth=max_depth` flag. - -Now, judiciously use the right flag to enable gMock serve you better! - -### Gaining Super Vision into Mock Calls - -You have a test using gMock. It fails: gMock tells you some expectations aren't -satisfied. However, you aren't sure why: Is there a typo somewhere in the -matchers? Did you mess up the order of the `EXPECT_CALL`s? Or is the code under -test doing something wrong? How can you find out the cause? - -Won't it be nice if you have X-ray vision and can actually see the trace of all -`EXPECT_CALL`s and mock method calls as they are made? For each call, would you -like to see its actual argument values and which `EXPECT_CALL` gMock thinks it -matches? If you still need some help to figure out who made these calls, how -about being able to see the complete stack trace at each mock call? - -You can unlock this power by running your test with the `--gmock_verbose=info` -flag. For example, given the test program: - -```cpp -#include "gmock/gmock.h" - -using testing::_; -using testing::HasSubstr; -using testing::Return; - -class MockFoo { - public: - MOCK_METHOD(void, F, (const string& x, const string& y)); -}; - -TEST(Foo, Bar) { - MockFoo mock; - EXPECT_CALL(mock, F(_, _)).WillRepeatedly(Return()); - EXPECT_CALL(mock, F("a", "b")); - EXPECT_CALL(mock, F("c", HasSubstr("d"))); - - mock.F("a", "good"); - mock.F("a", "b"); -} -``` - -if you run it with `--gmock_verbose=info`, you will see this output: - -```shell -[ RUN ] Foo.Bar - -foo_test.cc:14: EXPECT_CALL(mock, F(_, _)) invoked -Stack trace: ... - -foo_test.cc:15: EXPECT_CALL(mock, F("a", "b")) invoked -Stack trace: ... - -foo_test.cc:16: EXPECT_CALL(mock, F("c", HasSubstr("d"))) invoked -Stack trace: ... - -foo_test.cc:14: Mock function call matches EXPECT_CALL(mock, F(_, _))... - Function call: F(@0x7fff7c8dad40"a",@0x7fff7c8dad10"good") -Stack trace: ... - -foo_test.cc:15: Mock function call matches EXPECT_CALL(mock, F("a", "b"))... - Function call: F(@0x7fff7c8dada0"a",@0x7fff7c8dad70"b") -Stack trace: ... - -foo_test.cc:16: Failure -Actual function call count doesn't match EXPECT_CALL(mock, F("c", HasSubstr("d")))... - Expected: to be called once - Actual: never called - unsatisfied and active -[ FAILED ] Foo.Bar -``` - -Suppose the bug is that the `"c"` in the third `EXPECT_CALL` is a typo and -should actually be `"a"`. With the above message, you should see that the actual -`F("a", "good")` call is matched by the first `EXPECT_CALL`, not the third as -you thought. From that it should be obvious that the third `EXPECT_CALL` is -written wrong. Case solved. - -If you are interested in the mock call trace but not the stack traces, you can -combine `--gmock_verbose=info` with `--gtest_stack_trace_depth=0` on the test -command line. - -### Running Tests in Emacs - -If you build and run your tests in Emacs using the `M-x google-compile` command -(as many googletest users do), the source file locations of gMock and googletest -errors will be highlighted. Just press `` on one of them and you'll be -taken to the offending line. Or, you can just type `C-x`` to jump to the next -error. - -To make it even easier, you can add the following lines to your `~/.emacs` file: - -```text -(global-set-key "\M-m" 'google-compile) ; m is for make -(global-set-key [M-down] 'next-error) -(global-set-key [M-up] '(lambda () (interactive) (next-error -1))) -``` - -Then you can type `M-m` to start a build (if you want to run the test as well, -just make sure `foo_test.run` or `runtests` is in the build command you supply -after typing `M-m`), or `M-up`/`M-down` to move back and forth between errors. - -## Extending gMock - -### Writing New Matchers Quickly {#NewMatchers} - -{: .callout .warning} -WARNING: gMock does not guarantee when or how many times a matcher will be -invoked. Therefore, all matchers must be functionally pure. See -[this section](#PureMatchers) for more details. - -The `MATCHER*` family of macros can be used to define custom matchers easily. -The syntax: - -```cpp -MATCHER(name, description_string_expression) { statements; } -``` - -will define a matcher with the given name that executes the statements, which -must return a `bool` to indicate if the match succeeds. Inside the statements, -you can refer to the value being matched by `arg`, and refer to its type by -`arg_type`. - -The *description string* is a `string`-typed expression that documents what the -matcher does, and is used to generate the failure message when the match fails. -It can (and should) reference the special `bool` variable `negation`, and should -evaluate to the description of the matcher when `negation` is `false`, or that -of the matcher's negation when `negation` is `true`. - -For convenience, we allow the description string to be empty (`""`), in which -case gMock will use the sequence of words in the matcher name as the -description. - -For example: - -```cpp -MATCHER(IsDivisibleBy7, "") { return (arg % 7) == 0; } -``` - -allows you to write - -```cpp - // Expects mock_foo.Bar(n) to be called where n is divisible by 7. - EXPECT_CALL(mock_foo, Bar(IsDivisibleBy7())); -``` - -or, - -```cpp - using ::testing::Not; - ... - // Verifies that two values are divisible by 7. - EXPECT_THAT(some_expression, IsDivisibleBy7()); - EXPECT_THAT(some_other_expression, Not(IsDivisibleBy7())); -``` - -If the above assertions fail, they will print something like: - -```shell - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 - ... - Value of: some_other_expression - Expected: not (is divisible by 7) - Actual: 21 -``` - -where the descriptions `"is divisible by 7"` and `"not (is divisible by 7)"` are -automatically calculated from the matcher name `IsDivisibleBy7`. - -As you may have noticed, the auto-generated descriptions (especially those for -the negation) may not be so great. You can always override them with a `string` -expression of your own: - -```cpp -MATCHER(IsDivisibleBy7, - absl::StrCat(negation ? "isn't" : "is", " divisible by 7")) { - return (arg % 7) == 0; -} -``` - -Optionally, you can stream additional information to a hidden argument named -`result_listener` to explain the match result. For example, a better definition -of `IsDivisibleBy7` is: - -```cpp -MATCHER(IsDivisibleBy7, "") { - if ((arg % 7) == 0) - return true; - - *result_listener << "the remainder is " << (arg % 7); - return false; -} -``` - -With this definition, the above assertion will give a better message: - -```shell - Value of: some_expression - Expected: is divisible by 7 - Actual: 27 (the remainder is 6) -``` - -You should let `MatchAndExplain()` print *any additional information* that can -help a user understand the match result. Note that it should explain why the -match succeeds in case of a success (unless it's obvious) - this is useful when -the matcher is used inside `Not()`. There is no need to print the argument value -itself, as gMock already prints it for you. - -{: .callout .note} -NOTE: The type of the value being matched (`arg_type`) is determined by the -context in which you use the matcher and is supplied to you by the compiler, so -you don't need to worry about declaring it (nor can you). This allows the -matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match -any type where the value of `(arg % 7) == 0` can be implicitly converted to a -`bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an -`int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will -be `unsigned long`; and so on. - -### Writing New Parameterized Matchers Quickly - -Sometimes you'll want to define a matcher that has parameters. For that you can -use the macro: - -```cpp -MATCHER_P(name, param_name, description_string) { statements; } -``` - -where the description string can be either `""` or a `string` expression that -references `negation` and `param_name`. - -For example: - -```cpp -MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -``` - -will allow you to write: - -```cpp - EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -``` - -which may lead to this message (assuming `n` is 10): - -```shell - Value of: Blah("a") - Expected: has absolute value 10 - Actual: -9 -``` - -Note that both the matcher description and its parameter are printed, making the -message human-friendly. - -In the matcher definition body, you can write `foo_type` to reference the type -of a parameter named `foo`. For example, in the body of -`MATCHER_P(HasAbsoluteValue, value)` above, you can write `value_type` to refer -to the type of `value`. - -gMock also provides `MATCHER_P2`, `MATCHER_P3`, ..., up to `MATCHER_P10` to -support multi-parameter matchers: - -```cpp -MATCHER_Pk(name, param_1, ..., param_k, description_string) { statements; } -``` - -Please note that the custom description string is for a particular *instance* of -the matcher, where the parameters have been bound to actual values. Therefore -usually you'll want the parameter values to be part of the description. gMock -lets you do that by referencing the matcher parameters in the description string -expression. - -For example, - -```cpp -using ::testing::PrintToString; -MATCHER_P2(InClosedRange, low, hi, - absl::StrFormat("%s in range [%s, %s]", negation ? "isn't" : "is", - PrintToString(low), PrintToString(hi))) { - return low <= arg && arg <= hi; -} -... -EXPECT_THAT(3, InClosedRange(4, 6)); -``` - -would generate a failure that contains the message: - -```shell - Expected: is in range [4, 6] -``` - -If you specify `""` as the description, the failure message will contain the -sequence of words in the matcher name followed by the parameter values printed -as a tuple. For example, - -```cpp - MATCHER_P2(InClosedRange, low, hi, "") { ... } - ... - EXPECT_THAT(3, InClosedRange(4, 6)); -``` - -would generate a failure that contains the text: - -```shell - Expected: in closed range (4, 6) -``` - -For the purpose of typing, you can view - -```cpp -MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } -``` - -as shorthand for - -```cpp -template -FooMatcherPk -Foo(p1_type p1, ..., pk_type pk) { ... } -``` - -When you write `Foo(v1, ..., vk)`, the compiler infers the types of the -parameters `v1`, ..., and `vk` for you. If you are not happy with the result of -the type inference, you can specify the types by explicitly instantiating the -template, as in `Foo(5, false)`. As said earlier, you don't get to -(or need to) specify `arg_type` as that's determined by the context in which the -matcher is used. - -You can assign the result of expression `Foo(p1, ..., pk)` to a variable of type -`FooMatcherPk`. This can be useful when composing -matchers. Matchers that don't have a parameter or have only one parameter have -special types: you can assign `Foo()` to a `FooMatcher`-typed variable, and -assign `Foo(p)` to a `FooMatcherP`-typed variable. - -While you can instantiate a matcher template with reference types, passing the -parameters by pointer usually makes your code more readable. If, however, you -still want to pass a parameter by reference, be aware that in the failure -message generated by the matcher you will see the value of the referenced object -but not its address. - -You can overload matchers with different numbers of parameters: - -```cpp -MATCHER_P(Blah, a, description_string_1) { ... } -MATCHER_P2(Blah, a, b, description_string_2) { ... } -``` - -While it's tempting to always use the `MATCHER*` macros when defining a new -matcher, you should also consider implementing the matcher interface directly -instead (see the recipes that follow), especially if you need to use the matcher -a lot. While these approaches require more work, they give you more control on -the types of the value being matched and the matcher parameters, which in -general leads to better compiler error messages that pay off in the long run. -They also allow overloading matchers based on parameter types (as opposed to -just based on the number of parameters). - -### Writing New Monomorphic Matchers - -A matcher of argument type `T` implements the matcher interface for `T` and does -two things: it tests whether a value of type `T` matches the matcher, and can -describe what kind of values it matches. The latter ability is used for -generating readable error messages when expectations are violated. - -A matcher of `T` must declare a typedef like: - -```cpp -using is_gtest_matcher = void; -``` - -and supports the following operations: - -```cpp -// Match a value and optionally explain into an ostream. -bool matched = matcher.MatchAndExplain(value, maybe_os); -// where `value` is of type `T` and -// `maybe_os` is of type `std::ostream*`, where it can be null if the caller -// is not interested in there textual explanation. - -matcher.DescribeTo(os); -matcher.DescribeNegationTo(os); -// where `os` is of type `std::ostream*`. -``` - -If you need a custom matcher but `Truly()` is not a good option (for example, -you may not be happy with the way `Truly(predicate)` describes itself, or you -may want your matcher to be polymorphic as `Eq(value)` is), you can define a -matcher to do whatever you want in two steps: first implement the matcher -interface, and then define a factory function to create a matcher instance. The -second step is not strictly needed but it makes the syntax of using the matcher -nicer. - -For example, you can define a matcher to test whether an `int` is divisible by 7 -and then use it like this: - -```cpp -using ::testing::Matcher; - -class DivisibleBy7Matcher { - public: - using is_gtest_matcher = void; - - bool MatchAndExplain(int n, std::ostream*) const { - return (n % 7) == 0; - } - - void DescribeTo(std::ostream* os) const { - *os << "is divisible by 7"; - } - - void DescribeNegationTo(std::ostream* os) const { - *os << "is not divisible by 7"; - } -}; - -Matcher DivisibleBy7() { - return DivisibleBy7Matcher(); -} - -... - EXPECT_CALL(foo, Bar(DivisibleBy7())); -``` - -You may improve the matcher message by streaming additional information to the -`os` argument in `MatchAndExplain()`: - -```cpp -class DivisibleBy7Matcher { - public: - bool MatchAndExplain(int n, std::ostream* os) const { - const int remainder = n % 7; - if (remainder != 0 && os != nullptr) { - *os << "the remainder is " << remainder; - } - return remainder == 0; - } - ... -}; -``` - -Then, `EXPECT_THAT(x, DivisibleBy7());` may generate a message like this: - -```shell -Value of: x -Expected: is divisible by 7 - Actual: 23 (the remainder is 2) -``` - -{: .callout .tip} -Tip: for convenience, `MatchAndExplain()` can take a `MatchResultListener*` -instead of `std::ostream*`. - -### Writing New Polymorphic Matchers - -Expanding what we learned above to *polymorphic* matchers is now just as simple -as adding templates in the right place. - -```cpp - -class NotNullMatcher { - public: - using is_gtest_matcher = void; - - // To implement a polymorphic matcher, we just need to make MatchAndExplain a - // template on its first argument. - - // In this example, we want to use NotNull() with any pointer, so - // MatchAndExplain() accepts a pointer of any type as its first argument. - // In general, you can define MatchAndExplain() as an ordinary method or - // a method template, or even overload it. - template - bool MatchAndExplain(T* p, std::ostream*) const { - return p != nullptr; - } - - // Describes the property of a value matching this matcher. - void DescribeTo(std::ostream& os) const { *os << "is not NULL"; } - - // Describes the property of a value NOT matching this matcher. - void DescribeNegationTo(std::ostream* os) const { *os << "is NULL"; } -}; - -NotNullMatcher NotNull() { - return NotNullMatcher(); -} - -... - - EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. -``` - -### Legacy Matcher Implementation - -Defining matchers used to be somewhat more complicated, in which it required -several supporting classes and virtual functions. To implement a matcher for -type `T` using the legacy API you have to derive from `MatcherInterface` and -call `MakeMatcher` to construct the object. - -The interface looks like this: - -```cpp -class MatchResultListener { - public: - ... - // Streams x to the underlying ostream; does nothing if the ostream - // is NULL. - template - MatchResultListener& operator<<(const T& x); - - // Returns the underlying ostream. - std::ostream* stream(); -}; - -template -class MatcherInterface { - public: - virtual ~MatcherInterface(); - - // Returns true if and only if the matcher matches x; also explains the match - // result to 'listener'. - virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0; - - // Describes this matcher to an ostream. - virtual void DescribeTo(std::ostream* os) const = 0; - - // Describes the negation of this matcher to an ostream. - virtual void DescribeNegationTo(std::ostream* os) const; -}; -``` - -Fortunately, most of the time you can define a polymorphic matcher easily with -the help of `MakePolymorphicMatcher()`. Here's how you can define `NotNull()` as -an example: - -```cpp -using ::testing::MakePolymorphicMatcher; -using ::testing::MatchResultListener; -using ::testing::PolymorphicMatcher; - -class NotNullMatcher { - public: - // To implement a polymorphic matcher, first define a COPYABLE class - // that has three members MatchAndExplain(), DescribeTo(), and - // DescribeNegationTo(), like the following. - - // In this example, we want to use NotNull() with any pointer, so - // MatchAndExplain() accepts a pointer of any type as its first argument. - // In general, you can define MatchAndExplain() as an ordinary method or - // a method template, or even overload it. - template - bool MatchAndExplain(T* p, - MatchResultListener* /* listener */) const { - return p != NULL; - } - - // Describes the property of a value matching this matcher. - void DescribeTo(std::ostream* os) const { *os << "is not NULL"; } - - // Describes the property of a value NOT matching this matcher. - void DescribeNegationTo(std::ostream* os) const { *os << "is NULL"; } -}; - -// To construct a polymorphic matcher, pass an instance of the class -// to MakePolymorphicMatcher(). Note the return type. -PolymorphicMatcher NotNull() { - return MakePolymorphicMatcher(NotNullMatcher()); -} - -... - - EXPECT_CALL(foo, Bar(NotNull())); // The argument must be a non-NULL pointer. -``` - -{: .callout .note} -**Note:** Your polymorphic matcher class does **not** need to inherit from -`MatcherInterface` or any other class, and its methods do **not** need to be -virtual. - -Like in a monomorphic matcher, you may explain the match result by streaming -additional information to the `listener` argument in `MatchAndExplain()`. - -### Writing New Cardinalities - -A cardinality is used in `Times()` to tell gMock how many times you expect a -call to occur. It doesn't have to be exact. For example, you can say -`AtLeast(5)` or `Between(2, 4)`. - -If the [built-in set](gmock_cheat_sheet.md#CardinalityList) of cardinalities -doesn't suit you, you are free to define your own by implementing the following -interface (in namespace `testing`): - -```cpp -class CardinalityInterface { - public: - virtual ~CardinalityInterface(); - - // Returns true if and only if call_count calls will satisfy this cardinality. - virtual bool IsSatisfiedByCallCount(int call_count) const = 0; - - // Returns true if and only if call_count calls will saturate this - // cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const = 0; - - // Describes self to an ostream. - virtual void DescribeTo(std::ostream* os) const = 0; -}; -``` - -For example, to specify that a call must occur even number of times, you can -write - -```cpp -using ::testing::Cardinality; -using ::testing::CardinalityInterface; -using ::testing::MakeCardinality; - -class EvenNumberCardinality : public CardinalityInterface { - public: - bool IsSatisfiedByCallCount(int call_count) const override { - return (call_count % 2) == 0; - } - - bool IsSaturatedByCallCount(int call_count) const override { - return false; - } - - void DescribeTo(std::ostream* os) const { - *os << "called even number of times"; - } -}; - -Cardinality EvenNumber() { - return MakeCardinality(new EvenNumberCardinality); -} - -... - EXPECT_CALL(foo, Bar(3)) - .Times(EvenNumber()); -``` - -### Writing New Actions Quickly {#QuickNewActions} - -If the built-in actions don't work for you, you can easily define your own one. -Just define a functor class with a (possibly templated) call operator, matching -the signature of your action. - -```cpp -struct Increment { - template - T operator()(T* arg) { - return ++(*arg); - } -} -``` - -The same approach works with stateful functors (or any callable, really): - -``` -struct MultiplyBy { - template - T operator()(T arg) { return arg * multiplier; } - - int multiplier; -} - -// Then use: -// EXPECT_CALL(...).WillOnce(MultiplyBy{7}); -``` - -#### Legacy macro-based Actions - -Before C++11, the functor-based actions were not supported; the old way of -writing actions was through a set of `ACTION*` macros. We suggest to avoid them -in new code; they hide a lot of logic behind the macro, potentially leading to -harder-to-understand compiler errors. Nevertheless, we cover them here for -completeness. - -By writing - -```cpp -ACTION(name) { statements; } -``` - -in a namespace scope (i.e. not inside a class or function), you will define an -action with the given name that executes the statements. The value returned by -`statements` will be used as the return value of the action. Inside the -statements, you can refer to the K-th (0-based) argument of the mock function as -`argK`. For example: - -```cpp -ACTION(IncrementArg1) { return ++(*arg1); } -``` - -allows you to write - -```cpp -... WillOnce(IncrementArg1()); -``` - -Note that you don't need to specify the types of the mock function arguments. -Rest assured that your code is type-safe though: you'll get a compiler error if -`*arg1` doesn't support the `++` operator, or if the type of `++(*arg1)` isn't -compatible with the mock function's return type. - -Another example: - -```cpp -ACTION(Foo) { - (*arg2)(5); - Blah(); - *arg1 = 0; - return arg0; -} -``` - -defines an action `Foo()` that invokes argument #2 (a function pointer) with 5, -calls function `Blah()`, sets the value pointed to by argument #1 to 0, and -returns argument #0. - -For more convenience and flexibility, you can also use the following pre-defined -symbols in the body of `ACTION`: - -`argK_type` | The type of the K-th (0-based) argument of the mock function -:-------------- | :----------------------------------------------------------- -`args` | All arguments of the mock function as a tuple -`args_type` | The type of all arguments of the mock function as a tuple -`return_type` | The return type of the mock function -`function_type` | The type of the mock function - -For example, when using an `ACTION` as a stub action for mock function: - -```cpp -int DoSomething(bool flag, int* ptr); -``` - -we have: - -Pre-defined Symbol | Is Bound To ------------------- | --------------------------------- -`arg0` | the value of `flag` -`arg0_type` | the type `bool` -`arg1` | the value of `ptr` -`arg1_type` | the type `int*` -`args` | the tuple `(flag, ptr)` -`args_type` | the type `std::tuple` -`return_type` | the type `int` -`function_type` | the type `int(bool, int*)` - -#### Legacy macro-based parameterized Actions - -Sometimes you'll want to parameterize an action you define. For that we have -another macro - -```cpp -ACTION_P(name, param) { statements; } -``` - -For example, - -```cpp -ACTION_P(Add, n) { return arg0 + n; } -``` - -will allow you to write - -```cpp -// Returns argument #0 + 5. -... WillOnce(Add(5)); -``` - -For convenience, we use the term *arguments* for the values used to invoke the -mock function, and the term *parameters* for the values used to instantiate an -action. - -Note that you don't need to provide the type of the parameter either. Suppose -the parameter is named `param`, you can also use the gMock-defined symbol -`param_type` to refer to the type of the parameter as inferred by the compiler. -For example, in the body of `ACTION_P(Add, n)` above, you can write `n_type` for -the type of `n`. - -gMock also provides `ACTION_P2`, `ACTION_P3`, and etc to support multi-parameter -actions. For example, - -```cpp -ACTION_P2(ReturnDistanceTo, x, y) { - double dx = arg0 - x; - double dy = arg1 - y; - return sqrt(dx*dx + dy*dy); -} -``` - -lets you write - -```cpp -... WillOnce(ReturnDistanceTo(5.0, 26.5)); -``` - -You can view `ACTION` as a degenerated parameterized action where the number of -parameters is 0. - -You can also easily define actions overloaded on the number of parameters: - -```cpp -ACTION_P(Plus, a) { ... } -ACTION_P2(Plus, a, b) { ... } -``` - -### Restricting the Type of an Argument or Parameter in an ACTION - -For maximum brevity and reusability, the `ACTION*` macros don't ask you to -provide the types of the mock function arguments and the action parameters. -Instead, we let the compiler infer the types for us. - -Sometimes, however, we may want to be more explicit about the types. There are -several tricks to do that. For example: - -```cpp -ACTION(Foo) { - // Makes sure arg0 can be converted to int. - int n = arg0; - ... use n instead of arg0 here ... -} - -ACTION_P(Bar, param) { - // Makes sure the type of arg1 is const char*. - ::testing::StaticAssertTypeEq(); - - // Makes sure param can be converted to bool. - bool flag = param; -} -``` - -where `StaticAssertTypeEq` is a compile-time assertion in googletest that -verifies two types are the same. - -### Writing New Action Templates Quickly - -Sometimes you want to give an action explicit template parameters that cannot be -inferred from its value parameters. `ACTION_TEMPLATE()` supports that and can be -viewed as an extension to `ACTION()` and `ACTION_P*()`. - -The syntax: - -```cpp -ACTION_TEMPLATE(ActionName, - HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m), - AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; } -``` - -defines an action template that takes *m* explicit template parameters and *n* -value parameters, where *m* is in [1, 10] and *n* is in [0, 10]. `name_i` is the -name of the *i*-th template parameter, and `kind_i` specifies whether it's a -`typename`, an integral constant, or a template. `p_i` is the name of the *i*-th -value parameter. - -Example: - -```cpp -// DuplicateArg(output) converts the k-th argument of the mock -// function to type T and copies it to *output. -ACTION_TEMPLATE(DuplicateArg, - // Note the comma between int and k: - HAS_2_TEMPLATE_PARAMS(int, k, typename, T), - AND_1_VALUE_PARAMS(output)) { - *output = T(std::get(args)); -} -``` - -To create an instance of an action template, write: - -```cpp -ActionName(v1, ..., v_n) -``` - -where the `t`s are the template arguments and the `v`s are the value arguments. -The value argument types are inferred by the compiler. For example: - -```cpp -using ::testing::_; -... - int n; - EXPECT_CALL(mock, Foo).WillOnce(DuplicateArg<1, unsigned char>(&n)); -``` - -If you want to explicitly specify the value argument types, you can provide -additional template arguments: - -```cpp -ActionName(v1, ..., v_n) -``` - -where `u_i` is the desired type of `v_i`. - -`ACTION_TEMPLATE` and `ACTION`/`ACTION_P*` can be overloaded on the number of -value parameters, but not on the number of template parameters. Without the -restriction, the meaning of the following is unclear: - -```cpp - OverloadedAction(x); -``` - -Are we using a single-template-parameter action where `bool` refers to the type -of `x`, or a two-template-parameter action where the compiler is asked to infer -the type of `x`? - -### Using the ACTION Object's Type - -If you are writing a function that returns an `ACTION` object, you'll need to -know its type. The type depends on the macro used to define the action and the -parameter types. The rule is relatively simple: - - -| Given Definition | Expression | Has Type | -| ----------------------------- | ------------------- | --------------------- | -| `ACTION(Foo)` | `Foo()` | `FooAction` | -| `ACTION_TEMPLATE(Foo, HAS_m_TEMPLATE_PARAMS(...), AND_0_VALUE_PARAMS())` | `Foo()` | `FooAction` | -| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP` | -| `ACTION_TEMPLATE(Bar, HAS_m_TEMPLATE_PARAMS(...), AND_1_VALUE_PARAMS(p1))` | `Bar(int_value)` | `BarActionP` | -| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2` | -| `ACTION_TEMPLATE(Baz, HAS_m_TEMPLATE_PARAMS(...), AND_2_VALUE_PARAMS(p1, p2))` | `Baz(bool_value, int_value)` | `BazActionP2` | -| ... | ... | ... | - - -Note that we have to pick different suffixes (`Action`, `ActionP`, `ActionP2`, -and etc) for actions with different numbers of value parameters, or the action -definitions cannot be overloaded on the number of them. - -### Writing New Monomorphic Actions {#NewMonoActions} - -While the `ACTION*` macros are very convenient, sometimes they are -inappropriate. For example, despite the tricks shown in the previous recipes, -they don't let you directly specify the types of the mock function arguments and -the action parameters, which in general leads to unoptimized compiler error -messages that can baffle unfamiliar users. They also don't allow overloading -actions based on parameter types without jumping through some hoops. - -An alternative to the `ACTION*` macros is to implement -`::testing::ActionInterface`, where `F` is the type of the mock function in -which the action will be used. For example: - -```cpp -template -class ActionInterface { - public: - virtual ~ActionInterface(); - - // Performs the action. Result is the return type of function type - // F, and ArgumentTuple is the tuple of arguments of F. - // - - // For example, if F is int(bool, const string&), then Result would - // be int, and ArgumentTuple would be std::tuple. - virtual Result Perform(const ArgumentTuple& args) = 0; -}; -``` - -```cpp -using ::testing::_; -using ::testing::Action; -using ::testing::ActionInterface; -using ::testing::MakeAction; - -typedef int IncrementMethod(int*); - -class IncrementArgumentAction : public ActionInterface { - public: - int Perform(const std::tuple& args) override { - int* p = std::get<0>(args); // Grabs the first argument. - return *p++; - } -}; - -Action IncrementArgument() { - return MakeAction(new IncrementArgumentAction); -} - -... - EXPECT_CALL(foo, Baz(_)) - .WillOnce(IncrementArgument()); - - int n = 5; - foo.Baz(&n); // Should return 5 and change n to 6. -``` - -### Writing New Polymorphic Actions {#NewPolyActions} - -The previous recipe showed you how to define your own action. This is all good, -except that you need to know the type of the function in which the action will -be used. Sometimes that can be a problem. For example, if you want to use the -action in functions with *different* types (e.g. like `Return()` and -`SetArgPointee()`). - -If an action can be used in several types of mock functions, we say it's -*polymorphic*. The `MakePolymorphicAction()` function template makes it easy to -define such an action: - -```cpp -namespace testing { -template -PolymorphicAction MakePolymorphicAction(const Impl& impl); -} // namespace testing -``` - -As an example, let's define an action that returns the second argument in the -mock function's argument list. The first step is to define an implementation -class: - -```cpp -class ReturnSecondArgumentAction { - public: - template - Result Perform(const ArgumentTuple& args) const { - // To get the i-th (0-based) argument, use std::get(args). - return std::get<1>(args); - } -}; -``` - -This implementation class does *not* need to inherit from any particular class. -What matters is that it must have a `Perform()` method template. This method -template takes the mock function's arguments as a tuple in a **single** -argument, and returns the result of the action. It can be either `const` or not, -but must be invokable with exactly one template argument, which is the result -type. In other words, you must be able to call `Perform(args)` where `R` is -the mock function's return type and `args` is its arguments in a tuple. - -Next, we use `MakePolymorphicAction()` to turn an instance of the implementation -class into the polymorphic action we need. It will be convenient to have a -wrapper for this: - -```cpp -using ::testing::MakePolymorphicAction; -using ::testing::PolymorphicAction; - -PolymorphicAction ReturnSecondArgument() { - return MakePolymorphicAction(ReturnSecondArgumentAction()); -} -``` - -Now, you can use this polymorphic action the same way you use the built-in ones: - -```cpp -using ::testing::_; - -class MockFoo : public Foo { - public: - MOCK_METHOD(int, DoThis, (bool flag, int n), (override)); - MOCK_METHOD(string, DoThat, (int x, const char* str1, const char* str2), - (override)); -}; - - ... - MockFoo foo; - EXPECT_CALL(foo, DoThis).WillOnce(ReturnSecondArgument()); - EXPECT_CALL(foo, DoThat).WillOnce(ReturnSecondArgument()); - ... - foo.DoThis(true, 5); // Will return 5. - foo.DoThat(1, "Hi", "Bye"); // Will return "Hi". -``` - -### Teaching gMock How to Print Your Values - -When an uninteresting or unexpected call occurs, gMock prints the argument -values and the stack trace to help you debug. Assertion macros like -`EXPECT_THAT` and `EXPECT_EQ` also print the values in question when the -assertion fails. gMock and googletest do this using googletest's user-extensible -value printer. - -This printer knows how to print built-in C++ types, native arrays, STL -containers, and any type that supports the `<<` operator. For other types, it -prints the raw bytes in the value and hopes that you the user can figure it out. -[The GoogleTest advanced guide](advanced.md#teaching-googletest-how-to-print-your-values) -explains how to extend the printer to do a better job at printing your -particular type than to dump the bytes. - -## Useful Mocks Created Using gMock - - - - -### Mock std::function {#MockFunction} - -`std::function` is a general function type introduced in C++11. It is a -preferred way of passing callbacks to new interfaces. Functions are copiable, -and are not usually passed around by pointer, which makes them tricky to mock. -But fear not - `MockFunction` can help you with that. - -`MockFunction` has a mock method `Call()` with the signature: - -```cpp - R Call(T1, ..., Tn); -``` - -It also has a `AsStdFunction()` method, which creates a `std::function` proxy -forwarding to Call: - -```cpp - std::function AsStdFunction(); -``` - -To use `MockFunction`, first create `MockFunction` object and set up -expectations on its `Call` method. Then pass proxy obtained from -`AsStdFunction()` to the code you are testing. For example: - -```cpp -TEST(FooTest, RunsCallbackWithBarArgument) { - // 1. Create a mock object. - MockFunction mock_function; - - // 2. Set expectations on Call() method. - EXPECT_CALL(mock_function, Call("bar")).WillOnce(Return(1)); - - // 3. Exercise code that uses std::function. - Foo(mock_function.AsStdFunction()); - // Foo's signature can be either of: - // void Foo(const std::function& fun); - // void Foo(std::function fun); - - // 4. All expectations will be verified when mock_function - // goes out of scope and is destroyed. -} -``` - -Remember that function objects created with `AsStdFunction()` are just -forwarders. If you create multiple of them, they will share the same set of -expectations. - -Although `std::function` supports unlimited number of arguments, `MockFunction` -implementation is limited to ten. If you ever hit that limit... well, your -callback has bigger problems than being mockable. :-) diff --git a/vendor/googletest/gtest/docs/gmock_faq.md b/vendor/googletest/gtest/docs/gmock_faq.md deleted file mode 100644 index 09623b4e..00000000 --- a/vendor/googletest/gtest/docs/gmock_faq.md +++ /dev/null @@ -1,390 +0,0 @@ -# Legacy gMock FAQ - -### When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? - -In order for a method to be mocked, it must be *virtual*, unless you use the -[high-perf dependency injection technique](gmock_cook_book.md#MockingNonVirtualMethods). - -### Can I mock a variadic function? - -You cannot mock a variadic function (i.e. a function taking ellipsis (`...`) -arguments) directly in gMock. - -The problem is that in general, there is *no way* for a mock object to know how -many arguments are passed to the variadic method, and what the arguments' types -are. Only the *author of the base class* knows the protocol, and we cannot look -into his or her head. - -Therefore, to mock such a function, the *user* must teach the mock object how to -figure out the number of arguments and their types. One way to do it is to -provide overloaded versions of the function. - -Ellipsis arguments are inherited from C and not really a C++ feature. They are -unsafe to use and don't work with arguments that have constructors or -destructors. Therefore we recommend to avoid them in C++ as much as possible. - -### MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? - -If you compile this using Microsoft Visual C++ 2005 SP1: - -```cpp -class Foo { - ... - virtual void Bar(const int i) = 0; -}; - -class MockFoo : public Foo { - ... - MOCK_METHOD(void, Bar, (const int i), (override)); -}; -``` - -You may get the following warning: - -```shell -warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier -``` - -This is a MSVC bug. The same code compiles fine with gcc, for example. If you -use Visual C++ 2008 SP1, you would get the warning: - -```shell -warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers -``` - -In C++, if you *declare* a function with a `const` parameter, the `const` -modifier is ignored. Therefore, the `Foo` base class above is equivalent to: - -```cpp -class Foo { - ... - virtual void Bar(int i) = 0; // int or const int? Makes no difference. -}; -``` - -In fact, you can *declare* `Bar()` with an `int` parameter, and define it with a -`const int` parameter. The compiler will still match them up. - -Since making a parameter `const` is meaningless in the method declaration, we -recommend to remove it in both `Foo` and `MockFoo`. That should workaround the -VC bug. - -Note that we are talking about the *top-level* `const` modifier here. If the -function parameter is passed by pointer or reference, declaring the pointee or -referee as `const` is still meaningful. For example, the following two -declarations are *not* equivalent: - -```cpp -void Bar(int* p); // Neither p nor *p is const. -void Bar(const int* p); // p is not const, but *p is. -``` - -### I can't figure out why gMock thinks my expectations are not satisfied. What should I do? - -You might want to run your test with `--gmock_verbose=info`. This flag lets -gMock print a trace of every mock function call it receives. By studying the -trace, you'll gain insights on why the expectations you set are not met. - -If you see the message "The mock function has no default action set, and its -return type has no default value set.", then try -[adding a default action](gmock_for_dummies.md#DefaultValue). Due to a known -issue, unexpected calls on mocks without default actions don't print out a -detailed comparison between the actual arguments and the expected arguments. - -### My program crashed and `ScopedMockLog` spit out tons of messages. Is it a gMock bug? - -gMock and `ScopedMockLog` are likely doing the right thing here. - -When a test crashes, the failure signal handler will try to log a lot of -information (the stack trace, and the address map, for example). The messages -are compounded if you have many threads with depth stacks. When `ScopedMockLog` -intercepts these messages and finds that they don't match any expectations, it -prints an error for each of them. - -You can learn to ignore the errors, or you can rewrite your expectations to make -your test more robust, for example, by adding something like: - -```cpp -using ::testing::AnyNumber; -using ::testing::Not; -... - // Ignores any log not done by us. - EXPECT_CALL(log, Log(_, Not(EndsWith("/my_file.cc")), _)) - .Times(AnyNumber()); -``` - -### How can I assert that a function is NEVER called? - -```cpp -using ::testing::_; -... - EXPECT_CALL(foo, Bar(_)) - .Times(0); -``` - -### I have a failed test where gMock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? - -When gMock detects a failure, it prints relevant information (the mock function -arguments, the state of relevant expectations, and etc) to help the user debug. -If another failure is detected, gMock will do the same, including printing the -state of relevant expectations. - -Sometimes an expectation's state didn't change between two failures, and you'll -see the same description of the state twice. They are however *not* redundant, -as they refer to *different points in time*. The fact they are the same *is* -interesting information. - -### I get a heapcheck failure when using a mock object, but using a real object is fine. What can be wrong? - -Does the class (hopefully a pure interface) you are mocking have a virtual -destructor? - -Whenever you derive from a base class, make sure its destructor is virtual. -Otherwise Bad Things will happen. Consider the following code: - -```cpp -class Base { - public: - // Not virtual, but should be. - ~Base() { ... } - ... -}; - -class Derived : public Base { - public: - ... - private: - std::string value_; -}; - -... - Base* p = new Derived; - ... - delete p; // Surprise! ~Base() will be called, but ~Derived() will not - // - value_ is leaked. -``` - -By changing `~Base()` to virtual, `~Derived()` will be correctly called when -`delete p` is executed, and the heap checker will be happy. - -### The "newer expectations override older ones" rule makes writing expectations awkward. Why does gMock do that? - -When people complain about this, often they are referring to code like: - -```cpp -using ::testing::Return; -... - // foo.Bar() should be called twice, return 1 the first time, and return - // 2 the second time. However, I have to write the expectations in the - // reverse order. This sucks big time!!! - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); -``` - -The problem, is that they didn't pick the **best** way to express the test's -intent. - -By default, expectations don't have to be matched in *any* particular order. If -you want them to match in a certain order, you need to be explicit. This is -gMock's (and jMock's) fundamental philosophy: it's easy to accidentally -over-specify your tests, and we want to make it harder to do so. - -There are two better ways to write the test spec. You could either put the -expectations in sequence: - -```cpp -using ::testing::Return; -... - // foo.Bar() should be called twice, return 1 the first time, and return - // 2 the second time. Using a sequence, we can write the expectations - // in their natural order. - { - InSequence s; - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .RetiresOnSaturation(); - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(2)) - .RetiresOnSaturation(); - } -``` - -or you can put the sequence of actions in the same expectation: - -```cpp -using ::testing::Return; -... - // foo.Bar() should be called twice, return 1 the first time, and return - // 2 the second time. - EXPECT_CALL(foo, Bar()) - .WillOnce(Return(1)) - .WillOnce(Return(2)) - .RetiresOnSaturation(); -``` - -Back to the original questions: why does gMock search the expectations (and -`ON_CALL`s) from back to front? Because this allows a user to set up a mock's -behavior for the common case early (e.g. in the mock's constructor or the test -fixture's set-up phase) and customize it with more specific rules later. If -gMock searches from front to back, this very useful pattern won't be possible. - -### gMock prints a warning when a function without EXPECT_CALL is called, even if I have set its behavior using ON_CALL. Would it be reasonable not to show the warning in this case? - -When choosing between being neat and being safe, we lean toward the latter. So -the answer is that we think it's better to show the warning. - -Often people write `ON_CALL`s in the mock object's constructor or `SetUp()`, as -the default behavior rarely changes from test to test. Then in the test body -they set the expectations, which are often different for each test. Having an -`ON_CALL` in the set-up part of a test doesn't mean that the calls are expected. -If there's no `EXPECT_CALL` and the method is called, it's possibly an error. If -we quietly let the call go through without notifying the user, bugs may creep in -unnoticed. - -If, however, you are sure that the calls are OK, you can write - -```cpp -using ::testing::_; -... - EXPECT_CALL(foo, Bar(_)) - .WillRepeatedly(...); -``` - -instead of - -```cpp -using ::testing::_; -... - ON_CALL(foo, Bar(_)) - .WillByDefault(...); -``` - -This tells gMock that you do expect the calls and no warning should be printed. - -Also, you can control the verbosity by specifying `--gmock_verbose=error`. Other -values are `info` and `warning`. If you find the output too noisy when -debugging, just choose a less verbose level. - -### How can I delete the mock function's argument in an action? - -If your mock function takes a pointer argument and you want to delete that -argument, you can use testing::DeleteArg() to delete the N'th (zero-indexed) -argument: - -```cpp -using ::testing::_; - ... - MOCK_METHOD(void, Bar, (X* x, const Y& y)); - ... - EXPECT_CALL(mock_foo_, Bar(_, _)) - .WillOnce(testing::DeleteArg<0>())); -``` - -### How can I perform an arbitrary action on a mock function's argument? - -If you find yourself needing to perform some action that's not supported by -gMock directly, remember that you can define your own actions using -[`MakeAction()`](#NewMonoActions) or -[`MakePolymorphicAction()`](#NewPolyActions), or you can write a stub function -and invoke it using [`Invoke()`](#FunctionsAsActions). - -```cpp -using ::testing::_; -using ::testing::Invoke; - ... - MOCK_METHOD(void, Bar, (X* p)); - ... - EXPECT_CALL(mock_foo_, Bar(_)) - .WillOnce(Invoke(MyAction(...))); -``` - -### My code calls a static/global function. Can I mock it? - -You can, but you need to make some changes. - -In general, if you find yourself needing to mock a static function, it's a sign -that your modules are too tightly coupled (and less flexible, less reusable, -less testable, etc). You are probably better off defining a small interface and -call the function through that interface, which then can be easily mocked. It's -a bit of work initially, but usually pays for itself quickly. - -This Google Testing Blog -[post](https://testing.googleblog.com/2008/06/defeat-static-cling.html) says it -excellently. Check it out. - -### My mock object needs to do complex stuff. It's a lot of pain to specify the actions. gMock sucks! - -I know it's not a question, but you get an answer for free any way. :-) - -With gMock, you can create mocks in C++ easily. And people might be tempted to -use them everywhere. Sometimes they work great, and sometimes you may find them, -well, a pain to use. So, what's wrong in the latter case? - -When you write a test without using mocks, you exercise the code and assert that -it returns the correct value or that the system is in an expected state. This is -sometimes called "state-based testing". - -Mocks are great for what some call "interaction-based" testing: instead of -checking the system state at the very end, mock objects verify that they are -invoked the right way and report an error as soon as it arises, giving you a -handle on the precise context in which the error was triggered. This is often -more effective and economical to do than state-based testing. - -If you are doing state-based testing and using a test double just to simulate -the real object, you are probably better off using a fake. Using a mock in this -case causes pain, as it's not a strong point for mocks to perform complex -actions. If you experience this and think that mocks suck, you are just not -using the right tool for your problem. Or, you might be trying to solve the -wrong problem. :-) - -### I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? - -By all means, NO! It's just an FYI. :-) - -What it means is that you have a mock function, you haven't set any expectations -on it (by gMock's rule this means that you are not interested in calls to this -function and therefore it can be called any number of times), and it is called. -That's OK - you didn't say it's not OK to call the function! - -What if you actually meant to disallow this function to be called, but forgot to -write `EXPECT_CALL(foo, Bar()).Times(0)`? While one can argue that it's the -user's fault, gMock tries to be nice and prints you a note. - -So, when you see the message and believe that there shouldn't be any -uninteresting calls, you should investigate what's going on. To make your life -easier, gMock dumps the stack trace when an uninteresting call is encountered. -From that you can figure out which mock function it is, and how it is called. - -### I want to define a custom action. Should I use Invoke() or implement the ActionInterface interface? - -Either way is fine - you want to choose the one that's more convenient for your -circumstance. - -Usually, if your action is for a particular function type, defining it using -`Invoke()` should be easier; if your action can be used in functions of -different types (e.g. if you are defining `Return(*value*)`), -`MakePolymorphicAction()` is easiest. Sometimes you want precise control on what -types of functions the action can be used in, and implementing `ActionInterface` -is the way to go here. See the implementation of `Return()` in -`testing/base/public/gmock-actions.h` for an example. - -### I use SetArgPointee() in WillOnce(), but gcc complains about "conflicting return type specified". What does it mean? - -You got this error as gMock has no idea what value it should return when the -mock method is called. `SetArgPointee()` says what the side effect is, but -doesn't say what the return value should be. You need `DoAll()` to chain a -`SetArgPointee()` with a `Return()` that provides a value appropriate to the API -being mocked. - -See this [recipe](gmock_cook_book.md#mocking-side-effects) for more details and -an example. - -### I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? - -We've noticed that when the `/clr` compiler flag is used, Visual C++ uses 5~6 -times as much memory when compiling a mock class. We suggest to avoid `/clr` -when compiling native C++ mocks. diff --git a/vendor/googletest/gtest/docs/gmock_for_dummies.md b/vendor/googletest/gtest/docs/gmock_for_dummies.md deleted file mode 100644 index 6e41cafe..00000000 --- a/vendor/googletest/gtest/docs/gmock_for_dummies.md +++ /dev/null @@ -1,699 +0,0 @@ -# gMock for Dummies - -## What Is gMock? - -When you write a prototype or test, often it's not feasible or wise to rely on -real objects entirely. A **mock object** implements the same interface as a real -object (so it can be used as one), but lets you specify at run time how it will -be used and what it should do (which methods will be called? in which order? how -many times? with what arguments? what will they return? etc). - -It is easy to confuse the term *fake objects* with mock objects. Fakes and mocks -actually mean very different things in the Test-Driven Development (TDD) -community: - -* **Fake** objects have working implementations, but usually take some - shortcut (perhaps to make the operations less expensive), which makes them - not suitable for production. An in-memory file system would be an example of - a fake. -* **Mocks** are objects pre-programmed with *expectations*, which form a - specification of the calls they are expected to receive. - -If all this seems too abstract for you, don't worry - the most important thing -to remember is that a mock allows you to check the *interaction* between itself -and code that uses it. The difference between fakes and mocks shall become much -clearer once you start to use mocks. - -**gMock** is a library (sometimes we also call it a "framework" to make it sound -cool) for creating mock classes and using them. It does to C++ what -jMock/EasyMock does to Java (well, more or less). - -When using gMock, - -1. first, you use some simple macros to describe the interface you want to - mock, and they will expand to the implementation of your mock class; -2. next, you create some mock objects and specify its expectations and behavior - using an intuitive syntax; -3. then you exercise code that uses the mock objects. gMock will catch any - violation to the expectations as soon as it arises. - -## Why gMock? - -While mock objects help you remove unnecessary dependencies in tests and make -them fast and reliable, using mocks manually in C++ is *hard*: - -* Someone has to implement the mocks. The job is usually tedious and - error-prone. No wonder people go great distance to avoid it. -* The quality of those manually written mocks is a bit, uh, unpredictable. You - may see some really polished ones, but you may also see some that were - hacked up in a hurry and have all sorts of ad hoc restrictions. -* The knowledge you gained from using one mock doesn't transfer to the next - one. - -In contrast, Java and Python programmers have some fine mock frameworks (jMock, -EasyMock, etc), which automate the creation of mocks. As a result, mocking is a -proven effective technique and widely adopted practice in those communities. -Having the right tool absolutely makes the difference. - -gMock was built to help C++ programmers. It was inspired by jMock and EasyMock, -but designed with C++'s specifics in mind. It is your friend if any of the -following problems is bothering you: - -* You are stuck with a sub-optimal design and wish you had done more - prototyping before it was too late, but prototyping in C++ is by no means - "rapid". -* Your tests are slow as they depend on too many libraries or use expensive - resources (e.g. a database). -* Your tests are brittle as some resources they use are unreliable (e.g. the - network). -* You want to test how your code handles a failure (e.g. a file checksum - error), but it's not easy to cause one. -* You need to make sure that your module interacts with other modules in the - right way, but it's hard to observe the interaction; therefore you resort to - observing the side effects at the end of the action, but it's awkward at - best. -* You want to "mock out" your dependencies, except that they don't have mock - implementations yet; and, frankly, you aren't thrilled by some of those - hand-written mocks. - -We encourage you to use gMock as - -* a *design* tool, for it lets you experiment with your interface design early - and often. More iterations lead to better designs! -* a *testing* tool to cut your tests' outbound dependencies and probe the - interaction between your module and its collaborators. - -## Getting Started - -gMock is bundled with googletest. - -## A Case for Mock Turtles - -Let's look at an example. Suppose you are developing a graphics program that -relies on a [LOGO](http://en.wikipedia.org/wiki/Logo_programming_language)-like -API for drawing. How would you test that it does the right thing? Well, you can -run it and compare the screen with a golden screen snapshot, but let's admit it: -tests like this are expensive to run and fragile (What if you just upgraded to a -shiny new graphics card that has better anti-aliasing? Suddenly you have to -update all your golden images.). It would be too painful if all your tests are -like this. Fortunately, you learned about -[Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) and know the right thing -to do: instead of having your application talk to the system API directly, wrap -the API in an interface (say, `Turtle`) and code to that interface: - -```cpp -class Turtle { - ... - virtual ~Turtle() {} - virtual void PenUp() = 0; - virtual void PenDown() = 0; - virtual void Forward(int distance) = 0; - virtual void Turn(int degrees) = 0; - virtual void GoTo(int x, int y) = 0; - virtual int GetX() const = 0; - virtual int GetY() const = 0; -}; -``` - -(Note that the destructor of `Turtle` **must** be virtual, as is the case for -**all** classes you intend to inherit from - otherwise the destructor of the -derived class will not be called when you delete an object through a base -pointer, and you'll get corrupted program states like memory leaks.) - -You can control whether the turtle's movement will leave a trace using `PenUp()` -and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and -`GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the -turtle. - -Your program will normally use a real implementation of this interface. In -tests, you can use a mock implementation instead. This allows you to easily -check what drawing primitives your program is calling, with what arguments, and -in which order. Tests written this way are much more robust (they won't break -because your new machine does anti-aliasing differently), easier to read and -maintain (the intent of a test is expressed in the code, not in some binary -images), and run *much, much faster*. - -## Writing the Mock Class - -If you are lucky, the mocks you need to use have already been implemented by -some nice people. If, however, you find yourself in the position to write a mock -class, relax - gMock turns this task into a fun game! (Well, almost.) - -### How to Define It - -Using the `Turtle` interface as example, here are the simple steps you need to -follow: - -* Derive a class `MockTurtle` from `Turtle`. -* Take a *virtual* function of `Turtle` (while it's possible to - [mock non-virtual methods using templates](gmock_cook_book.md#MockingNonVirtualMethods), - it's much more involved). -* In the `public:` section of the child class, write `MOCK_METHOD();` -* Now comes the fun part: you take the function signature, cut-and-paste it - into the macro, and add two commas - one between the return type and the - name, another between the name and the argument list. -* If you're mocking a const method, add a 4th parameter containing `(const)` - (the parentheses are required). -* Since you're overriding a virtual method, we suggest adding the `override` - keyword. For const methods the 4th parameter becomes `(const, override)`, - for non-const methods just `(override)`. This isn't mandatory. -* Repeat until all virtual functions you want to mock are done. (It goes - without saying that *all* pure virtual methods in your abstract class must - be either mocked or overridden.) - -After the process, you should have something like: - -```cpp -#include "gmock/gmock.h" // Brings in gMock. - -class MockTurtle : public Turtle { - public: - ... - MOCK_METHOD(void, PenUp, (), (override)); - MOCK_METHOD(void, PenDown, (), (override)); - MOCK_METHOD(void, Forward, (int distance), (override)); - MOCK_METHOD(void, Turn, (int degrees), (override)); - MOCK_METHOD(void, GoTo, (int x, int y), (override)); - MOCK_METHOD(int, GetX, (), (const, override)); - MOCK_METHOD(int, GetY, (), (const, override)); -}; -``` - -You don't need to define these mock methods somewhere else - the `MOCK_METHOD` -macro will generate the definitions for you. It's that simple! - -### Where to Put It - -When you define a mock class, you need to decide where to put its definition. -Some people put it in a `_test.cc`. This is fine when the interface being mocked -(say, `Foo`) is owned by the same person or team. Otherwise, when the owner of -`Foo` changes it, your test could break. (You can't really expect `Foo`'s -maintainer to fix every test that uses `Foo`, can you?) - -So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, -define the mock class in `Foo`'s package (better, in a `testing` sub-package -such that you can clearly separate production code and testing utilities), put -it in a `.h` and a `cc_library`. Then everyone can reference them from their -tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and -only tests that depend on the changed methods need to be fixed. - -Another way to do it: you can introduce a thin layer `FooAdaptor` on top of -`Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb -changes in `Foo` much more easily. While this is more work initially, carefully -choosing the adaptor interface can make your code easier to write and more -readable (a net win in the long run), as you can choose `FooAdaptor` to fit your -specific domain much better than `Foo` does. - -## Using Mocks in Tests - -Once you have a mock class, using it is easy. The typical work flow is: - -1. Import the gMock names from the `testing` namespace such that you can use - them unqualified (You only have to do it once per file). Remember that - namespaces are a good idea. -2. Create some mock objects. -3. Specify your expectations on them (How many times will a method be called? - With what arguments? What should it do? etc.). -4. Exercise some code that uses the mocks; optionally, check the result using - googletest assertions. If a mock method is called more than expected or with - wrong arguments, you'll get an error immediately. -5. When a mock is destructed, gMock will automatically check whether all - expectations on it have been satisfied. - -Here's an example: - -```cpp -#include "path/to/mock-turtle.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using ::testing::AtLeast; // #1 - -TEST(PainterTest, CanDrawSomething) { - MockTurtle turtle; // #2 - EXPECT_CALL(turtle, PenDown()) // #3 - .Times(AtLeast(1)); - - Painter painter(&turtle); // #4 - - EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); // #5 -} -``` - -As you might have guessed, this test checks that `PenDown()` is called at least -once. If the `painter` object didn't call this method, your test will fail with -a message like this: - -```text -path/to/my_test.cc:119: Failure -Actual function call count doesn't match this expectation: -Actually: never called; -Expected: called at least once. -Stack trace: -... -``` - -**Tip 1:** If you run the test from an Emacs buffer, you can hit `` on -the line number to jump right to the failed expectation. - -**Tip 2:** If your mock objects are never deleted, the final verification won't -happen. Therefore it's a good idea to turn on the heap checker in your tests -when you allocate mocks on the heap. You get that automatically if you use the -`gtest_main` library already. - -**Important note:** gMock requires expectations to be set **before** the mock -functions are called, otherwise the behavior is **undefined**. In particular, -you mustn't interleave `EXPECT_CALL()s` and calls to the mock functions. - -This means `EXPECT_CALL()` should be read as expecting that a call will occur -*in the future*, not that a call has occurred. Why does gMock work like that? -Well, specifying the expectation beforehand allows gMock to report a violation -as soon as it rises, when the context (stack trace, etc) is still available. -This makes debugging much easier. - -Admittedly, this test is contrived and doesn't do much. You can easily achieve -the same effect without using gMock. However, as we shall reveal soon, gMock -allows you to do *so much more* with the mocks. - -## Setting Expectations - -The key to using a mock object successfully is to set the *right expectations* -on it. If you set the expectations too strict, your test will fail as the result -of unrelated changes. If you set them too loose, bugs can slip through. You want -to do it just right such that your test can catch exactly the kind of bugs you -intend it to catch. gMock provides the necessary means for you to do it "just -right." - -### General Syntax - -In gMock we use the `EXPECT_CALL()` macro to set an expectation on a mock -method. The general syntax is: - -```cpp -EXPECT_CALL(mock_object, method(matchers)) - .Times(cardinality) - .WillOnce(action) - .WillRepeatedly(action); -``` - -The macro has two arguments: first the mock object, and then the method and its -arguments. Note that the two are separated by a comma (`,`), not a period (`.`). -(Why using a comma? The answer is that it was necessary for technical reasons.) -If the method is not overloaded, the macro can also be called without matchers: - -```cpp -EXPECT_CALL(mock_object, non-overloaded-method) - .Times(cardinality) - .WillOnce(action) - .WillRepeatedly(action); -``` - -This syntax allows the test writer to specify "called with any arguments" -without explicitly specifying the number or types of arguments. To avoid -unintended ambiguity, this syntax may only be used for methods that are not -overloaded. - -Either form of the macro can be followed by some optional *clauses* that provide -more information about the expectation. We'll discuss how each clause works in -the coming sections. - -This syntax is designed to make an expectation read like English. For example, -you can probably guess that - -```cpp -using ::testing::Return; -... -EXPECT_CALL(turtle, GetX()) - .Times(5) - .WillOnce(Return(100)) - .WillOnce(Return(150)) - .WillRepeatedly(Return(200)); -``` - -says that the `turtle` object's `GetX()` method will be called five times, it -will return 100 the first time, 150 the second time, and then 200 every time. -Some people like to call this style of syntax a Domain-Specific Language (DSL). - -{: .callout .note} -**Note:** Why do we use a macro to do this? Well it serves two purposes: first -it makes expectations easily identifiable (either by `grep` or by a human -reader), and second it allows gMock to include the source file location of a -failed expectation in messages, making debugging easier. - -### Matchers: What Arguments Do We Expect? - -When a mock function takes arguments, we may specify what arguments we are -expecting, for example: - -```cpp -// Expects the turtle to move forward by 100 units. -EXPECT_CALL(turtle, Forward(100)); -``` - -Oftentimes you do not want to be too specific. Remember that talk about tests -being too rigid? Over specification leads to brittle tests and obscures the -intent of tests. Therefore we encourage you to specify only what's necessary—no -more, no less. If you aren't interested in the value of an argument, write `_` -as the argument, which means "anything goes": - -```cpp -using ::testing::_; -... -// Expects that the turtle jumps to somewhere on the x=50 line. -EXPECT_CALL(turtle, GoTo(50, _)); -``` - -`_` is an instance of what we call **matchers**. A matcher is like a predicate -and can test whether an argument is what we'd expect. You can use a matcher -inside `EXPECT_CALL()` wherever a function argument is expected. `_` is a -convenient way of saying "any value". - -In the above examples, `100` and `50` are also matchers; implicitly, they are -the same as `Eq(100)` and `Eq(50)`, which specify that the argument must be -equal (using `operator==`) to the matcher argument. There are many -[built-in matchers](gmock_cheat_sheet.md#MatcherList) for common types (as well -as [custom matchers](gmock_cook_book.md#NewMatchers)); for example: - -```cpp -using ::testing::Ge; -... -// Expects the turtle moves forward by at least 100. -EXPECT_CALL(turtle, Forward(Ge(100))); -``` - -If you don't care about *any* arguments, rather than specify `_` for each of -them you may instead omit the parameter list: - -```cpp -// Expects the turtle to move forward. -EXPECT_CALL(turtle, Forward); -// Expects the turtle to jump somewhere. -EXPECT_CALL(turtle, GoTo); -``` - -This works for all non-overloaded methods; if a method is overloaded, you need -to help gMock resolve which overload is expected by specifying the number of -arguments and possibly also the -[types of the arguments](gmock_cook_book.md#SelectOverload). - -### Cardinalities: How Many Times Will It Be Called? - -The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We -call its argument a **cardinality** as it tells *how many times* the call should -occur. It allows us to repeat an expectation many times without actually writing -it as many times. More importantly, a cardinality can be "fuzzy", just like a -matcher can be. This allows a user to express the intent of a test exactly. - -An interesting special case is when we say `Times(0)`. You may have guessed - it -means that the function shouldn't be called with the given arguments at all, and -gMock will report a googletest failure whenever the function is (wrongfully) -called. - -We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the -list of built-in cardinalities you can use, see -[here](gmock_cheat_sheet.md#CardinalityList). - -The `Times()` clause can be omitted. **If you omit `Times()`, gMock will infer -the cardinality for you.** The rules are easy to remember: - -* If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the - `EXPECT_CALL()`, the inferred cardinality is `Times(1)`. -* If there are *n* `WillOnce()`'s but **no** `WillRepeatedly()`, where *n* >= - 1, the cardinality is `Times(n)`. -* If there are *n* `WillOnce()`'s and **one** `WillRepeatedly()`, where *n* >= - 0, the cardinality is `Times(AtLeast(n))`. - -**Quick quiz:** what do you think will happen if a function is expected to be -called twice but actually called four times? - -### Actions: What Should It Do? - -Remember that a mock object doesn't really have a working implementation? We as -users have to tell it what to do when a method is invoked. This is easy in -gMock. - -First, if the return type of a mock function is a built-in type or a pointer, -the function has a **default action** (a `void` function will just return, a -`bool` function will return `false`, and other functions will return 0). In -addition, in C++ 11 and above, a mock function whose return type is -default-constructible (i.e. has a default constructor) has a default action of -returning a default-constructed value. If you don't say anything, this behavior -will be used. - -Second, if a mock function doesn't have a default action, or the default action -doesn't suit you, you can specify the action to be taken each time the -expectation matches using a series of `WillOnce()` clauses followed by an -optional `WillRepeatedly()`. For example, - -```cpp -using ::testing::Return; -... -EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillOnce(Return(300)); -``` - -says that `turtle.GetX()` will be called *exactly three times* (gMock inferred -this from how many `WillOnce()` clauses we've written, since we didn't -explicitly write `Times()`), and will return 100, 200, and 300 respectively. - -```cpp -using ::testing::Return; -... -EXPECT_CALL(turtle, GetY()) - .WillOnce(Return(100)) - .WillOnce(Return(200)) - .WillRepeatedly(Return(300)); -``` - -says that `turtle.GetY()` will be called *at least twice* (gMock knows this as -we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no -explicit `Times()`), will return 100 and 200 respectively the first two times, -and 300 from the third time on. - -Of course, if you explicitly write a `Times()`, gMock will not try to infer the -cardinality itself. What if the number you specified is larger than there are -`WillOnce()` clauses? Well, after all `WillOnce()`s are used up, gMock will do -the *default* action for the function every time (unless, of course, you have a -`WillRepeatedly()`.). - -What can we do inside `WillOnce()` besides `Return()`? You can return a -reference using `ReturnRef(*variable*)`, or invoke a pre-defined function, among -[others](gmock_cook_book.md#using-actions). - -**Important note:** The `EXPECT_CALL()` statement evaluates the action clause -only once, even though the action may be performed many times. Therefore you -must be careful about side effects. The following may not do what you want: - -```cpp -using ::testing::Return; -... -int n = 100; -EXPECT_CALL(turtle, GetX()) - .Times(4) - .WillRepeatedly(Return(n++)); -``` - -Instead of returning 100, 101, 102, ..., consecutively, this mock function will -always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` -will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will -return the same pointer every time. If you want the side effect to happen every -time, you need to define a custom action, which we'll teach in the -[cook book](gmock_cook_book.md). - -Time for another quiz! What do you think the following means? - -```cpp -using ::testing::Return; -... -EXPECT_CALL(turtle, GetY()) - .Times(4) - .WillOnce(Return(100)); -``` - -Obviously `turtle.GetY()` is expected to be called four times. But if you think -it will return 100 every time, think twice! Remember that one `WillOnce()` -clause will be consumed each time the function is invoked and the default action -will be taken afterwards. So the right answer is that `turtle.GetY()` will -return 100 the first time, but **return 0 from the second time on**, as -returning 0 is the default action for `int` functions. - -### Using Multiple Expectations {#MultiExpectations} - -So far we've only shown examples where you have a single expectation. More -realistically, you'll specify expectations on multiple mock methods which may be -from multiple mock objects. - -By default, when a mock method is invoked, gMock will search the expectations in -the **reverse order** they are defined, and stop when an active expectation that -matches the arguments is found (you can think of it as "newer rules override -older ones."). If the matching expectation cannot take any more calls, you will -get an upper-bound-violated failure. Here's an example: - -```cpp -using ::testing::_; -... -EXPECT_CALL(turtle, Forward(_)); // #1 -EXPECT_CALL(turtle, Forward(10)) // #2 - .Times(2); -``` - -If `Forward(10)` is called three times in a row, the third time it will be an -error, as the last matching expectation (#2) has been saturated. If, however, -the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, -as now #1 will be the matching expectation. - -{: .callout .note} -**Note:** Why does gMock search for a match in the *reverse* order of the -expectations? The reason is that this allows a user to set up the default -expectations in a mock object's constructor or the test fixture's set-up phase -and then customize the mock by writing more specific expectations in the test -body. So, if you have two expectations on the same method, you want to put the -one with more specific matchers **after** the other, or the more specific rule -would be shadowed by the more general one that comes after it. - -{: .callout .tip} -**Tip:** It is very common to start with a catch-all expectation for a method -and `Times(AnyNumber())` (omitting arguments, or with `_` for all arguments, if -overloaded). This makes any calls to the method expected. This is not necessary -for methods that are not mentioned at all (these are "uninteresting"), but is -useful for methods that have some expectations, but for which other calls are -ok. See -[Understanding Uninteresting vs Unexpected Calls](gmock_cook_book.md#uninteresting-vs-unexpected). - -### Ordered vs Unordered Calls {#OrderedCalls} - -By default, an expectation can match a call even though an earlier expectation -hasn't been satisfied. In other words, the calls don't have to occur in the -order the expectations are specified. - -Sometimes, you may want all the expected calls to occur in a strict order. To -say this in gMock is easy: - -```cpp -using ::testing::InSequence; -... -TEST(FooTest, DrawsLineSegment) { - ... - { - InSequence seq; - - EXPECT_CALL(turtle, PenDown()); - EXPECT_CALL(turtle, Forward(100)); - EXPECT_CALL(turtle, PenUp()); - } - Foo(); -} -``` - -By creating an object of type `InSequence`, all expectations in its scope are -put into a *sequence* and have to occur *sequentially*. Since we are just -relying on the constructor and destructor of this object to do the actual work, -its name is really irrelevant. - -In this example, we test that `Foo()` calls the three expected functions in the -order as written. If a call is made out-of-order, it will be an error. - -(What if you care about the relative order of some of the calls, but not all of -them? Can you specify an arbitrary partial order? The answer is ... yes! The -details can be found [here](gmock_cook_book.md#OrderedCalls).) - -### All Expectations Are Sticky (Unless Said Otherwise) {#StickyExpectations} - -Now let's do a quick quiz to see how well you can use this mock stuff already. -How would you test that the turtle is asked to go to the origin *exactly twice* -(you want to ignore any other instructions it receives)? - -After you've come up with your answer, take a look at ours and compare notes -(solve it yourself first - don't cheat!): - -```cpp -using ::testing::_; -using ::testing::AnyNumber; -... -EXPECT_CALL(turtle, GoTo(_, _)) // #1 - .Times(AnyNumber()); -EXPECT_CALL(turtle, GoTo(0, 0)) // #2 - .Times(2); -``` - -Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, gMock will -see that the arguments match expectation #2 (remember that we always pick the -last matching expectation). Now, since we said that there should be only two -such calls, gMock will report an error immediately. This is basically what we've -told you in the [Using Multiple Expectations](#MultiExpectations) section above. - -This example shows that **expectations in gMock are "sticky" by default**, in -the sense that they remain active even after we have reached their invocation -upper bounds. This is an important rule to remember, as it affects the meaning -of the spec, and is **different** to how it's done in many other mocking -frameworks (Why'd we do that? Because we think our rule makes the common cases -easier to express and understand.). - -Simple? Let's see if you've really understood it: what does the following code -say? - -```cpp -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)); -} -``` - -If you think it says that `turtle.GetX()` will be called `n` times and will -return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we -said, expectations are sticky. So, the second time `turtle.GetX()` is called, -the last (latest) `EXPECT_CALL()` statement will match, and will immediately -lead to an "upper bound violated" error - this piece of code is not very useful! - -One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is -to explicitly say that the expectations are *not* sticky. In other words, they -should *retire* as soon as they are saturated: - -```cpp -using ::testing::Return; -... -for (int i = n; i > 0; i--) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); -} -``` - -And, there's a better way to do it: in this case, we expect the calls to occur -in a specific order, and we line up the actions to match the order. Since the -order is important here, we should make it explicit using a sequence: - -```cpp -using ::testing::InSequence; -using ::testing::Return; -... -{ - InSequence s; - - for (int i = 1; i <= n; i++) { - EXPECT_CALL(turtle, GetX()) - .WillOnce(Return(10*i)) - .RetiresOnSaturation(); - } -} -``` - -By the way, the other situation where an expectation may *not* be sticky is when -it's in a sequence - as soon as another expectation that comes after it in the -sequence has been used, it automatically retires (and will never be used to -match any call). - -### Uninteresting Calls - -A mock object may have many methods, and not all of them are that interesting. -For example, in some tests we may not care about how many times `GetX()` and -`GetY()` get called. - -In gMock, if you are not interested in a method, just don't say anything about -it. If a call to this method occurs, you'll see a warning in the test output, -but it won't be a failure. This is called "naggy" behavior; to change, see -[The Nice, the Strict, and the Naggy](gmock_cook_book.md#NiceStrictNaggy). diff --git a/vendor/googletest/gtest/docs/index.md b/vendor/googletest/gtest/docs/index.md deleted file mode 100644 index b162c740..00000000 --- a/vendor/googletest/gtest/docs/index.md +++ /dev/null @@ -1,22 +0,0 @@ -# GoogleTest User's Guide - -## Welcome to GoogleTest! - -GoogleTest is Google's C++ testing and mocking framework. This user's guide has -the following contents: - -* [GoogleTest Primer](primer.md) - Teaches you how to write simple tests using - GoogleTest. Read this first if you are new to GoogleTest. -* [GoogleTest Advanced](advanced.md) - Read this when you've finished the - Primer and want to utilize GoogleTest to its full potential. -* [GoogleTest Samples](samples.md) - Describes some GoogleTest samples. -* [GoogleTest FAQ](faq.md) - Have a question? Want some tips? Check here - first. -* [Mocking for Dummies](gmock_for_dummies.md) - Teaches you how to create mock - objects and use them in tests. -* [Mocking Cookbook](gmock_cook_book.md) - Includes tips and approaches to - common mocking use cases. -* [Mocking Cheat Sheet](gmock_cheat_sheet.md) - A handy reference for - matchers, actions, invariants, and more. -* [Mocking FAQ](gmock_faq.md) - Contains answers to some mocking-specific - questions. diff --git a/vendor/googletest/gtest/docs/pkgconfig.md b/vendor/googletest/gtest/docs/pkgconfig.md deleted file mode 100644 index 768e9b4c..00000000 --- a/vendor/googletest/gtest/docs/pkgconfig.md +++ /dev/null @@ -1,148 +0,0 @@ -## Using GoogleTest from various build systems - -GoogleTest comes with pkg-config files that can be used to determine all -necessary flags for compiling and linking to GoogleTest (and GoogleMock). -Pkg-config is a standardised plain-text format containing - -* the includedir (-I) path -* necessary macro (-D) definitions -* further required flags (-pthread) -* the library (-L) path -* the library (-l) to link to - -All current build systems support pkg-config in one way or another. For all -examples here we assume you want to compile the sample -`samples/sample3_unittest.cc`. - -### CMake - -Using `pkg-config` in CMake is fairly easy: - -```cmake -cmake_minimum_required(VERSION 3.0) - -cmake_policy(SET CMP0048 NEW) -project(my_gtest_pkgconfig VERSION 0.0.1 LANGUAGES CXX) - -find_package(PkgConfig) -pkg_search_module(GTEST REQUIRED gtest_main) - -add_executable(testapp samples/sample3_unittest.cc) -target_link_libraries(testapp ${GTEST_LDFLAGS}) -target_compile_options(testapp PUBLIC ${GTEST_CFLAGS}) - -include(CTest) -add_test(first_and_only_test testapp) -``` - -It is generally recommended that you use `target_compile_options` + `_CFLAGS` -over `target_include_directories` + `_INCLUDE_DIRS` as the former includes not -just -I flags (GoogleTest might require a macro indicating to internal headers -that all libraries have been compiled with threading enabled. In addition, -GoogleTest might also require `-pthread` in the compiling step, and as such -splitting the pkg-config `Cflags` variable into include dirs and macros for -`target_compile_definitions()` might still miss this). The same recommendation -goes for using `_LDFLAGS` over the more commonplace `_LIBRARIES`, which happens -to discard `-L` flags and `-pthread`. - -### Help! pkg-config can't find GoogleTest! - -Let's say you have a `CMakeLists.txt` along the lines of the one in this -tutorial and you try to run `cmake`. It is very possible that you get a failure -along the lines of: - -``` --- Checking for one of the modules 'gtest_main' -CMake Error at /usr/share/cmake/Modules/FindPkgConfig.cmake:640 (message): - None of the required 'gtest_main' found -``` - -These failures are common if you installed GoogleTest yourself and have not -sourced it from a distro or other package manager. If so, you need to tell -pkg-config where it can find the `.pc` files containing the information. Say you -installed GoogleTest to `/usr/local`, then it might be that the `.pc` files are -installed under `/usr/local/lib64/pkgconfig`. If you set - -``` -export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig -``` - -pkg-config will also try to look in `PKG_CONFIG_PATH` to find `gtest_main.pc`. - -### Using pkg-config in a cross-compilation setting - -Pkg-config can be used in a cross-compilation setting too. To do this, let's -assume the final prefix of the cross-compiled installation will be `/usr`, and -your sysroot is `/home/MYUSER/sysroot`. Configure and install GTest using - -``` -mkdir build && cmake -DCMAKE_INSTALL_PREFIX=/usr .. -``` - -Install into the sysroot using `DESTDIR`: - -``` -make -j install DESTDIR=/home/MYUSER/sysroot -``` - -Before we continue, it is recommended to **always** define the following two -variables for pkg-config in a cross-compilation setting: - -``` -export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=yes -export PKG_CONFIG_ALLOW_SYSTEM_LIBS=yes -``` - -otherwise `pkg-config` will filter `-I` and `-L` flags against standard prefixes -such as `/usr` (see https://bugs.freedesktop.org/show_bug.cgi?id=28264#c3 for -reasons why this stripping needs to occur usually). - -If you look at the generated pkg-config file, it will look something like - -``` -libdir=/usr/lib64 -includedir=/usr/include - -Name: gtest -Description: GoogleTest (without main() function) -Version: 1.10.0 -URL: https://github.com/google/googletest -Libs: -L${libdir} -lgtest -lpthread -Cflags: -I${includedir} -DGTEST_HAS_PTHREAD=1 -lpthread -``` - -Notice that the sysroot is not included in `libdir` and `includedir`! If you try -to run `pkg-config` with the correct -`PKG_CONFIG_LIBDIR=/home/MYUSER/sysroot/usr/lib64/pkgconfig` against this `.pc` -file, you will get - -``` -$ pkg-config --cflags gtest --DGTEST_HAS_PTHREAD=1 -lpthread -I/usr/include -$ pkg-config --libs gtest --L/usr/lib64 -lgtest -lpthread -``` - -which is obviously wrong and points to the `CBUILD` and not `CHOST` root. In -order to use this in a cross-compilation setting, we need to tell pkg-config to -inject the actual sysroot into `-I` and `-L` variables. Let us now tell -pkg-config about the actual sysroot - -``` -export PKG_CONFIG_DIR= -export PKG_CONFIG_SYSROOT_DIR=/home/MYUSER/sysroot -export PKG_CONFIG_LIBDIR=${PKG_CONFIG_SYSROOT_DIR}/usr/lib64/pkgconfig -``` - -and running `pkg-config` again we get - -``` -$ pkg-config --cflags gtest --DGTEST_HAS_PTHREAD=1 -lpthread -I/home/MYUSER/sysroot/usr/include -$ pkg-config --libs gtest --L/home/MYUSER/sysroot/usr/lib64 -lgtest -lpthread -``` - -which contains the correct sysroot now. For a more comprehensive guide to also -including `${CHOST}` in build system calls, see the excellent tutorial by Diego -Elio Pettenò: diff --git a/vendor/googletest/gtest/docs/platforms.md b/vendor/googletest/gtest/docs/platforms.md deleted file mode 100644 index eba6ef80..00000000 --- a/vendor/googletest/gtest/docs/platforms.md +++ /dev/null @@ -1,35 +0,0 @@ -# Supported Platforms - -GoogleTest requires a codebase and compiler compliant with the C++11 standard or -newer. - -The GoogleTest code is officially supported on the following platforms. -Operating systems or tools not listed below are community-supported. For -community-supported platforms, patches that do not complicate the code may be -considered. - -If you notice any problems on your platform, please file an issue on the -[GoogleTest GitHub Issue Tracker](https://github.com/google/googletest/issues). -Pull requests containing fixes are welcome! - -### Operating systems - -* Linux -* macOS -* Windows - -### Compilers - -* gcc 5.0+ -* clang 5.0+ -* MSVC 2015+ - -**macOS users:** Xcode 9.3+ provides clang 5.0+. - -### Build systems - -* [Bazel](https://bazel.build/) -* [CMake](https://cmake.org/) - -Bazel is the build system used by the team internally and in tests. CMake is -supported on a best-effort basis and by the community. diff --git a/vendor/googletest/gtest/docs/primer.md b/vendor/googletest/gtest/docs/primer.md deleted file mode 100644 index 44a1cb55..00000000 --- a/vendor/googletest/gtest/docs/primer.md +++ /dev/null @@ -1,578 +0,0 @@ -# Googletest Primer - -## Introduction: Why googletest? - -*googletest* helps you write better C++ tests. - -googletest is a testing framework developed by the Testing Technology team with -Google's specific requirements and constraints in mind. Whether you work on -Linux, Windows, or a Mac, if you write C++ code, googletest can help you. And it -supports *any* kind of tests, not just unit tests. - -So what makes a good test, and how does googletest fit in? We believe: - -1. Tests should be *independent* and *repeatable*. It's a pain to debug a test - that succeeds or fails as a result of other tests. googletest isolates the - tests by running each of them on a different object. When a test fails, - googletest allows you to run it in isolation for quick debugging. -2. Tests should be well *organized* and reflect the structure of the tested - code. googletest groups related tests into test suites that can share data - and subroutines. This common pattern is easy to recognize and makes tests - easy to maintain. Such consistency is especially helpful when people switch - projects and start to work on a new code base. -3. Tests should be *portable* and *reusable*. Google has a lot of code that is - platform-neutral; its tests should also be platform-neutral. googletest - works on different OSes, with different compilers, with or without - exceptions, so googletest tests can work with a variety of configurations. -4. When tests fail, they should provide as much *information* about the problem - as possible. googletest doesn't stop at the first test failure. Instead, it - only stops the current test and continues with the next. You can also set up - tests that report non-fatal failures after which the current test continues. - Thus, you can detect and fix multiple bugs in a single run-edit-compile - cycle. -5. The testing framework should liberate test writers from housekeeping chores - and let them focus on the test *content*. googletest automatically keeps - track of all tests defined, and doesn't require the user to enumerate them - in order to run them. -6. Tests should be *fast*. With googletest, you can reuse shared resources - across tests and pay for the set-up/tear-down only once, without making - tests depend on each other. - -Since googletest is based on the popular xUnit architecture, you'll feel right -at home if you've used JUnit or PyUnit before. If not, it will take you about 10 -minutes to learn the basics and get started. So let's go! - -## Beware of the nomenclature - -{: .callout .note} -_Note:_ There might be some confusion arising from different definitions of the -terms _Test_, _Test Case_ and _Test Suite_, so beware of misunderstanding these. - -Historically, googletest started to use the term _Test Case_ for grouping -related tests, whereas current publications, including International Software -Testing Qualifications Board ([ISTQB](http://www.istqb.org/)) materials and -various textbooks on software quality, use the term -_[Test Suite][istqb test suite]_ for this. - -The related term _Test_, as it is used in googletest, corresponds to the term -_[Test Case][istqb test case]_ of ISTQB and others. - -The term _Test_ is commonly of broad enough sense, including ISTQB's definition -of _Test Case_, so it's not much of a problem here. But the term _Test Case_ as -was used in Google Test is of contradictory sense and thus confusing. - -googletest recently started replacing the term _Test Case_ with _Test Suite_. -The preferred API is *TestSuite*. The older TestCase API is being slowly -deprecated and refactored away. - -So please be aware of the different definitions of the terms: - - -Meaning | googletest Term | [ISTQB](http://www.istqb.org/) Term -:----------------------------------------------------------------------------------- | :---------------------- | :---------------------------------- -Exercise a particular program path with specific input values and verify the results | [TEST()](#simple-tests) | [Test Case][istqb test case] - - -[istqb test case]: http://glossary.istqb.org/en/search/test%20case -[istqb test suite]: http://glossary.istqb.org/en/search/test%20suite - -## Basic Concepts - -When using googletest, you start by writing *assertions*, which are statements -that check whether a condition is true. An assertion's result can be *success*, -*nonfatal failure*, or *fatal failure*. If a fatal failure occurs, it aborts the -current function; otherwise the program continues normally. - -*Tests* use assertions to verify the tested code's behavior. If a test crashes -or has a failed assertion, then it *fails*; otherwise it *succeeds*. - -A *test suite* contains one or many tests. You should group your tests into test -suites that reflect the structure of the tested code. When multiple tests in a -test suite need to share common objects and subroutines, you can put them into a -*test fixture* class. - -A *test program* can contain multiple test suites. - -We'll now explain how to write a test program, starting at the individual -assertion level and building up to tests and test suites. - -## Assertions - -googletest assertions are macros that resemble function calls. You test a class -or function by making assertions about its behavior. When an assertion fails, -googletest prints the assertion's source file and line number location, along -with a failure message. You may also supply a custom failure message which will -be appended to googletest's message. - -The assertions come in pairs that test the same thing but have different effects -on the current function. `ASSERT_*` versions generate fatal failures when they -fail, and **abort the current function**. `EXPECT_*` versions generate nonfatal -failures, which don't abort the current function. Usually `EXPECT_*` are -preferred, as they allow more than one failure to be reported in a test. -However, you should use `ASSERT_*` if it doesn't make sense to continue when the -assertion in question fails. - -Since a failed `ASSERT_*` returns from the current function immediately, -possibly skipping clean-up code that comes after it, it may cause a space leak. -Depending on the nature of the leak, it may or may not be worth fixing - so keep -this in mind if you get a heap checker error in addition to assertion errors. - -To provide a custom failure message, simply stream it into the macro using the -`<<` operator or a sequence of such operators. An example: - -```c++ -ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; - -for (int i = 0; i < x.size(); ++i) { - EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; -} -``` - -Anything that can be streamed to an `ostream` can be streamed to an assertion -macro--in particular, C strings and `string` objects. If a wide string -(`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is -streamed to an assertion, it will be translated to UTF-8 when printed. - -### Basic Assertions - -These assertions do basic true/false condition testing. - -Fatal assertion | Nonfatal assertion | Verifies --------------------------- | -------------------------- | -------------------- -`ASSERT_TRUE(condition);` | `EXPECT_TRUE(condition);` | `condition` is true -`ASSERT_FALSE(condition);` | `EXPECT_FALSE(condition);` | `condition` is false - -Remember, when they fail, `ASSERT_*` yields a fatal failure and returns from the -current function, while `EXPECT_*` yields a nonfatal failure, allowing the -function to continue running. In either case, an assertion failure means its -containing test fails. - -**Availability**: Linux, Windows, Mac. - -### Binary Comparison - -This section describes assertions that compare two values. - -Fatal assertion | Nonfatal assertion | Verifies ------------------------- | ------------------------ | -------------- -`ASSERT_EQ(val1, val2);` | `EXPECT_EQ(val1, val2);` | `val1 == val2` -`ASSERT_NE(val1, val2);` | `EXPECT_NE(val1, val2);` | `val1 != val2` -`ASSERT_LT(val1, val2);` | `EXPECT_LT(val1, val2);` | `val1 < val2` -`ASSERT_LE(val1, val2);` | `EXPECT_LE(val1, val2);` | `val1 <= val2` -`ASSERT_GT(val1, val2);` | `EXPECT_GT(val1, val2);` | `val1 > val2` -`ASSERT_GE(val1, val2);` | `EXPECT_GE(val1, val2);` | `val1 >= val2` - -Value arguments must be comparable by the assertion's comparison operator or -you'll get a compiler error. We used to require the arguments to support the -`<<` operator for streaming to an `ostream`, but this is no longer necessary. If -`<<` is supported, it will be called to print the arguments when the assertion -fails; otherwise googletest will attempt to print them in the best way it can. -For more details and how to customize the printing of the arguments, see the -[documentation](./advanced.md#teaching-googletest-how-to-print-your-values). - -These assertions can work with a user-defined type, but only if you define the -corresponding comparison operator (e.g., `==` or `<`). Since this is discouraged -by the Google -[C++ Style Guide](https://google.github.io/styleguide/cppguide.html#Operator_Overloading), -you may need to use `ASSERT_TRUE()` or `EXPECT_TRUE()` to assert the equality of -two objects of a user-defined type. - -However, when possible, `ASSERT_EQ(actual, expected)` is preferred to -`ASSERT_TRUE(actual == expected)`, since it tells you `actual` and `expected`'s -values on failure. - -Arguments are always evaluated exactly once. Therefore, it's OK for the -arguments to have side effects. However, as with any ordinary C/C++ function, -the arguments' evaluation order is undefined (i.e., the compiler is free to -choose any order), and your code should not depend on any particular argument -evaluation order. - -`ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it -tests if they are in the same memory location, not if they have the same value. -Therefore, if you want to compare C strings (e.g. `const char*`) by value, use -`ASSERT_STREQ()`, which will be described later on. In particular, to assert -that a C string is `NULL`, use `ASSERT_STREQ(c_string, NULL)`. Consider using -`ASSERT_EQ(c_string, nullptr)` if c++11 is supported. To compare two `string` -objects, you should use `ASSERT_EQ`. - -When doing pointer comparisons use `*_EQ(ptr, nullptr)` and `*_NE(ptr, nullptr)` -instead of `*_EQ(ptr, NULL)` and `*_NE(ptr, NULL)`. This is because `nullptr` is -typed, while `NULL` is not. See the [FAQ](faq.md) for more details. - -If you're working with floating point numbers, you may want to use the floating -point variations of some of these macros in order to avoid problems caused by -rounding. See [Advanced googletest Topics](advanced.md) for details. - -Macros in this section work with both narrow and wide string objects (`string` -and `wstring`). - -**Availability**: Linux, Windows, Mac. - -**Historical note**: Before February 2016 `*_EQ` had a convention of calling it -as `ASSERT_EQ(expected, actual)`, so lots of existing code uses this order. Now -`*_EQ` treats both parameters in the same way. - -### String Comparison - -The assertions in this group compare two **C strings**. If you want to compare -two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead. - - -| Fatal assertion | Nonfatal assertion | Verifies | -| -------------------------- | ------------------------------ | -------------------------------------------------------- | -| `ASSERT_STREQ(str1,str2);` | `EXPECT_STREQ(str1,str2);` | the two C strings have the same content | -| `ASSERT_STRNE(str1,str2);` | `EXPECT_STRNE(str1,str2);` | the two C strings have different contents | -| `ASSERT_STRCASEEQ(str1,str2);` | `EXPECT_STRCASEEQ(str1,str2);` | the two C strings have the same content, ignoring case | -| `ASSERT_STRCASENE(str1,str2);` | `EXPECT_STRCASENE(str1,str2);` | the two C strings have different contents, ignoring case | - - -Note that "CASE" in an assertion name means that case is ignored. A `NULL` -pointer and an empty string are considered *different*. - -`*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a comparison -of two wide strings fails, their values will be printed as UTF-8 narrow strings. - -**Availability**: Linux, Windows, Mac. - -**See also**: For more string comparison tricks (substring, prefix, suffix, and -regular expression matching, for example), see [this](advanced.md) in the -Advanced googletest Guide. - -## Simple Tests - -To create a test: - -1. Use the `TEST()` macro to define and name a test function. These are - ordinary C++ functions that don't return a value. -2. In this function, along with any valid C++ statements you want to include, - use the various googletest assertions to check values. -3. The test's result is determined by the assertions; if any assertion in the - test fails (either fatally or non-fatally), or if the test crashes, the - entire test fails. Otherwise, it succeeds. - -```c++ -TEST(TestSuiteName, TestName) { - ... test body ... -} -``` - -`TEST()` arguments go from general to specific. The *first* argument is the name -of the test suite, and the *second* argument is the test's name within the test -suite. Both names must be valid C++ identifiers, and they should not contain -any underscores (`_`). A test's *full name* consists of its containing test suite and -its individual name. Tests from different test suites can have the same -individual name. - -For example, let's take a simple integer function: - -```c++ -int Factorial(int n); // Returns the factorial of n -``` - -A test suite for this function might look like: - -```c++ -// Tests factorial of 0. -TEST(FactorialTest, HandlesZeroInput) { - EXPECT_EQ(Factorial(0), 1); -} - -// Tests factorial of positive numbers. -TEST(FactorialTest, HandlesPositiveInput) { - EXPECT_EQ(Factorial(1), 1); - EXPECT_EQ(Factorial(2), 2); - EXPECT_EQ(Factorial(3), 6); - EXPECT_EQ(Factorial(8), 40320); -} -``` - -googletest groups the test results by test suites, so logically related tests -should be in the same test suite; in other words, the first argument to their -`TEST()` should be the same. In the above example, we have two tests, -`HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test -suite `FactorialTest`. - -When naming your test suites and tests, you should follow the same convention as -for -[naming functions and classes](https://google.github.io/styleguide/cppguide.html#Function_Names). - -**Availability**: Linux, Windows, Mac. - -## Test Fixtures: Using the Same Data Configuration for Multiple Tests {#same-data-multiple-tests} - -If you find yourself writing two or more tests that operate on similar data, you -can use a *test fixture*. This allows you to reuse the same configuration of -objects for several different tests. - -To create a fixture: - -1. Derive a class from `::testing::Test` . Start its body with `protected:`, as - we'll want to access fixture members from sub-classes. -2. Inside the class, declare any objects you plan to use. -3. If necessary, write a default constructor or `SetUp()` function to prepare - the objects for each test. A common mistake is to spell `SetUp()` as - **`Setup()`** with a small `u` - Use `override` in C++11 to make sure you - spelled it correctly. -4. If necessary, write a destructor or `TearDown()` function to release any - resources you allocated in `SetUp()` . To learn when you should use the - constructor/destructor and when you should use `SetUp()/TearDown()`, read - the [FAQ](faq.md#CtorVsSetUp). -5. If needed, define subroutines for your tests to share. - -When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to -access objects and subroutines in the test fixture: - -```c++ -TEST_F(TestFixtureName, TestName) { - ... test body ... -} -``` - -Like `TEST()`, the first argument is the test suite name, but for `TEST_F()` -this must be the name of the test fixture class. You've probably guessed: `_F` -is for fixture. - -Unfortunately, the C++ macro system does not allow us to create a single macro -that can handle both types of tests. Using the wrong macro causes a compiler -error. - -Also, you must first define a test fixture class before using it in a -`TEST_F()`, or you'll get the compiler error "`virtual outside class -declaration`". - -For each test defined with `TEST_F()`, googletest will create a *fresh* test -fixture at runtime, immediately initialize it via `SetUp()`, run the test, -clean up by calling `TearDown()`, and then delete the test fixture. Note that -different tests in the same test suite have different test fixture objects, and -googletest always deletes a test fixture before it creates the next one. -googletest does **not** reuse the same test fixture for multiple tests. Any -changes one test makes to the fixture do not affect other tests. - -As an example, let's write tests for a FIFO queue class named `Queue`, which has -the following interface: - -```c++ -template // E is the element type. -class Queue { - public: - Queue(); - void Enqueue(const E& element); - E* Dequeue(); // Returns NULL if the queue is empty. - size_t size() const; - ... -}; -``` - -First, define a fixture class. By convention, you should give it the name -`FooTest` where `Foo` is the class being tested. - -```c++ -class QueueTest : public ::testing::Test { - protected: - void SetUp() override { - q1_.Enqueue(1); - q2_.Enqueue(2); - q2_.Enqueue(3); - } - - // void TearDown() override {} - - Queue q0_; - Queue q1_; - Queue q2_; -}; -``` - -In this case, `TearDown()` is not needed since we don't have to clean up after -each test, other than what's already done by the destructor. - -Now we'll write tests using `TEST_F()` and this fixture. - -```c++ -TEST_F(QueueTest, IsEmptyInitially) { - EXPECT_EQ(q0_.size(), 0); -} - -TEST_F(QueueTest, DequeueWorks) { - int* n = q0_.Dequeue(); - EXPECT_EQ(n, nullptr); - - n = q1_.Dequeue(); - ASSERT_NE(n, nullptr); - EXPECT_EQ(*n, 1); - EXPECT_EQ(q1_.size(), 0); - delete n; - - n = q2_.Dequeue(); - ASSERT_NE(n, nullptr); - EXPECT_EQ(*n, 2); - EXPECT_EQ(q2_.size(), 1); - delete n; -} -``` - -The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is -to use `EXPECT_*` when you want the test to continue to reveal more errors after -the assertion failure, and use `ASSERT_*` when continuing after failure doesn't -make sense. For example, the second assertion in the `Dequeue` test is -`ASSERT_NE(nullptr, n)`, as we need to dereference the pointer `n` later, which -would lead to a segfault when `n` is `NULL`. - -When these tests run, the following happens: - -1. googletest constructs a `QueueTest` object (let's call it `t1`). -2. `t1.SetUp()` initializes `t1`. -3. The first test (`IsEmptyInitially`) runs on `t1`. -4. `t1.TearDown()` cleans up after the test finishes. -5. `t1` is destructed. -6. The above steps are repeated on another `QueueTest` object, this time - running the `DequeueWorks` test. - -**Availability**: Linux, Windows, Mac. - -## Invoking the Tests - -`TEST()` and `TEST_F()` implicitly register their tests with googletest. So, -unlike with many other C++ testing frameworks, you don't have to re-list all -your defined tests in order to run them. - -After defining your tests, you can run them with `RUN_ALL_TESTS()`, which -returns `0` if all the tests are successful, or `1` otherwise. Note that -`RUN_ALL_TESTS()` runs *all tests* in your link unit--they can be from -different test suites, or even different source files. - -When invoked, the `RUN_ALL_TESTS()` macro: - -* Saves the state of all googletest flags. - -* Creates a test fixture object for the first test. - -* Initializes it via `SetUp()`. - -* Runs the test on the fixture object. - -* Cleans up the fixture via `TearDown()`. - -* Deletes the fixture. - -* Restores the state of all googletest flags. - -* Repeats the above steps for the next test, until all tests have run. - -If a fatal failure happens the subsequent steps will be skipped. - -{: .callout .important} -> IMPORTANT: You must **not** ignore the return value of `RUN_ALL_TESTS()`, or -> you will get a compiler error. The rationale for this design is that the -> automated testing service determines whether a test has passed based on its -> exit code, not on its stdout/stderr output; thus your `main()` function must -> return the value of `RUN_ALL_TESTS()`. -> -> Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than -> once conflicts with some advanced googletest features (e.g., thread-safe -> [death tests](advanced.md#death-tests)) and thus is not supported. - -**Availability**: Linux, Windows, Mac. - -## Writing the main() Function - -Most users should _not_ need to write their own `main` function and instead link -with `gtest_main` (as opposed to with `gtest`), which defines a suitable entry -point. See the end of this section for details. The remainder of this section -should only apply when you need to do something custom before the tests run that -cannot be expressed within the framework of fixtures and test suites. - -If you write your own `main` function, it should return the value of -`RUN_ALL_TESTS()`. - -You can start from this boilerplate: - -```c++ -#include "this/package/foo.h" - -#include "gtest/gtest.h" - -namespace my { -namespace project { -namespace { - -// The fixture for testing class Foo. -class FooTest : public ::testing::Test { - protected: - // You can remove any or all of the following functions if their bodies would - // be empty. - - FooTest() { - // You can do set-up work for each test here. - } - - ~FooTest() override { - // You can do clean-up work that doesn't throw exceptions here. - } - - // If the constructor and destructor are not enough for setting up - // and cleaning up each test, you can define the following methods: - - void SetUp() override { - // Code here will be called immediately after the constructor (right - // before each test). - } - - void TearDown() override { - // Code here will be called immediately after each test (right - // before the destructor). - } - - // Class members declared here can be used by all tests in the test suite - // for Foo. -}; - -// Tests that the Foo::Bar() method does Abc. -TEST_F(FooTest, MethodBarDoesAbc) { - const std::string input_filepath = "this/package/testdata/myinputfile.dat"; - const std::string output_filepath = "this/package/testdata/myoutputfile.dat"; - Foo f; - EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0); -} - -// Tests that Foo does Xyz. -TEST_F(FooTest, DoesXyz) { - // Exercises the Xyz feature of Foo. -} - -} // namespace -} // namespace project -} // namespace my - -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} -``` - -The `::testing::InitGoogleTest()` function parses the command line for -googletest flags, and removes all recognized flags. This allows the user to -control a test program's behavior via various flags, which we'll cover in -the [AdvancedGuide](advanced.md). You **must** call this function before calling -`RUN_ALL_TESTS()`, or the flags won't be properly initialized. - -On Windows, `InitGoogleTest()` also works with wide strings, so it can be used -in programs compiled in `UNICODE` mode as well. - -But maybe you think that writing all those `main` functions is too much work? We -agree with you completely, and that's why Google Test provides a basic -implementation of main(). If it fits your needs, then just link your test with -the `gtest_main` library and you are good to go. - -{: .callout .note} -NOTE: `ParseGUnitFlags()` is deprecated in favor of `InitGoogleTest()`. - -## Known Limitations - -* Google Test is designed to be thread-safe. The implementation is thread-safe - on systems where the `pthreads` library is available. It is currently - _unsafe_ to use Google Test assertions from two threads concurrently on - other systems (e.g. Windows). In most tests this is not an issue as usually - the assertions are done in the main thread. If you want to help, you can - volunteer to implement the necessary synchronization primitives in - `gtest-port.h` for your platform. diff --git a/vendor/googletest/gtest/docs/quickstart-bazel.md b/vendor/googletest/gtest/docs/quickstart-bazel.md deleted file mode 100644 index 362ee6d0..00000000 --- a/vendor/googletest/gtest/docs/quickstart-bazel.md +++ /dev/null @@ -1,161 +0,0 @@ -# Quickstart: Building with Bazel - -This tutorial aims to get you up and running with GoogleTest using the Bazel -build system. If you're using GoogleTest for the first time or need a refresher, -we recommend this tutorial as a starting point. - -## Prerequisites - -To complete this tutorial, you'll need: - -* A compatible operating system (e.g. Linux, macOS, Windows). -* A compatible C++ compiler that supports at least C++11. -* [Bazel](https://bazel.build/), the preferred build system used by the - GoogleTest team. - -See [Supported Platforms](platforms.md) for more information about platforms -compatible with GoogleTest. - -If you don't already have Bazel installed, see the -[Bazel installation guide](https://docs.bazel.build/versions/master/install.html). - -{: .callout .note} -Note: The terminal commands in this tutorial show a Unix shell prompt, but the -commands work on the Windows command line as well. - -## Set up a Bazel workspace - -A -[Bazel workspace](https://docs.bazel.build/versions/master/build-ref.html#workspace) -is a directory on your filesystem that you use to manage source files for the -software you want to build. Each workspace directory has a text file named -`WORKSPACE` which may be empty, or may contain references to external -dependencies required to build the outputs. - -First, create a directory for your workspace: - -``` -$ mkdir my_workspace && cd my_workspace -``` - -Next, you’ll create the `WORKSPACE` file to specify dependencies. A common and -recommended way to depend on GoogleTest is to use a -[Bazel external dependency](https://docs.bazel.build/versions/master/external.html) -via the -[`http_archive` rule](https://docs.bazel.build/versions/master/repo/http.html#http_archive). -To do this, in the root directory of your workspace (`my_workspace/`), create a -file named `WORKSPACE` with the following contents: - -``` -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -http_archive( - name = "com_google_googletest", - urls = ["https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip"], - strip_prefix = "googletest-609281088cfefc76f9d0ce82e1ff6c30cc3591e5", -) -``` - -The above configuration declares a dependency on GoogleTest which is downloaded -as a ZIP archive from GitHub. In the above example, -`609281088cfefc76f9d0ce82e1ff6c30cc3591e5` is the Git commit hash of the -GoogleTest version to use; we recommend updating the hash often to point to the -latest version. - -Bazel also needs a dependency on the -[`rules_cc` repository](https://github.com/bazelbuild/rules_cc) to build C++ -code, so add the following to the `WORKSPACE` file: - -``` -http_archive( - name = "rules_cc", - urls = ["https://github.com/bazelbuild/rules_cc/archive/40548a2974f1aea06215272d9c2b47a14a24e556.zip"], - strip_prefix = "rules_cc-40548a2974f1aea06215272d9c2b47a14a24e556", -) -``` - -Now you're ready to build C++ code that uses GoogleTest. - -## Create and run a binary - -With your Bazel workspace set up, you can now use GoogleTest code within your -own project. - -As an example, create a file named `hello_test.cc` in your `my_workspace` -directory with the following contents: - -```cpp -#include - -// Demonstrate some basic assertions. -TEST(HelloTest, BasicAssertions) { - // Expect two strings not to be equal. - EXPECT_STRNE("hello", "world"); - // Expect equality. - EXPECT_EQ(7 * 6, 42); -} -``` - -GoogleTest provides [assertions](primer.md#assertions) that you use to test the -behavior of your code. The above sample includes the main GoogleTest header file -and demonstrates some basic assertions. - -To build the code, create a file named `BUILD` in the same directory with the -following contents: - -``` -load("@rules_cc//cc:defs.bzl", "cc_test") - -cc_test( - name = "hello_test", - size = "small", - srcs = ["hello_test.cc"], - deps = ["@com_google_googletest//:gtest_main"], -) -``` - -This `cc_test` rule declares the C++ test binary you want to build, and links to -GoogleTest (`//:gtest_main`) using the prefix you specified in the `WORKSPACE` -file (`@com_google_googletest`). For more information about Bazel `BUILD` files, -see the -[Bazel C++ Tutorial](https://docs.bazel.build/versions/master/tutorial/cpp.html). - -Now you can build and run your test: - -
-my_workspace$ bazel test --test_output=all //:hello_test
-INFO: Analyzed target //:hello_test (26 packages loaded, 362 targets configured).
-INFO: Found 1 test target...
-INFO: From Testing //:hello_test:
-==================== Test output for //:hello_test:
-Running main() from gmock_main.cc
-[==========] Running 1 test from 1 test suite.
-[----------] Global test environment set-up.
-[----------] 1 test from HelloTest
-[ RUN      ] HelloTest.BasicAssertions
-[       OK ] HelloTest.BasicAssertions (0 ms)
-[----------] 1 test from HelloTest (0 ms total)
-
-[----------] Global test environment tear-down
-[==========] 1 test from 1 test suite ran. (0 ms total)
-[  PASSED  ] 1 test.
-================================================================================
-Target //:hello_test up-to-date:
-  bazel-bin/hello_test
-INFO: Elapsed time: 4.190s, Critical Path: 3.05s
-INFO: 27 processes: 8 internal, 19 linux-sandbox.
-INFO: Build completed successfully, 27 total actions
-//:hello_test                                                     PASSED in 0.1s
-
-INFO: Build completed successfully, 27 total actions
-
- -Congratulations! You've successfully built and run a test binary using -GoogleTest. - -## Next steps - -* [Check out the Primer](primer.md) to start learning how to write simple - tests. -* [See the code samples](samples.md) for more examples showing how to use a - variety of GoogleTest features. diff --git a/vendor/googletest/gtest/docs/quickstart-cmake.md b/vendor/googletest/gtest/docs/quickstart-cmake.md deleted file mode 100644 index 420f1d3a..00000000 --- a/vendor/googletest/gtest/docs/quickstart-cmake.md +++ /dev/null @@ -1,156 +0,0 @@ -# Quickstart: Building with CMake - -This tutorial aims to get you up and running with GoogleTest using CMake. If -you're using GoogleTest for the first time or need a refresher, we recommend -this tutorial as a starting point. If your project uses Bazel, see the -[Quickstart for Bazel](quickstart-bazel.md) instead. - -## Prerequisites - -To complete this tutorial, you'll need: - -* A compatible operating system (e.g. Linux, macOS, Windows). -* A compatible C++ compiler that supports at least C++11. -* [CMake](https://cmake.org/) and a compatible build tool for building the - project. - * Compatible build tools include - [Make](https://www.gnu.org/software/make/), - [Ninja](https://ninja-build.org/), and others - see - [CMake Generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) - for more information. - -See [Supported Platforms](platforms.md) for more information about platforms -compatible with GoogleTest. - -If you don't already have CMake installed, see the -[CMake installation guide](https://cmake.org/install). - -{: .callout .note} -Note: The terminal commands in this tutorial show a Unix shell prompt, but the -commands work on the Windows command line as well. - -## Set up a project - -CMake uses a file named `CMakeLists.txt` to configure the build system for a -project. You'll use this file to set up your project and declare a dependency on -GoogleTest. - -First, create a directory for your project: - -``` -$ mkdir my_project && cd my_project -``` - -Next, you'll create the `CMakeLists.txt` file and declare a dependency on -GoogleTest. There are many ways to express dependencies in the CMake ecosystem; -in this quickstart, you'll use the -[`FetchContent` CMake module](https://cmake.org/cmake/help/latest/module/FetchContent.html). -To do this, in your project directory (`my_project`), create a file named -`CMakeLists.txt` with the following contents: - -```cmake -cmake_minimum_required(VERSION 3.14) -project(my_project) - -# GoogleTest requires at least C++11 -set(CMAKE_CXX_STANDARD 11) - -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip -) -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) -``` - -The above configuration declares a dependency on GoogleTest which is downloaded -from GitHub. In the above example, `609281088cfefc76f9d0ce82e1ff6c30cc3591e5` is -the Git commit hash of the GoogleTest version to use; we recommend updating the -hash often to point to the latest version. - -For more information about how to create `CMakeLists.txt` files, see the -[CMake Tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/index.html). - -## Create and run a binary - -With GoogleTest declared as a dependency, you can use GoogleTest code within -your own project. - -As an example, create a file named `hello_test.cc` in your `my_project` -directory with the following contents: - -```cpp -#include - -// Demonstrate some basic assertions. -TEST(HelloTest, BasicAssertions) { - // Expect two strings not to be equal. - EXPECT_STRNE("hello", "world"); - // Expect equality. - EXPECT_EQ(7 * 6, 42); -} -``` - -GoogleTest provides [assertions](primer.md#assertions) that you use to test the -behavior of your code. The above sample includes the main GoogleTest header file -and demonstrates some basic assertions. - -To build the code, add the following to the end of your `CMakeLists.txt` file: - -```cmake -enable_testing() - -add_executable( - hello_test - hello_test.cc -) -target_link_libraries( - hello_test - gtest_main -) - -include(GoogleTest) -gtest_discover_tests(hello_test) -``` - -The above configuration enables testing in CMake, declares the C++ test binary -you want to build (`hello_test`), and links it to GoogleTest (`gtest_main`). The -last two lines enable CMake's test runner to discover the tests included in the -binary, using the -[`GoogleTest` CMake module](https://cmake.org/cmake/help/git-stage/module/GoogleTest.html). - -Now you can build and run your test: - -
-my_project$ cmake -S . -B build
--- The C compiler identification is GNU 10.2.1
--- The CXX compiler identification is GNU 10.2.1
-...
--- Build files have been written to: .../my_project/build
-
-my_project$ cmake --build build
-Scanning dependencies of target gtest
-...
-[100%] Built target gmock_main
-
-my_project$ cd build && ctest
-Test project .../my_project/build
-    Start 1: HelloTest.BasicAssertions
-1/1 Test #1: HelloTest.BasicAssertions ........   Passed    0.00 sec
-
-100% tests passed, 0 tests failed out of 1
-
-Total Test time (real) =   0.01 sec
-
- -Congratulations! You've successfully built and run a test binary using -GoogleTest. - -## Next steps - -* [Check out the Primer](primer.md) to start learning how to write simple - tests. -* [See the code samples](samples.md) for more examples showing how to use a - variety of GoogleTest features. diff --git a/vendor/googletest/gtest/docs/samples.md b/vendor/googletest/gtest/docs/samples.md deleted file mode 100644 index 2d97ca55..00000000 --- a/vendor/googletest/gtest/docs/samples.md +++ /dev/null @@ -1,22 +0,0 @@ -# Googletest Samples - -If you're like us, you'd like to look at -[googletest samples.](https://github.com/google/googletest/tree/master/googletest/samples) -The sample directory has a number of well-commented samples showing how to use a -variety of googletest features. - -* Sample #1 shows the basic steps of using googletest to test C++ functions. -* Sample #2 shows a more complex unit test for a class with multiple member - functions. -* Sample #3 uses a test fixture. -* Sample #4 teaches you how to use googletest and `googletest.h` together to - get the best of both libraries. -* Sample #5 puts shared testing logic in a base test fixture, and reuses it in - derived fixtures. -* Sample #6 demonstrates type-parameterized tests. -* Sample #7 teaches the basics of value-parameterized tests. -* Sample #8 shows using `Combine()` in value-parameterized tests. -* Sample #9 shows use of the listener API to modify Google Test's console - output and the use of its reflection API to inspect test results. -* Sample #10 shows use of the listener API to implement a primitive memory - leak checker. diff --git a/vendor/googletest/gtest/googlemock/CMakeLists.txt b/vendor/googletest/gtest/googlemock/CMakeLists.txt deleted file mode 100644 index e7df8ec5..00000000 --- a/vendor/googletest/gtest/googlemock/CMakeLists.txt +++ /dev/null @@ -1,218 +0,0 @@ -######################################################################## -# Note: CMake support is community-based. The maintainers do not use CMake -# internally. -# -# CMake build script for Google Mock. -# -# To run the tests for Google Mock itself on Linux, use 'make test' or -# ctest. You can select which tests to run using 'ctest -R regex'. -# For more options, run 'ctest --help'. - -option(gmock_build_tests "Build all of Google Mock's own tests." OFF) - -# A directory to find Google Test sources. -if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt") - set(gtest_dir gtest) -else() - set(gtest_dir ../googletest) -endif() - -# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). -include("${gtest_dir}/cmake/hermetic_build.cmake" OPTIONAL) - -if (COMMAND pre_project_set_up_hermetic_build) - # Google Test also calls hermetic setup functions from add_subdirectory, - # although its changes will not affect things at the current scope. - pre_project_set_up_hermetic_build() -endif() - -######################################################################## -# -# Project-wide settings - -# Name of the project. -# -# CMake files in this project can refer to the root source directory -# as ${gmock_SOURCE_DIR} and to the root binary directory as -# ${gmock_BINARY_DIR}. -# Language "C" is required for find_package(Threads). -if (CMAKE_VERSION VERSION_LESS 3.0) - project(gmock CXX C) -else() - cmake_policy(SET CMP0048 NEW) - project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C) -endif() -cmake_minimum_required(VERSION 2.8.12) - -if (COMMAND set_up_hermetic_build) - set_up_hermetic_build() -endif() - -# Instructs CMake to process Google Test's CMakeLists.txt and add its -# targets to the current scope. We are placing Google Test's binary -# directory in a subdirectory of our own as VC compilation may break -# if they are the same (the default). -add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/${gtest_dir}") - - -# These commands only run if this is the main project -if(CMAKE_PROJECT_NAME STREQUAL "gmock" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution") - # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to - # make it prominent in the GUI. - option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) -else() - mark_as_advanced(gmock_build_tests) -endif() - -# Although Google Test's CMakeLists.txt calls this function, the -# changes there don't affect the current scope. Therefore we have to -# call it again here. -config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake - -# Adds Google Mock's and Google Test's header directories to the search path. -set(gmock_build_include_dirs - "${gmock_SOURCE_DIR}/include" - "${gmock_SOURCE_DIR}" - "${gtest_SOURCE_DIR}/include" - # This directory is needed to build directly from Google Test sources. - "${gtest_SOURCE_DIR}") -include_directories(${gmock_build_include_dirs}) - -######################################################################## -# -# Defines the gmock & gmock_main libraries. User tests should link -# with one of them. - -# Google Mock libraries. We build them using more strict warnings than what -# are used for other targets, to ensure that Google Mock can be compiled by -# a user aggressive about warnings. -if (MSVC) - cxx_library(gmock - "${cxx_strict}" - "${gtest_dir}/src/gtest-all.cc" - src/gmock-all.cc) - - cxx_library(gmock_main - "${cxx_strict}" - "${gtest_dir}/src/gtest-all.cc" - src/gmock-all.cc - src/gmock_main.cc) -else() - cxx_library(gmock "${cxx_strict}" src/gmock-all.cc) - target_link_libraries(gmock PUBLIC gtest) - set_target_properties(gmock PROPERTIES VERSION ${GOOGLETEST_VERSION}) - cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc) - target_link_libraries(gmock_main PUBLIC gmock) - set_target_properties(gmock_main PROPERTIES VERSION ${GOOGLETEST_VERSION}) -endif() -# If the CMake version supports it, attach header directory information -# to the targets for when we are part of a parent build (ie being pulled -# in via add_subdirectory() rather than being a standalone build). -if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") - target_include_directories(gmock SYSTEM INTERFACE - "$" - "$/${CMAKE_INSTALL_INCLUDEDIR}>") - target_include_directories(gmock_main SYSTEM INTERFACE - "$" - "$/${CMAKE_INSTALL_INCLUDEDIR}>") -endif() - -######################################################################## -# -# Install rules -install_project(gmock gmock_main) - -######################################################################## -# -# Google Mock's own tests. -# -# You can skip this section if you aren't interested in testing -# Google Mock itself. -# -# The tests are not built by default. To build them, set the -# gmock_build_tests option to ON. You can do it by running ccmake -# or specifying the -Dgmock_build_tests=ON flag when running cmake. - -if (gmock_build_tests) - # This must be set in the root directory for the tests to be run by - # 'make test' or ctest. - enable_testing() - - if (MINGW OR CYGWIN) - if (CMAKE_VERSION VERSION_LESS "2.8.12") - add_compile_options("-Wa,-mbig-obj") - else() - add_definitions("-Wa,-mbig-obj") - endif() - endif() - - ############################################################ - # C++ tests built with standard compiler flags. - - cxx_test(gmock-actions_test gmock_main) - cxx_test(gmock-cardinalities_test gmock_main) - cxx_test(gmock_ex_test gmock_main) - cxx_test(gmock-function-mocker_test gmock_main) - cxx_test(gmock-internal-utils_test gmock_main) - cxx_test(gmock-matchers_test gmock_main) - cxx_test(gmock-more-actions_test gmock_main) - cxx_test(gmock-nice-strict_test gmock_main) - cxx_test(gmock-port_test gmock_main) - cxx_test(gmock-spec-builders_test gmock_main) - cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) - cxx_test(gmock_test gmock_main) - - if (DEFINED GTEST_HAS_PTHREAD) - cxx_test(gmock_stress_test gmock) - endif() - - # gmock_all_test is commented to save time building and running tests. - # Uncomment if necessary. - # cxx_test(gmock_all_test gmock_main) - - ############################################################ - # C++ tests built with non-standard compiler flags. - - if (MSVC) - cxx_library(gmock_main_no_exception "${cxx_no_exception}" - "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) - - cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" - "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) - - else() - cxx_library(gmock_main_no_exception "${cxx_no_exception}" src/gmock_main.cc) - target_link_libraries(gmock_main_no_exception PUBLIC gmock) - - cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" src/gmock_main.cc) - target_link_libraries(gmock_main_no_rtti PUBLIC gmock) - endif() - cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}" - gmock_main_no_exception test/gmock-more-actions_test.cc) - - cxx_test_with_flags(gmock_no_rtti_test "${cxx_no_rtti}" - gmock_main_no_rtti test/gmock-spec-builders_test.cc) - - cxx_shared_library(shared_gmock_main "${cxx_default}" - "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) - - # Tests that a binary can be built with Google Mock as a shared library. On - # some system configurations, it may not possible to run the binary without - # knowing more details about the system configurations. We do not try to run - # this binary. To get a more robust shared library coverage, configure with - # -DBUILD_SHARED_LIBS=ON. - cxx_executable_with_flags(shared_gmock_test_ "${cxx_default}" - shared_gmock_main test/gmock-spec-builders_test.cc) - set_target_properties(shared_gmock_test_ - PROPERTIES - COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") - - ############################################################ - # Python tests. - - cxx_executable(gmock_leak_test_ test gmock_main) - py_test(gmock_leak_test) - - cxx_executable(gmock_output_test_ test gmock) - py_test(gmock_output_test) -endif() diff --git a/vendor/googletest/gtest/googlemock/README.md b/vendor/googletest/gtest/googlemock/README.md deleted file mode 100644 index ead68832..00000000 --- a/vendor/googletest/gtest/googlemock/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# Googletest Mocking (gMock) Framework - -### Overview - -Google's framework for writing and using C++ mock classes. It can help you -derive better designs of your system and write better tests. - -It is inspired by: - -* [jMock](http://www.jmock.org/) -* [EasyMock](http://www.easymock.org/) -* [Hamcrest](http://code.google.com/p/hamcrest/) - -It is designed with C++'s specifics in mind. - -gMock: - -- Provides a declarative syntax for defining mocks. -- Can define partial (hybrid) mocks, which are a cross of real and mock - objects. -- Handles functions of arbitrary types and overloaded functions. -- Comes with a rich set of matchers for validating function arguments. -- Uses an intuitive syntax for controlling the behavior of a mock. -- Does automatic verification of expectations (no record-and-replay needed). -- Allows arbitrary (partial) ordering constraints on function calls to be - expressed. -- Lets a user extend it by defining new matchers and actions. -- Does not use exceptions. -- Is easy to learn and use. - -Details and examples can be found here: - -* [gMock for Dummies](https://google.github.io/googletest/gmock_for_dummies.html) -* [Legacy gMock FAQ](https://google.github.io/googletest/gmock_faq.html) -* [gMock Cookbook](https://google.github.io/googletest/gmock_cook_book.html) -* [gMock Cheat Sheet](https://google.github.io/googletest/gmock_cheat_sheet.html) - -Please note that code under scripts/generator/ is from the -[cppclean project](http://code.google.com/p/cppclean/) and under the Apache -License, which is different from GoogleMock's license. - -GoogleMock is a part of -[GoogleTest C++ testing framework](http://github.com/google/googletest/) and a -subject to the same requirements. diff --git a/vendor/googletest/gtest/googlemock/cmake/gmock.pc.in b/vendor/googletest/gtest/googlemock/cmake/gmock.pc.in deleted file mode 100644 index 23c67b5c..00000000 --- a/vendor/googletest/gtest/googlemock/cmake/gmock.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -libdir=@CMAKE_INSTALL_FULL_LIBDIR@ -includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ - -Name: gmock -Description: GoogleMock (without main() function) -Version: @PROJECT_VERSION@ -URL: https://github.com/google/googletest -Requires: gtest = @PROJECT_VERSION@ -Libs: -L${libdir} -lgmock @CMAKE_THREAD_LIBS_INIT@ -Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ diff --git a/vendor/googletest/gtest/googlemock/cmake/gmock_main.pc.in b/vendor/googletest/gtest/googlemock/cmake/gmock_main.pc.in deleted file mode 100644 index 66ffea7f..00000000 --- a/vendor/googletest/gtest/googlemock/cmake/gmock_main.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -libdir=@CMAKE_INSTALL_FULL_LIBDIR@ -includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ - -Name: gmock_main -Description: GoogleMock (with main() function) -Version: @PROJECT_VERSION@ -URL: https://github.com/google/googletest -Requires: gmock = @PROJECT_VERSION@ -Libs: -L${libdir} -lgmock_main @CMAKE_THREAD_LIBS_INIT@ -Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ diff --git a/vendor/googletest/gtest/googlemock/docs/README.md b/vendor/googletest/gtest/googlemock/docs/README.md deleted file mode 100644 index 1bc57b79..00000000 --- a/vendor/googletest/gtest/googlemock/docs/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Content Moved - -We are working on updates to the GoogleTest documentation, which has moved to -the top-level [docs](../../docs) directory. diff --git a/vendor/googletest/gtest/googlemock/include/gmock/gmock-actions.h b/vendor/googletest/gtest/googlemock/include/gmock/gmock-actions.h deleted file mode 100644 index f2393bd3..00000000 --- a/vendor/googletest/gtest/googlemock/include/gmock/gmock-actions.h +++ /dev/null @@ -1,1687 +0,0 @@ -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Google Mock - a framework for writing C++ mock classes. -// -// The ACTION* family of macros can be used in a namespace scope to -// define custom actions easily. The syntax: -// -// ACTION(name) { statements; } -// -// will define an action with the given name that executes the -// statements. The value returned by the statements will be used as -// the return value of the action. Inside the statements, you can -// refer to the K-th (0-based) argument of the mock function by -// 'argK', and refer to its type by 'argK_type'. For example: -// -// ACTION(IncrementArg1) { -// arg1_type temp = arg1; -// return ++(*temp); -// } -// -// allows you to write -// -// ...WillOnce(IncrementArg1()); -// -// You can also refer to the entire argument tuple and its type by -// 'args' and 'args_type', and refer to the mock function type and its -// return type by 'function_type' and 'return_type'. -// -// Note that you don't need to specify the types of the mock function -// arguments. However rest assured that your code is still type-safe: -// you'll get a compiler error if *arg1 doesn't support the ++ -// operator, or if the type of ++(*arg1) isn't compatible with the -// mock function's return type, for example. -// -// Sometimes you'll want to parameterize the action. For that you can use -// another macro: -// -// ACTION_P(name, param_name) { statements; } -// -// For example: -// -// ACTION_P(Add, n) { return arg0 + n; } -// -// will allow you to write: -// -// ...WillOnce(Add(5)); -// -// Note that you don't need to provide the type of the parameter -// either. If you need to reference the type of a parameter named -// 'foo', you can write 'foo_type'. For example, in the body of -// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type -// of 'n'. -// -// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support -// multi-parameter actions. -// -// For the purpose of typing, you can view -// -// ACTION_Pk(Foo, p1, ..., pk) { ... } -// -// as shorthand for -// -// template -// FooActionPk Foo(p1_type p1, ..., pk_type pk) { ... } -// -// In particular, you can provide the template type arguments -// explicitly when invoking Foo(), as in Foo(5, false); -// although usually you can rely on the compiler to infer the types -// for you automatically. You can assign the result of expression -// Foo(p1, ..., pk) to a variable of type FooActionPk. This can be useful when composing actions. -// -// You can also overload actions with different numbers of parameters: -// -// ACTION_P(Plus, a) { ... } -// ACTION_P2(Plus, a, b) { ... } -// -// While it's tempting to always use the ACTION* macros when defining -// a new action, you should also consider implementing ActionInterface -// or using MakePolymorphicAction() instead, especially if you need to -// use the action a lot. While these approaches require more work, -// they give you more control on the types of the mock function -// arguments and the action parameters, which in general leads to -// better compiler error messages that pay off in the long run. They -// also allow overloading actions based on parameter types (as opposed -// to just based on the number of parameters). -// -// CAVEAT: -// -// ACTION*() can only be used in a namespace scope as templates cannot be -// declared inside of a local class. -// Users can, however, define any local functors (e.g. a lambda) that -// can be used as actions. -// -// MORE INFORMATION: -// -// To learn more about using these macros, please search for 'ACTION' on -// https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md - -// GOOGLETEST_CM0002 DO NOT DELETE - -#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ -#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ - -#ifndef _WIN32_WCE -# include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "gmock/internal/gmock-internal-utils.h" -#include "gmock/internal/gmock-port.h" -#include "gmock/internal/gmock-pp.h" - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable:4100) -#endif - -namespace testing { - -// To implement an action Foo, define: -// 1. a class FooAction that implements the ActionInterface interface, and -// 2. a factory function that creates an Action object from a -// const FooAction*. -// -// The two-level delegation design follows that of Matcher, providing -// consistency for extension developers. It also eases ownership -// management as Action objects can now be copied like plain values. - -namespace internal { - -// BuiltInDefaultValueGetter::Get() returns a -// default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. -// -// This primary template is used when kDefaultConstructible is true. -template -struct BuiltInDefaultValueGetter { - static T Get() { return T(); } -}; -template -struct BuiltInDefaultValueGetter { - static T Get() { - Assert(false, __FILE__, __LINE__, - "Default action undefined for the function return type."); - return internal::Invalid(); - // The above statement will never be reached, but is required in - // order for this function to compile. - } -}; - -// BuiltInDefaultValue::Get() returns the "built-in" default value -// for type T, which is NULL when T is a raw pointer type, 0 when T is -// a numeric type, false when T is bool, or "" when T is string or -// std::string. In addition, in C++11 and above, it turns a -// default-constructed T value if T is default constructible. For any -// other type T, the built-in default T value is undefined, and the -// function will abort the process. -template -class BuiltInDefaultValue { - public: - // This function returns true if and only if type T has a built-in default - // value. - static bool Exists() { - return ::std::is_default_constructible::value; - } - - static T Get() { - return BuiltInDefaultValueGetter< - T, ::std::is_default_constructible::value>::Get(); - } -}; - -// This partial specialization says that we use the same built-in -// default value for T and const T. -template -class BuiltInDefaultValue { - public: - static bool Exists() { return BuiltInDefaultValue::Exists(); } - static T Get() { return BuiltInDefaultValue::Get(); } -}; - -// This partial specialization defines the default values for pointer -// types. -template -class BuiltInDefaultValue { - public: - static bool Exists() { return true; } - static T* Get() { return nullptr; } -}; - -// The following specializations define the default values for -// specific types we care about. -#define GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(type, value) \ - template <> \ - class BuiltInDefaultValue { \ - public: \ - static bool Exists() { return true; } \ - static type Get() { return value; } \ - } - -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, ); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, ""); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); - -// There's no need for a default action for signed wchar_t, as that -// type is the same as wchar_t for gcc, and invalid for MSVC. -// -// There's also no need for a default action for unsigned wchar_t, as -// that type is the same as unsigned int for gcc, and invalid for -// MSVC. -#if GMOCK_WCHAR_T_IS_NATIVE_ -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT -#endif - -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned short, 0U); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed short, 0); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned int, 0U); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long long, 0); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long long, 0); // NOLINT -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0); -GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0); - -#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_ - -// Simple two-arg form of std::disjunction. -template -using disjunction = typename ::std::conditional::type; - -} // namespace internal - -// When an unexpected function call is encountered, Google Mock will -// let it return a default value if the user has specified one for its -// return type, or if the return type has a built-in default value; -// otherwise Google Mock won't know what value to return and will have -// to abort the process. -// -// The DefaultValue class allows a user to specify the -// default value for a type T that is both copyable and publicly -// destructible (i.e. anything that can be used as a function return -// type). The usage is: -// -// // Sets the default value for type T to be foo. -// DefaultValue::Set(foo); -template -class DefaultValue { - public: - // Sets the default value for type T; requires T to be - // copy-constructable and have a public destructor. - static void Set(T x) { - delete producer_; - producer_ = new FixedValueProducer(x); - } - - // Provides a factory function to be called to generate the default value. - // This method can be used even if T is only move-constructible, but it is not - // limited to that case. - typedef T (*FactoryFunction)(); - static void SetFactory(FactoryFunction factory) { - delete producer_; - producer_ = new FactoryValueProducer(factory); - } - - // Unsets the default value for type T. - static void Clear() { - delete producer_; - producer_ = nullptr; - } - - // Returns true if and only if the user has set the default value for type T. - static bool IsSet() { return producer_ != nullptr; } - - // Returns true if T has a default return value set by the user or there - // exists a built-in default value. - static bool Exists() { - return IsSet() || internal::BuiltInDefaultValue::Exists(); - } - - // Returns the default value for type T if the user has set one; - // otherwise returns the built-in default value. Requires that Exists() - // is true, which ensures that the return value is well-defined. - static T Get() { - return producer_ == nullptr ? internal::BuiltInDefaultValue::Get() - : producer_->Produce(); - } - - private: - class ValueProducer { - public: - virtual ~ValueProducer() {} - virtual T Produce() = 0; - }; - - class FixedValueProducer : public ValueProducer { - public: - explicit FixedValueProducer(T value) : value_(value) {} - T Produce() override { return value_; } - - private: - const T value_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(FixedValueProducer); - }; - - class FactoryValueProducer : public ValueProducer { - public: - explicit FactoryValueProducer(FactoryFunction factory) - : factory_(factory) {} - T Produce() override { return factory_(); } - - private: - const FactoryFunction factory_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(FactoryValueProducer); - }; - - static ValueProducer* producer_; -}; - -// This partial specialization allows a user to set default values for -// reference types. -template -class DefaultValue { - public: - // Sets the default value for type T&. - static void Set(T& x) { // NOLINT - address_ = &x; - } - - // Unsets the default value for type T&. - static void Clear() { address_ = nullptr; } - - // Returns true if and only if the user has set the default value for type T&. - static bool IsSet() { return address_ != nullptr; } - - // Returns true if T has a default return value set by the user or there - // exists a built-in default value. - static bool Exists() { - return IsSet() || internal::BuiltInDefaultValue::Exists(); - } - - // Returns the default value for type T& if the user has set one; - // otherwise returns the built-in default value if there is one; - // otherwise aborts the process. - static T& Get() { - return address_ == nullptr ? internal::BuiltInDefaultValue::Get() - : *address_; - } - - private: - static T* address_; -}; - -// This specialization allows DefaultValue::Get() to -// compile. -template <> -class DefaultValue { - public: - static bool Exists() { return true; } - static void Get() {} -}; - -// Points to the user-set default value for type T. -template -typename DefaultValue::ValueProducer* DefaultValue::producer_ = nullptr; - -// Points to the user-set default value for type T&. -template -T* DefaultValue::address_ = nullptr; - -// Implement this interface to define an action for function type F. -template -class ActionInterface { - public: - typedef typename internal::Function::Result Result; - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - ActionInterface() {} - virtual ~ActionInterface() {} - - // Performs the action. This method is not const, as in general an - // action can have side effects and be stateful. For example, a - // get-the-next-element-from-the-collection action will need to - // remember the current element. - virtual Result Perform(const ArgumentTuple& args) = 0; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface); -}; - -// An Action is a copyable and IMMUTABLE (except by assignment) -// object that represents an action to be taken when a mock function -// of type F is called. The implementation of Action is just a -// std::shared_ptr to const ActionInterface. Don't inherit from Action! -// You can view an object implementing ActionInterface as a -// concrete action (including its current state), and an Action -// object as a handle to it. -template -class Action { - // Adapter class to allow constructing Action from a legacy ActionInterface. - // New code should create Actions from functors instead. - struct ActionAdapter { - // Adapter must be copyable to satisfy std::function requirements. - ::std::shared_ptr> impl_; - - template - typename internal::Function::Result operator()(Args&&... args) { - return impl_->Perform( - ::std::forward_as_tuple(::std::forward(args)...)); - } - }; - - template - using IsCompatibleFunctor = std::is_constructible, G>; - - public: - typedef typename internal::Function::Result Result; - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - // Constructs a null Action. Needed for storing Action objects in - // STL containers. - Action() {} - - // Construct an Action from a specified callable. - // This cannot take std::function directly, because then Action would not be - // directly constructible from lambda (it would require two conversions). - template < - typename G, - typename = typename std::enable_if, std::is_constructible, - G>>::value>::type> - Action(G&& fun) { // NOLINT - Init(::std::forward(fun), IsCompatibleFunctor()); - } - - // Constructs an Action from its implementation. - explicit Action(ActionInterface* impl) - : fun_(ActionAdapter{::std::shared_ptr>(impl)}) {} - - // This constructor allows us to turn an Action object into an - // Action, as long as F's arguments can be implicitly converted - // to Func's and Func's return type can be implicitly converted to F's. - template - explicit Action(const Action& action) : fun_(action.fun_) {} - - // Returns true if and only if this is the DoDefault() action. - bool IsDoDefault() const { return fun_ == nullptr; } - - // Performs the action. Note that this method is const even though - // the corresponding method in ActionInterface is not. The reason - // is that a const Action means that it cannot be re-bound to - // another concrete action, not that the concrete action it binds to - // cannot change state. (Think of the difference between a const - // pointer and a pointer to const.) - Result Perform(ArgumentTuple args) const { - if (IsDoDefault()) { - internal::IllegalDoDefault(__FILE__, __LINE__); - } - return internal::Apply(fun_, ::std::move(args)); - } - - private: - template - friend class Action; - - template - void Init(G&& g, ::std::true_type) { - fun_ = ::std::forward(g); - } - - template - void Init(G&& g, ::std::false_type) { - fun_ = IgnoreArgs::type>{::std::forward(g)}; - } - - template - struct IgnoreArgs { - template - Result operator()(const Args&...) const { - return function_impl(); - } - - FunctionImpl function_impl; - }; - - // fun_ is an empty function if and only if this is the DoDefault() action. - ::std::function fun_; -}; - -// The PolymorphicAction class template makes it easy to implement a -// polymorphic action (i.e. an action that can be used in mock -// functions of than one type, e.g. Return()). -// -// To define a polymorphic action, a user first provides a COPYABLE -// implementation class that has a Perform() method template: -// -// class FooAction { -// public: -// template -// Result Perform(const ArgumentTuple& args) const { -// // Processes the arguments and returns a result, using -// // std::get(args) to get the N-th (0-based) argument in the tuple. -// } -// ... -// }; -// -// Then the user creates the polymorphic action using -// MakePolymorphicAction(object) where object has type FooAction. See -// the definition of Return(void) and SetArgumentPointee(value) for -// complete examples. -template -class PolymorphicAction { - public: - explicit PolymorphicAction(const Impl& impl) : impl_(impl) {} - - template - operator Action() const { - return Action(new MonomorphicImpl(impl_)); - } - - private: - template - class MonomorphicImpl : public ActionInterface { - public: - typedef typename internal::Function::Result Result; - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {} - - Result Perform(const ArgumentTuple& args) override { - return impl_.template Perform(args); - } - - private: - Impl impl_; - }; - - Impl impl_; -}; - -// Creates an Action from its implementation and returns it. The -// created Action object owns the implementation. -template -Action MakeAction(ActionInterface* impl) { - return Action(impl); -} - -// Creates a polymorphic action from its implementation. This is -// easier to use than the PolymorphicAction constructor as it -// doesn't require you to explicitly write the template argument, e.g. -// -// MakePolymorphicAction(foo); -// vs -// PolymorphicAction(foo); -template -inline PolymorphicAction MakePolymorphicAction(const Impl& impl) { - return PolymorphicAction(impl); -} - -namespace internal { - -// Helper struct to specialize ReturnAction to execute a move instead of a copy -// on return. Useful for move-only types, but could be used on any type. -template -struct ByMoveWrapper { - explicit ByMoveWrapper(T value) : payload(std::move(value)) {} - T payload; -}; - -// Implements the polymorphic Return(x) action, which can be used in -// any function that returns the type of x, regardless of the argument -// types. -// -// Note: The value passed into Return must be converted into -// Function::Result when this action is cast to Action rather than -// when that action is performed. This is important in scenarios like -// -// MOCK_METHOD1(Method, T(U)); -// ... -// { -// Foo foo; -// X x(&foo); -// EXPECT_CALL(mock, Method(_)).WillOnce(Return(x)); -// } -// -// In the example above the variable x holds reference to foo which leaves -// scope and gets destroyed. If copying X just copies a reference to foo, -// that copy will be left with a hanging reference. If conversion to T -// makes a copy of foo, the above code is safe. To support that scenario, we -// need to make sure that the type conversion happens inside the EXPECT_CALL -// statement, and conversion of the result of Return to Action is a -// good place for that. -// -// The real life example of the above scenario happens when an invocation -// of gtl::Container() is passed into Return. -// -template -class ReturnAction { - public: - // Constructs a ReturnAction object from the value to be returned. - // 'value' is passed by value instead of by const reference in order - // to allow Return("string literal") to compile. - explicit ReturnAction(R value) : value_(new R(std::move(value))) {} - - // This template type conversion operator allows Return(x) to be - // used in ANY function that returns x's type. - template - operator Action() const { // NOLINT - // Assert statement belongs here because this is the best place to verify - // conditions on F. It produces the clearest error messages - // in most compilers. - // Impl really belongs in this scope as a local class but can't - // because MSVC produces duplicate symbols in different translation units - // in this case. Until MS fixes that bug we put Impl into the class scope - // and put the typedef both here (for use in assert statement) and - // in the Impl class. But both definitions must be the same. - typedef typename Function::Result Result; - GTEST_COMPILE_ASSERT_( - !std::is_reference::value, - use_ReturnRef_instead_of_Return_to_return_a_reference); - static_assert(!std::is_void::value, - "Can't use Return() on an action expected to return `void`."); - return Action(new Impl(value_)); - } - - private: - // Implements the Return(x) action for a particular function type F. - template - class Impl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - // The implicit cast is necessary when Result has more than one - // single-argument constructor (e.g. Result is std::vector) and R - // has a type conversion operator template. In that case, value_(value) - // won't compile as the compiler doesn't known which constructor of - // Result to call. ImplicitCast_ forces the compiler to convert R to - // Result without considering explicit constructors, thus resolving the - // ambiguity. value_ is then initialized using its copy constructor. - explicit Impl(const std::shared_ptr& value) - : value_before_cast_(*value), - value_(ImplicitCast_(value_before_cast_)) {} - - Result Perform(const ArgumentTuple&) override { return value_; } - - private: - GTEST_COMPILE_ASSERT_(!std::is_reference::value, - Result_cannot_be_a_reference_type); - // We save the value before casting just in case it is being cast to a - // wrapper type. - R value_before_cast_; - Result value_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(Impl); - }; - - // Partially specialize for ByMoveWrapper. This version of ReturnAction will - // move its contents instead. - template - class Impl, F> : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - explicit Impl(const std::shared_ptr& wrapper) - : performed_(false), wrapper_(wrapper) {} - - Result Perform(const ArgumentTuple&) override { - GTEST_CHECK_(!performed_) - << "A ByMove() action should only be performed once."; - performed_ = true; - return std::move(wrapper_->payload); - } - - private: - bool performed_; - const std::shared_ptr wrapper_; - }; - - const std::shared_ptr value_; -}; - -// Implements the ReturnNull() action. -class ReturnNullAction { - public: - // Allows ReturnNull() to be used in any pointer-returning function. In C++11 - // this is enforced by returning nullptr, and in non-C++11 by asserting a - // pointer type on compile time. - template - static Result Perform(const ArgumentTuple&) { - return nullptr; - } -}; - -// Implements the Return() action. -class ReturnVoidAction { - public: - // Allows Return() to be used in any void-returning function. - template - static void Perform(const ArgumentTuple&) { - static_assert(std::is_void::value, "Result should be void."); - } -}; - -// Implements the polymorphic ReturnRef(x) action, which can be used -// in any function that returns a reference to the type of x, -// regardless of the argument types. -template -class ReturnRefAction { - public: - // Constructs a ReturnRefAction object from the reference to be returned. - explicit ReturnRefAction(T& ref) : ref_(ref) {} // NOLINT - - // This template type conversion operator allows ReturnRef(x) to be - // used in ANY function that returns a reference to x's type. - template - operator Action() const { - typedef typename Function::Result Result; - // Asserts that the function return type is a reference. This - // catches the user error of using ReturnRef(x) when Return(x) - // should be used, and generates some helpful error message. - GTEST_COMPILE_ASSERT_(std::is_reference::value, - use_Return_instead_of_ReturnRef_to_return_a_value); - return Action(new Impl(ref_)); - } - - private: - // Implements the ReturnRef(x) action for a particular function type F. - template - class Impl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - explicit Impl(T& ref) : ref_(ref) {} // NOLINT - - Result Perform(const ArgumentTuple&) override { return ref_; } - - private: - T& ref_; - }; - - T& ref_; -}; - -// Implements the polymorphic ReturnRefOfCopy(x) action, which can be -// used in any function that returns a reference to the type of x, -// regardless of the argument types. -template -class ReturnRefOfCopyAction { - public: - // Constructs a ReturnRefOfCopyAction object from the reference to - // be returned. - explicit ReturnRefOfCopyAction(const T& value) : value_(value) {} // NOLINT - - // This template type conversion operator allows ReturnRefOfCopy(x) to be - // used in ANY function that returns a reference to x's type. - template - operator Action() const { - typedef typename Function::Result Result; - // Asserts that the function return type is a reference. This - // catches the user error of using ReturnRefOfCopy(x) when Return(x) - // should be used, and generates some helpful error message. - GTEST_COMPILE_ASSERT_( - std::is_reference::value, - use_Return_instead_of_ReturnRefOfCopy_to_return_a_value); - return Action(new Impl(value_)); - } - - private: - // Implements the ReturnRefOfCopy(x) action for a particular function type F. - template - class Impl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - explicit Impl(const T& value) : value_(value) {} // NOLINT - - Result Perform(const ArgumentTuple&) override { return value_; } - - private: - T value_; - }; - - const T value_; -}; - -// Implements the polymorphic ReturnRoundRobin(v) action, which can be -// used in any function that returns the element_type of v. -template -class ReturnRoundRobinAction { - public: - explicit ReturnRoundRobinAction(std::vector values) { - GTEST_CHECK_(!values.empty()) - << "ReturnRoundRobin requires at least one element."; - state_->values = std::move(values); - } - - template - T operator()(Args&&...) const { - return state_->Next(); - } - - private: - struct State { - T Next() { - T ret_val = values[i++]; - if (i == values.size()) i = 0; - return ret_val; - } - - std::vector values; - size_t i = 0; - }; - std::shared_ptr state_ = std::make_shared(); -}; - -// Implements the polymorphic DoDefault() action. -class DoDefaultAction { - public: - // This template type conversion operator allows DoDefault() to be - // used in any function. - template - operator Action() const { return Action(); } // NOLINT -}; - -// Implements the Assign action to set a given pointer referent to a -// particular value. -template -class AssignAction { - public: - AssignAction(T1* ptr, T2 value) : ptr_(ptr), value_(value) {} - - template - void Perform(const ArgumentTuple& /* args */) const { - *ptr_ = value_; - } - - private: - T1* const ptr_; - const T2 value_; -}; - -#if !GTEST_OS_WINDOWS_MOBILE - -// Implements the SetErrnoAndReturn action to simulate return from -// various system calls and libc functions. -template -class SetErrnoAndReturnAction { - public: - SetErrnoAndReturnAction(int errno_value, T result) - : errno_(errno_value), - result_(result) {} - template - Result Perform(const ArgumentTuple& /* args */) const { - errno = errno_; - return result_; - } - - private: - const int errno_; - const T result_; -}; - -#endif // !GTEST_OS_WINDOWS_MOBILE - -// Implements the SetArgumentPointee(x) action for any function -// whose N-th argument (0-based) is a pointer to x's type. -template -struct SetArgumentPointeeAction { - A value; - - template - void operator()(const Args&... args) const { - *::std::get(std::tie(args...)) = value; - } -}; - -// Implements the Invoke(object_ptr, &Class::Method) action. -template -struct InvokeMethodAction { - Class* const obj_ptr; - const MethodPtr method_ptr; - - template - auto operator()(Args&&... args) const - -> decltype((obj_ptr->*method_ptr)(std::forward(args)...)) { - return (obj_ptr->*method_ptr)(std::forward(args)...); - } -}; - -// Implements the InvokeWithoutArgs(f) action. The template argument -// FunctionImpl is the implementation type of f, which can be either a -// function pointer or a functor. InvokeWithoutArgs(f) can be used as an -// Action as long as f's type is compatible with F. -template -struct InvokeWithoutArgsAction { - FunctionImpl function_impl; - - // Allows InvokeWithoutArgs(f) to be used as any action whose type is - // compatible with f. - template - auto operator()(const Args&...) -> decltype(function_impl()) { - return function_impl(); - } -}; - -// Implements the InvokeWithoutArgs(object_ptr, &Class::Method) action. -template -struct InvokeMethodWithoutArgsAction { - Class* const obj_ptr; - const MethodPtr method_ptr; - - using ReturnType = - decltype((std::declval()->*std::declval())()); - - template - ReturnType operator()(const Args&...) const { - return (obj_ptr->*method_ptr)(); - } -}; - -// Implements the IgnoreResult(action) action. -template -class IgnoreResultAction { - public: - explicit IgnoreResultAction(const A& action) : action_(action) {} - - template - operator Action() const { - // Assert statement belongs here because this is the best place to verify - // conditions on F. It produces the clearest error messages - // in most compilers. - // Impl really belongs in this scope as a local class but can't - // because MSVC produces duplicate symbols in different translation units - // in this case. Until MS fixes that bug we put Impl into the class scope - // and put the typedef both here (for use in assert statement) and - // in the Impl class. But both definitions must be the same. - typedef typename internal::Function::Result Result; - - // Asserts at compile time that F returns void. - static_assert(std::is_void::value, "Result type should be void."); - - return Action(new Impl(action_)); - } - - private: - template - class Impl : public ActionInterface { - public: - typedef typename internal::Function::Result Result; - typedef typename internal::Function::ArgumentTuple ArgumentTuple; - - explicit Impl(const A& action) : action_(action) {} - - void Perform(const ArgumentTuple& args) override { - // Performs the action and ignores its result. - action_.Perform(args); - } - - private: - // Type OriginalFunction is the same as F except that its return - // type is IgnoredValue. - typedef typename internal::Function::MakeResultIgnoredValue - OriginalFunction; - - const Action action_; - }; - - const A action_; -}; - -template -struct WithArgsAction { - InnerAction action; - - // The inner action could be anything convertible to Action. - // We use the conversion operator to detect the signature of the inner Action. - template - operator Action() const { // NOLINT - using TupleType = std::tuple; - Action::type...)> - converted(action); - - return [converted](Args... args) -> R { - return converted.Perform(std::forward_as_tuple( - std::get(std::forward_as_tuple(std::forward(args)...))...)); - }; - } -}; - -template -struct DoAllAction { - private: - template - using NonFinalType = - typename std::conditional::value, T, const T&>::type; - - template - std::vector Convert(IndexSequence) const { - return {ActionT(std::get(actions))...}; - } - - public: - std::tuple actions; - - template - operator Action() const { // NOLINT - struct Op { - std::vector...)>> converted; - Action last; - R operator()(Args... args) const { - auto tuple_args = std::forward_as_tuple(std::forward(args)...); - for (auto& a : converted) { - a.Perform(tuple_args); - } - return last.Perform(std::move(tuple_args)); - } - }; - return Op{Convert...)>>( - MakeIndexSequence()), - std::get(actions)}; - } -}; - -template -struct ReturnNewAction { - T* operator()() const { - return internal::Apply( - [](const Params&... unpacked_params) { - return new T(unpacked_params...); - }, - params); - } - std::tuple params; -}; - -template -struct ReturnArgAction { - template - auto operator()(const Args&... args) const -> - typename std::tuple_element>::type { - return std::get(std::tie(args...)); - } -}; - -template -struct SaveArgAction { - Ptr pointer; - - template - void operator()(const Args&... args) const { - *pointer = std::get(std::tie(args...)); - } -}; - -template -struct SaveArgPointeeAction { - Ptr pointer; - - template - void operator()(const Args&... args) const { - *pointer = *std::get(std::tie(args...)); - } -}; - -template -struct SetArgRefereeAction { - T value; - - template - void operator()(Args&&... args) const { - using argk_type = - typename ::std::tuple_element>::type; - static_assert(std::is_lvalue_reference::value, - "Argument must be a reference type."); - std::get(std::tie(args...)) = value; - } -}; - -template -struct SetArrayArgumentAction { - I1 first; - I2 last; - - template - void operator()(const Args&... args) const { - auto value = std::get(std::tie(args...)); - for (auto it = first; it != last; ++it, (void)++value) { - *value = *it; - } - } -}; - -template -struct DeleteArgAction { - template - void operator()(const Args&... args) const { - delete std::get(std::tie(args...)); - } -}; - -template -struct ReturnPointeeAction { - Ptr pointer; - template - auto operator()(const Args&...) const -> decltype(*pointer) { - return *pointer; - } -}; - -#if GTEST_HAS_EXCEPTIONS -template -struct ThrowAction { - T exception; - // We use a conversion operator to adapt to any return type. - template - operator Action() const { // NOLINT - T copy = exception; - return [copy](Args...) -> R { throw copy; }; - } -}; -#endif // GTEST_HAS_EXCEPTIONS - -} // namespace internal - -// An Unused object can be implicitly constructed from ANY value. -// This is handy when defining actions that ignore some or all of the -// mock function arguments. For example, given -// -// MOCK_METHOD3(Foo, double(const string& label, double x, double y)); -// MOCK_METHOD3(Bar, double(int index, double x, double y)); -// -// instead of -// -// double DistanceToOriginWithLabel(const string& label, double x, double y) { -// return sqrt(x*x + y*y); -// } -// double DistanceToOriginWithIndex(int index, double x, double y) { -// return sqrt(x*x + y*y); -// } -// ... -// EXPECT_CALL(mock, Foo("abc", _, _)) -// .WillOnce(Invoke(DistanceToOriginWithLabel)); -// EXPECT_CALL(mock, Bar(5, _, _)) -// .WillOnce(Invoke(DistanceToOriginWithIndex)); -// -// you could write -// -// // We can declare any uninteresting argument as Unused. -// double DistanceToOrigin(Unused, double x, double y) { -// return sqrt(x*x + y*y); -// } -// ... -// EXPECT_CALL(mock, Foo("abc", _, _)).WillOnce(Invoke(DistanceToOrigin)); -// EXPECT_CALL(mock, Bar(5, _, _)).WillOnce(Invoke(DistanceToOrigin)); -typedef internal::IgnoredValue Unused; - -// Creates an action that does actions a1, a2, ..., sequentially in -// each invocation. All but the last action will have a readonly view of the -// arguments. -template -internal::DoAllAction::type...> DoAll( - Action&&... action) { - return {std::forward_as_tuple(std::forward(action)...)}; -} - -// WithArg(an_action) creates an action that passes the k-th -// (0-based) argument of the mock function to an_action and performs -// it. It adapts an action accepting one argument to one that accepts -// multiple arguments. For convenience, we also provide -// WithArgs(an_action) (defined below) as a synonym. -template -internal::WithArgsAction::type, k> -WithArg(InnerAction&& action) { - return {std::forward(action)}; -} - -// WithArgs(an_action) creates an action that passes -// the selected arguments of the mock function to an_action and -// performs it. It serves as an adaptor between actions with -// different argument lists. -template -internal::WithArgsAction::type, k, ks...> -WithArgs(InnerAction&& action) { - return {std::forward(action)}; -} - -// WithoutArgs(inner_action) can be used in a mock function with a -// non-empty argument list to perform inner_action, which takes no -// argument. In other words, it adapts an action accepting no -// argument to one that accepts (and ignores) arguments. -template -internal::WithArgsAction::type> -WithoutArgs(InnerAction&& action) { - return {std::forward(action)}; -} - -// Creates an action that returns 'value'. 'value' is passed by value -// instead of const reference - otherwise Return("string literal") -// will trigger a compiler error about using array as initializer. -template -internal::ReturnAction Return(R value) { - return internal::ReturnAction(std::move(value)); -} - -// Creates an action that returns NULL. -inline PolymorphicAction ReturnNull() { - return MakePolymorphicAction(internal::ReturnNullAction()); -} - -// Creates an action that returns from a void function. -inline PolymorphicAction Return() { - return MakePolymorphicAction(internal::ReturnVoidAction()); -} - -// Creates an action that returns the reference to a variable. -template -inline internal::ReturnRefAction ReturnRef(R& x) { // NOLINT - return internal::ReturnRefAction(x); -} - -// Prevent using ReturnRef on reference to temporary. -template -internal::ReturnRefAction ReturnRef(R&&) = delete; - -// Creates an action that returns the reference to a copy of the -// argument. The copy is created when the action is constructed and -// lives as long as the action. -template -inline internal::ReturnRefOfCopyAction ReturnRefOfCopy(const R& x) { - return internal::ReturnRefOfCopyAction(x); -} - -// Modifies the parent action (a Return() action) to perform a move of the -// argument instead of a copy. -// Return(ByMove()) actions can only be executed once and will assert this -// invariant. -template -internal::ByMoveWrapper ByMove(R x) { - return internal::ByMoveWrapper(std::move(x)); -} - -// Creates an action that returns an element of `vals`. Calling this action will -// repeatedly return the next value from `vals` until it reaches the end and -// will restart from the beginning. -template -internal::ReturnRoundRobinAction ReturnRoundRobin(std::vector vals) { - return internal::ReturnRoundRobinAction(std::move(vals)); -} - -// Creates an action that returns an element of `vals`. Calling this action will -// repeatedly return the next value from `vals` until it reaches the end and -// will restart from the beginning. -template -internal::ReturnRoundRobinAction ReturnRoundRobin( - std::initializer_list vals) { - return internal::ReturnRoundRobinAction(std::vector(vals)); -} - -// Creates an action that does the default action for the give mock function. -inline internal::DoDefaultAction DoDefault() { - return internal::DoDefaultAction(); -} - -// Creates an action that sets the variable pointed by the N-th -// (0-based) function argument to 'value'. -template -internal::SetArgumentPointeeAction SetArgPointee(T value) { - return {std::move(value)}; -} - -// The following version is DEPRECATED. -template -internal::SetArgumentPointeeAction SetArgumentPointee(T value) { - return {std::move(value)}; -} - -// Creates an action that sets a pointer referent to a given value. -template -PolymorphicAction > Assign(T1* ptr, T2 val) { - return MakePolymorphicAction(internal::AssignAction(ptr, val)); -} - -#if !GTEST_OS_WINDOWS_MOBILE - -// Creates an action that sets errno and returns the appropriate error. -template -PolymorphicAction > -SetErrnoAndReturn(int errval, T result) { - return MakePolymorphicAction( - internal::SetErrnoAndReturnAction(errval, result)); -} - -#endif // !GTEST_OS_WINDOWS_MOBILE - -// Various overloads for Invoke(). - -// Legacy function. -// Actions can now be implicitly constructed from callables. No need to create -// wrapper objects. -// This function exists for backwards compatibility. -template -typename std::decay::type Invoke(FunctionImpl&& function_impl) { - return std::forward(function_impl); -} - -// Creates an action that invokes the given method on the given object -// with the mock function's arguments. -template -internal::InvokeMethodAction Invoke(Class* obj_ptr, - MethodPtr method_ptr) { - return {obj_ptr, method_ptr}; -} - -// Creates an action that invokes 'function_impl' with no argument. -template -internal::InvokeWithoutArgsAction::type> -InvokeWithoutArgs(FunctionImpl function_impl) { - return {std::move(function_impl)}; -} - -// Creates an action that invokes the given method on the given object -// with no argument. -template -internal::InvokeMethodWithoutArgsAction InvokeWithoutArgs( - Class* obj_ptr, MethodPtr method_ptr) { - return {obj_ptr, method_ptr}; -} - -// Creates an action that performs an_action and throws away its -// result. In other words, it changes the return type of an_action to -// void. an_action MUST NOT return void, or the code won't compile. -template -inline internal::IgnoreResultAction IgnoreResult(const A& an_action) { - return internal::IgnoreResultAction(an_action); -} - -// Creates a reference wrapper for the given L-value. If necessary, -// you can explicitly specify the type of the reference. For example, -// suppose 'derived' is an object of type Derived, ByRef(derived) -// would wrap a Derived&. If you want to wrap a const Base& instead, -// where Base is a base class of Derived, just write: -// -// ByRef(derived) -// -// N.B. ByRef is redundant with std::ref, std::cref and std::reference_wrapper. -// However, it may still be used for consistency with ByMove(). -template -inline ::std::reference_wrapper ByRef(T& l_value) { // NOLINT - return ::std::reference_wrapper(l_value); -} - -// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new -// instance of type T, constructed on the heap with constructor arguments -// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. -template -internal::ReturnNewAction::type...> ReturnNew( - Params&&... params) { - return {std::forward_as_tuple(std::forward(params)...)}; -} - -// Action ReturnArg() returns the k-th argument of the mock function. -template -internal::ReturnArgAction ReturnArg() { - return {}; -} - -// Action SaveArg(pointer) saves the k-th (0-based) argument of the -// mock function to *pointer. -template -internal::SaveArgAction SaveArg(Ptr pointer) { - return {pointer}; -} - -// Action SaveArgPointee(pointer) saves the value pointed to -// by the k-th (0-based) argument of the mock function to *pointer. -template -internal::SaveArgPointeeAction SaveArgPointee(Ptr pointer) { - return {pointer}; -} - -// Action SetArgReferee(value) assigns 'value' to the variable -// referenced by the k-th (0-based) argument of the mock function. -template -internal::SetArgRefereeAction::type> SetArgReferee( - T&& value) { - return {std::forward(value)}; -} - -// Action SetArrayArgument(first, last) copies the elements in -// source range [first, last) to the array pointed to by the k-th -// (0-based) argument, which can be either a pointer or an -// iterator. The action does not take ownership of the elements in the -// source range. -template -internal::SetArrayArgumentAction SetArrayArgument(I1 first, - I2 last) { - return {first, last}; -} - -// Action DeleteArg() deletes the k-th (0-based) argument of the mock -// function. -template -internal::DeleteArgAction DeleteArg() { - return {}; -} - -// This action returns the value pointed to by 'pointer'. -template -internal::ReturnPointeeAction ReturnPointee(Ptr pointer) { - return {pointer}; -} - -// Action Throw(exception) can be used in a mock function of any type -// to throw the given exception. Any copyable value can be thrown. -#if GTEST_HAS_EXCEPTIONS -template -internal::ThrowAction::type> Throw(T&& exception) { - return {std::forward(exception)}; -} -#endif // GTEST_HAS_EXCEPTIONS - -namespace internal { - -// A macro from the ACTION* family (defined later in gmock-generated-actions.h) -// defines an action that can be used in a mock function. Typically, -// these actions only care about a subset of the arguments of the mock -// function. For example, if such an action only uses the second -// argument, it can be used in any mock function that takes >= 2 -// arguments where the type of the second argument is compatible. -// -// Therefore, the action implementation must be prepared to take more -// arguments than it needs. The ExcessiveArg type is used to -// represent those excessive arguments. In order to keep the compiler -// error messages tractable, we define it in the testing namespace -// instead of testing::internal. However, this is an INTERNAL TYPE -// and subject to change without notice, so a user MUST NOT USE THIS -// TYPE DIRECTLY. -struct ExcessiveArg {}; - -// Builds an implementation of an Action<> for some particular signature, using -// a class defined by an ACTION* macro. -template struct ActionImpl; - -template -struct ImplBase { - struct Holder { - // Allows each copy of the Action<> to get to the Impl. - explicit operator const Impl&() const { return *ptr; } - std::shared_ptr ptr; - }; - using type = typename std::conditional::value, - Impl, Holder>::type; -}; - -template -struct ActionImpl : ImplBase::type { - using Base = typename ImplBase::type; - using function_type = R(Args...); - using args_type = std::tuple; - - ActionImpl() = default; // Only defined if appropriate for Base. - explicit ActionImpl(std::shared_ptr impl) : Base{std::move(impl)} { } - - R operator()(Args&&... arg) const { - static constexpr size_t kMaxArgs = - sizeof...(Args) <= 10 ? sizeof...(Args) : 10; - return Apply(MakeIndexSequence{}, - MakeIndexSequence<10 - kMaxArgs>{}, - args_type{std::forward(arg)...}); - } - - template - R Apply(IndexSequence, IndexSequence, - const args_type& args) const { - // Impl need not be specific to the signature of action being implemented; - // only the implementing function body needs to have all of the specific - // types instantiated. Up to 10 of the args that are provided by the - // args_type get passed, followed by a dummy of unspecified type for the - // remainder up to 10 explicit args. - static constexpr ExcessiveArg kExcessArg{}; - return static_cast(*this).template gmock_PerformImpl< - /*function_type=*/function_type, /*return_type=*/R, - /*args_type=*/args_type, - /*argN_type=*/typename std::tuple_element::type...>( - /*args=*/args, std::get(args)..., - ((void)excess_id, kExcessArg)...); - } -}; - -// Stores a default-constructed Impl as part of the Action<>'s -// std::function<>. The Impl should be trivial to copy. -template -::testing::Action MakeAction() { - return ::testing::Action(ActionImpl()); -} - -// Stores just the one given instance of Impl. -template -::testing::Action MakeAction(std::shared_ptr impl) { - return ::testing::Action(ActionImpl(std::move(impl))); -} - -#define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \ - , const arg##i##_type& arg##i GTEST_ATTRIBUTE_UNUSED_ -#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ - const args_type& args GTEST_ATTRIBUTE_UNUSED_ GMOCK_PP_REPEAT( \ - GMOCK_INTERNAL_ARG_UNUSED, , 10) - -#define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i -#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_ \ - const args_type& args GMOCK_PP_REPEAT(GMOCK_INTERNAL_ARG, , 10) - -#define GMOCK_INTERNAL_TEMPLATE_ARG(i, data, el) , typename arg##i##_type -#define GMOCK_ACTION_TEMPLATE_ARGS_NAMES_ \ - GMOCK_PP_TAIL(GMOCK_PP_REPEAT(GMOCK_INTERNAL_TEMPLATE_ARG, , 10)) - -#define GMOCK_INTERNAL_TYPENAME_PARAM(i, data, param) , typename param##_type -#define GMOCK_ACTION_TYPENAME_PARAMS_(params) \ - GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPENAME_PARAM, , params)) - -#define GMOCK_INTERNAL_TYPE_PARAM(i, data, param) , param##_type -#define GMOCK_ACTION_TYPE_PARAMS_(params) \ - GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_PARAM, , params)) - -#define GMOCK_INTERNAL_TYPE_GVALUE_PARAM(i, data, param) \ - , param##_type gmock_p##i -#define GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params) \ - GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_GVALUE_PARAM, , params)) - -#define GMOCK_INTERNAL_GVALUE_PARAM(i, data, param) \ - , std::forward(gmock_p##i) -#define GMOCK_ACTION_GVALUE_PARAMS_(params) \ - GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GVALUE_PARAM, , params)) - -#define GMOCK_INTERNAL_INIT_PARAM(i, data, param) \ - , param(::std::forward(gmock_p##i)) -#define GMOCK_ACTION_INIT_PARAMS_(params) \ - GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_INIT_PARAM, , params)) - -#define GMOCK_INTERNAL_FIELD_PARAM(i, data, param) param##_type param; -#define GMOCK_ACTION_FIELD_PARAMS_(params) \ - GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_FIELD_PARAM, , params) - -#define GMOCK_INTERNAL_ACTION(name, full_name, params) \ - template \ - class full_name { \ - public: \ - explicit full_name(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ - : impl_(std::make_shared( \ - GMOCK_ACTION_GVALUE_PARAMS_(params))) { } \ - full_name(const full_name&) = default; \ - full_name(full_name&&) noexcept = default; \ - template \ - operator ::testing::Action() const { \ - return ::testing::internal::MakeAction(impl_); \ - } \ - private: \ - class gmock_Impl { \ - public: \ - explicit gmock_Impl(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) \ - : GMOCK_ACTION_INIT_PARAMS_(params) {} \ - template \ - return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ - GMOCK_ACTION_FIELD_PARAMS_(params) \ - }; \ - std::shared_ptr impl_; \ - }; \ - template \ - inline full_name name( \ - GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \ - return full_name( \ - GMOCK_ACTION_GVALUE_PARAMS_(params)); \ - } \ - template \ - template \ - return_type full_name::gmock_Impl:: \ - gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -} // namespace internal - -// Similar to GMOCK_INTERNAL_ACTION, but no bound parameters are stored. -#define ACTION(name) \ - class name##Action { \ - public: \ - explicit name##Action() noexcept {} \ - name##Action(const name##Action&) noexcept {} \ - template \ - operator ::testing::Action() const { \ - return ::testing::internal::MakeAction(); \ - } \ - private: \ - class gmock_Impl { \ - public: \ - template \ - return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ - }; \ - }; \ - inline name##Action name() GTEST_MUST_USE_RESULT_; \ - inline name##Action name() { return name##Action(); } \ - template \ - return_type name##Action::gmock_Impl::gmock_PerformImpl( \ - GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const - -#define ACTION_P(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP, (__VA_ARGS__)) - -#define ACTION_P2(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP2, (__VA_ARGS__)) - -#define ACTION_P3(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP3, (__VA_ARGS__)) - -#define ACTION_P4(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP4, (__VA_ARGS__)) - -#define ACTION_P5(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP5, (__VA_ARGS__)) - -#define ACTION_P6(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP6, (__VA_ARGS__)) - -#define ACTION_P7(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP7, (__VA_ARGS__)) - -#define ACTION_P8(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP8, (__VA_ARGS__)) - -#define ACTION_P9(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP9, (__VA_ARGS__)) - -#define ACTION_P10(name, ...) \ - GMOCK_INTERNAL_ACTION(name, name##ActionP10, (__VA_ARGS__)) - -} // namespace testing - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_ diff --git a/vendor/googletest/gtest/googlemock/include/gmock/gmock-cardinalities.h b/vendor/googletest/gtest/googlemock/include/gmock/gmock-cardinalities.h deleted file mode 100644 index fc7f803a..00000000 --- a/vendor/googletest/gtest/googlemock/include/gmock/gmock-cardinalities.h +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Google Mock - a framework for writing C++ mock classes. -// -// This file implements some commonly used cardinalities. More -// cardinalities can be defined by the user implementing the -// CardinalityInterface interface if necessary. - -// GOOGLETEST_CM0002 DO NOT DELETE - -#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ -#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ - -#include -#include -#include // NOLINT -#include "gmock/internal/gmock-port.h" -#include "gtest/gtest.h" - -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ -/* class A needs to have dll-interface to be used by clients of class B */) - -namespace testing { - -// To implement a cardinality Foo, define: -// 1. a class FooCardinality that implements the -// CardinalityInterface interface, and -// 2. a factory function that creates a Cardinality object from a -// const FooCardinality*. -// -// The two-level delegation design follows that of Matcher, providing -// consistency for extension developers. It also eases ownership -// management as Cardinality objects can now be copied like plain values. - -// The implementation of a cardinality. -class CardinalityInterface { - public: - virtual ~CardinalityInterface() {} - - // Conservative estimate on the lower/upper bound of the number of - // calls allowed. - virtual int ConservativeLowerBound() const { return 0; } - virtual int ConservativeUpperBound() const { return INT_MAX; } - - // Returns true if and only if call_count calls will satisfy this - // cardinality. - virtual bool IsSatisfiedByCallCount(int call_count) const = 0; - - // Returns true if and only if call_count calls will saturate this - // cardinality. - virtual bool IsSaturatedByCallCount(int call_count) const = 0; - - // Describes self to an ostream. - virtual void DescribeTo(::std::ostream* os) const = 0; -}; - -// A Cardinality is a copyable and IMMUTABLE (except by assignment) -// object that specifies how many times a mock function is expected to -// be called. The implementation of Cardinality is just a std::shared_ptr -// to const CardinalityInterface. Don't inherit from Cardinality! -class GTEST_API_ Cardinality { - public: - // Constructs a null cardinality. Needed for storing Cardinality - // objects in STL containers. - Cardinality() {} - - // Constructs a Cardinality from its implementation. - explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {} - - // Conservative estimate on the lower/upper bound of the number of - // calls allowed. - int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); } - int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); } - - // Returns true if and only if call_count calls will satisfy this - // cardinality. - bool IsSatisfiedByCallCount(int call_count) const { - return impl_->IsSatisfiedByCallCount(call_count); - } - - // Returns true if and only if call_count calls will saturate this - // cardinality. - bool IsSaturatedByCallCount(int call_count) const { - return impl_->IsSaturatedByCallCount(call_count); - } - - // Returns true if and only if call_count calls will over-saturate this - // cardinality, i.e. exceed the maximum number of allowed calls. - bool IsOverSaturatedByCallCount(int call_count) const { - return impl_->IsSaturatedByCallCount(call_count) && - !impl_->IsSatisfiedByCallCount(call_count); - } - - // Describes self to an ostream - void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } - - // Describes the given actual call count to an ostream. - static void DescribeActualCallCountTo(int actual_call_count, - ::std::ostream* os); - - private: - std::shared_ptr impl_; -}; - -// Creates a cardinality that allows at least n calls. -GTEST_API_ Cardinality AtLeast(int n); - -// Creates a cardinality that allows at most n calls. -GTEST_API_ Cardinality AtMost(int n); - -// Creates a cardinality that allows any number of calls. -GTEST_API_ Cardinality AnyNumber(); - -// Creates a cardinality that allows between min and max calls. -GTEST_API_ Cardinality Between(int min, int max); - -// Creates a cardinality that allows exactly n calls. -GTEST_API_ Cardinality Exactly(int n); - -// Creates a cardinality from its implementation. -inline Cardinality MakeCardinality(const CardinalityInterface* c) { - return Cardinality(c); -} - -} // namespace testing - -GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 - -#endif // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ diff --git a/vendor/googletest/gtest/googlemock/include/gmock/gmock-function-mocker.h b/vendor/googletest/gtest/googlemock/include/gmock/gmock-function-mocker.h deleted file mode 100644 index 0fc6f6f3..00000000 --- a/vendor/googletest/gtest/googlemock/include/gmock/gmock-function-mocker.h +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Google Mock - a framework for writing C++ mock classes. -// -// This file implements MOCK_METHOD. - -// GOOGLETEST_CM0002 DO NOT DELETE - -#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT -#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT - -#include // IWYU pragma: keep -#include // IWYU pragma: keep - -#include "gmock/gmock-spec-builders.h" -#include "gmock/internal/gmock-internal-utils.h" -#include "gmock/internal/gmock-pp.h" - -namespace testing { -namespace internal { -template -using identity_t = T; - -template -struct ThisRefAdjuster { - template - using AdjustT = typename std::conditional< - std::is_const::type>::value, - typename std::conditional::value, - const T&, const T&&>::type, - typename std::conditional::value, T&, - T&&>::type>::type; - - template - static AdjustT Adjust(const MockType& mock) { - return static_cast>(const_cast(mock)); - } -}; - -} // namespace internal - -// The style guide prohibits "using" statements in a namespace scope -// inside a header file. However, the FunctionMocker class template -// is meant to be defined in the ::testing namespace. The following -// line is just a trick for working around a bug in MSVC 8.0, which -// cannot handle it if we define FunctionMocker in ::testing. -using internal::FunctionMocker; -} // namespace testing - -#define MOCK_METHOD(...) \ - GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__) - -#define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \ - GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) - -#define GMOCK_INTERNAL_MOCK_METHOD_ARG_2(...) \ - GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) - -#define GMOCK_INTERNAL_MOCK_METHOD_ARG_3(_Ret, _MethodName, _Args) \ - GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, ()) - -#define GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, _Spec) \ - GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Args); \ - GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Spec); \ - GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ - GMOCK_PP_NARG0 _Args, GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)); \ - GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ - GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ - GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec), \ - GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec), \ - GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Spec), \ - GMOCK_INTERNAL_GET_CALLTYPE(_Spec), GMOCK_INTERNAL_GET_REF_SPEC(_Spec), \ - (GMOCK_INTERNAL_SIGNATURE(_Ret, _Args))) - -#define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \ - GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) - -#define GMOCK_INTERNAL_MOCK_METHOD_ARG_6(...) \ - GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) - -#define GMOCK_INTERNAL_MOCK_METHOD_ARG_7(...) \ - GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__) - -#define GMOCK_INTERNAL_WRONG_ARITY(...) \ - static_assert( \ - false, \ - "MOCK_METHOD must be called with 3 or 4 arguments. _Ret, " \ - "_MethodName, _Args and optionally _Spec. _Args and _Spec must be " \ - "enclosed in parentheses. If _Ret is a type with unprotected commas, " \ - "it must also be enclosed in parentheses.") - -#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \ - static_assert( \ - GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \ - GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.") - -#define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...) \ - static_assert( \ - std::is_function<__VA_ARGS__>::value, \ - "Signature must be a function type, maybe return type contains " \ - "unprotected comma."); \ - static_assert( \ - ::testing::tuple_size::ArgumentTuple>::value == _N, \ - "This method does not take " GMOCK_PP_STRINGIZE( \ - _N) " arguments. Parenthesize all types with unprotected commas.") - -#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \ - GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec) - -#define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness, \ - _Override, _Final, _NoexceptSpec, \ - _CallType, _RefSpec, _Signature) \ - typename ::testing::internal::Function::Result \ - GMOCK_INTERNAL_EXPAND(_CallType) \ - _MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N)) \ - GMOCK_PP_IF(_Constness, const, ) _RefSpec _NoexceptSpec \ - GMOCK_PP_IF(_Override, override, ) GMOCK_PP_IF(_Final, final, ) { \ - GMOCK_MOCKER_(_N, _Constness, _MethodName) \ - .SetOwnerAndName(this, #_MethodName); \ - return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ - .Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \ - } \ - ::testing::MockSpec gmock_##_MethodName( \ - GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \ - GMOCK_PP_IF(_Constness, const, ) _RefSpec { \ - GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \ - return GMOCK_MOCKER_(_N, _Constness, _MethodName) \ - .With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \ - } \ - ::testing::MockSpec gmock_##_MethodName( \ - const ::testing::internal::WithoutMatchers&, \ - GMOCK_PP_IF(_Constness, const, )::testing::internal::Function< \ - GMOCK_PP_REMOVE_PARENS(_Signature)>*) const _RefSpec _NoexceptSpec { \ - return ::testing::internal::ThisRefAdjuster::Adjust(*this) \ - .gmock_##_MethodName(GMOCK_PP_REPEAT( \ - GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \ - } \ - mutable ::testing::FunctionMocker \ - GMOCK_MOCKER_(_N, _Constness, _MethodName) - -#define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__ - -// Five Valid modifiers. -#define GMOCK_INTERNAL_HAS_CONST(_Tuple) \ - GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple)) - -#define GMOCK_INTERNAL_HAS_OVERRIDE(_Tuple) \ - GMOCK_PP_HAS_COMMA( \ - GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_OVERRIDE, ~, _Tuple)) - -#define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \ - GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple)) - -#define GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Tuple) \ - GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT, ~, _Tuple) - -#define GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT(_i, _, _elem) \ - GMOCK_PP_IF( \ - GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)), \ - _elem, ) - -#define GMOCK_INTERNAL_GET_REF_SPEC(_Tuple) \ - GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_REF_SPEC_IF_REF, ~, _Tuple) - -#define GMOCK_INTERNAL_REF_SPEC_IF_REF(_i, _, _elem) \ - GMOCK_PP_IF(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)), \ - GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), ) - -#define GMOCK_INTERNAL_GET_CALLTYPE(_Tuple) \ - GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_CALLTYPE_IMPL, ~, _Tuple) - -#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \ - static_assert( \ - (GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) + \ - GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \ - GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) + \ - GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \ - GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)) + \ - GMOCK_INTERNAL_IS_CALLTYPE(_elem)) == 1, \ - GMOCK_PP_STRINGIZE( \ - _elem) " cannot be recognized as a valid specification modifier."); - -// Modifiers implementation. -#define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \ - GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem) - -#define GMOCK_INTERNAL_DETECT_CONST_I_const , - -#define GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem) \ - GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_OVERRIDE_I_, _elem) - -#define GMOCK_INTERNAL_DETECT_OVERRIDE_I_override , - -#define GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem) \ - GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_FINAL_I_, _elem) - -#define GMOCK_INTERNAL_DETECT_FINAL_I_final , - -#define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \ - GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem) - -#define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept , - -#define GMOCK_INTERNAL_DETECT_REF(_i, _, _elem) \ - GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_REF_I_, _elem) - -#define GMOCK_INTERNAL_DETECT_REF_I_ref , - -#define GMOCK_INTERNAL_UNPACK_ref(x) x - -#define GMOCK_INTERNAL_GET_CALLTYPE_IMPL(_i, _, _elem) \ - GMOCK_PP_IF(GMOCK_INTERNAL_IS_CALLTYPE(_elem), \ - GMOCK_INTERNAL_GET_VALUE_CALLTYPE, GMOCK_PP_EMPTY) \ - (_elem) - -// TODO(iserna): GMOCK_INTERNAL_IS_CALLTYPE and -// GMOCK_INTERNAL_GET_VALUE_CALLTYPE needed more expansions to work on windows -// maybe they can be simplified somehow. -#define GMOCK_INTERNAL_IS_CALLTYPE(_arg) \ - GMOCK_INTERNAL_IS_CALLTYPE_I( \ - GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg)) -#define GMOCK_INTERNAL_IS_CALLTYPE_I(_arg) GMOCK_PP_IS_ENCLOSED_PARENS(_arg) - -#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE(_arg) \ - GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I( \ - GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg)) -#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I(_arg) \ - GMOCK_PP_IDENTITY _arg - -#define GMOCK_INTERNAL_IS_CALLTYPE_HELPER_Calltype - -// Note: The use of `identity_t` here allows _Ret to represent return types that -// would normally need to be specified in a different way. For example, a method -// returning a function pointer must be written as -// -// fn_ptr_return_t (*method(method_args_t...))(fn_ptr_args_t...) -// -// But we only support placing the return type at the beginning. To handle this, -// we wrap all calls in identity_t, so that a declaration will be expanded to -// -// identity_t method(method_args_t...) -// -// This allows us to work around the syntactic oddities of function/method -// types. -#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args) \ - ::testing::internal::identity_t( \ - GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args)) - -#define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem) \ - GMOCK_PP_COMMA_IF(_i) \ - GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_elem), GMOCK_PP_REMOVE_PARENS, \ - GMOCK_PP_IDENTITY) \ - (_elem) - -#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _) \ - GMOCK_PP_COMMA_IF(_i) \ - GMOCK_INTERNAL_ARG_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ - gmock_a##_i - -#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \ - GMOCK_PP_COMMA_IF(_i) \ - ::std::forward(gmock_a##_i) - -#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _) \ - GMOCK_PP_COMMA_IF(_i) \ - GMOCK_INTERNAL_MATCHER_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \ - gmock_a##_i - -#define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \ - GMOCK_PP_COMMA_IF(_i) \ - gmock_a##_i - -#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \ - GMOCK_PP_COMMA_IF(_i) \ - ::testing::A() - -#define GMOCK_INTERNAL_ARG_O(_i, ...) \ - typename ::testing::internal::Function<__VA_ARGS__>::template Arg<_i>::type - -#define GMOCK_INTERNAL_MATCHER_O(_i, ...) \ - const ::testing::Matcher::template Arg<_i>::type>& - -#define MOCK_METHOD0(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 0, __VA_ARGS__) -#define MOCK_METHOD1(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 1, __VA_ARGS__) -#define MOCK_METHOD2(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 2, __VA_ARGS__) -#define MOCK_METHOD3(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 3, __VA_ARGS__) -#define MOCK_METHOD4(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 4, __VA_ARGS__) -#define MOCK_METHOD5(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 5, __VA_ARGS__) -#define MOCK_METHOD6(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 6, __VA_ARGS__) -#define MOCK_METHOD7(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 7, __VA_ARGS__) -#define MOCK_METHOD8(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 8, __VA_ARGS__) -#define MOCK_METHOD9(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 9, __VA_ARGS__) -#define MOCK_METHOD10(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, , m, 10, __VA_ARGS__) - -#define MOCK_CONST_METHOD0(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 0, __VA_ARGS__) -#define MOCK_CONST_METHOD1(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 1, __VA_ARGS__) -#define MOCK_CONST_METHOD2(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 2, __VA_ARGS__) -#define MOCK_CONST_METHOD3(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 3, __VA_ARGS__) -#define MOCK_CONST_METHOD4(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 4, __VA_ARGS__) -#define MOCK_CONST_METHOD5(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 5, __VA_ARGS__) -#define MOCK_CONST_METHOD6(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 6, __VA_ARGS__) -#define MOCK_CONST_METHOD7(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 7, __VA_ARGS__) -#define MOCK_CONST_METHOD8(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 8, __VA_ARGS__) -#define MOCK_CONST_METHOD9(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 9, __VA_ARGS__) -#define MOCK_CONST_METHOD10(m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, , m, 10, __VA_ARGS__) - -#define MOCK_METHOD0_T(m, ...) MOCK_METHOD0(m, __VA_ARGS__) -#define MOCK_METHOD1_T(m, ...) MOCK_METHOD1(m, __VA_ARGS__) -#define MOCK_METHOD2_T(m, ...) MOCK_METHOD2(m, __VA_ARGS__) -#define MOCK_METHOD3_T(m, ...) MOCK_METHOD3(m, __VA_ARGS__) -#define MOCK_METHOD4_T(m, ...) MOCK_METHOD4(m, __VA_ARGS__) -#define MOCK_METHOD5_T(m, ...) MOCK_METHOD5(m, __VA_ARGS__) -#define MOCK_METHOD6_T(m, ...) MOCK_METHOD6(m, __VA_ARGS__) -#define MOCK_METHOD7_T(m, ...) MOCK_METHOD7(m, __VA_ARGS__) -#define MOCK_METHOD8_T(m, ...) MOCK_METHOD8(m, __VA_ARGS__) -#define MOCK_METHOD9_T(m, ...) MOCK_METHOD9(m, __VA_ARGS__) -#define MOCK_METHOD10_T(m, ...) MOCK_METHOD10(m, __VA_ARGS__) - -#define MOCK_CONST_METHOD0_T(m, ...) MOCK_CONST_METHOD0(m, __VA_ARGS__) -#define MOCK_CONST_METHOD1_T(m, ...) MOCK_CONST_METHOD1(m, __VA_ARGS__) -#define MOCK_CONST_METHOD2_T(m, ...) MOCK_CONST_METHOD2(m, __VA_ARGS__) -#define MOCK_CONST_METHOD3_T(m, ...) MOCK_CONST_METHOD3(m, __VA_ARGS__) -#define MOCK_CONST_METHOD4_T(m, ...) MOCK_CONST_METHOD4(m, __VA_ARGS__) -#define MOCK_CONST_METHOD5_T(m, ...) MOCK_CONST_METHOD5(m, __VA_ARGS__) -#define MOCK_CONST_METHOD6_T(m, ...) MOCK_CONST_METHOD6(m, __VA_ARGS__) -#define MOCK_CONST_METHOD7_T(m, ...) MOCK_CONST_METHOD7(m, __VA_ARGS__) -#define MOCK_CONST_METHOD8_T(m, ...) MOCK_CONST_METHOD8(m, __VA_ARGS__) -#define MOCK_CONST_METHOD9_T(m, ...) MOCK_CONST_METHOD9(m, __VA_ARGS__) -#define MOCK_CONST_METHOD10_T(m, ...) MOCK_CONST_METHOD10(m, __VA_ARGS__) - -#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 0, __VA_ARGS__) -#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 1, __VA_ARGS__) -#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 2, __VA_ARGS__) -#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 3, __VA_ARGS__) -#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 4, __VA_ARGS__) -#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 5, __VA_ARGS__) -#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 6, __VA_ARGS__) -#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 7, __VA_ARGS__) -#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 8, __VA_ARGS__) -#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 9, __VA_ARGS__) -#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 10, __VA_ARGS__) - -#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 0, __VA_ARGS__) -#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 1, __VA_ARGS__) -#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 2, __VA_ARGS__) -#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 3, __VA_ARGS__) -#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 4, __VA_ARGS__) -#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 5, __VA_ARGS__) -#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 6, __VA_ARGS__) -#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 7, __VA_ARGS__) -#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 8, __VA_ARGS__) -#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 9, __VA_ARGS__) -#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \ - GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 10, __VA_ARGS__) - -#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) - -#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__) -#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \ - MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__) - -#define GMOCK_INTERNAL_MOCK_METHODN(constness, ct, Method, args_num, ...) \ - GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \ - args_num, ::testing::internal::identity_t<__VA_ARGS__>); \ - GMOCK_INTERNAL_MOCK_METHOD_IMPL( \ - args_num, Method, GMOCK_PP_NARG0(constness), 0, 0, , ct, , \ - (::testing::internal::identity_t<__VA_ARGS__>)) - -#define GMOCK_MOCKER_(arity, constness, Method) \ - GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__) - -#endif // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ diff --git a/vendor/googletest/gtest/googlemock/include/gmock/gmock-matchers.h b/vendor/googletest/gtest/googlemock/include/gmock/gmock-matchers.h deleted file mode 100644 index eec5044f..00000000 --- a/vendor/googletest/gtest/googlemock/include/gmock/gmock-matchers.h +++ /dev/null @@ -1,5392 +0,0 @@ -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// Google Mock - a framework for writing C++ mock classes. -// -// The MATCHER* family of macros can be used in a namespace scope to -// define custom matchers easily. -// -// Basic Usage -// =========== -// -// The syntax -// -// MATCHER(name, description_string) { statements; } -// -// defines a matcher with the given name that executes the statements, -// which must return a bool to indicate if the match succeeds. Inside -// the statements, you can refer to the value being matched by 'arg', -// and refer to its type by 'arg_type'. -// -// The description string documents what the matcher does, and is used -// to generate the failure message when the match fails. Since a -// MATCHER() is usually defined in a header file shared by multiple -// C++ source files, we require the description to be a C-string -// literal to avoid possible side effects. It can be empty, in which -// case we'll use the sequence of words in the matcher name as the -// description. -// -// For example: -// -// MATCHER(IsEven, "") { return (arg % 2) == 0; } -// -// allows you to write -// -// // Expects mock_foo.Bar(n) to be called where n is even. -// EXPECT_CALL(mock_foo, Bar(IsEven())); -// -// or, -// -// // Verifies that the value of some_expression is even. -// EXPECT_THAT(some_expression, IsEven()); -// -// If the above assertion fails, it will print something like: -// -// Value of: some_expression -// Expected: is even -// Actual: 7 -// -// where the description "is even" is automatically calculated from the -// matcher name IsEven. -// -// Argument Type -// ============= -// -// Note that the type of the value being matched (arg_type) is -// determined by the context in which you use the matcher and is -// supplied to you by the compiler, so you don't need to worry about -// declaring it (nor can you). This allows the matcher to be -// polymorphic. For example, IsEven() can be used to match any type -// where the value of "(arg % 2) == 0" can be implicitly converted to -// a bool. In the "Bar(IsEven())" example above, if method Bar() -// takes an int, 'arg_type' will be int; if it takes an unsigned long, -// 'arg_type' will be unsigned long; and so on. -// -// Parameterizing Matchers -// ======================= -// -// Sometimes you'll want to parameterize the matcher. For that you -// can use another macro: -// -// MATCHER_P(name, param_name, description_string) { statements; } -// -// For example: -// -// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; } -// -// will allow you to write: -// -// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n)); -// -// which may lead to this message (assuming n is 10): -// -// Value of: Blah("a") -// Expected: has absolute value 10 -// Actual: -9 -// -// Note that both the matcher description and its parameter are -// printed, making the message human-friendly. -// -// In the matcher definition body, you can write 'foo_type' to -// reference the type of a parameter named 'foo'. For example, in the -// body of MATCHER_P(HasAbsoluteValue, value) above, you can write -// 'value_type' to refer to the type of 'value'. -// -// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to -// support multi-parameter matchers. -// -// Describing Parameterized Matchers -// ================================= -// -// The last argument to MATCHER*() is a string-typed expression. The -// expression can reference all of the matcher's parameters and a -// special bool-typed variable named 'negation'. When 'negation' is -// false, the expression should evaluate to the matcher's description; -// otherwise it should evaluate to the description of the negation of -// the matcher. For example, -// -// using testing::PrintToString; -// -// MATCHER_P2(InClosedRange, low, hi, -// std::string(negation ? "is not" : "is") + " in range [" + -// PrintToString(low) + ", " + PrintToString(hi) + "]") { -// return low <= arg && arg <= hi; -// } -// ... -// EXPECT_THAT(3, InClosedRange(4, 6)); -// EXPECT_THAT(3, Not(InClosedRange(2, 4))); -// -// would generate two failures that contain the text: -// -// Expected: is in range [4, 6] -// ... -// Expected: is not in range [2, 4] -// -// If you specify "" as the description, the failure message will -// contain the sequence of words in the matcher name followed by the -// parameter values printed as a tuple. For example, -// -// MATCHER_P2(InClosedRange, low, hi, "") { ... } -// ... -// EXPECT_THAT(3, InClosedRange(4, 6)); -// EXPECT_THAT(3, Not(InClosedRange(2, 4))); -// -// would generate two failures that contain the text: -// -// Expected: in closed range (4, 6) -// ... -// Expected: not (in closed range (2, 4)) -// -// Types of Matcher Parameters -// =========================== -// -// For the purpose of typing, you can view -// -// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... } -// -// as shorthand for -// -// template -// FooMatcherPk -// Foo(p1_type p1, ..., pk_type pk) { ... } -// -// When you write Foo(v1, ..., vk), the compiler infers the types of -// the parameters v1, ..., and vk for you. If you are not happy with -// the result of the type inference, you can specify the types by -// explicitly instantiating the template, as in Foo(5, -// false). As said earlier, you don't get to (or need to) specify -// 'arg_type' as that's determined by the context in which the matcher -// is used. You can assign the result of expression Foo(p1, ..., pk) -// to a variable of type FooMatcherPk. This -// can be useful when composing matchers. -// -// While you can instantiate a matcher template with reference types, -// passing the parameters by pointer usually makes your code more -// readable. If, however, you still want to pass a parameter by -// reference, be aware that in the failure message generated by the -// matcher you will see the value of the referenced object but not its -// address. -// -// Explaining Match Results -// ======================== -// -// Sometimes the matcher description alone isn't enough to explain why -// the match has failed or succeeded. For example, when expecting a -// long string, it can be very helpful to also print the diff between -// the expected string and the actual one. To achieve that, you can -// optionally stream additional information to a special variable -// named result_listener, whose type is a pointer to class -// MatchResultListener: -// -// MATCHER_P(EqualsLongString, str, "") { -// if (arg == str) return true; -// -// *result_listener << "the difference: " -/// << DiffStrings(str, arg); -// return false; -// } -// -// Overloading Matchers -// ==================== -// -// You can overload matchers with different numbers of parameters: -// -// MATCHER_P(Blah, a, description_string1) { ... } -// MATCHER_P2(Blah, a, b, description_string2) { ... } -// -// Caveats -// ======= -// -// When defining a new matcher, you should also consider implementing -// MatcherInterface or using MakePolymorphicMatcher(). These -// approaches require more work than the MATCHER* macros, but also -// give you more control on the types of the value being matched and -// the matcher parameters, which may leads to better compiler error -// messages when the matcher is used wrong. They also allow -// overloading matchers based on parameter types (as opposed to just -// based on the number of parameters). -// -// MATCHER*() can only be used in a namespace scope as templates cannot be -// declared inside of a local class. -// -// More Information -// ================ -// -// To learn more about using these macros, please search for 'MATCHER' -// on -// https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md -// -// This file also implements some commonly used argument matchers. More -// matchers can be defined by the user implementing the -// MatcherInterface interface if necessary. -// -// See googletest/include/gtest/gtest-matchers.h for the definition of class -// Matcher, class MatcherInterface, and others. - -// GOOGLETEST_CM0002 DO NOT DELETE - -#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ -#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ - -#include -#include -#include -#include -#include -#include -#include // NOLINT -#include -#include -#include -#include -#include - -#include "gmock/internal/gmock-internal-utils.h" -#include "gmock/internal/gmock-port.h" -#include "gmock/internal/gmock-pp.h" -#include "gtest/gtest.h" - -// MSVC warning C5046 is new as of VS2017 version 15.8. -#if defined(_MSC_VER) && _MSC_VER >= 1915 -#define GMOCK_MAYBE_5046_ 5046 -#else -#define GMOCK_MAYBE_5046_ -#endif - -GTEST_DISABLE_MSC_WARNINGS_PUSH_( - 4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by - clients of class B */ - /* Symbol involving type with internal linkage not defined */) - -namespace testing { - -// To implement a matcher Foo for type T, define: -// 1. a class FooMatcherImpl that implements the -// MatcherInterface interface, and -// 2. a factory function that creates a Matcher object from a -// FooMatcherImpl*. -// -// The two-level delegation design makes it possible to allow a user -// to write "v" instead of "Eq(v)" where a Matcher is expected, which -// is impossible if we pass matchers by pointers. It also eases -// ownership management as Matcher objects can now be copied like -// plain values. - -// A match result listener that stores the explanation in a string. -class StringMatchResultListener : public MatchResultListener { - public: - StringMatchResultListener() : MatchResultListener(&ss_) {} - - // Returns the explanation accumulated so far. - std::string str() const { return ss_.str(); } - - // Clears the explanation accumulated so far. - void Clear() { ss_.str(""); } - - private: - ::std::stringstream ss_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(StringMatchResultListener); -}; - -// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION -// and MUST NOT BE USED IN USER CODE!!! -namespace internal { - -// The MatcherCastImpl class template is a helper for implementing -// MatcherCast(). We need this helper in order to partially -// specialize the implementation of MatcherCast() (C++ allows -// class/struct templates to be partially specialized, but not -// function templates.). - -// This general version is used when MatcherCast()'s argument is a -// polymorphic matcher (i.e. something that can be converted to a -// Matcher but is not one yet; for example, Eq(value)) or a value (for -// example, "hello"). -template -class MatcherCastImpl { - public: - static Matcher Cast(const M& polymorphic_matcher_or_value) { - // M can be a polymorphic matcher, in which case we want to use - // its conversion operator to create Matcher. Or it can be a value - // that should be passed to the Matcher's constructor. - // - // We can't call Matcher(polymorphic_matcher_or_value) when M is a - // polymorphic matcher because it'll be ambiguous if T has an implicit - // constructor from M (this usually happens when T has an implicit - // constructor from any type). - // - // It won't work to unconditionally implict_cast - // polymorphic_matcher_or_value to Matcher because it won't trigger - // a user-defined conversion from M to T if one exists (assuming M is - // a value). - return CastImpl(polymorphic_matcher_or_value, - std::is_convertible>{}, - std::is_convertible{}); - } - - private: - template - static Matcher CastImpl(const M& polymorphic_matcher_or_value, - std::true_type /* convertible_to_matcher */, - std::integral_constant) { - // M is implicitly convertible to Matcher, which means that either - // M is a polymorphic matcher or Matcher has an implicit constructor - // from M. In both cases using the implicit conversion will produce a - // matcher. - // - // Even if T has an implicit constructor from M, it won't be called because - // creating Matcher would require a chain of two user-defined conversions - // (first to create T from M and then to create Matcher from T). - return polymorphic_matcher_or_value; - } - - // M can't be implicitly converted to Matcher, so M isn't a polymorphic - // matcher. It's a value of a type implicitly convertible to T. Use direct - // initialization to create a matcher. - static Matcher CastImpl(const M& value, - std::false_type /* convertible_to_matcher */, - std::true_type /* convertible_to_T */) { - return Matcher(ImplicitCast_(value)); - } - - // M can't be implicitly converted to either Matcher or T. Attempt to use - // polymorphic matcher Eq(value) in this case. - // - // Note that we first attempt to perform an implicit cast on the value and - // only fall back to the polymorphic Eq() matcher afterwards because the - // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end - // which might be undefined even when Rhs is implicitly convertible to Lhs - // (e.g. std::pair vs. std::pair). - // - // We don't define this method inline as we need the declaration of Eq(). - static Matcher CastImpl(const M& value, - std::false_type /* convertible_to_matcher */, - std::false_type /* convertible_to_T */); -}; - -// This more specialized version is used when MatcherCast()'s argument -// is already a Matcher. This only compiles when type T can be -// statically converted to type U. -template -class MatcherCastImpl > { - public: - static Matcher Cast(const Matcher& source_matcher) { - return Matcher(new Impl(source_matcher)); - } - - private: - class Impl : public MatcherInterface { - public: - explicit Impl(const Matcher& source_matcher) - : source_matcher_(source_matcher) {} - - // We delegate the matching logic to the source matcher. - bool MatchAndExplain(T x, MatchResultListener* listener) const override { - using FromType = typename std::remove_cv::type>::type>::type; - using ToType = typename std::remove_cv::type>::type>::type; - // Do not allow implicitly converting base*/& to derived*/&. - static_assert( - // Do not trigger if only one of them is a pointer. That implies a - // regular conversion and not a down_cast. - (std::is_pointer::type>::value != - std::is_pointer::type>::value) || - std::is_same::value || - !std::is_base_of::value, - "Can't implicitly convert from to "); - - // Do the cast to `U` explicitly if necessary. - // Otherwise, let implicit conversions do the trick. - using CastType = - typename std::conditional::value, - T&, U>::type; - - return source_matcher_.MatchAndExplain(static_cast(x), - listener); - } - - void DescribeTo(::std::ostream* os) const override { - source_matcher_.DescribeTo(os); - } - - void DescribeNegationTo(::std::ostream* os) const override { - source_matcher_.DescribeNegationTo(os); - } - - private: - const Matcher source_matcher_; - }; -}; - -// This even more specialized version is used for efficiently casting -// a matcher to its own type. -template -class MatcherCastImpl > { - public: - static Matcher Cast(const Matcher& matcher) { return matcher; } -}; - -// Template specialization for parameterless Matcher. -template -class MatcherBaseImpl { - public: - MatcherBaseImpl() = default; - - template - operator ::testing::Matcher() const { // NOLINT(runtime/explicit) - return ::testing::Matcher(new - typename Derived::template gmock_Impl()); - } -}; - -// Template specialization for Matcher with parameters. -template