OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sync/internal_api/public/base/unique_position.h" | 5 #include "components/sync/base/unique_position.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <functional> | 11 #include <functional> |
12 #include <memory> | 12 #include <memory> |
13 #include <string> | 13 #include <string> |
14 #include <vector> | 14 #include <vector> |
15 | 15 |
16 #include "base/base64.h" | 16 #include "base/base64.h" |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/macros.h" | 18 #include "base/macros.h" |
19 #include "base/sha1.h" | 19 #include "base/sha1.h" |
20 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
21 #include "sync/protocol/unique_position.pb.h" | 21 #include "components/sync/protocol/unique_position.pb.h" |
22 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
23 | 23 |
24 namespace syncer { | 24 namespace syncer { |
25 | 25 |
26 namespace { | 26 namespace { |
27 | 27 |
28 class UniquePositionTest : public ::testing::Test { | 28 class UniquePositionTest : public ::testing::Test { |
29 protected: | 29 protected: |
30 // Accessor to fetch the length of the position's internal representation | 30 // Accessor to fetch the length of the position's internal representation |
31 // We try to avoid having any test expectations on it because this is an | 31 // We try to avoid having any test expectations on it because this is an |
(...skipping 18 matching lines...) Expand all Loading... |
50 } | 50 } |
51 | 51 |
52 const size_t kMinLength = UniquePosition::kSuffixLength; | 52 const size_t kMinLength = UniquePosition::kSuffixLength; |
53 const size_t kGenericPredecessorLength = kMinLength + 2; | 53 const size_t kGenericPredecessorLength = kMinLength + 2; |
54 const size_t kGenericSuccessorLength = kMinLength + 1; | 54 const size_t kGenericSuccessorLength = kMinLength + 1; |
55 const size_t kBigPositionLength = kMinLength; | 55 const size_t kBigPositionLength = kMinLength; |
56 const size_t kSmallPositionLength = kMinLength; | 56 const size_t kSmallPositionLength = kMinLength; |
57 | 57 |
58 // Be careful when adding more prefixes to this list. | 58 // Be careful when adding more prefixes to this list. |
59 // We have to manually ensure each has a unique suffix. | 59 // We have to manually ensure each has a unique suffix. |
60 const UniquePosition kGenericPredecessor = FromBytes( | 60 const UniquePosition kGenericPredecessor = |
61 (std::string(kGenericPredecessorLength, '\x23') + '\xFF')); | 61 FromBytes((std::string(kGenericPredecessorLength, '\x23') + '\xFF')); |
62 const UniquePosition kGenericSuccessor = FromBytes( | 62 const UniquePosition kGenericSuccessor = |
63 std::string(kGenericSuccessorLength, '\xAB') + '\xFF'); | 63 FromBytes(std::string(kGenericSuccessorLength, '\xAB') + '\xFF'); |
64 const UniquePosition kBigPosition = FromBytes( | 64 const UniquePosition kBigPosition = |
65 std::string(kBigPositionLength - 1, '\xFF') + '\xFE' + '\xFF'); | 65 FromBytes(std::string(kBigPositionLength - 1, '\xFF') + '\xFE' + '\xFF'); |
66 const UniquePosition kBigPositionLessTwo = FromBytes( | 66 const UniquePosition kBigPositionLessTwo = |
67 std::string(kBigPositionLength - 1, '\xFF') + '\xFC' + '\xFF'); | 67 FromBytes(std::string(kBigPositionLength - 1, '\xFF') + '\xFC' + '\xFF'); |
68 const UniquePosition kBiggerPosition = FromBytes( | 68 const UniquePosition kBiggerPosition = |
69 std::string(kBigPositionLength, '\xFF') + '\xFF'); | 69 FromBytes(std::string(kBigPositionLength, '\xFF') + '\xFF'); |
70 const UniquePosition kSmallPosition = FromBytes( | 70 const UniquePosition kSmallPosition = |
71 std::string(kSmallPositionLength - 1, '\x00') + '\x01' + '\xFF'); | 71 FromBytes(std::string(kSmallPositionLength - 1, '\x00') + '\x01' + '\xFF'); |
72 const UniquePosition kSmallPositionPlusOne = FromBytes( | 72 const UniquePosition kSmallPositionPlusOne = |
73 std::string(kSmallPositionLength - 1, '\x00') + '\x02' + '\xFF'); | 73 FromBytes(std::string(kSmallPositionLength - 1, '\x00') + '\x02' + '\xFF'); |
74 const UniquePosition kHugePosition = FromBytes( | 74 const UniquePosition kHugePosition = FromBytes( |
75 std::string(UniquePosition::kCompressBytesThreshold, '\xFF') + '\xAB'); | 75 std::string(UniquePosition::kCompressBytesThreshold, '\xFF') + '\xAB'); |
76 | 76 |
77 const std::string kMinSuffix = | 77 const std::string kMinSuffix = |
78 std::string(UniquePosition::kSuffixLength - 1, '\x00') + '\x01'; | 78 std::string(UniquePosition::kSuffixLength - 1, '\x00') + '\x01'; |
79 const std::string kMaxSuffix(UniquePosition::kSuffixLength, '\xFF'); | 79 const std::string kMaxSuffix(UniquePosition::kSuffixLength, '\xFF'); |
80 const std::string kNormalSuffix( | 80 const std::string kNormalSuffix( |
81 "\x68\x44\x6C\x6B\x32\x58\x78\x34\x69\x70\x46\x34\x79\x49" | 81 "\x68\x44\x6C\x6B\x32\x58\x78\x34\x69\x70\x46\x34\x79\x49" |
82 "\x44\x4F\x66\x4C\x58\x41\x31\x34\x68\x59\x56\x43\x6F\x3D"); | 82 "\x44\x4F\x66\x4C\x58\x41\x31\x34\x68\x59\x56\x43\x6F\x3D"); |
83 | 83 |
84 ::testing::AssertionResult LessThan(const char* m_expr, | 84 ::testing::AssertionResult LessThan(const char* m_expr, |
85 const char* n_expr, | 85 const char* n_expr, |
86 const UniquePosition &m, | 86 const UniquePosition& m, |
87 const UniquePosition &n) { | 87 const UniquePosition& n) { |
88 if (m.LessThan(n)) | 88 if (m.LessThan(n)) |
89 return ::testing::AssertionSuccess(); | 89 return ::testing::AssertionSuccess(); |
90 | 90 |
91 return ::testing::AssertionFailure() | 91 return ::testing::AssertionFailure() << m_expr << " is not less than " |
92 << m_expr << " is not less than " << n_expr | 92 << n_expr << " (" << m.ToDebugString() |
93 << " (" << m.ToDebugString() << " and " << n.ToDebugString() << ")"; | 93 << " and " << n.ToDebugString() << ")"; |
94 } | 94 } |
95 | 95 |
96 ::testing::AssertionResult Equals(const char* m_expr, | 96 ::testing::AssertionResult Equals(const char* m_expr, |
97 const char* n_expr, | 97 const char* n_expr, |
98 const UniquePosition &m, | 98 const UniquePosition& m, |
99 const UniquePosition &n) { | 99 const UniquePosition& n) { |
100 if (m.Equals(n)) | 100 if (m.Equals(n)) |
101 return ::testing::AssertionSuccess(); | 101 return ::testing::AssertionSuccess(); |
102 | 102 |
103 return ::testing::AssertionFailure() | 103 return ::testing::AssertionFailure() << m_expr << " is not equal to " |
104 << m_expr << " is not equal to " << n_expr | 104 << n_expr << " (" << m.ToDebugString() |
105 << " (" << m.ToDebugString() << " != " << n.ToDebugString() << ")"; | 105 << " != " << n.ToDebugString() << ")"; |
106 } | 106 } |
107 | 107 |
108 // Test that the code can read the uncompressed serialization format. | 108 // Test that the code can read the uncompressed serialization format. |
109 TEST_F(UniquePositionTest, DeserializeObsoleteUncompressedPosition) { | 109 TEST_F(UniquePositionTest, DeserializeObsoleteUncompressedPosition) { |
110 // We no longer support the encoding data in this format. This hard-coded | 110 // We no longer support the encoding data in this format. This hard-coded |
111 // input is a serialization of kGenericPredecessor created by an older version | 111 // input is a serialization of kGenericPredecessor created by an older version |
112 // of this code. | 112 // of this code. |
113 const char kSerializedCstr[] = { | 113 const char kSerializedCstr[] = { |
114 '\x0a', '\x1f', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', | 114 '\x0a', '\x1f', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', |
115 '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', | 115 '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', |
116 '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', | 116 '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', '\x23', |
117 '\x23', '\x23', '\x23', '\x23', '\x23', '\xff' }; | 117 '\x23', '\x23', '\x23', '\x23', '\x23', '\xff'}; |
118 const std::string serialized(kSerializedCstr, sizeof(kSerializedCstr)); | 118 const std::string serialized(kSerializedCstr, sizeof(kSerializedCstr)); |
119 | 119 |
120 sync_pb::UniquePosition proto; | 120 sync_pb::UniquePosition proto; |
121 proto.ParseFromString(serialized); | 121 proto.ParseFromString(serialized); |
122 | 122 |
123 // Double-check that this test is testing what we think it tests. | 123 // Double-check that this test is testing what we think it tests. |
124 EXPECT_TRUE(proto.has_value()); | 124 EXPECT_TRUE(proto.has_value()); |
125 EXPECT_FALSE(proto.has_compressed_value()); | 125 EXPECT_FALSE(proto.has_compressed_value()); |
126 EXPECT_FALSE(proto.has_uncompressed_length()); | 126 EXPECT_FALSE(proto.has_uncompressed_length()); |
127 | 127 |
128 UniquePosition pos = UniquePosition::FromProto(proto); | 128 UniquePosition pos = UniquePosition::FromProto(proto); |
129 EXPECT_PRED_FORMAT2(Equals, kGenericPredecessor, pos); | 129 EXPECT_PRED_FORMAT2(Equals, kGenericPredecessor, pos); |
130 } | 130 } |
131 | 131 |
132 // Test that the code can read the gzip serialization format. | 132 // Test that the code can read the gzip serialization format. |
133 TEST_F(UniquePositionTest, DeserializeObsoleteGzippedPosition) { | 133 TEST_F(UniquePositionTest, DeserializeObsoleteGzippedPosition) { |
134 // We no longer support the encoding data in this format. This hard-coded | 134 // We no longer support the encoding data in this format. This hard-coded |
135 // input is a serialization of kHugePosition created by an older version of | 135 // input is a serialization of kHugePosition created by an older version of |
136 // this code. | 136 // this code. |
137 const char kSerializedCstr[] = { | 137 const char kSerializedCstr[] = { |
138 '\x12', '\x0d', '\x78', '\x9c', '\xfb', '\xff', '\x7f', '\x60', '\xc1', | 138 '\x12', '\x0d', '\x78', '\x9c', '\xfb', '\xff', '\x7f', '\x60', '\xc1', |
139 '\x6a', '\x00', '\xa2', '\x4c', '\x80', '\x2c', '\x18', '\x81', '\x01' }; | 139 '\x6a', '\x00', '\xa2', '\x4c', '\x80', '\x2c', '\x18', '\x81', '\x01'}; |
140 const std::string serialized(kSerializedCstr, sizeof(kSerializedCstr)); | 140 const std::string serialized(kSerializedCstr, sizeof(kSerializedCstr)); |
141 | 141 |
142 sync_pb::UniquePosition proto; | 142 sync_pb::UniquePosition proto; |
143 proto.ParseFromString(serialized); | 143 proto.ParseFromString(serialized); |
144 | 144 |
145 // Double-check that this test is testing what we think it tests. | 145 // Double-check that this test is testing what we think it tests. |
146 EXPECT_FALSE(proto.has_value()); | 146 EXPECT_FALSE(proto.has_value()); |
147 EXPECT_TRUE(proto.has_compressed_value()); | 147 EXPECT_TRUE(proto.has_compressed_value()); |
148 EXPECT_TRUE(proto.has_uncompressed_length()); | 148 EXPECT_TRUE(proto.has_uncompressed_length()); |
149 | 149 |
150 UniquePosition pos = UniquePosition::FromProto(proto); | 150 UniquePosition pos = UniquePosition::FromProto(proto); |
151 EXPECT_PRED_FORMAT2(Equals, kHugePosition, pos); | 151 EXPECT_PRED_FORMAT2(Equals, kHugePosition, pos); |
152 } | 152 } |
153 | 153 |
154 class RelativePositioningTest : public UniquePositionTest { }; | 154 class RelativePositioningTest : public UniquePositionTest {}; |
155 | 155 |
156 const UniquePosition kPositionArray[] = { | 156 const UniquePosition kPositionArray[] = { |
157 kGenericPredecessor, | 157 kGenericPredecessor, kGenericSuccessor, kBigPosition, |
158 kGenericSuccessor, | 158 kBigPositionLessTwo, kBiggerPosition, kSmallPosition, |
159 kBigPosition, | 159 kSmallPositionPlusOne, |
160 kBigPositionLessTwo, | |
161 kBiggerPosition, | |
162 kSmallPosition, | |
163 kSmallPositionPlusOne, | |
164 }; | 160 }; |
165 | 161 |
166 const UniquePosition kSortedPositionArray[] = { | 162 const UniquePosition kSortedPositionArray[] = { |
167 kSmallPosition, | 163 kSmallPosition, kSmallPositionPlusOne, kGenericPredecessor, |
168 kSmallPositionPlusOne, | 164 kGenericSuccessor, kBigPositionLessTwo, kBigPosition, |
169 kGenericPredecessor, | 165 kBiggerPosition, |
170 kGenericSuccessor, | |
171 kBigPositionLessTwo, | |
172 kBigPosition, | |
173 kBiggerPosition, | |
174 }; | 166 }; |
175 | 167 |
176 static const size_t kNumPositions = arraysize(kPositionArray); | 168 static const size_t kNumPositions = arraysize(kPositionArray); |
177 static const size_t kNumSortedPositions = arraysize(kSortedPositionArray); | 169 static const size_t kNumSortedPositions = arraysize(kSortedPositionArray); |
178 | 170 |
179 struct PositionLessThan { | 171 struct PositionLessThan { |
180 bool operator()(const UniquePosition& a, const UniquePosition& b) { | 172 bool operator()(const UniquePosition& a, const UniquePosition& b) { |
181 return a.LessThan(b); | 173 return a.LessThan(b); |
182 } | 174 } |
183 }; | 175 }; |
184 | 176 |
185 // Returns true iff the given position's suffix matches the input parameter. | 177 // Returns true iff the given position's suffix matches the input parameter. |
186 static bool IsSuffixInUse( | 178 static bool IsSuffixInUse(const UniquePosition& pos, |
187 const UniquePosition& pos, const std::string& suffix) { | 179 const std::string& suffix) { |
188 return pos.GetSuffixForTest() == suffix; | 180 return pos.GetSuffixForTest() == suffix; |
189 } | 181 } |
190 | 182 |
191 // Test some basic properties of comparison and equality. | 183 // Test some basic properties of comparison and equality. |
192 TEST_F(RelativePositioningTest, ComparisonSanityTest1) { | 184 TEST_F(RelativePositioningTest, ComparisonSanityTest1) { |
193 const UniquePosition& a = kPositionArray[0]; | 185 const UniquePosition& a = kPositionArray[0]; |
194 ASSERT_TRUE(a.IsValid()); | 186 ASSERT_TRUE(a.IsValid()); |
195 | 187 |
196 // Necessarily true for any non-invalid positions. | 188 // Necessarily true for any non-invalid positions. |
197 EXPECT_TRUE(a.Equals(a)); | 189 EXPECT_TRUE(a.Equals(a)); |
(...skipping 15 matching lines...) Expand all Loading... |
213 TEST_F(RelativePositioningTest, SortPositions) { | 205 TEST_F(RelativePositioningTest, SortPositions) { |
214 ASSERT_EQ(kNumPositions, kNumSortedPositions); | 206 ASSERT_EQ(kNumPositions, kNumSortedPositions); |
215 UniquePosition positions[arraysize(kPositionArray)]; | 207 UniquePosition positions[arraysize(kPositionArray)]; |
216 for (size_t i = 0; i < kNumPositions; ++i) { | 208 for (size_t i = 0; i < kNumPositions; ++i) { |
217 positions[i] = kPositionArray[i]; | 209 positions[i] = kPositionArray[i]; |
218 } | 210 } |
219 | 211 |
220 std::sort(&positions[0], &positions[kNumPositions], PositionLessThan()); | 212 std::sort(&positions[0], &positions[kNumPositions], PositionLessThan()); |
221 for (size_t i = 0; i < kNumPositions; ++i) { | 213 for (size_t i = 0; i < kNumPositions; ++i) { |
222 EXPECT_TRUE(positions[i].Equals(kSortedPositionArray[i])) | 214 EXPECT_TRUE(positions[i].Equals(kSortedPositionArray[i])) |
223 << "i: " << i << ", " | 215 << "i: " << i << ", " << positions[i].ToDebugString() |
224 << positions[i].ToDebugString() << " != " | 216 << " != " << kSortedPositionArray[i].ToDebugString(); |
225 << kSortedPositionArray[i].ToDebugString(); | |
226 } | 217 } |
227 } | 218 } |
228 | 219 |
229 // Some more exercise for the comparison function. | 220 // Some more exercise for the comparison function. |
230 TEST_F(RelativePositioningTest, ReverseSortPositions) { | 221 TEST_F(RelativePositioningTest, ReverseSortPositions) { |
231 ASSERT_EQ(kNumPositions, kNumSortedPositions); | 222 ASSERT_EQ(kNumPositions, kNumSortedPositions); |
232 UniquePosition positions[arraysize(kPositionArray)]; | 223 UniquePosition positions[arraysize(kPositionArray)]; |
233 for (size_t i = 0; i < kNumPositions; ++i) { | 224 for (size_t i = 0; i < kNumPositions; ++i) { |
234 positions[i] = kPositionArray[i]; | 225 positions[i] = kPositionArray[i]; |
235 } | 226 } |
236 | 227 |
237 std::reverse(&positions[0], &positions[kNumPositions]); | 228 std::reverse(&positions[0], &positions[kNumPositions]); |
238 std::sort(&positions[0], &positions[kNumPositions], PositionLessThan()); | 229 std::sort(&positions[0], &positions[kNumPositions], PositionLessThan()); |
239 for (size_t i = 0; i < kNumPositions; ++i) { | 230 for (size_t i = 0; i < kNumPositions; ++i) { |
240 EXPECT_TRUE(positions[i].Equals(kSortedPositionArray[i])) | 231 EXPECT_TRUE(positions[i].Equals(kSortedPositionArray[i])) |
241 << "i: " << i << ", " | 232 << "i: " << i << ", " << positions[i].ToDebugString() |
242 << positions[i].ToDebugString() << " != " | 233 << " != " << kSortedPositionArray[i].ToDebugString(); |
243 << kSortedPositionArray[i].ToDebugString(); | |
244 } | 234 } |
245 } | 235 } |
246 | 236 |
247 class PositionInsertTest : | 237 class PositionInsertTest : public RelativePositioningTest, |
248 public RelativePositioningTest, | 238 public ::testing::WithParamInterface<std::string> {}; |
249 public ::testing::WithParamInterface<std::string> { }; | |
250 | 239 |
251 // Exercise InsertBetween with various insertion operations. | 240 // Exercise InsertBetween with various insertion operations. |
252 TEST_P(PositionInsertTest, InsertBetween) { | 241 TEST_P(PositionInsertTest, InsertBetween) { |
253 const std::string suffix = GetParam(); | 242 const std::string suffix = GetParam(); |
254 ASSERT_TRUE(UniquePosition::IsValidSuffix(suffix)); | 243 ASSERT_TRUE(UniquePosition::IsValidSuffix(suffix)); |
255 | 244 |
256 for (size_t i = 0; i < kNumSortedPositions; ++i) { | 245 for (size_t i = 0; i < kNumSortedPositions; ++i) { |
257 const UniquePosition& predecessor = kSortedPositionArray[i]; | 246 const UniquePosition& predecessor = kSortedPositionArray[i]; |
258 // Verify our suffixes are unique before we continue. | 247 // Verify our suffixes are unique before we continue. |
259 if (IsSuffixInUse(predecessor, suffix)) | 248 if (IsSuffixInUse(predecessor, suffix)) |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 } | 368 } |
380 | 369 |
381 VLOG(1) << "Lengths: " << GetLength(left_pos) << ", " << GetLength(right_pos); | 370 VLOG(1) << "Lengths: " << GetLength(left_pos) << ", " << GetLength(right_pos); |
382 } | 371 } |
383 | 372 |
384 // Generates suffixes similar to those generated by the directory. | 373 // Generates suffixes similar to those generated by the directory. |
385 // This may become obsolete if the suffix generation code is modified. | 374 // This may become obsolete if the suffix generation code is modified. |
386 class SuffixGenerator { | 375 class SuffixGenerator { |
387 public: | 376 public: |
388 explicit SuffixGenerator(const std::string& cache_guid) | 377 explicit SuffixGenerator(const std::string& cache_guid) |
389 : cache_guid_(cache_guid), | 378 : cache_guid_(cache_guid), next_id_(-65535) {} |
390 next_id_(-65535) { | |
391 } | |
392 | 379 |
393 std::string NextSuffix() { | 380 std::string NextSuffix() { |
394 // This is not entirely realistic, but that should be OK. The current | 381 // This is not entirely realistic, but that should be OK. The current |
395 // suffix format is a base64'ed SHA1 hash, which should be fairly close to | 382 // suffix format is a base64'ed SHA1 hash, which should be fairly close to |
396 // random anyway. | 383 // random anyway. |
397 std::string input = cache_guid_ + base::Int64ToString(next_id_--); | 384 std::string input = cache_guid_ + base::Int64ToString(next_id_--); |
398 std::string output; | 385 std::string output; |
399 base::Base64Encode(base::SHA1HashString(input), &output); | 386 base::Base64Encode(base::SHA1HashString(input), &output); |
400 return output; | 387 return output; |
401 } | 388 } |
402 | 389 |
403 private: | 390 private: |
404 const std::string cache_guid_; | 391 const std::string cache_guid_; |
405 int64_t next_id_; | 392 int64_t next_id_; |
406 }; | 393 }; |
407 | 394 |
408 // Cache guids generated in the same style as real clients. | 395 // Cache guids generated in the same style as real clients. |
409 static const char kCacheGuidStr1[] = "tuiWdG8hV+8y4RT9N5Aikg=="; | 396 static const char kCacheGuidStr1[] = "tuiWdG8hV+8y4RT9N5Aikg=="; |
410 static const char kCacheGuidStr2[] = "yaKb7zHtY06aue9a0vlZgw=="; | 397 static const char kCacheGuidStr2[] = "yaKb7zHtY06aue9a0vlZgw=="; |
411 | 398 |
412 class PositionScenariosTest : public UniquePositionTest { | 399 class PositionScenariosTest : public UniquePositionTest { |
413 public: | 400 public: |
414 PositionScenariosTest() | 401 PositionScenariosTest() |
415 : generator1_(std::string(kCacheGuidStr1, arraysize(kCacheGuidStr1)-1)), | 402 : generator1_(std::string(kCacheGuidStr1, arraysize(kCacheGuidStr1) - 1)), |
416 generator2_(std::string(kCacheGuidStr2, arraysize(kCacheGuidStr2)-1)) { | 403 generator2_( |
417 } | 404 std::string(kCacheGuidStr2, arraysize(kCacheGuidStr2) - 1)) {} |
418 | 405 |
419 std::string NextClient1Suffix() { | 406 std::string NextClient1Suffix() { return generator1_.NextSuffix(); } |
420 return generator1_.NextSuffix(); | |
421 } | |
422 | 407 |
423 std::string NextClient2Suffix() { | 408 std::string NextClient2Suffix() { return generator2_.NextSuffix(); } |
424 return generator2_.NextSuffix(); | |
425 } | |
426 | 409 |
427 private: | 410 private: |
428 SuffixGenerator generator1_; | 411 SuffixGenerator generator1_; |
429 SuffixGenerator generator2_; | 412 SuffixGenerator generator2_; |
430 }; | 413 }; |
431 | 414 |
432 // One client creating new bookmarks, always inserting at the end. | 415 // One client creating new bookmarks, always inserting at the end. |
433 TEST_F(PositionScenariosTest, OneClientInsertAtEnd) { | 416 TEST_F(PositionScenariosTest, OneClientInsertAtEnd) { |
434 UniquePosition pos = | 417 UniquePosition pos = UniquePosition::InitialPosition(NextClient1Suffix()); |
435 UniquePosition::InitialPosition(NextClient1Suffix()); | |
436 for (int i = 0; i < 1024; i++) { | 418 for (int i = 0; i < 1024; i++) { |
437 const std::string suffix = NextClient1Suffix(); | 419 const std::string suffix = NextClient1Suffix(); |
438 UniquePosition new_pos = UniquePosition::After(pos, suffix); | 420 UniquePosition new_pos = UniquePosition::After(pos, suffix); |
439 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos); | 421 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos); |
440 pos = new_pos; | 422 pos = new_pos; |
441 } | 423 } |
442 | 424 |
443 VLOG(1) << "Length: " << GetLength(pos); | 425 VLOG(1) << "Length: " << GetLength(pos); |
444 | 426 |
445 // Normally we wouldn't want to make an assertion about the internal | 427 // Normally we wouldn't want to make an assertion about the internal |
446 // representation of our data, but we make an exception for this case. | 428 // representation of our data, but we make an exception for this case. |
447 // If this scenario causes lengths to explode, we have a big problem. | 429 // If this scenario causes lengths to explode, we have a big problem. |
448 EXPECT_LT(GetLength(pos), 500U); | 430 EXPECT_LT(GetLength(pos), 500U); |
449 } | 431 } |
450 | 432 |
451 // Two clients alternately inserting entries at the end, with a strong | 433 // Two clients alternately inserting entries at the end, with a strong |
452 // bias towards insertions by the first client. | 434 // bias towards insertions by the first client. |
453 TEST_F(PositionScenariosTest, TwoClientsInsertAtEnd_A) { | 435 TEST_F(PositionScenariosTest, TwoClientsInsertAtEnd_A) { |
454 UniquePosition pos = | 436 UniquePosition pos = UniquePosition::InitialPosition(NextClient1Suffix()); |
455 UniquePosition::InitialPosition(NextClient1Suffix()); | |
456 for (int i = 0; i < 1024; i++) { | 437 for (int i = 0; i < 1024; i++) { |
457 std::string suffix; | 438 std::string suffix; |
458 if (i % 5 == 0) { | 439 if (i % 5 == 0) { |
459 suffix = NextClient2Suffix(); | 440 suffix = NextClient2Suffix(); |
460 } else { | 441 } else { |
461 suffix = NextClient1Suffix(); | 442 suffix = NextClient1Suffix(); |
462 } | 443 } |
463 | 444 |
464 UniquePosition new_pos = UniquePosition::After(pos, suffix); | 445 UniquePosition new_pos = UniquePosition::After(pos, suffix); |
465 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos); | 446 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos); |
466 pos = new_pos; | 447 pos = new_pos; |
467 } | 448 } |
468 | 449 |
469 VLOG(1) << "Length: " << GetLength(pos); | 450 VLOG(1) << "Length: " << GetLength(pos); |
470 EXPECT_LT(GetLength(pos), 500U); | 451 EXPECT_LT(GetLength(pos), 500U); |
471 } | 452 } |
472 | 453 |
473 // Two clients alternately inserting entries at the end. | 454 // Two clients alternately inserting entries at the end. |
474 TEST_F(PositionScenariosTest, TwoClientsInsertAtEnd_B) { | 455 TEST_F(PositionScenariosTest, TwoClientsInsertAtEnd_B) { |
475 UniquePosition pos = | 456 UniquePosition pos = UniquePosition::InitialPosition(NextClient1Suffix()); |
476 UniquePosition::InitialPosition(NextClient1Suffix()); | |
477 for (int i = 0; i < 1024; i++) { | 457 for (int i = 0; i < 1024; i++) { |
478 std::string suffix; | 458 std::string suffix; |
479 if (i % 2 == 0) { | 459 if (i % 2 == 0) { |
480 suffix = NextClient1Suffix(); | 460 suffix = NextClient1Suffix(); |
481 } else { | 461 } else { |
482 suffix = NextClient2Suffix(); | 462 suffix = NextClient2Suffix(); |
483 } | 463 } |
484 | 464 |
485 UniquePosition new_pos = UniquePosition::After(pos, suffix); | 465 UniquePosition new_pos = UniquePosition::After(pos, suffix); |
486 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos); | 466 ASSERT_PRED_FORMAT2(LessThan, pos, new_pos); |
487 pos = new_pos; | 467 pos = new_pos; |
488 } | 468 } |
489 | 469 |
490 VLOG(1) << "Length: " << GetLength(pos); | 470 VLOG(1) << "Length: " << GetLength(pos); |
491 EXPECT_LT(GetLength(pos), 500U); | 471 EXPECT_LT(GetLength(pos), 500U); |
492 } | 472 } |
493 | 473 |
494 INSTANTIATE_TEST_CASE_P(MinSuffix, PositionInsertTest, | 474 INSTANTIATE_TEST_CASE_P(MinSuffix, |
| 475 PositionInsertTest, |
495 ::testing::Values(kMinSuffix)); | 476 ::testing::Values(kMinSuffix)); |
496 INSTANTIATE_TEST_CASE_P(MaxSuffix, PositionInsertTest, | 477 INSTANTIATE_TEST_CASE_P(MaxSuffix, |
| 478 PositionInsertTest, |
497 ::testing::Values(kMaxSuffix)); | 479 ::testing::Values(kMaxSuffix)); |
498 INSTANTIATE_TEST_CASE_P(NormalSuffix, PositionInsertTest, | 480 INSTANTIATE_TEST_CASE_P(NormalSuffix, |
| 481 PositionInsertTest, |
499 ::testing::Values(kNormalSuffix)); | 482 ::testing::Values(kNormalSuffix)); |
500 | 483 |
501 class PositionFromIntTest : public UniquePositionTest { | 484 class PositionFromIntTest : public UniquePositionTest { |
502 public: | 485 public: |
503 PositionFromIntTest() | 486 PositionFromIntTest() |
504 : generator_(std::string(kCacheGuidStr1, arraysize(kCacheGuidStr1)-1)) { | 487 : generator_(std::string(kCacheGuidStr1, arraysize(kCacheGuidStr1) - 1)) { |
505 } | 488 } |
506 | 489 |
507 protected: | 490 protected: |
508 static const int64_t kTestValues[]; | 491 static const int64_t kTestValues[]; |
509 static const size_t kNumTestValues; | 492 static const size_t kNumTestValues; |
510 | 493 |
511 std::string NextSuffix() { | 494 std::string NextSuffix() { return generator_.NextSuffix(); } |
512 return generator_.NextSuffix(); | |
513 } | |
514 | 495 |
515 private: | 496 private: |
516 SuffixGenerator generator_; | 497 SuffixGenerator generator_; |
517 }; | 498 }; |
518 | 499 |
519 const int64_t PositionFromIntTest::kTestValues[] = {0LL, | 500 const int64_t PositionFromIntTest::kTestValues[] = {0LL, |
520 1LL, | 501 1LL, |
521 -1LL, | 502 -1LL, |
522 2LL, | 503 2LL, |
523 -2LL, | 504 -2LL, |
(...skipping 28 matching lines...) Expand all Loading... |
552 0x112358132134LL, | 533 0x112358132134LL, |
553 -0x112358132134LL, | 534 -0x112358132134LL, |
554 0xFEFFBEEFABC1234LL, | 535 0xFEFFBEEFABC1234LL, |
555 -0xFEFFBEEFABC1234LL, | 536 -0xFEFFBEEFABC1234LL, |
556 INT64_MAX, | 537 INT64_MAX, |
557 INT64_MIN, | 538 INT64_MIN, |
558 INT64_MIN + 1, | 539 INT64_MIN + 1, |
559 INT64_MAX - 1}; | 540 INT64_MAX - 1}; |
560 | 541 |
561 const size_t PositionFromIntTest::kNumTestValues = | 542 const size_t PositionFromIntTest::kNumTestValues = |
562 arraysize(PositionFromIntTest::kTestValues); | 543 arraysize(PositionFromIntTest::kTestValues); |
563 | 544 |
564 TEST_F(PositionFromIntTest, IsValid) { | 545 TEST_F(PositionFromIntTest, IsValid) { |
565 for (size_t i = 0; i < kNumTestValues; ++i) { | 546 for (size_t i = 0; i < kNumTestValues; ++i) { |
566 const UniquePosition pos = | 547 const UniquePosition pos = |
567 UniquePosition::FromInt64(kTestValues[i], NextSuffix()); | 548 UniquePosition::FromInt64(kTestValues[i], NextSuffix()); |
568 EXPECT_TRUE(pos.IsValid()) << "i = " << i << "; " << pos.ToDebugString(); | 549 EXPECT_TRUE(pos.IsValid()) << "i = " << i << "; " << pos.ToDebugString(); |
569 } | 550 } |
570 } | 551 } |
571 | 552 |
572 TEST_F(PositionFromIntTest, RoundTripConversion) { | 553 TEST_F(PositionFromIntTest, RoundTripConversion) { |
573 for (size_t i = 0; i < kNumTestValues; ++i) { | 554 for (size_t i = 0; i < kNumTestValues; ++i) { |
574 const int64_t expected_value = kTestValues[i]; | 555 const int64_t expected_value = kTestValues[i]; |
575 const UniquePosition pos = | 556 const UniquePosition pos = |
576 UniquePosition::FromInt64(kTestValues[i], NextSuffix()); | 557 UniquePosition::FromInt64(kTestValues[i], NextSuffix()); |
577 const int64_t value = pos.ToInt64(); | 558 const int64_t value = pos.ToInt64(); |
578 EXPECT_EQ(expected_value, value) << "i = " << i; | 559 EXPECT_EQ(expected_value, value) << "i = " << i; |
579 } | 560 } |
580 } | 561 } |
581 | 562 |
582 template <typename T, typename LessThan = std::less<T> > | 563 template <typename T, typename LessThan = std::less<T>> |
583 class IndexedLessThan { | 564 class IndexedLessThan { |
584 public: | 565 public: |
585 explicit IndexedLessThan(const T* values) : values_(values) {} | 566 explicit IndexedLessThan(const T* values) : values_(values) {} |
586 | 567 |
587 bool operator()(int i1, int i2) { | 568 bool operator()(int i1, int i2) { |
588 return less_than_(values_[i1], values_[i2]); | 569 return less_than_(values_[i1], values_[i2]); |
589 } | 570 } |
590 | 571 |
591 private: | 572 private: |
592 const T* values_; | 573 const T* values_; |
593 LessThan less_than_; | 574 LessThan less_than_; |
594 }; | 575 }; |
595 | 576 |
596 TEST_F(PositionFromIntTest, ConsistentOrdering) { | 577 TEST_F(PositionFromIntTest, ConsistentOrdering) { |
597 UniquePosition positions[kNumTestValues]; | 578 UniquePosition positions[kNumTestValues]; |
598 std::vector<int> original_ordering(kNumTestValues); | 579 std::vector<int> original_ordering(kNumTestValues); |
599 std::vector<int> int64_ordering(kNumTestValues); | 580 std::vector<int> int64_ordering(kNumTestValues); |
600 std::vector<int> position_ordering(kNumTestValues); | 581 std::vector<int> position_ordering(kNumTestValues); |
601 for (size_t i = 0; i < kNumTestValues; ++i) { | 582 for (size_t i = 0; i < kNumTestValues; ++i) { |
602 positions[i] = UniquePosition::FromInt64( | 583 positions[i] = UniquePosition::FromInt64(kTestValues[i], NextSuffix()); |
603 kTestValues[i], NextSuffix()); | |
604 original_ordering[i] = int64_ordering[i] = position_ordering[i] = i; | 584 original_ordering[i] = int64_ordering[i] = position_ordering[i] = i; |
605 } | 585 } |
606 | 586 |
607 std::sort(int64_ordering.begin(), int64_ordering.end(), | 587 std::sort(int64_ordering.begin(), int64_ordering.end(), |
608 IndexedLessThan<int64_t>(kTestValues)); | 588 IndexedLessThan<int64_t>(kTestValues)); |
609 std::sort(position_ordering.begin(), position_ordering.end(), | 589 std::sort(position_ordering.begin(), position_ordering.end(), |
610 IndexedLessThan<UniquePosition, PositionLessThan>(positions)); | 590 IndexedLessThan<UniquePosition, PositionLessThan>(positions)); |
611 EXPECT_NE(original_ordering, int64_ordering); | 591 EXPECT_NE(original_ordering, int64_ordering); |
612 EXPECT_EQ(int64_ordering, position_ordering); | 592 EXPECT_EQ(int64_ordering, position_ordering); |
613 } | 593 } |
(...skipping 26 matching lines...) Expand all Loading... |
640 private: | 620 private: |
641 UniquePosition MakePosition(const std::string& compressed_prefix, | 621 UniquePosition MakePosition(const std::string& compressed_prefix, |
642 const std::string& compressed_suffix); | 622 const std::string& compressed_suffix); |
643 std::string MakeSuffix(char unique_value); | 623 std::string MakeSuffix(char unique_value); |
644 | 624 |
645 protected: | 625 protected: |
646 std::vector<UniquePosition> positions_; | 626 std::vector<UniquePosition> positions_; |
647 }; | 627 }; |
648 | 628 |
649 UniquePosition CompressedPositionTest::MakePosition( | 629 UniquePosition CompressedPositionTest::MakePosition( |
650 const std::string& compressed_prefix, | 630 const std::string& compressed_prefix, |
651 const std::string& compressed_suffix) { | 631 const std::string& compressed_suffix) { |
652 sync_pb::UniquePosition proto; | 632 sync_pb::UniquePosition proto; |
653 proto.set_custom_compressed_v1( | 633 proto.set_custom_compressed_v1( |
654 std::string(compressed_prefix + compressed_suffix)); | 634 std::string(compressed_prefix + compressed_suffix)); |
655 return UniquePosition::FromProto(proto); | 635 return UniquePosition::FromProto(proto); |
656 } | 636 } |
657 | 637 |
658 std::string CompressedPositionTest::MakeSuffix(char unique_value) { | 638 std::string CompressedPositionTest::MakeSuffix(char unique_value) { |
659 // We're dealing in compressed positions in this test. That means the | 639 // We're dealing in compressed positions in this test. That means the |
660 // suffix should be compressed, too. To avoid complication, we use suffixes | 640 // suffix should be compressed, too. To avoid complication, we use suffixes |
661 // that don't have any repeating digits, and therefore are identical in | 641 // that don't have any repeating digits, and therefore are identical in |
662 // compressed and uncompressed form. | 642 // compressed and uncompressed form. |
663 std::string suffix; | 643 std::string suffix; |
664 for (size_t i = 0; i < UniquePosition::kSuffixLength; ++i) { | 644 for (size_t i = 0; i < UniquePosition::kSuffixLength; ++i) { |
665 suffix.push_back(static_cast<char>(i)); | 645 suffix.push_back(static_cast<char>(i)); |
666 } | 646 } |
667 suffix[UniquePosition::kSuffixLength-1] = unique_value; | 647 suffix[UniquePosition::kSuffixLength - 1] = unique_value; |
668 return suffix; | 648 return suffix; |
669 } | 649 } |
670 | 650 |
671 // Make sure that serialization and deserialization routines are correct. | 651 // Make sure that serialization and deserialization routines are correct. |
672 TEST_F(CompressedPositionTest, SerializeAndDeserialize) { | 652 TEST_F(CompressedPositionTest, SerializeAndDeserialize) { |
673 for (std::vector<UniquePosition>::const_iterator it = positions_.begin(); | 653 for (std::vector<UniquePosition>::const_iterator it = positions_.begin(); |
674 it != positions_.end(); ++it) { | 654 it != positions_.end(); ++it) { |
675 SCOPED_TRACE("iteration: " + it->ToDebugString()); | 655 SCOPED_TRACE("iteration: " + it->ToDebugString()); |
676 | 656 |
677 sync_pb::UniquePosition proto; | 657 sync_pb::UniquePosition proto; |
678 it->ToProto(&proto); | 658 it->ToProto(&proto); |
679 UniquePosition deserialized = UniquePosition::FromProto(proto); | 659 UniquePosition deserialized = UniquePosition::FromProto(proto); |
680 | 660 |
681 EXPECT_PRED_FORMAT2(Equals, *it, deserialized); | 661 EXPECT_PRED_FORMAT2(Equals, *it, deserialized); |
682 } | 662 } |
683 } | 663 } |
684 | 664 |
685 // Test that deserialization failures of protobufs where we know none of its | 665 // Test that deserialization failures of protobufs where we know none of its |
686 // fields is not catastrophic. This may happen if all the fields currently | 666 // fields is not catastrophic. This may happen if all the fields currently |
687 // known to this client become deprecated in the future. | 667 // known to this client become deprecated in the future. |
688 TEST_F(CompressedPositionTest, DeserializeProtobufFromTheFuture) { | 668 TEST_F(CompressedPositionTest, DeserializeProtobufFromTheFuture) { |
689 sync_pb::UniquePosition proto; | 669 sync_pb::UniquePosition proto; |
690 UniquePosition deserialized = UniquePosition::FromProto(proto); | 670 UniquePosition deserialized = UniquePosition::FromProto(proto); |
691 EXPECT_FALSE(deserialized.IsValid()); | 671 EXPECT_FALSE(deserialized.IsValid()); |
692 } | 672 } |
693 | 673 |
694 // Make sure the comparison functions are working correctly. | 674 // Make sure the comparison functions are working correctly. |
695 // This requires values in the test harness to be hard-coded in ascending order. | 675 // This requires values in the test harness to be hard-coded in ascending order. |
696 TEST_F(CompressedPositionTest, OrderingTest) { | 676 TEST_F(CompressedPositionTest, OrderingTest) { |
697 for (size_t i = 0; i < positions_.size()-1; ++i) { | 677 for (size_t i = 0; i < positions_.size() - 1; ++i) { |
698 EXPECT_PRED_FORMAT2(LessThan, positions_[i], positions_[i+1]); | 678 EXPECT_PRED_FORMAT2(LessThan, positions_[i], positions_[i + 1]); |
699 } | 679 } |
700 } | 680 } |
701 | 681 |
702 } // namespace | 682 } // namespace |
703 | 683 |
704 } // namespace syncer | 684 } // namespace syncer |
OLD | NEW |