5
5
#include " core/qlist.h"
6
6
7
7
#include < absl/strings/str_cat.h>
8
+ #include < absl/strings/str_format.h>
8
9
#include < gmock/gmock.h>
9
10
10
11
#include " base/gtest.h"
@@ -21,6 +22,100 @@ namespace dfly {
21
22
using namespace std ;
22
23
using namespace testing ;
23
24
25
+ static int _ql_verify_compress (const QList& ql) {
26
+ int errors = 0 ;
27
+ unsigned compress_param = ql.compress_param ();
28
+ if (compress_param > 0 ) {
29
+ const quicklistNode* node = ql.Head ();
30
+ unsigned int low_raw = compress_param;
31
+ unsigned int high_raw = ql.node_count () - compress_param;
32
+
33
+ for (unsigned int at = 0 ; at < ql.node_count (); at++, node = node->next ) {
34
+ if (node && (at < low_raw || at >= high_raw)) {
35
+ if (node->encoding != QUICKLIST_NODE_ENCODING_RAW) {
36
+ LOG (ERROR) << " Incorrect compression: node " << at << " is compressed at depth "
37
+ << compress_param << " ((" << low_raw << " ," << high_raw
38
+ << " total nodes: " << ql.node_count () << " ; size: " << node->sz
39
+ << " ; recompress: " << node->recompress ;
40
+ errors++;
41
+ }
42
+ } else {
43
+ if (node->encoding != QUICKLIST_NODE_ENCODING_LZF && !node->attempted_compress ) {
44
+ LOG (ERROR) << absl::StrFormat (
45
+ " Incorrect non-compression: node %d is NOT "
46
+ " compressed at depth %d ((%u, %u); total "
47
+ " nodes: %lu; size: %zu; recompress: %d; attempted: %d)" ,
48
+ at, compress_param, low_raw, high_raw, ql.node_count (), node->sz , node->recompress ,
49
+ node->attempted_compress );
50
+ errors++;
51
+ }
52
+ }
53
+ }
54
+ }
55
+ return errors;
56
+ }
57
+
58
+ /* Verify list metadata matches physical list contents. */
59
+ static int ql_verify (const QList& ql, uint32_t nc, uint32_t count, uint32_t head_count,
60
+ uint32_t tail_count) {
61
+ int errors = 0 ;
62
+
63
+ if (nc != ql.node_count ()) {
64
+ LOG (ERROR) << " quicklist length wrong: expected " << nc << " got " << ql.node_count ();
65
+ errors++;
66
+ }
67
+
68
+ if (count != ql.Size ()) {
69
+ LOG (ERROR) << " quicklist count wrong: expected " << count << " got " << ql.Size ();
70
+ errors++;
71
+ }
72
+
73
+ auto * node = ql.Head ();
74
+ size_t node_size = 0 ;
75
+ while (node) {
76
+ node_size += node->count ;
77
+ node = node->next ;
78
+ }
79
+
80
+ if (node_size != ql.Size ()) {
81
+ LOG (ERROR) << " quicklist cached count not match actual count: expected " << ql.Size () << " got "
82
+ << node_size;
83
+ errors++;
84
+ }
85
+
86
+ node = ql.Tail ();
87
+ node_size = 0 ;
88
+ while (node) {
89
+ node_size += node->count ;
90
+ node = node->prev ;
91
+ }
92
+ if (node_size != ql.Size ()) {
93
+ LOG (ERROR) << " has different forward count than reverse count! "
94
+ " Forward count is "
95
+ << ql.Size () << " , reverse count is " << node_size;
96
+ errors++;
97
+ }
98
+
99
+ if (ql.node_count () == 0 && errors == 0 ) {
100
+ return 0 ;
101
+ }
102
+
103
+ if (ql.Head () && head_count != ql.Head ()->count && head_count != lpLength (ql.Head ()->entry )) {
104
+ LOG (ERROR) << absl::StrFormat (" head count wrong: expected %u got cached %u vs. actual %lu" ,
105
+ head_count, ql.Head ()->count , lpLength (ql.Head ()->entry ));
106
+ errors++;
107
+ }
108
+
109
+ if (ql.Tail () && tail_count != ql.Tail ()->count && tail_count != lpLength (ql.Tail ()->entry )) {
110
+ LOG (ERROR) << " tail count wrong: expected " << tail_count << " got cached " << ql.Tail ()->count
111
+ << " vs. actual " << lpLength (ql.Tail ()->entry );
112
+ errors++;
113
+ }
114
+
115
+ errors += _ql_verify_compress (ql);
116
+ return errors;
117
+ }
118
+
24
119
class QListTest : public ::testing::Test {
25
120
protected:
26
121
QListTest () : mr_(mi_heap_get_backing()) {
@@ -183,4 +278,100 @@ TEST_P(OptionsTest, Numbers) {
183
278
EXPECT_EQ (" xxxxxxxxxxxxxxxxxxxx" , it.Get ().view ());
184
279
}
185
280
186
- }; // namespace dfly
281
+ TEST_P (OptionsTest, DelRangeA) {
282
+ auto [fill, compress] = GetParam ();
283
+ ql_ = QList (fill, compress);
284
+ long long nums[5000 ];
285
+ for (int i = 0 ; i < 33 ; i++) {
286
+ nums[i] = -5157318210846258176 + i;
287
+ ql_.Push (absl::StrCat (nums[i]), QList::TAIL);
288
+ }
289
+ if (fill == 32 )
290
+ ql_verify (ql_, 2 , 33 , 32 , 1 );
291
+
292
+ /* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
293
+ ql_.Erase (0 , 3 );
294
+ ql_.Erase (-29 , 4000 ); /* make sure not loop forever */
295
+ if (fill == 32 )
296
+ ql_verify (ql_, 1 , 1 , 1 , 1 );
297
+
298
+ auto it = ql_.GetIterator (0 );
299
+ ASSERT_TRUE (it.Next ());
300
+ EXPECT_EQ (-5157318210846258173 , it.Get ().ival ());
301
+ }
302
+
303
+ TEST_P (OptionsTest, DelRangeB) {
304
+ auto [fill, _] = GetParam ();
305
+ ql_ = QList (fill, QUICKLIST_NOCOMPRESS); // ignore compress parameter
306
+
307
+ long long nums[5000 ];
308
+ for (int i = 0 ; i < 33 ; i++) {
309
+ nums[i] = i;
310
+ ql_.Push (absl::StrCat (nums[i]), QList::TAIL);
311
+ }
312
+ if (fill == 32 )
313
+ ql_verify (ql_, 2 , 33 , 32 , 1 );
314
+
315
+ /* ltrim 5 16 (keep [5,16] inclusive = 12 remaining) */
316
+ ql_.Erase (0 , 5 );
317
+ ql_.Erase (-16 , 16 );
318
+ if (fill == 32 )
319
+ ql_verify (ql_, 1 , 12 , 12 , 12 );
320
+
321
+ auto it = ql_.GetIterator (0 );
322
+ ASSERT_TRUE (it.Next ());
323
+ EXPECT_EQ (5 , it.Get ().ival ());
324
+
325
+ it = ql_.GetIterator (-1 );
326
+ ASSERT_TRUE (it.Next ());
327
+ EXPECT_EQ (16 , it.Get ().ival ());
328
+
329
+ ql_.Push (" bobobob" , QList::TAIL);
330
+ it = ql_.GetIterator (-1 );
331
+ ASSERT_TRUE (it.Next ());
332
+ EXPECT_EQ (" bobobob" , it.Get ().view ());
333
+
334
+ for (int i = 0 ; i < 12 ; i++) {
335
+ it = ql_.GetIterator (i);
336
+ ASSERT_TRUE (it.Next ());
337
+ EXPECT_EQ (i + 5 , it.Get ().ival ());
338
+ }
339
+ }
340
+
341
+ TEST_P (OptionsTest, DelRangeC) {
342
+ auto [fill, compress] = GetParam ();
343
+ ql_ = QList (fill, compress);
344
+ long long nums[5000 ];
345
+ for (int i = 0 ; i < 33 ; i++) {
346
+ nums[i] = -5157318210846258176 + i;
347
+ ql_.Push (absl::StrCat (nums[i]), QList::TAIL);
348
+ }
349
+ if (fill == 32 )
350
+ ql_verify (ql_, 2 , 33 , 32 , 1 );
351
+
352
+ /* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
353
+ ql_.Erase (0 , 3 );
354
+ ql_.Erase (-29 , 4000 ); /* make sure not loop forever */
355
+ if (fill == 32 )
356
+ ql_verify (ql_, 1 , 1 , 1 , 1 );
357
+ auto it = ql_.GetIterator (0 );
358
+ ASSERT_TRUE (it.Next ());
359
+ ASSERT_EQ (-5157318210846258173 , it.Get ().ival ());
360
+ }
361
+
362
+ TEST_P (OptionsTest, DelRangeD) {
363
+ auto [fill, compress] = GetParam ();
364
+ ql_ = QList (fill, compress);
365
+ long long nums[5000 ];
366
+ for (int i = 0 ; i < 33 ; i++) {
367
+ nums[i] = -5157318210846258176 + i;
368
+ ql_.Push (absl::StrCat (nums[i]), QList::TAIL);
369
+ }
370
+ if (fill == 32 )
371
+ ql_verify (ql_, 2 , 33 , 32 , 1 );
372
+ ql_.Erase (-12 , 3 );
373
+
374
+ ASSERT_EQ (30 , ql_.Size ());
375
+ }
376
+
377
+ } // namespace dfly
0 commit comments