1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/core/lib/promise/try_seq.h"
16
17 #include <stdlib.h>
18
19 #include <memory>
20 #include <string>
21 #include <vector>
22
23 #include "gtest/gtest.h"
24 #include "test/core/promise/poll_matcher.h"
25
26 namespace grpc_core {
27
28 struct AbslStatusTraits {
29 template <typename T>
30 using Promise = std::function<Poll<absl::StatusOr<T>>()>;
31
32 template <typename T>
instant_okgrpc_core::AbslStatusTraits33 static Promise<T> instant_ok(T x) {
34 return [x] { return absl::StatusOr<T>(x); };
35 }
36
instant_ok_statusgrpc_core::AbslStatusTraits37 static auto instant_ok_status() {
38 return [] { return absl::OkStatus(); };
39 }
40
41 template <typename T>
instant_failgrpc_core::AbslStatusTraits42 static Promise<T> instant_fail() {
43 return [] { return absl::StatusOr<T>(); };
44 }
45
46 template <typename T>
instant_crashgrpc_core::AbslStatusTraits47 static Poll<absl::StatusOr<T>> instant_crash() {
48 abort();
49 }
50
51 template <typename T>
okgrpc_core::AbslStatusTraits52 static Poll<absl::StatusOr<T>> ok(T x) {
53 return absl::StatusOr<T>(x);
54 }
55
ok_statusgrpc_core::AbslStatusTraits56 static Poll<absl::Status> ok_status() { return absl::OkStatus(); }
57
58 template <typename T>
failgrpc_core::AbslStatusTraits59 static Poll<absl::StatusOr<T>> fail() {
60 return absl::StatusOr<T>();
61 }
62
63 template <typename T>
pendinggrpc_core::AbslStatusTraits64 static Promise<T> pending() {
65 return []() -> Poll<absl::StatusOr<T>> { return Pending(); };
66 }
67 };
68
69 struct ValueOrFailureTraits {
70 template <typename T>
71 using Promise = std::function<Poll<ValueOrFailure<T>>()>;
72
73 template <typename T>
instant_okgrpc_core::ValueOrFailureTraits74 static Promise<T> instant_ok(T x) {
75 return [x] { return ValueOrFailure<T>(x); };
76 }
77
instant_ok_statusgrpc_core::ValueOrFailureTraits78 static auto instant_ok_status() {
79 return [] { return StatusFlag(true); };
80 }
81
82 template <typename T>
instant_failgrpc_core::ValueOrFailureTraits83 static Promise<T> instant_fail() {
84 return [] { return Failure{}; };
85 }
86
87 template <typename T>
instant_crashgrpc_core::ValueOrFailureTraits88 static Poll<ValueOrFailure<T>> instant_crash() {
89 abort();
90 }
91
92 template <typename T>
okgrpc_core::ValueOrFailureTraits93 static Poll<ValueOrFailure<T>> ok(T x) {
94 return ValueOrFailure<T>(x);
95 }
96
ok_statusgrpc_core::ValueOrFailureTraits97 static Poll<StatusFlag> ok_status() { return Success{}; }
98
99 template <typename T>
failgrpc_core::ValueOrFailureTraits100 static Poll<ValueOrFailure<T>> fail() {
101 return Failure{};
102 }
103
104 template <typename T>
pendinggrpc_core::ValueOrFailureTraits105 static Promise<T> pending() {
106 return []() -> Poll<ValueOrFailure<T>> { return Pending(); };
107 }
108 };
109
110 template <typename T>
111 class TrySeqTest : public ::testing::Test {};
112
113 using Traits = ::testing::Types<AbslStatusTraits, ValueOrFailureTraits>;
114 TYPED_TEST_SUITE(TrySeqTest, Traits);
115
TYPED_TEST(TrySeqTest,SucceedAndThen)116 TYPED_TEST(TrySeqTest, SucceedAndThen) {
117 EXPECT_EQ(TrySeq(TypeParam::instant_ok(1),
118 [](int i) { return TypeParam::instant_ok(i + 1); })(),
119 TypeParam::ok(2));
120 }
121
TYPED_TEST(TrySeqTest,SucceedDirectlyAndThenDirectly)122 TYPED_TEST(TrySeqTest, SucceedDirectlyAndThenDirectly) {
123 EXPECT_EQ(
124 TrySeq([] { return 1; }, [](int i) { return [i]() { return i + 1; }; })(),
125 Poll<absl::StatusOr<int>>(2));
126 }
127
TYPED_TEST(TrySeqTest,SucceedAndThenChangeType)128 TYPED_TEST(TrySeqTest, SucceedAndThenChangeType) {
129 EXPECT_EQ(
130 TrySeq(TypeParam::instant_ok(42),
131 [](int i) { return TypeParam::instant_ok(std::to_string(i)); })(),
132 TypeParam::ok(std::string("42")));
133 }
134
TYPED_TEST(TrySeqTest,FailAndThen)135 TYPED_TEST(TrySeqTest, FailAndThen) {
136 EXPECT_EQ(
137 TrySeq(TypeParam::template instant_fail<int>(),
138 [](int) { return TypeParam::template instant_crash<double>(); })(),
139 TypeParam::template fail<double>());
140 }
141
TYPED_TEST(TrySeqTest,RawSucceedAndThen)142 TYPED_TEST(TrySeqTest, RawSucceedAndThen) {
143 EXPECT_EQ(TrySeq(TypeParam::instant_ok_status(),
144 [] { return TypeParam::instant_ok_status(); })(),
145 TypeParam::ok_status());
146 }
147
TYPED_TEST(TrySeqTest,RawFailAndThen)148 TYPED_TEST(TrySeqTest, RawFailAndThen) {
149 EXPECT_EQ(TrySeq([] { return absl::CancelledError(); },
150 []() { return []() -> Poll<absl::Status> { abort(); }; })(),
151 Poll<absl::Status>(absl::CancelledError()));
152 }
153
TYPED_TEST(TrySeqTest,RawSucceedAndThenValue)154 TYPED_TEST(TrySeqTest, RawSucceedAndThenValue) {
155 EXPECT_EQ(TrySeq([] { return absl::OkStatus(); },
156 [] { return []() { return absl::StatusOr<int>(42); }; })(),
157 Poll<absl::StatusOr<int>>(absl::StatusOr<int>(42)));
158 }
159
TEST(TrySeqIterTest,Ok)160 TEST(TrySeqIterTest, Ok) {
161 std::vector<int> v{1, 2, 3, 4, 5};
162 EXPECT_EQ(TrySeqIter(v.begin(), v.end(), 0,
163 [](int elem, int accum) {
164 return [elem, accum]() -> absl::StatusOr<int> {
165 return elem + accum;
166 };
167 })(),
168 Poll<absl::StatusOr<int>>(15));
169 }
170
TEST(TrySeqIterTest,ErrorAt3)171 TEST(TrySeqIterTest, ErrorAt3) {
172 std::vector<int> v{1, 2, 3, 4, 5};
173 EXPECT_EQ(TrySeqIter(v.begin(), v.end(), 0,
174 [](int elem, int accum) {
175 return [elem, accum]() -> absl::StatusOr<int> {
176 if (elem < 3) {
177 return elem + accum;
178 }
179 if (elem == 3) {
180 return absl::CancelledError();
181 }
182 abort(); // unreachable
183 };
184 })(),
185 Poll<absl::StatusOr<int>>(absl::CancelledError()));
186 }
187
TEST(TrySeqContainer,Ok)188 TEST(TrySeqContainer, Ok) {
189 std::vector<std::unique_ptr<int>> v;
190 v.emplace_back(std::make_unique<int>(1));
191 v.emplace_back(std::make_unique<int>(2));
192 v.emplace_back(std::make_unique<int>(3));
193 int expect = 1;
194 auto p = TrySeqContainer(std::move(v), Empty{},
195 [&expect](const std::unique_ptr<int>& i, Empty) {
196 EXPECT_EQ(*i, expect);
197 ++expect;
198 });
199 EXPECT_THAT(p(), IsReady());
200 EXPECT_EQ(expect, 4);
201 }
202
203 } // namespace grpc_core
204
main(int argc,char ** argv)205 int main(int argc, char** argv) {
206 ::testing::InitGoogleTest(&argc, argv);
207 return RUN_ALL_TESTS();
208 }
209