github.com/flower-corp/rosedb@v1.1.2-0.20230117132829-21dc4f7b319a/list_test.go (about) 1 package rosedb 2 3 import ( 4 "path/filepath" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 ) 9 10 func TestRoseDB_LPush(t *testing.T) { 11 t.Run("fileio", func(t *testing.T) { 12 testRoseDBPush(t, true, FileIO, KeyOnlyMemMode) 13 }) 14 15 t.Run("mmap", func(t *testing.T) { 16 testRoseDBPush(t, true, MMap, KeyValueMemMode) 17 }) 18 } 19 20 func TestRoseDB_RPush(t *testing.T) { 21 t.Run("fileio", func(t *testing.T) { 22 testRoseDBPush(t, false, FileIO, KeyOnlyMemMode) 23 }) 24 25 t.Run("mmap", func(t *testing.T) { 26 testRoseDBPush(t, false, MMap, KeyValueMemMode) 27 }) 28 } 29 30 func TestRoseDB_Push_UntilRotateFile(t *testing.T) { 31 path := filepath.Join("/tmp", "rosedb") 32 opts := DefaultOptions(path) 33 opts.LogFileSizeThreshold = 32 << 20 34 db, err := Open(opts) 35 assert.Nil(t, err) 36 defer destroyDB(db) 37 38 writeCount := 600000 39 key := []byte("mylist") 40 for i := 0; i <= writeCount; i++ { 41 err := db.LPush(key, GetValue128B()) 42 assert.Nil(t, err) 43 } 44 } 45 46 func testRoseDBPush(t *testing.T, isLush bool, ioType IOType, mode DataIndexMode) { 47 path := filepath.Join("/tmp", "rosedb") 48 opts := DefaultOptions(path) 49 opts.IoType = ioType 50 opts.IndexMode = mode 51 db, err := Open(opts) 52 assert.Nil(t, err) 53 defer destroyDB(db) 54 55 type args struct { 56 key []byte 57 values [][]byte 58 } 59 tests := []struct { 60 name string 61 db *RoseDB 62 args args 63 wantErr bool 64 }{ 65 { 66 "nil-value", db, args{key: GetKey(0), values: [][]byte{GetValue16B()}}, false, 67 }, 68 { 69 "one-value", db, args{key: GetKey(1), values: [][]byte{GetValue16B()}}, false, 70 }, 71 { 72 "multi-value", db, args{key: GetKey(2), values: [][]byte{GetValue16B(), GetValue16B(), GetValue16B()}}, false, 73 }, 74 } 75 for _, tt := range tests { 76 t.Run(tt.name, func(t *testing.T) { 77 if isLush { 78 if err := tt.db.LPush(tt.args.key, tt.args.values...); (err != nil) != tt.wantErr { 79 t.Errorf("LPush() error = %v, wantErr %v", err, tt.wantErr) 80 } 81 } else { 82 if err := tt.db.RPush(tt.args.key, tt.args.values...); (err != nil) != tt.wantErr { 83 t.Errorf("RPush() error = %v, wantErr %v", err, tt.wantErr) 84 } 85 } 86 }) 87 } 88 } 89 90 func TestRoseDB_LPop(t *testing.T) { 91 t.Run("fileio", func(t *testing.T) { 92 testRoseDBLPop(t, FileIO, KeyOnlyMemMode) 93 }) 94 t.Run("mmap", func(t *testing.T) { 95 testRoseDBLPop(t, MMap, KeyValueMemMode) 96 }) 97 } 98 99 func TestRoseDB_RPop(t *testing.T) { 100 t.Run("fileio", func(t *testing.T) { 101 testRoseDBRPop(t, FileIO, KeyOnlyMemMode) 102 }) 103 t.Run("mmap", func(t *testing.T) { 104 testRoseDBRPop(t, MMap, KeyValueMemMode) 105 }) 106 } 107 108 func testRoseDBLPop(t *testing.T, ioType IOType, mode DataIndexMode) { 109 path := filepath.Join("/tmp", "rosedb") 110 opts := DefaultOptions(path) 111 opts.IoType = ioType 112 opts.IndexMode = mode 113 db, err := Open(opts) 114 assert.Nil(t, err) 115 defer destroyDB(db) 116 117 // none 118 listKey := []byte("my_list") 119 pop, err := db.LPop(listKey) 120 assert.Nil(t, pop) 121 assert.Nil(t, err) 122 123 // one 124 err = db.LPush(listKey, GetValue16B()) 125 assert.Nil(t, err) 126 v1, err := db.LPop(listKey) 127 assert.Nil(t, err) 128 assert.NotNil(t, v1) 129 130 // rpush one 131 err = db.RPush(listKey, GetValue16B()) 132 assert.Nil(t, err) 133 v2, err := db.LPop(listKey) 134 assert.Nil(t, err) 135 assert.NotNil(t, v2) 136 137 // multi 138 err = db.LPush(listKey, GetKey(0), GetKey(1), GetKey(2)) 139 assert.Nil(t, err) 140 141 var values [][]byte 142 for db.LLen(listKey) > 0 { 143 v, err := db.LPop(listKey) 144 assert.Nil(t, err) 145 values = append(values, v) 146 } 147 expected := [][]byte{GetKey(2), GetKey(1), GetKey(0)} 148 assert.Equal(t, expected, values) 149 150 // lRange 151 values, err = db.LRange(listKey, 0, -1) 152 assert.Equal(t, ErrKeyNotFound, err) 153 assert.Nil(t, values) 154 } 155 156 func testRoseDBRPop(t *testing.T, ioType IOType, mode DataIndexMode) { 157 path := filepath.Join("/tmp", "rosedb") 158 opts := DefaultOptions(path) 159 opts.IoType = ioType 160 opts.IndexMode = mode 161 db, err := Open(opts) 162 assert.Nil(t, err) 163 defer destroyDB(db) 164 165 // none 166 listKey := []byte("my_list") 167 pop, err := db.RPop(listKey) 168 assert.Nil(t, pop) 169 assert.Nil(t, err) 170 171 // one 172 err = db.RPush(listKey, GetValue16B()) 173 assert.Nil(t, err) 174 v1, err := db.RPop(listKey) 175 assert.Nil(t, err) 176 assert.NotNil(t, v1) 177 178 // lpush one 179 err = db.LPush(listKey, GetValue16B()) 180 assert.Nil(t, err) 181 v2, err := db.RPop(listKey) 182 assert.Nil(t, err) 183 assert.NotNil(t, v2) 184 185 // multi 186 err = db.RPush(listKey, GetKey(0), GetKey(1), GetKey(2)) 187 assert.Nil(t, err) 188 189 var values [][]byte 190 for db.LLen(listKey) > 0 { 191 v, err := db.RPop(listKey) 192 assert.Nil(t, err) 193 values = append(values, v) 194 } 195 expected := [][]byte{GetKey(2), GetKey(1), GetKey(0)} 196 assert.Equal(t, expected, values) 197 198 // lRange 199 values, err = db.LRange(listKey, 0, -1) 200 assert.Equal(t, ErrKeyNotFound, err) 201 assert.Nil(t, values) 202 } 203 204 func TestRoseDB_LMove(t *testing.T) { 205 t.Run("fileio", func(t *testing.T) { 206 testRoseDBLMove(t, FileIO, KeyOnlyMemMode) 207 }) 208 t.Run("mmap", func(t *testing.T) { 209 testRoseDBLMove(t, MMap, KeyValueMemMode) 210 }) 211 } 212 213 func testRoseDBLMove(t *testing.T, ioType IOType, mode DataIndexMode) { 214 path := filepath.Join("/tmp", "rosedb") 215 opts := DefaultOptions(path) 216 opts.IoType = ioType 217 opts.IndexMode = mode 218 db, err := Open(opts) 219 assert.Nil(t, err) 220 defer destroyDB(db) 221 222 // none 223 srcListKey := []byte("src_list") 224 dstListKey := []byte("dst_list") 225 v, err := db.LMove(srcListKey, dstListKey, true, true) 226 assert.Nil(t, v) 227 assert.Nil(t, err) 228 229 err = db.RPush(srcListKey, GetKey(1), GetKey(2), GetKey(3), GetKey(4), GetKey(5)) 230 assert.Nil(t, err) 231 232 // left-pop left-push 233 v, err = db.LMove(srcListKey, dstListKey, true, true) 234 assert.Nil(t, err) 235 assert.Equal(t, v, GetKey(1)) 236 // src[2, 3, 4, 5] dst[1] 237 238 // left-pop right-push 239 v, err = db.LMove(srcListKey, dstListKey, true, false) 240 assert.Nil(t, err) 241 assert.Equal(t, v, GetKey(2)) 242 // src[3, 4, 5] dst[1, 2] 243 244 // right-pop left-push 245 v, err = db.LMove(srcListKey, dstListKey, false, true) 246 assert.Nil(t, err) 247 assert.Equal(t, v, GetKey(5)) 248 // src[3, 4] dst[5, 1, 2] 249 250 // right-pop right-push 251 v, err = db.LMove(srcListKey, dstListKey, false, false) 252 assert.Nil(t, err) 253 assert.Equal(t, v, GetKey(4)) 254 // src[3] dst[5, 1, 2, 4] 255 256 v, err = db.LIndex(dstListKey, 0) 257 assert.Nil(t, err) 258 assert.Equal(t, v, GetKey(5)) 259 260 v, err = db.LIndex(dstListKey, 1) 261 assert.Nil(t, err) 262 assert.Equal(t, v, GetKey(1)) 263 264 v, err = db.LIndex(dstListKey, 2) 265 assert.Nil(t, err) 266 assert.Equal(t, v, GetKey(2)) 267 268 v, err = db.LIndex(dstListKey, 3) 269 assert.Nil(t, err) 270 assert.Equal(t, v, GetKey(4)) 271 } 272 273 func TestRoseDB_LLen(t *testing.T) { 274 path := filepath.Join("/tmp", "rosedb") 275 opts := DefaultOptions(path) 276 db, err := Open(opts) 277 assert.Nil(t, err) 278 defer destroyDB(db) 279 280 listKey := []byte("my_list") 281 err = db.LPush(listKey, GetValue16B(), GetValue16B(), GetValue16B()) 282 assert.Nil(t, err) 283 assert.Equal(t, 3, db.LLen(listKey)) 284 285 // close and reopen 286 err = db.Close() 287 assert.Nil(t, err) 288 289 db2, err := Open(opts) 290 assert.Nil(t, err) 291 defer func() { 292 _ = db2.Close() 293 }() 294 err = db2.LPush(listKey, GetValue16B(), GetValue16B(), GetValue16B()) 295 assert.Nil(t, err) 296 assert.Equal(t, 6, db2.LLen(listKey)) 297 } 298 299 func TestRoseDB_DiscardStat_List(t *testing.T) { 300 helper := func(isDelete bool) { 301 path := filepath.Join("/tmp", "rosedb") 302 opts := DefaultOptions(path) 303 opts.LogFileSizeThreshold = 64 << 20 304 db, err := Open(opts) 305 assert.Nil(t, err) 306 defer destroyDB(db) 307 308 listKey := []byte("my_list") 309 writeCount := 800000 310 for i := 0; i < writeCount; i++ { 311 err := db.LPush(listKey, GetKey(i)) 312 assert.Nil(t, err) 313 } 314 315 for i := 0; i < writeCount/3; i++ { 316 if i%2 == 0 { 317 _, err := db.LPop(listKey) 318 assert.Nil(t, err) 319 } else { 320 _, err := db.RPop(listKey) 321 assert.Nil(t, err) 322 } 323 } 324 325 _ = db.Sync() 326 ccl, err := db.discards[List].getCCL(10, 0.2) 327 t.Log(err) 328 t.Log(ccl) 329 assert.Nil(t, err) 330 assert.Equal(t, 1, len(ccl)) 331 } 332 333 t.Run("delete", func(t *testing.T) { 334 helper(true) 335 }) 336 } 337 338 func TestRoseDB_ListGC(t *testing.T) { 339 path := filepath.Join("/tmp", "rosedb") 340 opts := DefaultOptions(path) 341 opts.LogFileSizeThreshold = 64 << 20 342 db, err := Open(opts) 343 assert.Nil(t, err) 344 defer destroyDB(db) 345 346 listKey := []byte("my_list") 347 writeCount := 800000 348 for i := 0; i < writeCount; i++ { 349 err := db.LPush(listKey, GetKey(i)) 350 assert.Nil(t, err) 351 } 352 353 for i := 0; i < writeCount/3; i++ { 354 if i%2 == 0 { 355 _, err := db.LPop(listKey) 356 assert.Nil(t, err) 357 } else { 358 _, err := db.RPop(listKey) 359 assert.Nil(t, err) 360 } 361 } 362 363 l1 := db.LLen(listKey) 364 assert.Equal(t, writeCount-writeCount/3, l1) 365 366 err = db.RunLogFileGC(List, 0, 0.3) 367 assert.Nil(t, err) 368 369 l2 := db.LLen(listKey) 370 assert.Equal(t, writeCount-writeCount/3, l2) 371 } 372 373 func TestRoseDB_LPushX(t *testing.T) { 374 t.Run("fileio", func(t *testing.T) { 375 testRoseDBPushX(t, true, FileIO, KeyOnlyMemMode) 376 }) 377 378 t.Run("mmap", func(t *testing.T) { 379 testRoseDBPushX(t, true, MMap, KeyValueMemMode) 380 }) 381 } 382 383 func TestRoseDB_RPushX(t *testing.T) { 384 t.Run("fileio", func(t *testing.T) { 385 testRoseDBPushX(t, false, FileIO, KeyOnlyMemMode) 386 }) 387 388 t.Run("mmap", func(t *testing.T) { 389 testRoseDBPushX(t, false, MMap, KeyValueMemMode) 390 }) 391 } 392 393 func testRoseDBPushX(t *testing.T, isLPush bool, ioType IOType, mode DataIndexMode) { 394 path := filepath.Join("/tmp", "rosedb") 395 opts := DefaultOptions(path) 396 opts.IoType = ioType 397 opts.IndexMode = mode 398 db, err := Open(opts) 399 assert.Nil(t, err) 400 defer destroyDB(db) 401 402 err = db.LPush(GetKey(1), []byte("1")) 403 assert.Nil(t, err) 404 err = db.LPush(GetKey(2), []byte("1")) 405 assert.Nil(t, err) 406 407 type args struct { 408 key []byte 409 values [][]byte 410 } 411 tests := []struct { 412 name string 413 db *RoseDB 414 args args 415 wantErr bool 416 }{ 417 { 418 "nil-key", db, args{key: GetKey(0), values: [][]byte{GetValue16B()}}, true, 419 }, 420 { 421 "one-value", db, args{key: GetKey(1), values: [][]byte{GetValue16B()}}, false, 422 }, 423 { 424 "multi-value", db, args{key: GetKey(2), values: [][]byte{GetValue16B(), GetValue16B(), GetValue16B()}}, false, 425 }, 426 } 427 for _, tt := range tests { 428 t.Run(tt.name, func(t *testing.T) { 429 if isLPush { 430 if err := tt.db.LPushX(tt.args.key, tt.args.values...); (err != nil) != tt.wantErr { 431 t.Errorf("LPushX() error = %v, wantErr %v", err, tt.wantErr) 432 } 433 } else { 434 if err := tt.db.RPushX(tt.args.key, tt.args.values...); (err != nil) != tt.wantErr { 435 t.Errorf("RPushX() error = %v, wantErr %v", err, tt.wantErr) 436 } 437 } 438 }) 439 } 440 } 441 func TestRoseDB_LIndex(t *testing.T) { 442 t.Run("fileio", func(t *testing.T) { 443 testRoseDBRLIndex(t, FileIO, KeyOnlyMemMode) 444 }) 445 t.Run("mmap", func(t *testing.T) { 446 testRoseDBRLIndex(t, MMap, KeyValueMemMode) 447 }) 448 } 449 450 func testRoseDBRLIndex(t *testing.T, ioType IOType, mode DataIndexMode) { 451 path := filepath.Join("/tmp", "rosedb") 452 opts := DefaultOptions(path) 453 opts.IoType = ioType 454 opts.IndexMode = mode 455 db, err := Open(opts) 456 assert.Nil(t, err) 457 defer destroyDB(db) 458 459 // none 460 listKey := []byte("my_list") 461 v, err := db.LIndex(listKey, 0) 462 assert.Nil(t, v) 463 assert.Nil(t, err) 464 465 // one 466 err = db.RPush(listKey, GetKey(1)) 467 assert.Nil(t, err) 468 469 lVal1, err := db.LIndex(listKey, 0) 470 assert.Nil(t, err) 471 assert.Equal(t, lVal1, GetKey(1)) 472 473 rVal1, err := db.LIndex(listKey, -1) 474 assert.Nil(t, err) 475 assert.Equal(t, rVal1, GetKey(1)) 476 477 // out of right range with one 478 rOut1, err := db.LIndex(listKey, 1) 479 assert.Equal(t, ErrWrongIndex, err) 480 assert.Nil(t, rOut1) 481 482 // out of left range with one 483 lOut1, err := db.LIndex(listKey, -2) 484 assert.Equal(t, ErrWrongIndex, err) 485 assert.Nil(t, lOut1) 486 487 // two 488 err = db.RPush(listKey, GetKey(2)) 489 assert.Nil(t, err) 490 491 lVal1, err = db.LIndex(listKey, 0) 492 assert.Nil(t, err) 493 assert.Equal(t, lVal1, GetKey(1)) 494 495 lVal2, err := db.LIndex(listKey, 1) 496 assert.Nil(t, err) 497 assert.Equal(t, lVal2, GetKey(2)) 498 499 rVal1, err = db.LIndex(listKey, -2) 500 assert.Nil(t, err) 501 assert.Equal(t, rVal1, GetKey(1)) 502 503 rVal2, err := db.LIndex(listKey, -1) 504 assert.Nil(t, err) 505 assert.Equal(t, rVal2, GetKey(2)) 506 507 // out of right range with two 508 rOut2, err := db.LIndex(listKey, 2) 509 assert.Equal(t, ErrWrongIndex, err) 510 assert.Nil(t, rOut2) 511 512 // out of left range with two 513 lOut2, err := db.LIndex(listKey, -3) 514 assert.Equal(t, ErrWrongIndex, err) 515 assert.Nil(t, lOut2) 516 } 517 518 func TestRoseDB_LSet(t *testing.T) { 519 t.Run("fileio", func(t *testing.T) { 520 testRoseDBLSet(t, FileIO, KeyOnlyMemMode) 521 }) 522 t.Run("mmap", func(t *testing.T) { 523 testRoseDBLSet(t, MMap, KeyValueMemMode) 524 }) 525 } 526 527 func testRoseDBLSet(t *testing.T, ioType IOType, mode DataIndexMode) { 528 path := filepath.Join("/tmp", "rosedb") 529 opts := DefaultOptions(path) 530 opts.IoType = ioType 531 opts.IndexMode = mode 532 db, err := Open(opts) 533 assert.Nil(t, err) 534 defer destroyDB(db) 535 536 // none 537 listKey := []byte("my_list") 538 err = db.LSet(listKey, 0, GetKey(1)) 539 assert.Equal(t, err, ErrKeyNotFound) 540 541 // one 542 err = db.RPush(listKey, GetKey(1)) 543 assert.Nil(t, err) 544 err = db.LSet(listKey, 0, GetKey(111)) 545 assert.Nil(t, err) 546 lPop, err := db.LPop(listKey) 547 assert.Nil(t, err) 548 assert.Equal(t, GetKey(111), lPop) 549 550 // three 551 err = db.RPush(listKey, GetKey(1)) 552 assert.Nil(t, err) 553 err = db.RPush(listKey, GetKey(2)) 554 assert.Nil(t, err) 555 err = db.RPush(listKey, GetKey(3)) 556 assert.Nil(t, err) 557 err = db.LSet(listKey, 0, GetKey(111)) 558 assert.Nil(t, err) 559 err = db.LSet(listKey, 1, GetKey(222)) 560 assert.Nil(t, err) 561 err = db.LSet(listKey, -1, GetKey(333)) 562 assert.Nil(t, err) 563 lPop, err = db.LPop(listKey) 564 assert.Nil(t, err) 565 assert.Equal(t, GetKey(111), lPop) 566 lPop, err = db.LPop(listKey) 567 assert.Nil(t, err) 568 assert.Equal(t, GetKey(222), lPop) 569 lPop, err = db.LPop(listKey) 570 assert.Nil(t, err) 571 assert.Equal(t, GetKey(333), lPop) 572 573 // out of range 574 err = db.RPush(listKey, GetKey(1)) 575 assert.Nil(t, err) 576 err = db.LSet(listKey, 1, GetKey(111)) 577 assert.Equal(t, err, ErrWrongIndex) 578 err = db.LSet(listKey, -2, GetKey(111)) 579 assert.Equal(t, err, ErrWrongIndex) 580 } 581 582 func TestRoseDB_listSequence(t *testing.T) { 583 584 t.Run("fileio", func(t *testing.T) { 585 testListSequence(t, FileIO, KeyOnlyMemMode) 586 }) 587 588 t.Run("mmap", func(t *testing.T) { 589 testListSequence(t, MMap, KeyValueMemMode) 590 }) 591 } 592 593 func testListSequence(t *testing.T, ioType IOType, mode DataIndexMode) { 594 path := filepath.Join("/tmp", "rosedb") 595 opts := DefaultOptions(path) 596 opts.IoType = ioType 597 opts.IndexMode = mode 598 db, err := Open(opts) 599 assert.Nil(t, err) 600 defer destroyDB(db) 601 602 listKey := []byte("my_list") 603 // prepare List 604 err = db.LPush(listKey, []byte("zero")) 605 assert.Nil(t, err) 606 err = db.LPush(listKey, []byte("negative one")) 607 assert.Nil(t, err) 608 err = db.RPush(listKey, []byte("one")) 609 assert.Nil(t, err) 610 err = db.RPush(listKey, []byte("two")) 611 assert.Nil(t, err) 612 err = db.RPush(listKey, []byte("three")) 613 assert.Nil(t, err) 614 615 type args struct { 616 key []byte 617 index int 618 } 619 620 tests := []struct { 621 name string 622 db *RoseDB 623 args args 624 expected uint32 625 wantErr bool 626 }{ 627 { 628 "0", db, args{key: listKey, index: 0}, uint32(initialListSeq - 1), false, 629 }, 630 { 631 "negative-1", db, args{key: listKey, index: -3}, uint32(initialListSeq + 1), false, 632 }, 633 { 634 "negative-2", db, args{key: listKey, index: -4}, uint32(initialListSeq), false, 635 }, 636 { 637 "positive-1", db, args{key: listKey, index: 1}, uint32(initialListSeq), false, 638 }, 639 { 640 "positive-2", db, args{key: listKey, index: 3}, uint32(initialListSeq + 2), false, 641 }, 642 } 643 644 for _, tt := range tests { 645 t.Run(tt.name, func(t *testing.T) { 646 idxTree := db.listIndex.trees[string(tt.args.key)] 647 start, end, err := db.listMeta(idxTree, tt.args.key) 648 assert.Nil(t, err) 649 actual, err := tt.db.listSequence(start, end, tt.args.index) 650 assert.Equal(t, tt.expected, actual, "expected is not the same with actual") 651 if (err != nil) != tt.wantErr { 652 t.Errorf("convertLogicalIndexToSeq() error = %v, wantErr %v", err, tt.wantErr) 653 } 654 }) 655 } 656 } 657 658 func TestRoseDB_LRange(t *testing.T) { 659 t.Run("fileio", func(t *testing.T) { 660 testRoseDBLRange(t, FileIO, KeyOnlyMemMode) 661 }) 662 663 t.Run("mmap", func(t *testing.T) { 664 testRoseDBLRange(t, MMap, KeyValueMemMode) 665 }) 666 } 667 668 func testRoseDBLRange(t *testing.T, ioType IOType, mode DataIndexMode) { 669 path := filepath.Join("/tmp", "rosedb") 670 opts := DefaultOptions(path) 671 opts.IoType = ioType 672 opts.IndexMode = mode 673 db, err := Open(opts) 674 assert.Nil(t, err) 675 defer destroyDB(db) 676 677 type args struct { 678 key []byte 679 start int 680 end int 681 } 682 683 listKey := []byte("my_list") 684 // prepare List 685 err = db.LPush(listKey, []byte("zero")) 686 assert.Nil(t, err) 687 err = db.LPush(listKey, []byte("negative one")) 688 assert.Nil(t, err) 689 err = db.RPush(listKey, []byte("one")) 690 assert.Nil(t, err) 691 err = db.RPush(listKey, []byte("two")) 692 assert.Nil(t, err) 693 err = db.RPush(listKey, []byte("three")) 694 assert.Nil(t, err) 695 696 tests := []struct { 697 name string 698 db *RoseDB 699 args args 700 wantValues [][]byte 701 wantErr bool 702 }{ 703 { 704 "nil-key", db, args{key: nil, start: 0, end: 3}, [][]byte(nil), true, 705 }, 706 { 707 "start==end", db, args{key: listKey, start: 1, end: 1}, [][]byte{[]byte("zero")}, false, 708 }, 709 { 710 "start==end==tailSeq", db, args{key: listKey, start: 4, end: 4}, [][]byte{[]byte("three")}, false, 711 }, 712 { 713 "end reset to endSeq", db, args{key: listKey, start: 0, end: 8}, 714 [][]byte{[]byte("negative one"), []byte("zero"), []byte("one"), []byte("two"), []byte("three")}, false, 715 }, 716 { 717 "start and end reset", db, args{key: listKey, start: -100, end: 100}, 718 [][]byte{[]byte("negative one"), []byte("zero"), []byte("one"), []byte("two"), []byte("three")}, false, 719 }, 720 { 721 "start negative end positive", db, args{key: listKey, start: -4, end: 2}, 722 [][]byte{[]byte("zero"), []byte("one")}, false, 723 }, 724 { 725 "start out of range", db, args{key: listKey, start: 5, end: 10}, [][]byte(nil), true, 726 }, 727 { 728 "end out of range", db, args{key: listKey, start: 1, end: -8}, [][]byte(nil), true, 729 }, 730 { 731 "end larger than start", db, args{key: listKey, start: -1, end: 1}, [][]byte(nil), true, 732 }, 733 } 734 735 for _, tt := range tests { 736 t.Run(tt.name, func(t *testing.T) { 737 actual, actualErr := tt.db.LRange(tt.args.key, tt.args.start, tt.args.end) 738 assert.Equal(t, tt.wantValues, actual, "actual is not the same with expected") 739 if (actualErr != nil) != tt.wantErr { 740 t.Errorf("LRange() error = %v, wantErr %v", actualErr, tt.wantErr) 741 } 742 }) 743 } 744 } 745 746 func TestRoseDB_LRem(t *testing.T) { 747 t.Run("fileio", func(t *testing.T) { 748 testRoseDBLRem(t, FileIO, KeyOnlyMemMode) 749 }) 750 t.Run("mmap", func(t *testing.T) { 751 testRoseDBLRem(t, MMap, KeyValueMemMode) 752 }) 753 } 754 755 func testRoseDBLRem(t *testing.T, ioType IOType, mode DataIndexMode) { 756 path := filepath.Join("/tmp", "rosedb") 757 opts := DefaultOptions(path) 758 opts.IoType = ioType 759 opts.IndexMode = mode 760 db, err := Open(opts) 761 assert.Nil(t, err) 762 defer destroyDB(db) 763 764 listKey := []byte("my_list") 765 v, err := db.LRem(listKey, 1, GetKey(1)) 766 assert.Equal(t, 0, v) 767 assert.Nil(t, err) 768 v, err = db.LRem(listKey, 0, GetKey(1)) 769 assert.Equal(t, 0, v) 770 assert.Nil(t, err) 771 v, err = db.LRem(listKey, -1, GetKey(1)) 772 assert.Equal(t, 0, v) 773 assert.Nil(t, err) 774 775 err = db.RPush(listKey, GetKey(1), GetKey(2), GetKey(1), GetKey(3), GetKey(3), GetKey(4)) 776 assert.Nil(t, err) 777 // list : 1 2 1 3 3 4 778 expected := [][]byte{GetKey(1), GetKey(2), GetKey(1), GetKey(3), GetKey(3), GetKey(4)} 779 v, err = db.LRem(listKey, 1, GetKey(5)) 780 assert.Equal(t, 0, v) 781 assert.Nil(t, err) 782 values, err := db.LRange(listKey, 0, -1) 783 assert.Equal(t, expected, values) 784 assert.Nil(t, err) 785 786 // list : 1 2 1 3 3 4 787 expected = [][]byte{GetKey(1), GetKey(2), GetKey(1), GetKey(3), GetKey(3), GetKey(4)} 788 v, err = db.LRem(listKey, 0, GetKey(5)) 789 assert.Equal(t, 0, v) 790 assert.Nil(t, err) 791 values, err = db.LRange(listKey, 0, -1) 792 assert.Equal(t, expected, values) 793 assert.Nil(t, err) 794 795 // list : 1 2 1 3 3 4 796 expected = [][]byte{GetKey(1), GetKey(2), GetKey(1), GetKey(3), GetKey(3), GetKey(4)} 797 v, err = db.LRem(listKey, -1, GetKey(5)) 798 assert.Equal(t, 0, v) 799 assert.Nil(t, err) 800 values, err = db.LRange(listKey, 0, -1) 801 assert.Equal(t, expected, values) 802 assert.Nil(t, err) 803 804 // list : 1 2 1 3 3 4 805 expected = [][]byte{GetKey(2), GetKey(3), GetKey(3), GetKey(4)} 806 v, err = db.LRem(listKey, 3, GetKey(1)) 807 assert.Equal(t, 2, v) 808 assert.Nil(t, err) 809 values, err = db.LRange(listKey, 0, -1) 810 assert.Equal(t, expected, values) 811 assert.Nil(t, err) 812 813 // list : 2 3 3 4 814 expected = [][]byte{GetKey(2), GetKey(4)} 815 v, err = db.LRem(listKey, -3, GetKey(3)) 816 assert.Equal(t, 2, v) 817 assert.Nil(t, err) 818 values, err = db.LRange(listKey, 0, -1) 819 assert.Equal(t, expected, values) 820 assert.Nil(t, err) 821 822 // list : 2 4 823 expected = [][]byte{GetKey(4)} 824 v, err = db.LRem(listKey, 0, GetKey(2)) 825 assert.Equal(t, 1, v) 826 assert.Nil(t, err) 827 values, err = db.LRange(listKey, 0, -1) 828 assert.Equal(t, expected, values) 829 assert.Nil(t, err) 830 831 // list : 4 832 err = db.RPush(listKey, GetKey(3), GetKey(2), GetKey(1)) 833 assert.Nil(t, err) 834 835 // list : 4 3 2 1 836 expected = [][]byte{GetKey(3), GetKey(2), GetKey(1)} 837 v, err = db.LRem(listKey, 1, GetKey(4)) 838 assert.Equal(t, 1, v) 839 assert.Nil(t, err) 840 values, err = db.LRange(listKey, 0, -1) 841 assert.Equal(t, expected, values) 842 assert.Nil(t, err) 843 844 // list : 3 2 1 845 expected = [][]byte{GetKey(3), GetKey(2)} 846 v, err = db.LRem(listKey, -1, GetKey(1)) 847 assert.Equal(t, 1, v) 848 assert.Nil(t, err) 849 values, err = db.LRange(listKey, 0, -1) 850 assert.Equal(t, expected, values) 851 assert.Nil(t, err) 852 853 // list : 3 2 854 expected = [][]byte{GetKey(3)} 855 v, err = db.LRem(listKey, 0, GetKey(2)) 856 assert.Equal(t, 1, v) 857 assert.Nil(t, err) 858 values, err = db.LRange(listKey, 0, -1) 859 assert.Equal(t, expected, values) 860 assert.Nil(t, err) 861 }