1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-11 13:06:01 +01:00

Apply clang-format universally.

* It is tough to contribute to a project that doesn't use a formatter,
* It is extra hard to contribute to a project which has configured the formatter, but ignores it for some files
* Code formatting makes it harder to hide obscure / weird bugs by accident or on purpose,

Let's rip the bandaid off?

Note that PRs currently in flight should be able to be merged relatively easily by applying `clang-format` to their tip prior to merge.
This commit is contained in:
Graham Christensen 2025-07-18 12:47:27 -04:00
parent 41bf87ec70
commit e4f62e4608
587 changed files with 23258 additions and 23135 deletions

View file

@ -7,97 +7,110 @@
namespace nix {
TEST(parseShebangContent, basic) {
std::list<std::string> r = parseShebangContent("hi there");
ASSERT_EQ(r.size(), 2u);
auto i = r.begin();
ASSERT_EQ(*i++, "hi");
ASSERT_EQ(*i++, "there");
}
TEST(parseShebangContent, basic)
{
std::list<std::string> r = parseShebangContent("hi there");
ASSERT_EQ(r.size(), 2u);
auto i = r.begin();
ASSERT_EQ(*i++, "hi");
ASSERT_EQ(*i++, "there");
}
TEST(parseShebangContent, empty) {
std::list<std::string> r = parseShebangContent("");
ASSERT_EQ(r.size(), 0u);
}
TEST(parseShebangContent, empty)
{
std::list<std::string> r = parseShebangContent("");
ASSERT_EQ(r.size(), 0u);
}
TEST(parseShebangContent, doubleBacktick) {
std::list<std::string> r = parseShebangContent("``\"ain't that nice\"``");
ASSERT_EQ(r.size(), 1u);
auto i = r.begin();
ASSERT_EQ(*i++, "\"ain't that nice\"");
}
TEST(parseShebangContent, doubleBacktick)
{
std::list<std::string> r = parseShebangContent("``\"ain't that nice\"``");
ASSERT_EQ(r.size(), 1u);
auto i = r.begin();
ASSERT_EQ(*i++, "\"ain't that nice\"");
}
TEST(parseShebangContent, doubleBacktickEmpty) {
std::list<std::string> r = parseShebangContent("````");
ASSERT_EQ(r.size(), 1u);
auto i = r.begin();
ASSERT_EQ(*i++, "");
}
TEST(parseShebangContent, doubleBacktickEmpty)
{
std::list<std::string> r = parseShebangContent("````");
ASSERT_EQ(r.size(), 1u);
auto i = r.begin();
ASSERT_EQ(*i++, "");
}
TEST(parseShebangContent, doubleBacktickMarkdownInlineCode) {
std::list<std::string> r = parseShebangContent("``# I'm markdown section about `coolFunction` ``");
ASSERT_EQ(r.size(), 1u);
auto i = r.begin();
ASSERT_EQ(*i++, "# I'm markdown section about `coolFunction`");
}
TEST(parseShebangContent, doubleBacktickMarkdownInlineCode)
{
std::list<std::string> r = parseShebangContent("``# I'm markdown section about `coolFunction` ``");
ASSERT_EQ(r.size(), 1u);
auto i = r.begin();
ASSERT_EQ(*i++, "# I'm markdown section about `coolFunction`");
}
TEST(parseShebangContent, doubleBacktickMarkdownCodeBlockNaive) {
std::list<std::string> r = parseShebangContent("``Example 1\n```nix\na: a\n``` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "Example 1\n``nix\na: a\n``");
}
TEST(parseShebangContent, doubleBacktickMarkdownCodeBlockNaive)
{
std::list<std::string> r = parseShebangContent("``Example 1\n```nix\na: a\n``` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "Example 1\n``nix\na: a\n``");
}
TEST(parseShebangContent, doubleBacktickMarkdownCodeBlockCorrect) {
std::list<std::string> r = parseShebangContent("``Example 1\n````nix\na: a\n```` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "Example 1\n```nix\na: a\n```");
}
TEST(parseShebangContent, doubleBacktickMarkdownCodeBlockCorrect)
{
std::list<std::string> r = parseShebangContent("``Example 1\n````nix\na: a\n```` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "Example 1\n```nix\na: a\n```");
}
TEST(parseShebangContent, doubleBacktickMarkdownCodeBlock2) {
std::list<std::string> r = parseShebangContent("``Example 1\n````nix\na: a\n````\nExample 2\n````nix\na: a\n```` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "Example 1\n```nix\na: a\n```\nExample 2\n```nix\na: a\n```");
}
TEST(parseShebangContent, doubleBacktickMarkdownCodeBlock2)
{
std::list<std::string> r =
parseShebangContent("``Example 1\n````nix\na: a\n````\nExample 2\n````nix\na: a\n```` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "Example 1\n```nix\na: a\n```\nExample 2\n```nix\na: a\n```");
}
TEST(parseShebangContent, singleBacktickInDoubleBacktickQuotes) {
std::list<std::string> r = parseShebangContent("``` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "`");
}
TEST(parseShebangContent, singleBacktickInDoubleBacktickQuotes)
{
std::list<std::string> r = parseShebangContent("``` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "`");
}
TEST(parseShebangContent, singleBacktickAndSpaceInDoubleBacktickQuotes) {
std::list<std::string> r = parseShebangContent("``` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "` ");
}
TEST(parseShebangContent, singleBacktickAndSpaceInDoubleBacktickQuotes)
{
std::list<std::string> r = parseShebangContent("``` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "` ");
}
TEST(parseShebangContent, doubleBacktickInDoubleBacktickQuotes) {
std::list<std::string> r = parseShebangContent("````` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "``");
}
TEST(parseShebangContent, increasingQuotes) {
std::list<std::string> r = parseShebangContent("```` ``` `` ````` `` `````` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 4u);
ASSERT_EQ(*i++, "");
ASSERT_EQ(*i++, "`");
ASSERT_EQ(*i++, "``");
ASSERT_EQ(*i++, "```");
}
TEST(parseShebangContent, doubleBacktickInDoubleBacktickQuotes)
{
std::list<std::string> r = parseShebangContent("````` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 1u);
ASSERT_EQ(*i++, "``");
}
TEST(parseShebangContent, increasingQuotes)
{
std::list<std::string> r = parseShebangContent("```` ``` `` ````` `` `````` ``");
auto i = r.begin();
ASSERT_EQ(r.size(), 4u);
ASSERT_EQ(*i++, "");
ASSERT_EQ(*i++, "`");
ASSERT_EQ(*i++, "``");
ASSERT_EQ(*i++, "```");
}
#ifndef COVERAGE
// quick and dirty
static inline std::string escape(std::string_view s_) {
static inline std::string escape(std::string_view s_)
{
std::string_view s = s_;
std::string r = "``";
@ -125,11 +138,7 @@ static inline std::string escape(std::string_view s_) {
}
}
if (!r.empty()
&& (
r[r.size() - 1] == '`'
|| r[r.size() - 1] == ' '
)) {
if (!r.empty() && (r[r.size() - 1] == '`' || r[r.size() - 1] == ' ')) {
r += " ";
}
@ -138,10 +147,7 @@ static inline std::string escape(std::string_view s_) {
return r;
};
RC_GTEST_PROP(
parseShebangContent,
prop_round_trip_single,
(const std::string & orig))
RC_GTEST_PROP(parseShebangContent, prop_round_trip_single, (const std::string & orig))
{
auto escaped = escape(orig);
// RC_LOG() << "escaped: <[[" << escaped << "]]>" << std::endl;
@ -150,10 +156,7 @@ RC_GTEST_PROP(
RC_ASSERT(*ss.begin() == orig);
}
RC_GTEST_PROP(
parseShebangContent,
prop_round_trip_two,
(const std::string & one, const std::string & two))
RC_GTEST_PROP(parseShebangContent, prop_round_trip_two, (const std::string & one, const std::string & two))
{
auto ss = parseShebangContent(escape(one) + " " + escape(two));
RC_ASSERT(ss.size() == 2u);
@ -162,7 +165,6 @@ RC_GTEST_PROP(
RC_ASSERT(*i++ == two);
}
#endif
}
} // namespace nix

View file

@ -4,177 +4,189 @@
namespace nix {
TEST(CanonPath, basic) {
{
CanonPath p("/");
ASSERT_EQ(p.abs(), "/");
ASSERT_EQ(p.rel(), "");
ASSERT_EQ(p.baseName(), std::nullopt);
ASSERT_EQ(p.dirOf(), std::nullopt);
ASSERT_FALSE(p.parent());
}
{
CanonPath p("/foo//");
ASSERT_EQ(p.abs(), "/foo");
ASSERT_EQ(p.rel(), "foo");
ASSERT_EQ(*p.baseName(), "foo");
ASSERT_EQ(*p.dirOf(), ""); // FIXME: do we want this?
ASSERT_EQ(p.parent()->abs(), "/");
}
{
CanonPath p("foo/bar");
ASSERT_EQ(p.abs(), "/foo/bar");
ASSERT_EQ(p.rel(), "foo/bar");
ASSERT_EQ(*p.baseName(), "bar");
ASSERT_EQ(*p.dirOf(), "/foo");
ASSERT_EQ(p.parent()->abs(), "/foo");
}
{
CanonPath p("foo//bar/");
ASSERT_EQ(p.abs(), "/foo/bar");
ASSERT_EQ(p.rel(), "foo/bar");
ASSERT_EQ(*p.baseName(), "bar");
ASSERT_EQ(*p.dirOf(), "/foo");
}
}
TEST(CanonPath, from_existing) {
CanonPath p0("foo//bar/");
{
CanonPath p("/baz//quux/", p0);
ASSERT_EQ(p.abs(), "/baz/quux");
ASSERT_EQ(p.rel(), "baz/quux");
ASSERT_EQ(*p.baseName(), "quux");
ASSERT_EQ(*p.dirOf(), "/baz");
}
{
CanonPath p("baz//quux/", p0);
ASSERT_EQ(p.abs(), "/foo/bar/baz/quux");
ASSERT_EQ(p.rel(), "foo/bar/baz/quux");
ASSERT_EQ(*p.baseName(), "quux");
ASSERT_EQ(*p.dirOf(), "/foo/bar/baz");
}
}
TEST(CanonPath, pop) {
CanonPath p("foo/bar/x");
ASSERT_EQ(p.abs(), "/foo/bar/x");
p.pop();
ASSERT_EQ(p.abs(), "/foo/bar");
p.pop();
ASSERT_EQ(p.abs(), "/foo");
p.pop();
TEST(CanonPath, basic)
{
{
CanonPath p("/");
ASSERT_EQ(p.abs(), "/");
ASSERT_EQ(p.rel(), "");
ASSERT_EQ(p.baseName(), std::nullopt);
ASSERT_EQ(p.dirOf(), std::nullopt);
ASSERT_FALSE(p.parent());
}
TEST(CanonPath, removePrefix) {
CanonPath p1("foo/bar");
CanonPath p2("foo/bar/a/b/c");
ASSERT_EQ(p2.removePrefix(p1).abs(), "/a/b/c");
ASSERT_EQ(p1.removePrefix(p1).abs(), "/");
ASSERT_EQ(p1.removePrefix(CanonPath("/")).abs(), "/foo/bar");
{
CanonPath p("/foo//");
ASSERT_EQ(p.abs(), "/foo");
ASSERT_EQ(p.rel(), "foo");
ASSERT_EQ(*p.baseName(), "foo");
ASSERT_EQ(*p.dirOf(), ""); // FIXME: do we want this?
ASSERT_EQ(p.parent()->abs(), "/");
}
TEST(CanonPath, iter) {
{
CanonPath p("a//foo/bar//");
std::vector<std::string_view> ss;
for (auto & c : p) ss.push_back(c);
ASSERT_EQ(ss, std::vector<std::string_view>({"a", "foo", "bar"}));
}
{
CanonPath p("/");
std::vector<std::string_view> ss;
for (auto & c : p) ss.push_back(c);
ASSERT_EQ(ss, std::vector<std::string_view>());
}
{
CanonPath p("foo/bar");
ASSERT_EQ(p.abs(), "/foo/bar");
ASSERT_EQ(p.rel(), "foo/bar");
ASSERT_EQ(*p.baseName(), "bar");
ASSERT_EQ(*p.dirOf(), "/foo");
ASSERT_EQ(p.parent()->abs(), "/foo");
}
TEST(CanonPath, concat) {
{
CanonPath p1("a//foo/bar//");
CanonPath p2("xyzzy/bla");
ASSERT_EQ((p1 / p2).abs(), "/a/foo/bar/xyzzy/bla");
}
{
CanonPath p1("/");
CanonPath p2("/a/b");
ASSERT_EQ((p1 / p2).abs(), "/a/b");
}
{
CanonPath p1("/a/b");
CanonPath p2("/");
ASSERT_EQ((p1 / p2).abs(), "/a/b");
}
{
CanonPath p("/foo/bar");
ASSERT_EQ((p / "x").abs(), "/foo/bar/x");
}
{
CanonPath p("/");
ASSERT_EQ((p / "foo" / "bar").abs(), "/foo/bar");
}
}
TEST(CanonPath, within) {
ASSERT_TRUE(CanonPath("foo").isWithin(CanonPath("foo")));
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("bar")));
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("fo")));
ASSERT_TRUE(CanonPath("foo/bar").isWithin(CanonPath("foo")));
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("foo/bar")));
ASSERT_TRUE(CanonPath("/foo/bar/default.nix").isWithin(CanonPath("/")));
ASSERT_TRUE(CanonPath("/").isWithin(CanonPath("/")));
}
TEST(CanonPath, sort) {
ASSERT_FALSE(CanonPath("foo") < CanonPath("foo"));
ASSERT_TRUE (CanonPath("foo") < CanonPath("foo/bar"));
ASSERT_TRUE (CanonPath("foo/bar") < CanonPath("foo!"));
ASSERT_FALSE(CanonPath("foo!") < CanonPath("foo"));
ASSERT_TRUE (CanonPath("foo") < CanonPath("foo!"));
}
TEST(CanonPath, allowed) {
std::set<CanonPath> allowed {
CanonPath("foo/bar"),
CanonPath("foo!"),
CanonPath("xyzzy"),
CanonPath("a/b/c"),
};
ASSERT_TRUE (CanonPath("foo/bar").isAllowed(allowed));
ASSERT_TRUE (CanonPath("foo/bar/bla").isAllowed(allowed));
ASSERT_TRUE (CanonPath("foo").isAllowed(allowed));
ASSERT_FALSE(CanonPath("bar").isAllowed(allowed));
ASSERT_FALSE(CanonPath("bar/a").isAllowed(allowed));
ASSERT_TRUE (CanonPath("a").isAllowed(allowed));
ASSERT_TRUE (CanonPath("a/b").isAllowed(allowed));
ASSERT_TRUE (CanonPath("a/b/c").isAllowed(allowed));
ASSERT_TRUE (CanonPath("a/b/c/d").isAllowed(allowed));
ASSERT_TRUE (CanonPath("a/b/c/d/e").isAllowed(allowed));
ASSERT_FALSE(CanonPath("a/b/a").isAllowed(allowed));
ASSERT_FALSE(CanonPath("a/b/d").isAllowed(allowed));
ASSERT_FALSE(CanonPath("aaa").isAllowed(allowed));
ASSERT_FALSE(CanonPath("zzz").isAllowed(allowed));
ASSERT_TRUE (CanonPath("/").isAllowed(allowed));
}
TEST(CanonPath, makeRelative) {
CanonPath d("/foo/bar");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar")), ".");
ASSERT_EQ(d.makeRelative(CanonPath("/foo")), "..");
ASSERT_EQ(d.makeRelative(CanonPath("/")), "../..");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy")), "xyzzy");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy/bla")), "xyzzy/bla");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/xyzzy/bla")), "../xyzzy/bla");
ASSERT_EQ(d.makeRelative(CanonPath("/xyzzy/bla")), "../../xyzzy/bla");
{
CanonPath p("foo//bar/");
ASSERT_EQ(p.abs(), "/foo/bar");
ASSERT_EQ(p.rel(), "foo/bar");
ASSERT_EQ(*p.baseName(), "bar");
ASSERT_EQ(*p.dirOf(), "/foo");
}
}
TEST(CanonPath, from_existing)
{
CanonPath p0("foo//bar/");
{
CanonPath p("/baz//quux/", p0);
ASSERT_EQ(p.abs(), "/baz/quux");
ASSERT_EQ(p.rel(), "baz/quux");
ASSERT_EQ(*p.baseName(), "quux");
ASSERT_EQ(*p.dirOf(), "/baz");
}
{
CanonPath p("baz//quux/", p0);
ASSERT_EQ(p.abs(), "/foo/bar/baz/quux");
ASSERT_EQ(p.rel(), "foo/bar/baz/quux");
ASSERT_EQ(*p.baseName(), "quux");
ASSERT_EQ(*p.dirOf(), "/foo/bar/baz");
}
}
TEST(CanonPath, pop)
{
CanonPath p("foo/bar/x");
ASSERT_EQ(p.abs(), "/foo/bar/x");
p.pop();
ASSERT_EQ(p.abs(), "/foo/bar");
p.pop();
ASSERT_EQ(p.abs(), "/foo");
p.pop();
ASSERT_EQ(p.abs(), "/");
}
TEST(CanonPath, removePrefix)
{
CanonPath p1("foo/bar");
CanonPath p2("foo/bar/a/b/c");
ASSERT_EQ(p2.removePrefix(p1).abs(), "/a/b/c");
ASSERT_EQ(p1.removePrefix(p1).abs(), "/");
ASSERT_EQ(p1.removePrefix(CanonPath("/")).abs(), "/foo/bar");
}
TEST(CanonPath, iter)
{
{
CanonPath p("a//foo/bar//");
std::vector<std::string_view> ss;
for (auto & c : p)
ss.push_back(c);
ASSERT_EQ(ss, std::vector<std::string_view>({"a", "foo", "bar"}));
}
{
CanonPath p("/");
std::vector<std::string_view> ss;
for (auto & c : p)
ss.push_back(c);
ASSERT_EQ(ss, std::vector<std::string_view>());
}
}
TEST(CanonPath, concat)
{
{
CanonPath p1("a//foo/bar//");
CanonPath p2("xyzzy/bla");
ASSERT_EQ((p1 / p2).abs(), "/a/foo/bar/xyzzy/bla");
}
{
CanonPath p1("/");
CanonPath p2("/a/b");
ASSERT_EQ((p1 / p2).abs(), "/a/b");
}
{
CanonPath p1("/a/b");
CanonPath p2("/");
ASSERT_EQ((p1 / p2).abs(), "/a/b");
}
{
CanonPath p("/foo/bar");
ASSERT_EQ((p / "x").abs(), "/foo/bar/x");
}
{
CanonPath p("/");
ASSERT_EQ((p / "foo" / "bar").abs(), "/foo/bar");
}
}
TEST(CanonPath, within)
{
ASSERT_TRUE(CanonPath("foo").isWithin(CanonPath("foo")));
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("bar")));
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("fo")));
ASSERT_TRUE(CanonPath("foo/bar").isWithin(CanonPath("foo")));
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("foo/bar")));
ASSERT_TRUE(CanonPath("/foo/bar/default.nix").isWithin(CanonPath("/")));
ASSERT_TRUE(CanonPath("/").isWithin(CanonPath("/")));
}
TEST(CanonPath, sort)
{
ASSERT_FALSE(CanonPath("foo") < CanonPath("foo"));
ASSERT_TRUE(CanonPath("foo") < CanonPath("foo/bar"));
ASSERT_TRUE(CanonPath("foo/bar") < CanonPath("foo!"));
ASSERT_FALSE(CanonPath("foo!") < CanonPath("foo"));
ASSERT_TRUE(CanonPath("foo") < CanonPath("foo!"));
}
TEST(CanonPath, allowed)
{
std::set<CanonPath> allowed{
CanonPath("foo/bar"),
CanonPath("foo!"),
CanonPath("xyzzy"),
CanonPath("a/b/c"),
};
ASSERT_TRUE(CanonPath("foo/bar").isAllowed(allowed));
ASSERT_TRUE(CanonPath("foo/bar/bla").isAllowed(allowed));
ASSERT_TRUE(CanonPath("foo").isAllowed(allowed));
ASSERT_FALSE(CanonPath("bar").isAllowed(allowed));
ASSERT_FALSE(CanonPath("bar/a").isAllowed(allowed));
ASSERT_TRUE(CanonPath("a").isAllowed(allowed));
ASSERT_TRUE(CanonPath("a/b").isAllowed(allowed));
ASSERT_TRUE(CanonPath("a/b/c").isAllowed(allowed));
ASSERT_TRUE(CanonPath("a/b/c/d").isAllowed(allowed));
ASSERT_TRUE(CanonPath("a/b/c/d/e").isAllowed(allowed));
ASSERT_FALSE(CanonPath("a/b/a").isAllowed(allowed));
ASSERT_FALSE(CanonPath("a/b/d").isAllowed(allowed));
ASSERT_FALSE(CanonPath("aaa").isAllowed(allowed));
ASSERT_FALSE(CanonPath("zzz").isAllowed(allowed));
ASSERT_TRUE(CanonPath("/").isAllowed(allowed));
}
TEST(CanonPath, makeRelative)
{
CanonPath d("/foo/bar");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar")), ".");
ASSERT_EQ(d.makeRelative(CanonPath("/foo")), "..");
ASSERT_EQ(d.makeRelative(CanonPath("/")), "../..");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy")), "xyzzy");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy/bla")), "xyzzy/bla");
ASSERT_EQ(d.makeRelative(CanonPath("/foo/xyzzy/bla")), "../xyzzy/bla");
ASSERT_EQ(d.makeRelative(CanonPath("/xyzzy/bla")), "../../xyzzy/bla");
}
} // namespace nix

