diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml new file mode 100644 index 0000000..1d2471c --- /dev/null +++ b/.github/workflows/build-docs.yml @@ -0,0 +1,54 @@ +--- +name: Convert markdown docs to html + +on: + push: + branches: ["master", "develop"] + paths: + - proposal/** + - .github/workflows/build-docs.yml + + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + container: + image: cppalliance/wg21:latest + options: --user 1001 + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Build docs + run: | + set -xe + # list_of_files="draft P3390R0" + list_of_files="draft" + cd proposal + git clone https://github.com/mpark/wg21.git + echo "include wg21/Makefile" > Makefile + for file in $list_of_files; do + make ${file}.html + done + cp generated/* ../docs/ + cd .. + git config --global user.name 'commitbot' + git config --global user.email 'commitbot@example.com' + git add docs/* || true + git commit -m "Docs: update from proposal/ md files" || true + git push + + - name: Trigger Publish Workflow + uses: actions/github-script@v7 + with: + script: | + github.rest.repos.createDispatchEvent({ + owner: context.repo.owner, + repo: context.repo.repo, + event_type: 'publish-trigger', + }); diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index b816dbe..1b39eb0 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -11,6 +11,9 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + repository_dispatch: + types: [publish-trigger] + # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read diff --git a/libsafecxx/single-header/std2.h b/libsafecxx/single-header/std2.h index 1f4f6e4..83c702f 100644 --- a/libsafecxx/single-header/std2.h +++ b/libsafecxx/single-header/std2.h @@ -1,3 +1,9 @@ +// Copyright 2024 Sean Baxter +// Copyright 2024 Christian Mazakas +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once #feature on safety #include @@ -162,7 +168,7 @@ basic_string_view/(a) static constexpr size_type npos = size_type(-1); private: - [[noreturn, safety::panic(panic_code::generic)]] + [[noreturn, noinline, safety::panic(panic_code::generic)]] static void panic_impl(string_constant msg, source_location loc = source_location::current()) safe { @@ -431,7 +437,7 @@ auto operator""sv2(wchar_t const* p, std::size_t len) noexcept safe -> wstring_v // Panic functions are categorized and marked with an safety::panic(N) attribute. // This makes it easy for the frontend to toggle on or off panic calls on a // per-file basis. -[[noreturn, safety::panic(panic_code::generic)]] +[[noreturn, noinline, safety::panic(panic_code::generic)]] inline void panic( str msg, source_location loc = source_location::current()) noexcept safe { @@ -449,7 +455,7 @@ inline void panic( } } -[[noreturn, safety::panic(panic_code::bounds)]] +[[noreturn, noinline, safety::panic(panic_code::bounds)]] inline void panic_bounds( str msg, source_location loc = source_location::current()) noexcept safe { @@ -792,6 +798,10 @@ arc T const^ operator->(self const^) noexcept safe { return ^*self->p_->data_.get(); } + + T const^ operator*(self const^) noexcept safe { + return ^*self->p_->data_.get(); + } }; //////////////////////////////////////////////////////////////////////////////// @@ -817,6 +827,8 @@ box { } + box(box const^) = delete; + [[unsafe::drop_only(T)]] ~box() safe { delete p_; @@ -1684,8 +1696,7 @@ class vector auto* pos = self^.data(); while (pos < end) { - auto t = __rel_read(pos); - drp t; + std::destroy_at(pos); ++pos; } @@ -1785,7 +1796,7 @@ class vector value_type* unsafe p_; size_type capacity_; size_type size_; - // value_type __phantom_data; + value_type __phantom_data; }; template diff --git a/libsafecxx/test/CMakeLists.txt b/libsafecxx/test/CMakeLists.txt index ddcd5f5..87c6515 100644 --- a/libsafecxx/test/CMakeLists.txt +++ b/libsafecxx/test/CMakeLists.txt @@ -109,6 +109,7 @@ add_test(NAME "safecxx-verify-headers" COMMAND "${CMAKE_COMMAND}" --build ${CMAK safe_cxx_compile_fail_test(string_view1 "use of sv depends on expired loan") safe_cxx_compile_fail_test(box_incomplete "class incomplete is incomplete") safe_cxx_compile_fail_test(box1 "cannot convert prvalue int to std2::box") +safe_cxx_compile_fail_test(box2 "call to deleted borrow constructor") safe_cxx_compile_fail_test(arc1 "cannot convert prvalue int to std2::arc") safe_cxx_compile_fail_test(rc1 "cannot convert prvalue int to std2::rc") safe_cxx_compile_fail_test(unsafe_cell1 "cannot convert prvalue std2::box to std2::unsafe_cell>") diff --git a/libsafecxx/test/arc_test.cxx b/libsafecxx/test/arc_test.cxx new file mode 100644 index 0000000..f59a560 --- /dev/null +++ b/libsafecxx/test/arc_test.cxx @@ -0,0 +1,58 @@ +#feature on safety + +#include +#include "lightweight_test.h" + +struct anon_callable/(a, b, c) +{ + std2::string_view/c sv_; + int^/a x_; + int const^/b y_; + + anon_callable( + std2::string_view/c sv, + int^/a x, + int const^/b y) safe + : sv_(sv) + , x_(x) + , y_(y) + { + } + + [[unsafe::drop_only(a, b)]] + ~anon_callable() = default; + + void operator()(self const^) safe + { + self->sv_; + self->x_; + self->y_; + } +}; + +void functor_test() safe +{ + std2::string_view sv = "hello, world!"sv2; + + int a = 1234; + int const b = 4321; + + anon_callable f(sv, ^a, b); + f(); +} + +void drop_only() safe +{ + { + std2::arc p; + { + std2::string s("hello, world!"); + + // TODO: re-enable this test once we get pointer variance working + p = std2::arc(s.str()); + REQUIRE_EQ(*p, "hello, world!"sv2); + } + } +} + +TEST_MAIN(functor_test, drop_only) diff --git a/libsafecxx/test/box_test.cxx b/libsafecxx/test/box_test.cxx index b0df3d3..7626a5c 100644 --- a/libsafecxx/test/box_test.cxx +++ b/libsafecxx/test/box_test.cxx @@ -5,26 +5,26 @@ #feature on safety #include -#include "helpers.h" +#include "lightweight_test.h" void box_constructor() safe { { std2::box p(1337); - assert_eq(mut *p, 1337); - assert_eq(*p, 1337); + REQUIRE_EQ(mut *p, 1337); + REQUIRE_EQ(*p, 1337); // Bind a mutable borrow. int^ x = mut *p; *x = 7331; - assert_eq(*p, 7331); + REQUIRE_EQ(*p, 7331); } { std2::box> p(std2::box(1337)); - assert_eq(**p, 1337); + REQUIRE_EQ(**p, 1337); } } @@ -39,12 +39,25 @@ void unique_ptr_constructor() safe .none => 7331; }; - assert_eq(x, 1337); + REQUIRE_EQ(x, 1337); } -int main() +void drop_only() safe { - box_constructor(); - unique_ptr_constructor(); + { + std2::box p; + + { + std2::string s("hello, world!"); + p = std2::box(s.str()); + REQUIRE_EQ(*p, "hello, world!"sv2); + } + } } + +TEST_MAIN( + box_constructor, + unique_ptr_constructor, + drop_only +); diff --git a/libsafecxx/test/compile-fail/box2.cxx b/libsafecxx/test/compile-fail/box2.cxx new file mode 100644 index 0000000..80adb3b --- /dev/null +++ b/libsafecxx/test/compile-fail/box2.cxx @@ -0,0 +1,13 @@ +// Copyright 2024 Christian Mazakas +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#feature on safety + +#include + +int main() +{ + std2::box p(1234); + auto p2 = cpy p; +} diff --git a/libsafecxx/test/helpers.h b/libsafecxx/test/helpers.h deleted file mode 100644 index dcd26df..0000000 --- a/libsafecxx/test/helpers.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2024 Christian Mazakas -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#pragma once -#feature on safety - -template -void assert_eq(const T^ t, const U^ u) safe -{ - if (*t != *u) throw "unequal values"; -} - -void assert_true(bool b) safe -{ - if (!b) throw "failed boolean assertion"; -} - -template -void assert_throws(F f) safe -{ - bool threw = false; - try { - f(); - } catch(...) { - threw = true; - } - assert_true(threw); -} diff --git a/libsafecxx/test/initializer_list_test.cxx b/libsafecxx/test/initializer_list_test.cxx new file mode 100644 index 0000000..3186d8e --- /dev/null +++ b/libsafecxx/test/initializer_list_test.cxx @@ -0,0 +1,53 @@ +#feature on safety + +#include "lightweight_test.h" + +struct borrow_with_drop/(a) +{ + int x_; + int^/a p_; + + borrow_with_drop(int x, int^/a p) safe + : x_{x} + , p_(p) + { + } + + [[unsafe::drop_only(a)]] + ~borrow_with_drop() safe {} +}; + +void drop_only() safe +{ + { + std2::string s("hello, world!"); + std2::initializer_list list = { s.str() }; + { + REQUIRE_EQ(list.slice()[0], "hello, world!"sv2); + + std2::string s2("rawr"); + mut list.slice()[0] = s2.str(); + } + } + + { + std2::string s("hello, world!"); + std2::initializer_list list = { rel s }; + { + REQUIRE_EQ(list.slice()[0], "hello, world!"sv2); + std2::string s2("rawr"); + mut list.slice()[0] = rel s2; + } + } + + { + int x = 4321; + std2::initializer_list list = { {1234, ^x} }; + { + int y = 1234; + mut list.slice()[0] = borrow_with_drop{4321, ^y}; + } + } +} + +TEST_MAIN(drop_only) diff --git a/libsafecxx/test/lightweight_test.h b/libsafecxx/test/lightweight_test.h new file mode 100644 index 0000000..2f79796 --- /dev/null +++ b/libsafecxx/test/lightweight_test.h @@ -0,0 +1,126 @@ +// Copyright 2024 Christian Mazakas +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once +#feature on safety + +#include + +using namespace std2::literals::string_literals; + +struct failed_assert { + std2::string msg_; + std2::source_location loc_; + + failed_assert(std2::string msg, std2::source_location loc) noexcept safe + : msg_(rel msg) + , loc_(rel loc) + { + } + + // TODO: should this be unsafe? + failed_assert(failed_assert const& rhs) safe + : msg_(cpy rhs->msg_) + , loc_(cpy rhs->loc_) + { + } +}; + +failed_assert +make_failed_assert( + std2::string msg, + std2::source_location loc) safe +{ + return failed_assert(rel msg, rel loc); +} + +template +void require_eq_impl( + T const^ t, U const^ u, + std2::source_location loc = std2::source_location::current()) safe +{ + if (!(*t == *u)) + throw make_failed_assert(std2::string("unequal arguments"), loc); +} + +void require_impl( + bool b, std2::source_location loc = std2::source_location::current()) safe +{ + if (!b) + throw make_failed_assert(std2::string("expected boolean expression was false"), loc); +} + +template +void require_throws_impl(F f, std2::source_location loc = std2::source_location::current()) safe +{ + bool threw = false; + try { + f(); + } catch(...) { + threw = true; + } + + if (!threw) + throw make_failed_assert(std2::string("function didn't throw as expected"), loc); +} + +#define REQUIRE_EQ(x, y) require_eq_impl((x), (y)) +#define REQUIRE(x) require_impl((x)) +#define REQUIRE_THROWS(x) require_throws_impl((x)) + +struct test_runner { + using fp_type = void(*)() safe; + + std2::vector test_fns_; + std2::vector fails_; + + test_runner() safe = default; + + void add_test(self^, fp_type fp) safe { + mut self->test_fns_.push_back(fp); + } + + int run(self) safe { + for (auto fn : self.test_fns_) { + try { + fn(); + } catch(failed_assert const& fa) { + mut self.fails_.push_back(cpy fa); + } + } + + if (self.fails_.size() > 0) { + for (failed_assert const^ fail : self.fails_) { + std2::println("tests failed!"); + unsafe { + printf( + "%.*s at %s(), line %d:%d in %s\n", + fail->msg_.str().size(), fail->msg_.str().data(), + fail->loc_.function_name(), fail->loc_.line(), fail->loc_.column(), + fail->loc_.file_name()); + } + } + unsafe { printf("%llu of %llu tests failed\n", self.fails_.size(), self.test_fns_.size()); }; + unsafe { fflush(stdout); } + drp self; + return 1; + } + + unsafe { printf("%d of %d tests passed\n", self.test_fns_.size(), self.test_fns_.size()); } + drp self; + return 0; + } +}; + +#define TEST_MAIN(...) \ +int main() safe \ +{ \ + using fp_type = void(*)() safe; \ + std2::vector test_fns = { __VA_ARGS__ }; \ + test_runner runner{}; \ + for (auto fn : test_fns) { \ + mut runner.add_test(fn); \ + } \ + return runner rel.run(); \ +} diff --git a/libsafecxx/test/match_test.cxx b/libsafecxx/test/match_test.cxx index ccb1361..dab9fe8 100644 --- a/libsafecxx/test/match_test.cxx +++ b/libsafecxx/test/match_test.cxx @@ -6,7 +6,7 @@ #include -#include "helpers.h" +#include "lightweight_test.h" void simple() safe { @@ -16,7 +16,7 @@ void simple() safe y if y >= 0 => 1337; _ => -1; }; - assert_eq(z, 1337); + REQUIRE_EQ(z, 1337); } @@ -92,28 +92,28 @@ void use_cow() safe }; std2::string_view s = *borrow; - assert_eq(s, std2::string_view("rawr")); + REQUIRE_EQ(s, std2::string_view("rawr")); } { cow str = .owned(std2::string("rawr")); - assert_true(str.is_owned()); - assert_true(!str.is_borrowed()); + REQUIRE(str.is_owned()); + REQUIRE(!str.is_borrowed()); std2::string s = str rel.into_owned(); - assert_eq(s, std2::string_view("rawr")); + REQUIRE_EQ(s, std2::string_view("rawr")); } { std2::string base("rawr"); cow str = .borrowed(^const base); - assert_true(str.is_borrowed()); - assert_true(!str.is_owned()); + REQUIRE(str.is_borrowed()); + REQUIRE(!str.is_owned()); // std2::string^ b = mut str.to_mut(); std2::string s = str rel.into_owned(); - assert_eq(s, std2::string_view("rawr")); + REQUIRE_EQ(s, std2::string_view("rawr")); } { @@ -122,8 +122,4 @@ void use_cow() safe } } -int main() safe -{ - simple(); - use_cow(); -} +TEST_MAIN(simple, use_cow) diff --git a/libsafecxx/test/optional_test.cxx b/libsafecxx/test/optional_test.cxx index b75fd64..0b92f96 100644 --- a/libsafecxx/test/optional_test.cxx +++ b/libsafecxx/test/optional_test.cxx @@ -6,7 +6,7 @@ #include -#include "helpers.h" +#include "lightweight_test.h" class error_code { @@ -21,17 +21,17 @@ void optional_accessors() safe std2::optional mx = .some(-1); std2::expected mx2 = mx.ok_or(error_code{}); - assert_eq(mx2.unwrap(), -1); + REQUIRE_EQ(mx2.unwrap(), -1); } { std2::optional mx = .some(-1); - assert_eq(mx.expect("invalid optional used"), -1); + REQUIRE_EQ(mx.expect("invalid optional used"), -1); } { std2::optional mx = .some(-1); - assert_eq(mx.unwrap(), -1); + REQUIRE_EQ(mx.unwrap(), -1); } { @@ -41,14 +41,14 @@ void optional_accessors() safe std2::vector ys{4, 3, 2, 1, 1, 2, 3, 4}; mp = .some(rel ys); - assert_eq((mp rel.unwrap()).size(), 8u); + REQUIRE_EQ((mp rel.unwrap()).size(), 8u); } { std2::optional> mp = .some(std2::box{1234}); mp = .some(std2::box{4321}); - assert_eq(*(mp rel.unwrap()), 4321); + REQUIRE_EQ(*(mp rel.unwrap()), 4321); } } @@ -58,22 +58,22 @@ void take() safe std2::optional> opt = .some(std2::box{1234}); auto m_p = mut opt.take(); - assert_true(m_p.is_some()); - assert_true(!m_p.is_none()); + REQUIRE(m_p.is_some()); + REQUIRE(!m_p.is_none()); - assert_true(opt.is_none()); - assert_true(!opt.is_some()); + REQUIRE(opt.is_none()); + REQUIRE(!opt.is_some()); } { std2::optional> opt = .none; auto m_p = mut opt.take(); - assert_true(m_p.is_none()); - assert_true(!m_p.is_some()); + REQUIRE(m_p.is_none()); + REQUIRE(!m_p.is_some()); - assert_true(opt.is_none()); - assert_true(!opt.is_some()); + REQUIRE(opt.is_none()); + REQUIRE(!opt.is_some()); } struct C @@ -89,38 +89,34 @@ void take() safe std2::optional opt = .some(1234); auto m_p = mut opt.take_if(addr C::invoke); - assert_true(m_p.is_some()); - assert_true(!m_p.is_none()); + REQUIRE(m_p.is_some()); + REQUIRE(!m_p.is_none()); - assert_true(opt.is_none()); - assert_true(!opt.is_some()); + REQUIRE(opt.is_none()); + REQUIRE(!opt.is_some()); } { std2::optional opt = .some(43211234); auto m_p = mut opt.take_if(addr C::invoke); - assert_true(!m_p.is_some()); - assert_true(m_p.is_none()); + REQUIRE(!m_p.is_some()); + REQUIRE(m_p.is_none()); - assert_true(!opt.is_none()); - assert_true(opt.is_some()); + REQUIRE(!opt.is_none()); + REQUIRE(opt.is_some()); } { std2::optional opt = .none; auto m_p = mut opt.take_if(addr C::invoke); - assert_true(!m_p.is_some()); - assert_true(m_p.is_none()); + REQUIRE(!m_p.is_some()); + REQUIRE(m_p.is_none()); - assert_true(opt.is_none()); - assert_true(!opt.is_some()); + REQUIRE(opt.is_none()); + REQUIRE(!opt.is_some()); } } -int main() safe -{ - // optional_accessors(); - take(); -} +TEST_MAIN(optional_accessors, take) diff --git a/libsafecxx/test/rc_test.cxx b/libsafecxx/test/rc_test.cxx index 0fd146e..55b864b 100644 --- a/libsafecxx/test/rc_test.cxx +++ b/libsafecxx/test/rc_test.cxx @@ -5,14 +5,13 @@ #feature on safety #include - -#include "helpers.h" +#include "lightweight_test.h" void rc_constructor() safe { { std2::rc p{-1}; - assert_eq(*p, -1); + REQUIRE_EQ(*p, -1); } { @@ -20,17 +19,31 @@ void rc_constructor() safe std2::rc p{cell_type{1234}}; auto b = p->borrow(); - assert_eq(*b, 1234); + REQUIRE_EQ(*b, 1234); std2::rc p2 = cpy p; auto b2 = p2->borrow(); - assert_eq(*b2, 1234); + REQUIRE_EQ(*b2, 1234); - assert_eq(addr *b, addr *b2); + REQUIRE_EQ(addr *b, addr *b2); } } -int main() safe +void drop_only() safe { - rc_constructor(); + { + std2::rc p; + { + std2::string s("hello, world!"); + + // TODO: re-enable this test once we get pointer variance working + p = std2::rc(s.str()); + REQUIRE(*p == "hello, world!"sv2); + } + } } + +TEST_MAIN( + rc_constructor, + drop_only +) diff --git a/libsafecxx/test/ref_cell_test.cxx b/libsafecxx/test/ref_cell_test.cxx index e8daa19..ef97653 100644 --- a/libsafecxx/test/ref_cell_test.cxx +++ b/libsafecxx/test/ref_cell_test.cxx @@ -6,7 +6,7 @@ #include -#include "helpers.h" +#include "lightweight_test.h" struct copyable { @@ -22,12 +22,12 @@ void cell_constructor() safe { { std2::cell x{-1}; - assert_eq(x.get(), -1); + REQUIRE_EQ(x.get(), -1); } { std2::cell x{42}; - assert_eq(x.get().x_, 42); + REQUIRE_EQ(x.get().x_, 42); } } @@ -36,11 +36,11 @@ void cell_mutate() safe { std2::cell x{42}; x.set(copyable{24}); - assert_eq(x.get().x_, 24); + REQUIRE_EQ(x.get().x_, 24); auto old = x.replace(copyable{1337}); - assert_eq(old.x_, 24); - assert_eq(x.get().x_, 1337); + REQUIRE_EQ(old.x_, 24); + REQUIRE_EQ(x.get().x_, 1337); } } @@ -49,7 +49,7 @@ void verify_ref(std2::ref_cell::ref h) safe int const^ b1 = *h; int const^ b2 = *h; - assert_eq(b1, b2); + REQUIRE_EQ(b1, b2); // TODO: manual drop here seems to cause a double-free with the match block // drp h; @@ -61,21 +61,21 @@ void ref_cell_constructor() safe { auto m_x = rc.try_borrow(); match (m_x) { - .some(x) => assert_eq(*x, -1); - .none => assert_true(false); + .some(x) => REQUIRE_EQ(*x, -1); + .none => REQUIRE(false); }; auto rc1 = ^const rc; auto m_x1 = rc1.try_borrow(); match (m_x1) { - .some(x) => assert_eq(*x, -1); - .none => assert_true(false); + .some(x) => REQUIRE_EQ(*x, -1); + .none => REQUIRE(false); }; auto rc2 = ^const rc; auto m_x2 = rc2.try_borrow_mut(); match (m_x2) { - .some(x) => assert_true(false); + .some(x) => REQUIRE(false); .none => void(); }; @@ -83,7 +83,7 @@ void ref_cell_constructor() safe auto m_x3 = rc3.try_borrow(); match (m_x3) { .some(x) => verify_ref(rel x); - .none => assert_true(false); + .none => REQUIRE(false); }; } @@ -91,26 +91,26 @@ void ref_cell_constructor() safe auto m_x = rc.try_borrow_mut(); match (m_x) { .some(x) => void(mut *x = 1337); - .none => assert_true(false); + .none => REQUIRE(false); }; auto rc1 = ^const rc; auto m_x1 = rc1.try_borrow(); match (m_x1) { - .some(x) => assert_true(false); + .some(x) => REQUIRE(false); .none => void(); }; auto rc2 = ^const rc; auto m_x2 = rc2.try_borrow_mut(); match (m_x2) { - .some(x) => assert_true(false); + .some(x) => REQUIRE(false); .none => void(); }; } auto^ p = mut rc.get_mut(); - assert_eq(*p, 1337); + REQUIRE_EQ(*p, 1337); } void borrowing() safe @@ -131,10 +131,9 @@ void borrowing() safe } -int main() safe -{ - cell_constructor(); - cell_mutate(); - ref_cell_constructor(); - borrowing(); -} +TEST_MAIN( + cell_constructor, + cell_mutate, + ref_cell_constructor, + borrowing +) diff --git a/libsafecxx/test/source_location_test.cxx b/libsafecxx/test/source_location_test.cxx index 89fce64..95c6c2d 100644 --- a/libsafecxx/test/source_location_test.cxx +++ b/libsafecxx/test/source_location_test.cxx @@ -5,26 +5,12 @@ #feature on safety #include -#include - -template -void assert_eq(const T^ t, const U^ u) safe -{ - if (*t != *u) throw "unequal values"; -} - -void assert_true(bool b) safe -{ - if (!b) throw "failed boolean assertion"; -} +#include "lightweight_test.h" void source_location() safe { - char buf[] = {'l','m','a','o'}; - auto loc = std2::source_location::current(buf); + auto loc = std2::source_location::current(); unsafe { printf("%s\n", loc.file_name()); } } -int main() { - source_location(); -} +TEST_MAIN(source_location) diff --git a/libsafecxx/test/string_test.cxx b/libsafecxx/test/string_test.cxx index ff9db3a..3afa3b2 100644 --- a/libsafecxx/test/string_test.cxx +++ b/libsafecxx/test/string_test.cxx @@ -6,58 +6,58 @@ #include -#include "helpers.h" +#include "lightweight_test.h" void string_constructor() safe { { std2::string s = {}; - assert_eq(s.size(), 0u); - assert_eq(s.capacity(), 0u); + REQUIRE_EQ(s.size(), 0u); + REQUIRE_EQ(s.capacity(), 0u); } { std2::string s("hello, world!"); - assert_eq(s.size(), 13u); - assert_eq(s.capacity(), 13u); - assert_true(s == std2::string_view("hello, world!")); - assert_true(s != std2::string_view("")); + REQUIRE_EQ(s.size(), 13u); + REQUIRE_EQ(s.capacity(), 13u); + REQUIRE(s == std2::string_view("hello, world!")); + REQUIRE(s != std2::string_view("")); } { std2::string s{"hello, world!"}; - assert_eq(s.size(), 13u); - assert_eq(s.capacity(), 13u); - assert_true(s == std2::string_view("hello, world!")); - assert_true(s != std2::string_view("")); + REQUIRE_EQ(s.size(), 13u); + REQUIRE_EQ(s.capacity(), 13u); + REQUIRE(s == std2::string_view("hello, world!")); + REQUIRE(s != std2::string_view("")); } { char const buf[] = "hello, world!"; std2::string s{buf}; - assert_eq(s.size(), 14u); // null terminator - assert_eq(s.capacity(), 14u); - assert_true(s == std2::string_view(buf)); - assert_true(s != std2::string_view("")); + REQUIRE_EQ(s.size(), 14u); // null terminator + REQUIRE_EQ(s.capacity(), 14u); + REQUIRE(s == std2::string_view(buf)); + REQUIRE(s != std2::string_view("")); } { char const buf[] = "hello, world!"; const [char; dyn]^ p_buf = buf; std2::string s{p_buf}; - assert_eq(s.size(), 14u); // null terminator - assert_eq(s.capacity(), 14u); - assert_true(s == std2::string_view(p_buf)); - assert_true(s != std2::string_view("")); + REQUIRE_EQ(s.size(), 14u); // null terminator + REQUIRE_EQ(s.capacity(), 14u); + REQUIRE(s == std2::string_view(p_buf)); + REQUIRE(s != std2::string_view("")); } { std2::string_view sv = "hello, world!"; std2::string s(sv); - assert_eq(s.size(), 13u); - assert_eq(s.capacity(), 13u); - assert_true(s == sv); - assert_true(s != std2::string_view("")); + REQUIRE_EQ(s.size(), 13u); + REQUIRE_EQ(s.capacity(), 13u); + REQUIRE(s == sv); + REQUIRE(s != std2::string_view("")); } } @@ -70,10 +70,10 @@ void string_append() safe std2::string s(sv1); mut s.append(sv2); - assert_eq(s.size(), sv1.size() + sv2.size()); - assert_eq(s.capacity(), s.size()); - assert_eq(s, std2::string_view("if I only had the heart to find out exactly who you are")); - assert_true(s != std2::string_view("")); + REQUIRE_EQ(s.size(), sv1.size() + sv2.size()); + REQUIRE_EQ(s.capacity(), s.size()); + REQUIRE_EQ(s, std2::string_view("if I only had the heart to find out exactly who you are")); + REQUIRE(s != std2::string_view("")); } { @@ -85,10 +85,10 @@ void string_append() safe std2::string s(s1 + s2); - assert_eq(s.size(), sv1.size() + sv2.size()); - assert_eq(s.capacity(), s.size()); - assert_eq(s, std2::string_view("if I only had the heart to find out exactly who you are")); - assert_true(s != std2::string_view("")); + REQUIRE_EQ(s.size(), sv1.size() + sv2.size()); + REQUIRE_EQ(s.capacity(), s.size()); + REQUIRE_EQ(s, std2::string_view("if I only had the heart to find out exactly who you are")); + REQUIRE(s != std2::string_view("")); } } @@ -98,31 +98,30 @@ void literal_test() safe { std2::string s = "hello, world!"s2; - assert_true(s == std2::string_view("hello, world!")); + REQUIRE(s == std2::string_view("hello, world!")); } { std2::u8string s = u8"hello, world!"s2; - assert_true(s == std2::u8string_view(u8"hello, world!")); + REQUIRE(s == std2::u8string_view(u8"hello, world!")); } { std2::u16string s = u"hello, world!"s2; - assert_true(s == std2::u16string_view(u"hello, world!")); + REQUIRE(s == std2::u16string_view(u"hello, world!")); } { std2::u32string s = U"hello, world!"s2; - assert_true(s == std2::u32string_view(U"hello, world!")); + REQUIRE(s == std2::u32string_view(U"hello, world!")); } { std2::wstring s = L"hello, world!"s2; - assert_true(s == std2::wstring_view(L"hello, world!")); + REQUIRE(s == std2::wstring_view(L"hello, world!")); } } -int main() safe -{ - string_constructor(); - string_append(); - literal_test(); -} +TEST_MAIN( + string_constructor, + string_append, + literal_test +) diff --git a/libsafecxx/test/string_view_test.cxx b/libsafecxx/test/string_view_test.cxx index b30ce9d..883ff73 100644 --- a/libsafecxx/test/string_view_test.cxx +++ b/libsafecxx/test/string_view_test.cxx @@ -5,16 +5,16 @@ #feature on safety #include -#include "helpers.h" +#include "lightweight_test.h" void string_view_constructor() safe { std2::string_constant sc = "hello, world!"; std2::string_view sv = sc; - assert_eq(sv.size(), (*sc.text())~length); - assert_eq(sv.data(), (*sc.text())~as_pointer); - assert_true(sv == sc); - assert_true(!(sv != sc)); + REQUIRE_EQ(sv.size(), (*sc.text())~length); + REQUIRE_EQ(sv.data(), (*sc.text())~as_pointer); + REQUIRE(sv == sc); + REQUIRE(!(sv != sc)); } // Encodes ucs into the UTF-8 buffer at s. Returns the number of characters @@ -99,161 +99,161 @@ void string_view_slice_ordinary_utf8_constructor() safe { const [char; dyn]^ str = "rawr"; std2::string_view sv = str; - assert_eq(sv.size(), 5u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 5u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { // outside valid range - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xff }; std2::string_view sv = str; (void)sv; - }); + })); } // 2 byte code points { const [char; dyn]^ str = "£"; std2::string_view sv = str; - assert_eq(sv.size(), 3u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 3u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { char const str[] = { (char)0xcf, (char)0xbf }; std2::string_view sv = str; - assert_eq(sv.size(), 2u); - assert_eq(sv.data(), str); + REQUIRE_EQ(sv.size(), 2u); + REQUIRE_EQ(sv.data(), str); } { // invalid lengths - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xcf }; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid continuation - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xcf, (char)0xcf }; std2::string_view sv = str; (void)sv; - }); + })); } // 3 byte code points { const [char; dyn]^ str = "한"; std2::string_view sv = str; - assert_eq(sv.size(), 4u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 4u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { char const str[] = { (char)0xed, (char)0x95, (char)0x9c }; std2::string_view sv = str; - assert_eq(sv.size(), 3u); - assert_eq(sv.data(), str); + REQUIRE_EQ(sv.size(), 3u); + REQUIRE_EQ(sv.data(), str); } { // invalid length - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xed }; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid length - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xed, (char)0x95 }; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid continuation - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xed, (char)0x95, (char)0xcc }; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid continuation - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xed, (char)0xc5, (char)0x9c }; std2::string_view sv = str; (void)sv; - }); + })); } // 4 byte code points { const [char; dyn]^ str = "𐍈"; std2::string_view sv = str; - assert_eq(sv.size(), 5u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 5u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { char const str[] = { (char)0xf0, (char)0x90, (char)0x8d, (char)0x88, }; std2::string_view sv = str; - assert_eq(sv.size(), 4u); - assert_eq(sv.data(), str); + REQUIRE_EQ(sv.size(), 4u); + REQUIRE_EQ(sv.data(), str); } { // invalid length - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xf0}; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid length - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xf0, (char)0x90, }; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid continuation - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xf0, (char)0xc0, (char)0x8d, (char)0x88, }; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid continuation - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xf0, (char)0x90, (char)0xcd, (char)0x88, }; std2::string_view sv = str; (void)sv; - }); + })); } { // invalid continuation - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { char const str[] = { (char)0xf0, (char)0x90, (char)0x8d, (char)0xc8, }; std2::string_view sv = str; (void)sv; - }); + })); } // prove we can parse the entire utf space @@ -261,11 +261,11 @@ void string_view_slice_ordinary_utf8_constructor() safe for (char32_t i = 0; i <= 0x10ffff; ++i) { [char; 4] buf = {}; auto str = to_utf8(^buf, i); - assert_true((*str)~length > 0); + REQUIRE((*str)~length > 0); std2::string_view sv = str; - assert_true(sv.size() > 0u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE(sv.size() > 0u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } } @@ -273,8 +273,8 @@ void string_view_slice_ordinary_utf8_constructor() safe const [char; dyn]^ str = "$£Иह€한𐍈"; std2::string_view sv = str; - assert_eq(sv.size(), 19u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 19u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } } @@ -284,8 +284,8 @@ void string_view_slice_utf8_constructor() safe { const [char8_t; dyn]^ str = u8"rawr"; std2::u8string_view sv = str; - assert_eq(sv.size(), 5u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 5u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } } @@ -295,87 +295,87 @@ void string_view_slice_utf16_constructor() safe { const [char16_t; dyn]^ str = u"rawr"; std2::u16string_view sv = str; - assert_eq(sv.size(), 5u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 5u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { const char16_t str[] = { (char16_t)0xffff }; std2::u16string_view sv = str; - assert_eq(sv.size(), 1u); - assert_eq(sv.data(), str); + REQUIRE_EQ(sv.size(), 1u); + REQUIRE_EQ(sv.data(), str); } { const char16_t str[] = { (char16_t)0xfffe }; std2::u16string_view sv = str; - assert_eq(sv.size(), 1u); - assert_eq(sv.data(), str); + REQUIRE_EQ(sv.size(), 1u); + REQUIRE_EQ(sv.data(), str); } { const char16_t str[] = { (char16_t)0xfeff }; std2::u16string_view sv = str; - assert_eq(sv.size(), 1u); - assert_eq(sv.data(), str); + REQUIRE_EQ(sv.size(), 1u); + REQUIRE_EQ(sv.data(), str); } { const [char16_t; dyn]^ str = u"€"; std2::u16string_view sv = str; - assert_eq(sv.size(), 2u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 2u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { const [char16_t; dyn]^ str = u"𐐷"; std2::u16string_view sv = str; - assert_eq(sv.size(), 3u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 3u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { const char16_t str[] = { (char16_t)0xd801, (char16_t)0xdc37 }; std2::u16string_view sv = str; - assert_eq(sv.size(), 2u); - assert_eq(sv.data(), str); + REQUIRE_EQ(sv.size(), 2u); + REQUIRE_EQ(sv.data(), str); } { // length error - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { const char16_t str[] = { (char16_t)0xd801 }; std2::u16string_view sv = str; (void)sv; - }); + })); } { // invalid leading surrogate - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { const char16_t str[] = { (char16_t)0xf801, (char16_t)0xdc37 }; std2::u16string_view sv = str; (void)sv; - }); + })); } { // invalid trailing surrogate - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { const char16_t str[] = { (char16_t)0xd801, (char16_t)0xfc37 }; std2::u16string_view sv = str; (void)sv; - }); + })); } { const [char16_t; dyn]^ str = u"𤭢"; std2::u16string_view sv = str; - assert_eq(sv.size(), 3u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 3u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } // prove we can parse the entire utf space @@ -385,11 +385,11 @@ void string_view_slice_utf16_constructor() safe [char16_t; 2] buf = {}; auto str = to_utf16(^buf, i); - assert_true((*str)~length > 0); + REQUIRE((*str)~length > 0); std2::u16string_view sv = str; - assert_true(sv.size() > 0u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE(sv.size() > 0u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } } @@ -397,24 +397,24 @@ void string_view_slice_utf16_constructor() safe const [char16_t; dyn]^ str = u"$€𐐷𤭢"; std2::u16string_view sv = str; - assert_eq(sv.size(), 7u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 7u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { const char16_t str[] = { (char16_t)0xd800 }; std2::u16string_view sv = str; (void)sv; - }); + })); } { - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { const char16_t str[] = { (char16_t)0xdfff }; std2::u16string_view sv = str; (void)sv; - }); + })); } } @@ -428,25 +428,25 @@ void string_view_slice_utf32_constructor() safe const char32_t str[] = { i }; std2::u32string_view sv = str; - assert_true(sv.size() > 0u); - assert_eq(sv.data(), str); + REQUIRE(sv.size() > 0u); + REQUIRE_EQ(sv.data(), str); } } { - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { const char32_t str[] = { (char32_t)0xd800 }; std2::u32string_view sv = str; (void)sv; - }); + })); } { - assert_throws([]() safe { + REQUIRE_THROWS(([]() safe { const char32_t str[] = { (char32_t)0xdfff }; std2::u32string_view sv = str; (void)sv; - }); + })); } } @@ -456,15 +456,15 @@ void string_view_slice_wstring_constructor() safe { const [wchar_t; dyn]^ str = L"rawr"; std2::wstring_view sv = str; - assert_eq(sv.size(), 5u); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE_EQ(sv.size(), 5u); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } { const [wchar_t; dyn]^ str = L"한"; std2::wstring_view sv = str; - assert_true(sv.size() > 0); - assert_eq(sv.data(), (*str)~as_pointer); + REQUIRE(sv.size() > 0); + REQUIRE_EQ(sv.data(), (*str)~as_pointer); } } @@ -476,8 +476,8 @@ void string_view_compare() safe std2::string_view sv1 = str; std2::string_view sv2 = str; - assert_true(sv1 == sv2); - assert_true(!(sv1 != sv2)); + REQUIRE(sv1 == sv2); + REQUIRE(!(sv1 != sv2)); } { @@ -487,8 +487,8 @@ void string_view_compare() safe std2::string_view sv1 = str1; std2::string_view sv2 = str2; - assert_true(sv1 != sv2); - assert_true(!(sv1 == sv2)); + REQUIRE(sv1 != sv2); + REQUIRE(!(sv1 == sv2)); } } @@ -500,8 +500,8 @@ void string_view_slice() safe auto s = sv.slice(); - assert_eq((*s)~length, sv.size()); - assert_eq((*s)~as_pointer, sv.data()); + REQUIRE_EQ((*s)~length, sv.size()); + REQUIRE_EQ((*s)~as_pointer, sv.data()); } } @@ -511,39 +511,38 @@ void literal_test() safe { std2::string_view sv = "hello, world!"sv2; - assert_true(sv == std2::string_view("hello, world!")); + REQUIRE(sv == std2::string_view("hello, world!")); } { std2::u8string_view sv = u8"hello, world!"sv2; - assert_true(sv == std2::u8string_view(u8"hello, world!")); + REQUIRE(sv == std2::u8string_view(u8"hello, world!")); } { std2::u16string_view sv = u"hello, world!"sv2; - assert_true(sv == std2::u16string_view(u"hello, world!")); + REQUIRE(sv == std2::u16string_view(u"hello, world!")); } { std2::u32string_view sv = U"hello, world!"sv2; - assert_true(sv == std2::u32string_view(U"hello, world!")); + REQUIRE(sv == std2::u32string_view(U"hello, world!")); } { std2::wstring_view sv = L"hello, world!"sv2; - assert_true(sv == std2::wstring_view(L"hello, world!")); + REQUIRE(sv == std2::wstring_view(L"hello, world!")); } } -int main() safe -{ - string_view_constructor(); - string_view_slice_ordinary_utf8_constructor(); - string_view_slice_utf8_constructor(); - string_view_slice_utf16_constructor(); - string_view_slice_utf32_constructor(); - string_view_slice_wstring_constructor(); - string_view_compare(); - string_view_slice(); - literal_test(); -} +TEST_MAIN( + string_view_constructor, + string_view_slice_ordinary_utf8_constructor, + string_view_slice_utf8_constructor, + string_view_slice_utf16_constructor, + string_view_slice_utf32_constructor, + string_view_slice_wstring_constructor, + string_view_compare, + string_view_slice, + literal_test +) diff --git a/libsafecxx/test/thread_test.cxx b/libsafecxx/test/thread_test.cxx index 68c2288..35aa5a6 100644 --- a/libsafecxx/test/thread_test.cxx +++ b/libsafecxx/test/thread_test.cxx @@ -8,7 +8,7 @@ #include -#include "helpers.h" +#include "lightweight_test.h" int add(std2::arc> mtx, int x, int y) safe { @@ -67,7 +67,7 @@ void thread_constructor() safe std2::thread t(add, cpy mtx, 1, 2); int r = *mtx->lock(); - if (r != 1337) assert_eq(r, 1 + 2); + if (r != 1337) REQUIRE_EQ(r, 1 + 2); t rel.join(); } @@ -124,7 +124,7 @@ void mutex_test() safe int const val = *sp->lock()^.borrow(); auto const expected = num_threads * 10'000; - assert_eq(val, expected); + REQUIRE_EQ(val, expected); } void shared_mutex_test() safe @@ -189,12 +189,11 @@ void shared_mutex_test() safe t rel.join(); } - assert_eq(**sp->lock_shared(), value); + REQUIRE_EQ(**sp->lock_shared(), value); } -int main() safe -{ - thread_constructor(); - mutex_test(); - shared_mutex_test(); -} +TEST_MAIN( + thread_constructor, + mutex_test, + shared_mutex_test +) diff --git a/libsafecxx/test/vector_test.cxx b/libsafecxx/test/vector_test.cxx index c98e04d..2936e22 100644 --- a/libsafecxx/test/vector_test.cxx +++ b/libsafecxx/test/vector_test.cxx @@ -7,44 +7,44 @@ #include #include -#include "helpers.h" +#include "lightweight_test.h" void vector_constructor() safe { { std2::vector vec{}; - assert_eq(vec.size(), 0u); + REQUIRE_EQ(vec.size(), 0u); vec^.push_back(1); vec^.push_back(2); vec^.push_back(3); - assert_eq(vec.size(), 3u); + REQUIRE_EQ(vec.size(), 3u); { auto s = vec^.slice(); - assert_eq(s[0], 1); - assert_eq(s[1], 2); - assert_eq(s[2], 3); + REQUIRE_EQ(s[0], 1); + REQUIRE_EQ(s[1], 2); + REQUIRE_EQ(s[2], 3); s[0] = 17; - assert_eq((^vec)[0], 17); + REQUIRE_EQ((^vec)[0], 17); (^vec)[0] = 4; - assert_eq(vec[0], 4); + REQUIRE_EQ(vec[0], 4); } { auto s = vec.slice(); - assert_eq(s[0], 4); - assert_eq(s[1], 2); - assert_eq(s[2], 3); + REQUIRE_EQ(s[0], 4); + REQUIRE_EQ(s[1], 2); + REQUIRE_EQ(s[2], 3); } { const std2::vector^ v = ^vec; const int^ x = v[0]; - assert_eq(*x, 4); + REQUIRE_EQ(*x, 4); } } @@ -53,17 +53,17 @@ void vector_constructor() safe { std2::vector vec = {}; vec^.push_back(^x); - assert_eq(vec.size(), 1u); + REQUIRE_EQ(vec.size(), 1u); { const [int^; dyn]^ elems = vec.slice(); - assert_eq(*elems[0], 1); + REQUIRE_EQ(*elems[0], 1); } [int^; dyn]^ elems = (^vec).slice(); *elems[0] = 20; } - assert_eq(x, 20); + REQUIRE_EQ(x, 20); } { @@ -72,31 +72,31 @@ void vector_constructor() safe int^ p = ^x; std2::vector vec = {}; vec^.push_back(^p); - assert_eq(vec.size(), 1u); + REQUIRE_EQ(vec.size(), 1u); int^ const^ q = vec.slice()[0]; (void)q; - assert_eq(**q, 1); + REQUIRE_EQ(**q, 1); } } { std2::vector xs = { 1, 2, 3, 4, 5 }; - assert_eq(xs.size(), 5u); + REQUIRE_EQ(xs.size(), 5u); for (int i = 0; i < 5; ++i) { auto idx = static_cast(i); - assert_eq(xs[idx], i + 1); + REQUIRE_EQ(xs[idx], i + 1); } } { std2::vector> xs = { std2::box(1), std2::box(2), std2::box(3), std2::box(4), std2::box(5) }; - assert_eq(xs.size(), 5u); + REQUIRE_EQ(xs.size(), 5u); for (int i = 0; i < 5; ++i) { auto idx = static_cast(i); - assert_eq(*xs[idx], i + 1); + REQUIRE_EQ(*xs[idx], i + 1); } } } @@ -122,8 +122,8 @@ void vector_iterator() safe .none => true; .some(x) => false; }; - assert_true(v.empty()); - assert_true(b); + REQUIRE(v.empty()); + REQUIRE(b); v^.push_back(1); v^.push_back(2); @@ -131,14 +131,14 @@ void vector_iterator() safe v^.push_back(4); v^.push_back(5); - assert_eq(v.size(), 5u); + REQUIRE_EQ(v.size(), 5u); int sum = 0; for (int x : v.iter()) { sum += x; } - assert_eq(sum, 1 + 2 + 3 + 4 + 5); + REQUIRE_EQ(sum, 1 + 2 + 3 + 4 + 5); } } @@ -157,11 +157,11 @@ void vector_string_view() safe strs^.push_back(sv2); strs^.push_back(sv3); - assert_eq(strs.size(), 3u); + REQUIRE_EQ(strs.size(), 3u); const std2::vector^ v = ^strs; const std2::string_view^ sv = v[0]; - assert_eq(sv, sv1); + REQUIRE_EQ(sv, sv1); } void vector_box() safe @@ -172,13 +172,25 @@ void vector_box() safe xs^.push_back(std2::box(1)); } - assert_eq(xs.size(), 16u); + REQUIRE_EQ(xs.size(), 16u); } -int main() +void drop_only() safe { - vector_constructor(); - vector_iterator(); - vector_string_view(); - vector_box(); + { + std2::vector p; + { + std2::string s("hello, world!"); + p = {s.str()}; + REQUIRE(p[0] == "hello, world!"sv2); + } + } } + +TEST_MAIN( + vector_constructor, + vector_iterator, + vector_string_view, + vector_box, + drop_only +)