xref: /aosp_15_r20/external/pigweed/pw_result/expected_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2023 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_result/expected.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <string>
18*61c4878aSAndroid Build Coastguard Worker 
19*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
20*61c4878aSAndroid Build Coastguard Worker 
21*61c4878aSAndroid Build Coastguard Worker namespace pw {
22*61c4878aSAndroid Build Coastguard Worker namespace {
23*61c4878aSAndroid Build Coastguard Worker 
24*61c4878aSAndroid Build Coastguard Worker struct Defaults {
25*61c4878aSAndroid Build Coastguard Worker   Defaults() = default;
26*61c4878aSAndroid Build Coastguard Worker   Defaults(const Defaults&) = default;
27*61c4878aSAndroid Build Coastguard Worker   Defaults(Defaults&&) = default;
28*61c4878aSAndroid Build Coastguard Worker   Defaults& operator=(const Defaults&) = default;
29*61c4878aSAndroid Build Coastguard Worker   Defaults& operator=(Defaults&&) = default;
30*61c4878aSAndroid Build Coastguard Worker };
31*61c4878aSAndroid Build Coastguard Worker 
32*61c4878aSAndroid Build Coastguard Worker struct NoDefaultConstructor {
33*61c4878aSAndroid Build Coastguard Worker   NoDefaultConstructor() = delete;
NoDefaultConstructorpw::__anon1efd96b40111::NoDefaultConstructor34*61c4878aSAndroid Build Coastguard Worker   NoDefaultConstructor(std::nullptr_t) {}
35*61c4878aSAndroid Build Coastguard Worker };
36*61c4878aSAndroid Build Coastguard Worker 
37*61c4878aSAndroid Build Coastguard Worker struct NoCopy {
38*61c4878aSAndroid Build Coastguard Worker   NoCopy(const NoCopy&) = delete;
39*61c4878aSAndroid Build Coastguard Worker   NoCopy(NoCopy&&) = default;
40*61c4878aSAndroid Build Coastguard Worker   NoCopy& operator=(const NoCopy&) = delete;
41*61c4878aSAndroid Build Coastguard Worker   NoCopy& operator=(NoCopy&&) = default;
42*61c4878aSAndroid Build Coastguard Worker };
43*61c4878aSAndroid Build Coastguard Worker 
44*61c4878aSAndroid Build Coastguard Worker struct NoCopyNoMove {
45*61c4878aSAndroid Build Coastguard Worker   NoCopyNoMove(const NoCopyNoMove&) = delete;
46*61c4878aSAndroid Build Coastguard Worker   NoCopyNoMove(NoCopyNoMove&&) = delete;
47*61c4878aSAndroid Build Coastguard Worker   NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
48*61c4878aSAndroid Build Coastguard Worker   NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;
49*61c4878aSAndroid Build Coastguard Worker };
50*61c4878aSAndroid Build Coastguard Worker 
51*61c4878aSAndroid Build Coastguard Worker struct NonTrivialDestructor {
~NonTrivialDestructorpw::__anon1efd96b40111::NonTrivialDestructor52*61c4878aSAndroid Build Coastguard Worker   ~NonTrivialDestructor() {}
53*61c4878aSAndroid Build Coastguard Worker };
54*61c4878aSAndroid Build Coastguard Worker 
55*61c4878aSAndroid Build Coastguard Worker namespace test_constexpr {
56*61c4878aSAndroid Build Coastguard Worker // Expected and unexpected are constexpr types.
57*61c4878aSAndroid Build Coastguard Worker constexpr expected<int, int> kExpectedConstexpr1;
58*61c4878aSAndroid Build Coastguard Worker constexpr expected<int, int> kExpectedConstexpr2{5};
59*61c4878aSAndroid Build Coastguard Worker constexpr expected<int, int> kExpectedConstexpr3 = unexpected<int>(42);
60*61c4878aSAndroid Build Coastguard Worker constexpr unexpected<int> kExpectedConstexprUnexpected{50};
61*61c4878aSAndroid Build Coastguard Worker static_assert(kExpectedConstexpr1.has_value());
62*61c4878aSAndroid Build Coastguard Worker static_assert(kExpectedConstexpr1.value() == 0);
63*61c4878aSAndroid Build Coastguard Worker static_assert(kExpectedConstexpr2.has_value());
64*61c4878aSAndroid Build Coastguard Worker static_assert(kExpectedConstexpr2.value() == 5);
65*61c4878aSAndroid Build Coastguard Worker static_assert(!kExpectedConstexpr3.has_value());
66*61c4878aSAndroid Build Coastguard Worker static_assert(kExpectedConstexpr3.error() == 42);
67*61c4878aSAndroid Build Coastguard Worker static_assert(kExpectedConstexprUnexpected.error() == 50);
68*61c4878aSAndroid Build Coastguard Worker }  // namespace test_constexpr
69*61c4878aSAndroid Build Coastguard Worker 
70*61c4878aSAndroid Build Coastguard Worker namespace test_default_construction {
71*61c4878aSAndroid Build Coastguard Worker // Default constructible if and only if T is default constructible.
72*61c4878aSAndroid Build Coastguard Worker static_assert(
73*61c4878aSAndroid Build Coastguard Worker     std::is_default_constructible<expected<Defaults, Defaults>>::value);
74*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_default_constructible<
75*61c4878aSAndroid Build Coastguard Worker               expected<NoDefaultConstructor, Defaults>>::value);
76*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_default_constructible<
77*61c4878aSAndroid Build Coastguard Worker               expected<Defaults, NoDefaultConstructor>>::value);
78*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_default_constructible<
79*61c4878aSAndroid Build Coastguard Worker               expected<NoDefaultConstructor, NoDefaultConstructor>>::value);
80*61c4878aSAndroid Build Coastguard Worker // Never default constructible.
81*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_default_constructible<unexpected<Defaults>>::value);
82*61c4878aSAndroid Build Coastguard Worker static_assert(
83*61c4878aSAndroid Build Coastguard Worker     !std::is_default_constructible<unexpected<NoDefaultConstructor>>::value);
84*61c4878aSAndroid Build Coastguard Worker }  // namespace test_default_construction
85*61c4878aSAndroid Build Coastguard Worker 
86*61c4878aSAndroid Build Coastguard Worker namespace test_copy_construction {
87*61c4878aSAndroid Build Coastguard Worker // Copy constructible if and only if both types are copy constructible.
88*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_copy_constructible<expected<Defaults, Defaults>>::value);
89*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_constructible<expected<Defaults, NoCopy>>::value);
90*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_constructible<expected<NoCopy, Defaults>>::value);
91*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_constructible<expected<NoCopy, NoCopy>>::value);
92*61c4878aSAndroid Build Coastguard Worker // Copy constructible if and only if E is copy constructible.
93*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_copy_constructible<unexpected<Defaults>>::value);
94*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_constructible<unexpected<NoCopy>>::value);
95*61c4878aSAndroid Build Coastguard Worker }  // namespace test_copy_construction
96*61c4878aSAndroid Build Coastguard Worker 
97*61c4878aSAndroid Build Coastguard Worker namespace test_copy_assignment {
98*61c4878aSAndroid Build Coastguard Worker // Copy assignable if and only if both types are copy assignable.
99*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_copy_assignable<expected<Defaults, Defaults>>::value);
100*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_assignable<expected<Defaults, NoCopy>>::value);
101*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_assignable<expected<NoCopy, Defaults>>::value);
102*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_assignable<expected<NoCopy, NoCopy>>::value);
103*61c4878aSAndroid Build Coastguard Worker // Copy assignable if and only if E is copy assignable.
104*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_copy_assignable<unexpected<Defaults>>::value);
105*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_copy_assignable<unexpected<NoCopy>>::value);
106*61c4878aSAndroid Build Coastguard Worker }  // namespace test_copy_assignment
107*61c4878aSAndroid Build Coastguard Worker 
108*61c4878aSAndroid Build Coastguard Worker namespace test_move_construction {
109*61c4878aSAndroid Build Coastguard Worker // Move constructible if and only if both types are move constructible.
110*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_move_constructible<expected<Defaults, Defaults>>::value);
111*61c4878aSAndroid Build Coastguard Worker static_assert(
112*61c4878aSAndroid Build Coastguard Worker     !std::is_move_constructible<expected<Defaults, NoCopyNoMove>>::value);
113*61c4878aSAndroid Build Coastguard Worker static_assert(
114*61c4878aSAndroid Build Coastguard Worker     !std::is_move_constructible<expected<NoCopyNoMove, Defaults>>::value);
115*61c4878aSAndroid Build Coastguard Worker static_assert(
116*61c4878aSAndroid Build Coastguard Worker     !std::is_move_constructible<expected<NoCopyNoMove, NoCopyNoMove>>::value);
117*61c4878aSAndroid Build Coastguard Worker // Move constructible if and only if E is move constructible.
118*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_move_constructible<unexpected<Defaults>>::value);
119*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_move_constructible<unexpected<NoCopyNoMove>>::value);
120*61c4878aSAndroid Build Coastguard Worker }  // namespace test_move_construction
121*61c4878aSAndroid Build Coastguard Worker 
122*61c4878aSAndroid Build Coastguard Worker namespace test_move_assignment {
123*61c4878aSAndroid Build Coastguard Worker // Move assignable if and only if both types are move assignable.
124*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_move_assignable<expected<Defaults, Defaults>>::value);
125*61c4878aSAndroid Build Coastguard Worker static_assert(
126*61c4878aSAndroid Build Coastguard Worker     !std::is_move_assignable<expected<Defaults, NoCopyNoMove>>::value);
127*61c4878aSAndroid Build Coastguard Worker static_assert(
128*61c4878aSAndroid Build Coastguard Worker     !std::is_move_assignable<expected<NoCopyNoMove, Defaults>>::value);
129*61c4878aSAndroid Build Coastguard Worker static_assert(
130*61c4878aSAndroid Build Coastguard Worker     !std::is_move_assignable<expected<NoCopyNoMove, NoCopyNoMove>>::value);
131*61c4878aSAndroid Build Coastguard Worker // Move assignable if and only if E is move assignable.
132*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_move_assignable<unexpected<Defaults>>::value);
133*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_move_assignable<unexpected<NoCopyNoMove>>::value);
134*61c4878aSAndroid Build Coastguard Worker }  // namespace test_move_assignment
135*61c4878aSAndroid Build Coastguard Worker 
136*61c4878aSAndroid Build Coastguard Worker namespace test_trivial_destructor {
137*61c4878aSAndroid Build Coastguard Worker // Destructor is trivial if and only if both types are trivially destructible.
138*61c4878aSAndroid Build Coastguard Worker static_assert(
139*61c4878aSAndroid Build Coastguard Worker     std::is_trivially_destructible<expected<Defaults, Defaults>>::value);
140*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_trivially_destructible<
141*61c4878aSAndroid Build Coastguard Worker               expected<NonTrivialDestructor, Defaults>>::value);
142*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_trivially_destructible<
143*61c4878aSAndroid Build Coastguard Worker               expected<Defaults, NonTrivialDestructor>>::value);
144*61c4878aSAndroid Build Coastguard Worker static_assert(!std::is_trivially_destructible<
145*61c4878aSAndroid Build Coastguard Worker               expected<NonTrivialDestructor, NonTrivialDestructor>>::value);
146*61c4878aSAndroid Build Coastguard Worker // Destructor is trivial if and only if E is trivially destructible.
147*61c4878aSAndroid Build Coastguard Worker static_assert(std::is_trivially_destructible<unexpected<Defaults>>::value);
148*61c4878aSAndroid Build Coastguard Worker static_assert(
149*61c4878aSAndroid Build Coastguard Worker     !std::is_trivially_destructible<unexpected<NonTrivialDestructor>>::value);
150*61c4878aSAndroid Build Coastguard Worker }  // namespace test_trivial_destructor
151*61c4878aSAndroid Build Coastguard Worker 
FailableFunction1(bool fail,int num)152*61c4878aSAndroid Build Coastguard Worker expected<int, const char*> FailableFunction1(bool fail, int num) {
153*61c4878aSAndroid Build Coastguard Worker   if (fail) {
154*61c4878aSAndroid Build Coastguard Worker     return unexpected("FailableFunction1");
155*61c4878aSAndroid Build Coastguard Worker   }
156*61c4878aSAndroid Build Coastguard Worker   return num;
157*61c4878aSAndroid Build Coastguard Worker }
158*61c4878aSAndroid Build Coastguard Worker 
FailableFunction2(bool fail,int num)159*61c4878aSAndroid Build Coastguard Worker expected<std::string, const char*> FailableFunction2(bool fail, int num) {
160*61c4878aSAndroid Build Coastguard Worker   if (fail) {
161*61c4878aSAndroid Build Coastguard Worker     return unexpected("FailableFunction2");
162*61c4878aSAndroid Build Coastguard Worker   }
163*61c4878aSAndroid Build Coastguard Worker   return std::to_string(num);
164*61c4878aSAndroid Build Coastguard Worker }
165*61c4878aSAndroid Build Coastguard Worker 
FailOnOdd(int x)166*61c4878aSAndroid Build Coastguard Worker expected<int, const char*> FailOnOdd(int x) {
167*61c4878aSAndroid Build Coastguard Worker   if (x % 2) {
168*61c4878aSAndroid Build Coastguard Worker     return unexpected("odd");
169*61c4878aSAndroid Build Coastguard Worker   }
170*61c4878aSAndroid Build Coastguard Worker   return x;
171*61c4878aSAndroid Build Coastguard Worker }
172*61c4878aSAndroid Build Coastguard Worker 
ItoaFailOnNegative(int x)173*61c4878aSAndroid Build Coastguard Worker expected<std::string, const char*> ItoaFailOnNegative(int x) {
174*61c4878aSAndroid Build Coastguard Worker   if (x < 0) {
175*61c4878aSAndroid Build Coastguard Worker     return unexpected("negative");
176*61c4878aSAndroid Build Coastguard Worker   }
177*61c4878aSAndroid Build Coastguard Worker   return std::to_string(x);
178*61c4878aSAndroid Build Coastguard Worker }
179*61c4878aSAndroid Build Coastguard Worker 
GetSecondChar(const std::string & s)180*61c4878aSAndroid Build Coastguard Worker expected<char, const char*> GetSecondChar(const std::string& s) {
181*61c4878aSAndroid Build Coastguard Worker   if (s.size() < 2) {
182*61c4878aSAndroid Build Coastguard Worker     return unexpected("string too small");
183*61c4878aSAndroid Build Coastguard Worker   }
184*61c4878aSAndroid Build Coastguard Worker   return s[1];
185*61c4878aSAndroid Build Coastguard Worker }
186*61c4878aSAndroid Build Coastguard Worker 
Decrement(int x)187*61c4878aSAndroid Build Coastguard Worker int Decrement(int x) { return x - 1; }
188*61c4878aSAndroid Build Coastguard Worker 
189*61c4878aSAndroid Build Coastguard Worker template <class T, class E>
Consume(const expected<T,E> & e)190*61c4878aSAndroid Build Coastguard Worker expected<void, E> Consume(const expected<T, E>& e) {
191*61c4878aSAndroid Build Coastguard Worker   return e.transform([](auto) {});
192*61c4878aSAndroid Build Coastguard Worker }
193*61c4878aSAndroid Build Coastguard Worker 
TEST(ExpectedTest,HoldIntValueSuccess)194*61c4878aSAndroid Build Coastguard Worker TEST(ExpectedTest, HoldIntValueSuccess) {
195*61c4878aSAndroid Build Coastguard Worker   auto x = FailableFunction1(false, 10);
196*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(x.has_value());
197*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.value(), 10);
198*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(*x, 10);
199*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.value_or(33), 10);
200*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.error_or("no error"), std::string("no error"));
201*61c4878aSAndroid Build Coastguard Worker }
202*61c4878aSAndroid Build Coastguard Worker 
TEST(ExpectedTest,HoldIntValueFail)203*61c4878aSAndroid Build Coastguard Worker TEST(ExpectedTest, HoldIntValueFail) {
204*61c4878aSAndroid Build Coastguard Worker   auto x = FailableFunction1(true, 10);
205*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(x.has_value());
206*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.error(), std::string("FailableFunction1"));
207*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.value_or(33), 33);
208*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.error_or("no error"), std::string("FailableFunction1"));
209*61c4878aSAndroid Build Coastguard Worker }
210*61c4878aSAndroid Build Coastguard Worker 
TEST(ExpectedTest,HoldStringValueSuccess)211*61c4878aSAndroid Build Coastguard Worker TEST(ExpectedTest, HoldStringValueSuccess) {
212*61c4878aSAndroid Build Coastguard Worker   auto x = FailableFunction2(false, 42);
213*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(x.has_value());
214*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.value(), std::string("42"));
215*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(*x, std::string("42"));
216*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.value_or("33"), std::string("42"));
217*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.error_or("no error"), std::string("no error"));
218*61c4878aSAndroid Build Coastguard Worker }
219*61c4878aSAndroid Build Coastguard Worker 
TEST(ExpectedTest,HoldStringValueFail)220*61c4878aSAndroid Build Coastguard Worker TEST(ExpectedTest, HoldStringValueFail) {
221*61c4878aSAndroid Build Coastguard Worker   auto x = FailableFunction2(true, 42);
222*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(x.has_value());
223*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.error(), std::string("FailableFunction2"));
224*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.value_or("33"), std::string("33"));
225*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(x.error_or("no error"), std::string("FailableFunction2"));
226*61c4878aSAndroid Build Coastguard Worker }
227*61c4878aSAndroid Build Coastguard Worker 
TEST(ExpectedTest,MonadicOperation)228*61c4878aSAndroid Build Coastguard Worker TEST(ExpectedTest, MonadicOperation) {
229*61c4878aSAndroid Build Coastguard Worker   auto f = [](expected<int, const char*> value) {
230*61c4878aSAndroid Build Coastguard Worker     return value.and_then(FailOnOdd)
231*61c4878aSAndroid Build Coastguard Worker         .transform(Decrement)
232*61c4878aSAndroid Build Coastguard Worker         .transform(Decrement)
233*61c4878aSAndroid Build Coastguard Worker         .and_then(ItoaFailOnNegative)
234*61c4878aSAndroid Build Coastguard Worker         .and_then(GetSecondChar);
235*61c4878aSAndroid Build Coastguard Worker   };
236*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(26).value_or(0), '4');
237*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(26).error_or(nullptr), nullptr);
238*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(25).value_or(0), 0);
239*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(25).error_or(nullptr), std::string("odd"));
240*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(0).value_or(0), 0);
241*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(0).error_or(nullptr), std::string("negative"));
242*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(4).value_or(0), 0);
243*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(f(4).error_or(nullptr), std::string("string too small"));
244*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(Consume(f(26)).has_value());
245*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Consume(f(25)).error_or(nullptr), std::string("odd"));
246*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Consume(f(0)).error_or(nullptr), std::string("negative"));
247*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Consume(f(4)).error_or(nullptr), std::string("string too small"));
248*61c4878aSAndroid Build Coastguard Worker }
249*61c4878aSAndroid Build Coastguard Worker 
250*61c4878aSAndroid Build Coastguard Worker }  // namespace
251*61c4878aSAndroid Build Coastguard Worker }  // namespace pw
252