View file

@ -21,7 +21,7 @@ struct Arbitrary<nix::checked::Checked<T>>
}
};
}
} // namespace rc
namespace nix::checked {
@ -155,4 +155,4 @@ TEST(Checked, div_signed_special_cases)
checkDivision<int16_t, int64_t>(0, 0);
}
}
} // namespace nix::checked

View file

@ -3,52 +3,54 @@
#include <gtest/gtest.h>
namespace nix {
TEST(ChunkedVector, InitEmpty) {
auto v = ChunkedVector<int, 2>(100);
ASSERT_EQ(v.size(), 0u);
}
TEST(ChunkedVector, GrowsCorrectly) {
auto v = ChunkedVector<int, 2>(100);
for (uint32_t i = 1; i < 20; i++) {
v.add(i);
ASSERT_EQ(v.size(), i);
}
}
TEST(ChunkedVector, AddAndGet) {
auto v = ChunkedVector<int, 2>(100);
for (auto i = 1; i < 20; i++) {
auto [i2, idx] = v.add(i);
auto & i3 = v[idx];
ASSERT_EQ(i, i2);
ASSERT_EQ(&i2, &i3);
}
}
TEST(ChunkedVector, ForEach) {
auto v = ChunkedVector<int, 2>(100);
for (auto i = 1; i < 20; i++) {
v.add(i);
}
uint32_t count = 0;
v.forEach([&count](int elt) {
count++;
});
ASSERT_EQ(count, v.size());
}
TEST(ChunkedVector, OverflowOK) {
// Similar to the AddAndGet, but intentionnally use a small
// initial ChunkedVector to force it to overflow
auto v = ChunkedVector<int, 2>(2);
for (auto i = 1; i < 20; i++) {
auto [i2, idx] = v.add(i);
auto & i3 = v[idx];
ASSERT_EQ(i, i2);
ASSERT_EQ(&i2, &i3);
}
}
TEST(ChunkedVector, InitEmpty)
{
auto v = ChunkedVector<int, 2>(100);
ASSERT_EQ(v.size(), 0u);
}
TEST(ChunkedVector, GrowsCorrectly)
{
auto v = ChunkedVector<int, 2>(100);
for (uint32_t i = 1; i < 20; i++) {
v.add(i);
ASSERT_EQ(v.size(), i);
}
}
TEST(ChunkedVector, AddAndGet)
{
auto v = ChunkedVector<int, 2>(100);
for (auto i = 1; i < 20; i++) {
auto [i2, idx] = v.add(i);
auto & i3 = v[idx];
ASSERT_EQ(i, i2);
ASSERT_EQ(&i2, &i3);
}
}
TEST(ChunkedVector, ForEach)
{
auto v = ChunkedVector<int, 2>(100);
for (auto i = 1; i < 20; i++) {
v.add(i);
}
uint32_t count = 0;
v.forEach([&count](int elt) { count++; });
ASSERT_EQ(count, v.size());
}
TEST(ChunkedVector, OverflowOK)
{
// Similar to the AddAndGet, but intentionnally use a small
// initial ChunkedVector to force it to overflow
auto v = ChunkedVector<int, 2>(2);
for (auto i = 1; i < 20; i++) {
auto [i2, idx] = v.add(i);
auto & i3 = v[idx];
ASSERT_EQ(i, i2);
ASSERT_EQ(&i2, &i3);
}
}
} // namespace nix

View file

@ -6,48 +6,48 @@ namespace nix {
using namespace std;
map<string, set<string>> testGraph = {
{ "A", { "B", "C", "G" } },
{ "B", { "A" } }, // Loops back to A
{ "C", { "F" } }, // Indirect reference
{ "D", { "A" } }, // Not reachable, but has backreferences
{ "E", {} }, // Just not reachable
{ "F", {} },
{ "G", { "G" } }, // Self reference
{"A", {"B", "C", "G"}},
{"B", {"A"}}, // Loops back to A
{"C", {"F"}}, // Indirect reference
{"D", {"A"}}, // Not reachable, but has backreferences
{"E", {}}, // Just not reachable
{"F", {}},
{"G", {"G"}}, // Self reference
};
TEST(closure, correctClosure) {
TEST(closure, correctClosure)
{
set<string> aClosure;
set<string> expectedClosure = {"A", "B", "C", "F", "G"};
computeClosure<string>(
{"A"},
aClosure,
[&](const string currentNode, function<void(promise<set<string>> &)> processEdges) {
{"A"}, aClosure, [&](const string currentNode, function<void(promise<set<string>> &)> processEdges) {
promise<set<string>> promisedNodes;
promisedNodes.set_value(testGraph[currentNode]);
processEdges(promisedNodes);
}
);
});
ASSERT_EQ(aClosure, expectedClosure);
}
TEST(closure, properlyHandlesDirectExceptions) {
struct TestExn {};
TEST(closure, properlyHandlesDirectExceptions)
{
struct TestExn
{};
set<string> aClosure;
EXPECT_THROW(
computeClosure<string>(
{"A"},
aClosure,
[&](const string currentNode, function<void(promise<set<string>> &)> processEdges) {
throw TestExn();
}
),
TestExn
);
[&](const string currentNode, function<void(promise<set<string>> &)> processEdges) { throw TestExn(); }),
TestExn);
}
TEST(closure, properlyHandlesExceptionsInPromise) {
struct TestExn {};
TEST(closure, properlyHandlesExceptionsInPromise)
{
struct TestExn
{};
set<string> aClosure;
EXPECT_THROW(
computeClosure<string>(
@ -61,10 +61,8 @@ TEST(closure, properlyHandlesExceptionsInPromise) {
promise.set_exception(std::current_exception());
}
processEdges(promise);
}
),
TestExn
);
}),
TestExn);
}
}
} // namespace nix

