Skip to content

Commit ca2f1ea

Browse files
authored
Merge pull request #4 from threeal/add-result
Add Result
2 parents c5f27a8 + 7ce6678 commit ca2f1ea

File tree

5 files changed

+131
-3
lines changed

5 files changed

+131
-3
lines changed

CMakeLists.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
cmake_minimum_required(VERSION 3.14)
22

33
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
4+
set(CMAKE_CXX_STANDARD 17)
45

56
project(result)
67

8+
add_library(result INTERFACE)
9+
target_include_directories(result INTERFACE include)
10+
711
if(BUILD_TESTING)
812
enable_testing()
913
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -coverage")
1014

1115
find_package(Catch2 REQUIRED)
1216

1317
add_executable(result_test test/result_test.cpp)
14-
target_link_libraries(result_test PRIVATE Catch2::Catch2WithMain)
18+
target_link_libraries(result_test PRIVATE result Catch2::Catch2WithMain)
1519
catch_discover_tests(result_test)
1620
endif()

include/result/internal/err_msg.hpp

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <memory>
4+
#include <string>
5+
6+
namespace res::internal {
7+
8+
using ErrMsg = std::string;
9+
using ErrMsgPtr = std::shared_ptr<ErrMsg>;
10+
11+
ErrMsgPtr uninitialized_err_msg_ptr = std::make_shared<ErrMsg>("result is uninitialized");
12+
}

include/result/internal/ok.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
namespace res {
4+
5+
namespace internal { struct Ok {}; }
6+
constexpr internal::Ok ok = {};
7+
}

include/result/result.hpp

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
#include "internal/err_msg.hpp"
4+
#include "internal/ok.hpp"
5+
#include <exception>
6+
#include <memory>
7+
8+
namespace res {
9+
10+
class Result {
11+
private:
12+
internal::ErrMsgPtr err_msg_ptr;
13+
public:
14+
Result() : err_msg_ptr(internal::uninitialized_err_msg_ptr) {}
15+
Result(const internal::Ok& ok) {}
16+
Result(const internal::ErrMsgPtr& err_msg_ptr) : err_msg_ptr(err_msg_ptr) {}
17+
18+
template<typename E>
19+
Result(const E& err_msg) : err_msg_ptr(std::make_shared<internal::ErrMsg>(err_msg)) {}
20+
21+
bool is_ok() const { return !err_msg_ptr; }
22+
bool is_err() const { return (bool)err_msg_ptr; }
23+
24+
internal::ErrMsg unwrap_err() const {
25+
if (!err_msg_ptr) throw std::runtime_error("is ok");
26+
return *err_msg_ptr;
27+
} // LCOV_EXCL_LINE
28+
};
29+
}

test/result_test.cpp

+78-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,81 @@
1+
#include <result/result.hpp>
12
#include <catch2/catch_test_macros.hpp>
23

3-
TEST_CASE("example test") {
4-
REQUIRE(true);
4+
TEST_CASE("check ok result") {
5+
const res::Result res = res::ok;
6+
REQUIRE(res.is_ok());
7+
REQUIRE_FALSE(res.is_err());
8+
}
9+
10+
TEST_CASE("check error result") {
11+
const res::Result res = "unknown error";
12+
REQUIRE(res.is_err());
13+
REQUIRE_FALSE(res.is_ok());
14+
}
15+
16+
TEST_CASE("uninitialized result contains error") {
17+
const res::Result res;
18+
REQUIRE(res.is_err());
19+
}
20+
21+
TEST_CASE("call `unwrap_err` on error result") {
22+
const res::internal::ErrMsg err_msg = "unknown error";
23+
const res::Result res = err_msg;
24+
REQUIRE(res.is_err());
25+
REQUIRE(res.unwrap_err() == err_msg);
26+
}
27+
28+
TEST_CASE("call `unwrap_err` on ok result") {
29+
const res::Result res = res::ok;
30+
REQUIRE(res.is_ok());
31+
REQUIRE_THROWS(res.unwrap_err());
32+
}
33+
34+
TEST_CASE("check rewriting result") {
35+
res::Result res = res::ok;
36+
REQUIRE(res.is_ok());
37+
res::internal::ErrMsg err_msg = "unknown error";
38+
res = err_msg;
39+
REQUIRE(res.is_err());
40+
REQUIRE(res.unwrap_err() == err_msg);
41+
res = err_msg = "other error";
42+
REQUIRE(res.is_err());
43+
REQUIRE(res.unwrap_err() == err_msg);
44+
res = res::ok;
45+
REQUIRE(res.is_ok());
46+
}
47+
48+
namespace {
49+
res::Result foo(bool is_ok) {
50+
if (is_ok) return res::ok;
51+
return "unknown error";
52+
}
53+
}
54+
55+
TEST_CASE("get result from function returning ok") {
56+
const auto res = foo(true);
57+
REQUIRE(res.is_ok());
58+
}
59+
60+
TEST_CASE("get result from function returning error") {
61+
const auto res = foo(false);
62+
REQUIRE(res.is_err());
63+
}
64+
65+
TEST_CASE("check if ok result is preserved outside the scope") {
66+
res::Result res;
67+
{
68+
res = foo(true);
69+
REQUIRE(res.is_ok());
70+
}
71+
REQUIRE(res.is_ok());
72+
}
73+
74+
TEST_CASE("check if error result is preserved outside the scope") {
75+
res::Result res;
76+
{
77+
res = foo(false);
78+
REQUIRE(res.is_err());
79+
}
80+
REQUIRE(res.is_err());
581
}

0 commit comments

Comments
 (0)