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 30TEST(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 37TEST(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 45TEST(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 52TEST(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 60TEST(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 67TEST(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 74TEST(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 81TEST(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 97TEST(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 105TEST(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. 113TEST(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 129TEST(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 140TEST(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 172TEST(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