| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "sync/internal_api/public/util/proto_value_ptr.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <utility> | |
| 9 | |
| 10 #include "base/macros.h" | |
| 11 #include "testing/gtest/include/gtest/gtest.h" | |
| 12 | |
| 13 namespace syncer { | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 // Simple test struct that wraps an integer | |
| 18 struct IntValue { | |
| 19 public: | |
| 20 explicit IntValue(int value) { value_ = value; } | |
| 21 int value() { return value_; } | |
| 22 | |
| 23 private: | |
| 24 int value_; | |
| 25 }; | |
| 26 | |
| 27 // TestValue class is used as a template argument with ProtoValuePtr<T> | |
| 28 class TestValue { | |
| 29 public: | |
| 30 TestValue() : value_(nullptr), is_default_(false) {} | |
| 31 explicit TestValue(int value) | |
| 32 : value_(new IntValue(value)), is_default_(false) {} | |
| 33 | |
| 34 ~TestValue() { g_delete_count++; } | |
| 35 | |
| 36 static void ResetCounters() { | |
| 37 g_copy_count = 0; | |
| 38 g_parse_count = 0; | |
| 39 g_delete_count = 0; | |
| 40 } | |
| 41 | |
| 42 static int copy_count() { return g_copy_count; } | |
| 43 static int parse_count() { return g_parse_count; } | |
| 44 static int delete_count() { return g_delete_count; } | |
| 45 | |
| 46 int value() const { return value_->value(); } | |
| 47 IntValue* value_ptr() const { return value_.get(); } | |
| 48 bool is_initialized() const { return !!value_; } | |
| 49 bool is_default() const { return is_default_; } | |
| 50 | |
| 51 // TestValue uses the default traits struct with ProtoValuePtr<TestValue>. | |
| 52 // The following 4 functions are expected by the traits struct to exist | |
| 53 // in this class. | |
| 54 void CopyFrom(const TestValue& from) { | |
| 55 // Expected to always copy from an initialized instance | |
| 56 // to an uninitialized one. | |
| 57 // Not expected either value to be default. | |
| 58 ASSERT_FALSE(is_initialized()); | |
| 59 ASSERT_FALSE(is_default()); | |
| 60 ASSERT_TRUE(from.is_initialized()); | |
| 61 ASSERT_FALSE(from.is_default()); | |
| 62 value_.reset(new IntValue(from.value())); | |
| 63 g_copy_count++; | |
| 64 } | |
| 65 | |
| 66 void Swap(TestValue* src) { | |
| 67 // Expected to always swap with an initialized instance. | |
| 68 // The current instance must always be an uninitialized one. | |
| 69 // Not expected either value to be default. | |
| 70 ASSERT_FALSE(is_initialized()); | |
| 71 ASSERT_FALSE(is_default()); | |
| 72 ASSERT_TRUE(src->is_initialized()); | |
| 73 ASSERT_FALSE(src->is_default()); | |
| 74 // Not exactly swap, but good enough for the test. | |
| 75 value_ = std::move(src->value_); | |
| 76 } | |
| 77 | |
| 78 void ParseFromArray(const void* blob, int length) { | |
| 79 // Similarly to CopyFrom this is expected to be called on | |
| 80 // an uninitialized instance. | |
| 81 ASSERT_FALSE(is_initialized()); | |
| 82 ASSERT_FALSE(is_default()); | |
| 83 // The blob is an address of an integer | |
| 84 ASSERT_EQ(static_cast<int>(sizeof(int)), length); | |
| 85 value_.reset(new IntValue(*static_cast<const int*>(blob))); | |
| 86 g_parse_count++; | |
| 87 } | |
| 88 | |
| 89 int ByteSize() const { return is_initialized() ? sizeof(int) : 0; } | |
| 90 | |
| 91 static const TestValue& default_instance() { | |
| 92 static TestValue default_instance; | |
| 93 default_instance.is_default_ = true; | |
| 94 return default_instance; | |
| 95 } | |
| 96 | |
| 97 private: | |
| 98 static int g_copy_count; | |
| 99 static int g_parse_count; | |
| 100 static int g_delete_count; | |
| 101 | |
| 102 std::unique_ptr<IntValue> value_; | |
| 103 bool is_default_; | |
| 104 | |
| 105 DISALLOW_COPY_AND_ASSIGN(TestValue); | |
| 106 }; | |
| 107 | |
| 108 // Static initializers. | |
| 109 int TestValue::g_copy_count = 0; | |
| 110 int TestValue::g_parse_count = 0; | |
| 111 int TestValue::g_delete_count = 0; | |
| 112 | |
| 113 } // namespace | |
| 114 | |
| 115 typedef ProtoValuePtr<TestValue> TestPtr; | |
| 116 | |
| 117 class ProtoValuePtrTest : public testing::Test { | |
| 118 public: | |
| 119 void SetUp() override { TestValue::ResetCounters(); } | |
| 120 | |
| 121 static bool WrappedValuesAreShared(const TestPtr& ptr1, const TestPtr& ptr2) { | |
| 122 const TestValue& wrapped_value_1 = ptr1.value(); | |
| 123 const TestValue& wrapped_value_2 = ptr2.value(); | |
| 124 // Compare addresses. | |
| 125 return &wrapped_value_1 == &wrapped_value_2; | |
| 126 } | |
| 127 }; | |
| 128 | |
| 129 TEST_F(ProtoValuePtrTest, ValueAssignment) { | |
| 130 // Basic assignment and default value. | |
| 131 TestValue t1(1); | |
| 132 { | |
| 133 TestPtr ptr1; | |
| 134 EXPECT_TRUE(ptr1->is_default()); | |
| 135 | |
| 136 ptr1.set_value(t1); | |
| 137 EXPECT_FALSE(ptr1->is_default()); | |
| 138 EXPECT_EQ(1, ptr1->value()); | |
| 139 } | |
| 140 | |
| 141 EXPECT_EQ(1, TestValue::copy_count()); | |
| 142 EXPECT_EQ(1, TestValue::delete_count()); | |
| 143 } | |
| 144 | |
| 145 TEST_F(ProtoValuePtrTest, ValueSwap) { | |
| 146 TestValue t2(2); | |
| 147 { | |
| 148 TestPtr ptr2; | |
| 149 EXPECT_TRUE(ptr2->is_default()); | |
| 150 | |
| 151 IntValue* inner_ptr = t2.value_ptr(); | |
| 152 | |
| 153 ptr2.swap_value(&t2); | |
| 154 EXPECT_FALSE(ptr2->is_default()); | |
| 155 EXPECT_EQ(2, ptr2->value()); | |
| 156 EXPECT_EQ(inner_ptr, ptr2->value_ptr()); | |
| 157 } | |
| 158 | |
| 159 EXPECT_EQ(0, TestValue::copy_count()); | |
| 160 EXPECT_EQ(1, TestValue::delete_count()); | |
| 161 } | |
| 162 | |
| 163 TEST_F(ProtoValuePtrTest, SharingTest) { | |
| 164 // Sharing between two pointers. | |
| 165 TestValue empty; | |
| 166 TestValue t2(2); | |
| 167 TestValue t3(3); | |
| 168 { | |
| 169 TestPtr ptr2; | |
| 170 TestPtr ptr3; | |
| 171 | |
| 172 EXPECT_TRUE(ptr2->is_default()); | |
| 173 EXPECT_TRUE(ptr3->is_default()); | |
| 174 EXPECT_EQ(0, TestValue::copy_count()); | |
| 175 EXPECT_EQ(0, TestValue::delete_count()); | |
| 176 | |
| 177 ptr2.set_value(t2); | |
| 178 EXPECT_EQ(1, TestValue::copy_count()); | |
| 179 EXPECT_EQ(0, TestValue::delete_count()); | |
| 180 | |
| 181 ptr3 = ptr2; | |
| 182 // Both |ptr2| and |ptr3| now share the same value "2". | |
| 183 // No additional copies expected. | |
| 184 EXPECT_EQ(1, TestValue::copy_count()); | |
| 185 EXPECT_EQ(0, TestValue::delete_count()); | |
| 186 EXPECT_FALSE(ptr3->is_default()); | |
| 187 EXPECT_EQ(2, ptr3->value()); | |
| 188 EXPECT_TRUE(WrappedValuesAreShared(ptr2, ptr3)); | |
| 189 | |
| 190 // Stop sharing - |ptr2| is "3" and |ptr3| is still "2". | |
| 191 ptr2.set_value(t3); | |
| 192 EXPECT_FALSE(WrappedValuesAreShared(ptr2, ptr3)); | |
| 193 EXPECT_EQ(3, ptr2->value()); | |
| 194 EXPECT_EQ(2, ptr3->value()); | |
| 195 // No extra copies or deletions expected. | |
| 196 EXPECT_EQ(2, TestValue::copy_count()); | |
| 197 EXPECT_EQ(0, TestValue::delete_count()); | |
| 198 | |
| 199 // |ptr3| still has the old value. | |
| 200 EXPECT_EQ(2, ptr3->value()); | |
| 201 | |
| 202 // Share again. Both values are "3". | |
| 203 ptr3 = ptr2; | |
| 204 EXPECT_EQ(3, ptr3->value()); | |
| 205 // This should have resulted in deleting the wrapper for the value "2". | |
| 206 EXPECT_EQ(1, TestValue::delete_count()); | |
| 207 // No extra copies expected. | |
| 208 EXPECT_EQ(2, TestValue::copy_count()); | |
| 209 | |
| 210 // Set default value to one of the pointers. | |
| 211 ptr2.set_value(empty); | |
| 212 EXPECT_TRUE(ptr2->is_default()); | |
| 213 // The other one is still intact. | |
| 214 EXPECT_FALSE(ptr3->is_default()); | |
| 215 EXPECT_EQ(3, ptr3->value()); | |
| 216 // No extra copies or deletions expected. | |
| 217 EXPECT_EQ(1, TestValue::delete_count()); | |
| 218 EXPECT_EQ(2, TestValue::copy_count()); | |
| 219 | |
| 220 // Copy the default value between the pointers. | |
| 221 ptr3 = ptr2; | |
| 222 EXPECT_TRUE(ptr3->is_default()); | |
| 223 // The wrapper for "3" is now deleted. | |
| 224 EXPECT_EQ(2, TestValue::delete_count()); | |
| 225 } | |
| 226 | |
| 227 // No extra deletions expected upon leaving the scope. | |
| 228 EXPECT_EQ(2, TestValue::delete_count()); | |
| 229 } | |
| 230 | |
| 231 TEST_F(ProtoValuePtrTest, ParsingTest) { | |
| 232 int v1 = 21; | |
| 233 | |
| 234 { | |
| 235 TestPtr ptr1; | |
| 236 | |
| 237 ptr1.load(&v1, sizeof(int)); | |
| 238 | |
| 239 EXPECT_EQ(1, TestValue::parse_count()); | |
| 240 EXPECT_EQ(0, TestValue::copy_count()); | |
| 241 | |
| 242 EXPECT_EQ(v1, ptr1->value()); | |
| 243 } | |
| 244 | |
| 245 EXPECT_EQ(1, TestValue::delete_count()); | |
| 246 } | |
| 247 | |
| 248 } // namespace syncer | |
| OLD | NEW |