aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/libutil/compression.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/libutil/compression.cc')
-rw-r--r--tests/unit/libutil/compression.cc218
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
+ }
}
+}
}