diff options
| author | Lexi Winter <lexi@le-fay.org> | 2025-06-30 07:51:23 +0100 |
|---|---|---|
| committer | Lexi Winter <lexi@le-fay.org> | 2025-06-30 07:51:23 +0100 |
| commit | 034cd404a129103a8dd7747e6bd00ffd5550da93 (patch) | |
| tree | d27946517d4d9333abd26ac50bbd4a436093e2ce /nihil.posix/argv.test.cc | |
| parent | 3e7902f7d790a486d3d9cb978df193f07f3a6ad9 (diff) | |
| download | nihil-034cd404a129103a8dd7747e6bd00ffd5550da93.tar.gz nihil-034cd404a129103a8dd7747e6bd00ffd5550da93.tar.bz2 | |
refactoring
Diffstat (limited to 'nihil.posix/argv.test.cc')
| -rw-r--r-- | nihil.posix/argv.test.cc | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/nihil.posix/argv.test.cc b/nihil.posix/argv.test.cc new file mode 100644 index 0000000..3cc218d --- /dev/null +++ b/nihil.posix/argv.test.cc @@ -0,0 +1,256 @@ +/* + * This source code is released into the public domain + */ + +#include <algorithm> +#include <string> +#include <type_traits> +#include <vector> + +#include <catch2/catch_test_macros.hpp> + +import nihil.posix; + +namespace { +constexpr auto *test_tags = "[nihil][nihil.posix][nihil.posix.argv]"; + +TEST_CASE("nihil.posix: argv: invariants", test_tags) +{ + static_assert(std::movable<nihil::argv>); + static_assert(std::move_constructible<nihil::argv>); + static_assert(std::is_nothrow_move_constructible_v<nihil::argv>); + static_assert(std::is_nothrow_move_assignable_v<nihil::argv>); + + static_assert(!std::copy_constructible<nihil::argv>); + + static_assert(std::destructible<nihil::argv>); + + static_assert(std::swappable<nihil::argv>); + static_assert(std::is_nothrow_swappable_v<nihil::argv>); + + static_assert(std::constructible_from<nihil::argv, + std::initializer_list<std::string_view>>); + static_assert(std::constructible_from<nihil::argv, + std::initializer_list<std::string>>); + static_assert(std::constructible_from<nihil::argv, + std::initializer_list<char const *>>); + static_assert(std::constructible_from<nihil::argv, + std::initializer_list<char *>>); + + static_assert(std::ranges::sized_range<nihil::argv>); + static_assert(std::ranges::contiguous_range<nihil::argv>); +} + +SCENARIO("nihil::argv::size() works") +{ + GIVEN("An argv constructed from 3 elements") + { + auto argv = nihil::argv{"one", "two", "three"}; + + THEN("size() returns 4") + { + REQUIRE(std::ranges::size(argv) == 4); + } + } +} + +SCENARIO("nihil::argv::operator[] works") +{ + using namespace std::literals; + + GIVEN("An argv constructed from 3 elements") + { + auto argv = nihil::argv{"one", "two", "three"}; + + THEN("operator[] returns the expected elements") + { + REQUIRE(argv[0] == "one"sv); + REQUIRE(argv[1] == "two"sv); + REQUIRE(argv[2] == "three"sv); + REQUIRE(argv[3] == nullptr); + } + + AND_THEN("operator[] on a non-existent element throws std::out_of_range") + { + REQUIRE_THROWS_AS(argv[4], std::out_of_range); + } + } +} + +SCENARIO("nihil::argv can be constructed from an initializer_list<char const *>") +{ + using namespace std::literals; + + GIVEN("An argv constructed from an initializer_list") + { + auto argv = nihil::argv{"one", "two", "three"}; + + THEN("size() returns 4") + { + REQUIRE(std::ranges::size(argv) == 4); + } + + AND_THEN("The stored values match the initializer_list") + { + REQUIRE(argv[0] == "one"sv); + REQUIRE(argv[1] == "two"sv); + REQUIRE(argv[2] == "three"sv); + REQUIRE(argv[3] == nullptr); + } + } +} + +SCENARIO("nihil::argv can be constructed from an initializer_list<std::string_view>") +{ + using namespace std::literals; + + GIVEN("An argv constructed from an initializer_list") + { + auto argv = nihil::argv{"one"sv, "two"sv, "three"sv}; + + THEN("size() returns 4") + { + REQUIRE(std::ranges::size(argv) == 4); + } + + AND_THEN("The stored values match the initializer_list") + { + REQUIRE(argv[0] == "one"sv); + REQUIRE(argv[1] == "two"sv); + REQUIRE(argv[2] == "three"sv); + REQUIRE(argv[3] == nullptr); + } + } +} + +SCENARIO("nihil::argv can be constructed from a range of std::string") +{ + using namespace std::literals; + + GIVEN("An argv constructed from an initializer_list") + { + auto vec = std::vector{"one"s, "two"s, "three"s}; + auto argv = nihil::argv(std::from_range, vec); + + THEN("size() returns 4") + { + REQUIRE(std::ranges::size(argv) == 4); + } + + AND_THEN("The stored values match the range") + { + REQUIRE(argv[0] == "one"sv); + REQUIRE(argv[1] == "two"sv); + REQUIRE(argv[2] == "three"sv); + REQUIRE(argv[3] == nullptr); + } + } +} + +SCENARIO("nihil::data() returns the correct data") +{ + using namespace std::literals; + + GIVEN("An argv") + { + auto argv = nihil::argv{"one", "two", "three"}; + + THEN("The values in data() match the provided data") + { + REQUIRE(argv.data()[0] == "one"sv); + REQUIRE(argv.data()[1] == "two"sv); + REQUIRE(argv.data()[2] == "three"sv); + REQUIRE(argv.data()[3] == nullptr); + } + } +} + +SCENARIO("nihil::argv can be used as a range") +{ + using namespace std::literals; + + GIVEN("An argv") + { + auto argv = nihil::argv{"one"sv, "two"sv, "three"sv}; + + WHEN("An std::vector is constructed from the argv") + { + auto vec = std::vector(std::from_range, argv); + + THEN("The argv and the vector contain the same data") + { + REQUIRE(std::ranges::equal(argv, vec)); + } + } + + WHEN("The argv is copied to an std::vector using a range-based for") + { + auto vec = std::vector<char *>(); + + for (auto &&arg: argv) + vec.push_back(arg); + + THEN("The argv and the vector contain the same data") + { + REQUIRE(std::ranges::equal(argv, vec)); + } + } + } +} + +SCENARIO("nihil::argv can be move-constructed") +{ + using namespace std::literals; + + GIVEN("An argv object") + { + auto argv = nihil::argv{"one", "two", "three"}; + + WHEN("The argv is moved") + { + auto argv2 = std::move(argv); + + THEN("The new object contains the data") + { + REQUIRE(argv2.size() == 4); + REQUIRE(argv2[0] == "one"sv); + } + + AND_THEN("The old object does not") + { + REQUIRE(argv.size() == 0); + } + } + } +} + +SCENARIO("nihil::argv can be move-assigned") +{ + using namespace std::literals; + + GIVEN("Two argv objects") + { + auto argv1 = nihil::argv{"one", "two", "three"}; + auto argv2 = nihil::argv{"x", "y"}; + + WHEN("argv2 is move-assigned to argv1") + { + argv1 = std::move(argv2); + + THEN("argv1 contains the data from argv2") + { + REQUIRE(argv1.size() == 3); + REQUIRE(argv1[0] == "x"sv); + REQUIRE(argv1[1] == "y"sv); + REQUIRE(argv1[2] == nullptr); + } + + AND_THEN("argv2 is empty") + { + REQUIRE(argv2.size() == 0); + } + } + } +} + +} // anonymous namespace |
