GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
my_expected_test.h
[詳解]
1
3
4// Copyright(c) 2023-2025 Design Engineering Laboratory, Saitama University
5// Released under the MIT license
6// https://opensource.org/licenses/mit-license.php
7
8#ifndef DESIGNLAB_MY_EXPECTED_TEST_H_
9#define DESIGNLAB_MY_EXPECTED_TEST_H_
10
11#include <doctest.h>
12
13#include <string>
14
15#include "my_expected.h"
16
18
19struct CustomValue final {
20 int code;
21 std::string message;
22};
23
24struct Sample final {
25 void count() { cnt++; }
26 int value() const { return 42; }
27
28 int cnt = 0;
29};
30
31std::string ToFizzBuzz(int value) {
32 if (value % 3 == 0 && value % 5 == 0) {
33 return "FizzBuzz";
34 } else if (value % 3 == 0) {
35 return "Fizz";
36 } else if (value % 5 == 0) {
37 return "Buzz";
38 } else {
39 return std::to_string(value);
40 }
41}
42
45
46ess FizzBuzz(int value) {
47 if (value < 0) {
48 return ues("Negative value");
49 }
50 return ess(ToFizzBuzz(value));
51}
52
53ess FizzBuzzRef(const int& value) {
54 if (value < 0) {
55 return ues("Negative value");
56 }
57 return ToFizzBuzz(value);
58}
59
60} // namespace designlab::impl::my_expected_test
61
62TEST_SUITE("expected") {
70
71 TEST_CASE("expected construction") {
72 // 単一の変数によるコンストラクタ
73
74 SUBCASE("when T is a integral type, it should be constructible") {
75 expected<int, std::string> e(42);
76
77 CHECK_EQ(e.value(), 42);
78 CHECK(e.has_value());
79 }
80
81 SUBCASE("when T is a string, it should be constructible") {
82 expected<std::string, int> e("success");
83
84 CHECK_EQ(e.value(), "success");
85 CHECK(e.has_value());
86 }
87
88 SUBCASE("when T and E are the same type, it should be constructible") {
89 expected<std::string, std::string> e("success");
90
91 CHECK_EQ(e.value(), "success");
92 CHECK(e.has_value());
93 }
94
95 SUBCASE("when T is a custom type, it should be constructible") {
96 expected<CustomValue, std::string> e(CustomValue{200, "OK"});
97
98 CHECK_EQ(e.value().code, 200);
99 CHECK_EQ(e.value().message, "OK");
100 CHECK(e.has_value());
101 }
102 }
103
104 TEST_CASE("arrow operator") {
105 SUBCASE(
106 "when T is a class with member functions, arrow operator should work") {
107 // Act1
108 expected<Sample, std::string> e;
109
110 CHECK_EQ(e->value(), 42);
111 CHECK_EQ(e->cnt, 0);
112
113 // Act2
114 e->count();
115
116 CHECK_EQ(e->cnt, 1);
117 }
118 }
119
120 TEST_CASE("asterisk operator") {
121 SUBCASE("when T is a class with member functions, * operator should work") {
122 expected<int, std::string> e(42);
123
124 CHECK_EQ(*e, 42);
125 }
126 }
127
128 TEST_CASE("bool operator") {
129 SUBCASE("when has_value is true, bool operator should return true") {
130 expected<int, std::string> e(42);
131 CHECK(e);
132 }
133
134 SUBCASE("when has_value is false, bool operator should return false") {
135 expected<int, std::string> e(unexpected<std::string>("error"));
136 CHECK(!e);
137 }
138 }
139
140 TEST_CASE("has_value") {
141 SUBCASE("has_value should return true when value is present") {
142 expected<int, std::string> e(42);
143 CHECK(e.has_value());
144 }
145
146 SUBCASE("has_value should return false when error is present") {
147 expected<int, std::string> e(unexpected<std::string>("error"));
148 CHECK(!e.has_value());
149 }
150 }
151
152 TEST_CASE("value") {
153 SUBCASE("value should return the value when has_value is true") {
154 expected<int, std::string> e(42);
155 CHECK_EQ(e.value(), 42);
156 }
157
158 SUBCASE("value should throw when has_value is false") {
159 expected<int, std::string> e(unexpected<std::string>("error"));
160 CHECK_THROWS_AS(e.value(), bad_expected_access);
161 }
162 }
163
164 TEST_CASE("error") {
165 SUBCASE("error should return the error when has_value is false") {
166 expected<int, std::string> e(unexpected<std::string>("error"));
167 CHECK_EQ(e.error(), "error");
168 }
169
170 SUBCASE("error should throw when has_value is true") {
171 expected<int, std::string> e(42);
172 CHECK_THROWS_AS(e.error(), bad_expected_access);
173 }
174 }
175
176 TEST_CASE("value_or") {
177 SUBCASE("value_or should return the value when has_value is true") {
178 expected<int, std::string> e(42);
179 CHECK_EQ(e.value_or(0), 42);
180 }
181
182 SUBCASE(
183 "value_or should return the default value when has_value is false") {
184 expected<int, std::string> e(unexpected<std::string>("error"));
185 CHECK_EQ(e.value_or(0), 0);
186 }
187 }
188
189 TEST_CASE("error_or") {
190 SUBCASE("error_or should return the error when has_value is false") {
191 expected<int, std::string> e(unexpected<std::string>("error"));
192 CHECK_EQ(e.error_or("default error"), "error");
193 }
194
195 SUBCASE("error_or should return the default value when has_value is true") {
196 expected<int, std::string> e(42);
197 CHECK_EQ(e.error_or("default error"), "default error");
198 }
199 }
200
201 TEST_CASE("and_then") {
202 SUBCASE("and_then should call the function when has_value is true") {
203 const auto div2 = [](int value) -> expected<int, std::string> {
204 return expected<int, std::string>(value / 2);
205 };
206
207 // Act1
208 const expected<int, std::string> e1(42);
209 const auto result = e1.and_then(div2);
210
211 CHECK(result.has_value());
212 CHECK_EQ(result.value(), 21);
213
214 // Act2
215 const expected<int, std::string> e2(44);
216 const auto result2 = e2.and_then(div2).and_then(div2);
217
218 CHECK(result2.has_value());
219 CHECK_EQ(result2.value(), 11);
220 }
221
222 SUBCASE("and_then should not call the function when has_value is false") {
223 const auto div2 = [](int value) -> expected<int, std::string> {
224 return expected<int, std::string>(value / 2);
225 };
226
227 // Act1
228 const expected<int, std::string> e1(unexpected<std::string>("error"));
229 const auto result1 = e1.and_then(div2);
230
231 CHECK(!result1.has_value());
232 CHECK_EQ(result1.error(), "error");
233
234 // Act2
235 const expected<int, std::string> e2(unexpected<std::string>("error"));
236 const auto result2 = e2.and_then(div2).and_then(div2);
237
238 CHECK(!result2.has_value());
239 CHECK_EQ(result2.error(), "error");
240 }
241
242 SUBCASE("and_then with member function should work") {
243 const auto get_value = [](const Sample& s) {
244 return expected<int, std::string>(s.value());
245 };
246
247 // Act
248 expected<Sample, std::string> e(Sample{});
249 const auto result = e.and_then(get_value);
250
251 CHECK(result.has_value());
252 CHECK_EQ(result.value(), 42);
253 }
254
255 SUBCASE("") {
256 const expected<int, std::string> e1(42);
257
258 // Act1
259 const auto res1 = e1.and_then(FizzBuzz);
260 const auto res2 = e1.and_then(FizzBuzzRef);
261
262 CHECK(res1.has_value());
263 CHECK_EQ(res1.value(), "Fizz");
264 CHECK(res2.has_value());
265 CHECK_EQ(res2.value(), "Fizz");
266 }
267 }
268}
269
270#endif // DESIGNLAB_MY_EXPECTED_TEST_H_
自作の expected クラス
Definition my_expected.h:46
TEST_SUITE("expected")
designlab::nostd::expected< std::string, std::string > ess
std::string ToFizzBuzz(int value)
designlab::nostd::unexpected< std::string > ues