View file

@ -3,94 +3,104 @@
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);
}
/* ----------------------------------------------------------------------------
* 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) {
StringSink strSink;
auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf";
auto decompressionSink = makeDecompressionSink("bzip2", strSink);
auto sink = makeCompressionSink("bzip2", *decompressionSink);
(*sink)(inputString);
sink->finish();
decompressionSink->finish();
ASSERT_STREQ(strSink.s.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, 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);
}
/* ----------------------------------------------------------------------------
* 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)
{
StringSink strSink;
auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf";
auto decompressionSink = makeDecompressionSink("bzip2", strSink);
auto sink = makeCompressionSink("bzip2", *decompressionSink);
(*sink)(inputString);
sink->finish();
decompressionSink->finish();
ASSERT_STREQ(strSink.s.c_str(), inputString);
}
} // namespace nix

View file

@ -7,169 +7,195 @@
namespace nix {
/* ----------------------------------------------------------------------------
* Config
* --------------------------------------------------------------------------*/
/* ----------------------------------------------------------------------------
* Config
* --------------------------------------------------------------------------*/
TEST(Config, setUndefinedSetting) {
Config config;
ASSERT_EQ(config.set("undefined-key", "value"), false);
}
TEST(Config, setUndefinedSetting)
{
Config config;
ASSERT_EQ(config.set("undefined-key", "value"), false);
}
TEST(Config, setDefinedSetting) {
Config config;
std::string value;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
ASSERT_EQ(config.set("name-of-the-setting", "value"), true);
}
TEST(Config, setDefinedSetting)
{
Config config;
std::string value;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
ASSERT_EQ(config.set("name-of-the-setting", "value"), true);
}
TEST(Config, getDefinedSetting) {
Config config;
std::string value;
TEST(Config, getDefinedSetting)
{
Config config;
std::string value;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
config.getSettings(settings, /* overriddenOnly = */ false);
const auto iter = settings.find("name-of-the-setting");
ASSERT_NE(iter, settings.end());
ASSERT_EQ(iter->second.value, "");
ASSERT_EQ(iter->second.description, "description\n");
}
TEST(Config, getDefinedOverriddenSettingNotSet)
{
Config config;
std::string value;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
config.getSettings(settings, /* overriddenOnly = */ true);
const auto e = settings.find("name-of-the-setting");
ASSERT_EQ(e, settings.end());
}
TEST(Config, getDefinedSettingSet1)
{
Config config;
std::string value;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, value, "name-of-the-setting", "description"};
setting.assign("value");
config.getSettings(settings, /* overriddenOnly = */ false);
const auto iter = settings.find("name-of-the-setting");
ASSERT_NE(iter, settings.end());
ASSERT_EQ(iter->second.value, "value");
ASSERT_EQ(iter->second.description, "description\n");
}
TEST(Config, getDefinedSettingSet2)
{
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
ASSERT_TRUE(config.set("name-of-the-setting", "value"));
config.getSettings(settings, /* overriddenOnly = */ false);
const auto e = settings.find("name-of-the-setting");
ASSERT_NE(e, settings.end());
ASSERT_EQ(e->second.value, "value");
ASSERT_EQ(e->second.description, "description\n");
}
TEST(Config, addSetting)
{
class TestSetting : public AbstractSetting
{
public:
TestSetting()
: AbstractSetting("test", "test", {})
{
}
void set(const std::string & value, bool append) override {}
std::string to_string() const override
{
return {};
}
bool isAppendable() override
{
return false;
}
};
Config config;
TestSetting setting;
ASSERT_FALSE(config.set("test", "value"));
config.addSetting(&setting);
ASSERT_TRUE(config.set("test", "value"));
ASSERT_FALSE(config.set("extra-test", "value"));
}
TEST(Config, withInitialValue)
{
const StringMap initials = {
{"key", "value"},
};
Config config(initials);
{
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
config.getSettings(settings, /* overriddenOnly = */ false);
const auto iter = settings.find("name-of-the-setting");
ASSERT_NE(iter, settings.end());
ASSERT_EQ(iter->second.value, "");
ASSERT_EQ(iter->second.description, "description\n");
ASSERT_EQ(settings.find("key"), settings.end());
}
TEST(Config, getDefinedOverriddenSettingNotSet) {
Config config;
std::string value;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> foo{&config, value, "name-of-the-setting", "description"};
Setting<std::string> setting{&config, "default-value", "key", "description"};
{
std::map<std::string, Config::SettingInfo> settings;
config.getSettings(settings, /* overriddenOnly = */ false);
ASSERT_EQ(settings["key"].value, "value");
}
}
TEST(Config, resetOverridden)
{
Config config;
config.resetOverridden();
}
TEST(Config, resetOverriddenWithSetting)
{
Config config;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
{
std::map<std::string, Config::SettingInfo> settings;
setting.set("foo");
ASSERT_EQ(setting.get(), "foo");
config.getSettings(settings, /* overriddenOnly = */ true);
const auto e = settings.find("name-of-the-setting");
ASSERT_EQ(e, settings.end());
ASSERT_TRUE(settings.empty());
}
TEST(Config, getDefinedSettingSet1) {
Config config;
std::string value;
{
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, value, "name-of-the-setting", "description"};
setting.assign("value");
config.getSettings(settings, /* overriddenOnly = */ false);
const auto iter = settings.find("name-of-the-setting");
ASSERT_NE(iter, settings.end());
ASSERT_EQ(iter->second.value, "value");
ASSERT_EQ(iter->second.description, "description\n");
setting.override("bar");
ASSERT_TRUE(setting.overridden);
ASSERT_EQ(setting.get(), "bar");
config.getSettings(settings, /* overriddenOnly = */ true);
ASSERT_FALSE(settings.empty());
}
TEST(Config, getDefinedSettingSet2) {
Config config;
{
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
ASSERT_TRUE(config.set("name-of-the-setting", "value"));
config.getSettings(settings, /* overriddenOnly = */ false);
const auto e = settings.find("name-of-the-setting");
ASSERT_NE(e, settings.end());
ASSERT_EQ(e->second.value, "value");
ASSERT_EQ(e->second.description, "description\n");
}
TEST(Config, addSetting) {
class TestSetting : public AbstractSetting {
public:
TestSetting() : AbstractSetting("test", "test", {}) {}
void set(const std::string & value, bool append) override {}
std::string to_string() const override { return {}; }
bool isAppendable() override { return false; }
};
Config config;
TestSetting setting;
ASSERT_FALSE(config.set("test", "value"));
config.addSetting(&setting);
ASSERT_TRUE(config.set("test", "value"));
ASSERT_FALSE(config.set("extra-test", "value"));
}
TEST(Config, withInitialValue) {
const StringMap initials = {
{ "key", "value" },
};
Config config(initials);
{
std::map<std::string, Config::SettingInfo> settings;
config.getSettings(settings, /* overriddenOnly = */ false);
ASSERT_EQ(settings.find("key"), settings.end());
}
Setting<std::string> setting{&config, "default-value", "key", "description"};
{
std::map<std::string, Config::SettingInfo> settings;
config.getSettings(settings, /* overriddenOnly = */ false);
ASSERT_EQ(settings["key"].value, "value");
}
}
TEST(Config, resetOverridden) {
Config config;
config.resetOverridden();
ASSERT_FALSE(setting.overridden);
config.getSettings(settings, /* overriddenOnly = */ true);
ASSERT_TRUE(settings.empty());
}
}
TEST(Config, resetOverriddenWithSetting) {
Config config;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
TEST(Config, toJSONOnEmptyConfig)
{
ASSERT_EQ(Config().toJSON().dump(), "{}");
}
{
std::map<std::string, Config::SettingInfo> settings;
TEST(Config, toJSONOnNonEmptyConfig)
{
using nlohmann::literals::operator"" _json;
Config config;
Setting<std::string> setting{
&config,
"",
"name-of-the-setting",
"description",
};
setting.assign("value");
setting.set("foo");
ASSERT_EQ(setting.get(), "foo");
config.getSettings(settings, /* overriddenOnly = */ true);
ASSERT_TRUE(settings.empty());
}
{
std::map<std::string, Config::SettingInfo> settings;
setting.override("bar");
ASSERT_TRUE(setting.overridden);
ASSERT_EQ(setting.get(), "bar");
config.getSettings(settings, /* overriddenOnly = */ true);
ASSERT_FALSE(settings.empty());
}
{
std::map<std::string, Config::SettingInfo> settings;
config.resetOverridden();
ASSERT_FALSE(setting.overridden);
config.getSettings(settings, /* overriddenOnly = */ true);
ASSERT_TRUE(settings.empty());
}
}
TEST(Config, toJSONOnEmptyConfig) {
ASSERT_EQ(Config().toJSON().dump(), "{}");
}
TEST(Config, toJSONOnNonEmptyConfig) {
using nlohmann::literals::operator "" _json;
Config config;
Setting<std::string> setting{
&config,
"",
"name-of-the-setting",
"description",
};
setting.assign("value");
ASSERT_EQ(config.toJSON(),
R"#({
ASSERT_EQ(
config.toJSON(),
R"#({
"name-of-the-setting": {
"aliases": [],
"defaultValue": "",
@ -179,24 +205,26 @@ namespace nix {
"experimentalFeature": null
}
})#"_json);
}
}
TEST(Config, toJSONOnNonEmptyConfigWithExperimentalSetting) {
using nlohmann::literals::operator "" _json;
Config config;
Setting<std::string> setting{
&config,
"",
"name-of-the-setting",
"description",
{},
true,
Xp::Flakes,
};
setting.assign("value");
TEST(Config, toJSONOnNonEmptyConfigWithExperimentalSetting)
{
using nlohmann::literals::operator"" _json;
Config config;
Setting<std::string> setting{
&config,
"",
"name-of-the-setting",
"description",
{},
true,
Xp::Flakes,
};
setting.assign("value");
ASSERT_EQ(config.toJSON(),
R"#({
ASSERT_EQ(
config.toJSON(),
R"#({
"name-of-the-setting": {
"aliases": [],
"defaultValue": "",
@ -206,90 +234,97 @@ namespace nix {
"experimentalFeature": "flakes"
}
})#"_json);
}
}
TEST(Config, setSettingAlias) {
Config config;
Setting<std::string> setting{&config, "", "some-int", "best number", { "another-int" }};
ASSERT_TRUE(config.set("some-int", "1"));
ASSERT_EQ(setting.get(), "1");
ASSERT_TRUE(config.set("another-int", "2"));
ASSERT_EQ(setting.get(), "2");
ASSERT_TRUE(config.set("some-int", "3"));
ASSERT_EQ(setting.get(), "3");
}
TEST(Config, setSettingAlias)
{
Config config;
Setting<std::string> setting{&config, "", "some-int", "best number", {"another-int"}};
ASSERT_TRUE(config.set("some-int", "1"));
ASSERT_EQ(setting.get(), "1");
ASSERT_TRUE(config.set("another-int", "2"));
ASSERT_EQ(setting.get(), "2");
ASSERT_TRUE(config.set("some-int", "3"));
ASSERT_EQ(setting.get(), "3");
}
/* FIXME: The reapplyUnknownSettings method doesn't seem to do anything
* useful (these days). Whenever we add a new setting to Config the
* unknown settings are always considered. In which case is this function
* actually useful? Is there some way to register a Setting without calling
* addSetting? */
TEST(Config, DISABLED_reapplyUnknownSettings) {
Config config;
ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue"));
Setting<std::string> setting{&config, "default", "name-of-the-setting", "description"};
ASSERT_EQ(setting.get(), "default");
config.reapplyUnknownSettings();
ASSERT_EQ(setting.get(), "unknownvalue");
}
/* FIXME: The reapplyUnknownSettings method doesn't seem to do anything
* useful (these days). Whenever we add a new setting to Config the
* unknown settings are always considered. In which case is this function
* actually useful? Is there some way to register a Setting without calling
* addSetting? */
TEST(Config, DISABLED_reapplyUnknownSettings)
{
Config config;
ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue"));
Setting<std::string> setting{&config, "default", "name-of-the-setting", "description"};
ASSERT_EQ(setting.get(), "default");
config.reapplyUnknownSettings();
ASSERT_EQ(setting.get(), "unknownvalue");
}
TEST(Config, applyConfigEmpty) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
config.applyConfig("");
config.getSettings(settings);
ASSERT_TRUE(settings.empty());
}
TEST(Config, applyConfigEmpty)
{
Config config;
std::map<std::string, Config::SettingInfo> settings;
config.applyConfig("");
config.getSettings(settings);
ASSERT_TRUE(settings.empty());
}
TEST(Config, applyConfigEmptyWithComment) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
config.applyConfig("# just a comment");
config.getSettings(settings);
ASSERT_TRUE(settings.empty());
}
TEST(Config, applyConfigEmptyWithComment)
{
Config config;
std::map<std::string, Config::SettingInfo> settings;
config.applyConfig("# just a comment");
config.getSettings(settings);
ASSERT_TRUE(settings.empty());
}
TEST(Config, applyConfigAssignment) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
TEST(Config, applyConfigAssignment)
{
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
config.applyConfig(
"name-of-the-setting = value-from-file #useful comment\n"
"# name-of-the-setting = foo\n");
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file");
}
TEST(Config, applyConfigWithReassignedSetting)
{
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
config.applyConfig(
"name-of-the-setting = first-value\n"
"name-of-the-setting = second-value\n");
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["name-of-the-setting"].value, "second-value");
}
TEST(Config, applyConfigFailsOnMissingIncludes)
{
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
ASSERT_THROW(
config.applyConfig(
"name-of-the-setting = value-from-file #useful comment\n"
"# name-of-the-setting = foo\n"
);
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file");
}
TEST(Config, applyConfigWithReassignedSetting) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
config.applyConfig(
"name-of-the-setting = first-value\n"
"name-of-the-setting = second-value\n"
);
config.getSettings(settings);
ASSERT_FALSE(settings.empty());
ASSERT_EQ(settings["name-of-the-setting"].value, "second-value");
}
TEST(Config, applyConfigFailsOnMissingIncludes) {
Config config;
std::map<std::string, Config::SettingInfo> settings;
Setting<std::string> setting{&config, "", "name-of-the-setting", "description"};
ASSERT_THROW(config.applyConfig(
"name-of-the-setting = value-from-file\n"
"# name-of-the-setting = foo\n"
"include /nix/store/does/not/exist.nix"
), Error);
}
TEST(Config, applyConfigInvalidThrows) {
Config config;
ASSERT_THROW(config.applyConfig("value == key"), UsageError);
ASSERT_THROW(config.applyConfig("value "), UsageError);
}
"include /nix/store/does/not/exist.nix"),
Error);
}
TEST(Config, applyConfigInvalidThrows)
{
Config config;
ASSERT_THROW(config.applyConfig("value == key"), UsageError);
ASSERT_THROW(config.applyConfig("value "), UsageError);
}
} // namespace nix

