From 4046e019ca6be35b583820df5c3f49e284259319 Mon Sep 17 00:00:00 2001 From: Jade Lovelace Date: Tue, 17 Sep 2024 18:34:01 -0700 Subject: [PATCH] tests/compression: rewrite This test suite was in desperate need of using the parameterization available with gtest, and was a bunch of useless duplicated code. At least now it's not duplicated code, though it still probably should be more full of property tests. Change-Id: Ia8ccee7ef4f02b2fa40417b79aa8c8f0626ea479 --- tests/unit/libutil/compression.cc | 232 +++++++++++++++++------------- 1 file changed, 132 insertions(+), 100 deletions(-) diff --git a/tests/unit/libutil/compression.cc b/tests/unit/libutil/compression.cc index 3b40db0cd..f629fb0a3 100644 --- a/tests/unit/libutil/compression.cc +++ b/tests/unit/libutil/compression.cc @@ -3,105 +3,137 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * compress / decompress - * --------------------------------------------------------------------------*/ - - TEST(compress, compressWithUnknownMethod) { - ASSERT_THROW(compress("invalid-method", "something-to-compress"), UnknownCompressionMethod); - } - - TEST(compress, noneMethodDoesNothingToTheInput) { - auto o = compress("none", "this-is-a-test"); - - ASSERT_EQ(o, "this-is-a-test"); - } - - TEST(decompress, decompressNoneCompressed) { - auto method = "none"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, str); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressEmptyCompressed) { - // Empty-method decompression used e.g. by S3 store - // (Content-Encoding == ""). - auto method = ""; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, str); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressXzCompressed) { - auto method = "xz"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressBzip2Compressed) { - auto method = "bzip2"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressBrCompressed) { - auto method = "br"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressInvalidInputThrowsCompressionError) { - auto method = "bzip2"; - auto str = "this is a string that does not qualify as valid bzip2 data"; - - ASSERT_THROW(decompress(method, str), CompressionError); - } - - TEST(decompress, veryLongBrotli) { - auto method = "br"; - auto str = std::string(65536, 'a'); - auto o = decompress(method, compress(method, str)); - - // This is just to not print 64k of "a" for most failures - ASSERT_EQ(o.length(), str.length()); - ASSERT_EQ(o, str); - } - - /* ---------------------------------------------------------------------------- - * compression sinks - * --------------------------------------------------------------------------*/ - - TEST(makeCompressionSink, noneSinkDoesNothingToInput) { - StringSink strSink; - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto sink = makeCompressionSink("none", strSink); - (*sink)(inputString); - sink->finish(); - - ASSERT_STREQ(strSink.s.c_str(), inputString); - } - - TEST(makeCompressionSink, compressAndDecompress) { - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - - StringSink strSink; - auto sink = makeCompressionSink("bzip2", strSink); - (*sink)(inputString); - sink->finish(); - - StringSource strSource{strSink.s}; - auto decompressionSource = makeDecompressionSource("bzip2", strSource); - - ASSERT_STREQ(decompressionSource->drain().c_str(), inputString); - } +/* ---------------------------------------------------------------------------- + * compress / decompress + * --------------------------------------------------------------------------*/ +TEST(compress, compressWithUnknownMethod) +{ + ASSERT_THROW(compress("invalid-method", "something-to-compress"), UnknownCompressionMethod); +} + +TEST(compress, noneMethodDoesNothingToTheInput) +{ + auto o = compress("none", "this-is-a-test"); + + ASSERT_EQ(o, "this-is-a-test"); +} + +TEST(decompress, decompressEmptyString) +{ + // Empty-method decompression used e.g. by S3 store + // (Content-Encoding == ""). + auto o = decompress("", "this-is-a-test"); + + ASSERT_EQ(o, "this-is-a-test"); +} + +/* ---------------------------------------------------------------------------- + * compression sinks + * --------------------------------------------------------------------------*/ + +TEST(makeCompressionSink, noneSinkDoesNothingToInput) +{ + auto method = "none"; + StringSink strSink; + auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto sink = makeCompressionSink(method, strSink); + (*sink)(inputString); + sink->finish(); + + ASSERT_STREQ(strSink.s.c_str(), inputString); +} + +/** Tests applied to all compression types */ +class PerTypeCompressionTest : public testing::TestWithParam +{}; + +/** Tests applied to non-passthrough compression types */ +class PerTypeNonNullCompressionTest : public testing::TestWithParam +{}; + +constexpr const char * COMPRESSION_TYPES_NONNULL[] = { + // libarchive + "bzip2", + "compress", + "gzip", + "lzip", + "lzma", + "xz", + "zstd", + // Uses external program via libarchive so cannot be used :( + /* + "grzip", + "lrzip", + "lzop", + "lz4", + */ + // custom + "br", +}; + +INSTANTIATE_TEST_SUITE_P( + compressionNonNull, PerTypeNonNullCompressionTest, testing::ValuesIn(COMPRESSION_TYPES_NONNULL) +); +INSTANTIATE_TEST_SUITE_P( + compressionNonNull, PerTypeCompressionTest, testing::ValuesIn(COMPRESSION_TYPES_NONNULL) +); + +INSTANTIATE_TEST_SUITE_P( + compressionNull, PerTypeCompressionTest, testing::Values("none") +); + +/* --------------------------------------- + * All compression types + * --------------------------------------- */ + +TEST_P(PerTypeCompressionTest, roundTrips) +{ + auto method = GetParam(); + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto o = decompress(method, compress(method, str)); + + ASSERT_EQ(o, str); +} + +TEST_P(PerTypeCompressionTest, longerThanBuffer) +{ + // This is targeted originally at regression testing a brotli bug, but we might as well do it to + // everything + auto method = GetParam(); + auto str = std::string(65536, 'a'); + auto o = decompress(method, compress(method, str)); + + // This is just to not print 64k of "a" for most failures + ASSERT_EQ(o.length(), str.length()); + ASSERT_EQ(o, str); +} + +TEST_P(PerTypeCompressionTest, sinkAndSource) +{ + auto method = GetParam(); + auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + + StringSink strSink; + auto sink = makeCompressionSink(method, strSink); + (*sink)(inputString); + sink->finish(); + + StringSource strSource{strSink.s}; + auto decompressionSource = makeDecompressionSource(method, strSource); + + ASSERT_STREQ(decompressionSource->drain().c_str(), inputString); +} + +/* --------------------------------------- + * Non null compression types + * --------------------------------------- */ + +TEST_P(PerTypeNonNullCompressionTest, bogusInputDecompression) +{ + auto param = GetParam(); + + auto bogus = "this data is bogus and should throw when decompressing"; + ASSERT_THROW(decompress(param, bogus), CompressionError); +} }