Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,15 @@ lint-manual: ## Run all manual tools in pre-commit

.PHONY: coverage
coverage: ## Build and run the tests with the GCOV profile and process the results
coverage: venv
coverage: venv $(_build_path)/CMakeCache.txt
$(ACTIVATE) cmake --build $(_build_path) --config Gcov
$(ACTIVATE) ctest --build-config Gcov --output-on-failure --test-dir $(_build_path)
$(ACTIVATE) cmake --build $(_build_path) --config Gcov --target process_coverage

.PHONY: view-coverage
view-coverage: ## View the coverage report
sensible-browser $(_build_path)/coverage/coverage.html

# Help target
.PHONY: help
help: ## Show this help.
Expand Down
1 change: 1 addition & 0 deletions etc/clang-20-toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ include_guard(GLOBAL)

set(CMAKE_C_COMPILER clang-20)
set(CMAKE_CXX_COMPILER clang++-20)
set(GCOV_EXECUTABLE "llvm-cov-20 gcov" CACHE STRING "GCOV executable" FORCE)

include("${CMAKE_CURRENT_LIST_DIR}/clang-flags.cmake")
1 change: 1 addition & 0 deletions etc/clang-21-toolchain.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ include_guard(GLOBAL)

set(CMAKE_C_COMPILER clang-21)
set(CMAKE_CXX_COMPILER clang++-21)
set(GCOV_EXECUTABLE "llvm-cov-21 gcov" CACHE STRING "GCOV executable" FORCE)

include("${CMAKE_CURRENT_LIST_DIR}/clang-flags.cmake")
2 changes: 1 addition & 1 deletion etc/gcc-flags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ set(CMAKE_CXX_FLAGS_ASAN
)

