aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/functional/build.sh13
-rw-r--r--tests/functional/fetchGit.sh45
-rw-r--r--tests/nixos/default.nix2
-rw-r--r--tests/nixos/fetchurl.nix84
-rw-r--r--tests/unit/libmain/crash.cc56
-rw-r--r--tests/unit/libutil/async-collect.cc104
-rw-r--r--tests/unit/libutil/async-semaphore.cc74
-rw-r--r--tests/unit/libutil/compression.cc218
-rw-r--r--tests/unit/meson.build10
9 files changed, 516 insertions, 90 deletions
diff --git a/tests/functional/build.sh b/tests/functional/build.sh
index 356985a64..a14f6e3c2 100644
--- a/tests/functional/build.sh
+++ b/tests/functional/build.sh
@@ -146,11 +146,8 @@ out="$(nix build -f fod-failing.nix -L 2>&1)" && status=0 || status=$?
test "$status" = 1
# one "hash mismatch" error, one "build of ... failed"
test "$(<<<"$out" grep -E '^error:' | wc -l)" = 2
-<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x1\\.drv'"
-<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x3\\.drv'"
-<<<"$out" grepQuiet -vE "hash mismatch in fixed-output derivation '.*-x2\\.drv'"
-<<<"$out" grepQuiet -E "likely URL: https://meow.puppy.forge/puppy.tar.gz"
-<<<"$out" grepQuiet -vE "likely URL: https://kitty.forge/cat.tar.gz"
+<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x.\\.drv'"
+<<<"$out" grepQuiet -E "likely URL: "
<<<"$out" grepQuiet -E "error: build of '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out', '.*-x[1-4]\\.drv\\^out' failed"
out="$(nix build -f fod-failing.nix -L x1 x2 x3 --keep-going 2>&1)" && status=0 || status=$?
@@ -167,9 +164,9 @@ test "$(<<<"$out" grep -E '^error:' | wc -l)" = 4
out="$(nix build -f fod-failing.nix -L x4 2>&1)" && status=0 || status=$?
test "$status" = 1
-test "$(<<<"$out" grep -E '^error:' | wc -l)" = 2
-<<<"$out" grepQuiet -E "error: 1 dependencies of derivation '.*-x4\\.drv' failed to build"
-<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x2\\.drv'"
+test "$(<<<"$out" grep -E '^error:' | wc -l)" -ge 2
+<<<"$out" grepQuiet -E "error: [12] dependencies of derivation '.*-x4\\.drv' failed to build"
+<<<"$out" grepQuiet -E "hash mismatch in fixed-output derivation '.*-x[23]\\.drv'"
out="$(nix build -f fod-failing.nix -L x4 --keep-going 2>&1)" && status=0 || status=$?
test "$status" = 1
diff --git a/tests/functional/fetchGit.sh b/tests/functional/fetchGit.sh
index 2c00facc2..492c57602 100644
--- a/tests/functional/fetchGit.sh
+++ b/tests/functional/fetchGit.sh
@@ -53,8 +53,17 @@ out=$(nix eval --impure --raw --expr "builtins.fetchGit { url = \"file://$repo\"
[[ $status == 1 ]]
[[ $out =~ 'Cannot find Git revision' ]]
+# allow revs as refs (for 2.3 compat)
[[ $(nix eval --raw --expr "builtins.readFile (builtins.fetchGit { url = \"file://$repo\"; rev = \"$devrev\"; allRefs = true; } + \"/differentbranch\")") = 'different file' ]]
+rm -rf "$TEST_ROOT/test-home"
+[[ $(nix eval --raw --expr "builtins.readFile (builtins.fetchGit { url = \"file://$repo\"; rev = \"$devrev\"; allRefs = true; } + \"/differentbranch\")") = 'different file' ]]
+
+rm -rf "$TEST_ROOT/test-home"
+out=$(nix eval --raw --expr "builtins.readFile (builtins.fetchGit { url = \"file://$repo\"; rev = \"$devrev\"; ref = \"lolkek\"; } + \"/differentbranch\")" 2>&1) || status=$?
+[[ $status == 1 ]]
+[[ $out =~ 'Cannot find Git revision' ]]
+
# In pure eval mode, fetchGit without a revision should fail.
[[ $(nix eval --impure --raw --expr "builtins.readFile (fetchGit \"file://$repo\" + \"/hello\")") = world ]]
(! nix eval --raw --expr "builtins.readFile (fetchGit \"file://$repo\" + \"/hello\")")
@@ -228,6 +237,12 @@ export _NIX_FORCE_HTTP=1
rev_tag1_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag1\"; }).rev")
rev_tag1=$(git -C $repo rev-parse refs/tags/tag1)
[[ $rev_tag1_nix = $rev_tag1 ]]
+
+# Allow fetching tags w/o specifying refs/tags
+rm -rf "$TEST_ROOT/test-home"
+rev_tag1_nix_alt=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"tag1\"; }).rev")
+[[ $rev_tag1_nix_alt = $rev_tag1 ]]
+
rev_tag2_nix=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/tag2\"; }).rev")
rev_tag2=$(git -C $repo rev-parse refs/tags/tag2)
[[ $rev_tag2_nix = $rev_tag2 ]]
@@ -254,3 +269,33 @@ git -C "$repo" add hello .gitignore
git -C "$repo" commit -m 'Bla1'
cd "$repo"
path11=$(nix eval --impure --raw --expr "(builtins.fetchGit ./.).outPath")
+
+# test behavior if both branch and tag with same name exist
+repo="$TEST_ROOT/git"
+rm -rf "$repo"/.git
+git init "$repo"
+git -C "$repo" config user.email "foobar@example.com"
+git -C "$repo" config user.name "Foobar"
+
+touch "$repo"/test
+echo "hello world" > "$repo"/test
+git -C "$repo" checkout -b branch
+git -C "$repo" add test
+
+git -C "$repo" commit -m "Init"
+
+git -C "$repo" tag branch
+
+echo "goodbye world" > "$repo"/test
+git -C "$repo" add test
+git -C "$repo" commit -m "Update test"
+
+path12=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"branch\"; }).outPath")
+[[ "$(cat "$path12"/test)" =~ 'hello world' ]]
+[[ "$(cat "$repo"/test)" =~ 'goodbye world' ]]
+
+path13=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/heads/branch\"; }).outPath")
+[[ "$(cat "$path13"/test)" =~ 'goodbye world' ]]
+
+path14=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; ref = \"refs/tags/branch\"; }).outPath")
+[[ "$path14" = "$path12" ]]
diff --git a/tests/nixos/default.nix b/tests/nixos/default.nix
index 20e66f6c1..2d6eaed16 100644
--- a/tests/nixos/default.nix
+++ b/tests/nixos/default.nix
@@ -157,4 +157,6 @@ in
coredumps = runNixOSTestFor "x86_64-linux" ./coredumps;
io_uring = runNixOSTestFor "x86_64-linux" ./io_uring;
+
+ fetchurl = runNixOSTestFor "x86_64-linux" ./fetchurl.nix;
}
diff --git a/tests/nixos/fetchurl.nix b/tests/nixos/fetchurl.nix
new file mode 100644
index 000000000..97365d053
--- /dev/null
+++ b/tests/nixos/fetchurl.nix
@@ -0,0 +1,84 @@
+# Test whether builtin:fetchurl properly performs TLS certificate
+# checks on HTTPS servers.
+
+{ lib, config, pkgs, ... }:
+
+let
+
+ makeTlsCert = name: pkgs.runCommand name {
+ nativeBuildInputs = with pkgs; [ openssl ];
+ } ''
+ mkdir -p $out
+ openssl req -x509 \
+ -subj '/CN=${name}/' -days 49710 \
+ -addext 'subjectAltName = DNS:${name}' \
+ -keyout "$out/key.pem" -newkey ed25519 \
+ -out "$out/cert.pem" -noenc
+ '';
+
+ goodCert = makeTlsCert "good";
+ badCert = makeTlsCert "bad";
+
+in
+
+{
+ name = "fetchurl";
+
+ nodes = {
+ machine = { lib, pkgs, ... }: {
+ services.nginx = {
+ enable = true;
+
+ virtualHosts."good" = {
+ addSSL = true;
+ sslCertificate = "${goodCert}/cert.pem";
+ sslCertificateKey = "${goodCert}/key.pem";
+ root = pkgs.runCommand "nginx-root" {} ''
+ mkdir "$out"
+ echo 'hello world' > "$out/index.html"
+ '';
+ };
+
+ virtualHosts."bad" = {
+ addSSL = true;
+ sslCertificate = "${badCert}/cert.pem";
+ sslCertificateKey = "${badCert}/key.pem";
+ root = pkgs.runCommand "nginx-root" {} ''
+ mkdir "$out"
+ echo 'foobar' > "$out/index.html"
+ '';
+ };
+ };
+
+ security.pki.certificateFiles = [ "${goodCert}/cert.pem" ];
+
+ networking.hosts."127.0.0.1" = [ "good" "bad" ];
+
+ virtualisation.writableStore = true;
+
+ nix.settings.experimental-features = "nix-command";
+ };
+ };
+
+ testScript = { nodes, ... }: ''
+ machine.wait_for_unit("nginx")
+ machine.wait_for_open_port(443)
+
+ out = machine.succeed("curl https://good/index.html")
+ assert out == "hello world\n"
+
+ out = machine.succeed("cat ${badCert}/cert.pem > /tmp/cafile.pem; curl --cacert /tmp/cafile.pem https://bad/index.html")
+ assert out == "foobar\n"
+
+ # Fetching from a server with a trusted cert should work.
+ machine.succeed("nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://good/index.html\"; hash = \"sha256-qUiQTy8PR5uPgZdpSzAYSw0u0cHNKh7A+4XSmaGSpEc=\"; }'")
+
+ # Fetching from a server with an untrusted cert should fail.
+ err = machine.fail("nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://bad/index.html\"; hash = \"sha256-rsBwZF/lPuOzdjBZN2E08FjMM3JHyXit0Xi2zN+wAZ8=\"; }' 2>&1")
+ print(err)
+ assert "SSL certificate problem: self-signed certificate" in err or "SSL peer certificate or SSH remote key was not OK" in err
+
+ # Fetching from a server with a trusted cert should work via environment variable override.
+ machine.succeed("NIX_SSL_CERT_FILE=/tmp/cafile.pem nix build --no-substitute --expr 'import <nix/fetchurl.nix> { url = \"https://bad/index.html\"; hash = \"sha256-rsBwZF/lPuOzdjBZN2E08FjMM3JHyXit0Xi2zN+wAZ8=\"; }'")
+ '';
+}
diff --git a/tests/unit/libmain/crash.cc b/tests/unit/libmain/crash.cc
new file mode 100644
index 000000000..883dc39bd
--- /dev/null
+++ b/tests/unit/libmain/crash.cc
@@ -0,0 +1,56 @@
+#include <gtest/gtest.h>
+#include "crash-handler.hh"
+
+namespace nix {
+
+class OopsException : public std::exception
+{
+ const char * msg;
+
+public:
+ OopsException(const char * msg) : msg(msg) {}
+ const char * what() const noexcept override
+ {
+ return msg;
+ }
+};
+
+void causeCrashForTesting(std::function<void()> fixture)
+{
+ registerCrashHandler();
+ std::cerr << "time to crash\n";
+ try {
+ fixture();
+ } catch (...) {
+ std::terminate();
+ }
+}
+
+TEST(CrashHandler, exceptionName)
+{
+ ASSERT_DEATH(
+ causeCrashForTesting([]() { throw OopsException{"lol oops"}; }),
+ "time to crash\nLix crashed.*OopsException: lol oops"
+ );
+}
+
+TEST(CrashHandler, unknownTerminate)
+{
+ ASSERT_DEATH(
+ causeCrashForTesting([]() { std::terminate(); }),
+ "time to crash\nLix crashed.*std::terminate\\(\\) called without exception"
+ );
+}
+
+TEST(CrashHandler, nonStdException)
+{
+ ASSERT_DEATH(
+ causeCrashForTesting([]() {
+ // NOLINTNEXTLINE(hicpp-exception-baseclass): intentional
+ throw 4;
+ }),
+ "time to crash\nLix crashed.*Unknown exception! Spooky\\."
+ );
+}
+
+}
diff --git a/tests/unit/libutil/async-collect.cc b/tests/unit/libutil/async-collect.cc
new file mode 100644
index 000000000..770374d21
--- /dev/null
+++ b/tests/unit/libutil/async-collect.cc
@@ -0,0 +1,104 @@
+#include "async-collect.hh"
+
+#include <gtest/gtest.h>
+#include <kj/array.h>
+#include <kj/async.h>
+#include <kj/exception.h>
+#include <stdexcept>
+
+namespace nix {
+
+TEST(AsyncCollect, void)
+{
+ kj::EventLoop loop;
+ kj::WaitScope waitScope(loop);
+
+ auto a = kj::newPromiseAndFulfiller<void>();
+ auto b = kj::newPromiseAndFulfiller<void>();
+ auto c = kj::newPromiseAndFulfiller<void>();
+ auto d = kj::newPromiseAndFulfiller<void>();
+
+ auto collect = asyncCollect(kj::arr(
+ std::pair(1, std::move(a.promise)),
+ std::pair(2, std::move(b.promise)),
+ std::pair(3, std::move(c.promise)),
+ std::pair(4, std::move(d.promise))
+ ));
+
+ auto p = collect.next();
+ ASSERT_FALSE(p.poll(waitScope));
+
+ // collection is ordered
+ c.fulfiller->fulfill();
+ b.fulfiller->fulfill();
+
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_EQ(p.wait(waitScope), 3);
+
+ p = collect.next();
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_EQ(p.wait(waitScope), 2);
+
+ p = collect.next();
+ ASSERT_FALSE(p.poll(waitScope));
+
+ // exceptions propagate
+ a.fulfiller->rejectIfThrows([] { throw std::runtime_error("test"); });
+
+ p = collect.next();
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_THROW(p.wait(waitScope), kj::Exception);
+
+ // first exception aborts collection
+ p = collect.next();
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_THROW(p.wait(waitScope), kj::Exception);
+}
+
+TEST(AsyncCollect, nonVoid)
+{
+ kj::EventLoop loop;
+ kj::WaitScope waitScope(loop);
+
+ auto a = kj::newPromiseAndFulfiller<int>();
+ auto b = kj::newPromiseAndFulfiller<int>();
+ auto c = kj::newPromiseAndFulfiller<int>();
+ auto d = kj::newPromiseAndFulfiller<int>();
+
+ auto collect = asyncCollect(kj::arr(
+ std::pair(1, std::move(a.promise)),
+ std::pair(2, std::move(b.promise)),
+ std::pair(3, std::move(c.promise)),
+ std::pair(4, std::move(d.promise))
+ ));
+
+ auto p = collect.next();
+ ASSERT_FALSE(p.poll(waitScope));
+
+ // collection is ordered
+ c.fulfiller->fulfill(1);
+ b.fulfiller->fulfill(2);
+
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_EQ(p.wait(waitScope), std::pair(3, 1));
+
+ p = collect.next();
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_EQ(p.wait(waitScope), std::pair(2, 2));
+
+ p = collect.next();
+ ASSERT_FALSE(p.poll(waitScope));
+
+ // exceptions propagate
+ a.fulfiller->rejectIfThrows([] { throw std::runtime_error("test"); });
+
+ p = collect.next();
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_THROW(p.wait(waitScope), kj::Exception);
+
+ // first exception aborts collection
+ p = collect.next();
+ ASSERT_TRUE(p.poll(waitScope));
+ ASSERT_THROW(p.wait(waitScope), kj::Exception);
+}
+}
diff --git a/tests/unit/libutil/async-semaphore.cc b/tests/unit/libutil/async-semaphore.cc
new file mode 100644
index 000000000..12b52885d
--- /dev/null
+++ b/tests/unit/libutil/async-semaphore.cc
@@ -0,0 +1,74 @@
+#include "async-semaphore.hh"
+
+#include <gtest/gtest.h>
+#include <kj/async.h>
+
+namespace nix {
+
+TEST(AsyncSemaphore, counting)
+{
+ kj::EventLoop loop;
+ kj::WaitScope waitScope(loop);
+
+ AsyncSemaphore sem(2);
+
+ ASSERT_EQ(sem.available(), 2);
+ ASSERT_EQ(sem.used(), 0);
+
+ auto a = kj::evalNow([&] { return sem.acquire(); });
+ ASSERT_EQ(sem.available(), 1);
+ ASSERT_EQ(sem.used(), 1);
+ auto b = kj::evalNow([&] { return sem.acquire(); });
+ ASSERT_EQ(sem.available(), 0);
+ ASSERT_EQ(sem.used(), 2);
+
+ auto c = kj::evalNow([&] { return sem.acquire(); });
+ auto d = kj::evalNow([&] { return sem.acquire(); });
+
+ ASSERT_TRUE(a.poll(waitScope));
+ ASSERT_TRUE(b.poll(waitScope));
+ ASSERT_FALSE(c.poll(waitScope));
+ ASSERT_FALSE(d.poll(waitScope));
+
+ a = nullptr;
+ ASSERT_TRUE(c.poll(waitScope));
+ ASSERT_FALSE(d.poll(waitScope));
+
+ {
+ auto lock = b.wait(waitScope);
+ ASSERT_FALSE(d.poll(waitScope));
+ }
+
+ ASSERT_TRUE(d.poll(waitScope));
+
+ ASSERT_EQ(sem.available(), 0);
+ ASSERT_EQ(sem.used(), 2);
+ c = nullptr;
+ ASSERT_EQ(sem.available(), 1);
+ ASSERT_EQ(sem.used(), 1);
+ d = nullptr;
+ ASSERT_EQ(sem.available(), 2);
+ ASSERT_EQ(sem.used(), 0);
+}
+
+TEST(AsyncSemaphore, cancelledWaiter)
+{
+ kj::EventLoop loop;
+ kj::WaitScope waitScope(loop);
+
+ AsyncSemaphore sem(1);
+
+ auto a = kj::evalNow([&] { return sem.acquire(); });
+ auto b = kj::evalNow([&] { return sem.acquire(); });
+ auto c = kj::evalNow([&] { return sem.acquire(); });
+
+ ASSERT_TRUE(a.poll(waitScope));
+ ASSERT_FALSE(b.poll(waitScope));
+
+ b = nullptr;
+ a = nullptr;
+
+ ASSERT_TRUE(c.poll(waitScope));
+}
+
+}
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
+ }
}
+}
}
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 8ff0b5ec5..8b0c66dd8 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -39,6 +39,8 @@ liblixutil_test_support = declare_dependency(
)
libutil_tests_sources = files(
+ 'libutil/async-collect.cc',
+ 'libutil/async-semaphore.cc',
'libutil/canon-path.cc',
'libutil/checked-arithmetic.cc',
'libutil/chunked-vector.cc',
@@ -76,6 +78,7 @@ libutil_tester = executable(
liblixexpr_mstatic,
liblixutil_test_support,
nlohmann_json,
+ kj,
],
cpp_pch : cpp_pch,
)
@@ -262,9 +265,14 @@ test(
protocol : 'gtest',
)
+libmain_tests_sources = files(
+ 'libmain/crash.cc',
+ 'libmain/progress-bar.cc',
+)
+
libmain_tester = executable(
'liblixmain-tests',
- files('libmain/progress-bar.cc'),
+ libmain_tests_sources,
dependencies : [
liblixmain,
liblixexpr,