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