#include "fesa/core/status.h" #include #include #include #include #include #include #include namespace { fesa::Diagnostic ModelDiagnostic() { return fesa::Diagnostic{fesa::Severity::kError, "invalid-beam-length", {std::filesystem::path{"beam.inp"}, 12U}, "*ELEMENT", "Beam-1.10", "Beam length must be positive."}; } struct CopyOnlyPayload { explicit CopyOnlyPayload(int initial_value) : value{initial_value} {} CopyOnlyPayload(const CopyOnlyPayload& other) : value{other.value}, copies{other.copies + 1} {} int value; int copies = 0; }; struct TransferPayload { explicit TransferPayload(int initial_value) : value{initial_value} {} TransferPayload(const TransferPayload& other) : value{other.value}, copies{other.copies + 1}, moves{other.moves} {} TransferPayload(TransferPayload&& other) noexcept : value{other.value}, copies{other.copies}, moves{other.moves + 1} { other.value = -1; } int value; int copies = 0; int moves = 0; }; } // namespace TEST(CoreDiagnostics, ResultOwnsCopyOnlyPayloadWithoutIntermediateCopy) { CopyOnlyPayload source{23}; auto result = fesa::Result::Success(source); ASSERT_TRUE(result.HasValue()); EXPECT_TRUE(result.GetStatus().IsOk()); EXPECT_EQ(result.Value().value, 23); EXPECT_EQ(result.Value().copies, 2); result.Value().value = 42; EXPECT_EQ(source.value, 23); EXPECT_EQ(source.copies, 0); } TEST(CoreDiagnostics, ResultTransfersOwnedPayloadDirectlyIntoValue) { TransferPayload source{17}; const auto from_lvalue = fesa::Result::Success(source); EXPECT_EQ(source.value, 17); EXPECT_EQ(source.copies, 0); EXPECT_EQ(source.moves, 0); EXPECT_EQ(from_lvalue.Value().value, 17); EXPECT_EQ(from_lvalue.Value().copies, 1); EXPECT_EQ(from_lvalue.Value().moves, 1); const auto from_temporary = fesa::Result::Success(TransferPayload{29}); EXPECT_EQ(from_temporary.Value().value, 29); EXPECT_EQ(from_temporary.Value().copies, 0); EXPECT_EQ(from_temporary.Value().moves, 1); auto owned = std::make_unique(31); const auto move_only = fesa::Result>::Success(std::move(owned)); EXPECT_EQ(owned, nullptr); ASSERT_NE(move_only.Value(), nullptr); EXPECT_EQ(*move_only.Value(), 31); } TEST(CoreDiagnostics, ResultEnforcesValueErrorExclusivity) { const fesa::Status ok = fesa::Status::Ok(); EXPECT_TRUE(ok.IsOk()); EXPECT_FALSE(ok.Category().has_value()); EXPECT_TRUE(ok.Diagnostics().empty()); const fesa::Status uncategorized = fesa::Status::Failure(std::vector{ModelDiagnostic()}); EXPECT_FALSE(uncategorized.IsOk()); EXPECT_FALSE(uncategorized.Category().has_value()); ASSERT_EQ(uncategorized.Diagnostics().size(), 1U); EXPECT_EQ(uncategorized.Diagnostics()[0].code, "invalid-beam-length"); const fesa::Status categorized = fesa::Status::Failure(fesa::FailureCategory::kModel, std::vector{ModelDiagnostic()}); EXPECT_FALSE(categorized.IsOk()); ASSERT_TRUE(categorized.Category().has_value()); EXPECT_EQ(*categorized.Category(), fesa::FailureCategory::kModel); const auto success = fesa::Result::Success("solved"); EXPECT_TRUE(success.HasValue()); EXPECT_TRUE(success.GetStatus().IsOk()); EXPECT_EQ(success.Value(), "solved"); auto copied = success; EXPECT_EQ(copied.Value(), "solved"); auto moved = std::move(copied); EXPECT_EQ(moved.Value(), "solved"); auto failure = fesa::Result::Failure(categorized); EXPECT_FALSE(failure.HasValue()); EXPECT_FALSE(failure.GetStatus().IsOk()); EXPECT_EQ(failure.GetStatus().Category(), fesa::FailureCategory::kModel); EXPECT_THROW(failure.Value(), std::logic_error); const auto& const_failure = failure; EXPECT_THROW(const_failure.Value(), std::logic_error); EXPECT_THROW((void)fesa::Result::Failure(fesa::Status::Ok()), std::invalid_argument); }