1 /*
2 * Copyright 2019 Google LLC
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 "fcp/base/unique_value.h"
18
19 #include <utility>
20
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "absl/strings/str_cat.h"
24 #include "fcp/base/monitoring.h"
25
26 namespace fcp {
27
28 using ::testing::Eq;
29
30 struct ValueBox {
31 bool destructed = false;
32 int value = 0;
33 };
34
35 class TracedValue {
36 public:
TracedValue(int value)37 explicit TracedValue(int value) : local_value_(0), box_(nullptr) {
38 UpdateValue(value);
39 }
40
AttachToBox(ValueBox * box)41 void AttachToBox(ValueBox* box) {
42 FCP_CHECK(box_ == nullptr);
43 box_ = box;
44 UpdateValue(local_value_);
45 }
46
TracedValue(TracedValue const & other)47 TracedValue(TracedValue const& other) : local_value_(0), box_(nullptr) {
48 UpdateValue(other.value());
49 }
50
operator =(TracedValue const & other)51 TracedValue& operator=(TracedValue const& other) {
52 UpdateValue(other.value());
53 return *this;
54 }
55
~TracedValue()56 ~TracedValue() {
57 if (box_) {
58 box_->destructed = true;
59 }
60 }
61
value() const62 int value() const { return local_value_; }
63
64 private:
UpdateValue(int value)65 void UpdateValue(int value) {
66 local_value_ = value;
67 if (box_) {
68 box_->destructed = false;
69 box_->value = value;
70 }
71 }
72
73 int local_value_;
74 ValueBox* box_;
75 };
76
TEST(UniqueValueTest,MoveToInnerScope)77 TEST(UniqueValueTest, MoveToInnerScope) {
78 ValueBox box_a{};
79 ValueBox box_b{};
80
81 {
82 UniqueValue<TracedValue> a = MakeUniqueValue<TracedValue>(123);
83 a->AttachToBox(&box_a);
84 EXPECT_THAT(box_a.destructed, Eq(false));
85 EXPECT_THAT(box_a.value, Eq(123));
86
87 {
88 UniqueValue<TracedValue> b = MakeUniqueValue<TracedValue>(456);
89 b->AttachToBox(&box_b);
90 EXPECT_THAT(box_b.destructed, Eq(false));
91 EXPECT_THAT(box_b.value, Eq(456));
92
93 b = std::move(a);
94
95 EXPECT_THAT(box_a.destructed, Eq(true));
96 EXPECT_THAT(box_b.destructed, Eq(false));
97 EXPECT_THAT(box_b.value, Eq(123));
98 }
99
100 EXPECT_THAT(box_a.destructed, Eq(true));
101 EXPECT_THAT(box_b.destructed, Eq(true));
102 }
103 }
104
TEST(UniqueValueTest,MoveToOuterScope)105 TEST(UniqueValueTest, MoveToOuterScope) {
106 ValueBox box_a{};
107 ValueBox box_b{};
108
109 {
110 UniqueValue<TracedValue> a = MakeUniqueValue<TracedValue>(123);
111 a->AttachToBox(&box_a);
112 EXPECT_THAT(box_a.destructed, Eq(false));
113 EXPECT_THAT(box_a.value, Eq(123));
114
115 {
116 UniqueValue<TracedValue> b = MakeUniqueValue<TracedValue>(456);
117 b->AttachToBox(&box_b);
118 EXPECT_THAT(box_b.destructed, Eq(false));
119 EXPECT_THAT(box_b.value, Eq(456));
120
121 a = std::move(b);
122
123 EXPECT_THAT(box_a.destructed, Eq(false));
124 EXPECT_THAT(box_a.value, Eq(456));
125 EXPECT_THAT(box_b.destructed, Eq(true));
126 }
127
128 EXPECT_THAT(box_a.destructed, Eq(false));
129 EXPECT_THAT(box_a.value, Eq(456));
130 EXPECT_THAT(box_b.destructed, Eq(true));
131 }
132
133 EXPECT_THAT(box_a.destructed, Eq(true));
134 EXPECT_THAT(box_b.destructed, Eq(true));
135 }
136
TEST(UniqueValueTest,Emplace)137 TEST(UniqueValueTest, Emplace) {
138 ValueBox box_a{};
139 ValueBox box_b{};
140 {
141 UniqueValue<TracedValue> v{std::nullopt};
142 v.Emplace(123);
143 v->AttachToBox(&box_a);
144 EXPECT_THAT(box_a.destructed, Eq(false));
145 EXPECT_THAT(box_a.value, Eq(123));
146 v.Emplace(321);
147 v->AttachToBox(&box_b);
148 EXPECT_THAT(box_a.destructed, Eq(true));
149 EXPECT_THAT(box_b.destructed, Eq(false));
150 EXPECT_THAT(box_b.value, Eq(321));
151 }
152 }
153
TEST(UniqueValueTest,Reset)154 TEST(UniqueValueTest, Reset) {
155 ValueBox box_a{};
156 UniqueValue<TracedValue> v = MakeUniqueValue<TracedValue>(123);
157 v.Emplace(123);
158 v->AttachToBox(&box_a);
159 EXPECT_THAT(box_a.destructed, Eq(false));
160 EXPECT_THAT(box_a.value, Eq(123));
161 v.Reset();
162 EXPECT_THAT(box_a.destructed, Eq(true));
163 v.Reset();
164 EXPECT_THAT(box_a.destructed, Eq(true));
165 }
166
167 } // namespace fcp
168