blob: ca6501369ccec4ff633d085970d4bbf660edd531 [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
77 EXPECT_EQ("failure1", result.error());
78}
79
80TEST(result, result_error_empty) {
81 Result<Success> result = Error();
82 ASSERT_FALSE(result);
83 ASSERT_FALSE(result.has_value());
84
85 EXPECT_EQ("", result.error());
86}
87
88TEST(result, result_error_rvalue) {
89 // Error() and ErrnoError() aren't actually used to create a Result<T> object.
90 // Under the hood, they are an intermediate class that can be implicitly constructed into a
91 // Result<T>. This is needed both to create the ostream and because Error() itself, by
92 // definition will not know what the type, T, of the underlying Result<T> object that it would
93 // create is.
94
95 auto MakeRvalueErrorResult = []() -> Result<Success> { return Error() << "failure" << 1; };
96 ASSERT_FALSE(MakeRvalueErrorResult());
97 ASSERT_FALSE(MakeRvalueErrorResult().has_value());
98
99 EXPECT_EQ("failure1", MakeRvalueErrorResult().error());
100}
101
102TEST(result, result_errno_error) {
103 constexpr int test_errno = 6;
104 errno = test_errno;
105 Result<Success> result = ErrnoError() << "failure" << 1;
106
107 ASSERT_FALSE(result);
108 ASSERT_FALSE(result.has_value());
109
110 EXPECT_EQ("failure1: "s + strerror(test_errno), result.error());
111}
112
113TEST(result, constructor_forwarding) {
114 auto result = Result<std::string>(5, 'a');
115
116 ASSERT_TRUE(result);
117 ASSERT_TRUE(result.has_value());
118
119 EXPECT_EQ("aaaaa", *result);
120}
121
122struct ConstructorTracker {
123 static size_t constructor_called;
124 static size_t copy_constructor_called;
125 static size_t move_constructor_called;
126 static size_t copy_assignment_called;
127 static size_t move_assignment_called;
128
129 template <typename T>
130 ConstructorTracker(T&& string) : string(string) {
131 ++constructor_called;
132 }
133
134 ConstructorTracker(const ConstructorTracker& ct) {
135 ++copy_constructor_called;
136 string = ct.string;
137 }
138 ConstructorTracker(ConstructorTracker&& ct) noexcept {
139 ++move_constructor_called;
140 string = std::move(ct.string);
141 }
142 ConstructorTracker& operator=(const ConstructorTracker& ct) {
143 ++copy_assignment_called;
144 string = ct.string;
145 return *this;
146 }
147 ConstructorTracker& operator=(ConstructorTracker&& ct) noexcept {
148 ++move_assignment_called;
149 string = std::move(ct.string);
150 return *this;
151 }
152
153 std::string string;
154};
155
156size_t ConstructorTracker::constructor_called = 0;
157size_t ConstructorTracker::copy_constructor_called = 0;
158size_t ConstructorTracker::move_constructor_called = 0;
159size_t ConstructorTracker::copy_assignment_called = 0;
160size_t ConstructorTracker::move_assignment_called = 0;
161
162Result<ConstructorTracker> ReturnConstructorTracker(const std::string& in) {
163 if (in.empty()) {
164 return "literal string";
165 }
166 if (in == "test2") {
167 return ConstructorTracker(in + in + "2");
168 }
169 ConstructorTracker result(in + " " + in);
170 return result;
171};
172
173TEST(result, no_copy_on_return) {
174 // If returning parameters that may be used to implicitly construct the type T of Result<T>,
175 // then those parameters are forwarded to the construction of Result<T>.
176
177 // If returning an prvalue or xvalue, it will be move constructed during the construction of
178 // Result<T>.
179
180 // This check ensures that that is the case, and particularly that no copy constructors
181 // are called.
182
183 auto result1 = ReturnConstructorTracker("");
184 ASSERT_TRUE(result1);
185 EXPECT_EQ("literal string", result1->string);
186 EXPECT_EQ(1U, ConstructorTracker::constructor_called);
187 EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
188 EXPECT_EQ(0U, ConstructorTracker::move_constructor_called);
189 EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
190 EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
191
192 auto result2 = ReturnConstructorTracker("test2");
193 ASSERT_TRUE(result2);
194 EXPECT_EQ("test2test22", result2->string);
195 EXPECT_EQ(2U, ConstructorTracker::constructor_called);
196 EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
197 EXPECT_EQ(1U, ConstructorTracker::move_constructor_called);
198 EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
199 EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
200
201 auto result3 = ReturnConstructorTracker("test3");
202 ASSERT_TRUE(result3);
203 EXPECT_EQ("test3 test3", result3->string);
204 EXPECT_EQ(3U, ConstructorTracker::constructor_called);
205 EXPECT_EQ(0U, ConstructorTracker::copy_constructor_called);
206 EXPECT_EQ(2U, ConstructorTracker::move_constructor_called);
207 EXPECT_EQ(0U, ConstructorTracker::copy_assignment_called);
208 EXPECT_EQ(0U, ConstructorTracker::move_assignment_called);
209}
210
211TEST(result, die_on_access_failed_result) {
212 Result<std::string> result = Error();
213 ASSERT_DEATH(*result, "");
214}
215
216TEST(result, die_on_get_error_succesful_result) {
217 Result<std::string> result = "success";
218 ASSERT_DEATH(result.error(), "");
219}
220
221} // namespace init
222} // namespace android