1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright 2024 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #include <ftl/expected.h>
18*38e8c45fSAndroid Build Coastguard Worker #include <ftl/optional.h>
19*38e8c45fSAndroid Build Coastguard Worker #include <ftl/unit.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
21*38e8c45fSAndroid Build Coastguard Worker
22*38e8c45fSAndroid Build Coastguard Worker #include <cctype>
23*38e8c45fSAndroid Build Coastguard Worker #include <string>
24*38e8c45fSAndroid Build Coastguard Worker #include <system_error>
25*38e8c45fSAndroid Build Coastguard Worker
26*38e8c45fSAndroid Build Coastguard Worker namespace android::test {
27*38e8c45fSAndroid Build Coastguard Worker
28*38e8c45fSAndroid Build Coastguard Worker using IntExp = ftl::Expected<int, std::errc>;
29*38e8c45fSAndroid Build Coastguard Worker using StringExp = ftl::Expected<std::string, std::errc>;
30*38e8c45fSAndroid Build Coastguard Worker
31*38e8c45fSAndroid Build Coastguard Worker using namespace std::string_literals;
32*38e8c45fSAndroid Build Coastguard Worker
TEST(Expected,Construct)33*38e8c45fSAndroid Build Coastguard Worker TEST(Expected, Construct) {
34*38e8c45fSAndroid Build Coastguard Worker // Default value.
35*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(IntExp().has_value());
36*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(IntExp(), IntExp(0));
37*38e8c45fSAndroid Build Coastguard Worker
38*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(StringExp().has_value());
39*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(StringExp(), StringExp(""));
40*38e8c45fSAndroid Build Coastguard Worker
41*38e8c45fSAndroid Build Coastguard Worker // Value.
42*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(IntExp(42).has_value());
43*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(42, IntExp(42).value());
44*38e8c45fSAndroid Build Coastguard Worker
45*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(StringExp("test").has_value());
46*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ("test"s, StringExp("test").value());
47*38e8c45fSAndroid Build Coastguard Worker
48*38e8c45fSAndroid Build Coastguard Worker // Error.
49*38e8c45fSAndroid Build Coastguard Worker const auto exp = StringExp(ftl::Unexpected(std::errc::invalid_argument));
50*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(exp.has_value());
51*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(std::errc::invalid_argument, exp.error());
52*38e8c45fSAndroid Build Coastguard Worker }
53*38e8c45fSAndroid Build Coastguard Worker
TEST(Expected,HasError)54*38e8c45fSAndroid Build Coastguard Worker TEST(Expected, HasError) {
55*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(IntExp(123).has_error([](auto) { return true; }));
56*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(IntExp(ftl::Unexpected(std::errc::io_error)).has_error([](auto) { return false; }));
57*38e8c45fSAndroid Build Coastguard Worker
58*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(StringExp(ftl::Unexpected(std::errc::permission_denied)).has_error([](auto e) {
59*38e8c45fSAndroid Build Coastguard Worker return e == std::errc::permission_denied;
60*38e8c45fSAndroid Build Coastguard Worker }));
61*38e8c45fSAndroid Build Coastguard Worker }
62*38e8c45fSAndroid Build Coastguard Worker
TEST(Expected,ValueOpt)63*38e8c45fSAndroid Build Coastguard Worker TEST(Expected, ValueOpt) {
64*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(ftl::Optional(-1), IntExp(-1).value_opt());
65*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(std::nullopt, IntExp(ftl::Unexpected(std::errc::broken_pipe)).value_opt());
66*38e8c45fSAndroid Build Coastguard Worker
67*38e8c45fSAndroid Build Coastguard Worker {
68*38e8c45fSAndroid Build Coastguard Worker const StringExp exp("foo"s);
69*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(ftl::Optional('f'),
70*38e8c45fSAndroid Build Coastguard Worker exp.value_opt().transform([](const auto& s) { return s.front(); }));
71*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ("foo"s, exp.value());
72*38e8c45fSAndroid Build Coastguard Worker }
73*38e8c45fSAndroid Build Coastguard Worker {
74*38e8c45fSAndroid Build Coastguard Worker StringExp exp("foobar"s);
75*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(ftl::Optional(6), std::move(exp).value_opt().transform(&std::string::length));
76*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(exp.value().empty());
77*38e8c45fSAndroid Build Coastguard Worker }
78*38e8c45fSAndroid Build Coastguard Worker }
79*38e8c45fSAndroid Build Coastguard Worker
80*38e8c45fSAndroid Build Coastguard Worker namespace {
81*38e8c45fSAndroid Build Coastguard Worker
increment_try(IntExp exp)82*38e8c45fSAndroid Build Coastguard Worker IntExp increment_try(IntExp exp) {
83*38e8c45fSAndroid Build Coastguard Worker const int i = FTL_TRY(exp);
84*38e8c45fSAndroid Build Coastguard Worker return IntExp(i + 1);
85*38e8c45fSAndroid Build Coastguard Worker }
86*38e8c45fSAndroid Build Coastguard Worker
increment_expect(IntExp exp,int & out)87*38e8c45fSAndroid Build Coastguard Worker std::errc increment_expect(IntExp exp, int& out) {
88*38e8c45fSAndroid Build Coastguard Worker const int i = FTL_EXPECT(exp);
89*38e8c45fSAndroid Build Coastguard Worker out = i + 1;
90*38e8c45fSAndroid Build Coastguard Worker return std::errc::operation_in_progress;
91*38e8c45fSAndroid Build Coastguard Worker }
92*38e8c45fSAndroid Build Coastguard Worker
repeat_try(StringExp exp)93*38e8c45fSAndroid Build Coastguard Worker StringExp repeat_try(StringExp exp) {
94*38e8c45fSAndroid Build Coastguard Worker const std::string str = FTL_TRY(exp);
95*38e8c45fSAndroid Build Coastguard Worker return StringExp(str + str);
96*38e8c45fSAndroid Build Coastguard Worker }
97*38e8c45fSAndroid Build Coastguard Worker
repeat_expect(StringExp exp,std::string & out)98*38e8c45fSAndroid Build Coastguard Worker std::errc repeat_expect(StringExp exp, std::string& out) {
99*38e8c45fSAndroid Build Coastguard Worker const std::string str = FTL_EXPECT(exp);
100*38e8c45fSAndroid Build Coastguard Worker out = str + str;
101*38e8c45fSAndroid Build Coastguard Worker return std::errc::operation_in_progress;
102*38e8c45fSAndroid Build Coastguard Worker }
103*38e8c45fSAndroid Build Coastguard Worker
uppercase(char & c,ftl::Optional<char> opt)104*38e8c45fSAndroid Build Coastguard Worker void uppercase(char& c, ftl::Optional<char> opt) {
105*38e8c45fSAndroid Build Coastguard Worker c = std::toupper(FTL_TRY(std::move(opt).ok_or(ftl::Unit())));
106*38e8c45fSAndroid Build Coastguard Worker }
107*38e8c45fSAndroid Build Coastguard Worker
108*38e8c45fSAndroid Build Coastguard Worker } // namespace
109*38e8c45fSAndroid Build Coastguard Worker
110*38e8c45fSAndroid Build Coastguard Worker // Keep in sync with example usage in header file.
TEST(Expected,Try)111*38e8c45fSAndroid Build Coastguard Worker TEST(Expected, Try) {
112*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(IntExp(100), increment_try(IntExp(99)));
113*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(increment_try(ftl::Unexpected(std::errc::value_too_large)).has_error([](std::errc e) {
114*38e8c45fSAndroid Build Coastguard Worker return e == std::errc::value_too_large;
115*38e8c45fSAndroid Build Coastguard Worker }));
116*38e8c45fSAndroid Build Coastguard Worker
117*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(StringExp("haha"s), repeat_try(StringExp("ha"s)));
118*38e8c45fSAndroid Build Coastguard Worker EXPECT_TRUE(repeat_try(ftl::Unexpected(std::errc::bad_message)).has_error([](std::errc e) {
119*38e8c45fSAndroid Build Coastguard Worker return e == std::errc::bad_message;
120*38e8c45fSAndroid Build Coastguard Worker }));
121*38e8c45fSAndroid Build Coastguard Worker
122*38e8c45fSAndroid Build Coastguard Worker char c = '?';
123*38e8c45fSAndroid Build Coastguard Worker uppercase(c, std::nullopt);
124*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(c, '?');
125*38e8c45fSAndroid Build Coastguard Worker
126*38e8c45fSAndroid Build Coastguard Worker uppercase(c, 'a');
127*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(c, 'A');
128*38e8c45fSAndroid Build Coastguard Worker }
129*38e8c45fSAndroid Build Coastguard Worker
TEST(Expected,Expect)130*38e8c45fSAndroid Build Coastguard Worker TEST(Expected, Expect) {
131*38e8c45fSAndroid Build Coastguard Worker int i = 0;
132*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(std::errc::operation_in_progress, increment_expect(IntExp(99), i));
133*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(100, i);
134*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(std::errc::value_too_large,
135*38e8c45fSAndroid Build Coastguard Worker increment_expect(ftl::Unexpected(std::errc::value_too_large), i));
136*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(100, i);
137*38e8c45fSAndroid Build Coastguard Worker
138*38e8c45fSAndroid Build Coastguard Worker std::string str;
139*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(std::errc::operation_in_progress, repeat_expect(StringExp("ha"s), str));
140*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ("haha"s, str);
141*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(std::errc::bad_message, repeat_expect(ftl::Unexpected(std::errc::bad_message), str));
142*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ("haha"s, str);
143*38e8c45fSAndroid Build Coastguard Worker }
144*38e8c45fSAndroid Build Coastguard Worker
145*38e8c45fSAndroid Build Coastguard Worker } // namespace android::test
146