Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(384)

Side by Side Diff: sync/internal_api/public/base/unique_position_unittest.cc

Issue 11569045: Initial UniquePositions implementation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "sync/internal_api/public/base/unique_position.h"
6
7 #include <algorithm>
8 #include <string>
9
10 #include "base/basictypes.h"
11 #include "base/logging.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace syncer {
15
16 namespace {
17
18 class UniquePositionTest : public ::testing::Test {
19 protected:
20 // Accessor to fetch the length of the position's internal representation. We
21 // don't have any test expectations on it because this is an implementation
22 // detail.
23 //
24 // We use it to see just how big our ordinals are getting in some of the
25 // worst-case scenarios that occur in our tests. This can be useful when
26 // testing and comparing alternative implementations. Enable with --v=1.
27 size_t GetLength(UniquePosition &pos) {
28 return pos.ToInternalValue().length();
29 }
30 };
31
32 const size_t kMinLength = UniquePosition::kSuffixLength;
33 const size_t kGenericPredecessorLength = kMinLength + 2;
34 const size_t kGenericSuccessorLength = kMinLength + 1;
35 const size_t kBigPositionLength = kMinLength;
36 const size_t kSmallPositionLength = kMinLength;
37
38 // Be careful when adding more prefixes to this list.
39 // We have to manually ensure each has a unique suffix.
40 const UniquePosition kGenericPredecessor = UniquePosition::FromBytes(
41 (std::string(kGenericPredecessorLength, '\x23') + '\xFF'));
42 const UniquePosition kGenericSuccessor = UniquePosition::FromBytes(
43 std::string(kGenericSuccessorLength, '\xAB') + '\xFF');
44 const UniquePosition kBigPosition = UniquePosition::FromBytes(
45 std::string(kBigPositionLength - 1, '\xFF') + '\xFE' + '\xFF');
46 const UniquePosition kBigPositionLessTwo = UniquePosition::FromBytes(
47 std::string(kBigPositionLength - 1, '\xFF') + '\xFC' + '\xFF');
48 const UniquePosition kBiggerPosition = UniquePosition::FromBytes(
49 std::string(kBigPositionLength, '\xFF') + '\xFF');
50 const UniquePosition kSmallPosition = UniquePosition::FromBytes(
51 std::string(kSmallPositionLength - 1, '\x00') + '\x01' + '\xFF');
52 const UniquePosition kSmallPositionPlusOne = UniquePosition::FromBytes(
53 std::string(kSmallPositionLength - 1, '\x00') + '\x02' + '\xFF');
54
55 const std::string kMinSuffix =
56 std::string(UniquePosition::kSuffixLength - 1, '\x00') + '\x01';
57 const std::string kMaxSuffix(UniquePosition::kSuffixLength, '\xFF');
58 const std::string kNormalSuffix(UniquePosition::kSuffixLength, '\xAB');
59
60 ::testing::AssertionResult LessThan(const char* m_expr,
61 const char* n_expr,
62 const UniquePosition &m,
63 const UniquePosition &n) {
64 if (m.LessThan(n))
65 return ::testing::AssertionSuccess();
66
67 return ::testing::AssertionFailure()
68 << m_expr << " is not less than " << n_expr
69 << " (" << m.ToDebugString() << " and " << n.ToDebugString() << ")";
70 }
71
72 class RelativePositioningTest : public UniquePositionTest { };
73
74 const UniquePosition kPositionArray[] = {
75 kGenericPredecessor,
76 kGenericSuccessor,
77 kBigPosition,
78 kBigPositionLessTwo,
79 kBiggerPosition,
80 kSmallPosition,
81 kSmallPositionPlusOne,
82 };
83
84 const UniquePosition kSortedPositionArray[] = {
85 kSmallPosition,
86 kSmallPositionPlusOne,
87 kGenericPredecessor,
88 kGenericSuccessor,
89 kBigPositionLessTwo,
90 kBigPosition,
91 kBiggerPosition,
92 };
93
94 static const size_t kNumPositions = arraysize(kPositionArray);
95 static const size_t kNumSortedPositions = arraysize(kSortedPositionArray);
96
97 struct PositionLessThan {
98 bool operator()(const UniquePosition& a, const UniquePosition& b) {
99 return a.LessThan(b);
100 }
101 };
102
103 static bool IsSuffixInUse(
104 const UniquePosition& pos, const std::string& suffix) {
105 const std::string& pos_bytes = pos.ToInternalValue();
106 const size_t prefix_len = pos_bytes.length() - UniquePosition::kSuffixLength;
107 return pos_bytes.substr(prefix_len, std::string::npos) == suffix;
108 }
109
110 // Exercise comparision functions by sorting and re-sorting the list.
111 TEST_F(RelativePositioningTest, SortPositions) {
112 ASSERT_EQ(kNumPositions, kNumSortedPositions);
113 UniquePosition positions[arraysize(kPositionArray)];
114 for (size_t i = 0; i < kNumPositions; ++i) {
115 positions[i] = kPositionArray[i];
116 }
117
118 std::sort(&positions[0], &positions[kNumPositions], PositionLessThan());
119 for (size_t i = 0; i < kNumPositions; ++i) {
120 EXPECT_TRUE(positions[i].Equals(kSortedPositionArray[i]))
121 << "i: " << i << ", "
122 << positions[i].ToDebugString() << " != "
123 << kSortedPositionArray[i].ToDebugString();
124 }
125
126 }
127
128 // Some more exercise for the comparison function.
129 TEST_F(RelativePositioningTest, ReverseSortPositions) {
130 ASSERT_EQ(kNumPositions, kNumSortedPositions);
131 UniquePosition positions[arraysize(kPositionArray)];
132 for (size_t i = 0; i < kNumPositions; ++i) {
133 positions[i] = kPositionArray[i];
134 }
135
136 std::reverse(&positions[0], &positions[kNumPositions]);
137 std::sort(&positions[0], &positions[kNumPositions], PositionLessThan());
138 for (size_t i = 0; i < kNumPositions; ++i) {
139 EXPECT_TRUE(positions[i].Equals(kSortedPositionArray[i]))
140 << "i: " << i << ", "
141 << positions[i].ToDebugString() << " != "
142 << kSortedPositionArray[i].ToDebugString();
143 }
144 }
145
146 class PositionInsertTest :
147 public RelativePositioningTest,
148 public ::testing::WithParamInterface<std::string> { };
149
150 // Exercise InsertBetween with various insertion operations.
151 TEST_P(PositionInsertTest, InsertBetween) {
152 const std::string suffix = GetParam();
153 ASSERT_TRUE(UniquePosition::IsValidSuffix(suffix));
154
155 for (size_t i = 0; i < kNumSortedPositions; ++i) {
156 const UniquePosition& predecessor = kSortedPositionArray[i];
157 // Verify our suffixes are unique before we continue.
158 if (IsSuffixInUse(predecessor, suffix))
159 continue;
160
161 for (size_t j = i + 1; j < kNumSortedPositions; ++j) {
162 const UniquePosition& successor = kSortedPositionArray[j];
163
164 // Another guard against non-unique suffixes.
165 if (IsSuffixInUse(successor, suffix))
166 continue;
167
168 UniquePosition midpoint =
169 UniquePosition::Between(predecessor, successor, suffix);
170
171 EXPECT_PRED_FORMAT2(LessThan, predecessor, midpoint);
172 EXPECT_PRED_FORMAT2(LessThan, midpoint, successor);
173 }
174 }
175 }
176
177 TEST_P(PositionInsertTest, InsertBefore) {
178 const std::string suffix = GetParam();
179 for (size_t i = 0; i < kNumSortedPositions; ++i) {
180 const UniquePosition& successor = kSortedPositionArray[i];
181 // Verify our suffixes are unique before we continue.
182 if (IsSuffixInUse(successor, suffix))
183 continue;
184
185 UniquePosition before = UniquePosition::Before(successor, suffix);
186
187 EXPECT_PRED_FORMAT2(LessThan, before, successor);
188 }
189 }
190
191 TEST_P(PositionInsertTest, InsertAfter) {
192 const std::string suffix = GetParam();
193 for (size_t i = 0; i < kNumSortedPositions; ++i) {
194 const UniquePosition& predecessor = kSortedPositionArray[i];
195 // Verify our suffixes are unique before we continue.
196 if (IsSuffixInUse(predecessor, suffix))
197 continue;
198
199 UniquePosition after = UniquePosition::After(predecessor, suffix);
200
201 EXPECT_PRED_FORMAT2(LessThan, predecessor, after);
202 }
203 }
204
205 TEST_P(PositionInsertTest, StressInsertAfter) {
206 // Use two different suffixes to not violate our suffix uniqueness guarantee.
207 const std::string& suffix_a = GetParam();
208 std::string suffix_b = suffix_a;
209 suffix_b[10] = suffix_b[10] ^ 0xff;
210
211 UniquePosition pos = UniquePosition::InitialPosition(suffix_a);
212 for (int i = 0; i < 1024; i++) {
213 const std::string& suffix = (i % 2 == 0) ? suffix_b : suffix_a;
214 UniquePosition next_pos = UniquePosition::After(pos, suffix);
215 ASSERT_PRED_FORMAT2(LessThan, pos, next_pos);
216 pos = next_pos;
217 }
218
219 VLOG(1) << "Length: " << GetLength(pos);
220 }
221
222 TEST_P(PositionInsertTest, StressInsertBefore) {
223 // Use two different suffixes to not violate our suffix uniqueness guarantee.
224 const std::string& suffix_a = GetParam();
225 std::string suffix_b = suffix_a;
226 suffix_b[10] = suffix_b[10] ^ 0xff;
227
228 UniquePosition pos = UniquePosition::InitialPosition(suffix_a);
229 for (int i = 0; i < 1024; i++) {
230 const std::string& suffix = (i % 2 == 0) ? suffix_b : suffix_a;
231 UniquePosition prev_pos = UniquePosition::Before(pos, suffix);
232 ASSERT_PRED_FORMAT2(LessThan, prev_pos, pos);
233 pos = prev_pos;
234 }
235
236 VLOG(1) << "Length: " << GetLength(pos);
237 }
238
239 TEST_P(PositionInsertTest, StressLeftInsertBetween) {
240 // Use different suffixes to not violate our suffix uniqueness guarantee.
241 const std::string& suffix_a = GetParam();
242 std::string suffix_b = suffix_a;
243 suffix_b[10] = suffix_b[10] ^ 0xff;
244 std::string suffix_c = suffix_a;
245 suffix_c[10] = suffix_c[10] ^ 0xf0;
246
247 UniquePosition right_pos = UniquePosition::InitialPosition(suffix_c);
248 UniquePosition left_pos = UniquePosition::Before(right_pos, suffix_a);
249 for (int i = 0; i < 1024; i++) {
250 const std::string& suffix = (i % 2 == 0) ? suffix_b : suffix_a;
251 UniquePosition new_pos =
252 UniquePosition::Between(left_pos, right_pos, suffix);
253 ASSERT_PRED_FORMAT2(LessThan, left_pos, new_pos);
254 ASSERT_PRED_FORMAT2(LessThan, new_pos, right_pos);
255 left_pos = new_pos;
256 }
257
258 VLOG(1) << "Lengths: " << GetLength(left_pos) << ", " << GetLength(right_pos);
259 }
260
261 TEST_P(PositionInsertTest, StressRightInsertBetween) {
262 // Use different suffixes to not violate our suffix uniqueness guarantee.
263 const std::string& suffix_a = GetParam();
264 std::string suffix_b = suffix_a;
265 suffix_b[10] = suffix_b[10] ^ 0xff;
266 std::string suffix_c = suffix_a;
267 suffix_c[10] = suffix_c[10] ^ 0xf0;
268
269 UniquePosition right_pos = UniquePosition::InitialPosition(suffix_a);
270 UniquePosition left_pos = UniquePosition::Before(right_pos, suffix_c);
271 for (int i = 0; i < 1024; i++) {
272 const std::string& suffix = (i % 2 == 0) ? suffix_b : suffix_a;
273 UniquePosition new_pos =
274 UniquePosition::Between(left_pos, right_pos, suffix);
275 ASSERT_PRED_FORMAT2(LessThan, left_pos, new_pos);
276 ASSERT_PRED_FORMAT2(LessThan, new_pos, right_pos);
277 right_pos = new_pos;
278 }
279
280 VLOG(1) << "Lengths: " << GetLength(left_pos) << ", " << GetLength(right_pos);
281 }
282
283 INSTANTIATE_TEST_CASE_P(MinSuffix, PositionInsertTest,
284 ::testing::Values(kMinSuffix));
285 INSTANTIATE_TEST_CASE_P(MaxSuffix, PositionInsertTest,
286 ::testing::Values(kMaxSuffix));
287 INSTANTIATE_TEST_CASE_P(NormalSuffix, PositionInsertTest,
288 ::testing::Values(kNormalSuffix));
289
290 class PositionFromIntTest : public UniquePositionTest {
291 protected:
292 static std::string SuffixFromInt(int64 item_id) {
293 // Represents a cache_guid-like value.
294 const std::string guid(
295 "\xFF\xFE\xFE\xFF\x00\x01\x01\x00"
296 "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 16);
297
298 return UniquePosition::GenerateBookmarkSuffix(guid, item_id);
299 }
300 };
301
302 const int64 kTestValues[] = {
303 0LL,
304 1LL, -1LL,
305 2LL, -2LL,
306 3LL, -3LL,
307 0x79LL, -0x79LL,
308 0x80LL, -0x80LL,
309 0x81LL, -0x81LL,
310 0xFELL, -0xFELL,
311 0xFFLL, -0xFFLL,
312 0x100LL, -0x100LL,
313 0x101LL, -0x101LL,
314 0xFA1AFELL, -0xFA1AFELL,
315 0xFFFFFFFELL, -0xFFFFFFFELL,
316 0xFFFFFFFFLL, -0xFFFFFFFFLL,
317 0x100000000LL, -0x100000000LL,
318 0x100000001LL, -0x100000001LL,
319 0xFFFFFFFFFFLL, -0xFFFFFFFFFFLL,
320 0x112358132134LL, -0x112358132134LL,
321 0xFEFFBEEFABC1234LL, -0xFEFFBEEFABC1234LL,
322 kint64max,
323 kint64min,
324 kint64min + 1,
325 kint64max - 1
326 };
327
328 const size_t kNumTestValues = arraysize(kTestValues);
329
330 TEST_F(PositionFromIntTest, IsValid) {
331 for (size_t i = 0; i < kNumTestValues; ++i) {
332 const UniquePosition pos =
333 UniquePosition::FromInt64(kTestValues[i], SuffixFromInt(i));
334 EXPECT_TRUE(pos.IsValid()) << "i = " << i << "; " << pos.ToDebugString();
335 }
336 }
337
338 TEST_F(PositionFromIntTest, RoundTripConversion) {
339 for (size_t i = 0; i < kNumTestValues; ++i) {
340 const int64 expected_value = kTestValues[i];
341 const UniquePosition pos =
342 UniquePosition::FromInt64(kTestValues[i], SuffixFromInt(i));
343 const int64 value = pos.ToInt64();
344 EXPECT_EQ(expected_value, value) << "i = " << i;
345 }
346 }
347
348 template <typename T, typename LessThan = std::less<T> >
349 class IndexedLessThan {
350 public:
351 IndexedLessThan(const T* values) : values_(values) {}
352
353 bool operator()(int i1, int i2) {
354 return less_than_(values_[i1], values_[i2]);
355 }
356
357 private:
358 const T* values_;
359 LessThan less_than_;
360 };
361
362 TEST_F(PositionFromIntTest, ConsistentOrdering) {
363 UniquePosition positions[kNumTestValues];
364 std::vector<int> original_ordering(kNumTestValues);
365 std::vector<int> int64_ordering(kNumTestValues);
366 std::vector<int> position_ordering(kNumTestValues);
367 for (size_t i = 0; i < kNumTestValues; ++i) {
368 positions[i] = UniquePosition::FromInt64(
369 kTestValues[i], SuffixFromInt(i));
370 original_ordering[i] = int64_ordering[i] = position_ordering[i] = i;
371 }
372
373 std::sort(int64_ordering.begin(), int64_ordering.end(),
374 IndexedLessThan<int64>(kTestValues));
375 std::sort(position_ordering.begin(), position_ordering.end(),
376 IndexedLessThan<UniquePosition, PositionLessThan>(positions));
377 EXPECT_NE(original_ordering, int64_ordering);
378 EXPECT_EQ(int64_ordering, position_ordering);
379 }
380
381 } // namespace
382
383 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698