mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-10 18:05:44 +02:00
chore: Add more qlist tests (#4217)
* chore: Add more qlist tests Also fix a typo bug in NodeAllowMerge. Signed-off-by: Roman Gershman <roman@dragonflydb.io> * chore: fix build --------- Signed-off-by: Roman Gershman <roman@dragonflydb.io>
This commit is contained in:
parent
dc04b196d5
commit
c9654d4050
3 changed files with 371 additions and 58 deletions
|
@ -65,7 +65,7 @@ static_assert(sizeof(QList) == 32);
|
|||
enum IterDir : uint8_t { FWD = 1, REV = 0 };
|
||||
|
||||
/* This is for test suite development purposes only, 0 means disabled. */
|
||||
static size_t packed_threshold = 0;
|
||||
size_t packed_threshold = 0;
|
||||
|
||||
/* Optimization levels for size-based filling.
|
||||
* Note that the largest possible limit is 64k, so even if each record takes
|
||||
|
@ -123,7 +123,9 @@ bool NodeAllowMerge(const quicklistNode* a, const quicklistNode* b, const int fi
|
|||
/* approximate merged listpack size (- 7 to remove one listpack
|
||||
* header/trailer, see LP_HDR_SIZE and LP_EOF) */
|
||||
unsigned int merge_sz = a->sz + b->sz - 7;
|
||||
return quicklistNodeExceedsLimit(fill, merge_sz, a->count + b->count);
|
||||
|
||||
// Allow merge if new node will not exceed the limit.
|
||||
return !quicklistNodeExceedsLimit(fill, merge_sz, a->count + b->count);
|
||||
}
|
||||
|
||||
quicklistNode* CreateNode() {
|
||||
|
@ -140,6 +142,7 @@ quicklistNode* CreateNode() {
|
|||
}
|
||||
|
||||
uint8_t* LP_Insert(uint8_t* lp, string_view elem, uint8_t* pos, int lp_where) {
|
||||
DCHECK(pos);
|
||||
return lpInsertString(lp, uint_ptr(elem), elem.size(), pos, lp_where, NULL);
|
||||
}
|
||||
|
||||
|
@ -290,6 +293,10 @@ quicklistNode* SplitNode(quicklistNode* node, int offset, bool after) {
|
|||
|
||||
} // namespace
|
||||
|
||||
void QList::SetPackedThreshold(unsigned threshold) {
|
||||
packed_threshold = threshold;
|
||||
}
|
||||
|
||||
QList::QList() : fill_(-2), compress_(0), bookmark_count_(0) {
|
||||
}
|
||||
|
||||
|
@ -529,28 +536,15 @@ void QList::InsertNode(quicklistNode* old_node, quicklistNode* new_node, InsertO
|
|||
}
|
||||
|
||||
void QList::Insert(Iterator it, std::string_view elem, InsertOpt insert_opt) {
|
||||
DCHECK(it.current_);
|
||||
DCHECK(it.zi_);
|
||||
|
||||
int full = 0, at_tail = 0, at_head = 0, avail_next = 0, avail_prev = 0;
|
||||
quicklistNode* node = it.current_;
|
||||
quicklistNode* new_node = NULL;
|
||||
size_t sz = elem.size();
|
||||
bool after = insert_opt == AFTER;
|
||||
|
||||
if (!node) {
|
||||
/* we have no reference node, so let's create only node in the list */
|
||||
DCHECK_EQ(count_, 0u);
|
||||
DCHECK_EQ(len_, 0u);
|
||||
|
||||
if (ABSL_PREDICT_FALSE(IsLargeElement(sz, fill_))) {
|
||||
InsertPlainNode(tail_, elem, insert_opt);
|
||||
return;
|
||||
}
|
||||
|
||||
new_node = CreateNode(QUICKLIST_NODE_CONTAINER_PACKED, elem);
|
||||
InsertNode(NULL, new_node, insert_opt);
|
||||
count_++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Populate accounting flags for easier boolean checks later */
|
||||
if (!NodeAllowInsert(node, fill_, sz)) {
|
||||
full = 1;
|
||||
|
@ -831,10 +825,10 @@ quicklistNode* QList::ListpackMerge(quicklistNode* a, quicklistNode* b) {
|
|||
DelNode(nokeep);
|
||||
quicklistCompress(keep);
|
||||
return keep;
|
||||
} else {
|
||||
/* else, the merge returned NULL and nothing changed. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* else, the merge returned NULL and nothing changed. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void QList::DelNode(quicklistNode* node) {
|
||||
|
@ -909,13 +903,13 @@ auto QList::GetIterator(Where where) const -> Iterator {
|
|||
auto QList::GetIterator(long idx) const -> Iterator {
|
||||
quicklistNode* n;
|
||||
unsigned long long accum = 0;
|
||||
unsigned long long index;
|
||||
int forward = idx < 0 ? 0 : 1; /* < 0 -> reverse, 0+ -> forward */
|
||||
|
||||
index = forward ? idx : (-idx) - 1;
|
||||
uint64_t index = forward ? idx : (-idx) - 1;
|
||||
if (index >= count_)
|
||||
return {};
|
||||
|
||||
DCHECK(head_);
|
||||
|
||||
/* Seek in the other direction if that way is shorter. */
|
||||
int seek_forward = forward;
|
||||
unsigned long long seek_index = index;
|
||||
|
|
|
@ -46,6 +46,10 @@ class QList {
|
|||
|
||||
bool operator==(std::string_view sv) const;
|
||||
|
||||
friend bool operator==(std::string_view sv, const Entry& entry) {
|
||||
return entry == sv;
|
||||
}
|
||||
|
||||
std::string to_string() const {
|
||||
if (std::holds_alternative<int64_t>(value_)) {
|
||||
return std::to_string(std::get<int64_t>(value_));
|
||||
|
@ -100,6 +104,8 @@ class QList {
|
|||
// Returns true if pivot found and elem inserted, false otherwise.
|
||||
bool Insert(std::string_view pivot, std::string_view elem, InsertOpt opt);
|
||||
|
||||
void Insert(Iterator it, std::string_view elem, InsertOpt opt);
|
||||
|
||||
// Returns true if item was replaced, false if index is out of range.
|
||||
bool Replace(long index, std::string_view elem);
|
||||
|
||||
|
@ -141,6 +147,12 @@ class QList {
|
|||
return tail_;
|
||||
}
|
||||
|
||||
void set_fill(int fill) {
|
||||
fill_ = fill;
|
||||
}
|
||||
|
||||
static void SetPackedThreshold(unsigned threshold);
|
||||
|
||||
private:
|
||||
bool AllowCompression() const {
|
||||
return compress_ != 0;
|
||||
|
@ -153,7 +165,6 @@ class QList {
|
|||
bool PushTail(std::string_view value);
|
||||
void InsertPlainNode(quicklistNode* old_node, std::string_view, InsertOpt insert_opt);
|
||||
void InsertNode(quicklistNode* old_node, quicklistNode* new_node, InsertOpt insert_opt);
|
||||
void Insert(Iterator it, std::string_view elem, InsertOpt opt);
|
||||
void Replace(Iterator it, std::string_view elem);
|
||||
|
||||
void Compress(quicklistNode* node);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "core/qlist.h"
|
||||
|
||||
#include <absl/strings/match.h>
|
||||
#include <absl/strings/str_cat.h>
|
||||
#include <absl/strings/str_format.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
@ -76,6 +77,7 @@ static int ql_verify(const QList& ql, uint32_t nc, uint32_t count, uint32_t head
|
|||
while (node) {
|
||||
node_size += node->count;
|
||||
node = node->next;
|
||||
CHECK(node != ql.Head());
|
||||
}
|
||||
|
||||
if (node_size != ql.Size()) {
|
||||
|
@ -101,13 +103,13 @@ static int ql_verify(const QList& ql, uint32_t nc, uint32_t count, uint32_t head
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (ql.Head() && head_count != ql.Head()->count && head_count != lpLength(ql.Head()->entry)) {
|
||||
if (head_count != ql.Head()->count && head_count != lpLength(ql.Head()->entry)) {
|
||||
LOG(ERROR) << absl::StrFormat("head count wrong: expected %u got cached %u vs. actual %lu",
|
||||
head_count, ql.Head()->count, lpLength(ql.Head()->entry));
|
||||
errors++;
|
||||
}
|
||||
|
||||
if (ql.Tail() && tail_count != ql.Tail()->count && tail_count != lpLength(ql.Tail()->entry)) {
|
||||
if (tail_count != ql.Tail()->count && tail_count != lpLength(ql.Tail()->entry)) {
|
||||
LOG(ERROR) << "tail count wrong: expected " << tail_count << "got cached " << ql.Tail()->count
|
||||
<< " vs. actual " << lpLength(ql.Tail()->entry);
|
||||
errors++;
|
||||
|
@ -247,6 +249,37 @@ TEST_F(QListTest, PushPlain) {
|
|||
EXPECT_THAT(items, ElementsAre(val));
|
||||
}
|
||||
|
||||
TEST_F(QListTest, GetNum) {
|
||||
ql_.Push("1251977", QList::HEAD);
|
||||
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||
ASSERT_TRUE(it.Next());
|
||||
EXPECT_EQ(1251977, it.Get().ival());
|
||||
}
|
||||
|
||||
TEST_F(QListTest, CompressionPlain) {
|
||||
char buf[256];
|
||||
QList::SetPackedThreshold(1);
|
||||
ql_ = QList(-2, 1);
|
||||
|
||||
for (int i = 0; i < 500; i++) {
|
||||
/* Set to 256 to allow the node to be triggered to compress,
|
||||
* if it is less than 48(nocompress), the test will be successful. */
|
||||
snprintf(buf, sizeof(buf), "hello%d", i);
|
||||
ql_.Push(string_view{buf, sizeof(buf)}, QList::HEAD);
|
||||
}
|
||||
QList::SetPackedThreshold(0);
|
||||
|
||||
QList::Iterator it = ql_.GetIterator(QList::TAIL);
|
||||
int i = 0;
|
||||
while (it.Next()) {
|
||||
string_view sv = it.Get().view();
|
||||
ASSERT_EQ(sizeof(buf), sv.size());
|
||||
ASSERT_TRUE(absl::StartsWith(sv, StrCat("hello", i)));
|
||||
i++;
|
||||
}
|
||||
EXPECT_EQ(500, i);
|
||||
}
|
||||
|
||||
using FillCompress = tuple<int, unsigned>;
|
||||
|
||||
class PrintToFillCompress {
|
||||
|
@ -289,6 +322,25 @@ TEST_P(OptionsTest, Numbers) {
|
|||
EXPECT_EQ("xxxxxxxxxxxxxxxxxxxx", it.Get().view());
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, NumbersIndex) {
|
||||
auto [fill, compress] = GetParam();
|
||||
ql_ = QList(fill, compress);
|
||||
|
||||
long long nums[5000];
|
||||
for (int i = 0; i < 760; i++) {
|
||||
nums[i] = -5157318210846258176 + i;
|
||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||
}
|
||||
|
||||
unsigned i = 437;
|
||||
QList::Iterator it = ql_.GetIterator(i);
|
||||
while (it.Next()) {
|
||||
ASSERT_EQ(nums[i], it.Get().ival());
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQ(760, i);
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelRangeA) {
|
||||
auto [fill, compress] = GetParam();
|
||||
ql_ = QList(fill, compress);
|
||||
|
@ -297,15 +349,17 @@ TEST_P(OptionsTest, DelRangeA) {
|
|||
nums[i] = -5157318210846258176 + i;
|
||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||
}
|
||||
if (fill == 32)
|
||||
ql_verify(ql_, 2, 33, 32, 1);
|
||||
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||
}
|
||||
|
||||
/* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
|
||||
ql_.Erase(0, 3);
|
||||
ql_.Erase(-29, 4000); /* make sure not loop forever */
|
||||
if (fill == 32)
|
||||
ql_verify(ql_, 1, 1, 1, 1);
|
||||
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 1, 1, 1, 1));
|
||||
}
|
||||
auto it = ql_.GetIterator(0);
|
||||
ASSERT_TRUE(it.Next());
|
||||
EXPECT_EQ(-5157318210846258173, it.Get().ival());
|
||||
|
@ -320,14 +374,15 @@ TEST_P(OptionsTest, DelRangeB) {
|
|||
nums[i] = i;
|
||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||
}
|
||||
if (fill == 32)
|
||||
ql_verify(ql_, 2, 33, 32, 1);
|
||||
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||
}
|
||||
/* ltrim 5 16 (keep [5,16] inclusive = 12 remaining) */
|
||||
ql_.Erase(0, 5);
|
||||
ql_.Erase(-16, 16);
|
||||
if (fill == 32)
|
||||
ql_verify(ql_, 1, 12, 12, 12);
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 1, 12, 12, 12));
|
||||
}
|
||||
|
||||
auto it = ql_.GetIterator(0);
|
||||
ASSERT_TRUE(it.Next());
|
||||
|
@ -357,14 +412,16 @@ TEST_P(OptionsTest, DelRangeC) {
|
|||
nums[i] = -5157318210846258176 + i;
|
||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||
}
|
||||
if (fill == 32)
|
||||
ql_verify(ql_, 2, 33, 32, 1);
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||
}
|
||||
|
||||
/* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */
|
||||
ql_.Erase(0, 3);
|
||||
ql_.Erase(-29, 4000); /* make sure not loop forever */
|
||||
if (fill == 32)
|
||||
ql_verify(ql_, 1, 1, 1, 1);
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 1, 1, 1, 1));
|
||||
}
|
||||
auto it = ql_.GetIterator(0);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ(-5157318210846258173, it.Get().ival());
|
||||
|
@ -378,8 +435,9 @@ TEST_P(OptionsTest, DelRangeD) {
|
|||
nums[i] = -5157318210846258176 + i;
|
||||
ql_.Push(absl::StrCat(nums[i]), QList::TAIL);
|
||||
}
|
||||
if (fill == 32)
|
||||
ql_verify(ql_, 2, 33, 32, 1);
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 2, 33, 32, 1));
|
||||
}
|
||||
ql_.Erase(-12, 3);
|
||||
|
||||
ASSERT_EQ(30, ql_.Size());
|
||||
|
@ -392,9 +450,9 @@ TEST_P(OptionsTest, DelRangeNode) {
|
|||
for (int i = 0; i < 32; i++)
|
||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||
|
||||
ql_verify(ql_, 1, 32, 32, 32);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 1, 32, 32, 32));
|
||||
ql_.Erase(0, 32);
|
||||
ql_verify(ql_, 0, 0, 0, 0);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelRangeNodeOverflow) {
|
||||
|
@ -403,9 +461,9 @@ TEST_P(OptionsTest, DelRangeNodeOverflow) {
|
|||
|
||||
for (int i = 0; i < 32; i++)
|
||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||
ql_verify(ql_, 1, 32, 32, 32);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 1, 32, 32, 32));
|
||||
ql_.Erase(0, 128);
|
||||
ql_verify(ql_, 0, 0, 0, 0);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelRangeMiddle100of500) {
|
||||
|
@ -415,9 +473,9 @@ TEST_P(OptionsTest, DelRangeMiddle100of500) {
|
|||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||
|
||||
ql_verify(ql_, 16, 500, 32, 20);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||
ql_.Erase(200, 100);
|
||||
ql_verify(ql_, 14, 400, 32, 20);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 14, 400, 32, 20));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelLessFillAcrossNodes) {
|
||||
|
@ -426,9 +484,9 @@ TEST_P(OptionsTest, DelLessFillAcrossNodes) {
|
|||
|
||||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||
ql_verify(ql_, 16, 500, 32, 20);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||
ql_.Erase(60, 10);
|
||||
ql_verify(ql_, 16, 490, 32, 20);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 490, 32, 20));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelNegOne) {
|
||||
|
@ -436,9 +494,9 @@ TEST_P(OptionsTest, DelNegOne) {
|
|||
ql_ = QList(32, compress);
|
||||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||
ql_verify(ql_, 16, 500, 32, 20);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||
ql_.Erase(-1, 1);
|
||||
ql_verify(ql_, 16, 499, 32, 19);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 499, 32, 19));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelNegOneOverflow) {
|
||||
|
@ -447,10 +505,10 @@ TEST_P(OptionsTest, DelNegOneOverflow) {
|
|||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||
|
||||
ql_verify(ql_, 16, 500, 32, 20);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 32, 20));
|
||||
ql_.Erase(-1, 128);
|
||||
|
||||
ql_verify(ql_, 16, 499, 32, 19);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 499, 32, 19));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelNeg100From500) {
|
||||
|
@ -459,7 +517,7 @@ TEST_P(OptionsTest, DelNeg100From500) {
|
|||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||
ql_.Erase(-100, 100);
|
||||
ql_verify(ql_, 13, 400, 32, 16);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 13, 400, 32, 16));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelMin10_5_from50) {
|
||||
|
@ -468,9 +526,9 @@ TEST_P(OptionsTest, DelMin10_5_from50) {
|
|||
|
||||
for (int i = 0; i < 50; i++)
|
||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||
ql_verify(ql_, 2, 50, 32, 18);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 2, 50, 32, 18));
|
||||
ql_.Erase(-10, 5);
|
||||
ql_verify(ql_, 2, 45, 32, 13);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 2, 45, 32, 13));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, DelElems) {
|
||||
|
@ -513,4 +571,254 @@ TEST_P(OptionsTest, DelElems) {
|
|||
EXPECT_THAT(ToItems(), ElementsAreArray(resultB));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, IterateReverse) {
|
||||
auto [_, compress] = GetParam();
|
||||
ql_ = QList(32, compress);
|
||||
|
||||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||
QList::Iterator it = ql_.GetIterator(QList::TAIL);
|
||||
int i = 0;
|
||||
while (it.Next()) {
|
||||
ASSERT_EQ(StrCat("hello", i), it.Get());
|
||||
i++;
|
||||
}
|
||||
ASSERT_EQ(500, i);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 20, 32));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, Iterate500) {
|
||||
auto [_, compress] = GetParam();
|
||||
ql_ = QList(32, compress);
|
||||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||
|
||||
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||
int i = 499, count = 0;
|
||||
while (it.Next()) {
|
||||
QList::Entry entry = it.Get();
|
||||
ASSERT_EQ(StrCat("hello", i), entry);
|
||||
i--;
|
||||
count++;
|
||||
}
|
||||
EXPECT_EQ(500, count);
|
||||
ASSERT_EQ(0, ql_verify(ql_, 16, 500, 20, 32));
|
||||
|
||||
it = ql_.GetIterator(QList::TAIL);
|
||||
i = 0;
|
||||
while (it.Next()) {
|
||||
ASSERT_EQ(StrCat("hello", i), it.Get());
|
||||
i++;
|
||||
}
|
||||
EXPECT_EQ(500, i);
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, IterateAfterOne) {
|
||||
auto [_, compress] = GetParam();
|
||||
ql_ = QList(-2, compress);
|
||||
ql_.Push("hello", QList::HEAD);
|
||||
|
||||
QList::Iterator it = ql_.GetIterator(0);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ql_.Insert(it, "abc", QList::AFTER);
|
||||
|
||||
ASSERT_EQ(0, ql_verify(ql_, 1, 2, 2, 2));
|
||||
|
||||
/* verify results */
|
||||
it = ql_.GetIterator(0);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("hello", it.Get());
|
||||
|
||||
it = ql_.GetIterator(1);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("abc", it.Get());
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, IterateDelete) {
|
||||
auto [fill, compress] = GetParam();
|
||||
ql_ = QList(fill, compress);
|
||||
|
||||
ql_.Push("abc", QList::TAIL);
|
||||
ql_.Push("def", QList::TAIL);
|
||||
ql_.Push("hij", QList::TAIL);
|
||||
ql_.Push("jkl", QList::TAIL);
|
||||
ql_.Push("oop", QList::TAIL);
|
||||
|
||||
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||
int i = 0;
|
||||
while (it.Next()) {
|
||||
if (it.Get() == "hij") {
|
||||
it = ql_.Erase(it);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
ASSERT_EQ(5, i);
|
||||
|
||||
ASSERT_THAT(ToItems(), ElementsAre("abc", "def", "jkl", "oop"));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, InsertBeforeOne) {
|
||||
auto [_, compress] = GetParam();
|
||||
ql_ = QList(-2, compress);
|
||||
|
||||
ql_.Push("hello", QList::HEAD);
|
||||
QList::Iterator it = ql_.GetIterator(0);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ql_.Insert(it, "abc", QList::BEFORE);
|
||||
ql_verify(ql_, 1, 2, 2, 2);
|
||||
|
||||
/* verify results */
|
||||
it = ql_.GetIterator(0);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("abc", it.Get());
|
||||
|
||||
it = ql_.GetIterator(1);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("hello", it.Get());
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, InsertWithHeadFull) {
|
||||
auto [_, compress] = GetParam();
|
||||
ql_ = QList(4, compress);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
ql_.Push(StrCat("hello", i), QList::TAIL);
|
||||
|
||||
ql_.set_fill(-1);
|
||||
QList::Iterator it = ql_.GetIterator(-10);
|
||||
ASSERT_TRUE(it.Next());
|
||||
|
||||
char buf[4096] = {0};
|
||||
ql_.Insert(it, string_view{buf, sizeof(buf)}, QList::BEFORE);
|
||||
ql_verify(ql_, 4, 11, 1, 2);
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, InsertWithTailFull) {
|
||||
auto [_, compress] = GetParam();
|
||||
ql_ = QList(4, compress);
|
||||
for (int i = 0; i < 10; i++)
|
||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||
|
||||
ql_.set_fill(-1);
|
||||
QList::Iterator it = ql_.GetIterator(-1);
|
||||
ASSERT_TRUE(it.Next());
|
||||
|
||||
char buf[4096] = {0};
|
||||
ql_.Insert(it, string_view{buf, sizeof(buf)}, QList::AFTER);
|
||||
ql_verify(ql_, 4, 11, 2, 1);
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, InsertOnceWhileIterating) {
|
||||
auto [fill, compress] = GetParam();
|
||||
ql_ = QList(fill, compress);
|
||||
|
||||
ql_.Push("abc", QList::TAIL);
|
||||
ql_.set_fill(1);
|
||||
|
||||
ql_.Push("def", QList::TAIL);
|
||||
ql_.set_fill(fill);
|
||||
ql_.Push("bob", QList::TAIL);
|
||||
ql_.Push("foo", QList::TAIL);
|
||||
ql_.Push("zoo", QList::TAIL);
|
||||
|
||||
/* insert "bar" before "bob" while iterating over list. */
|
||||
QList::Iterator it = ql_.GetIterator(QList::HEAD);
|
||||
while (it.Next()) {
|
||||
if (it.Get() == "bob") {
|
||||
ql_.Insert(it, "bar", QList::BEFORE);
|
||||
break; /* didn't we fix insert-while-iterating? */
|
||||
}
|
||||
}
|
||||
EXPECT_THAT(ToItems(), ElementsAre("abc", "def", "bar", "bob", "foo", "zoo"));
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, InsertBefore250NewInMiddleOf500Elements) {
|
||||
auto [fill, compress] = GetParam();
|
||||
ql_ = QList(fill, compress);
|
||||
for (int i = 0; i < 500; i++) {
|
||||
string val = StrCat("hello", i);
|
||||
val.resize(32);
|
||||
ql_.Push(val, QList::TAIL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 250; i++) {
|
||||
QList::Iterator it = ql_.GetIterator(250);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ql_.Insert(it, StrCat("abc", i), QList::BEFORE);
|
||||
}
|
||||
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 25, 750, 32, 20));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, InsertAfter250NewInMiddleOf500Elements) {
|
||||
auto [fill, compress] = GetParam();
|
||||
ql_ = QList(fill, compress);
|
||||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i), QList::HEAD);
|
||||
|
||||
for (int i = 0; i < 250; i++) {
|
||||
QList::Iterator it = ql_.GetIterator(250);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ql_.Insert(it, StrCat("abc", i), QList::AFTER);
|
||||
}
|
||||
|
||||
ASSERT_EQ(750, ql_.Size());
|
||||
|
||||
if (fill == 32) {
|
||||
ASSERT_EQ(0, ql_verify(ql_, 26, 750, 20, 32));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, NextPlain) {
|
||||
auto [_, compress] = GetParam();
|
||||
ql_ = QList(-2, compress);
|
||||
|
||||
QList::SetPackedThreshold(3);
|
||||
|
||||
const char* strings[] = {"hello1", "hello2", "h3", "h4", "hello5"};
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
ql_.Push(strings[i], QList::HEAD);
|
||||
|
||||
QList::Iterator it = ql_.GetIterator(QList::TAIL);
|
||||
int j = 0;
|
||||
|
||||
while (it.Next()) {
|
||||
ASSERT_EQ(strings[j], it.Get());
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(OptionsTest, IndexFrom500) {
|
||||
auto [fill, compress] = GetParam();
|
||||
ql_ = QList(fill, compress);
|
||||
for (int i = 0; i < 500; i++)
|
||||
ql_.Push(StrCat("hello", i + 1), QList::TAIL);
|
||||
|
||||
QList::Iterator it = ql_.GetIterator(1);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("hello2", it.Get());
|
||||
it = ql_.GetIterator(200);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("hello201", it.Get());
|
||||
|
||||
it = ql_.GetIterator(-1);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("hello500", it.Get());
|
||||
|
||||
it = ql_.GetIterator(-2);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("hello499", it.Get());
|
||||
|
||||
it = ql_.GetIterator(-100);
|
||||
ASSERT_TRUE(it.Next());
|
||||
ASSERT_EQ("hello401", it.Get());
|
||||
|
||||
it = ql_.GetIterator(500);
|
||||
ASSERT_FALSE(it.Next());
|
||||
}
|
||||
|
||||
} // namespace dfly
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue