1 /*
2 * Copyright (C) 2018 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 "utils/base/statusor.h"
18
19 #include "utils/base/logging.h"
20 #include "utils/base/status.h"
21 #include "gtest/gtest.h"
22
23 namespace libtextclassifier3 {
24 namespace {
25
TEST(StatusOrTest,DoesntDieWhenOK)26 TEST(StatusOrTest, DoesntDieWhenOK) {
27 StatusOr<std::string> status_or_string = std::string("Hello World");
28 EXPECT_TRUE(status_or_string.ok());
29 EXPECT_EQ(status_or_string.ValueOrDie(), "Hello World");
30 }
31
TEST(StatusOrTest,DiesWhenNotOK)32 TEST(StatusOrTest, DiesWhenNotOK) {
33 StatusOr<std::string> status_or_string = {Status::UNKNOWN};
34 EXPECT_FALSE(status_or_string.ok());
35 // Android does not print the error message to stderr, so we are not checking
36 // the error message here.
37 EXPECT_DEATH(status_or_string.ValueOrDie(), "");
38 }
39
40 // Foo is NOT default constructible and can be implicitly converted to from int.
41 class Foo {
42 public:
43 // Copy value conversion
Foo(int i)44 Foo(int i) : i_(i) {} // NOLINT
i() const45 int i() const { return i_; }
46
47 private:
48 int i_;
49 };
50
TEST(StatusOrTest,HandlesNonDefaultConstructibleValues)51 TEST(StatusOrTest, HandlesNonDefaultConstructibleValues) {
52 StatusOr<Foo> foo_or(Foo(7));
53 EXPECT_TRUE(foo_or.ok());
54 EXPECT_EQ(foo_or.ValueOrDie().i(), 7);
55
56 StatusOr<Foo> error_or(Status::UNKNOWN);
57 EXPECT_FALSE(error_or.ok());
58 EXPECT_EQ(error_or.status().CanonicalCode(), StatusCode::UNKNOWN);
59 }
60
61 class Bar {
62 public:
63 // Move value conversion
Bar(Foo && f)64 Bar(Foo&& f) : i_(2 * f.i()) {} // NOLINT
65
66 // Movable, but not copyable.
67 Bar(const Bar& other) = delete;
68 Bar& operator=(const Bar& rhs) = delete;
69 Bar(Bar&& other) = default;
70 Bar& operator=(Bar&& rhs) = default;
71
i() const72 int i() const { return i_; }
73
74 private:
75 int i_;
76 };
77
TEST(StatusOrTest,HandlesValueConversion)78 TEST(StatusOrTest, HandlesValueConversion) {
79 // Copy value conversion constructor : StatusOr<Foo>(const int&)
80 StatusOr<Foo> foo_status(19);
81 EXPECT_TRUE(foo_status.ok());
82 EXPECT_EQ(foo_status.ValueOrDie().i(), 19);
83
84 // Move value conversion constructor : StatusOr<Bar>(Foo&&)
85 StatusOr<Bar> bar_status(std::move(foo_status));
86 EXPECT_TRUE(bar_status.ok());
87 EXPECT_EQ(bar_status.ValueOrDie().i(), 38);
88
89 StatusOr<int> int_status(19);
90 // Copy conversion constructor : StatusOr<Foo>(const StatusOr<int>&)
91 StatusOr<Foo> copied_status(int_status);
92 EXPECT_TRUE(copied_status.ok());
93 EXPECT_EQ(copied_status.ValueOrDie().i(), 19);
94
95 // Move conversion constructor : StatusOr<Bar>(StatusOr<Foo>&&)
96 StatusOr<Bar> moved_status(std::move(copied_status));
97 EXPECT_TRUE(moved_status.ok());
98 EXPECT_EQ(moved_status.ValueOrDie().i(), 38);
99
100 // Move conversion constructor with error : StatusOr<Bar>(StatusOr<Foo>&&)
101 StatusOr<Foo> error_status(Status::UNKNOWN);
102 StatusOr<Bar> moved_error_status(std::move(error_status));
103 EXPECT_FALSE(moved_error_status.ok());
104 }
105
106 // Create a class that has validly defined copy and move operators, but will
107 // cause a crash if assignment operators are invoked on an instance that was
108 // never initialized.
109 class Baz {
110 public:
Baz()111 Baz() : i_(new int), invalid_(false) {}
Baz(const Baz & other)112 Baz(const Baz& other) {
113 i_ = new int;
114 *i_ = *other.i_;
115 invalid_ = false;
116 }
Baz(const Foo & other)117 Baz(const Foo& other) { // NOLINT
118 i_ = new int;
119 *i_ = other.i();
120 invalid_ = false;
121 }
Baz(Baz && other)122 Baz(Baz&& other) {
123 // Copy other.i_ into this so that this holds it now. Mark other as invalid
124 // so that it doesn't destroy the int that this now owns when other is
125 // destroyed.
126 i_ = other.i_;
127 other.invalid_ = true;
128 invalid_ = false;
129 }
operator =(const Baz & rhs)130 Baz& operator=(const Baz& rhs) {
131 // Copy rhs.i_ into tmp. Then swap this with tmp so that this no has the
132 // value that rhs had and tmp will destroy the value that this used to hold.
133 Baz tmp(rhs);
134 std::swap(i_, tmp.i_);
135 return *this;
136 }
operator =(Baz && rhs)137 Baz& operator=(Baz&& rhs) {
138 std::swap(i_, rhs.i_);
139 return *this;
140 }
~Baz()141 ~Baz() {
142 if (!invalid_) delete i_;
143 }
144
145 private:
146 int* i_;
147 bool invalid_;
148 };
149
TEST(StatusOrTest,CopyAssignment)150 TEST(StatusOrTest, CopyAssignment) {
151 StatusOr<Baz> baz_or;
152 EXPECT_FALSE(baz_or.ok());
153 Baz b;
154 StatusOr<Baz> other(b);
155 baz_or = other;
156 EXPECT_TRUE(baz_or.ok());
157 EXPECT_TRUE(other.ok());
158 }
159
TEST(StatusOrTest,MoveAssignment)160 TEST(StatusOrTest, MoveAssignment) {
161 StatusOr<Baz> baz_or;
162 EXPECT_FALSE(baz_or.ok());
163 baz_or = StatusOr<Baz>(Baz());
164 EXPECT_TRUE(baz_or.ok());
165 }
166
TEST(StatusOrTest,CopyConversionAssignment)167 TEST(StatusOrTest, CopyConversionAssignment) {
168 StatusOr<Baz> baz_or;
169 EXPECT_FALSE(baz_or.ok());
170 StatusOr<Foo> foo_or(Foo(12));
171 baz_or = foo_or;
172 EXPECT_TRUE(baz_or.ok());
173 EXPECT_TRUE(foo_or.ok());
174 }
175
TEST(StatusOrTest,MoveConversionAssignment)176 TEST(StatusOrTest, MoveConversionAssignment) {
177 StatusOr<Baz> baz_or;
178 EXPECT_FALSE(baz_or.ok());
179 StatusOr<Foo> foo_or(Foo(12));
180 baz_or = std::move(foo_or);
181 EXPECT_TRUE(baz_or.ok());
182 }
183
184 struct OkFn {
operator ()libtextclassifier3::__anonfec098400111::OkFn185 StatusOr<int> operator()() { return 42; }
186 };
TEST(StatusOrTest,AssignOrReturnValOk)187 TEST(StatusOrTest, AssignOrReturnValOk) {
188 auto lambda = []() {
189 TC3_ASSIGN_OR_RETURN(int i, OkFn()(), -1);
190 return i;
191 };
192
193 // OkFn() should return a valid integer, so lambda should return that integer.
194 EXPECT_EQ(lambda(), 42);
195 }
196
197 struct FailFn {
operator ()libtextclassifier3::__anonfec098400111::FailFn198 StatusOr<int> operator()() { return Status::UNKNOWN; }
199 };
TEST(StatusOrTest,AssignOrReturnValError)200 TEST(StatusOrTest, AssignOrReturnValError) {
201 auto lambda = []() {
202 TC3_ASSIGN_OR_RETURN(int i, FailFn()(), -1);
203 return i;
204 };
205
206 // FailFn() should return an error, so lambda should return -1.
207 EXPECT_EQ(lambda(), -1);
208 }
209
210 } // namespace
211 } // namespace libtextclassifier3
212