aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl
diff options
context:
space:
mode:
Diffstat (limited to 'nihil.ucl')
-rw-r--r--nihil.ucl/boolean.ccm12
-rw-r--r--nihil.ucl/integer.ccm13
-rw-r--r--nihil.ucl/map.ccm2
-rw-r--r--nihil.ucl/object.ccm5
-rw-r--r--nihil.ucl/real.ccm12
-rw-r--r--nihil.ucl/string.ccm48
-rw-r--r--nihil.ucl/tests/array.cc78
-rw-r--r--nihil.ucl/tests/boolean.cc62
-rw-r--r--nihil.ucl/tests/integer.cc65
-rw-r--r--nihil.ucl/tests/map.cc58
-rw-r--r--nihil.ucl/tests/real.cc32
-rw-r--r--nihil.ucl/tests/string.cc93
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();