1 // Copyright 2021 The Abseil Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/strings/internal/cordz_update_tracker.h"
16
17 #include <array>
18 #include <thread> // NOLINT
19
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "absl/base/attributes.h"
23 #include "absl/base/config.h"
24 #include "absl/synchronization/notification.h"
25
26 namespace absl {
27 ABSL_NAMESPACE_BEGIN
28 namespace cord_internal {
29 namespace {
30
31 using ::testing::AnyOf;
32 using ::testing::Eq;
33
34 using Method = CordzUpdateTracker::MethodIdentifier;
35 using Methods = std::array<Method, Method::kNumMethods>;
36
37 // Returns an array of all methods defined in `MethodIdentifier`
AllMethods()38 Methods AllMethods() {
39 return Methods{Method::kUnknown,
40 Method::kAppendCord,
41 Method::kAppendExternalMemory,
42 Method::kAppendString,
43 Method::kAssignCord,
44 Method::kAssignString,
45 Method::kClear,
46 Method::kConstructorCord,
47 Method::kConstructorString,
48 Method::kCordReader,
49 Method::kFlatten,
50 Method::kGetAppendRegion,
51 Method::kMakeCordFromExternal,
52 Method::kMoveAppendCord,
53 Method::kMoveAssignCord,
54 Method::kMovePrependCord,
55 Method::kPrependCord,
56 Method::kPrependString,
57 Method::kRemovePrefix,
58 Method::kRemoveSuffix,
59 Method::kSubCord};
60 }
61
TEST(CordzUpdateTracker,IsConstExprAndInitializesToZero)62 TEST(CordzUpdateTracker, IsConstExprAndInitializesToZero) {
63 constexpr CordzUpdateTracker tracker;
64 for (Method method : AllMethods()) {
65 ASSERT_THAT(tracker.Value(method), Eq(0));
66 }
67 }
68
TEST(CordzUpdateTracker,LossyAdd)69 TEST(CordzUpdateTracker, LossyAdd) {
70 int64_t n = 1;
71 CordzUpdateTracker tracker;
72 for (Method method : AllMethods()) {
73 tracker.LossyAdd(method, n);
74 EXPECT_THAT(tracker.Value(method), Eq(n));
75 n += 2;
76 }
77 }
78
TEST(CordzUpdateTracker,CopyConstructor)79 TEST(CordzUpdateTracker, CopyConstructor) {
80 int64_t n = 1;
81 CordzUpdateTracker src;
82 for (Method method : AllMethods()) {
83 src.LossyAdd(method, n);
84 n += 2;
85 }
86
87 n = 1;
88 CordzUpdateTracker tracker(src);
89 for (Method method : AllMethods()) {
90 EXPECT_THAT(tracker.Value(method), Eq(n));
91 n += 2;
92 }
93 }
94
TEST(CordzUpdateTracker,OperatorAssign)95 TEST(CordzUpdateTracker, OperatorAssign) {
96 int64_t n = 1;
97 CordzUpdateTracker src;
98 CordzUpdateTracker tracker;
99 for (Method method : AllMethods()) {
100 src.LossyAdd(method, n);
101 n += 2;
102 }
103
104 n = 1;
105 tracker = src;
106 for (Method method : AllMethods()) {
107 EXPECT_THAT(tracker.Value(method), Eq(n));
108 n += 2;
109 }
110 }
111
TEST(CordzUpdateTracker,ThreadSanitizedValueCheck)112 TEST(CordzUpdateTracker, ThreadSanitizedValueCheck) {
113 absl::Notification done;
114 CordzUpdateTracker tracker;
115
116 std::thread reader([&done, &tracker] {
117 while (!done.HasBeenNotified()) {
118 int n = 1;
119 for (Method method : AllMethods()) {
120 EXPECT_THAT(tracker.Value(method), AnyOf(Eq(n), Eq(0)));
121 n += 2;
122 }
123 }
124 int n = 1;
125 for (Method method : AllMethods()) {
126 EXPECT_THAT(tracker.Value(method), Eq(n));
127 n += 2;
128 }
129 });
130
131 int64_t n = 1;
132 for (Method method : AllMethods()) {
133 tracker.LossyAdd(method, n);
134 n += 2;
135 }
136 done.Notify();
137 reader.join();
138 }
139
140 } // namespace
141 } // namespace cord_internal
142 ABSL_NAMESPACE_END
143 } // namespace absl
144