set(CMAKE_CXX_FLAGS_GCOV
"-O0 -fno-inline -g --coverage -fprofile-abs-path"
"-O0 -fno-default-inline -fno-inline -g --coverage -fprofile-abs-path"
CACHE STRING
"C++ GCOV Flags"
FORCE
Expand Down
118 changes: 118 additions & 0 deletions tests/beman/optional/optional.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,53 @@ TEST(OptionalTest, OptionalOfOptional) {
EXPECT_TRUE(oo2.value() == 43);
}

TEST(OptionalTest, EmplaceVariadic) {
struct for_emplace {
int a;
int b;
int c;
} f{4, 5, 6};

beman::optional::optional<for_emplace> o3;
o3.emplace(1, 2, 3);
EXPECT_TRUE(o3.has_value());

beman::optional::optional<for_emplace> engaged{f};
engaged.emplace(1, 2, 3);
EXPECT_TRUE(engaged.has_value());
EXPECT_EQ(engaged->a, 1);
}

TEST(OptionalTest, EmplaceInitializerList) {
struct for_emplace {
std::vector<int> v; // something to construct with list
std::string name = "";
for_emplace(std::initializer_list<int> l) : v(l) {}
for_emplace(std::initializer_list<int> l, std::string n) : v(l), name(n) {}
} f{{1, 2, 3}};

beman::optional::optional<for_emplace> o3;
o3.emplace({1, 2, 3});
EXPECT_TRUE(o3.has_value());

beman::optional::optional<for_emplace> engaged{f};

auto e1 = engaged.emplace({1, 2, 3});

EXPECT_TRUE(engaged.has_value());
EXPECT_EQ(engaged->v[0], 1);
EXPECT_EQ(engaged->name, std::string(""));
EXPECT_EQ(engaged->v[0], e1.v[0]);
EXPECT_EQ(engaged->name, e1.name);

auto e2 = engaged.emplace({2, 3, 4}, "Name");
EXPECT_TRUE(engaged.has_value());
EXPECT_EQ(engaged->v[0], 2);
EXPECT_EQ(engaged->name, std::string("Name"));
EXPECT_EQ(engaged->v[0], e2.v[0]);
EXPECT_EQ(engaged->name, e2.name);
}

TEST(OptionalTest, AssignmentValue) {
beman::optional::optional<int> o1 = 42;
beman::optional::optional<int> o2 = 12;
Expand Down Expand Up @@ -192,6 +239,15 @@ TEST(OptionalTest, AssignmentValue) {
o1 = s;
EXPECT_TRUE(*o1 == 54);

beman::optional::optional<short> emptyShort;
o1 = emptyShort;
EXPECT_FALSE(o1);

o1 = o4;
EXPECT_TRUE(*o1 == 42);
o1 = std::move(emptyShort);
EXPECT_FALSE(o1);

struct not_trivial_copy_assignable {
int i_;
constexpr not_trivial_copy_assignable(int i) : i_(i) {}
Expand Down Expand Up @@ -243,6 +299,58 @@ TEST(OptionalTest, AssignmentValue) {
EXPECT_FALSE(o8);
}

TEST(OptionalTest, ConvertingAssignmentValue) {
beman::optional::optional<int> o1 = 42;
beman::optional::optional<int> o2;

short s = 9;
o1 = s;
o2 = s;
EXPECT_TRUE(o1);
EXPECT_TRUE(o2);
}

TEST(OptionalTest, ConvertingValueAssignment) {
struct base {};

struct convertible {
operator base() { return base{}; }
};

beman::optional::optional<base> empty;
beman::optional::optional<base> engaged(base{});

empty = convertible{};
engaged = convertible{};
EXPECT_TRUE(empty);
EXPECT_TRUE(engaged);
}

TEST(OptionalTest, ValueObserver) {
beman::optional::optional<int> empty;
beman::optional::optional<int> bound{5};
EXPECT_TRUE(bound);
EXPECT_FALSE(empty);
EXPECT_EQ(*bound, 5);
EXPECT_EQ(bound.value(), 5);
EXPECT_EQ(std::as_const(bound).value(), 5);
EXPECT_EQ(std::move(bound).value(), 5);

EXPECT_THROW(
{
try {
empty.value();
} catch (const beman::optional::bad_optional_access& e) {
EXPECT_STREQ("Optional has no value", e.what());
throw;
}
},
beman::optional::bad_optional_access);

EXPECT_THROW({ std::as_const(empty).value(); }, beman::optional::bad_optional_access);
EXPECT_THROW({ std::move(empty).value(); }, beman::optional::bad_optional_access);
}

TEST(OptionalTest, Triviality) {
EXPECT_TRUE(std::is_trivially_copy_constructible<beman::optional::optional<int>>::value);
EXPECT_TRUE(std::is_trivially_copy_assignable<beman::optional::optional<int>>::value);
Expand Down Expand Up @@ -401,6 +509,16 @@ TEST(OptionalTest, MakeOptional) {
EXPECT_TRUE(o5->v[1] == 1);
EXPECT_TRUE(std::get<0>(o5->t) == 2);
EXPECT_TRUE(std::get<1>(o5->t) == 3);

struct for_variadic {
int a;
int b;
int c;
};

auto o6 = beman::optional::make_optional<for_variadic>(0, 1, 3);
EXPECT_TRUE(o6);
EXPECT_EQ(o6->a, 0);
}

TEST(OptionalTest, Nullopt) {
Expand Down
8 changes: 8 additions & 0 deletions tests/beman/optional/optional_constexpr.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ consteval bool testConstexprAssignmentValue() {
o1 = s;
retval &= (*o1 == 54);

beman::optional::optional<short> emptyShort;
o1 = emptyShort;
retval &= !o1.has_value();

o1 = o4;
o1 = std::move(emptyShort);
retval &= !o1.has_value();

struct not_trivial_copy_assignable {
int i_;
constexpr not_trivial_copy_assignable(int i) : i_(i) {}
Expand Down
85 changes: 77 additions & 8 deletions tests/beman/optional/optional_ref.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ beman::optional::optional<Thing&> process() {
return t;
}

beman::optional::optional<Thing&> processEmpty() { return beman::optional::nullopt; }

TEST(OptionalRefTest, BaseDerivedCastConstruction) {
base b;
derived& dref(b); // ok
Expand Down Expand Up @@ -145,13 +147,76 @@ TEST(OptionalRefTest, Assignment) {
o = process(); // well-formed
EXPECT_TRUE(o);

o = processEmpty(); // well-formed
EXPECT_FALSE(o);

beman::optional::optional<const int&> o2;
EXPECT_FALSE(o2);
o2 = [&]() { return i1; }();

EXPECT_EQ(*o2, 7);
}

TEST(OptionalRefTest, NullOptAssignment) {
beman::optional::optional<int&> i1;
EXPECT_FALSE(i1);
int i = 5;
i1 = i;

EXPECT_TRUE(i1);
i1 = beman::optional::nullopt;
EXPECT_FALSE(i1);
i1 = i;
EXPECT_TRUE(i1);
}

TEST(OptionalRefTest, ConstRefAssignment) {
int i = 7;
beman::optional::optional<int&> i1{i};
const beman::optional::optional<int&> i2 = i1;

beman::optional::optional<const int&> c1;
c1 = i2;
EXPECT_TRUE(c1);
EXPECT_EQ(*c1, 7);

i = 5;
EXPECT_EQ(*c1, 5);
const beman::optional::optional<int&> empty(beman::optional::nullopt);
c1 = empty;
EXPECT_FALSE(c1);
}

TEST(OptionalRefTest, ConvertingConstRvalRef) {
int i = 7;
beman::optional::optional<int&> i1{i};
const beman::optional::optional<int&> i2 = i1;

beman::optional::optional<const int&> c1;
c1 = std::move(i2);
EXPECT_TRUE(c1);
EXPECT_EQ(*c1, 7);

i = 5;
EXPECT_EQ(*c1, 5);
const beman::optional::optional<int&> empty(beman::optional::nullopt);
c1 = std::move(empty);
EXPECT_FALSE(c1);
}

TEST(OptionalRefTest, NullOptConstruction) {
beman::optional::optional<int&> i1(beman::optional::nullopt);
EXPECT_FALSE(i1);
int i = 5;
i1 = i;

EXPECT_TRUE(i1);
i1 = beman::optional::nullopt;
EXPECT_FALSE(i1);
i1 = i;
EXPECT_TRUE(i1);
}

TEST(OptionalRefTest, RelationalOps) {
int i1 = 4;
int i2 = 42;
Expand Down Expand Up @@ -527,17 +592,21 @@ TEST(OptionalRefTest, Observers) {
beman::optional::optional<int_box&> ob1 = i1;
beman::optional::optional<int_box&> ob2;
const beman::optional::optional<int_box&> ob3 = i1;
success = std::is_same<decltype(ob1->i_), int>::value;
static_assert(std::is_same<decltype(ob1->i_), int>::value);

EXPECT_EQ(ob1->i_, 3);
EXPECT_EQ(ob3->i_, 3);

success = std::is_same_v<decltype(ob1->i_), int>;
static_assert(std::is_same_v<decltype(ob1->i_), int>);
EXPECT_TRUE(success);
success = std::is_same<decltype(ob2->i_), int>::value;
static_assert(std::is_same<decltype(ob2->i_), int>::value);
success = std::is_same_v<decltype(ob2->i_), int>;
static_assert(std::is_same_v<decltype(ob2->i_), int>);
EXPECT_TRUE(success);
success = std::is_same<decltype(ob3->i_), int>::value;
static_assert(std::is_same<decltype(ob3->i_), int>::value);
success = std::is_same_v<decltype(ob3->i_), int>;
static_assert(std::is_same_v<decltype(ob3->i_), int>);
EXPECT_TRUE(success);
success = std::is_same<decltype(std::move(ob1)->i_), int>::value;
static_assert(std::is_same<decltype(std::move(ob1)->i_), int>::value);
success = std::is_same_v<decltype(std::move(ob1)->i_), int>;
static_assert(std::is_same_v<decltype(std::move(ob1)->i_), int>);
EXPECT_TRUE(success);
}

Expand Down