diff options
| author | Lexi Winter <lexi@le-fay.org> | 2025-06-23 00:32:38 +0100 |
|---|---|---|
| committer | Lexi Winter <lexi@le-fay.org> | 2025-06-23 00:32:38 +0100 |
| commit | 0fa623093366351ad47583f47add6e51f56a56d8 (patch) | |
| tree | 3eaaa64f5c9b88798d2b971d2810f85cc3e06cd6 /nihil.ucl | |
| parent | 8cbb82a1f6eb6605a4615d30922b777e7bf1e4d8 (diff) | |
| download | nihil-0fa623093366351ad47583f47add6e51f56a56d8.tar.gz nihil-0fa623093366351ad47583f47add6e51f56a56d8.tar.bz2 | |
nihil.ucl: improve tests
Diffstat (limited to 'nihil.ucl')
| -rw-r--r-- | nihil.ucl/boolean.ccm | 12 | ||||
| -rw-r--r-- | nihil.ucl/integer.ccm | 13 | ||||
| -rw-r--r-- | nihil.ucl/map.ccm | 2 | ||||
| -rw-r--r-- | nihil.ucl/object.ccm | 5 | ||||
| -rw-r--r-- | nihil.ucl/real.ccm | 12 | ||||
| -rw-r--r-- | nihil.ucl/string.ccm | 48 | ||||
| -rw-r--r-- | nihil.ucl/tests/array.cc | 78 | ||||
| -rw-r--r-- | nihil.ucl/tests/boolean.cc | 62 | ||||
| -rw-r--r-- | nihil.ucl/tests/integer.cc | 65 | ||||
| -rw-r--r-- | nihil.ucl/tests/map.cc | 58 | ||||
| -rw-r--r-- | nihil.ucl/tests/real.cc | 32 | ||||
| -rw-r--r-- | nihil.ucl/tests/string.cc | 93 |
12 files changed, 436 insertions, 44 deletions
diff --git a/nihil.ucl/boolean.ccm b/nihil.ucl/boolean.ccm index 8510152..6a93867 100644 --- a/nihil.ucl/boolean.ccm +++ b/nihil.ucl/boolean.ccm @@ -18,7 +18,7 @@ import :object; namespace nihil::ucl { export struct boolean final : object { - using value_type = bool; + using contained_type = bool; inline static constexpr object_type ucl_type = object_type::boolean; @@ -41,7 +41,7 @@ export struct boolean final : object { boolean() : boolean(false) {} // Create a new boolean from a value. - explicit boolean(value_type value) + explicit boolean(contained_type value) : object(noref, ::ucl_object_frombool(value)) { if (_object == nullptr) @@ -49,9 +49,9 @@ export struct boolean final : object { } // Return this object's value. - auto value(this boolean const &self) -> value_type + auto value(this boolean const &self) -> contained_type { - auto v = value_type{}; + auto v = contained_type{}; auto const *uobj = self.get_ucl_object(); if (::ucl_object_toboolean_safe(uobj, &v)) @@ -77,13 +77,13 @@ export auto operator<=> (boolean const &a, boolean const &b) return a.value() <=> b.value(); } -export auto operator== (boolean const &a, boolean::value_type b) +export auto operator== (boolean const &a, boolean::contained_type b) -> bool { return a.value() == b; } -export auto operator<=> (boolean const &a, boolean::value_type b) +export auto operator<=> (boolean const &a, boolean::contained_type b) -> std::strong_ordering { return a.value() <=> b; diff --git a/nihil.ucl/integer.ccm b/nihil.ucl/integer.ccm index b58c04d..482a716 100644 --- a/nihil.ucl/integer.ccm +++ b/nihil.ucl/integer.ccm @@ -18,8 +18,7 @@ import :object; namespace nihil::ucl { export struct integer final : object { - using value_type = std::int64_t; - + using contained_type = std::int64_t; inline static constexpr object_type ucl_type = object_type::integer; // Create a new integer from a UCL object. @@ -43,7 +42,7 @@ export struct integer final : object { {} // Create a new integer from a value. - explicit integer(value_type value) + explicit integer(contained_type value) : object(noref, ::ucl_object_fromint(value)) { if (_object == nullptr) @@ -51,9 +50,9 @@ export struct integer final : object { } // Return the value of this object. - auto value(this integer const &self) -> value_type + auto value(this integer const &self) -> contained_type { - auto v = value_type{}; + auto v = contained_type{}; auto const *uobj = self.get_ucl_object(); if (::ucl_object_toint_safe(uobj, &v)) @@ -79,13 +78,13 @@ export auto operator<=> (integer const &a, integer const &b) return a.value() <=> b.value(); } -export auto operator== (integer const &a, integer::value_type b) +export auto operator== (integer const &a, integer::contained_type b) -> bool { return a.value() == b; } -export auto operator<=> (integer const &a, integer::value_type b) +export auto operator<=> (integer const &a, integer::contained_type b) -> std::strong_ordering { return a.value() <=> b; diff --git a/nihil.ucl/map.ccm b/nihil.ucl/map.ccm index b486787..c140885 100644 --- a/nihil.ucl/map.ccm +++ b/nihil.ucl/map.ccm @@ -164,7 +164,7 @@ struct map final : object { value_type>) map(std::from_range_t, Range &&range) : map(std::ranges::begin(range), - std::ranges::end(range)) + std::ranges::end(range)) { } diff --git a/nihil.ucl/object.ccm b/nihil.ucl/object.ccm index 0814125..b220335 100644 --- a/nihil.ucl/object.ccm +++ b/nihil.ucl/object.ccm @@ -137,6 +137,11 @@ protected: // The object we're wrapping. ::ucl_object_t *_object = nullptr; + friend auto swap(object &a, object &b) -> void + { + std::swap(a._object, b._object); + } + private: friend struct parser; diff --git a/nihil.ucl/real.ccm b/nihil.ucl/real.ccm index 51607f2..260e993 100644 --- a/nihil.ucl/real.ccm +++ b/nihil.ucl/real.ccm @@ -17,7 +17,7 @@ import :object; namespace nihil::ucl { export struct real final : object { - using value_type = double; + using contained_type = double; inline static constexpr object_type ucl_type = object_type::real; @@ -42,7 +42,7 @@ export struct real final : object { {} // Create a new real from a value. - explicit real(value_type value) + explicit real(contained_type value) : object(noref, ::ucl_object_fromdouble(value)) { if (_object == nullptr) @@ -50,9 +50,9 @@ export struct real final : object { } // Return the value of this real. - auto value(this real const &self) -> value_type + auto value(this real const &self) -> contained_type { - auto v = value_type{}; + auto v = contained_type{}; auto const *uobj = self.get_ucl_object(); if (::ucl_object_todouble_safe(uobj, &v)) @@ -78,13 +78,13 @@ export auto operator<=> (real const &a, real const &b) return a.value() <=> b.value(); } -export auto operator== (real const &a, real::value_type b) +export auto operator== (real const &a, real::contained_type b) -> bool { return a.value() == b; } -export auto operator<=> (real const &a, real::value_type b) +export auto operator<=> (real const &a, real::contained_type b) -> std::partial_ordering { return a.value() <=> b; diff --git a/nihil.ucl/string.ccm b/nihil.ucl/string.ccm index 64f88dc..f92c82c 100644 --- a/nihil.ucl/string.ccm +++ b/nihil.ucl/string.ccm @@ -17,10 +17,16 @@ import :object; namespace nihil::ucl { export struct string final : object { - using value_type = std::string_view; - + using contained_type = std::string_view; inline static constexpr object_type ucl_type = object_type::string; + using value_type = char const; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type &; + using pointer = value_type *; + using iterator = pointer; + // Create a new string from a UCL object. string(ref_t, ::ucl_object_t const *uobj) : object(nihil::ucl::ref, uobj) @@ -71,7 +77,7 @@ export struct string final : object { {} // Return the value of this string. - auto value(this string const &self) -> value_type + auto value(this string const &self) -> contained_type { char const *dptr{}; std::size_t dlen; @@ -83,6 +89,42 @@ export struct string final : object { // This should never fail. std::abort(); } + + // Return the size of this string. + auto size(this string const &self) -> size_type + { + return self.value().size(); + } + + // Test if this string is empty. + auto empty(this string const &self) -> bool + { + return self.size() == 0; + } + + // Access this string's data + auto data(this string const &self) -> pointer + { + char const *dptr{}; + + auto const *uobj = self.get_ucl_object(); + if (::ucl_object_tostring_safe(uobj, &dptr)) + return dptr; + + // This should never fail. + std::abort(); + } + + // Iterator access + auto begin(this string const &self) -> iterator + { + return self.data(); + } + + auto end(this string const &self) -> iterator + { + return self.data() + self.size(); + } }; /* 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 <algorithm> +#include <concepts> #include <ranges> #include <string> #include <catch2/catch_test_macros.hpp> +#include <ucl.h> 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<array<>>); + static_assert(std::default_initializable<array<>>); + static_assert(std::move_constructible<array<>>); + static_assert(std::copy_constructible<array<>>); + static_assert(std::equality_comparable<array<>>); + static_assert(std::totally_ordered<array<>>); + static_assert(std::swappable<array<>>); + + static_assert(std::ranges::sized_range<array<integer>>); + static_assert(std::same_as<std::ranges::range_value_t<array<integer>>, + 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<integer>(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<integer>(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>{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<integer>(); - arr.push_back(integer(1)); - arr.push_back(integer(42)); - arr.push_back(integer(666)); + auto arr = array<integer>{ + integer(1), integer(42), integer(666) + }; auto arr2 = array<integer>(); REQUIRE(arr != arr2); @@ -58,10 +115,10 @@ TEST_CASE("ucl: array: compare", "[ucl]") arr2.push_back(integer(666)); REQUIRE(arr == arr2); - auto arr3 = array<integer>(); - arr3.push_back(integer(1)); - arr3.push_back(integer(1)); - arr3.push_back(integer(1)); + auto arr3 = array<integer>{ + 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>{integer(1), integer(42), integer(666)}; - static_assert(std::ranges::sized_range<decltype(arr)>); 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<integer::value_type>(); + auto int_vec = std::vector<integer::contained_type>(); std::ranges::copy(arr_as_ints, std::back_inserter(int_vec)); REQUIRE(int_vec == std::vector<std::int64_t>{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 <concepts> #include <string> #include <catch2/catch_test_macros.hpp> +#include <ucl.h> 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<bool, boolean::contained_type>); + REQUIRE(boolean::ucl_type == object_type::boolean); + REQUIRE(static_cast<::ucl_type>(boolean::ucl_type) == UCL_BOOLEAN); + + static_assert(std::destructible<boolean>); + static_assert(std::default_initializable<boolean>); + static_assert(std::move_constructible<boolean>); + static_assert(std::copy_constructible<boolean>); + static_assert(std::equality_comparable<boolean>); + static_assert(std::totally_ordered<boolean>); + static_assert(std::swappable<boolean>); } 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<boolean>(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); @@ -54,6 +103,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;"); auto output = std::string(); 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 <concepts> +#include <cstdint> #include <string> #include <catch2/catch_test_macros.hpp> +#include <ucl.h> 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<std::int64_t, integer::contained_type>); + REQUIRE(integer::ucl_type == object_type::integer); + REQUIRE(static_cast<::ucl_type>(integer::ucl_type) == UCL_INT); + + static_assert(std::destructible<integer>); + static_assert(std::default_initializable<integer>); + static_assert(std::move_constructible<integer>); + static_assert(std::copy_constructible<integer>); + static_assert(std::equality_comparable<integer>); + static_assert(std::totally_ordered<integer>); + static_assert(std::swappable<integer>); } 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<integer>(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; @@ -54,6 +104,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;"); auto output = std::string(); 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 <concepts> + #include <catch2/catch_test_macros.hpp> +#include <ucl.h> 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<map<>>); + static_assert(std::default_initializable<map<>>); + static_assert(std::move_constructible<map<>>); + static_assert(std::copy_constructible<map<>>); + static_assert(std::equality_comparable<map<>>); + static_assert(std::totally_ordered<map<>>); + static_assert(std::swappable<map<>>); + + static_assert(std::ranges::range<map<integer>>); + static_assert(std::same_as<std::pair<std::string_view, integer>, + std::ranges::range_value_t<map<integer>>>); +} + 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<std::pair<std::string_view, integer>>{ + {"1"sv, integer(1)}, + {"42"sv, integer(42)}, + }; + + auto map = nihil::ucl::map<integer>(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<std::pair<std::string_view, integer>>{ + {"1"sv, integer(1)}, + {"42"sv, integer(42)}, + }; + + auto map = nihil::ucl::map<integer>(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 <concepts> #include <string> #include <catch2/catch_test_macros.hpp> #include <catch2/matchers/catch_matchers_floating_point.hpp> +#include <ucl.h> import nihil.ucl; +TEST_CASE("ucl: real: invariants", "[ucl]") +{ + using namespace nihil::ucl; + + static_assert(std::same_as<double, real::contained_type>); + REQUIRE(real::ucl_type == object_type::real); + REQUIRE(static_cast<::ucl_type>(real::ucl_type) == UCL_FLOAT); + + static_assert(std::destructible<real>); + static_assert(std::default_initializable<real>); + static_assert(std::move_constructible<real>); + static_assert(std::copy_constructible<real>); + static_assert(std::equality_comparable<real>); + static_assert(std::totally_ordered<real>); + static_assert(std::swappable<real>); +} + 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 <concepts> #include <list> #include <string> #include <vector> @@ -15,9 +16,20 @@ TEST_CASE("ucl: string: invariants", "[ucl]") { using namespace nihil::ucl; - static_assert(std::same_as<std::string_view, string::value_type>); + static_assert(std::same_as<std::string_view, string::contained_type>); REQUIRE(string::ucl_type == object_type::string); REQUIRE(static_cast<::ucl_type>(string::ucl_type) == UCL_STRING); + + static_assert(std::destructible<string>); + static_assert(std::default_initializable<string>); + static_assert(std::move_constructible<string>); + static_assert(std::copy_constructible<string>); + static_assert(std::equality_comparable<string>); + static_assert(std::totally_ordered<string>); + static_assert(std::swappable<string>); + + static_assert(std::ranges::contiguous_range<string>); + static_assert(std::same_as<char, std::ranges::range_value_t<string>>); } 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<string>(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<decltype(begin)>); + + auto end = std::ranges::end(str); + static_assert(std::sentinel_for<decltype(end), decltype(begin)>); + + 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,14 +188,21 @@ 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<nihil::ucl::string>(v) == "str"); + REQUIRE(object_cast<nihil::ucl::string>(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\";"); auto output = std::string(); |
