File indexing completed on 2025-01-18 09:13:00
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Utilities/Result.hpp"
0012
0013 #include <stdexcept>
0014 #include <string>
0015 #include <system_error>
0016 #include <type_traits>
0017 #include <utility>
0018
0019 using namespace std::string_literals;
0020
0021 namespace {
0022
0023 enum class MyError {
0024 Failure = 1,
0025 SomethingElse,
0026 };
0027
0028 std::error_code make_error_code(MyError e) {
0029 return {static_cast<int>(e), std::generic_category()};
0030 }
0031
0032 }
0033
0034 namespace std {
0035
0036 template <>
0037 struct is_error_code_enum<MyError> : std::true_type {};
0038 }
0039
0040 namespace Acts::Test {
0041
0042 BOOST_AUTO_TEST_SUITE(Utilities)
0043
0044 BOOST_AUTO_TEST_CASE(TestConstruction) {
0045 {
0046 using Result = Result<int, char>;
0047
0048 Result res = Result::success(42);
0049 BOOST_CHECK_EQUAL(*res, 42);
0050 BOOST_CHECK_EQUAL(res.value(), 42);
0051 BOOST_CHECK(res.ok());
0052 res = Result::success('e');
0053 BOOST_CHECK_EQUAL(*res, 'e');
0054 BOOST_CHECK_EQUAL(res.value(), 'e');
0055 BOOST_CHECK(res.ok());
0056 res = Result::failure(42);
0057 BOOST_CHECK(!res.ok());
0058 BOOST_CHECK_EQUAL(res.error(), 42);
0059 BOOST_CHECK_THROW(res.value(), std::runtime_error);
0060 res = Result::failure('e');
0061 BOOST_CHECK(!res.ok());
0062 BOOST_CHECK_EQUAL(res.error(), 'e');
0063 BOOST_CHECK_THROW(res.value(), std::runtime_error);
0064 }
0065
0066 {
0067 using Result = Result<double, std::string>;
0068
0069 Result res1("hallo");
0070 BOOST_CHECK(!res1.ok());
0071 BOOST_CHECK_EQUAL(res1.error(), "hallo");
0072 BOOST_CHECK_THROW(res1.value(), std::runtime_error);
0073 res1 = Result::failure("hallo");
0074 BOOST_CHECK(!res1.ok());
0075 BOOST_CHECK_EQUAL(res1.error(), "hallo");
0076 BOOST_CHECK_THROW(res1.value(), std::runtime_error);
0077
0078 Result res2(4.5);
0079 BOOST_CHECK(res2.ok());
0080 BOOST_CHECK(*res2 == 4.5);
0081 BOOST_CHECK(res2.value() == 4.5);
0082 res2 = Result::success(4.5);
0083 BOOST_CHECK(res2.ok());
0084 BOOST_CHECK_EQUAL(*res2, 4.5);
0085 BOOST_CHECK_EQUAL(res2.value(), 4.5);
0086 }
0087 }
0088
0089 BOOST_AUTO_TEST_CASE(TestErrorCodes) {
0090 auto err1 = MyError::Failure;
0091
0092 std::error_code ec = err1;
0093
0094 {
0095 using Result = Result<double, MyError>;
0096
0097 Result res(42.);
0098 BOOST_CHECK(res.ok());
0099 BOOST_CHECK_EQUAL(*res, 42.);
0100
0101 Result res2(err1);
0102 BOOST_CHECK(!res2.ok());
0103 BOOST_CHECK_EQUAL(res2.error(), err1);
0104 BOOST_CHECK_THROW(res2.value(), std::runtime_error);
0105 }
0106
0107 {
0108 using Result = Result<double, std::error_code>;
0109
0110 Result res(42.);
0111 BOOST_CHECK(res.ok());
0112 BOOST_CHECK_EQUAL(*res, 42.);
0113 BOOST_CHECK_EQUAL(res.value(), 42u);
0114 res = 46.;
0115 BOOST_CHECK(res.ok());
0116 BOOST_CHECK_EQUAL(*res, 46.);
0117 BOOST_CHECK_EQUAL(res.value(), 46u);
0118
0119 Result res2(ec);
0120 BOOST_CHECK(!res2.ok());
0121 BOOST_CHECK_EQUAL(res2.error(), ec);
0122 BOOST_CHECK_EQUAL(res2.error(), err1);
0123
0124 res2 = MyError::SomethingElse;
0125 BOOST_CHECK(!res2.ok());
0126 BOOST_CHECK_EQUAL(res2.error(), MyError::SomethingElse);
0127 BOOST_CHECK_NE(res2.error(), MyError::Failure);
0128 }
0129
0130 {
0131 using Result = Result<double, const char*>;
0132 Result res{0.};
0133 BOOST_CHECK(res.ok());
0134 BOOST_CHECK_EQUAL(*res, 0.0);
0135
0136 res = 1.;
0137 BOOST_CHECK(res.ok());
0138 BOOST_CHECK_EQUAL(*res, 1.0);
0139
0140 Result res2{"blubb"};
0141 BOOST_CHECK(!res2.ok());
0142 BOOST_CHECK_EQUAL(res2.error(), "blubb");
0143 res2 = "sep";
0144 BOOST_CHECK(!res2.ok());
0145 BOOST_CHECK_EQUAL(res2.error(), "sep");
0146 }
0147
0148 {
0149 using Result = Result<const char*, double>;
0150 Result res{0.};
0151 BOOST_CHECK(!res.ok());
0152 BOOST_CHECK_EQUAL(res.error(), 0.0);
0153
0154 res = "blibb";
0155 BOOST_CHECK(res.ok());
0156 BOOST_CHECK_EQUAL(res.value(), "blibb");
0157
0158 Result res2{"blibb"};
0159 BOOST_CHECK(res2.ok());
0160 BOOST_CHECK_EQUAL(res2.value(), "blibb");
0161
0162 res2 = 0.;
0163 BOOST_CHECK(!res2.ok());
0164 BOOST_CHECK_EQUAL(res2.error(), 0.0);
0165 }
0166
0167 {
0168 using Result = Result<double, int>;
0169 Result res = Result::success(2);
0170 BOOST_CHECK(res.ok());
0171 BOOST_CHECK_EQUAL(res.value(), 2.0);
0172
0173 res = Result::failure(3);
0174 BOOST_CHECK(!res.ok());
0175 BOOST_CHECK_EQUAL(res.error(), 3);
0176
0177 Result res2 = Result::failure(2);
0178 BOOST_CHECK(!res2.ok());
0179 BOOST_CHECK_EQUAL(res2.error(), 2);
0180
0181 res2 = Result::success(3.3);
0182 BOOST_CHECK(res2.ok());
0183 BOOST_CHECK_EQUAL(res2.value(), 3.3);
0184 }
0185
0186 {
0187 using Result = Result<double>;
0188
0189 Result res(42.);
0190 BOOST_CHECK(res.ok());
0191 BOOST_CHECK_EQUAL(*res, 42.);
0192 BOOST_CHECK_EQUAL(res.value(), 42u);
0193 res = 46.;
0194 BOOST_CHECK(res.ok());
0195 BOOST_CHECK_EQUAL(*res, 46.);
0196 BOOST_CHECK_EQUAL(res.value(), 46u);
0197
0198 Result res2(ec);
0199 BOOST_CHECK(!res2.ok());
0200 BOOST_CHECK_EQUAL(res2.error(), ec);
0201 BOOST_CHECK_EQUAL(res2.error(), err1);
0202
0203 res2 = MyError::SomethingElse;
0204 BOOST_CHECK(!res2.ok());
0205 BOOST_CHECK_EQUAL(res2.error(), MyError::SomethingElse);
0206 BOOST_CHECK_NE(res2.error(), MyError::Failure);
0207 }
0208
0209 {
0210 using Result = Result<std::string>;
0211
0212 Result res("hallo");
0213
0214 BOOST_CHECK(res.ok());
0215 BOOST_CHECK_EQUAL(*res, "hallo");
0216 BOOST_CHECK_EQUAL(res.value(), "hallo");
0217
0218 res = "something else";
0219 BOOST_CHECK(res.ok());
0220 BOOST_CHECK_EQUAL(*res, "something else");
0221 BOOST_CHECK_EQUAL(res.value(), "something else");
0222
0223 res = MyError::SomethingElse;
0224 BOOST_CHECK(!res.ok());
0225 BOOST_CHECK_EQUAL(res.error(), MyError::SomethingElse);
0226 BOOST_CHECK_NE(res.error(), MyError::Failure);
0227 }
0228
0229 {
0230 using Result = Result<std::string, int>;
0231
0232 Result res{"hallo"};
0233 BOOST_CHECK(res.ok());
0234 BOOST_CHECK_EQUAL(res.value(), "hallo");
0235
0236 Result res2{4};
0237 BOOST_CHECK(!res2.ok());
0238 BOOST_CHECK_EQUAL(res2.error(), 4);
0239 }
0240 }
0241
0242 struct NoCopy {
0243 NoCopy(int i) : num(i) {}
0244 NoCopy(const NoCopy&) = delete;
0245 NoCopy& operator=(const NoCopy&) = delete;
0246 NoCopy(NoCopy&&) = default;
0247 NoCopy& operator=(NoCopy&&) = default;
0248
0249 int num;
0250 };
0251
0252 Result<NoCopy> make_nocopy(int i, bool v = true) {
0253 if (!v) {
0254 return MyError::Failure;
0255 }
0256 return i;
0257 }
0258
0259 BOOST_AUTO_TEST_CASE(CopyBehaviour) {
0260 using Result = Result<NoCopy>;
0261
0262 NoCopy n(5);
0263 Result res = std::move(n);
0264 BOOST_CHECK(res.ok());
0265 BOOST_CHECK_EQUAL((*res).num, res.value().num);
0266
0267 res = make_nocopy(3);
0268 BOOST_CHECK(res.ok());
0269 BOOST_CHECK_EQUAL((*res).num, res.value().num);
0270 BOOST_CHECK_EQUAL((*res).num, 3);
0271
0272 res = NoCopy(-4);
0273 BOOST_CHECK(res.ok());
0274 BOOST_CHECK_EQUAL((*res).num, res.value().num);
0275 BOOST_CHECK_EQUAL((*res).num, -4.);
0276
0277 NoCopy n2 = make_nocopy(7).value();
0278 BOOST_CHECK_EQUAL(n2.num, 7);
0279 BOOST_REQUIRE_THROW(make_nocopy(6, false).value();, std::runtime_error);
0280
0281 Result n4r = make_nocopy(8);
0282 BOOST_CHECK(n4r.ok());
0283 BOOST_CHECK_EQUAL((*n4r).num, 8);
0284 NoCopy n4 = std::move(n4r.value());
0285 BOOST_CHECK_EQUAL(n4.num, 8);
0286 }
0287
0288 Result<void> void_res_func(int b) {
0289 if (b > 5) {
0290 return MyError::SomethingElse;
0291 }
0292 return {};
0293 }
0294
0295 BOOST_AUTO_TEST_CASE(VoidResult) {
0296 using Result = Result<void>;
0297
0298 Result res;
0299 BOOST_CHECK(res.ok());
0300
0301 Result res2 = Result::success();
0302 BOOST_CHECK(res2.ok());
0303
0304 res = MyError::Failure;
0305 BOOST_CHECK(!res.ok());
0306 BOOST_CHECK_EQUAL(res.error(), MyError::Failure);
0307
0308 Result res3 = Result::failure(MyError::SomethingElse);
0309 BOOST_CHECK(!res3.ok());
0310 BOOST_CHECK_EQUAL(res3.error(), MyError::SomethingElse);
0311
0312 Result res4 = void_res_func(4);
0313 BOOST_CHECK(res4.ok());
0314
0315 Result res5 = void_res_func(42);
0316 BOOST_CHECK(!res5.ok());
0317 BOOST_CHECK_EQUAL(res5.error(), MyError::SomethingElse);
0318 }
0319
0320 BOOST_AUTO_TEST_CASE(BoolResult) {
0321 using Result = Result<bool>;
0322
0323 Result res = Result::success(false);
0324 BOOST_CHECK(res.ok());
0325 BOOST_CHECK_EQUAL(*res, false);
0326
0327 res = Result::success(true);
0328 BOOST_CHECK(res.ok());
0329 BOOST_CHECK_EQUAL(*res, true);
0330
0331 res = Result::failure(MyError::Failure);
0332 BOOST_CHECK(!res.ok());
0333 BOOST_CHECK_EQUAL(res.error(), MyError::Failure);
0334 }
0335
0336 BOOST_AUTO_TEST_CASE(ValueOrResult) {
0337 using Result = Result<int>;
0338
0339 Result res = Result::success(5);
0340 BOOST_CHECK_EQUAL(res.value_or(42), 5);
0341
0342 res = Result::failure(MyError::Failure);
0343 BOOST_CHECK_EQUAL(res.value_or(42), 42);
0344
0345 BOOST_CHECK_EQUAL(Result::success(5).value_or(42), 5);
0346 BOOST_CHECK_EQUAL(Result::failure(MyError::Failure).value_or(42), 42);
0347
0348 int val = 25;
0349 const int cval = 30;
0350
0351 BOOST_CHECK_EQUAL(Result::success(5).value_or(val), 5);
0352 BOOST_CHECK_EQUAL(Result::success(5).value_or(cval), 5);
0353 BOOST_CHECK_EQUAL(Result::failure(MyError::Failure).value_or(val), 25);
0354 BOOST_CHECK_EQUAL(Result::failure(MyError::Failure).value_or(cval), 30);
0355
0356 res = Result::success(5);
0357
0358 BOOST_CHECK_EQUAL(res.value_or(val), 5);
0359 BOOST_CHECK_EQUAL(&(res.value_or(val)), &res.value());
0360 BOOST_CHECK_EQUAL(res.value_or(cval), 5);
0361 BOOST_CHECK_EQUAL(&(res.value_or(cval)), &res.value());
0362
0363 res = Result::failure(MyError::Failure);
0364
0365 BOOST_CHECK_EQUAL(res.value_or(val), 25);
0366 BOOST_CHECK_EQUAL(res.value_or(cval), 30);
0367 BOOST_CHECK_EQUAL(&(res.value_or(val)), &val);
0368 BOOST_CHECK_EQUAL(&(res.value_or(cval)), &cval);
0369 }
0370
0371 BOOST_AUTO_TEST_CASE(TransformResult) {
0372 using Result = Result<int>;
0373
0374 auto f1 = [](int x) { return 2 * x; };
0375
0376 Result res = Result::success(5);
0377 Result res2 = res.transform(f1);
0378 BOOST_CHECK(res2.ok());
0379 BOOST_CHECK_EQUAL(*res2, 10);
0380
0381 res = Result::failure(MyError::Failure);
0382 res2 = res.transform(f1);
0383 BOOST_CHECK(!res2.ok());
0384
0385 BOOST_CHECK(Result::success(5).transform(f1).ok());
0386 BOOST_CHECK_EQUAL(Result::success(5).transform(f1).value(), 10);
0387
0388 BOOST_CHECK(!Result::failure(MyError::Failure).transform(f1).ok());
0389 }
0390
0391 BOOST_AUTO_TEST_CASE(AndThenResult) {
0392 using Result1 = Result<int>;
0393 using Result2 = Result<std::string>;
0394
0395 auto f1 = [](int x) -> Result2 {
0396 return Result2::success("hello " + std::to_string(x));
0397 };
0398 auto f2 = [](int) -> Result2 { return Result2::failure(MyError::Failure); };
0399
0400 Result1 res = Result1::success(5);
0401 Result2 res2 = res.and_then(f1);
0402 BOOST_CHECK(res2.ok());
0403 BOOST_CHECK_EQUAL(*res2, "hello 5");
0404
0405 res2 = res.and_then(f2);
0406 BOOST_CHECK(!res2.ok());
0407
0408 res = Result1::failure(MyError::Failure);
0409 res2 = res.and_then(f1);
0410 BOOST_CHECK(!res2.ok());
0411
0412 res2 = res.and_then(f2);
0413 BOOST_CHECK(!res2.ok());
0414
0415 BOOST_CHECK(Result1::success(5).and_then(f1).ok());
0416 BOOST_CHECK_EQUAL(Result1::success(5).and_then(f1).value(), "hello 5");
0417
0418 BOOST_CHECK(!Result1::success(5).and_then(f2).ok());
0419
0420 BOOST_CHECK(!Result1::failure(MyError::Failure).and_then(f1).ok());
0421
0422 BOOST_CHECK(!Result1::failure(MyError::Failure).and_then(f2).ok());
0423 }
0424 BOOST_AUTO_TEST_SUITE_END()
0425
0426 }