View file

@ -61,4 +61,4 @@ TEST(ExecutablePath, elementyElemNormalize)
EXPECT_EQ(s2, OS_STR("." PATH_VAR_SEP "." PATH_VAR_SEP "." PATH_VAR_SEP "."));
}
}
} // namespace nix

View file

@ -9,20 +9,22 @@ namespace nix {
* parseFileSerialisationMethod, renderFileSerialisationMethod
* --------------------------------------------------------------------------*/
TEST(FileSerialisationMethod, testRoundTripPrintParse_1) {
TEST(FileSerialisationMethod, testRoundTripPrintParse_1)
{
for (const FileSerialisationMethod fim : {
FileSerialisationMethod::Flat,
FileSerialisationMethod::NixArchive,
}) {
FileSerialisationMethod::Flat,
FileSerialisationMethod::NixArchive,
}) {
EXPECT_EQ(parseFileSerialisationMethod(renderFileSerialisationMethod(fim)), fim);
}
}
TEST(FileSerialisationMethod, testRoundTripPrintParse_2) {
TEST(FileSerialisationMethod, testRoundTripPrintParse_2)
{
for (const std::string_view fimS : {
"flat",
"nar",
}) {
"flat",
"nar",
}) {
EXPECT_EQ(renderFileSerialisationMethod(parseFileSerialisationMethod(fimS)), fimS);
}
}
@ -38,22 +40,24 @@ TEST(FileSerialisationMethod, testParseFileSerialisationMethodOptException)
* parseFileIngestionMethod, renderFileIngestionMethod
* --------------------------------------------------------------------------*/
TEST(FileIngestionMethod, testRoundTripPrintParse_1) {
TEST(FileIngestionMethod, testRoundTripPrintParse_1)
{
for (const FileIngestionMethod fim : {
FileIngestionMethod::Flat,
FileIngestionMethod::NixArchive,
FileIngestionMethod::Git,
}) {
FileIngestionMethod::Flat,
FileIngestionMethod::NixArchive,
FileIngestionMethod::Git,
}) {
EXPECT_EQ(parseFileIngestionMethod(renderFileIngestionMethod(fim)), fim);
}
}
TEST(FileIngestionMethod, testRoundTripPrintParse_2) {
TEST(FileIngestionMethod, testRoundTripPrintParse_2)
{
for (const std::string_view fimS : {
"flat",
"nar",
"git",
}) {
"flat",
"nar",
"git",
}) {
EXPECT_EQ(renderFileIngestionMethod(parseFileIngestionMethod(fimS)), fimS);
}
}
@ -65,4 +69,4 @@ TEST(FileIngestionMethod, testParseFileIngestionMethodOptException)
testing::ThrowsMessage<UsageError>(testing::HasSubstr("narwhal")));
}
}
} // namespace nix

View file

@ -318,4 +318,4 @@ TEST(DirectoryIterator, nonexistent)
ASSERT_THROW(DirectoryIterator("/schnitzel/darmstadt/pommes"), SysError);
}
}
} // namespace nix

View file

