Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:13:00

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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 }  // namespace
0033 
0034 namespace std {
0035 // register with STL
0036 template <>
0037 struct is_error_code_enum<MyError> : std::true_type {};
0038 }  // namespace std
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 }  // namespace Acts::Test