From 0fa623093366351ad47583f47add6e51f56a56d8 Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Mon, 23 Jun 2025 00:32:38 +0100 Subject: nihil.ucl: improve tests --- nihil.ucl/tests/array.cc | 78 ++++++++++++++++++++++++++++++++------ nihil.ucl/tests/boolean.cc | 62 +++++++++++++++++++++++++++++-- nihil.ucl/tests/integer.cc | 65 ++++++++++++++++++++++++++++++-- nihil.ucl/tests/map.cc | 58 +++++++++++++++++++++++++++++ nihil.ucl/tests/real.cc | 32 ++++++++++++++++ nihil.ucl/tests/string.cc | 93 ++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 367 insertions(+), 21 deletions(-) (limited to 'nihil.ucl/tests') diff --git a/nihil.ucl/tests/array.cc b/nihil.ucl/tests/array.cc index 023b3bf..ce0976f 100644 --- a/nihil.ucl/tests/array.cc +++ b/nihil.ucl/tests/array.cc @@ -3,14 +3,36 @@ */ #include +#include #include #include #include +#include import nihil.ucl; -TEST_CASE("ucl: array: construct", "[ucl]") +TEST_CASE("ucl: array: invariants", "[ucl]") +{ + using namespace nihil::ucl; + + REQUIRE(array<>::ucl_type == object_type::array); + REQUIRE(static_cast<::ucl_type>(array<>::ucl_type) == UCL_ARRAY); + + static_assert(std::destructible>); + static_assert(std::default_initializable>); + static_assert(std::move_constructible>); + static_assert(std::copy_constructible>); + static_assert(std::equality_comparable>); + static_assert(std::totally_ordered>); + static_assert(std::swappable>); + + static_assert(std::ranges::sized_range>); + static_assert(std::same_as>, + integer>); +} + +TEST_CASE("ucl: array: default construct", "[ucl]") { using namespace nihil::ucl; @@ -19,6 +41,42 @@ TEST_CASE("ucl: array: construct", "[ucl]") REQUIRE(str(arr.type()) == "array"); } +TEST_CASE("ucl: array: construct from range", "[ucl]") +{ + using namespace nihil::ucl; + + auto vec = std::vector{integer(1), integer(42)}; + auto arr = array(std::from_range, vec); + + REQUIRE(arr.size() == 2); + REQUIRE(arr[0] == 1); + REQUIRE(arr[1] == 42); +} + +TEST_CASE("ucl: array: construct from iterator pair", "[ucl]") +{ + using namespace nihil::ucl; + + auto vec = std::vector{integer(1), integer(42)}; + auto arr = array(std::ranges::begin(vec), + std::ranges::end(vec)); + + REQUIRE(arr.size() == 2); + REQUIRE(arr[0] == 1); + REQUIRE(arr[1] == 42); +} + +TEST_CASE("ucl: array: construct from initializer_list", "[ucl]") +{ + using namespace nihil::ucl; + + auto arr = array{integer(1), integer(42)}; + + REQUIRE(arr.size() == 2); + REQUIRE(arr[0] == 1); + REQUIRE(arr[1] == 42); +} + TEST_CASE("ucl: array: push_back", "[ucl]") { using namespace nihil::ucl; @@ -45,10 +103,9 @@ TEST_CASE("ucl: array: compare", "[ucl]") { using namespace nihil::ucl; - auto arr = array(); - arr.push_back(integer(1)); - arr.push_back(integer(42)); - arr.push_back(integer(666)); + auto arr = array{ + integer(1), integer(42), integer(666) + }; auto arr2 = array(); REQUIRE(arr != arr2); @@ -58,10 +115,10 @@ TEST_CASE("ucl: array: compare", "[ucl]") arr2.push_back(integer(666)); REQUIRE(arr == arr2); - auto arr3 = array(); - arr3.push_back(integer(1)); - arr3.push_back(integer(1)); - arr3.push_back(integer(1)); + auto arr3 = array{ + integer(1), integer(1), integer(1) + }; + REQUIRE(arr != arr3); } @@ -124,7 +181,6 @@ TEST_CASE("ucl: array is a sized_range", "[ucl]") using namespace nihil::ucl; auto arr = array{integer(1), integer(42), integer(666)}; - static_assert(std::ranges::sized_range); auto size = std::ranges::size(arr); REQUIRE(size == 3); @@ -143,7 +199,7 @@ TEST_CASE("ucl: array is a sized_range", "[ucl]") auto arr_as_ints = arr | std::views::transform(&integer::value); - auto int_vec = std::vector(); + auto int_vec = std::vector(); std::ranges::copy(arr_as_ints, std::back_inserter(int_vec)); REQUIRE(int_vec == std::vector{1, 42, 666}); diff --git a/nihil.ucl/tests/boolean.cc b/nihil.ucl/tests/boolean.cc index ed5e1d7..49dc408 100644 --- a/nihil.ucl/tests/boolean.cc +++ b/nihil.ucl/tests/boolean.cc @@ -2,16 +2,29 @@ * This source code is released into the public domain. */ +#include #include #include +#include import nihil.ucl; -TEST_CASE("ucl: boolean: construct", "[ucl]") +TEST_CASE("ucl: boolean: invariants", "[ucl]") { - auto b = nihil::ucl::boolean(true); - REQUIRE(b == true); + using namespace nihil::ucl; + + static_assert(std::same_as); + REQUIRE(boolean::ucl_type == object_type::boolean); + REQUIRE(static_cast<::ucl_type>(boolean::ucl_type) == UCL_BOOLEAN); + + static_assert(std::destructible); + static_assert(std::default_initializable); + static_assert(std::move_constructible); + static_assert(std::copy_constructible); + static_assert(std::equality_comparable); + static_assert(std::totally_ordered); + static_assert(std::swappable); } TEST_CASE("ucl: boolean: default construct", "[ucl]") @@ -20,6 +33,42 @@ TEST_CASE("ucl: boolean: default construct", "[ucl]") REQUIRE(b == false); } +TEST_CASE("ucl: boolean: construct from value", "[ucl]") +{ + auto b = nihil::ucl::boolean(true); + REQUIRE(b == true); +} + +TEST_CASE("ucl: boolean: swap", "[ucl]") +{ + // do not add using namespace nihil::ucl + + auto b1 = nihil::ucl::boolean(true); + auto b2 = nihil::ucl::boolean(false); + + swap(b1, b2); + + REQUIRE(b1 == false); + REQUIRE(b2 == true); +} + +TEST_CASE("ucl: boolean: value()", "[ucl]") +{ + auto b = nihil::ucl::boolean(true); + REQUIRE(b.value() == true); +} + +TEST_CASE("ucl: boolean: key()", "[ucl]") +{ + using namespace nihil::ucl; + + auto obj = parse("a_bool = true"); + REQUIRE(object_cast(obj["a_bool"]).key() == "a_bool"); + + auto b = nihil::ucl::boolean(true); + REQUIRE(b.key() == ""); +} + TEST_CASE("ucl: boolean: operator==", "[ucl]") { auto b = nihil::ucl::boolean(true); @@ -53,6 +102,13 @@ TEST_CASE("ucl: boolean: parse", "[ucl]") } TEST_CASE("ucl: boolean: emit", "[ucl]") +{ + auto b = nihil::ucl::boolean(true); + auto str = std::format("{}", b); + REQUIRE(str == "true"); +} + +TEST_CASE("ucl: boolean: parse and emit", "[ucl]") { auto ucl = nihil::ucl::parse("bool = true;"); diff --git a/nihil.ucl/tests/integer.cc b/nihil.ucl/tests/integer.cc index ad513ca..811a864 100644 --- a/nihil.ucl/tests/integer.cc +++ b/nihil.ucl/tests/integer.cc @@ -2,16 +2,30 @@ * This source code is released into the public domain. */ +#include +#include #include #include +#include import nihil.ucl; -TEST_CASE("ucl: integer: construct", "[ucl]") +TEST_CASE("ucl: integer: invariants", "[ucl]") { - auto i = nihil::ucl::integer(42); - REQUIRE(i == 42); + using namespace nihil::ucl; + + static_assert(std::same_as); + REQUIRE(integer::ucl_type == object_type::integer); + REQUIRE(static_cast<::ucl_type>(integer::ucl_type) == UCL_INT); + + static_assert(std::destructible); + static_assert(std::default_initializable); + static_assert(std::move_constructible); + static_assert(std::copy_constructible); + static_assert(std::equality_comparable); + static_assert(std::totally_ordered); + static_assert(std::swappable); } TEST_CASE("ucl: integer: default construct", "[ucl]") @@ -20,6 +34,42 @@ TEST_CASE("ucl: integer: default construct", "[ucl]") REQUIRE(i == 0); } +TEST_CASE("ucl: integer: construct", "[ucl]") +{ + auto i = nihil::ucl::integer(42); + REQUIRE(i == 42); +} + +TEST_CASE("ucl: integer: swap", "[ucl]") +{ + // do not add using namespace nihil::ucl + + auto i1 = nihil::ucl::integer(1); + auto i2 = nihil::ucl::integer(2); + + swap(i1, i2); + + REQUIRE(i1 == 2); + REQUIRE(i2 == 1); +} + +TEST_CASE("ucl: integer: value()", "[ucl]") +{ + auto i = nihil::ucl::integer(42); + REQUIRE(i.value() == 42); +} + +TEST_CASE("ucl: integer: key()", "[ucl]") +{ + using namespace nihil::ucl; + + auto obj = parse("an_int = 42"); + REQUIRE(object_cast(obj["an_int"]).key() == "an_int"); + + auto i = nihil::ucl::integer(42); + REQUIRE(i.key() == ""); +} + TEST_CASE("ucl: integer: operator==", "[ucl]") { auto i = nihil::ucl::integer(42); @@ -42,7 +92,7 @@ TEST_CASE("ucl: integer: operator<=>", "[ucl]") REQUIRE(i > nihil::ucl::integer(1)); } -TEST_CASE("ucl: parse: integer", "[ucl]") +TEST_CASE("ucl: integer: parse", "[ucl]") { using namespace std::literals; @@ -53,6 +103,13 @@ TEST_CASE("ucl: parse: integer", "[ucl]") } TEST_CASE("ucl: integer: emit", "[ucl]") +{ + auto i = nihil::ucl::integer(42); + auto str = std::format("{}", i); + REQUIRE(str == "42"); +} + +TEST_CASE("ucl: integer: parse and emit", "[ucl]") { auto ucl = nihil::ucl::parse("int = 42;"); diff --git a/nihil.ucl/tests/map.cc b/nihil.ucl/tests/map.cc index d106c79..5d2fbe1 100644 --- a/nihil.ucl/tests/map.cc +++ b/nihil.ucl/tests/map.cc @@ -2,10 +2,33 @@ * This source code is released into the public domain. */ +#include + #include +#include import nihil.ucl; +TEST_CASE("ucl: map: invariants", "[ucl]") +{ + using namespace nihil::ucl; + + REQUIRE(map<>::ucl_type == object_type::object); + REQUIRE(static_cast<::ucl_type>(map<>::ucl_type) == UCL_OBJECT); + + static_assert(std::destructible>); + static_assert(std::default_initializable>); + static_assert(std::move_constructible>); + static_assert(std::copy_constructible>); + static_assert(std::equality_comparable>); + static_assert(std::totally_ordered>); + static_assert(std::swappable>); + + static_assert(std::ranges::range>); + static_assert(std::same_as, + std::ranges::range_value_t>>); +} + TEST_CASE("ucl: map: default construct", "[ucl]") { auto map = nihil::ucl::map<>(); @@ -27,6 +50,41 @@ TEST_CASE("ucl: map: construct from initializer_list", "[ucl]") REQUIRE(map["42"] == 42); } +TEST_CASE("ucl: map: construct from range", "[ucl]") +{ + using namespace nihil::ucl; + using namespace std::literals; + + auto vec = std::vector>{ + {"1"sv, integer(1)}, + {"42"sv, integer(42)}, + }; + + auto map = nihil::ucl::map(std::from_range, vec); + + REQUIRE(str(map.type()) == "object"); + REQUIRE(map["1"] == 1); + REQUIRE(map["42"] == 42); +} + +TEST_CASE("ucl: map: construct from iterator pair", "[ucl]") +{ + using namespace nihil::ucl; + using namespace std::literals; + + auto vec = std::vector>{ + {"1"sv, integer(1)}, + {"42"sv, integer(42)}, + }; + + auto map = nihil::ucl::map(std::ranges::begin(vec), + std::ranges::end(vec)); + + REQUIRE(str(map.type()) == "object"); + REQUIRE(map["1"] == 1); + REQUIRE(map["42"] == 42); +} + TEST_CASE("ucl: map: insert", "[ucl]") { using namespace nihil::ucl; diff --git a/nihil.ucl/tests/real.cc b/nihil.ucl/tests/real.cc index 4bd9b3f..b11c113 100644 --- a/nihil.ucl/tests/real.cc +++ b/nihil.ucl/tests/real.cc @@ -2,13 +2,32 @@ * This source code is released into the public domain. */ +#include #include #include #include +#include import nihil.ucl; +TEST_CASE("ucl: real: invariants", "[ucl]") +{ + using namespace nihil::ucl; + + static_assert(std::same_as); + REQUIRE(real::ucl_type == object_type::real); + REQUIRE(static_cast<::ucl_type>(real::ucl_type) == UCL_FLOAT); + + static_assert(std::destructible); + static_assert(std::default_initializable); + static_assert(std::move_constructible); + static_assert(std::copy_constructible); + static_assert(std::equality_comparable); + static_assert(std::totally_ordered); + static_assert(std::swappable); +} + TEST_CASE("ucl: real: construct", "[ucl]") { auto obj = nihil::ucl::real(42.1); @@ -22,6 +41,19 @@ TEST_CASE("ucl: real: default construct", "[ucl]") REQUIRE(i == 0); } +TEST_CASE("ucl: real: swap", "[ucl]") +{ + // do not add using namespace nihil::ucl + + auto r1 = nihil::ucl::real(1); + auto r2 = nihil::ucl::real(2); + + swap(r1, r2); + + REQUIRE(r1 == 2.); + REQUIRE(r2 == 1.); +} + TEST_CASE("ucl: real: operator==", "[ucl]") { auto i = nihil::ucl::real(42.5); diff --git a/nihil.ucl/tests/string.cc b/nihil.ucl/tests/string.cc index 19052cd..e7eb0ad 100644 --- a/nihil.ucl/tests/string.cc +++ b/nihil.ucl/tests/string.cc @@ -2,6 +2,7 @@ * This source code is released into the public domain. */ +#include #include #include #include @@ -15,9 +16,20 @@ TEST_CASE("ucl: string: invariants", "[ucl]") { using namespace nihil::ucl; - static_assert(std::same_as); + static_assert(std::same_as); REQUIRE(string::ucl_type == object_type::string); REQUIRE(static_cast<::ucl_type>(string::ucl_type) == UCL_STRING); + + static_assert(std::destructible); + static_assert(std::default_initializable); + static_assert(std::move_constructible); + static_assert(std::copy_constructible); + static_assert(std::equality_comparable); + static_assert(std::totally_ordered); + static_assert(std::swappable); + + static_assert(std::ranges::contiguous_range); + static_assert(std::same_as>); } TEST_CASE("ucl: string: default construct", "[ucl]") @@ -74,6 +86,74 @@ TEST_CASE("ucl: string: construct from non-contiguous iterator", "[ucl]") REQUIRE(str == "testing"); } +TEST_CASE("ucl: string: swap", "[ucl]") +{ + // do not add using namespace nihil::ucl + + auto s1 = nihil::ucl::string("one"); + auto s2 = nihil::ucl::string("two"); + + swap(s1, s2); + + REQUIRE(s1 == "two"); + REQUIRE(s2 == "one"); +} + +TEST_CASE("ucl: string: value()", "[ucl]") +{ + auto s = nihil::ucl::string("te\"st"); + REQUIRE(s.value() == "te\"st"); +} + +TEST_CASE("ucl: string: key()", "[ucl]") +{ + using namespace nihil::ucl; + + auto obj = parse("a_string = \"test\""); + REQUIRE(object_cast(obj["a_string"]).key() == "a_string"); + + auto s = nihil::ucl::string("test"); + REQUIRE(s.key() == ""); +} + +TEST_CASE("ucl: string: size", "[ucl]") +{ + using namespace nihil::ucl; + + REQUIRE(string().size() == 0); + REQUIRE(string("test").size() == 4); +} + +TEST_CASE("ucl: string: empty", "[ucl]") +{ + using namespace nihil::ucl; + + REQUIRE(string().empty() == true); + REQUIRE(string("test").empty() == false); +} + +TEST_CASE("ucl: string: iterator", "[ucl]") +{ + auto str = nihil::ucl::string("test"); + + auto begin = std::ranges::begin(str); + static_assert(std::contiguous_iterator); + + auto end = std::ranges::end(str); + static_assert(std::sentinel_for); + + REQUIRE(*begin == 't'); + ++begin; + REQUIRE(*begin == 'e'); + ++begin; + REQUIRE(*begin == 's'); + ++begin; + REQUIRE(*begin == 't'); + ++begin; + + REQUIRE(begin == end); +} + TEST_CASE("ucl: string: operator==", "[ucl]") { auto str = nihil::ucl::string("testing"); @@ -108,13 +188,20 @@ TEST_CASE("ucl: string: parse", "[ucl]") { using namespace std::literals; - auto obj = nihil::ucl::parse("value = \"str\""sv); + auto obj = nihil::ucl::parse("value = \"te\\\"st\""sv); auto v = obj["value"]; REQUIRE(v.key() == "value"); - REQUIRE(object_cast(v) == "str"); + REQUIRE(object_cast(v) == "te\"st"); } TEST_CASE("ucl: string: emit", "[ucl]") +{ + auto s = nihil::ucl::string("te\"st"); + auto str = std::format("{}", s); + REQUIRE(str == "\"te\\\"st\""); +} + +TEST_CASE("ucl: string: parse and emit", "[ucl]") { auto ucl = nihil::ucl::parse("str = \"te\\\"st\";"); -- cgit v1.2.3