blob: 19caaf5b53847865802d34a14e2e5b00f063af86 [file] [log] [blame]
Tom Cherry11a3aee2017-08-03 12:54:07 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "result.h"
18
19#include "errno.h"
20
21#include <string>
22
23#include <gtest/gtest.h>
24
25using namespace std::string_literals;
26
27namespace android {
28namespace init {
29
30TEST(result, result_accessors) {
31 Result<std::string> result = "success";
32 ASSERT_TRUE(result);
33 ASSERT_TRUE(result.has_value());
34
35 EXPECT_EQ("success", *result);
36 EXPECT_EQ("success", result.value());
37
38 EXPECT_EQ('s', result->data()[0]);
39}
40
41TEST(result, result_accessors_rvalue) {
42 ASSERT_TRUE(Result<std::string>("success"));
43 ASSERT_TRUE(Result<std::string>("success").has_value());
44
45 EXPECT_EQ("success", *Result<std::string>("success"));
46 EXPECT_EQ("success", Result<std::string>("success").value());
47
48 EXPECT_EQ('s', Result<std::string>("success")->data()[0]);
49}
50
51TEST(result, result_success) {
52 Result<Success> result = Success();
53 ASSERT_TRUE(result);
54 ASSERT_TRUE(result.has_value());
55
56 EXPECT_EQ(Success(), *result);
57 EXPECT_EQ(Success(), result.value());
58}
59
60TEST(result, result_success_rvalue) {
61 // Success() doesn't actually create a Result<Success> object, but rather an object that can be
62 // implicitly constructed into a Result<Success> object.
63
64 auto MakeRvalueSuccessResult = []() -> Result<Success> { return Success(); };
65 ASSERT_TRUE(MakeRvalueSuccessResult());
66 ASSERT_TRUE(MakeRvalueSuccessResult().has_value());
67
68 EXPECT_EQ(Success(), *MakeRvalueSuccessResult());
69 EXPECT_EQ(Success(), MakeRvalueSuccessResult().value());
70}
71
72TEST(result, result_error) {
73 Result<Success> result = Error() << "failure" << 1;
74 ASSERT_FALSE(result);
75 ASSERT_FALSE(result.has_value());
76
Tom Cherry130e3d72017-08-22 16:07:15 -070077 EXPECT_EQ(0, result.error_errno());
78 EXPECT_EQ("failure1", result.error_string());
Tom Cherry11a3aee2017-08-03 12:54:07 -070079}
80
81TEST(result, result_error_empty) {
82 Result<Success> result = Error();
83 ASSERT_FALSE(result);
84 ASSERT_FALSE(result.has_value());
85
Tom Cherry130e3d72017-08-22 16:07:15 -070086 EXPECT_EQ(0, result.error_errno());
87 EXPECT_EQ("", result.error_string());
Tom Cherry11a3aee2017-08-03 12:54:07 -070088}
89
90TEST(result, result_error_rvalue) {
91 // Error() and ErrnoError() aren't actually used to create a Result<T> object.
92 // Under the hood, they are an intermediate class that can be implicitly constructed into a
93 // Result<T>. This is needed both to create the ostream and because Error() itself, by
94 // definition will not know what the type, T, of the underlying Result<T> object that it would
95 // create is.
96
97 auto MakeRvalueErrorResult = []() -> Result<Success> { return Error() << "failure" << 1; };
98 ASSERT_FALSE(MakeRvalueErrorResult());
99 ASSERT_FALSE(MakeRvalueErrorResult().has_value());
100
Tom Cherry130e3d72017-08-22 16:07:15 -0700101 EXPECT_EQ(0, MakeRvalueErrorResult().error_errno());
102 EXPECT_EQ("failure1", MakeRvalueErrorResult().error_string());
Tom Cherry11a3aee2017-08-03 12:54:07 -0700103}
104
105TEST(result, result_errno_error) {
106 constexpr int test_errno = 6;
107 errno = test_errno;
108 Result<Success> result = ErrnoError() << "failure" << 1;
109
110 ASSERT_FALSE(result);
111 ASSERT_FALSE(result.has_value());
112
Tom Cherry130e3d72017-08-22 16:07:15 -0700113 EXPECT_EQ(test_errno, result.error_errno());
114 EXPECT_EQ("failure1: "s + strerror(test_errno), result.error_string());
115}
116
117TEST(result, result_errno_error_no_text) {
118 constexpr int test_errno = 6;
119 errno = test_errno;
120 Result<Success> result = ErrnoError();
121
122 ASSERT_FALSE(result);
123 ASSERT_FALSE(result.has_value());
124
125 EXPECT_EQ(test_errno, result.error_errno());
126 EXPECT_EQ(strerror(test_errno), result.error_string());
127}
128
129TEST(result, result_error_from_other_result) {
130 auto error_text = "test error"s;
131 Result<Success> result = Error() << error_text;
132
133 ASSERT_FALSE(result);
134 ASSERT_FALSE(result.has_value());
135
136 Result<std::string> result2 = result.error();
137
138 ASSERT_FALSE(result2);
139 ASSERT_FALSE(result2.has_value());
140
141 EXPECT_EQ(0, result.error_errno());
142 EXPECT_EQ(error_text, result.error_string());
143}
144
145TEST(result, result_error_through_ostream) {
146 auto error_text = "test error"s;
147 Result<Success> result = Error() << error_text;
148
149 ASSERT_FALSE(result);
150 ASSERT_FALSE(result.has_value());
151
152 Result<std::string> result2 = Error() << result.error();
153
154 ASSERT_FALSE(result2);
155 ASSERT_FALSE(result2.has_value());
156
157 EXPECT_EQ(0, result.error_errno());
158 EXPECT_EQ(error_text, result.error_string());
159}
160
161TEST(result, result_errno_error_through_ostream) {
162 auto error_text = "test error"s;
163 constexpr int test_errno = 6;
164 errno = 6;
165 Result<Success> result = ErrnoError() << error_text;
166
167 errno = 0;
168
169 ASSERT_FALSE(result);
170 ASSERT_FALSE(result.has_value());
171
172 Result<std::string> result2 = Error() << result.error();
173
174 ASSERT_FALSE(result2);
175 ASSERT_FALSE(result2.has_value());
176
177 EXPECT_EQ(test_errno, result.error_errno());
178 EXPECT_EQ(error_text + ": " + strerror(test_errno), result.error_string());
Tom Cherry11a3aee2017-08-03 12:54:07 -0700179}
180
181TEST(result, constructor_forwarding) {
182 auto result = Result<std::string>(5, 'a');
183
184 ASSERT_TRUE(result);
185 ASSERT_TRUE(result.has_value());
186
187 EXPECT_EQ("aaaaa", *result);
188}
189
190struct ConstructorTracker {
191 static size_t constructor_called;
192 static size_t copy_constructor_called;
193 static size_t move_constructor_called;
194 static size_t copy_assignment_called;
195 static size_t move_assignment_called;
196
197 template <typename T>
198 ConstructorTracker(T&& string) : string(string) {
199 ++constructor_called;
200 }
201
202 ConstructorTracker(const ConstructorTracker& ct) {
203 ++copy_constructor_called;
204 string = ct.string;
205 }
206 ConstructorTracker(ConstructorTracker&& ct) noexcept {
207 ++move_constructor_called;
208 string = std::move(ct.string);
209 }
210 ConstructorTracker& operator=(const ConstructorTracker& ct) {
211 ++copy_assignment_called;
212 string = ct.string;
213 return *this;
214 }
215 ConstructorTracker& operator=(ConstructorTracker&& ct) noexcept {
216 ++move_assignment_called;
217 string = std::move(ct.string);
218 return *this;
219 }
220
221 std::string string;
222};
223
224size_t ConstructorTracker::constructor_called = 0;
225size_t ConstructorTracker::copy_constructor_called = 0;
226size_t ConstructorTracker::move_constructor_called = 0;
227size_t ConstructorTracker::copy_assignment_called = 0;
228size_t ConstructorTracker::move_assignment_called = 0;
229
230Result<ConstructorTracker> ReturnConstructorTracker(const std::string& in) {
231 if (in.empty()) {
232 return "literal string";
233 }
234 if (in == "test2") {
235 return ConstructorTracker(in + in + "2");
236 }
237 ConstructorTracker result(in + " " + in);
238 return result;
239};
240
241TEST(result, no_copy_on_return) {
242 // If returning parameters that may be used to implicitly construct the type T of Result<T>,
243 // then those parameters are forwarded to the construction of Result<T>.
244
245 // If returning an prvalue or xvalue, it will be move constructed during the construction of
246 // Result<T>.
247
248 // This check ensures that that is the case, and particularly that no copy constructors
249 // are called.
250
251 auto result1 = ReturnConstructorTracker("");
252 ASSERT_TRUE(result1);
253 EXPECT_EQ("literal string", result1->string);
254 EXPECT_EQ(1U, ConstructorTracker::constructor_called);
255 EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
256 EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
257 EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
258 EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
259
260 auto result2 = ReturnConstructorTracker("test2");
261 ASSERT_TRUE(result2);
262 EXPECT_EQ("test2test22", result2->string);
263 EXPECT_EQ(2U, ConstructorTracker::constructor_called);
264 EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
265 EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
266 EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
267 EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
268
269 auto result3 = ReturnConstructorTracker("test3");
270 ASSERT_TRUE(result3);
271 EXPECT_EQ("test3 test3", result3->string);
272 EXPECT_EQ(3U, ConstructorTracker::constructor_called);
273 EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
274 EXPECT_EQ(2U, ConstructorTracker::move_constructor_called);
275 EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
276 EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
277}
278
279TEST(result, die_on_access_failed_result) {
280 Result<std::string> result = Error();
281 ASSERT_DEATH(*result, "");
282}
283
284TEST(result, die_on_get_error_succesful_result) {
285 Result<std::string> result = "success";
Tom Cherry130e3d72017-08-22 16:07:15 -0700286 ASSERT_DEATH(result.error_string(), "");
Tom Cherry11a3aee2017-08-03 12:54:07 -0700287}
288
289} // namespace init
290} // namespace android