PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/nt/bptree/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
nt / bptree
Files
8 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/nt/bptree/v0
gno
0.9

Files (8)

  • README.mdmarkdown
  • gnomod.tomltoml
  • doc.gnogno
  • node.gnogno
  • tree.gnogno
  • example_test.gnogno
  • tree_test.gnogno
  • PLAN.mdmarkdown
  • tree_test.gnogno
    1package bptree23import (4	"math/rand"5	"sort"6	"testing"78

    Functions

    not supported for pure packages by the node (vm/qfuncs)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    "gno.land/p/nt/avl/v0"
    9)
    10
    11//----------------------------------------
    12// Basic operations
    13
    14func TestNewTree(t *testing.T) {
    15 tree := NewBPTree32()
    16 if tree.Size() != 0 {
    17 t.Error("Expected empty tree size to be 0")
    18 }
    19}
    20
    21func TestZeroValue(t *testing.T) {
    22 var tree BPTree
    23 if tree.Size() != 0 {
    24 t.Error("Expected zero-value tree size to be 0")
    25 }
    26 if tree.Has("x") {
    27 t.Error("Expected Has to return false on zero-value tree")
    28 }
    29 if v := tree.Get("x"); v != nil {
    30 t.Errorf("Expected Get to return nil on zero-value tree, got %v", v)
    31 }
    32 if _, ok := tree.Remove("x"); ok {
    33 t.Error("Expected Remove to return false on zero-value tree")
    34 }
    35
    36 // Set should work on zero-value tree.
    37 if updated := tree.Set("a", 1); updated {
    38 t.Error("Expected Set to return false for new key")
    39 }
    40 if tree.Size() != 1 {
    41 t.Errorf("Expected size 1, got %d", tree.Size())
    42 }
    43 if v := tree.Get("a"); v != 1 {
    44 t.Errorf("Expected Get(a) = 1, got %v", v)
    45 }
    46}
    47
    48func TestSetAndGet(t *testing.T) {
    49 tree := NewBPTreeN(4)
    50 tree.Set("key1", "value1")
    51 tree.Set("key2", "value2")
    52
    53 if tree.Size() != 2 {
    54 t.Errorf("Expected size 2, got %d", tree.Size())
    55 }
    56
    57 if v := tree.Get("key1"); v != "value1" {
    58 t.Errorf("Expected value1, got %v", v)
    59 }
    60
    61 if v := tree.Get("missing"); v != nil {
    62 t.Errorf("Expected Get to return nil for missing key, got %v", v)
    63 }
    64}
    65
    66func TestSetUpdate(t *testing.T) {
    67 tree := NewBPTreeN(4)
    68 if updated := tree.Set("k", "v1"); updated {
    69 t.Error("Expected false for new key")
    70 }
    71 if updated := tree.Set("k", "v2"); !updated {
    72 t.Error("Expected true for existing key")
    73 }
    74 if tree.Size() != 1 {
    75 t.Errorf("Expected size 1 after update, got %d", tree.Size())
    76 }
    77 if v := tree.Get("k"); v != "v2" {
    78 t.Errorf("Expected v2, got %v", v)
    79 }
    80}
    81
    82func TestHas(t *testing.T) {
    83 tree := NewBPTreeN(4)
    84 tree.Set("a", 1)
    85 if !tree.Has("a") {
    86 t.Error("Expected Has(a) = true")
    87 }
    88 if tree.Has("b") {
    89 t.Error("Expected Has(b) = false")
    90 }
    91}
    92
    93func TestRemove(t *testing.T) {
    94 tree := NewBPTreeN(4)
    95 tree.Set("a", 1)
    96 tree.Set("b", 2)
    97
    98 v, ok := tree.Remove("a")
    99 if !ok || v != 1 {
    100 t.Errorf("Expected (1, true), got (%v, %v)", v, ok)
    101 }
    102 if tree.Size() != 1 {
    103 t.Errorf("Expected size 1, got %d", tree.Size())
    104 }
    105 if tree.Has("a") {
    106 t.Error("Expected Has(a) = false after remove")
    107 }
    108
    109 v, ok = tree.Remove("missing")
    110 if ok || v != nil {
    111 t.Errorf("Expected (nil, false), got (%v, %v)", v, ok)
    112 }
    113}
    114
    115func TestRemoveLastKey(t *testing.T) {
    116 tree := NewBPTreeN(4)
    117 tree.Set("a", 1)
    118 tree.Remove("a")
    119 if tree.Size() != 0 {
    120 t.Errorf("Expected size 0, got %d", tree.Size())
    121 }
    122
    123 // Insert after removing everything.
    124 tree.Set("b", 2)
    125 if tree.Size() != 1 {
    126 t.Errorf("Expected size 1, got %d", tree.Size())
    127 }
    128 if v := tree.Get("b"); v != 2 {
    129 t.Errorf("Expected 2, got %v", v)
    130 }
    131}
    132
    133func TestNilValue(t *testing.T) {
    134 tree := NewBPTreeN(4)
    135 tree.Set("k", nil)
    136 // Has distinguishes a nil-valued entry from a missing key (Get returns
    137 // nil for both cases, by design).
    138 if !tree.Has("k") {
    139 t.Error("Expected Has(k) = true for nil-valued entry")
    140 }
    141 if v := tree.Get("k"); v != nil {
    142 t.Errorf("Expected nil value, got %v", v)
    143 }
    144 v, ok := tree.Remove("k")
    145 if !ok {
    146 t.Error("Expected remove to succeed")
    147 }
    148 if v != nil {
    149 t.Errorf("Expected nil removed value, got %v", v)
    150 }
    151}
    152
    153func TestEmptyStringKey(t *testing.T) {
    154 tree := NewBPTreeN(4)
    155 tree.Set("", "empty")
    156 tree.Set("a", "alpha")
    157 tree.Set("b", "beta")
    158
    159 if !tree.Has("") {
    160 t.Error("Expected Has('') = true for empty string key")
    161 }
    162 if v := tree.Get(""); v != "empty" {
    163 t.Errorf("Expected empty, got %v", v)
    164 }
    165 if tree.Size() != 3 {
    166 t.Errorf("Expected size 3, got %d", tree.Size())
    167 }
    168
    169 // Remove "" key.
    170 v, ok := tree.Remove("")
    171 if !ok || v != "empty" {
    172 t.Errorf("Remove('') = (%v, %v), want (empty, true)", v, ok)
    173 }
    174 if tree.Size() != 2 {
    175 t.Errorf("Expected size 2, got %d", tree.Size())
    176 }
    177 if tree.Has("") {
    178 t.Error("Expected Has('') = false after remove")
    179 }
    180}
    181
    182func TestGetMissingReturnsNil(t *testing.T) {
    183 tree := NewBPTreeN(4)
    184 tree.Set("a", 1)
    185 if v := tree.Get("missing"); v != nil {
    186 t.Errorf("Expected nil value for missing key, got %v", v)
    187 }
    188}
    189
    190func TestRemoveMissingReturnsNilFalse(t *testing.T) {
    191 tree := NewBPTreeN(4)
    192 tree.Set("a", 1)
    193 v, ok := tree.Remove("missing")
    194 if v != nil {
    195 t.Errorf("Expected nil value for missing remove, got %v", v)
    196 }
    197 if ok {
    198 t.Error("Expected false for missing remove")
    199 }
    200
    201 // Also on empty tree.
    202 var empty BPTree
    203 v, ok = empty.Remove("x")
    204 if v != nil || ok {
    205 t.Errorf("Remove on empty tree: got (%v, %v), want (nil, false)", v, ok)
    206 }
    207}
    208
    209func TestFanoutNeverResets(t *testing.T) {
    210 var tree BPTree
    211 tree.Set("a", 1)
    212 tree.Remove("a")
    213 // Tree is empty again, but fanout should still be 32.
    214 tree.Set("b", 2)
    215 if tree.Size() != 1 {
    216 t.Errorf("Expected size 1, got %d", tree.Size())
    217 }
    218 if tree.fanout != 32 {
    219 t.Errorf("Expected fanout 32 after re-insert, got %d", tree.fanout)
    220 }
    221}
    222
    223func TestSingleEntry(t *testing.T) {
    224 tree := NewBPTreeN(4)
    225 tree.Set("x", 42)
    226
    227 // Root should be a leaf for single entry.
    228 if tree.root == nil {
    229 t.Fatal("root is nil")
    230 }
    231 if !tree.root.isLeaf() {
    232 t.Error("root should be a leaf for single entry")
    233 }
    234 if tree.Size() != 1 {
    235 t.Errorf("Expected size 1, got %d", tree.Size())
    236 }
    237 k, v := tree.GetByIndex(0)
    238 if k != "x" || v != 42 {
    239 t.Errorf("GetByIndex(0) = (%v, %v), want (x, 42)", k, v)
    240 }
    241}
    242
    243//----------------------------------------
    244// GetByIndex
    245
    246func TestGetByIndex(t *testing.T) {
    247 tree := NewBPTreeN(4)
    248 tree.Set("c", 3)
    249 tree.Set("a", 1)
    250 tree.Set("b", 2)
    251
    252 k, v := tree.GetByIndex(0)
    253 if k != "a" || v != 1 {
    254 t.Errorf("GetByIndex(0) = (%v, %v), want (a, 1)", k, v)
    255 }
    256 k, v = tree.GetByIndex(1)
    257 if k != "b" || v != 2 {
    258 t.Errorf("GetByIndex(1) = (%v, %v), want (b, 2)", k, v)
    259 }
    260 k, v = tree.GetByIndex(2)
    261 if k != "c" || v != 3 {
    262 t.Errorf("GetByIndex(2) = (%v, %v), want (c, 3)", k, v)
    263 }
    264}
    265
    266func TestGetByIndexPanics(t *testing.T) {
    267 tree := NewBPTreeN(4)
    268 tree.Set("a", 1)
    269
    270 assertPanics(t, "empty tree", func() {
    271 var empty BPTree
    272 empty.GetByIndex(0)
    273 })
    274 assertPanics(t, "negative index", func() {
    275 tree.GetByIndex(-1)
    276 })
    277 assertPanics(t, "index == size", func() {
    278 tree.GetByIndex(1)
    279 })
    280}
    281
    282//----------------------------------------
    283// Iterate
    284
    285func TestIterate(t *testing.T) {
    286 tree := NewBPTreeN(4)
    287 tree.Set("a", 1)
    288 tree.Set("b", 2)
    289 tree.Set("c", 3)
    290 tree.Set("d", 4)
    291 tree.Set("e", 5)
    292
    293 // Full iteration.
    294 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    295 return tr.Iterate("", "", cb)
    296 })
    297 assertSliceEqual(t, got, []string{"a", "b", "c", "d", "e"})
    298
    299 // Bounded iteration [b, d) → b, c.
    300 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    301 return tr.Iterate("b", "d", cb)
    302 })
    303 assertSliceEqual(t, got, []string{"b", "c"})
    304
    305 // start == end → empty.
    306 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    307 return tr.Iterate("b", "b", cb)
    308 })
    309 assertSliceEqual(t, got, nil)
    310
    311 // start > end → empty.
    312 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    313 return tr.Iterate("z", "a", cb)
    314 })
    315 assertSliceEqual(t, got, nil)
    316
    317 // No lower bound.
    318 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    319 return tr.Iterate("", "c", cb)
    320 })
    321 assertSliceEqual(t, got, []string{"a", "b"})
    322
    323 // Empty tree.
    324 var empty BPTree
    325 stopped := empty.Iterate("", "", func(k string, v any) bool {
    326 t.Error("should not be called")
    327 return false
    328 })
    329 if stopped {
    330 t.Error("Expected false from Iterate on empty tree")
    331 }
    332}
    333
    334func TestIterateEarlyStop(t *testing.T) {
    335 tree := NewBPTreeN(4)
    336 tree.Set("a", 1)
    337 tree.Set("b", 2)
    338 tree.Set("c", 3)
    339
    340 count := 0
    341 stopped := tree.Iterate("", "", func(k string, v any) bool {
    342 count++
    343 return true
    344 })
    345 if !stopped {
    346 t.Error("Expected true from early-stopped Iterate")
    347 }
    348 if count != 1 {
    349 t.Errorf("Expected 1 callback, got %d", count)
    350 }
    351}
    352
    353func TestIterateAllEdgeCases(t *testing.T) {
    354 tree := NewBPTreeN(4)
    355 tree.Set("a", 1)
    356 tree.Set("b", 2)
    357 tree.Set("c", 3)
    358 tree.Set("d", 4)
    359 tree.Set("e", 5)
    360
    361 // Iterate("a", "a") → empty [a,a).
    362 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    363 return tr.Iterate("a", "a", cb)
    364 })
    365 assertSliceEqual(t, got, nil)
    366
    367 // Iterate("z", "a") → empty (start > end).
    368 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    369 return tr.Iterate("z", "a", cb)
    370 })
    371 assertSliceEqual(t, got, nil)
    372
    373 // Iterate("", "a") → nothing < "a".
    374 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    375 return tr.Iterate("", "a", cb)
    376 })
    377 assertSliceEqual(t, got, nil)
    378
    379 // Iterate("", "b") → just "a".
    380 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    381 return tr.Iterate("", "b", cb)
    382 })
    383 assertSliceEqual(t, got, []string{"a"})
    384
    385 // ReverseIterate("a", "a") → visits "a" (both inclusive).
    386 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    387 return tr.ReverseIterate("a", "a", cb)
    388 })
    389 assertSliceEqual(t, got, []string{"a"})
    390
    391 // ReverseIterate("z", "a") → empty (bounds don't swap).
    392 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    393 return tr.ReverseIterate("z", "a", cb)
    394 })
    395 assertSliceEqual(t, got, nil)
    396
    397 // ReverseIterate("c", "") → keys >= "c" descending.
    398 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    399 return tr.ReverseIterate("c", "", cb)
    400 })
    401 assertSliceEqual(t, got, []string{"e", "d", "c"})
    402
    403 // Iterate("", "a") on tree with key "" stored.
    404 tree2 := NewBPTreeN(4)
    405 tree2.Set("", "empty")
    406 tree2.Set("a", "alpha")
    407 tree2.Set("b", "beta")
    408 got = collectKeys(tree2, func(tr *BPTree, cb IterCbFn) bool {
    409 return tr.Iterate("", "a", cb)
    410 })
    411 assertSliceEqual(t, got, []string{""})
    412
    413 // Iterate("", "") visits all including "" key.
    414 got = collectKeys(tree2, func(tr *BPTree, cb IterCbFn) bool {
    415 return tr.Iterate("", "", cb)
    416 })
    417 assertSliceEqual(t, got, []string{"", "a", "b"})
    418}
    419
    420func TestAllIterationEmptyTree(t *testing.T) {
    421 var tree BPTree
    422 noop := func(k string, v any) bool {
    423 t.Error("should not be called")
    424 return false
    425 }
    426 if tree.Iterate("", "", noop) {
    427 t.Error("Iterate on empty tree should return false")
    428 }
    429 if tree.ReverseIterate("", "", noop) {
    430 t.Error("ReverseIterate on empty tree should return false")
    431 }
    432 if tree.IterateByOffset(0, 1, noop) {
    433 t.Error("IterateByOffset on empty tree should return false")
    434 }
    435 if tree.ReverseIterateByOffset(0, 1, noop) {
    436 t.Error("ReverseIterateByOffset on empty tree should return false")
    437 }
    438}
    439
    440func TestReverseIterate(t *testing.T) {
    441 tree := NewBPTreeN(4)
    442 tree.Set("a", 1)
    443 tree.Set("b", 2)
    444 tree.Set("c", 3)
    445 tree.Set("d", 4)
    446 tree.Set("e", 5)
    447
    448 // Full reverse.
    449 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    450 return tr.ReverseIterate("", "", cb)
    451 })
    452 assertSliceEqual(t, got, []string{"e", "d", "c", "b", "a"})
    453
    454 // Bounded [b, d] inclusive → d, c, b.
    455 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    456 return tr.ReverseIterate("b", "d", cb)
    457 })
    458 assertSliceEqual(t, got, []string{"d", "c", "b"})
    459
    460 // start == end → visits that one key.
    461 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    462 return tr.ReverseIterate("c", "c", cb)
    463 })
    464 assertSliceEqual(t, got, []string{"c"})
    465
    466 // start > end → empty.
    467 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    468 return tr.ReverseIterate("z", "a", cb)
    469 })
    470 assertSliceEqual(t, got, nil)
    471
    472 // No upper bound.
    473 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    474 return tr.ReverseIterate("c", "", cb)
    475 })
    476 assertSliceEqual(t, got, []string{"e", "d", "c"})
    477
    478 // end > max key → e, d, c, b, a.
    479 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    480 return tr.ReverseIterate("a", "z", cb)
    481 })
    482 assertSliceEqual(t, got, []string{"e", "d", "c", "b", "a"})
    483}
    484
    485func TestIterateByOffset(t *testing.T) {
    486 tree := NewBPTreeN(4)
    487 tree.Set("a", 1)
    488 tree.Set("b", 2)
    489 tree.Set("c", 3)
    490 tree.Set("d", 4)
    491 tree.Set("e", 5)
    492
    493 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    494 return tr.IterateByOffset(1, 3, cb)
    495 })
    496 assertSliceEqual(t, got, []string{"b", "c", "d"})
    497
    498 // offset=0, count=0 → nothing.
    499 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    500 return tr.IterateByOffset(0, 0, cb)
    501 })
    502 assertSliceEqual(t, got, nil)
    503
    504 // offset=size → nothing.
    505 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    506 return tr.IterateByOffset(5, 1, cb)
    507 })
    508 assertSliceEqual(t, got, nil)
    509
    510 // count exceeds remaining.
    511 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    512 return tr.IterateByOffset(3, 100, cb)
    513 })
    514 assertSliceEqual(t, got, []string{"d", "e"})
    515}
    516
    517func TestReverseIterateByOffset(t *testing.T) {
    518 tree := NewBPTreeN(4)
    519 tree.Set("a", 1)
    520 tree.Set("b", 2)
    521 tree.Set("c", 3)
    522 tree.Set("d", 4)
    523 tree.Set("e", 5)
    524
    525 // Full reverse.
    526 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    527 return tr.ReverseIterateByOffset(0, 5, cb)
    528 })
    529 assertSliceEqual(t, got, []string{"e", "d", "c", "b", "a"})
    530
    531 // offset=1, count=2 → [d, c].
    532 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    533 return tr.ReverseIterateByOffset(1, 2, cb)
    534 })
    535 assertSliceEqual(t, got, []string{"d", "c"})
    536
    537 // offset=4, count=1 → [a].
    538 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    539 return tr.ReverseIterateByOffset(4, 1, cb)
    540 })
    541 assertSliceEqual(t, got, []string{"a"})
    542
    543 // offset=4, count=10 → [a].
    544 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    545 return tr.ReverseIterateByOffset(4, 10, cb)
    546 })
    547 assertSliceEqual(t, got, []string{"a"})
    548
    549 // offset >= size → nothing.
    550 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    551 return tr.ReverseIterateByOffset(5, 1, cb)
    552 })
    553 assertSliceEqual(t, got, nil)
    554
    555 // count=0 → nothing.
    556 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    557 return tr.ReverseIterateByOffset(0, 0, cb)
    558 })
    559 assertSliceEqual(t, got, nil)
    560
    561 // negative offset
    562 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    563 return tr.ReverseIterateByOffset(-1, 3, cb)
    564 })
    565 assertSliceEqual(t, got, []string{"e", "d", "c"})
    566}
    567
    568func TestReverseIterateEarlyStop(t *testing.T) {
    569 tree := NewBPTreeN(4)
    570 tree.Set("a", 1)
    571 tree.Set("b", 2)
    572 tree.Set("c", 3)
    573 count := 0
    574 stopped := tree.ReverseIterate("", "", func(k string, v any) bool {
    575 count++
    576 return true
    577 })
    578 if !stopped {
    579 t.Error("Expected true from early-stopped ReverseIterate")
    580 }
    581 if count != 1 {
    582 t.Errorf("Expected 1 callback, got %d", count)
    583 }
    584}
    585
    586//----------------------------------------
    587// Splits and merges (use small fanout to trigger them)
    588
    589func TestSplitAndMerge(t *testing.T) {
    590 tree := NewBPTreeN(4)
    591
    592 // Insert enough keys to cause multiple splits.
    593 keys := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}
    594 for _, k := range keys {
    595 tree.Set(k, k)
    596 }
    597 if tree.Size() != len(keys) {
    598 t.Errorf("Expected size %d, got %d", len(keys), tree.Size())
    599 }
    600
    601 // Verify all keys present and in order.
    602 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    603 return tr.Iterate("", "", cb)
    604 })
    605 assertSliceEqual(t, got, keys)
    606
    607 // Verify GetByIndex works for all positions.
    608 for i, k := range keys {
    609 gk, gv := tree.GetByIndex(i)
    610 if gk != k || gv != k {
    611 t.Errorf("GetByIndex(%d) = (%v, %v), want (%v, %v)", i, gk, gv, k, k)
    612 }
    613 }
    614
    615 // Remove keys one by one and verify.
    616 for _, k := range keys {
    617 v, ok := tree.Remove(k)
    618 if !ok || v != k {
    619 t.Errorf("Remove(%v) = (%v, %v), want (%v, true)", k, v, ok, k)
    620 }
    621 }
    622 if tree.Size() != 0 {
    623 t.Errorf("Expected size 0 after removing all, got %d", tree.Size())
    624 }
    625}
    626
    627func TestRemoveFromMiddle(t *testing.T) {
    628 tree := NewBPTreeN(4)
    629 for _, k := range []string{"a", "b", "c", "d", "e", "f", "g", "h"} {
    630 tree.Set(k, k)
    631 }
    632
    633 // Remove from the middle to trigger redistributions and merges.
    634 tree.Remove("d")
    635 tree.Remove("e")
    636 tree.Remove("b")
    637 tree.Remove("g")
    638
    639 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    640 return tr.Iterate("", "", cb)
    641 })
    642 assertSliceEqual(t, got, []string{"a", "c", "f", "h"})
    643 if tree.Size() != 4 {
    644 t.Errorf("Expected size 4, got %d", tree.Size())
    645 }
    646}
    647
    648func TestSequentialInsertRemove(t *testing.T) {
    649 tree := NewBPTreeN(4)
    650
    651 // Sequential insert.
    652 n := 100
    653 for i := 0; i < n; i++ {
    654 k := intToKey(i)
    655 tree.Set(k, i)
    656 }
    657 if tree.Size() != n {
    658 t.Errorf("Expected size %d, got %d", n, tree.Size())
    659 }
    660
    661 // Verify sorted order.
    662 prev := ""
    663 tree.Iterate("", "", func(k string, v any) bool {
    664 if k <= prev && prev != "" {
    665 t.Errorf("Keys not in order: %q after %q", k, prev)
    666 }
    667 prev = k
    668 return false
    669 })
    670
    671 // Remove all in reverse order.
    672 for i := n - 1; i >= 0; i-- {
    673 k := intToKey(i)
    674 _, ok := tree.Remove(k)
    675 if !ok {
    676 t.Errorf("Remove(%v) failed", k)
    677 }
    678 }
    679 if tree.Size() != 0 {
    680 t.Errorf("Expected size 0, got %d", tree.Size())
    681 }
    682}
    683
    684func TestRandomInsertRemove(t *testing.T) {
    685 tree := NewBPTreeN(4)
    686
    687 // Insert in "random" order (shuffled via simple hash).
    688 keys := make([]string, 50)
    689 for i := range keys {
    690 keys[i] = intToKey((i*37 + 13) % 50)
    691 }
    692 for _, k := range keys {
    693 tree.Set(k, k)
    694 }
    695 if tree.Size() != 50 {
    696 t.Errorf("Expected size 50, got %d", tree.Size())
    697 }
    698
    699 // Remove half.
    700 for i := 0; i < 25; i++ {
    701 tree.Remove(keys[i])
    702 }
    703 if tree.Size() != 25 {
    704 t.Errorf("Expected size 25, got %d", tree.Size())
    705 }
    706
    707 // Verify remaining keys are in sorted order.
    708 prev := ""
    709 tree.Iterate("", "", func(k string, v any) bool {
    710 if k <= prev && prev != "" {
    711 t.Errorf("Keys not in order: %q after %q", k, prev)
    712 }
    713 prev = k
    714 return false
    715 })
    716}
    717
    718func TestDifferentFanouts(t *testing.T) {
    719 for _, fanout := range []int{4, 5, 8, 16, 32} {
    720 tree := NewBPTreeN(fanout)
    721 n := 100
    722 for i := 0; i < n; i++ {
    723 tree.Set(intToKey(i), i)
    724 }
    725 if tree.Size() != n {
    726 t.Errorf("fanout=%d: expected size %d, got %d", fanout, n, tree.Size())
    727 }
    728
    729 // Verify order.
    730 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    731 return tr.Iterate("", "", cb)
    732 })
    733 for i := 1; i < len(got); i++ {
    734 if got[i] <= got[i-1] {
    735 t.Errorf("fanout=%d: keys not in order at %d", fanout, i)
    736 break
    737 }
    738 }
    739
    740 // Remove all.
    741 for i := 0; i < n; i++ {
    742 tree.Remove(intToKey(i))
    743 }
    744 if tree.Size() != 0 {
    745 t.Errorf("fanout=%d: expected size 0 after remove all, got %d", fanout, tree.Size())
    746 }
    747 }
    748}
    749
    750func TestNegativeCount(t *testing.T) {
    751 tree := NewBPTreeN(4)
    752 tree.Set("a", 1)
    753
    754 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    755 return tr.IterateByOffset(0, -1, cb)
    756 })
    757 assertSliceEqual(t, got, nil)
    758
    759 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    760 return tr.ReverseIterateByOffset(0, -1, cb)
    761 })
    762 assertSliceEqual(t, got, nil)
    763}
    764
    765func TestRootCollapse(t *testing.T) {
    766 tree := NewBPTreeN(4)
    767 // Insert enough to create inner nodes.
    768 for _, k := range []string{"a", "b", "c", "d", "e"} {
    769 tree.Set(k, k)
    770 }
    771 if tree.root.isLeaf() {
    772 t.Error("Expected inner root after 5 inserts with fanout 4")
    773 }
    774
    775 // Remove enough to trigger merges and root collapse.
    776 tree.Remove("a")
    777 tree.Remove("b")
    778 tree.Remove("c")
    779 // With only "d" and "e" left, root should collapse to a leaf.
    780 if !tree.root.isLeaf() {
    781 t.Error("Expected leaf root after removing down to 2 entries")
    782 }
    783 if tree.Size() != 2 {
    784 t.Errorf("Expected size 2, got %d", tree.Size())
    785 }
    786 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    787 return tr.Iterate("", "", cb)
    788 })
    789 assertSliceEqual(t, got, []string{"d", "e"})
    790}
    791
    792func TestSeparatorKeyAfterLeftmostDeletion(t *testing.T) {
    793 tree := NewBPTreeN(4)
    794 // Insert keys to create a split.
    795 for _, k := range []string{"a", "b", "c", "d", "e", "f", "g", "h"} {
    796 tree.Set(k, k)
    797 }
    798 // Remove leftmost key "a" — should trigger separator update.
    799 tree.Remove("a")
    800
    801 // Verify all remaining keys are accessible.
    802 for _, k := range []string{"b", "c", "d", "e", "f", "g", "h"} {
    803 if !tree.Has(k) {
    804 t.Errorf("Expected Has(%s) = true after removing 'a'", k)
    805 }
    806 }
    807 if tree.Has("a") {
    808 t.Error("Expected Has(a) = false")
    809 }
    810
    811 // Verify sorted order.
    812 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    813 return tr.Iterate("", "", cb)
    814 })
    815 assertSliceEqual(t, got, []string{"b", "c", "d", "e", "f", "g", "h"})
    816
    817 // Verify GetByIndex still works.
    818 k, _ := tree.GetByIndex(0)
    819 if k != "b" {
    820 t.Errorf("GetByIndex(0) = %v, want b", k)
    821 }
    822}
    823
    824func TestNinetyTenSplit(t *testing.T) {
    825 // Sequential inserts should trigger 90/10 splits, keeping left leaves ~97% full.
    826 tree := NewBPTreeN(4)
    827 for _, k := range []string{"a", "b", "c", "d", "e"} {
    828 tree.Set(k, k)
    829 }
    830 // After inserting a,b,c,d (leaf full), then e (append → 90/10 split):
    831 // Left should have fanout-1=3 entries [a,b,c], right should have 2 entries [d,e].
    832 if !tree.root.isLeaf() == true {
    833 // Root should be an inner node after split.
    834 }
    835 inner := tree.root.(*innerNode)
    836 left := inner.children[0].(*leafNode)
    837 right := inner.children[1].(*leafNode)
    838 if len(left.keys) != 3 {
    839 t.Errorf("90/10 split: left leaf has %d entries, want 3", len(left.keys))
    840 }
    841 if len(right.keys) != 2 {
    842 t.Errorf("90/10 split: right leaf has %d entries, want 2", len(right.keys))
    843 }
    844
    845 // Verify all keys accessible.
    846 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    847 return tr.Iterate("", "", cb)
    848 })
    849 assertSliceEqual(t, got, []string{"a", "b", "c", "d", "e"})
    850}
    851
    852func TestNinetyTenSplitLargeFanout(t *testing.T) {
    853 // With fanout=32, sequential inserts should produce high fill factor.
    854 tree := NewBPTree32()
    855 n := 200
    856 for i := 0; i < n; i++ {
    857 tree.Set(intToKey(i), i)
    858 }
    859 if tree.Size() != n {
    860 t.Errorf("Expected size %d, got %d", n, tree.Size())
    861 }
    862
    863 // Verify all keys in order.
    864 prev := ""
    865 count := 0
    866 tree.Iterate("", "", func(k string, v any) bool {
    867 if k <= prev && prev != "" {
    868 t.Errorf("Keys not in order: %q after %q", k, prev)
    869 }
    870 prev = k
    871 count++
    872 return false
    873 })
    874 if count != n {
    875 t.Errorf("Iterate visited %d entries, want %d", count, n)
    876 }
    877
    878 // Remove all and verify.
    879 for i := 0; i < n; i++ {
    880 _, ok := tree.Remove(intToKey(i))
    881 if !ok {
    882 t.Errorf("Remove(%s) failed", intToKey(i))
    883 }
    884 }
    885 if tree.Size() != 0 {
    886 t.Errorf("Expected size 0, got %d", tree.Size())
    887 }
    888}
    889
    890func TestMixedSplitTypes(t *testing.T) {
    891 // Sequential inserts trigger 90/10, then a middle insert triggers 50/50.
    892 tree := NewBPTreeN(4)
    893 // Sequential: triggers 90/10 split.
    894 for _, k := range []string{"b", "c", "d", "e"} {
    895 tree.Set(k, k)
    896 }
    897 // Insert "a" at the beginning of the left leaf — not an append, so if
    898 // that leaf overflows it will use 50/50.
    899 tree.Set("a", "a")
    900
    901 // Verify all keys present and sorted.
    902 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    903 return tr.Iterate("", "", cb)
    904 })
    905 assertSliceEqual(t, got, []string{"a", "b", "c", "d", "e"})
    906}
    907
    908func TestSizeCacheConsistency(t *testing.T) {
    909 tree := NewBPTreeN(4)
    910 keys := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}
    911
    912 // Check after each insert.
    913 for _, k := range keys {
    914 tree.Set(k, k)
    915 verifySizeCache(t, tree.root)
    916 }
    917
    918 // Check after each remove.
    919 for _, k := range keys {
    920 tree.Remove(k)
    921 verifySizeCache(t, tree.root)
    922 }
    923
    924 // Also check with large fanout.
    925 tree2 := NewBPTree32()
    926 for i := 0; i < 100; i++ {
    927 tree2.Set(intToKey(i), i)
    928 }
    929 verifySizeCache(t, tree2.root)
    930 for i := 0; i < 100; i++ {
    931 tree2.Remove(intToKey(i))
    932 verifySizeCache(t, tree2.root)
    933 }
    934}
    935
    936func verifySizeCache(t *testing.T, n node) {
    937 t.Helper()
    938 if n == nil || n.isLeaf() {
    939 return
    940 }
    941 inner := n.(*innerNode)
    942 // Verify each sizes[i] matches the actual child subtree size.
    943 for i, child := range inner.children {
    944 actual := child.nodeSize()
    945 if inner.sizes[i] != actual {
    946 t.Errorf("innerNode.sizes[%d]=%d but child.nodeSize()=%d", i, inner.sizes[i], actual)
    947 }
    948 verifySizeCache(t, child)
    949 }
    950}
    951
    952func TestValueIndirection(t *testing.T) {
    953 tree := NewBPTreeN(4)
    954
    955 // Nil value through *any.
    956 tree.Set("nil", nil)
    957 if !tree.Has("nil") {
    958 t.Error("Expected key 'nil' to exist")
    959 }
    960 if v := tree.Get("nil"); v != nil {
    961 t.Errorf("Expected nil value, got %v", v)
    962 }
    963
    964 // Various types.
    965 tree.Set("int", 42)
    966 tree.Set("str", "hello")
    967 tree.Set("slice", []byte{1, 2, 3})
    968
    969 if v := tree.Get("int"); v != 42 {
    970 t.Errorf("Expected 42, got %v", v)
    971 }
    972 if v := tree.Get("str"); v != "hello" {
    973 t.Errorf("Expected hello, got %v", v)
    974 }
    975 if v := tree.Get("slice"); len(v.([]byte)) != 3 {
    976 t.Errorf("Expected 3-byte slice, got %v", v)
    977 }
    978
    979 // Update value in place (should reuse the *any pointer).
    980 tree.Set("int", 99)
    981 if v := tree.Get("int"); v != 99 {
    982 t.Errorf("Expected 99 after update, got %v", v)
    983 }
    984
    985 // Remove nil value.
    986 v, ok := tree.Remove("nil")
    987 if !ok || v != nil {
    988 t.Errorf("Remove nil: got (%v, %v), want (nil, true)", v, ok)
    989 }
    990
    991 // Remove typed value.
    992 v, ok = tree.Remove("int")
    993 if !ok || v != 99 {
    994 t.Errorf("Remove int: got (%v, %v), want (99, true)", v, ok)
    995 }
    996
    997 // Large string values — each stored as separate *any object.
    998 bigVal := make([]byte, 10000)
    999 for i := range bigVal {
    1000 bigVal[i] = byte(i % 256)
    1001 }
    1002 for i := 0; i < 10; i++ {
    1003 tree.Set(intToKey(i), string(bigVal))
    1004 }
    1005 if tree.Size() != 12 { // 10 new + "str" + "slice" remaining
    1006 t.Errorf("Expected size 12, got %d", tree.Size())
    1007 }
    1008
    1009 // Verify large values round-trip correctly.
    1010 for i := 0; i < 10; i++ {
    1011 v := tree.Get(intToKey(i))
    1012 if v == nil {
    1013 t.Errorf("Missing key %s", intToKey(i))
    1014 continue
    1015 }
    1016 s := v.(string)
    1017 if len(s) != 10000 {
    1018 t.Errorf("Key %s: expected 10000-byte string, got %d", intToKey(i), len(s))
    1019 }
    1020 }
    1021
    1022 // Iteration with mixed values.
    1023 count := 0
    1024 tree.Iterate("", "", func(k string, v any) bool {
    1025 count++
    1026 return false
    1027 })
    1028 if count != 12 {
    1029 t.Errorf("Iterate counted %d, want 12", count)
    1030 }
    1031
    1032 // Remove all and verify clean.
    1033 for i := 0; i < 10; i++ {
    1034 tree.Remove(intToKey(i))
    1035 }
    1036 tree.Remove("str")
    1037 tree.Remove("slice")
    1038 if tree.Size() != 0 {
    1039 t.Errorf("Expected empty tree, got size %d", tree.Size())
    1040 }
    1041}
    1042
    1043func TestFanoutPanics(t *testing.T) {
    1044 assertPanics(t, "fanout 3", func() {
    1045 NewBPTreeN(3)
    1046 })
    1047 assertPanics(t, "fanout 0", func() {
    1048 NewBPTreeN(0)
    1049 })
    1050}
    1051
    1052//----------------------------------------
    1053// Ported from avl/v0 node_test.gno
    1054
    1055func TestHasTableDriven(t *testing.T) {
    1056 tests := []struct {
    1057 name string
    1058 input []string
    1059 hasKey string
    1060 expected bool
    1061 }{
    1062 {"has key in non-empty tree", []string{"C", "A", "B", "E", "D"}, "B", true},
    1063 {"does not have key in non-empty tree", []string{"C", "A", "B", "E", "D"}, "F", false},
    1064 {"has key in single-node tree", []string{"A"}, "A", true},
    1065 {"does not have key in single-node tree", []string{"A"}, "B", false},
    1066 {"does not have key in empty tree", []string{}, "A", false},
    1067 }
    1068 for _, tt := range tests {
    1069 t.Run(tt.name, func(t *testing.T) {
    1070 tree := NewBPTreeN(4)
    1071 for _, key := range tt.input {
    1072 tree.Set(key, nil)
    1073 }
    1074 result := tree.Has(tt.hasKey)
    1075 if result != tt.expected {
    1076 t.Errorf("Expected %v, got %v", tt.expected, result)
    1077 }
    1078 })
    1079 }
    1080}
    1081
    1082func TestGetByIndexTableDriven(t *testing.T) {
    1083 tests := []struct {
    1084 name string
    1085 input []string
    1086 idx int
    1087 expectKey string
    1088 expectPanic bool
    1089 }{
    1090 {"get by valid index", []string{"C", "A", "B", "E", "D"}, 2, "C", false},
    1091 {"get by valid index (smallest)", []string{"C", "A", "B", "E", "D"}, 0, "A", false},
    1092 {"get by valid index (largest)", []string{"C", "A", "B", "E", "D"}, 4, "E", false},
    1093 {"get by invalid index (negative)", []string{"C", "A", "B", "E", "D"}, -1, "", true},
    1094 {"get by invalid index (out of range)", []string{"C", "A", "B", "E", "D"}, 5, "", true},
    1095 }
    1096 for _, tt := range tests {
    1097 t.Run(tt.name, func(t *testing.T) {
    1098 tree := NewBPTreeN(4)
    1099 for _, key := range tt.input {
    1100 tree.Set(key, nil)
    1101 }
    1102 if tt.expectPanic {
    1103 defer func() {
    1104 if r := recover(); r == nil {
    1105 t.Errorf("Expected a panic but didn't get one")
    1106 }
    1107 }()
    1108 }
    1109 key, _ := tree.GetByIndex(tt.idx)
    1110 if !tt.expectPanic && key != tt.expectKey {
    1111 t.Errorf("Expected key %s, got %s", tt.expectKey, key)
    1112 }
    1113 })
    1114 }
    1115}
    1116
    1117func TestRemoveTableDriven(t *testing.T) {
    1118 tests := []struct {
    1119 name string
    1120 input []string
    1121 removeKey string
    1122 expected []string
    1123 }{
    1124 {"remove from middle", []string{"C", "A", "B", "D"}, "B", []string{"A", "C", "D"}},
    1125 {"remove first key", []string{"C", "A", "B", "D"}, "A", []string{"B", "C", "D"}},
    1126 {"remove last key", []string{"C", "A", "B", "E", "D"}, "E", []string{"A", "B", "C", "D"}},
    1127 {"remove root-equivalent key", []string{"C", "A", "B", "E", "D"}, "C", []string{"A", "B", "D", "E"}},
    1128 {"remove non-existent key", []string{"C", "A", "B", "E", "D"}, "F", []string{"A", "B", "C", "D", "E"}},
    1129 }
    1130 for _, tt := range tests {
    1131 t.Run(tt.name, func(t *testing.T) {
    1132 tree := NewBPTreeN(4)
    1133 for _, key := range tt.input {
    1134 tree.Set(key, nil)
    1135 }
    1136 tree.Remove(tt.removeKey)
    1137 var result []string
    1138 tree.Iterate("", "", func(key string, value any) bool {
    1139 result = append(result, key)
    1140 return false
    1141 })
    1142 if len(result) == 0 {
    1143 result = []string{}
    1144 }
    1145 assertSliceEqual(t, result, tt.expected)
    1146 })
    1147 }
    1148}
    1149
    1150func TestTraverse(t *testing.T) {
    1151 tests := []struct {
    1152 name string
    1153 input []string
    1154 expected []string
    1155 }{
    1156 {"empty tree", []string{}, []string{}},
    1157 {"single node tree", []string{"A"}, []string{"A"}},
    1158 {"small tree", []string{"C", "A", "B", "E", "D"}, []string{"A", "B", "C", "D", "E"}},
    1159 {"large tree", []string{"H", "D", "L", "B", "F", "J", "N", "A", "C", "E", "G", "I", "K", "M", "O"},
    1160 []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"}},
    1161 }
    1162 for _, tt := range tests {
    1163 t.Run(tt.name, func(t *testing.T) {
    1164 tree := NewBPTreeN(4)
    1165 for _, key := range tt.input {
    1166 tree.Set(key, nil)
    1167 }
    1168
    1169 t.Run("iterate", func(t *testing.T) {
    1170 var result []string
    1171 tree.Iterate("", "", func(key string, value any) bool {
    1172 result = append(result, key)
    1173 return false
    1174 })
    1175 if len(result) == 0 {
    1176 result = []string{}
    1177 }
    1178 assertSliceEqual(t, result, tt.expected)
    1179 })
    1180
    1181 t.Run("ReverseIterate", func(t *testing.T) {
    1182 var result []string
    1183 tree.ReverseIterate("", "", func(key string, value any) bool {
    1184 result = append(result, key)
    1185 return false
    1186 })
    1187 expected := make([]string, len(tt.expected))
    1188 copy(expected, tt.expected)
    1189 for i, j := 0, len(expected)-1; i < j; i, j = i+1, j-1 {
    1190 expected[i], expected[j] = expected[j], expected[i]
    1191 }
    1192 if len(result) == 0 {
    1193 result = []string{}
    1194 }
    1195 assertSliceEqual(t, result, expected)
    1196 })
    1197
    1198 t.Run("TraverseInRange", func(t *testing.T) {
    1199 var result []string
    1200 start, end := "C", "M"
    1201 tree.Iterate(start, end, func(key string, value any) bool {
    1202 result = append(result, key)
    1203 return false
    1204 })
    1205 expected := make([]string, 0)
    1206 for _, key := range tt.expected {
    1207 if key >= start && key < end {
    1208 expected = append(expected, key)
    1209 }
    1210 }
    1211 if len(result) == 0 {
    1212 result = []string{}
    1213 }
    1214 assertSliceEqual(t, result, expected)
    1215 })
    1216
    1217 t.Run("early termination", func(t *testing.T) {
    1218 if len(tt.input) == 0 {
    1219 return
    1220 }
    1221 var result []string
    1222 var count int
    1223 tree.Iterate("", "", func(key string, value any) bool {
    1224 count++
    1225 result = append(result, key)
    1226 return true
    1227 })
    1228 if count != 1 {
    1229 t.Errorf("Expected callback to be called exactly once, got %d calls", count)
    1230 }
    1231 if len(result) != 1 {
    1232 t.Errorf("Expected exactly one result, got %d items", len(result))
    1233 }
    1234 if len(result) > 0 && result[0] != tt.expected[0] {
    1235 t.Errorf("Expected first item to be %v, got %v", tt.expected[0], result[0])
    1236 }
    1237 })
    1238 })
    1239 }
    1240}
    1241
    1242func TestTraverseByOffset(t *testing.T) {
    1243 sl := []string{"Alfa", "Alfred", "Alpha", "Alphabet", "Beta", "Beth", "Book", "Browser"}
    1244
    1245 // Insert in reverse order to ensure ordering is independent of insertion order.
    1246 reversed := make([]string, len(sl))
    1247 copy(reversed, sl)
    1248 for i, j := 0, len(reversed)-1; i < j; i, j = i+1, j-1 {
    1249 reversed[i], reversed[j] = reversed[j], reversed[i]
    1250 }
    1251
    1252 t.Run("ascending", func(t *testing.T) {
    1253 tree := NewBPTreeN(4)
    1254 for _, v := range reversed {
    1255 tree.Set(v, nil)
    1256 }
    1257
    1258 // Single-element offset traversal.
    1259 var result []string
    1260 for i := 0; i < len(sl); i++ {
    1261 tree.IterateByOffset(i, 1, func(key string, value any) bool {
    1262 result = append(result, key)
    1263 return false
    1264 })
    1265 }
    1266 assertSliceEqual(t, result, sl)
    1267
    1268 // Sliding window.
    1269 for l := 2; l <= len(sl); l++ {
    1270 for i := 0; i <= len(sl); i++ {
    1271 max := i + l
    1272 if max > len(sl) {
    1273 max = len(sl)
    1274 }
    1275 exp := sl[i:max]
    1276 var actual []string
    1277 tree.IterateByOffset(i, l, func(key string, value any) bool {
    1278 actual = append(actual, key)
    1279 return false
    1280 })
    1281 if len(actual) == 0 {
    1282 actual = []string{}
    1283 }
    1284 assertSliceEqual(t, actual, exp)
    1285 }
    1286 }
    1287 })
    1288
    1289 t.Run("descending", func(t *testing.T) {
    1290 tree := NewBPTreeN(4)
    1291 for _, v := range reversed {
    1292 tree.Set(v, nil)
    1293 }
    1294
    1295 // The descending order.
    1296 desc := make([]string, len(sl))
    1297 copy(desc, sl)
    1298 for i, j := 0, len(desc)-1; i < j; i, j = i+1, j-1 {
    1299 desc[i], desc[j] = desc[j], desc[i]
    1300 }
    1301
    1302 // Single-element offset traversal in reverse.
    1303 var result []string
    1304 for i := 0; i < len(desc); i++ {
    1305 tree.ReverseIterateByOffset(i, 1, func(key string, value any) bool {
    1306 result = append(result, key)
    1307 return false
    1308 })
    1309 }
    1310 assertSliceEqual(t, result, desc)
    1311
    1312 // Sliding window in descending.
    1313 for l := 2; l <= len(desc); l++ {
    1314 for i := 0; i <= len(desc); i++ {
    1315 max := i + l
    1316 if max > len(desc) {
    1317 max = len(desc)
    1318 }
    1319 exp := desc[i:max]
    1320 var actual []string
    1321 tree.ReverseIterateByOffset(i, l, func(key string, value any) bool {
    1322 actual = append(actual, key)
    1323 return false
    1324 })
    1325 if len(actual) == 0 {
    1326 actual = []string{}
    1327 }
    1328 assertSliceEqual(t, actual, exp)
    1329 }
    1330 }
    1331 })
    1332}
    1333
    1334func TestBSTProperty(t *testing.T) {
    1335 tree := NewBPTreeN(4)
    1336 keys := []string{"D", "B", "F", "A", "C", "E", "G"}
    1337 for _, key := range keys {
    1338 tree.Set(key, nil)
    1339 }
    1340
    1341 var result []string
    1342 tree.Iterate("", "", func(key string, value any) bool {
    1343 result = append(result, key)
    1344 return false
    1345 })
    1346
    1347 for i := 1; i < len(result); i++ {
    1348 if result[i] < result[i-1] {
    1349 t.Errorf("Sorted property violated: %s < %s (index %d)",
    1350 result[i], result[i-1], i)
    1351 }
    1352 }
    1353}
    1354
    1355func TestRemoveFromEmptyTree(t *testing.T) {
    1356 var tree BPTree
    1357 val, removed := tree.Remove("NonExistent")
    1358 if val != nil || removed {
    1359 t.Errorf("Expected no value and removed=false when removing from empty tree")
    1360 }
    1361}
    1362
    1363// Ported from avl tree_test.gno
    1364
    1365func TestPortedTreeSize(t *testing.T) {
    1366 tree := NewBPTree32()
    1367 if tree.Size() != 0 {
    1368 t.Error("Expected empty tree size to be 0")
    1369 }
    1370 tree.Set("key1", "value1")
    1371 tree.Set("key2", "value2")
    1372 if tree.Size() != 2 {
    1373 t.Error("Expected tree size to be 2")
    1374 }
    1375}
    1376
    1377func TestPortedTreeHas(t *testing.T) {
    1378 tree := NewBPTree32()
    1379 tree.Set("key1", "value1")
    1380 if !tree.Has("key1") {
    1381 t.Error("Expected tree to have key1")
    1382 }
    1383 if tree.Has("key2") {
    1384 t.Error("Expected tree to not have key2")
    1385 }
    1386}
    1387
    1388func TestPortedTreeGet(t *testing.T) {
    1389 tree := NewBPTree32()
    1390 tree.Set("key1", "value1")
    1391 if value := tree.Get("key1"); value != "value1" {
    1392 t.Error("Expected Get to return value1")
    1393 }
    1394 if value := tree.Get("key2"); value != nil {
    1395 t.Error("Expected Get to return nil for non-existent key")
    1396 }
    1397}
    1398
    1399func TestPortedTreeGetByIndex(t *testing.T) {
    1400 tree := NewBPTree32()
    1401 tree.Set("key1", "value1")
    1402 tree.Set("key2", "value2")
    1403 key, value := tree.GetByIndex(0)
    1404 if key != "key1" || value != "value1" {
    1405 t.Error("Expected GetByIndex(0) to return key1 and value1")
    1406 }
    1407 key, value = tree.GetByIndex(1)
    1408 if key != "key2" || value != "value2" {
    1409 t.Error("Expected GetByIndex(1) to return key2 and value2")
    1410 }
    1411 defer func() {
    1412 if r := recover(); r == nil {
    1413 t.Error("Expected GetByIndex to panic for out-of-range index")
    1414 }
    1415 }()
    1416 tree.GetByIndex(2)
    1417}
    1418
    1419func TestPortedTreeRemove(t *testing.T) {
    1420 tree := NewBPTree32()
    1421 tree.Set("key1", "value1")
    1422 value, removed := tree.Remove("key1")
    1423 if !removed || value != "value1" || tree.Size() != 0 {
    1424 t.Error("Expected Remove to remove key-value pair")
    1425 }
    1426 _, removed = tree.Remove("key2")
    1427 if removed {
    1428 t.Error("Expected Remove to return false for non-existent key")
    1429 }
    1430}
    1431
    1432func TestPortedTreeIterate(t *testing.T) {
    1433 tree := NewBPTree32()
    1434 tree.Set("key1", "value1")
    1435 tree.Set("key2", "value2")
    1436 tree.Set("key3", "value3")
    1437 var keys []string
    1438 tree.Iterate("", "", func(key string, value any) bool {
    1439 keys = append(keys, key)
    1440 return false
    1441 })
    1442 assertSliceEqual(t, keys, []string{"key1", "key2", "key3"})
    1443}
    1444
    1445func TestPortedTreeReverseIterate(t *testing.T) {
    1446 tree := NewBPTree32()
    1447 tree.Set("key1", "value1")
    1448 tree.Set("key2", "value2")
    1449 tree.Set("key3", "value3")
    1450 var keys []string
    1451 tree.ReverseIterate("", "", func(key string, value any) bool {
    1452 keys = append(keys, key)
    1453 return false
    1454 })
    1455 assertSliceEqual(t, keys, []string{"key3", "key2", "key1"})
    1456}
    1457
    1458func TestPortedTreeIterateByOffset(t *testing.T) {
    1459 tree := NewBPTree32()
    1460 tree.Set("key1", "value1")
    1461 tree.Set("key2", "value2")
    1462 tree.Set("key3", "value3")
    1463 var keys []string
    1464 tree.IterateByOffset(1, 2, func(key string, value any) bool {
    1465 keys = append(keys, key)
    1466 return false
    1467 })
    1468 assertSliceEqual(t, keys, []string{"key2", "key3"})
    1469}
    1470
    1471func TestPortedTreeReverseIterateByOffset(t *testing.T) {
    1472 tree := NewBPTree32()
    1473 tree.Set("key1", "value1")
    1474 tree.Set("key2", "value2")
    1475 tree.Set("key3", "value3")
    1476 var keys []string
    1477 tree.ReverseIterateByOffset(1, 2, func(key string, value any) bool {
    1478 keys = append(keys, key)
    1479 return false
    1480 })
    1481 assertSliceEqual(t, keys, []string{"key2", "key1"})
    1482}
    1483
    1484func TestPortedReverseIterateByOffsetVaried(t *testing.T) {
    1485 tree := NewBPTree32()
    1486 tree.Set("a", 1)
    1487 tree.Set("b", 2)
    1488 tree.Set("c", 3)
    1489 tree.Set("d", 4)
    1490 tree.Set("e", 5)
    1491
    1492 cases := []struct {
    1493 offset int
    1494 limit int
    1495 want []string
    1496 }{
    1497 {0, 5, []string{"e", "d", "c", "b", "a"}},
    1498 {0, 1, []string{"e"}},
    1499 {0, 3, []string{"e", "d", "c"}},
    1500 {1, 2, []string{"d", "c"}},
    1501 {2, 2, []string{"c", "b"}},
    1502 {3, 5, []string{"b", "a"}},
    1503 {4, 1, []string{"a"}},
    1504 {4, 10, []string{"a"}},
    1505 {5, 1, nil},
    1506 {0, 0, nil},
    1507 {10, 1, nil},
    1508 }
    1509
    1510 for _, tc := range cases {
    1511 var got []string
    1512 tree.ReverseIterateByOffset(tc.offset, tc.limit, func(key string, value any) bool {
    1513 got = append(got, key)
    1514 return false
    1515 })
    1516 if !slicesEqual(got, tc.want) {
    1517 t.Errorf("ReverseIterateByOffset(%d, %d): got %v, want %v",
    1518 tc.offset, tc.limit, got, tc.want)
    1519 }
    1520 }
    1521
    1522 // Early termination.
    1523 var got []string
    1524 tree.ReverseIterateByOffset(1, 5, func(key string, value any) bool {
    1525 got = append(got, key)
    1526 return len(got) >= 2
    1527 })
    1528 assertSliceEqual(t, got, []string{"d", "c"})
    1529}
    1530
    1531func TestPortedBalanceAfterRemoval(t *testing.T) {
    1532 // This tests the behavioral equivalence: after various insert/remove
    1533 // patterns, the tree maintains correct sorted order and all keys are
    1534 // accessible. (AVL tests checked balance factors; we check correctness.)
    1535 tests := []struct {
    1536 name string
    1537 insertKeys []string
    1538 removeKey string
    1539 }{
    1540 {"remove right node", []string{"B", "A", "D", "C", "E"}, "E"},
    1541 {"remove left node", []string{"D", "B", "E", "A", "C"}, "A"},
    1542 {"remove after complex insert", []string{"C", "B", "E", "A", "D", "F"}, "F"},
    1543 {"descending insert, remove middle", []string{"E", "D", "C", "B", "A"}, "C"},
    1544 {"ascending insert, remove middle", []string{"A", "B", "C", "D", "E"}, "C"},
    1545 {"duplicate insert, remove key", []string{"C", "B", "C", "A", "D"}, "C"},
    1546 {"complex case", []string{"H", "B", "A", "C", "E", "D", "F", "G"}, "B"},
    1547 }
    1548 for _, tt := range tests {
    1549 t.Run(tt.name, func(t *testing.T) {
    1550 tree := NewBPTreeN(4)
    1551 for _, key := range tt.insertKeys {
    1552 tree.Set(key, nil)
    1553 }
    1554 tree.Remove(tt.removeKey)
    1555
    1556 // Verify sorted order.
    1557 var result []string
    1558 tree.Iterate("", "", func(key string, value any) bool {
    1559 result = append(result, key)
    1560 return false
    1561 })
    1562 for i := 1; i < len(result); i++ {
    1563 if result[i] <= result[i-1] {
    1564 t.Errorf("Sorted property violated: %s <= %s", result[i], result[i-1])
    1565 }
    1566 }
    1567
    1568 // Verify all expected keys present.
    1569 for _, key := range tt.insertKeys {
    1570 if key == tt.removeKey {
    1571 if tree.Has(key) {
    1572 // Only check if the key was unique (not duplicated).
    1573 // With duplicates, Set overwrites, so there's only one copy.
    1574 continue
    1575 }
    1576 }
    1577 }
    1578 })
    1579 }
    1580}
    1581
    1582//----------------------------------------
    1583// Structural invariant verification
    1584
    1585// verifyInvariants checks all B+ tree structural invariants.
    1586func verifyInvariants(t *testing.T, tree *BPTree) {
    1587 t.Helper()
    1588 if tree.root == nil {
    1589 if tree.size != 0 {
    1590 t.Errorf("nil root but size=%d", tree.size)
    1591 }
    1592 return
    1593 }
    1594
    1595 // Check leaf depth uniformity.
    1596 depth := leafDepth(tree.root, 0)
    1597 if depth == -1 {
    1598 t.Error("leaves are at different depths")
    1599 }
    1600
    1601 // Check separator keys, child count bounds, sizes, ref-count.
    1602 seen := make(map[node]bool)
    1603 verifyNode(t, tree.root, tree.fanout, true, seen)
    1604
    1605 // Check tree.size matches actual leaf count.
    1606 actual := tree.root.nodeSize()
    1607 if tree.size != actual {
    1608 t.Errorf("tree.size=%d but root.nodeSize()=%d", tree.size, actual)
    1609 }
    1610}
    1611
    1612func leafDepth(n node, depth int) int {
    1613 if n.isLeaf() {
    1614 return depth
    1615 }
    1616 inner := n.(*innerNode)
    1617 d := -1
    1618 for _, child := range inner.children {
    1619 cd := leafDepth(child, depth+1)
    1620 if d == -1 {
    1621 d = cd
    1622 } else if cd != d {
    1623 return -1
    1624 }
    1625 }
    1626 return d
    1627}
    1628
    1629func verifyNode(t *testing.T, n node, fanout int, isRoot bool, seen map[node]bool) {
    1630 t.Helper()
    1631 if seen[n] {
    1632 t.Errorf("node reachable by multiple paths (ref-count >= 2)")
    1633 return
    1634 }
    1635 seen[n] = true
    1636
    1637 if n.isLeaf() {
    1638 leaf := n.(*leafNode)
    1639 if len(leaf.keys) == 0 && !isRoot {
    1640 t.Errorf("non-root leaf has 0 keys")
    1641 }
    1642 if len(leaf.keys) > fanout {
    1643 t.Errorf("leaf has %d keys, max=%d", len(leaf.keys), fanout)
    1644 }
    1645 return
    1646 }
    1647
    1648 inner := n.(*innerNode)
    1649
    1650 // Child count bounds.
    1651 minC := fanout / 2
    1652 if isRoot {
    1653 minC = 2
    1654 }
    1655 if len(inner.children) < minC && !isRoot {
    1656 t.Errorf("inner node has %d children, min=%d", len(inner.children), minC)
    1657 }
    1658 if len(inner.children) > fanout {
    1659 t.Errorf("inner node has %d children, max=%d", len(inner.children), fanout)
    1660 }
    1661
    1662 // keys/children/sizes length consistency.
    1663 if len(inner.keys) != len(inner.children)-1 {
    1664 t.Errorf("len(keys)=%d but len(children)=%d", len(inner.keys), len(inner.children))
    1665 }
    1666 if len(inner.sizes) != len(inner.children) {
    1667 t.Errorf("len(sizes)=%d but len(children)=%d", len(inner.sizes), len(inner.children))
    1668 }
    1669
    1670 // Separator key correctness: keys[i] == children[i+1].minKey().
    1671 for i, k := range inner.keys {
    1672 expected := inner.children[i+1].minKey()
    1673 if k != expected {
    1674 t.Errorf("separator keys[%d]=%q but children[%d].minKey()=%q", i, k, i+1, expected)
    1675 }
    1676 }
    1677
    1678 // sizes[i] matches child.
    1679 for i, child := range inner.children {
    1680 actual := child.nodeSize()
    1681 if inner.sizes[i] != actual {
    1682 t.Errorf("sizes[%d]=%d but child.nodeSize()=%d", i, inner.sizes[i], actual)
    1683 }
    1684 verifyNode(t, child, fanout, false, seen)
    1685 }
    1686}
    1687
    1688func TestInvariantsAfterEveryOperation(t *testing.T) {
    1689 tree := NewBPTreeN(4)
    1690 keys := []string{"m", "f", "t", "b", "i", "p", "w", "a", "d", "g", "k", "n", "r", "u", "y"}
    1691
    1692 for _, k := range keys {
    1693 tree.Set(k, k)
    1694 verifyInvariants(t, tree)
    1695 }
    1696 for _, k := range keys {
    1697 tree.Remove(k)
    1698 verifyInvariants(t, tree)
    1699 }
    1700}
    1701
    1702//----------------------------------------
    1703// Behavioral parity: GetByIndex == IterateByOffset
    1704
    1705func TestGetByIndexMatchesIterateByOffset(t *testing.T) {
    1706 tree := NewBPTreeN(4)
    1707 for _, k := range []string{"h", "d", "l", "b", "f", "j", "n", "a", "c", "e", "g"} {
    1708 tree.Set(k, k)
    1709 }
    1710
    1711 for i := 0; i < tree.Size(); i++ {
    1712 k1, v1 := tree.GetByIndex(i)
    1713 var k2 string
    1714 var v2 any
    1715 tree.IterateByOffset(i, 1, func(k string, v any) bool {
    1716 k2 = k
    1717 v2 = v
    1718 return true
    1719 })
    1720 if k1 != k2 || v1 != v2 {
    1721 t.Errorf("index %d: GetByIndex=(%q,%v) but IterateByOffset=(%q,%v)", i, k1, v1, k2, v2)
    1722 }
    1723 }
    1724}
    1725
    1726//----------------------------------------
    1727// Stress: oscillating tree size
    1728
    1729func TestOscillatingSize(t *testing.T) {
    1730 tree := NewBPTreeN(4)
    1731
    1732 // Insert 100.
    1733 for i := 0; i < 100; i++ {
    1734 tree.Set(intToKey(i), i)
    1735 }
    1736 verifyInvariants(t, tree)
    1737
    1738 // Remove 50.
    1739 for i := 0; i < 50; i++ {
    1740 tree.Remove(intToKey(i))
    1741 }
    1742 verifyInvariants(t, tree)
    1743 if tree.Size() != 50 {
    1744 t.Errorf("Expected size 50, got %d", tree.Size())
    1745 }
    1746
    1747 // Insert 50 new.
    1748 for i := 100; i < 150; i++ {
    1749 tree.Set(intToKey(i), i)
    1750 }
    1751 verifyInvariants(t, tree)
    1752 if tree.Size() != 100 {
    1753 t.Errorf("Expected size 100, got %d", tree.Size())
    1754 }
    1755
    1756 // Remove all.
    1757 for i := 50; i < 150; i++ {
    1758 tree.Remove(intToKey(i))
    1759 }
    1760 verifyInvariants(t, tree)
    1761 if tree.Size() != 0 {
    1762 t.Errorf("Expected size 0, got %d", tree.Size())
    1763 }
    1764
    1765 // Insert again from empty.
    1766 for i := 0; i < 20; i++ {
    1767 tree.Set(intToKey(i), i)
    1768 }
    1769 verifyInvariants(t, tree)
    1770 if tree.Size() != 20 {
    1771 t.Errorf("Expected size 20, got %d", tree.Size())
    1772 }
    1773}
    1774
    1775//----------------------------------------
    1776// All 6 rebalance paths
    1777
    1778func TestAllRebalancePaths(t *testing.T) {
    1779 // We use fanout=4 so min=2 for leaves.
    1780 // Each sub-test constructs a specific tree state and triggers one rebalance path.
    1781
    1782 t.Run("leaf redistribute from left", func(t *testing.T) {
    1783 tree := NewBPTreeN(4)
    1784 for _, k := range []string{"a", "b", "c", "d", "e"} {
    1785 tree.Set(k, k)
    1786 }
    1787 // After 90/10 split: left=[a,b,c], right=[d,e].
    1788 // Remove "d" → right=[e] (1 < min=2). Left has 3 > 2 → redistribute from left.
    1789 tree.Remove("d")
    1790 verifyInvariants(t, tree)
    1791 if !tree.Has("e") {
    1792 t.Error("Missing key 'e' after redistribute")
    1793 }
    1794 })
    1795
    1796 t.Run("leaf redistribute from right", func(t *testing.T) {
    1797 tree := NewBPTreeN(4)
    1798 for _, k := range []string{"a", "b", "c", "d", "e", "f", "g"} {
    1799 tree.Set(k, k)
    1800 }
    1801 // Remove from leftmost leaf until it underflows and must redistribute from right.
    1802 tree.Remove("a")
    1803 tree.Remove("b")
    1804 verifyInvariants(t, tree)
    1805 })
    1806
    1807 t.Run("leaf redistribute from right, no stale root separator keys", func(t *testing.T) {
    1808 tree := NewBPTreeN(4)
    1809 for _, k := range []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n"} {
    1810 tree.Set(k, k)
    1811 }
    1812 tree.Remove("g") // no underflow
    1813 tree.Remove("h") // leaf [h,i] underflows and must redistribute from right
    1814 verifyInvariants(t, tree)
    1815 })
    1816
    1817 t.Run("leaf redistribute from right, no stale inner node separator keys", func(t *testing.T) {
    1818 tree := NewBPTreeN(4)
    1819 for _, k := range []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q"} {
    1820 tree.Set(k, k)
    1821 }
    1822 tree.Remove("g") // no underflow
    1823 tree.Remove("j") // no underflow
    1824 tree.Remove("k") // leaf [k,l] underflows and must redistribute from right
    1825 verifyInvariants(t, tree)
    1826 })
    1827
    1828 t.Run("stale separator, middle leaf pos0 redistribute from right", func(t *testing.T) {
    1829 // Exercises the core bug: remove pos=0 from a middle leaf (childIdx > 0),
    1830 // where left sibling is at minimum (can't redistribute left) and right
    1831 // sibling has surplus (redistribute right fires). Without the fix,
    1832 // parent.keys[childIdx-1] remains stale.
    1833 //
    1834 // After inserting a-k with fanout=4, tree is:
    1835 // root keys=["d","g","j"]
    1836 // children=[["a","b","c"], ["d","e","f"], ["g","h","i"], ["j","k"]]
    1837 //
    1838 // Remove "a" thins children[0] to ["b","c"] (at minimum).
    1839 // Remove "f" thins children[1] to ["d","e"] (at minimum).
    1840 // Remove "d" is pos=0 from children[1], causing underflow to ["e"].
    1841 // Left sibling ["b","c"] has 2 = minKeys, can't spare.
    1842 // Right sibling ["g","h","i"] has 3 > minKeys, redistribute right fires.
    1843 // Without fix: keys[0] stays "d" (stale). With fix: updated to "e".
    1844 tree := NewBPTreeN(4)
    1845 for _, k := range []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"} {
    1846 tree.Set(k, k)
    1847 }
    1848 tree.Remove("a") // thin left sibling to minimum
    1849 tree.Remove("f") // thin target leaf to minimum
    1850 tree.Remove("d") // pos=0, underflow, triggers redistribute from right
    1851 verifyInvariants(t, tree)
    1852 })
    1853
    1854 t.Run("leaf merge", func(t *testing.T) {
    1855 tree := NewBPTreeN(4)
    1856 for _, k := range []string{"a", "b", "c", "d", "e"} {
    1857 tree.Set(k, k)
    1858 }
    1859 // Remove enough to make both siblings at minimum, then one more triggers merge.
    1860 tree.Remove("a")
    1861 tree.Remove("b") // left=[c], right=[d,e]. left underflows. right has 2=min. merge.
    1862 verifyInvariants(t, tree)
    1863 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    1864 return tr.Iterate("", "", cb)
    1865 })
    1866 assertSliceEqual(t, got, []string{"c", "d", "e"})
    1867 })
    1868
    1869 t.Run("inner redistribute from left", func(t *testing.T) {
    1870 // Build a tree with enough inner nodes, then remove to trigger inner rebalance.
    1871 tree := NewBPTreeN(4)
    1872 for i := 0; i < 30; i++ {
    1873 tree.Set(intToKey(i), i)
    1874 }
    1875 // Remove from the right side to underflow a right inner node.
    1876 for i := 25; i < 30; i++ {
    1877 tree.Remove(intToKey(i))
    1878 }
    1879 verifyInvariants(t, tree)
    1880 })
    1881
    1882 t.Run("inner redistribute from right", func(t *testing.T) {
    1883 tree := NewBPTreeN(4)
    1884 for i := 0; i < 30; i++ {
    1885 tree.Set(intToKey(i), i)
    1886 }
    1887 // Remove from the left side to underflow a left inner node.
    1888 for i := 0; i < 5; i++ {
    1889 tree.Remove(intToKey(i))
    1890 }
    1891 verifyInvariants(t, tree)
    1892 })
    1893
    1894 t.Run("inner merge", func(t *testing.T) {
    1895 tree := NewBPTreeN(4)
    1896 for i := 0; i < 20; i++ {
    1897 tree.Set(intToKey(i), i)
    1898 }
    1899 // Remove enough to trigger inner merge.
    1900 for i := 0; i < 15; i++ {
    1901 tree.Remove(intToKey(i))
    1902 }
    1903 verifyInvariants(t, tree)
    1904 if tree.Size() != 5 {
    1905 t.Errorf("Expected size 5, got %d", tree.Size())
    1906 }
    1907 })
    1908}
    1909
    1910//----------------------------------------
    1911// Value mutation after Get should not affect tree
    1912
    1913func TestValueMutationIndependence(t *testing.T) {
    1914 tree := NewBPTreeN(4)
    1915
    1916 // Store a slice value.
    1917 orig := []int{1, 2, 3}
    1918 tree.Set("k", orig)
    1919
    1920 // Get the value and mutate it.
    1921 v := tree.Get("k")
    1922 got := v.([]int)
    1923 got[0] = 999
    1924
    1925 // The tree's stored value should also be affected (since slices are reference types
    1926 // and *any holds the same interface). This is the expected Go behavior — not a copy.
    1927 v2 := tree.Get("k")
    1928 got2 := v2.([]int)
    1929 if got2[0] != 999 {
    1930 t.Errorf("Expected slice mutation to be visible (reference semantics), got %v", got2)
    1931 }
    1932
    1933 // But replacing the value via Set should not affect previous Get results.
    1934 tree.Set("k", []int{10, 20, 30})
    1935 v3 := tree.Get("k")
    1936 got3 := v3.([]int)
    1937 if got3[0] != 10 {
    1938 t.Errorf("Expected new value after Set, got %v", got3)
    1939 }
    1940 // The old reference should still have 999.
    1941 if got[0] != 999 {
    1942 t.Errorf("Old reference should still be 999, got %v", got)
    1943 }
    1944}
    1945
    1946//----------------------------------------
    1947// Comprehensive invariant check across fanouts and sizes
    1948
    1949func TestInvariantsAcrossFanouts(t *testing.T) {
    1950 for _, fanout := range []int{4, 5, 7, 8, 16, 32} {
    1951 tree := NewBPTreeN(fanout)
    1952 n := 200
    1953
    1954 // Insert all.
    1955 for i := 0; i < n; i++ {
    1956 tree.Set(intToKey(i), i)
    1957 }
    1958 verifyInvariants(t, tree)
    1959
    1960 // Remove every 3rd.
    1961 for i := 0; i < n; i += 3 {
    1962 tree.Remove(intToKey(i))
    1963 }
    1964 verifyInvariants(t, tree)
    1965
    1966 // Remove remaining.
    1967 for i := 0; i < n; i++ {
    1968 tree.Remove(intToKey(i))
    1969 }
    1970 verifyInvariants(t, tree)
    1971 if tree.Size() != 0 {
    1972 t.Errorf("fanout=%d: expected size 0, got %d", fanout, tree.Size())
    1973 }
    1974 }
    1975}
    1976
    1977//----------------------------------------
    1978// Deep stack unwinding
    1979
    1980func TestDeepStackUnwinding(t *testing.T) {
    1981 // With fanout=4 and 500 keys, the tree is 4-5 levels deep.
    1982 // Iterating across subtree boundaries forces advanceLeaf/retreatLeaf
    1983 // to pop multiple stack levels.
    1984 tree := NewBPTreeN(4)
    1985 n := 500
    1986 for i := 0; i < n; i++ {
    1987 tree.Set(intToKey(i), i)
    1988 }
    1989
    1990 // Full ascending iteration — every leaf boundary is crossed.
    1991 count := 0
    1992 prev := ""
    1993 tree.Iterate("", "", func(k string, v any) bool {
    1994 if k <= prev && prev != "" {
    1995 t.Errorf("ascending order broken: %q after %q", k, prev)
    1996 }
    1997 prev = k
    1998 count++
    1999 return false
    2000 })
    2001 if count != n {
    2002 t.Errorf("ascending: visited %d, want %d", count, n)
    2003 }
    2004
    2005 // Full descending iteration.
    2006 count = 0
    2007 prev = ""
    2008 tree.ReverseIterate("", "", func(k string, v any) bool {
    2009 if prev != "" && k >= prev {
    2010 t.Errorf("descending order broken: %q after %q", k, prev)
    2011 }
    2012 prev = k
    2013 count++
    2014 return false
    2015 })
    2016 if count != n {
    2017 t.Errorf("descending: visited %d, want %d", count, n)
    2018 }
    2019
    2020 // Offset-based iteration crossing deep boundaries.
    2021 // Start from the middle, iterate to the end.
    2022 count = 0
    2023 tree.IterateByOffset(250, 250, func(k string, v any) bool {
    2024 count++
    2025 return false
    2026 })
    2027 if count != 250 {
    2028 t.Errorf("IterateByOffset(250,250): visited %d, want 250", count)
    2029 }
    2030
    2031 // Reverse offset from middle.
    2032 count = 0
    2033 tree.ReverseIterateByOffset(250, 250, func(k string, v any) bool {
    2034 count++
    2035 return false
    2036 })
    2037 if count != 250 {
    2038 t.Errorf("ReverseIterateByOffset(250,250): visited %d, want 250", count)
    2039 }
    2040
    2041 verifyInvariants(t, tree)
    2042}
    2043
    2044//----------------------------------------
    2045// Height invariant
    2046
    2047func treeHeight(n node) int {
    2048 if n == nil {
    2049 return 0
    2050 }
    2051 if n.isLeaf() {
    2052 return 1
    2053 }
    2054 return 1 + treeHeight(n.(*innerNode).children[0])
    2055}
    2056
    2057func TestHeightInvariant(t *testing.T) {
    2058 // B+ tree with fanout F should have height <= 1 + log_{ceil(F/2)}(n).
    2059 for _, fanout := range []int{4, 8, 32} {
    2060 tree := NewBPTreeN(fanout)
    2061 n := 1000
    2062 for i := 0; i < n; i++ {
    2063 tree.Set(intToKey(i), i)
    2064 }
    2065
    2066 h := treeHeight(tree.root)
    2067 // Compute max height: log base ceil(fanout/2) of n, plus 1 for root.
    2068 minFill := fanout / 2
    2069 if minFill < 2 {
    2070 minFill = 2
    2071 }
    2072 maxH := 1
    2073 capacity := 1
    2074 for capacity < n {
    2075 capacity *= minFill
    2076 maxH++
    2077 }
    2078
    2079 if h > maxH {
    2080 t.Errorf("fanout=%d, n=%d: height=%d exceeds max=%d", fanout, n, h, maxH)
    2081 }
    2082 }
    2083}
    2084
    2085//----------------------------------------
    2086// Empty string as separator key
    2087
    2088func TestEmptyStringSeparator(t *testing.T) {
    2089 tree := NewBPTreeN(4)
    2090
    2091 // Insert "" first, then other keys. With sequential inserts,
    2092 // "" will end up in the leftmost leaf and could become a separator.
    2093 tree.Set("", "empty")
    2094 tree.Set("a", "a")
    2095 tree.Set("b", "b")
    2096 tree.Set("c", "c")
    2097 tree.Set("d", "d") // triggers split; "" should be in left leaf
    2098
    2099 verifyInvariants(t, tree)
    2100
    2101 // Verify all keys accessible.
    2102 if v := tree.Get(""); v != "empty" {
    2103 t.Errorf("Get('')=%v, want empty", v)
    2104 }
    2105 for _, k := range []string{"a", "b", "c", "d"} {
    2106 if !tree.Has(k) {
    2107 t.Errorf("missing key %q", k)
    2108 }
    2109 }
    2110
    2111 // Iterate should include "".
    2112 got := collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    2113 return tr.Iterate("", "", cb)
    2114 })
    2115 assertSliceEqual(t, got, []string{"", "a", "b", "c", "d"})
    2116
    2117 // ReverseIterate should include "".
    2118 got = collectKeys(tree, func(tr *BPTree, cb IterCbFn) bool {
    2119 return tr.ReverseIterate("", "", cb)
    2120 })
    2121 assertSliceEqual(t, got, []string{"d", "c", "b", "a", ""})
    2122
    2123 // Remove "" and verify tree is still valid.
    2124 v, ok := tree.Remove("")
    2125 if !ok || v != "empty" {
    2126 t.Errorf("Remove('')=(%v,%v), want (empty,true)", v, ok)
    2127 }
    2128 verifyInvariants(t, tree)
    2129 if tree.Has("") {
    2130 t.Error("'' should be gone after remove")
    2131 }
    2132
    2133 // Now insert more keys with "" to force it into a separator position.
    2134 // Build a tree where "" is between two inner node children.
    2135 tree2 := NewBPTreeN(4)
    2136 // Insert keys that will sort before and after "".
    2137 // In ASCII, "" < everything. So "" is always the smallest key.
    2138 // To make "" a separator, we need it to be the minKey of a right child.
    2139 // That happens when the leaf containing "" splits and "" ends up
    2140 // as right.keys[0] (the promoted separator).
    2141 // With 50/50 split: left gets lower half, right gets upper half.
    2142 // Since "" is the smallest, it will always be in the left leaf.
    2143 // With 90/10 on append: "" would be in the left leaf too.
    2144 // So "" can become a separator only if it's the minKey of a right child
    2145 // after a split where "" is in the right half.
    2146 // Insert in reverse order so "" ends up in the right half of a split:
    2147 tree2.Set("d", "d")
    2148 tree2.Set("c", "c")
    2149 tree2.Set("b", "b")
    2150 tree2.Set("a", "a")
    2151 tree2.Set("", "empty") // inserted at position 0 (not append), 50/50 split
    2152
    2153 verifyInvariants(t, tree2)
    2154 got = collectKeys(tree2, func(tr *BPTree, cb IterCbFn) bool {
    2155 return tr.Iterate("", "", cb)
    2156 })
    2157 assertSliceEqual(t, got, []string{"", "a", "b", "c", "d"})
    2158}
    2159
    2160//----------------------------------------
    2161// Pointer independence after split
    2162
    2163func TestPointerIndependenceAfterSplit(t *testing.T) {
    2164 tree := NewBPTreeN(4)
    2165
    2166 // Insert 5 keys to trigger a split.
    2167 tree.Set("a", "val_a")
    2168 tree.Set("b", "val_b")
    2169 tree.Set("c", "val_c")
    2170 tree.Set("d", "val_d")
    2171 tree.Set("e", "val_e") // triggers split
    2172
    2173 // Get values from both halves of the split.
    2174 vLeft := tree.Get("a")
    2175 vRight := tree.Get("d")
    2176
    2177 if vLeft != "val_a" {
    2178 t.Errorf("left value: got %v, want val_a", vLeft)
    2179 }
    2180 if vRight != "val_d" {
    2181 t.Errorf("right value: got %v, want val_d", vRight)
    2182 }
    2183
    2184 // Update a value in the left half — should not affect right half.
    2185 tree.Set("a", "new_a")
    2186 vLeft2 := tree.Get("a")
    2187 vRight2 := tree.Get("d")
    2188 if vLeft2 != "new_a" {
    2189 t.Errorf("updated left: got %v, want new_a", vLeft2)
    2190 }
    2191 if vRight2 != "val_d" {
    2192 t.Errorf("right should be unchanged: got %v, want val_d", vRight2)
    2193 }
    2194
    2195 // Update a value in the right half — should not affect left half.
    2196 tree.Set("d", "new_d")
    2197 vLeft3 := tree.Get("a")
    2198 vRight3 := tree.Get("d")
    2199 if vLeft3 != "new_a" {
    2200 t.Errorf("left should be unchanged: got %v, want new_a", vLeft3)
    2201 }
    2202 if vRight3 != "new_d" {
    2203 t.Errorf("updated right: got %v, want new_d", vRight3)
    2204 }
    2205
    2206 // Verify that the *any pointers in the two leaves are different objects.
    2207 // Access internals to check.
    2208 inner := tree.root.(*innerNode)
    2209 leftLeaf := inner.children[0].(*leafNode)
    2210 rightLeaf := inner.children[1].(*leafNode)
    2211
    2212 // Each value pointer should be unique.
    2213 seen := make(map[*any]bool)
    2214 for _, vp := range leftLeaf.values {
    2215 if seen[vp] {
    2216 t.Error("duplicate *any pointer in left leaf")
    2217 }
    2218 seen[vp] = true
    2219 }
    2220 for _, vp := range rightLeaf.values {
    2221 if seen[vp] {
    2222 t.Error("*any pointer shared between left and right leaves after split")
    2223 }
    2224 seen[vp] = true
    2225 }
    2226}
    2227
    2228//----------------------------------------
    2229// Helpers
    2230
    2231func slicesEqual(a, b []string) bool {
    2232 if len(a) != len(b) {
    2233 return false
    2234 }
    2235 for i := range a {
    2236 if a[i] != b[i] {
    2237 return false
    2238 }
    2239 }
    2240 return true
    2241}
    2242
    2243func intToKey(i int) string {
    2244 // Zero-padded 4-digit string for correct lexicographic ordering.
    2245 s := "0000"
    2246 n := i
    2247 b := []byte(s)
    2248 for j := 3; j >= 0; j-- {
    2249 b[j] = byte('0' + n%10)
    2250 n /= 10
    2251 }
    2252 return string(b)
    2253}
    2254
    2255func collectKeys(tree *BPTree, fn func(*BPTree, IterCbFn) bool) []string {
    2256 var keys []string
    2257 fn(tree, func(k string, v any) bool {
    2258 keys = append(keys, k)
    2259 return false
    2260 })
    2261 return keys
    2262}
    2263
    2264func assertSliceEqual(t *testing.T, got, want []string) {
    2265 t.Helper()
    2266 if len(got) != len(want) {
    2267 t.Errorf("got %v, want %v", got, want)
    2268 return
    2269 }
    2270 for i := range got {
    2271 if got[i] != want[i] {
    2272 t.Errorf("got %v, want %v", got, want)
    2273 return
    2274 }
    2275 }
    2276}
    2277
    2278func assertPanics(t *testing.T, name string, fn func()) {
    2279 t.Helper()
    2280 defer func() {
    2281 if r := recover(); r == nil {
    2282 t.Errorf("%s: expected panic, got none", name)
    2283 }
    2284 }()
    2285 fn()
    2286}
    2287
    2288//----------------------------------------
    2289// Stress tests
    2290
    2291// TestAVLCrossValidation runs identical random operations on both avl.Tree
    2292// and BPTree and compares every return value.
    2293func TestAVLCrossValidation(t *testing.T) {
    2294 rng := rand.New(rand.NewPCG(12345, 0))
    2295 at := avl.NewTree()
    2296 bt := NewBPTree32()
    2297
    2298 const nOps = 5000
    2299 const keyRange = 200
    2300
    2301 for i := 0; i < nOps; i++ {
    2302 key := intToKey(rng.IntN(keyRange))
    2303 op := rng.IntN(3)
    2304 switch op {
    2305 case 0: // Set
    2306 aUpd := at.Set(key, i)
    2307 bUpd := bt.Set(key, i)
    2308 if aUpd != bUpd {
    2309 t.Fatalf("op %d: Set(%q) updated avl=%v bpt=%v", i, key, aUpd, bUpd)
    2310 }
    2311 case 1: // Remove
    2312 aVal, aOk := at.Remove(key)
    2313 bVal, bOk := bt.Remove(key)
    2314 if aOk != bOk {
    2315 t.Fatalf("op %d: Remove(%q) avl=%v bpt=%v", i, key, aOk, bOk)
    2316 }
    2317 if aOk && aVal != bVal {
    2318 t.Fatalf("op %d: Remove(%q) value avl=%v bpt=%v", i, key, aVal, bVal)
    2319 }
    2320 case 2: // Get
    2321 aVal := at.Get(key)
    2322 aOk := at.Has(key)
    2323 bVal := bt.Get(key)
    2324 bOk := bt.Has(key)
    2325 if aOk != bOk {
    2326 t.Fatalf("op %d: exists avl=%v bpt=%v", i, aOk, bOk)
    2327 }
    2328 if aOk && aVal != bVal {
    2329 t.Fatalf("op %d: Get(%q) value avl=%v bpt=%v", i, key, aVal, bVal)
    2330 }
    2331 }
    2332 if at.Size() != bt.Size() {
    2333 t.Fatalf("op %d: size avl=%d bpt=%d", i, at.Size(), bt.Size())
    2334 }
    2335 }
    2336
    2337 // Compare full iteration.
    2338 var aKeys, bKeys []string
    2339 at.Iterate("", "", func(k string, v any) bool { aKeys = append(aKeys, k); return false })
    2340 bt.Iterate("", "", func(k string, v any) bool { bKeys = append(bKeys, k); return false })
    2341 assertSliceEqual(t, bKeys, aKeys)
    2342}
    2343
    2344// TestExhaustiveRemovalPermutations inserts N keys then tries all N!
    2345// permutations of removal order, verifying invariants after each remove.
    2346func TestExhaustiveRemovalPermutations(t *testing.T) {
    2347 keys := []string{"a", "b", "c", "d", "e", "f", "g", "h"}
    2348 n := len(keys)
    2349
    2350 perm := make([]int, n)
    2351 for i := range perm {
    2352 perm[i] = i
    2353 }
    2354
    2355 count := 0
    2356 permute(perm, 0, func(order []int) {
    2357 tree := NewBPTreeN(4)
    2358 for _, k := range keys {
    2359 tree.Set(k, k)
    2360 }
    2361 for _, idx := range order {
    2362 tree.Remove(keys[idx])
    2363 verifyInvariants(t, tree)
    2364 }
    2365 if tree.Size() != 0 {
    2366 t.Fatalf("perm %d: tree not empty after removing all keys", count)
    2367 }
    2368 count++
    2369 })
    2370}
    2371
    2372// permute generates all permutations of arr[start:] and calls fn for each.
    2373func permute(arr []int, start int, fn func([]int)) {
    2374 if start == len(arr) {
    2375 fn(arr)
    2376 return
    2377 }
    2378 for i := start; i < len(arr); i++ {
    2379 arr[start], arr[i] = arr[i], arr[start]
    2380 permute(arr, start+1, fn)
    2381 arr[start], arr[i] = arr[i], arr[start]
    2382 }
    2383}
    2384
    2385// TestMultiFanoutStress runs the same operation sequence across different
    2386// fanouts and verifies all produce identical results.
    2387func TestMultiFanoutStress(t *testing.T) {
    2388 fanouts := []int{4, 5, 6, 7, 8, 16, 32}
    2389 const nOps = 2000
    2390 const keyRange = 100
    2391
    2392 // Record expected results from the first fanout.
    2393 type result struct {
    2394 setUpdated bool
    2395 getVal any
    2396 getOk bool
    2397 rmVal any
    2398 rmOk bool
    2399 }
    2400
    2401 rng0 := rand.New(rand.NewPCG(99999, 0))
    2402 type op struct {
    2403 kind int // 0=set, 1=remove, 2=get
    2404 key string
    2405 val int
    2406 }
    2407 ops := make([]op, nOps)
    2408 for i := range ops {
    2409 ops[i] = op{
    2410 kind: rng0.IntN(3),
    2411 key: intToKey(rng0.IntN(keyRange)),
    2412 val: i,
    2413 }
    2414 }
    2415
    2416 // Run on each fanout and collect final keys.
    2417 var referenceKeys []string
    2418 for fi, fanout := range fanouts {
    2419 tree := NewBPTreeN(fanout)
    2420 for _, o := range ops {
    2421 switch o.kind {
    2422 case 0:
    2423 tree.Set(o.key, o.val)
    2424 case 1:
    2425 tree.Remove(o.key)
    2426 case 2:
    2427 tree.Get(o.key)
    2428 }
    2429 }
    2430 verifyInvariants(t, tree)
    2431
    2432 var keys []string
    2433 tree.Iterate("", "", func(k string, v any) bool {
    2434 keys = append(keys, k)
    2435 return false
    2436 })
    2437
    2438 if fi == 0 {
    2439 referenceKeys = keys
    2440 } else {
    2441 assertSliceEqual(t, keys, referenceKeys)
    2442 }
    2443 }
    2444}
    2445
    2446// TestSequentialInsertReverseRemove inserts keys 0..N-1 sequentially
    2447// (triggering 90/10 splits) then removes them in reverse order
    2448// (triggering cascading merges from the right).
    2449func TestSequentialInsertReverseRemove(t *testing.T) {
    2450 for _, fanout := range []int{4, 6, 8, 32} {
    2451 tree := NewBPTreeN(fanout)
    2452 n := 500
    2453 for i := 0; i < n; i++ {
    2454 tree.Set(intToKey(i), i)
    2455 }
    2456 verifyInvariants(t, tree)
    2457 if tree.Size() != n {
    2458 t.Errorf("fanout=%d: expected size %d, got %d", fanout, n, tree.Size())
    2459 }
    2460
    2461 for i := n - 1; i >= 0; i-- {
    2462 val, ok := tree.Remove(intToKey(i))
    2463 if !ok {
    2464 t.Fatalf("fanout=%d: Remove(%s) returned false", fanout, intToKey(i))
    2465 }
    2466 if val != i {
    2467 t.Fatalf("fanout=%d: Remove(%s) value=%v want %d", fanout, intToKey(i), val, i)
    2468 }
    2469 verifyInvariants(t, tree)
    2470 }
    2471 if tree.Size() != 0 {
    2472 t.Errorf("fanout=%d: expected empty tree, got size %d", fanout, tree.Size())
    2473 }
    2474 }
    2475}
    2476
    2477// TestRandomOpsWithPeriodicVerification does 10K random Set/Remove calls,
    2478// verifying invariants and sorted iteration every 100 ops.
    2479func TestRandomOpsWithPeriodicVerification(t *testing.T) {
    2480 rng := rand.New(rand.NewPCG(54321, 0))
    2481 tree := NewBPTreeN(4)
    2482
    2483 const nOps = 10000
    2484 const keyRange = 300
    2485 const checkEvery = 100
    2486
    2487 // Track expected keys in a sorted slice for comparison.
    2488 present := make(map[string]bool)
    2489
    2490 for i := 0; i < nOps; i++ {
    2491 key := intToKey(rng.IntN(keyRange))
    2492 if rng.IntN(3) == 0 { // ~33% removes
    2493 _, ok := tree.Remove(key)
    2494 if ok {
    2495 delete(present, key)
    2496 }
    2497 } else { // ~67% sets
    2498 tree.Set(key, i)
    2499 present[key] = true
    2500 }
    2501
    2502 if (i+1)%checkEvery == 0 {
    2503 verifyInvariants(t, tree)
    2504
    2505 // Check size.
    2506 if tree.Size() != len(present) {
    2507 t.Fatalf("op %d: size mismatch tree=%d map=%d", i, tree.Size(), len(present))
    2508 }
    2509
    2510 // Check iteration matches sorted keys.
    2511 var expected []string
    2512 for k := range present {
    2513 expected = append(expected, k)
    2514 }
    2515 sort.Strings(expected)
    2516
    2517 var got []string
    2518 tree.Iterate("", "", func(k string, v any) bool {
    2519 got = append(got, k)
    2520 return false
    2521 })
    2522 assertSliceEqual(t, got, expected)
    2523 }
    2524 }
    2525}
    2526
    2527// TestGetByIndexIterateByOffsetConsistency verifies that GetByIndex(i)
    2528// matches IterateByOffset(i, 1) for every valid index.
    2529func TestGetByIndexIterateByOffsetConsistency(t *testing.T) {
    2530 rng := rand.New(rand.NewPCG(77777, 0))
    2531 tree := NewBPTreeN(4)
    2532
    2533 // Build a tree with random insertions and removals.
    2534 const nOps = 1000
    2535 const keyRange = 200
    2536 for i := 0; i < nOps; i++ {
    2537 key := intToKey(rng.IntN(keyRange))
    2538 if rng.IntN(4) == 0 {
    2539 tree.Remove(key)
    2540 } else {
    2541 tree.Set(key, i)
    2542 }
    2543 }
    2544
    2545 n := tree.Size()
    2546 for i := 0; i < n; i++ {
    2547 gKey, gVal := tree.GetByIndex(i)
    2548
    2549 var iKey string
    2550 var iVal any
    2551 tree.IterateByOffset(i, 1, func(k string, v any) bool {
    2552 iKey = k
    2553 iVal = v
    2554 return true
    2555 })
    2556
    2557 if gKey != iKey {
    2558 t.Fatalf("index %d: GetByIndex key=%q IterateByOffset key=%q", i, gKey, iKey)
    2559 }
    2560 if gVal != iVal {
    2561 t.Fatalf("index %d: GetByIndex val=%v IterateByOffset val=%v", i, gVal, iVal)
    2562 }
    2563 }
    2564
    2565 // Also check ReverseIterateByOffset consistency.
    2566 for i := 0; i < n; i++ {
    2567 gKey, gVal := tree.GetByIndex(n - 1 - i)
    2568
    2569 var rKey string
    2570 var rVal any
    2571 tree.ReverseIterateByOffset(i, 1, func(k string, v any) bool {
    2572 rKey = k
    2573 rVal = v
    2574 return true
    2575 })
    2576
    2577 if gKey != rKey {
    2578 t.Fatalf("rev index %d: GetByIndex key=%q ReverseIterateByOffset key=%q", i, gKey, rKey)
    2579 }
    2580 if gVal != rVal {
    2581 t.Fatalf("rev index %d: GetByIndex val=%v ReverseIterateByOffset val=%v", i, gVal, rVal)
    2582 }
    2583 }
    2584}
    2585