• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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