1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2017 Couchbase, Inc
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "config.h"
19
20 #include "atomic.h"
21 #include "tagged_ptr.h"
22
23 #include <gtest/gtest.h>
24
25 /*
26 * Unit tests for the TaggedPtr class.
27 */
28
29 /// Test constructor taking object
TEST(TaggedPtrTest, constructorObjectTest)30 TEST(TaggedPtrTest, constructorObjectTest) {
31 uint32_t data = 123;
32 TaggedPtr<uint32_t> taggedPtr(&data);
33 ASSERT_EQ(&data, taggedPtr.get());
34 }
35
36 /// Test constructor taking object and tag
TEST(TaggedPtrTest, constructorObjectAndTagTest)37 TEST(TaggedPtrTest, constructorObjectAndTagTest) {
38 uint32_t data = 123;
39 TaggedPtr<uint32_t> taggedPtr(&data, 456);
40 EXPECT_EQ(&data, taggedPtr.get());
41 EXPECT_EQ(456, taggedPtr.getTag());
42 }
43
44 /// Test equal operator of TaggedPtr
TEST(TaggedPtrTest, equalTest)45 TEST(TaggedPtrTest, equalTest) {
46 uint32_t data = 0;
47 TaggedPtr<uint32_t> taggedPtr(&data);
48 EXPECT_TRUE(taggedPtr.get() == &data);
49 }
50
51 /// Test not equal operator of TaggedPtr
TEST(TaggedPtrTest, notEqualTest)52 TEST(TaggedPtrTest, notEqualTest) {
53 uint32_t data = 0;
54 uint32_t newData = 0;
55 TaggedPtr<uint32_t> taggedPtr(&data);
56 EXPECT_TRUE(taggedPtr.get() != &newData);
57 }
58
59 /// Test boolean operator of TaggedPtr - True case
TEST(TaggedPtrTest, boolTrueTest)60 TEST(TaggedPtrTest, boolTrueTest) {
61 uint32_t data = 123;
62 TaggedPtr<uint32_t> taggedPtr(&data);
63 EXPECT_TRUE(taggedPtr);
64 }
65
66 /// Test boolean operator of TaggedPtr - False case
TEST(TaggedPtrTest, boolFalseTest)67 TEST(TaggedPtrTest, boolFalseTest) {
68 TaggedPtr<uint32_t> taggedPtr;
69 EXPECT_FALSE(taggedPtr);
70 }
71
72 /// Check that when the tag is set if the pointer is nullptr then calling the
73 /// bool method on the taggedptr will return false
TEST(TaggedPtrTest, boolWithTagFalseTest)74 TEST(TaggedPtrTest, boolWithTagFalseTest) {
75 TaggedPtr<uint32_t> taggedPtr(nullptr, 123);
76 ASSERT_EQ(123, taggedPtr.getTag());
77 EXPECT_FALSE(taggedPtr);
78 }
79
80 /// Test the -> operator of TaggedPtr
TEST(TaggedPtrTest, ptrTest)81 TEST(TaggedPtrTest, ptrTest) {
82 class TestObject {
83 public:
84 TestObject() {
85 }
86 uint32_t data;
87 };
88
89 TestObject testObject;
90 testObject.data = 123;
91
92 TaggedPtr<TestObject> taggedPtr(&testObject);
93 EXPECT_EQ(123, taggedPtr->data);
94 }
95
96 /// Test set and get of TaggedPtr
TEST(TaggedPtrTest, setObjTest)97 TEST(TaggedPtrTest, setObjTest) {
98 uint32_t data = 0;
99 TaggedPtr<uint32_t> taggedPtr(nullptr);
100 taggedPtr.set(&data);
101 EXPECT_EQ(&data, taggedPtr.get());
102 }
103
104 /// Test setTag and getTag of TaggedPtr
TEST(TaggedPtrTest, setTagTest)105 TEST(TaggedPtrTest, setTagTest) {
106 TaggedPtr<uint32_t> taggedPtr(nullptr);
107 taggedPtr.setTag(123);
108 EXPECT_EQ(123, taggedPtr.getTag());
109 }
110
111 /// Check that the tagged pointer can have its tag set without affecting where
112 /// the pointer points to.
TEST(TaggedPtrTest, pointerUnaffectedTest)113 TEST(TaggedPtrTest, pointerUnaffectedTest) {
114 uint32_t data = 123;
115
116 TaggedPtr<uint32_t> taggedPtr(&data);
117 auto obj = taggedPtr.get();
118
119 // Tag should start at zero i.e. empty
120 ASSERT_EQ(0, taggedPtr.getTag());
121 taggedPtr.setTag(456);
122 ASSERT_EQ(456, taggedPtr.getTag());
123 EXPECT_EQ(obj, taggedPtr.get());
124 EXPECT_EQ(123, *(taggedPtr.get()));
125 }
126
127 /// Check that the tagged pointer can have its pointer set without affecting the
128 /// data held in the tag
TEST(TaggedPtrTest, tagUnaffectedTest)129 TEST(TaggedPtrTest, tagUnaffectedTest) {
130 uint32_t data = 0;
131
132 TaggedPtr<uint32_t> taggedPtr(nullptr, 123);
133 ASSERT_EQ(123, taggedPtr.getTag());
134 taggedPtr.set(&data);
135 ASSERT_EQ(&data, taggedPtr.get());
136 EXPECT_EQ(123, taggedPtr.getTag());
137 }
138
139 /// Check that the tag can be set using the updateTag helper method
TEST(TaggedPtrTest, updateTagTest)140 TEST(TaggedPtrTest, updateTagTest) {
141 // TestObject needs to inherit from RCValue because SingleThreadedRCPtr
142 // only takes RCValues
143 class TestObject : public RCValue {
144 public:
145 TestObject() : data(123) {
146 }
147
148 uint32_t getData() {
149 return data;
150 }
151
152 private:
153 uint32_t data;
154 };
155
156 // Custom deleter for TestObject objects
157 struct Deleter {
158 void operator()(TaggedPtr<TestObject> val) {
159 // Does not do anything
160 }
161 };
162
163 TestObject to;
164 SingleThreadedRCPtr<TestObject, TaggedPtr<TestObject>, Deleter> ptr{
165 TaggedPtr<TestObject>(&to)};
166 TaggedPtr<TestObject>::updateTag(ptr, 456);
167 EXPECT_EQ(456, ptr.get().getTag());
168 }
169
170 /// Check that the tag can be set using the updateTag helper method when pointer
171 /// is a std::unique_ptr
TEST(TaggedPtrTest, updateTagTestUniquePtr)172 TEST(TaggedPtrTest, updateTagTestUniquePtr) {
173 class TestObject {
174 public:
175 TestObject() : data(123) {
176 }
177
178 uint32_t getData() {
179 return data;
180 }
181
182 private:
183 uint32_t data;
184 };
185
186 // Custom deleter for TestObject objects
187 struct Deleter {
188 void operator()(TaggedPtr<TestObject> val) {
189 // Does not do anything
190 }
191 };
192
193 using UniquePtr =
194 std::unique_ptr<TestObject, TaggedPtrDeleter<TestObject, Deleter>>;
195
196 TestObject to;
197 UniquePtr ptr{TaggedPtr<TestObject>(&to)};
198 TaggedPtr<TestObject>::updateTag(ptr, 456);
199 EXPECT_EQ(456, ptr.get().getTag());
200 }
201