@ -15,7 +15,8 @@ class GitTest : public CharacterizationTest
public:
std::filesystem::path goldenMaster(std::string_view testStem) const override {
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / std::string(testStem);
}
@ -33,39 +34,44 @@ private:
}
};
TEST(GitMode, gitMode_directory) {
TEST(GitMode, gitMode_directory)
{
Mode m = Mode::Directory;
RawMode r = 0040000;
ASSERT_EQ(static_cast<RawMode>(m), r);
ASSERT_EQ(decodeMode(r), std::optional { m });
ASSERT_EQ(decodeMode(r), std::optional{m});
};
TEST(GitMode, gitMode_executable) {
TEST(GitMode, gitMode_executable)
{
Mode m = Mode::Executable;
RawMode r = 0100755;
ASSERT_EQ(static_cast<RawMode>(m), r);
ASSERT_EQ(decodeMode(r), std::optional { m });
ASSERT_EQ(decodeMode(r), std::optional{m});
};
TEST(GitMode, gitMode_regular) {
TEST(GitMode, gitMode_regular)
{
Mode m = Mode::Regular;
RawMode r = 0100644;
ASSERT_EQ(static_cast<RawMode>(m), r);
ASSERT_EQ(decodeMode(r), std::optional { m });
ASSERT_EQ(decodeMode(r), std::optional{m});
};
TEST(GitMode, gitMode_symlink) {
TEST(GitMode, gitMode_symlink)
{
Mode m = Mode::Symlink;
RawMode r = 0120000;
ASSERT_EQ(static_cast<RawMode>(m), r);
ASSERT_EQ(decodeMode(r), std::optional { m });
ASSERT_EQ(decodeMode(r), std::optional{m});
};
TEST_F(GitTest, blob_read) {
TEST_F(GitTest, blob_read)
{
readTest("hello-world-blob.bin", [&](const auto & encoded) {
StringSource in { encoded };
StringSource in{encoded};
StringSink out;
RegularFileSink out2 { out };
RegularFileSink out2{out};
ASSERT_EQ(parseObjectType(in, mockXpSettings), ObjectType::Blob);
parseBlob(out2, CanonPath::root, in, BlobMode::Regular, mockXpSettings);
@ -75,7 +81,8 @@ TEST_F(GitTest, blob_read) {
});
}
TEST_F(GitTest, blob_write) {
TEST_F(GitTest, blob_write)
{
writeTest("hello-world-blob.bin", [&]() {
auto decoded = readFile(goldenMaster("hello-world.bin"));
StringSink s;
@ -126,24 +133,31 @@ const static Tree tree = {
},
};
TEST_F(GitTest, tree_read) {
TEST_F(GitTest, tree_read)
{
readTest("tree.bin", [&](const auto & encoded) {
StringSource in { encoded };
StringSource in{encoded};
NullFileSystemObjectSink out;
Tree got;
ASSERT_EQ(parseObjectType(in, mockXpSettings), ObjectType::Tree);
parseTree(out, CanonPath::root, in, [&](auto & name, auto entry) {
auto name2 = std::string{name.rel()};
if (entry.mode == Mode::Directory)
name2 += '/';
got.insert_or_assign(name2, std::move(entry));
}, mockXpSettings);
parseTree(
out,
CanonPath::root,
in,
[&](auto & name, auto entry) {
auto name2 = std::string{name.rel()};
if (entry.mode == Mode::Directory)
name2 += '/';
got.insert_or_assign(name2, std::move(entry));
},
mockXpSettings);
ASSERT_EQ(got, tree);
});
}
TEST_F(GitTest, tree_write) {
TEST_F(GitTest, tree_write)
{
writeTest("tree.bin", [&]() {
StringSink s;
dumpTree(tree, s, mockXpSettings);
@ -151,36 +165,38 @@ TEST_F(GitTest, tree_write) {
});
}
TEST_F(GitTest, both_roundrip) {
TEST_F(GitTest, both_roundrip)
{
using File = MemorySourceAccessor::File;
auto files = make_ref<MemorySourceAccessor>();
files->root = File::Directory {
.contents {
files->root = File::Directory{
.contents{
{
"foo",
File::Regular {
File::Regular{
.contents = "hello\n\0\n\tworld!",
},
},
{
"bar",
File::Directory {
.contents = {
File::Directory{
.contents =
{
"baz",
File::Regular {
.executable = true,
.contents = "good day,\n\0\n\tworld!",
{
"baz",
File::Regular{
.executable = true,
.contents = "good day,\n\0\n\tworld!",
},
},
{
"quux",
File::Symlink{
.target = "/over/there",
},
},
},
{
"quux",
File::Symlink {
.target = "/over/there",
},
},
},
},
},
},
@ -191,14 +207,12 @@ TEST_F(GitTest, both_roundrip) {
std::function<DumpHook> dumpHook;
dumpHook = [&](const SourcePath & path) {
StringSink s;
HashSink hashSink { HashAlgorithm::SHA1 };
TeeSink s2 { s, hashSink };
auto mode = dump(
path, s2, dumpHook,
defaultPathFilter, mockXpSettings);
HashSink hashSink{HashAlgorithm::SHA1};
TeeSink s2{s, hashSink};
auto mode = dump(path, s2, dumpHook, defaultPathFilter, mockXpSettings);
auto hash = hashSink.finish().first;
cas.insert_or_assign(hash, std::move(s.s));
return TreeEntry {
return TreeEntry{
.mode = mode,
.hash = hash,
};
@ -208,13 +222,16 @@ TEST_F(GitTest, both_roundrip) {
auto files2 = make_ref<MemorySourceAccessor>();
MemorySink sinkFiles2 { *files2 };
MemorySink sinkFiles2{*files2};
std::function<void(const CanonPath, const Hash &, BlobMode)> mkSinkHook;
mkSinkHook = [&](auto prefix, auto & hash, auto blobMode) {
StringSource in { cas[hash] };
StringSource in{cas[hash]};
parse(
sinkFiles2, prefix, in, blobMode,
sinkFiles2,
prefix,
in,
blobMode,
[&](const CanonPath & name, const auto & entry) {
mkSinkHook(
prefix / name,
@ -232,7 +249,8 @@ TEST_F(GitTest, both_roundrip) {
ASSERT_EQ(files->root, files2->root);
}
TEST(GitLsRemote, parseSymrefLineWithReference) {
TEST(GitLsRemote, parseSymrefLineWithReference)
{
auto line = "ref: refs/head/main HEAD";
auto res = parseLsRemoteLine(line);
ASSERT_TRUE(res.has_value());
@ -241,7 +259,8 @@ TEST(GitLsRemote, parseSymrefLineWithReference) {
ASSERT_EQ(res->reference, "HEAD");
}
TEST(GitLsRemote, parseSymrefLineWithNoReference) {
TEST(GitLsRemote, parseSymrefLineWithNoReference)
{
auto line = "ref: refs/head/main";
auto res = parseLsRemoteLine(line);
ASSERT_TRUE(res.has_value());
@ -250,7 +269,8 @@ TEST(GitLsRemote, parseSymrefLineWithNoReference) {
ASSERT_EQ(res->reference, std::nullopt);
}
TEST(GitLsRemote, parseObjectRefLine) {
TEST(GitLsRemote, parseObjectRefLine)
{
auto line = "abc123 refs/head/main";
auto res = parseLsRemoteLine(line);
ASSERT_TRUE(res.has_value());
@ -259,4 +279,4 @@ TEST(GitLsRemote, parseObjectRefLine) {
ASSERT_EQ(res->reference, "refs/head/main");
}
}
} // namespace nix

View file

@ -24,111 +24,133 @@ private:
}
};
/* ----------------------------------------------------------------------------
* hashString
* --------------------------------------------------------------------------*/
/* ----------------------------------------------------------------------------
* hashString
* --------------------------------------------------------------------------*/
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes1) {
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abc";
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
"blake3:6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85");
}
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes1)
{
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abc";
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
ASSERT_EQ(
hash.to_string(HashFormat::Base16, true),
"blake3:6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85");
}
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes2) {
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
"blake3:c19012cc2aaf0dc3d8e5c45a1b79114d2df42abb2a410bf54be09e891af06ff8");
}
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes2)
{
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
ASSERT_EQ(
hash.to_string(HashFormat::Base16, true),
"blake3:c19012cc2aaf0dc3d8e5c45a1b79114d2df42abb2a410bf54be09e891af06ff8");
}
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes3) {
// values taken from: https://www.ietf.org/archive/id/draft-aumasson-blake3-00.txt
auto s = "IETF";
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
"blake3:83a2de1ee6f4e6ab686889248f4ec0cf4cc5709446a682ffd1cbb4d6165181e2");
}
TEST_F(BLAKE3HashTest, testKnownBLAKE3Hashes3)
{
// values taken from: https://www.ietf.org/archive/id/draft-aumasson-blake3-00.txt
auto s = "IETF";
auto hash = hashString(HashAlgorithm::BLAKE3, s, mockXpSettings);
ASSERT_EQ(
hash.to_string(HashFormat::Base16, true),
"blake3:83a2de1ee6f4e6ab686889248f4ec0cf4cc5709446a682ffd1cbb4d6165181e2");
}
TEST(hashString, testKnownMD5Hashes1) {
// values taken from: https://tools.ietf.org/html/rfc1321
auto s1 = "";
auto hash = hashString(HashAlgorithm::MD5, s1);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e");
}
TEST(hashString, testKnownMD5Hashes1)
{
// values taken from: https://tools.ietf.org/html/rfc1321
auto s1 = "";
auto hash = hashString(HashAlgorithm::MD5, s1);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e");
}
TEST(hashString, testKnownMD5Hashes2) {
// values taken from: https://tools.ietf.org/html/rfc1321
auto s2 = "abc";
auto hash = hashString(HashAlgorithm::MD5, s2);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72");
}
TEST(hashString, testKnownMD5Hashes2)
{
// values taken from: https://tools.ietf.org/html/rfc1321
auto s2 = "abc";
auto hash = hashString(HashAlgorithm::MD5, s2);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72");
}
TEST(hashString, testKnownSHA1Hashes1) {
// values taken from: https://tools.ietf.org/html/rfc3174
auto s = "abc";
auto hash = hashString(HashAlgorithm::SHA1, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),"sha1:a9993e364706816aba3e25717850c26c9cd0d89d");
}
TEST(hashString, testKnownSHA1Hashes1)
{
// values taken from: https://tools.ietf.org/html/rfc3174
auto s = "abc";
auto hash = hashString(HashAlgorithm::SHA1, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "sha1:a9993e364706816aba3e25717850c26c9cd0d89d");
}
TEST(hashString, testKnownSHA1Hashes2) {
// values taken from: https://tools.ietf.org/html/rfc3174
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
auto hash = hashString(HashAlgorithm::SHA1, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),"sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1");
}
TEST(hashString, testKnownSHA1Hashes2)
{
// values taken from: https://tools.ietf.org/html/rfc3174
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
auto hash = hashString(HashAlgorithm::SHA1, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true), "sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1");
}
TEST(hashString, testKnownSHA256Hashes1) {
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abc";
TEST(hashString, testKnownSHA256Hashes1)
{
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abc";
auto hash = hashString(HashAlgorithm::SHA256, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
"sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
}
auto hash = hashString(HashAlgorithm::SHA256, s);
ASSERT_EQ(
hash.to_string(HashFormat::Base16, true),
"sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
}
TEST(hashString, testKnownSHA256Hashes2) {
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
auto hash = hashString(HashAlgorithm::SHA256, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
"sha256:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
}
TEST(hashString, testKnownSHA256Hashes2)
{
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
auto hash = hashString(HashAlgorithm::SHA256, s);
ASSERT_EQ(
hash.to_string(HashFormat::Base16, true),
"sha256:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
}
TEST(hashString, testKnownSHA512Hashes1) {
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abc";
auto hash = hashString(HashAlgorithm::SHA512, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
"sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a9"
"7ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd"
"454d4423643ce80e2a9ac94fa54ca49f");
}
TEST(hashString, testKnownSHA512Hashes2) {
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
TEST(hashString, testKnownSHA512Hashes1)
{
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abc";
auto hash = hashString(HashAlgorithm::SHA512, s);
ASSERT_EQ(
hash.to_string(HashFormat::Base16, true),
"sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a9"
"7ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd"
"454d4423643ce80e2a9ac94fa54ca49f");
}
auto hash = hashString(HashAlgorithm::SHA512, s);
ASSERT_EQ(hash.to_string(HashFormat::Base16, true),
"sha512:8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa1"
"7299aeadb6889018501d289e4900f7e4331b99dec4b5433a"
"c7d329eeb6dd26545e96e55b874be909");
}
TEST(hashString, testKnownSHA512Hashes2)
{
// values taken from: https://tools.ietf.org/html/rfc4634
auto s =
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
/* ----------------------------------------------------------------------------
* parseHashFormat, parseHashFormatOpt, printHashFormat
* --------------------------------------------------------------------------*/
auto hash = hashString(HashAlgorithm::SHA512, s);
ASSERT_EQ(
hash.to_string(HashFormat::Base16, true),
"sha512:8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa1"
"7299aeadb6889018501d289e4900f7e4331b99dec4b5433a"
"c7d329eeb6dd26545e96e55b874be909");
}
TEST(hashFormat, testRoundTripPrintParse) {
for (const HashFormat hashFormat: { HashFormat::Base64, HashFormat::Nix32, HashFormat::Base16, HashFormat::SRI}) {
ASSERT_EQ(parseHashFormat(printHashFormat(hashFormat)), hashFormat);
ASSERT_EQ(*parseHashFormatOpt(printHashFormat(hashFormat)), hashFormat);
}
}
/* ----------------------------------------------------------------------------
* parseHashFormat, parseHashFormatOpt, printHashFormat
* --------------------------------------------------------------------------*/
TEST(hashFormat, testParseHashFormatOptException) {
ASSERT_EQ(parseHashFormatOpt("sha0042"), std::nullopt);
TEST(hashFormat, testRoundTripPrintParse)
{
for (const HashFormat hashFormat : {HashFormat::Base64, HashFormat::Nix32, HashFormat::Base16, HashFormat::SRI}) {
ASSERT_EQ(parseHashFormat(printHashFormat(hashFormat)), hashFormat);
ASSERT_EQ(*parseHashFormatOpt(printHashFormat(hashFormat)), hashFormat);
}
}
TEST(hashFormat, testParseHashFormatOptException)
{
ASSERT_EQ(parseHashFormatOpt("sha0042"), std::nullopt);
}
} // namespace nix

View file

@ -5,61 +5,57 @@
namespace nix {
/* ----------- tests for fmt.hh -------------------------------------------------*/
TEST(hiliteMatches, noHighlight) {
ASSERT_STREQ(hiliteMatches("Hello, world!", std::vector<std::smatch>(), "(", ")").c_str(), "Hello, world!");
}
TEST(hiliteMatches, simpleHighlight) {
std::string str = "Hello, world!";
std::regex re = std::regex("world");
auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator());
ASSERT_STREQ(
hiliteMatches(str, matches, "(", ")").c_str(),
"Hello, (world)!"
);
}
TEST(hiliteMatches, multipleMatches) {
std::string str = "Hello, world, world, world, world, world, world, Hello!";
std::regex re = std::regex("world");
auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator());
ASSERT_STREQ(
hiliteMatches(str, matches, "(", ")").c_str(),
"Hello, (world), (world), (world), (world), (world), (world), Hello!"
);
}
TEST(hiliteMatches, overlappingMatches) {
std::string str = "world, Hello, world, Hello, world, Hello, world, Hello, world!";
std::regex re = std::regex("Hello, world");
std::regex re2 = std::regex("world, Hello");
auto v = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator());
for(auto it = std::sregex_iterator(str.begin(), str.end(), re2); it != std::sregex_iterator(); ++it) {
v.push_back(*it);
}
ASSERT_STREQ(
hiliteMatches(str, v, "(", ")").c_str(),
"(world, Hello, world, Hello, world, Hello, world, Hello, world)!"
);
}
TEST(hiliteMatches, complexOverlappingMatches) {
std::string str = "legacyPackages.x86_64-linux.git-crypt";
std::vector regexes = {
std::regex("t-cry"),
std::regex("ux\\.git-cry"),
std::regex("git-c"),
std::regex("pt"),
};
std::vector<std::smatch> matches;
for (const auto & regex : regexes) {
for(auto it = std::sregex_iterator(str.begin(), str.end(), regex); it != std::sregex_iterator(); ++it) {
matches.push_back(*it);
}
}
ASSERT_STREQ(
hiliteMatches(str, matches, "(", ")").c_str(),
"legacyPackages.x86_64-lin(ux.git-crypt)"
);
}
TEST(hiliteMatches, noHighlight)
{
ASSERT_STREQ(hiliteMatches("Hello, world!", std::vector<std::smatch>(), "(", ")").c_str(), "Hello, world!");
}
TEST(hiliteMatches, simpleHighlight)
{
std::string str = "Hello, world!";
std::regex re = std::regex("world");
auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator());
ASSERT_STREQ(hiliteMatches(str, matches, "(", ")").c_str(), "Hello, (world)!");
}
TEST(hiliteMatches, multipleMatches)
{
std::string str = "Hello, world, world, world, world, world, world, Hello!";
std::regex re = std::regex("world");
auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator());
ASSERT_STREQ(
hiliteMatches(str, matches, "(", ")").c_str(),
"Hello, (world), (world), (world), (world), (world), (world), Hello!");
}
TEST(hiliteMatches, overlappingMatches)
{
std::string str = "world, Hello, world, Hello, world, Hello, world, Hello, world!";
std::regex re = std::regex("Hello, world");
std::regex re2 = std::regex("world, Hello");
auto v = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator());
for (auto it = std::sregex_iterator(str.begin(), str.end(), re2); it != std::sregex_iterator(); ++it) {
v.push_back(*it);
}
ASSERT_STREQ(
hiliteMatches(str, v, "(", ")").c_str(), "(world, Hello, world, Hello, world, Hello, world, Hello, world)!");
}
TEST(hiliteMatches, complexOverlappingMatches)
{
std::string str = "legacyPackages.x86_64-linux.git-crypt";
std::vector regexes = {
std::regex("t-cry"),
std::regex("ux\\.git-cry"),
std::regex("git-c"),
std::regex("pt"),
};
std::vector<std::smatch> matches;
for (const auto & regex : regexes) {
for (auto it = std::sregex_iterator(str.begin(), str.end(), regex); it != std::sregex_iterator(); ++it) {
matches.push_back(*it);
}
}
ASSERT_STREQ(hiliteMatches(str, matches, "(", ")").c_str(), "legacyPackages.x86_64-lin(ux.git-crypt)");
}
} // namespace nix

View file

@ -12,14 +12,16 @@ namespace nix {
* We are specifically interested in whether we can _nest_ optionals in STL
* containers so we that we can leverage existing adl_serializer templates. */
TEST(to_json, optionalInt) {
TEST(to_json, optionalInt)
{
std::optional<int> val = std::make_optional(420);
ASSERT_EQ(nlohmann::json(val), nlohmann::json(420));
val = std::nullopt;
ASSERT_EQ(nlohmann::json(val), nlohmann::json(nullptr));
}
TEST(to_json, vectorOfOptionalInts) {
TEST(to_json, vectorOfOptionalInts)
{
std::vector<std::optional<int>> vals = {
std::make_optional(420),
std::nullopt,
@ -27,17 +29,20 @@ TEST(to_json, vectorOfOptionalInts) {
ASSERT_EQ(nlohmann::json(vals), nlohmann::json::parse("[420,null]"));
}
TEST(to_json, optionalVectorOfInts) {
std::optional<std::vector<int>> val = std::make_optional(std::vector<int> {
-420,
420,
});
TEST(to_json, optionalVectorOfInts)
{
std::optional<std::vector<int>> val = std::make_optional(
std::vector<int>{
-420,
420,
});
ASSERT_EQ(nlohmann::json(val), nlohmann::json::parse("[-420,420]"));
val = std::nullopt;
ASSERT_EQ(nlohmann::json(val), nlohmann::json(nullptr));
}
TEST(from_json, optionalInt) {
TEST(from_json, optionalInt)
{
nlohmann::json json = 420;
std::optional<int> val = json;
ASSERT_TRUE(val.has_value());
@ -47,8 +52,9 @@ TEST(from_json, optionalInt) {
ASSERT_FALSE(val.has_value());
}
TEST(from_json, vectorOfOptionalInts) {
nlohmann::json json = { 420, nullptr };
TEST(from_json, vectorOfOptionalInts)
{
nlohmann::json json = {420, nullptr};
std::vector<std::optional<int>> vals = json;
ASSERT_EQ(vals.size(), 2u);
ASSERT_TRUE(vals.at(0).has_value());
@ -56,7 +62,8 @@ TEST(from_json, vectorOfOptionalInts) {
ASSERT_FALSE(vals.at(1).has_value());
}
TEST(valueAt, simpleObject) {
TEST(valueAt, simpleObject)
{
auto simple = R"({ "hello": "world" })"_json;
ASSERT_EQ(valueAt(getObject(simple), "hello"), "world");
@ -66,7 +73,8 @@ TEST(valueAt, simpleObject) {
ASSERT_EQ(valueAt(valueAt(getObject(nested), "hello"), "world"), "");
}
TEST(valueAt, missingKey) {
TEST(valueAt, missingKey)
{
auto json = R"({ "hello": { "nested": "world" } })"_json;
auto & obj = getObject(json);
@ -74,20 +82,22 @@ TEST(valueAt, missingKey) {
ASSERT_THROW(valueAt(obj, "foo"), Error);
}
TEST(getObject, rightAssertions) {
TEST(getObject, rightAssertions)
{
auto simple = R"({ "object": {} })"_json;
ASSERT_EQ(getObject(valueAt(getObject(simple), "object")), (nlohmann::json::object_t {}));
ASSERT_EQ(getObject(valueAt(getObject(simple), "object")), (nlohmann::json::object_t{}));
auto nested = R"({ "object": { "object": {} } })"_json;
auto nestedObject = getObject(valueAt(getObject(nested), "object"));
ASSERT_EQ(nestedObject, getObject(nlohmann::json::parse(R"({ "object": {} })")));
ASSERT_EQ(getObject(valueAt(getObject(nestedObject), "object")), (nlohmann::json::object_t {}));
ASSERT_EQ(getObject(valueAt(getObject(nestedObject), "object")), (nlohmann::json::object_t{}));
}
TEST(getObject, wrongAssertions) {
TEST(getObject, wrongAssertions)
{
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
auto & obj = getObject(json);
@ -98,13 +108,15 @@ TEST(getObject, wrongAssertions) {
ASSERT_THROW(getObject(valueAt(obj, "boolean")), Error);
}
TEST(getArray, rightAssertions) {
TEST(getArray, rightAssertions)
{
auto simple = R"({ "array": [] })"_json;
ASSERT_EQ(getArray(valueAt(getObject(simple), "array")), (nlohmann::json::array_t {}));
ASSERT_EQ(getArray(valueAt(getObject(simple), "array")), (nlohmann::json::array_t{}));
}
TEST(getArray, wrongAssertions) {
TEST(getArray, wrongAssertions)
{
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
ASSERT_THROW(getArray(valueAt(json, "object")), Error);
@ -113,13 +125,15 @@ TEST(getArray, wrongAssertions) {
ASSERT_THROW(getArray(valueAt(json, "boolean")), Error);
}
TEST(getString, rightAssertions) {
TEST(getString, rightAssertions)
{
auto simple = R"({ "string": "" })"_json;
ASSERT_EQ(getString(valueAt(getObject(simple), "string")), "");
}
TEST(getString, wrongAssertions) {
TEST(getString, wrongAssertions)
{
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
ASSERT_THROW(getString(valueAt(json, "object")), Error);
@ -128,7 +142,8 @@ TEST(getString, wrongAssertions) {
ASSERT_THROW(getString(valueAt(json, "boolean")), Error);
}
TEST(getIntegralNumber, rightAssertions) {
TEST(getIntegralNumber, rightAssertions)
{
auto simple = R"({ "int": 0, "signed": -1 })"_json;
ASSERT_EQ(getUnsigned(valueAt(getObject(simple), "int")), 0u);
@ -136,8 +151,10 @@ TEST(getIntegralNumber, rightAssertions) {
ASSERT_EQ(getInteger<int8_t>(valueAt(getObject(simple), "signed")), -1);
}
TEST(getIntegralNumber, wrongAssertions) {
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "signed": -256, "large": 128, "boolean": false })"_json;
TEST(getIntegralNumber, wrongAssertions)
{
auto json =
R"({ "object": {}, "array": [], "string": "", "int": 0, "signed": -256, "large": 128, "boolean": false })"_json;
ASSERT_THROW(getUnsigned(valueAt(json, "object")), Error);
ASSERT_THROW(getUnsigned(valueAt(json, "array")), Error);
@ -153,13 +170,15 @@ TEST(getIntegralNumber, wrongAssertions) {
ASSERT_THROW(getInteger<int8_t>(valueAt(json, "signed")), Error);
}
TEST(getBoolean, rightAssertions) {
TEST(getBoolean, rightAssertions)
{
auto simple = R"({ "boolean": false })"_json;
ASSERT_EQ(getBoolean(valueAt(getObject(simple), "boolean")), false);
}
TEST(getBoolean, wrongAssertions) {
TEST(getBoolean, wrongAssertions)
{
auto json = R"({ "object": {}, "array": [], "string": "", "int": 0, "boolean": false })"_json;
ASSERT_THROW(getBoolean(valueAt(json, "object")), Error);
@ -168,25 +187,29 @@ TEST(getBoolean, wrongAssertions) {
ASSERT_THROW(getBoolean(valueAt(json, "int")), Error);
}
TEST(optionalValueAt, existing) {
TEST(optionalValueAt, existing)
{
auto json = R"({ "string": "ssh-rsa" })"_json;
ASSERT_EQ(optionalValueAt(json, "string"), std::optional { "ssh-rsa" });
ASSERT_EQ(optionalValueAt(json, "string"), std::optional{"ssh-rsa"});
}
TEST(optionalValueAt, empty) {
TEST(optionalValueAt, empty)
{
auto json = R"({})"_json;
ASSERT_EQ(optionalValueAt(json, "string"), std::nullopt);
}
TEST(getNullable, null) {
TEST(getNullable, null)
{
auto json = R"(null)"_json;
ASSERT_EQ(getNullable(json), nullptr);
}
TEST(getNullable, empty) {
TEST(getNullable, empty)
{
auto json = R"({})"_json;
auto * p = getNullable(json);

View file

@ -1,10 +1,10 @@
#if 0
#include "nix/util/logging.hh"
#include "nix/expr/nixexpr.hh"
#include <fstream>
# include "nix/util/logging.hh"
# include "nix/expr/nixexpr.hh"
# include <fstream>
#include <gtest/gtest.h>
# include <gtest/gtest.h>
namespace nix {

View file

@ -3,128 +3,141 @@
namespace nix {
/* ----------------------------------------------------------------------------
* size
* --------------------------------------------------------------------------*/
/* ----------------------------------------------------------------------------
* size
* --------------------------------------------------------------------------*/
TEST(LRUCache, sizeOfEmptyCacheIsZero) {
LRUCache<std::string, std::string> c(10);
ASSERT_EQ(c.size(), 0u);
}
TEST(LRUCache, sizeOfSingleElementCacheIsOne) {
LRUCache<std::string, std::string> c(10);
c.upsert("foo", "bar");
ASSERT_EQ(c.size(), 1u);
}
/* ----------------------------------------------------------------------------
* upsert / get
* --------------------------------------------------------------------------*/
TEST(LRUCache, getFromEmptyCache) {
LRUCache<std::string, std::string> c(10);
auto val = c.get("x");
ASSERT_EQ(val.has_value(), false);
}
TEST(LRUCache, getExistingValue) {
LRUCache<std::string, std::string> c(10);
c.upsert("foo", "bar");
auto val = c.get("foo");
ASSERT_EQ(val, "bar");
}
TEST(LRUCache, getNonExistingValueFromNonEmptyCache) {
LRUCache<std::string, std::string> c(10);
c.upsert("foo", "bar");
auto val = c.get("another");
ASSERT_EQ(val.has_value(), false);
}
TEST(LRUCache, upsertOnZeroCapacityCache) {
LRUCache<std::string, std::string> c(0);
c.upsert("foo", "bar");
auto val = c.get("foo");
ASSERT_EQ(val.has_value(), false);
}
TEST(LRUCache, updateExistingValue) {
LRUCache<std::string, std::string> c(1);
c.upsert("foo", "bar");
auto val = c.get("foo");
ASSERT_EQ(val.value_or("error"), "bar");
ASSERT_EQ(c.size(), 1u);
c.upsert("foo", "changed");
val = c.get("foo");
ASSERT_EQ(val.value_or("error"), "changed");
ASSERT_EQ(c.size(), 1u);
}
TEST(LRUCache, overwriteOldestWhenCapacityIsReached) {
LRUCache<std::string, std::string> c(3);
c.upsert("one", "eins");
c.upsert("two", "zwei");
c.upsert("three", "drei");
ASSERT_EQ(c.size(), 3u);
ASSERT_EQ(c.get("one").value_or("error"), "eins");
// exceed capacity
c.upsert("another", "whatever");
ASSERT_EQ(c.size(), 3u);
// Retrieving "one" makes it the most recent element thus
// two will be the oldest one and thus replaced.
ASSERT_EQ(c.get("two").has_value(), false);
ASSERT_EQ(c.get("another").value(), "whatever");
}
/* ----------------------------------------------------------------------------
* clear
* --------------------------------------------------------------------------*/
TEST(LRUCache, clearEmptyCache) {
LRUCache<std::string, std::string> c(10);
c.clear();
ASSERT_EQ(c.size(), 0u);
}
TEST(LRUCache, clearNonEmptyCache) {
LRUCache<std::string, std::string> c(10);
c.upsert("one", "eins");
c.upsert("two", "zwei");
c.upsert("three", "drei");
ASSERT_EQ(c.size(), 3u);
c.clear();
ASSERT_EQ(c.size(), 0u);
}
/* ----------------------------------------------------------------------------
* erase
* --------------------------------------------------------------------------*/
TEST(LRUCache, eraseFromEmptyCache) {
LRUCache<std::string, std::string> c(10);
ASSERT_EQ(c.erase("foo"), false);
ASSERT_EQ(c.size(), 0u);
}
TEST(LRUCache, eraseMissingFromNonEmptyCache) {
LRUCache<std::string, std::string> c(10);
c.upsert("one", "eins");
ASSERT_EQ(c.erase("foo"), false);
ASSERT_EQ(c.size(), 1u);
ASSERT_EQ(c.get("one").value_or("error"), "eins");
}
TEST(LRUCache, eraseFromNonEmptyCache) {
LRUCache<std::string, std::string> c(10);
c.upsert("one", "eins");
ASSERT_EQ(c.erase("one"), true);
ASSERT_EQ(c.size(), 0u);
ASSERT_EQ(c.get("one").value_or("empty"), "empty");
}
TEST(LRUCache, sizeOfEmptyCacheIsZero)
{
LRUCache<std::string, std::string> c(10);
ASSERT_EQ(c.size(), 0u);
}
TEST(LRUCache, sizeOfSingleElementCacheIsOne)
{
LRUCache<std::string, std::string> c(10);
c.upsert("foo", "bar");
ASSERT_EQ(c.size(), 1u);
}
/* ----------------------------------------------------------------------------
* upsert / get
* --------------------------------------------------------------------------*/
TEST(LRUCache, getFromEmptyCache)
{
LRUCache<std::string, std::string> c(10);
auto val = c.get("x");
ASSERT_EQ(val.has_value(), false);
}
TEST(LRUCache, getExistingValue)
{
LRUCache<std::string, std::string> c(10);
c.upsert("foo", "bar");
auto val = c.get("foo");
ASSERT_EQ(val, "bar");
}
TEST(LRUCache, getNonExistingValueFromNonEmptyCache)
{
LRUCache<std::string, std::string> c(10);
c.upsert("foo", "bar");
auto val = c.get("another");
ASSERT_EQ(val.has_value(), false);
}
TEST(LRUCache, upsertOnZeroCapacityCache)
{
LRUCache<std::string, std::string> c(0);
c.upsert("foo", "bar");
auto val = c.get("foo");
ASSERT_EQ(val.has_value(), false);
}
TEST(LRUCache, updateExistingValue)
{
LRUCache<std::string, std::string> c(1);
c.upsert("foo", "bar");
auto val = c.get("foo");
ASSERT_EQ(val.value_or("error"), "bar");
ASSERT_EQ(c.size(), 1u);
c.upsert("foo", "changed");
val = c.get("foo");
ASSERT_EQ(val.value_or("error"), "changed");
ASSERT_EQ(c.size(), 1u);
}
TEST(LRUCache, overwriteOldestWhenCapacityIsReached)
{
LRUCache<std::string, std::string> c(3);
c.upsert("one", "eins");
c.upsert("two", "zwei");
c.upsert("three", "drei");
ASSERT_EQ(c.size(), 3u);
ASSERT_EQ(c.get("one").value_or("error"), "eins");
// exceed capacity
c.upsert("another", "whatever");
ASSERT_EQ(c.size(), 3u);
// Retrieving "one" makes it the most recent element thus
// two will be the oldest one and thus replaced.
ASSERT_EQ(c.get("two").has_value(), false);
ASSERT_EQ(c.get("another").value(), "whatever");
}
/* ----------------------------------------------------------------------------
* clear
* --------------------------------------------------------------------------*/
TEST(LRUCache, clearEmptyCache)
{
LRUCache<std::string, std::string> c(10);
c.clear();
ASSERT_EQ(c.size(), 0u);
}
TEST(LRUCache, clearNonEmptyCache)
{
LRUCache<std::string, std::string> c(10);
c.upsert("one", "eins");
c.upsert("two", "zwei");
c.upsert("three", "drei");
ASSERT_EQ(c.size(), 3u);
c.clear();
ASSERT_EQ(c.size(), 0u);
}
/* ----------------------------------------------------------------------------
* erase
* --------------------------------------------------------------------------*/
TEST(LRUCache, eraseFromEmptyCache)
{
LRUCache<std::string, std::string> c(10);
ASSERT_EQ(c.erase("foo"), false);
ASSERT_EQ(c.size(), 0u);
}
TEST(LRUCache, eraseMissingFromNonEmptyCache)
{
LRUCache<std::string, std::string> c(10);
c.upsert("one", "eins");
ASSERT_EQ(c.erase("foo"), false);
ASSERT_EQ(c.size(), 1u);
ASSERT_EQ(c.get("one").value_or("error"), "eins");
}
TEST(LRUCache, eraseFromNonEmptyCache)
{
LRUCache<std::string, std::string> c(10);
c.upsert("one", "eins");
ASSERT_EQ(c.erase("one"), true);
ASSERT_EQ(c.size(), 0u);
ASSERT_EQ(c.get("one").value_or("empty"), "empty");
}
} // namespace nix

View file

@ -17,6 +17,6 @@ TEST(MonitorFdHup, shouldNotBlock)
MonitorFdHup monitor(p.readSide.get());
}
}
}
} // namespace nix
#endif

View file

@ -155,4 +155,4 @@ TEST_F(nix_api_util_context, nix_err_code)
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_UNKNOWN);
}
}
} // namespace nixC

View file

@ -3,125 +3,133 @@
namespace nix {
struct TestResource
struct TestResource
{
TestResource()
{
TestResource() {
static int counter = 0;
num = counter++;
}
int dummyValue = 1;
bool good = true;
int num;
};
/* ----------------------------------------------------------------------------
* Pool
* --------------------------------------------------------------------------*/
TEST(Pool, freshPoolHasZeroCountAndSpecifiedCapacity) {
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
ASSERT_EQ(pool.count(), 0u);
ASSERT_EQ(pool.capacity(), 1u);
static int counter = 0;
num = counter++;
}
TEST(Pool, freshPoolCanGetAResource) {
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
int dummyValue = 1;
bool good = true;
int num;
};
Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
ASSERT_EQ(pool.count(), 0u);
/* ----------------------------------------------------------------------------
* Pool
* --------------------------------------------------------------------------*/
TestResource r = *(pool.get());
TEST(Pool, freshPoolHasZeroCountAndSpecifiedCapacity)
{
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t) 1, createResource, isGood);
ASSERT_EQ(pool.count(), 0u);
ASSERT_EQ(pool.capacity(), 1u);
}
TEST(Pool, freshPoolCanGetAResource)
{
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t) 1, createResource, isGood);
ASSERT_EQ(pool.count(), 0u);
TestResource r = *(pool.get());
ASSERT_EQ(pool.count(), 1u);
ASSERT_EQ(pool.capacity(), 1u);
ASSERT_EQ(r.dummyValue, 1);
ASSERT_EQ(r.good, true);
}
TEST(Pool, capacityCanBeIncremented)
{
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t) 1, createResource, isGood);
ASSERT_EQ(pool.capacity(), 1u);
pool.incCapacity();
ASSERT_EQ(pool.capacity(), 2u);
}
TEST(Pool, capacityCanBeDecremented)
{
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t) 1, createResource, isGood);
ASSERT_EQ(pool.capacity(), 1u);
pool.decCapacity();
ASSERT_EQ(pool.capacity(), 0u);
}
TEST(Pool, flushBadDropsOutOfScopeResources)
{
auto isGood = [](const ref<TestResource> & r) { return false; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t) 1, createResource, isGood);
{
auto _r = pool.get();
ASSERT_EQ(pool.count(), 1u);
ASSERT_EQ(pool.capacity(), 1u);
ASSERT_EQ(r.dummyValue, 1);
ASSERT_EQ(r.good, true);
}
TEST(Pool, capacityCanBeIncremented) {
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
pool.flushBad();
ASSERT_EQ(pool.count(), 0u);
}
Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
ASSERT_EQ(pool.capacity(), 1u);
pool.incCapacity();
ASSERT_EQ(pool.capacity(), 2u);
}
// Test that the resources we allocate are being reused when they are still good.
TEST(Pool, reuseResource)
{
auto isGood = [](const ref<TestResource> & r) { return true; };
auto createResource = []() { return make_ref<TestResource>(); };
TEST(Pool, capacityCanBeDecremented) {
auto isGood = [](const ref<TestResource> & r) { return r->good; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t) 1, createResource, isGood);
Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
ASSERT_EQ(pool.capacity(), 1u);
pool.decCapacity();
ASSERT_EQ(pool.capacity(), 0u);
}
// Compare the instance counter between the two handles. We expect them to be equal
// as the pool should hand out the same (still) good one again.
int counter = -1;
{
Pool<TestResource>::Handle h = pool.get();
counter = h->num;
} // the first handle goes out of scope
TEST(Pool, flushBadDropsOutOfScopeResources) {
auto isGood = [](const ref<TestResource> & r) { return false; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
{
auto _r = pool.get();
ASSERT_EQ(pool.count(), 1u);
}
pool.flushBad();
ASSERT_EQ(pool.count(), 0u);
}
// Test that the resources we allocate are being reused when they are still good.
TEST(Pool, reuseResource) {
auto isGood = [](const ref<TestResource> & r) { return true; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
// Compare the instance counter between the two handles. We expect them to be equal
// as the pool should hand out the same (still) good one again.
int counter = -1;
{
Pool<TestResource>::Handle h = pool.get();
counter = h->num;
} // the first handle goes out of scope
{ // the second handle should contain the same resource (with the same counter value)
Pool<TestResource>::Handle h = pool.get();
ASSERT_EQ(h->num, counter);
}
}
// Test that the resources we allocate are being thrown away when they are no longer good.
TEST(Pool, badResourceIsNotReused) {
auto isGood = [](const ref<TestResource> & r) { return false; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
// Compare the instance counter between the two handles. We expect them
// to *not* be equal as the pool should hand out a new instance after
// the first one was returned.
int counter = -1;
{
Pool<TestResource>::Handle h = pool.get();
counter = h->num;
} // the first handle goes out of scope
{
// the second handle should contain a different resource (with a
//different counter value)
Pool<TestResource>::Handle h = pool.get();
ASSERT_NE(h->num, counter);
}
{ // the second handle should contain the same resource (with the same counter value)
Pool<TestResource>::Handle h = pool.get();
ASSERT_EQ(h->num, counter);
}
}
// Test that the resources we allocate are being thrown away when they are no longer good.
TEST(Pool, badResourceIsNotReused)
{
auto isGood = [](const ref<TestResource> & r) { return false; };
auto createResource = []() { return make_ref<TestResource>(); };
Pool<TestResource> pool = Pool<TestResource>((size_t) 1, createResource, isGood);
// Compare the instance counter between the two handles. We expect them
// to *not* be equal as the pool should hand out a new instance after
// the first one was returned.
int counter = -1;
{
Pool<TestResource>::Handle h = pool.get();
counter = h->num;
} // the first handle goes out of scope
{
// the second handle should contain a different resource (with a
// different counter value)
Pool<TestResource>::Handle h = pool.get();
ASSERT_NE(h->num, counter);
}
}
} // namespace nix

View file

@ -15,6 +15,7 @@ TEST(Position, getSnippetUpTo_0)
Pos p(1, 1, o);
ASSERT_EQ(p.getSnippetUpTo(p), "");
}
TEST(Position, getSnippetUpTo_1)
{
Pos::Origin o = makeStdin("x");
@ -56,6 +57,7 @@ TEST(Position, getSnippetUpTo_1)
ASSERT_EQ(end.getSnippetUpTo(start), std::nullopt);
}
}
TEST(Position, getSnippetUpTo_2)
{
Pos::Origin o = makeStdin("asdf\njkl\nqwer");

View file

@ -5,25 +5,27 @@ namespace nix {
using std::string;
struct RewriteParams {
struct RewriteParams
{
string originalString, finalString;
StringMap rewrites;
friend std::ostream& operator<<(std::ostream& os, const RewriteParams& bar) {
friend std::ostream & operator<<(std::ostream & os, const RewriteParams & bar)
{
StringSet strRewrites;
for (auto & [from, to] : bar.rewrites)
strRewrites.insert(from + "->" + to);
return os <<
"OriginalString: " << bar.originalString << std::endl <<
"Rewrites: " << dropEmptyInitThenConcatStringsSep(",", strRewrites) << std::endl <<
"Expected result: " << bar.finalString;
return os << "OriginalString: " << bar.originalString << std::endl
<< "Rewrites: " << dropEmptyInitThenConcatStringsSep(",", strRewrites) << std::endl
<< "Expected result: " << bar.finalString;
}
};
class RewriteTest : public ::testing::TestWithParam<RewriteParams> {
};
class RewriteTest : public ::testing::TestWithParam<RewriteParams>
{};
TEST_P(RewriteTest, IdentityRewriteIsIdentity) {
TEST_P(RewriteTest, IdentityRewriteIsIdentity)
{
RewriteParams param = GetParam();
StringSink rewritten;
auto rewriter = RewritingSink(param.rewrites, rewritten);
@ -36,11 +38,8 @@ INSTANTIATE_TEST_CASE_P(
references,
RewriteTest,
::testing::Values(
RewriteParams{ "foooo", "baroo", {{"foo", "bar"}, {"bar", "baz"}}},
RewriteParams{ "foooo", "bazoo", {{"fou", "bar"}, {"foo", "baz"}}},
RewriteParams{ "foooo", "foooo", {}}
)
);
}
RewriteParams{"foooo", "baroo", {{"foo", "bar"}, {"bar", "baz"}}},
RewriteParams{"foooo", "bazoo", {{"fou", "bar"}, {"foo", "baz"}}},
RewriteParams{"foooo", "foooo", {}}));
} // namespace nix

View file

@ -33,4 +33,4 @@ TEST(SpawnTest, windowsEscape)
ASSERT_EQ(space, R"("hello world")");
}
#endif
}
} // namespace nix

View file

@ -3,41 +3,43 @@
namespace nix {
struct LevenshteinDistanceParam {
std::string s1, s2;
int distance;
};
struct LevenshteinDistanceParam
{
std::string s1, s2;
int distance;
};
class LevenshteinDistanceTest :
public testing::TestWithParam<LevenshteinDistanceParam> {
};
class LevenshteinDistanceTest : public testing::TestWithParam<LevenshteinDistanceParam>
{};
TEST_P(LevenshteinDistanceTest, CorrectlyComputed) {
auto params = GetParam();
TEST_P(LevenshteinDistanceTest, CorrectlyComputed)
{
auto params = GetParam();
ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance);
ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance);
}
INSTANTIATE_TEST_SUITE_P(LevenshteinDistance, LevenshteinDistanceTest,
testing::Values(
LevenshteinDistanceParam{"foo", "foo", 0},
LevenshteinDistanceParam{"foo", "", 3},
LevenshteinDistanceParam{"", "", 0},
LevenshteinDistanceParam{"foo", "fo", 1},
LevenshteinDistanceParam{"foo", "oo", 1},
LevenshteinDistanceParam{"foo", "fao", 1},
LevenshteinDistanceParam{"foo", "abc", 3}
)
);
TEST(Suggestions, Trim) {
auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo");
auto onlyOne = suggestions.trim(1);
ASSERT_EQ(onlyOne.suggestions.size(), 1u);
ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo");
auto closest = suggestions.trim(999, 2);
ASSERT_EQ(closest.suggestions.size(), 3u);
}
ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance);
ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance);
}
INSTANTIATE_TEST_SUITE_P(
LevenshteinDistance,
LevenshteinDistanceTest,
testing::Values(
LevenshteinDistanceParam{"foo", "foo", 0},
LevenshteinDistanceParam{"foo", "", 3},
LevenshteinDistanceParam{"", "", 0},
LevenshteinDistanceParam{"foo", "fo", 1},
LevenshteinDistanceParam{"foo", "oo", 1},
LevenshteinDistanceParam{"foo", "fao", 1},
LevenshteinDistanceParam{"foo", "abc", 3}));
TEST(Suggestions, Trim)
{
auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo");
auto onlyOne = suggestions.trim(1);
ASSERT_EQ(onlyOne.suggestions.size(), 1u);
ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo");
auto closest = suggestions.trim(999, 2);
ASSERT_EQ(closest.suggestions.size(), 3u);
}
} // namespace nix

View file

@ -5,313 +5,338 @@ namespace nix {
/* ----------- tests for url.hh --------------------------------------------------*/
std::string print_map(StringMap m) {
StringMap::iterator it;
std::string s = "{ ";
for (it = m.begin(); it != m.end(); ++it) {
s += "{ ";
s += it->first;
s += " = ";
s += it->second;
s += " } ";
}
s += "}";
return s;
std::string print_map(StringMap m)
{
StringMap::iterator it;
std::string s = "{ ";
for (it = m.begin(); it != m.end(); ++it) {
s += "{ ";
s += it->first;
s += " = ";
s += it->second;
s += " } ";
}
TEST(parseURL, parsesSimpleHttpUrl) {
auto s = "http://www.example.org/file.tar.gz";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "http",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesSimpleHttpsUrl) {
auto s = "https://www.example.org/file.tar.gz";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "https",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesSimpleHttpUrlWithQueryAndFragment) {
auto s = "https://www.example.org/file.tar.gz?download=fast&when=now#hello";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "https",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) { { "download", "fast" }, { "when", "now" } },
.fragment = "hello",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesSimpleHttpUrlWithComplexFragment) {
auto s = "http://www.example.org/file.tar.gz?field=value#?foo=bar%23";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "http",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) { { "field", "value" } },
.fragment = "?foo=bar#",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesFilePlusHttpsUrl) {
auto s = "file+https://www.example.org/video.mp4";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "file+https",
.authority = "www.example.org",
.path = "/video.mp4",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, rejectsAuthorityInUrlsWithFileTransportation) {
auto s = "file://www.example.org/video.mp4";
ASSERT_THROW(parseURL(s), Error);
}
TEST(parseURL, parseIPv4Address) {
auto s = "http://127.0.0.1:8080/file.tar.gz?download=fast&when=now#hello";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "http",
.authority = "127.0.0.1:8080",
.path = "/file.tar.gz",
.query = (StringMap) { { "download", "fast" }, { "when", "now" } },
.fragment = "hello",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseScopedRFC4007IPv6Address) {
auto s = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "http",
.authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
.path = "",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseIPv6Address) {
auto s = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "http",
.authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
.path = "",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseEmptyQueryParams) {
auto s = "http://127.0.0.1:8080/file.tar.gz?&&&&&";
auto parsed = parseURL(s);
ASSERT_EQ(parsed.query, (StringMap) { });
}
TEST(parseURL, parseUserPassword) {
auto s = "http://user:pass@www.example.org:8080/file.tar.gz";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "http",
.authority = "user:pass@www.example.org:8080",
.path = "/file.tar.gz",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseFileURLWithQueryAndFragment) {
auto s = "file:///none/of//your/business";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "file",
.authority = "",
.path = "/none/of//your/business",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsedUrlsIsEqualToItself) {
auto s = "http://www.example.org/file.tar.gz";
auto url = parseURL(s);
ASSERT_TRUE(url == url);
}
TEST(parseURL, parseFTPUrl) {
auto s = "ftp://ftp.nixos.org/downloads/nixos.iso";
auto parsed = parseURL(s);
ParsedURL expected {
.scheme = "ftp",
.authority = "ftp.nixos.org",
.path = "/downloads/nixos.iso",
.query = (StringMap) { },
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesAnythingInUriFormat) {
auto s = "whatever://github.com/NixOS/nixpkgs.git";
auto parsed = parseURL(s);
}
TEST(parseURL, parsesAnythingInUriFormatWithoutDoubleSlash) {
auto s = "whatever:github.com/NixOS/nixpkgs.git";
auto parsed = parseURL(s);
}
TEST(parseURL, emptyStringIsInvalidURL) {
ASSERT_THROW(parseURL(""), Error);
}
/* ----------------------------------------------------------------------------
* decodeQuery
* --------------------------------------------------------------------------*/
TEST(decodeQuery, emptyStringYieldsEmptyMap) {
auto d = decodeQuery("");
ASSERT_EQ(d, (StringMap) { });
}
TEST(decodeQuery, simpleDecode) {
auto d = decodeQuery("yi=one&er=two");
ASSERT_EQ(d, ((StringMap) { { "yi", "one" }, { "er", "two" } }));
}
TEST(decodeQuery, decodeUrlEncodedArgs) {
auto d = decodeQuery("arg=%3D%3D%40%3D%3D");
ASSERT_EQ(d, ((StringMap) { { "arg", "==@==" } }));
}
TEST(decodeQuery, decodeArgWithEmptyValue) {
auto d = decodeQuery("arg=");
ASSERT_EQ(d, ((StringMap) { { "arg", ""} }));
}
/* ----------------------------------------------------------------------------
* percentDecode
* --------------------------------------------------------------------------*/
TEST(percentDecode, decodesUrlEncodedString) {
std::string s = "==@==";
std::string d = percentDecode("%3D%3D%40%3D%3D");
ASSERT_EQ(d, s);
}
TEST(percentDecode, multipleDecodesAreIdempotent) {
std::string once = percentDecode("%3D%3D%40%3D%3D");
std::string twice = percentDecode(once);
ASSERT_EQ(once, twice);
}
TEST(percentDecode, trailingPercent) {
std::string s = "==@==%";
std::string d = percentDecode("%3D%3D%40%3D%3D%25");
ASSERT_EQ(d, s);
}
/* ----------------------------------------------------------------------------
* percentEncode
* --------------------------------------------------------------------------*/
TEST(percentEncode, encodesUrlEncodedString) {
std::string s = percentEncode("==@==");
std::string d = "%3D%3D%40%3D%3D";
ASSERT_EQ(d, s);
}
TEST(percentEncode, keepArgument) {
std::string a = percentEncode("abd / def");
std::string b = percentEncode("abd / def", "/");
ASSERT_EQ(a, "abd%20%2F%20def");
ASSERT_EQ(b, "abd%20/%20def");
}
TEST(percentEncode, inverseOfDecode) {
std::string original = "%3D%3D%40%3D%3D";
std::string once = percentEncode(original);
std::string back = percentDecode(once);
ASSERT_EQ(back, original);
}
TEST(percentEncode, trailingPercent) {
std::string s = percentEncode("==@==%");
std::string d = "%3D%3D%40%3D%3D%25";
ASSERT_EQ(d, s);
}
TEST(percentEncode, yen) {
// https://en.wikipedia.org/wiki/Percent-encoding#Character_data
std::string s = reinterpret_cast<const char*>(u8"");
std::string e = "%E5%86%86";
ASSERT_EQ(percentEncode(s), e);
ASSERT_EQ(percentDecode(e), s);
}
TEST(nix, isValidSchemeName) {
s += "}";
return s;
}
TEST(parseURL, parsesSimpleHttpUrl)
{
auto s = "http://www.example.org/file.tar.gz";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "http",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesSimpleHttpsUrl)
{
auto s = "https://www.example.org/file.tar.gz";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "https",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesSimpleHttpUrlWithQueryAndFragment)
{
auto s = "https://www.example.org/file.tar.gz?download=fast&when=now#hello";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "https",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) {{"download", "fast"}, {"when", "now"}},
.fragment = "hello",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesSimpleHttpUrlWithComplexFragment)
{
auto s = "http://www.example.org/file.tar.gz?field=value#?foo=bar%23";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "http",
.authority = "www.example.org",
.path = "/file.tar.gz",
.query = (StringMap) {{"field", "value"}},
.fragment = "?foo=bar#",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesFilePlusHttpsUrl)
{
auto s = "file+https://www.example.org/video.mp4";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "file+https",
.authority = "www.example.org",
.path = "/video.mp4",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, rejectsAuthorityInUrlsWithFileTransportation)
{
auto s = "file://www.example.org/video.mp4";
ASSERT_THROW(parseURL(s), Error);
}
TEST(parseURL, parseIPv4Address)
{
auto s = "http://127.0.0.1:8080/file.tar.gz?download=fast&when=now#hello";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "http",
.authority = "127.0.0.1:8080",
.path = "/file.tar.gz",
.query = (StringMap) {{"download", "fast"}, {"when", "now"}},
.fragment = "hello",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseScopedRFC4007IPv6Address)
{
auto s = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "http",
.authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080",
.path = "",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseIPv6Address)
{
auto s = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "http",
.authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080",
.path = "",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseEmptyQueryParams)
{
auto s = "http://127.0.0.1:8080/file.tar.gz?&&&&&";
auto parsed = parseURL(s);
ASSERT_EQ(parsed.query, (StringMap) {});
}
TEST(parseURL, parseUserPassword)
{
auto s = "http://user:pass@www.example.org:8080/file.tar.gz";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "http",
.authority = "user:pass@www.example.org:8080",
.path = "/file.tar.gz",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parseFileURLWithQueryAndFragment)
{
auto s = "file:///none/of//your/business";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "file",
.authority = "",
.path = "/none/of//your/business",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsedUrlsIsEqualToItself)
{
auto s = "http://www.example.org/file.tar.gz";
auto url = parseURL(s);
ASSERT_TRUE(url == url);
}
TEST(parseURL, parseFTPUrl)
{
auto s = "ftp://ftp.nixos.org/downloads/nixos.iso";
auto parsed = parseURL(s);
ParsedURL expected{
.scheme = "ftp",
.authority = "ftp.nixos.org",
.path = "/downloads/nixos.iso",
.query = (StringMap) {},
.fragment = "",
};
ASSERT_EQ(parsed, expected);
}
TEST(parseURL, parsesAnythingInUriFormat)
{
auto s = "whatever://github.com/NixOS/nixpkgs.git";
auto parsed = parseURL(s);
}
TEST(parseURL, parsesAnythingInUriFormatWithoutDoubleSlash)
{
auto s = "whatever:github.com/NixOS/nixpkgs.git";
auto parsed = parseURL(s);
}
TEST(parseURL, emptyStringIsInvalidURL)
{
ASSERT_THROW(parseURL(""), Error);
}
/* ----------------------------------------------------------------------------
* decodeQuery
* --------------------------------------------------------------------------*/
TEST(decodeQuery, emptyStringYieldsEmptyMap)
{
auto d = decodeQuery("");
ASSERT_EQ(d, (StringMap) {});
}
TEST(decodeQuery, simpleDecode)
{
auto d = decodeQuery("yi=one&er=two");
ASSERT_EQ(d, ((StringMap) {{"yi", "one"}, {"er", "two"}}));
}
TEST(decodeQuery, decodeUrlEncodedArgs)
{
auto d = decodeQuery("arg=%3D%3D%40%3D%3D");
ASSERT_EQ(d, ((StringMap) {{"arg", "==@=="}}));
}
TEST(decodeQuery, decodeArgWithEmptyValue)
{
auto d = decodeQuery("arg=");
ASSERT_EQ(d, ((StringMap) {{"arg", ""}}));
}
/* ----------------------------------------------------------------------------
* percentDecode
* --------------------------------------------------------------------------*/
TEST(percentDecode, decodesUrlEncodedString)
{
std::string s = "==@==";
std::string d = percentDecode("%3D%3D%40%3D%3D");
ASSERT_EQ(d, s);
}
TEST(percentDecode, multipleDecodesAreIdempotent)
{
std::string once = percentDecode("%3D%3D%40%3D%3D");
std::string twice = percentDecode(once);
ASSERT_EQ(once, twice);
}
TEST(percentDecode, trailingPercent)
{
std::string s = "==@==%";
std::string d = percentDecode("%3D%3D%40%3D%3D%25");
ASSERT_EQ(d, s);
}
/* ----------------------------------------------------------------------------
* percentEncode
* --------------------------------------------------------------------------*/
TEST(percentEncode, encodesUrlEncodedString)
{
std::string s = percentEncode("==@==");
std::string d = "%3D%3D%40%3D%3D";
ASSERT_EQ(d, s);
}
TEST(percentEncode, keepArgument)
{
std::string a = percentEncode("abd / def");
std::string b = percentEncode("abd / def", "/");
ASSERT_EQ(a, "abd%20%2F%20def");
ASSERT_EQ(b, "abd%20/%20def");
}
TEST(percentEncode, inverseOfDecode)
{
std::string original = "%3D%3D%40%3D%3D";
std::string once = percentEncode(original);
std::string back = percentDecode(once);
ASSERT_EQ(back, original);
}
TEST(percentEncode, trailingPercent)
{
std::string s = percentEncode("==@==%");
std::string d = "%3D%3D%40%3D%3D%25";
ASSERT_EQ(d, s);
}
TEST(percentEncode, yen)
{
// https://en.wikipedia.org/wiki/Percent-encoding#Character_data
std::string s = reinterpret_cast<const char *>(u8"");
std::string e = "%E5%86%86";
ASSERT_EQ(percentEncode(s), e);
ASSERT_EQ(percentDecode(e), s);
}
TEST(nix, isValidSchemeName)
{
ASSERT_TRUE(isValidSchemeName("http"));
ASSERT_TRUE(isValidSchemeName("https"));
ASSERT_TRUE(isValidSchemeName("file"));
@ -334,4 +359,4 @@ TEST(nix, isValidSchemeName) {
ASSERT_FALSE(isValidSchemeName("http "));
}
}
} // namespace nix

View file

@ -4,102 +4,101 @@
namespace nix {
/* ----------------------------------------------------------------------------
* XMLWriter
* --------------------------------------------------------------------------*/
/* ----------------------------------------------------------------------------
* XMLWriter
* --------------------------------------------------------------------------*/
TEST(XMLWriter, emptyObject) {
std::stringstream out;
{
XMLWriter t(false, out);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n");
}
TEST(XMLWriter, objectWithEmptyElement) {
std::stringstream out;
{
XMLWriter t(false, out);
t.openElement("foobar");
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar></foobar>");
}
TEST(XMLWriter, objectWithElementWithAttrs) {
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {
{ "foo", "bar" }
};
t.openElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\"></foobar>");
}
TEST(XMLWriter, objectWithElementWithEmptyAttrs) {
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {};
t.openElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar></foobar>");
}
TEST(XMLWriter, objectWithElementWithAttrsEscaping) {
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {
{ "<key>", "<value>" }
};
t.openElement("foobar", attrs);
}
// XXX: While "<value>" is escaped, "<key>" isn't which I think is a bug.
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar <key>=\"&lt;value&gt;\"></foobar>");
}
TEST(XMLWriter, objectWithElementWithAttrsIndented) {
std::stringstream out;
{
XMLWriter t(true, out);
XMLAttrs attrs = {
{ "foo", "bar" }
};
t.openElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\">\n</foobar>\n");
}
TEST(XMLWriter, writeEmptyElement) {
std::stringstream out;
{
XMLWriter t(false, out);
t.writeEmptyElement("foobar");
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar />");
}
TEST(XMLWriter, writeEmptyElementWithAttributes) {
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {
{ "foo", "bar" }
};
t.writeEmptyElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\" />");
TEST(XMLWriter, emptyObject)
{
std::stringstream out;
{
XMLWriter t(false, out);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n");
}
TEST(XMLWriter, objectWithEmptyElement)
{
std::stringstream out;
{
XMLWriter t(false, out);
t.openElement("foobar");
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar></foobar>");
}
TEST(XMLWriter, objectWithElementWithAttrs)
{
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {{"foo", "bar"}};
t.openElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\"></foobar>");
}
TEST(XMLWriter, objectWithElementWithEmptyAttrs)
{
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {};
t.openElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar></foobar>");
}
TEST(XMLWriter, objectWithElementWithAttrsEscaping)
{
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {{"<key>", "<value>"}};
t.openElement("foobar", attrs);
}
// XXX: While "<value>" is escaped, "<key>" isn't which I think is a bug.
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar <key>=\"&lt;value&gt;\"></foobar>");
}
TEST(XMLWriter, objectWithElementWithAttrsIndented)
{
std::stringstream out;
{
XMLWriter t(true, out);
XMLAttrs attrs = {{"foo", "bar"}};
t.openElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\">\n</foobar>\n");
}
TEST(XMLWriter, writeEmptyElement)
{
std::stringstream out;
{
XMLWriter t(false, out);
t.writeEmptyElement("foobar");
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar />");
}
TEST(XMLWriter, writeEmptyElementWithAttributes)
{
std::stringstream out;
{
XMLWriter t(false, out);
XMLAttrs attrs = {{"foo", "bar"}};
t.writeEmptyElement("foobar", attrs);
}
ASSERT_EQ(out.str(), "<?xml version='1.0' encoding='utf-8'?>\n<foobar foo=\"bar\" />");
}
} // namespace nix