diff options
Diffstat (limited to 'tests/unit/libutil/compression.cc')
-rw-r--r-- | tests/unit/libutil/compression.cc | 218 |
1 files changed, 137 insertions, 81 deletions
diff --git a/tests/unit/libutil/compression.cc b/tests/unit/libutil/compression.cc index 3b40db0cd..8d181f53d 100644 --- a/tests/unit/libutil/compression.cc +++ b/tests/unit/libutil/compression.cc @@ -3,105 +3,161 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * compress / decompress - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * 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(compress, compressWithUnknownMethod) +{ + ASSERT_THROW(compress("invalid-method", "something-to-compress"), UnknownCompressionMethod); +} - TEST(decompress, decompressXzCompressed) { - auto method = "xz"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); +TEST(compress, noneMethodDoesNothingToTheInput) +{ + auto o = compress("none", "this-is-a-test"); - ASSERT_EQ(o, str); - } + ASSERT_EQ(o, "this-is-a-test"); +} - TEST(decompress, decompressBzip2Compressed) { - auto method = "bzip2"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); +TEST(decompress, decompressEmptyString) +{ + // Empty-method decompression used e.g. by S3 store + // (Content-Encoding == ""). + auto o = decompress("", "this-is-a-test"); - ASSERT_EQ(o, str); - } + ASSERT_EQ(o, "this-is-a-test"); +} - TEST(decompress, decompressBrCompressed) { - auto method = "br"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); +/* ---------------------------------------------------------------------------- + * compression sinks + * --------------------------------------------------------------------------*/ - ASSERT_EQ(o, str); - } +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(); - TEST(decompress, decompressInvalidInputThrowsCompressionError) { - auto method = "bzip2"; - auto str = "this is a string that does not qualify as valid bzip2 data"; + ASSERT_STREQ(strSink.s.c_str(), inputString); +} - ASSERT_THROW(decompress(method, str), CompressionError); - } +/** Tests applied to all compression types */ +class PerTypeCompressionTest : public testing::TestWithParam<const char *> +{}; + +/** Tests applied to non-passthrough compression types */ +class PerTypeNonNullCompressionTest : public testing::TestWithParam<const char *> +{}; + +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(decompress, veryLongBrotli) { - auto method = "br"; - auto str = std::string(65536, 'a'); - auto o = decompress(method, compress(method, 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); +} - // 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"; - /* ---------------------------------------------------------------------------- - * compression sinks - * --------------------------------------------------------------------------*/ + StringSink strSink; + auto sink = makeCompressionSink(method, strSink); + (*sink)(inputString); + sink->finish(); - TEST(makeCompressionSink, noneSinkDoesNothingToInput) { - StringSink strSink; - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto sink = makeCompressionSink("none", strSink); - (*sink)(inputString); - sink->finish(); + StringSource strSource{strSink.s}; + auto decompressionSource = makeDecompressionSource(method, strSource); - ASSERT_STREQ(strSink.s.c_str(), inputString); - } + ASSERT_STREQ(decompressionSource->drain().c_str(), inputString); +} - TEST(makeCompressionSink, compressAndDecompress) { - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; +/* --------------------------------------- + * Non null compression types + * --------------------------------------- */ - StringSink strSink; - auto sink = makeCompressionSink("bzip2", strSink); - (*sink)(inputString); - sink->finish(); +TEST_P(PerTypeNonNullCompressionTest, bogusInputDecompression) +{ + auto param = GetParam(); - StringSource strSource{strSink.s}; - auto decompressionSource = makeDecompressionSource("bzip2", strSource); + auto bogus = "this data is bogus and should throw when decompressing"; + ASSERT_THROW(decompress(param, bogus), CompressionError); +} - ASSERT_STREQ(decompressionSource->drain().c_str(), inputString); +TEST_P(PerTypeNonNullCompressionTest, truncatedValidInput) +{ + auto method = GetParam(); + + auto inputString = "the quick brown fox jumps over the lazy doggos"; + auto compressed = compress(method, inputString); + + /* n.b. This also tests zero-length input, which is also invalid. + * As of the writing of this comment, it returns empty output, but is + * allowed to throw a compression error instead. */ + for (int i = 0; i < compressed.length(); ++i) { + auto newCompressed = compressed.substr(compressed.length() - i); + try { + decompress(method, newCompressed); + // Success is acceptable as well, even though it is corrupt data. + // The compression method is not expected to provide integrity, + // just, not break explosively on bad input. + } catch (CompressionError &) { + // Acceptable + } } +} } |