From eb6edc7ae1288ed70841d66fdc9b0b2f409926eb Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Thu, 24 Mar 2022 10:45:54 +0000 Subject: [PATCH] Restructure tests to use subtests --- amt_test.go | 1437 ++++++++++++++++++++++++----------------------- diff_test.go | 535 +++++++++--------- invalid_test.go | 86 +-- 3 files changed, 1065 insertions(+), 993 deletions(-) diff --git a/amt_test.go b/amt_test.go index c8ade69..2c2de16 100644 --- a/amt_test.go +++ b/amt_test.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "math/rand" - "os" "testing" "time" @@ -29,17 +28,27 @@ func init() { } } -func TestMain(m *testing.M) { - var exitCode int +var ( + bitWidths2to18 = []uint{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} + bitWidths2to3 = []uint{2, 3} +) - // Hack to test with multiple widths, without hassle. - for defaultBitWidth = 2; defaultBitWidth <= 18; defaultBitWidth++ { - fmt.Printf("WIDTH %d\n", defaultBitWidth) - if code := m.Run(); code != 0 { - exitCode = code - } +func runTestWithBitWidths(t *testing.T, bitwidths []uint, fn func(*testing.T, ...Option)) { + t.Helper() + if testing.Short() { + t.Run(fmt.Sprintf("bitwidth=%d", defaultBitWidth), func(t *testing.T) { fn(t, UseTreeBitWidth(defaultBitWidth)) }) + return + } + for _, bw := range bitwidths { + t.Run(fmt.Sprintf("bitwidth=%d", bw), func(t *testing.T) { fn(t, UseTreeBitWidth(bw)) }) + } +} + +func runBenchmarkWithBitWidths(b *testing.B, bitwidths []uint, fn func(*testing.B, ...Option)) { + b.Helper() + for _, bw := range bitwidths { + b.Run(fmt.Sprintf("bitwidth=%d", bw), func(b *testing.B) { fn(b, UseTreeBitWidth(bw)) }) } - os.Exit(exitCode) } type mockBlocks struct { @@ -105,80 +114,86 @@ func TestNew(t *testing.T) { } func TestBasicSetGet(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - assertSet(t, a, 2, "foo") - assertGet(ctx, t, a, 2, "foo") - assertCount(t, a, 1) + assertSet(t, a, 2, "foo") + assertGet(ctx, t, a, 2, "foo") + assertCount(t, a, 1) - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - clean, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } + clean, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + t.Fatal(err) + } - assertGet(ctx, t, clean, 2, "foo") + assertGet(ctx, t, clean, 2, "foo") - assertCount(t, clean, 1) + assertCount(t, clean, 1) + }) } func TestRoundTrip(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) - emptyCid, err := a.Flush(ctx) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) + emptyCid, err := a.Flush(ctx) + require.NoError(t, err) - k := uint64(100000) - assertSet(t, a, k, "foo") - assertDelete(t, a, k) + k := uint64(100000) + assertSet(t, a, k, "foo") + assertDelete(t, a, k) - c, err := a.Flush(ctx) - require.NoError(t, err) + c, err := a.Flush(ctx) + require.NoError(t, err) - require.Equal(t, emptyCid, c) + require.Equal(t, emptyCid, c) + }) } func TestMaxRange(t *testing.T) { - ctx := context.Background() - bs := cbor.NewCborStore(newMockBlocks()) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + ctx := context.Background() + bs := cbor.NewCborStore(newMockBlocks()) - a, err := NewAMT(bs) - require.NoError(t, err) + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - key := uint64(MaxIndex) - expected := cborstr("what is up 1") - err = a.Set(ctx, key, expected) - require.NoError(t, err) + key := uint64(MaxIndex) + expected := cborstr("what is up 1") + err = a.Set(ctx, key, expected) + require.NoError(t, err) - var actual CborByteArray - found, err := a.Get(ctx, key, &actual) - require.NoError(t, err) - require.True(t, found) - require.EqualValues(t, actual, *expected) + var actual CborByteArray + found, err := a.Get(ctx, key, &actual) + require.NoError(t, err) + require.True(t, found) + require.EqualValues(t, actual, *expected) - found = false - require.NoError(t, a.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { - require.Equal(t, uint64(i), key) - found = true - return nil - })) - require.True(t, found) + found = false + require.NoError(t, a.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { + require.Equal(t, uint64(i), key) + found = true + return nil + })) + require.True(t, found) - err = a.Set(ctx, MaxIndex+1, cborstr("what is up 2")) - require.Error(t, err) + err = a.Set(ctx, MaxIndex+1, cborstr("what is up 2")) + require.Error(t, err) - found, err = a.Get(ctx, MaxIndex+1, &actual) - require.Error(t, err) - require.False(t, found) + found, err = a.Get(ctx, MaxIndex+1, &actual) + require.Error(t, err) + require.False(t, found) + }) } func TestMaxRange11(t *testing.T) { @@ -239,105 +254,111 @@ func assertGet(ctx context.Context, t testing.TB, r *Root, i uint64, val string) } func TestExpand(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - assertSet(t, a, 2, "foo") - assertSet(t, a, 11, "bar") - assertSet(t, a, 79, "baz") + assertSet(t, a, 2, "foo") + assertSet(t, a, 11, "bar") + assertSet(t, a, 79, "baz") - assertGet(ctx, t, a, 2, "foo") - assertGet(ctx, t, a, 11, "bar") - assertGet(ctx, t, a, 79, "baz") + assertGet(ctx, t, a, 2, "foo") + assertGet(ctx, t, a, 11, "bar") + assertGet(ctx, t, a, 79, "baz") - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - na, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + t.Fatal(err) + } - assertGet(ctx, t, na, 2, "foo") - assertGet(ctx, t, na, 11, "bar") - assertGet(ctx, t, na, 79, "baz") + assertGet(ctx, t, na, 2, "foo") + assertGet(ctx, t, na, 11, "bar") + assertGet(ctx, t, na, 79, "baz") + }) } func TestInsertABunch(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - num := uint64(5000) + num := uint64(5000) - for i := uint64(0); i < num; i++ { - assertSet(t, a, i, "foo foo bar") - } + for i := uint64(0); i < num; i++ { + assertSet(t, a, i, "foo foo bar") + } - for i := uint64(0); i < num; i++ { - assertGet(ctx, t, a, i, "foo foo bar") - } + for i := uint64(0); i < num; i++ { + assertGet(ctx, t, a, i, "foo foo bar") + } - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - na, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + t.Fatal(err) + } - for i := uint64(0); i < num; i++ { - assertGet(ctx, t, na, i, "foo foo bar") - } + for i := uint64(0); i < num; i++ { + assertGet(ctx, t, na, i, "foo foo bar") + } - assertCount(t, na, num) + assertCount(t, na, num) + }) } func TestForEachWithoutFlush(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - - for _, vals := range [][]uint64{ - {0, 1, 2, 3, 4, 5, 6, 7}, - {8}, - {8, 9, 64}, - {64, 8, 9}, - } { - amt, err := NewAMT(bs) - require.NoError(t, err) - set1 := make(map[uint64]struct{}) - set2 := make(map[uint64]struct{}) - for _, val := range vals { - err := amt.Set(ctx, val, cborstr("")) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + + for _, vals := range [][]uint64{ + {0, 1, 2, 3, 4, 5, 6, 7}, + {8}, + {8, 9, 64}, + {64, 8, 9}, + } { + amt, err := NewAMT(bs, opts...) require.NoError(t, err) + set1 := make(map[uint64]struct{}) + set2 := make(map[uint64]struct{}) + for _, val := range vals { + err := amt.Set(ctx, val, cborstr("")) + require.NoError(t, err) - set1[val] = struct{}{} - set2[val] = struct{}{} - } + set1[val] = struct{}{} + set2[val] = struct{}{} + } - amt.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { - delete(set1, u) - return nil - }) - assert.Equal(t, make(map[uint64]struct{}), set1) + amt.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { + delete(set1, u) + return nil + }) + assert.Equal(t, make(map[uint64]struct{}), set1) - // ensure it still works after flush - _, err = amt.Flush(ctx) - require.NoError(t, err) + // ensure it still works after flush + _, err = amt.Flush(ctx) + require.NoError(t, err) - amt.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { - delete(set2, u) - return nil - }) - assert.Equal(t, make(map[uint64]struct{}), set2) - } + amt.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error { + delete(set2, u) + return nil + }) + assert.Equal(t, make(map[uint64]struct{}), set2) + } + }) } type op struct { @@ -346,456 +367,410 @@ type op struct { } func TestChaos(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - seed := time.Now().UnixNano() - ctx := context.Background() - // seed = 1579200312848358622 // FIXED - // seed = 1579202116615474412 - // seed = 1579202774458659521 - // all above are with ops=100,maxIndx=2000 - r := rand.New(rand.NewSource(seed)) - t.Logf("seed: %d", seed) - - a, err := NewAMT(bs) - require.NoError(t, err) - c, err := a.Flush(ctx) - assert.NoError(t, err) - - ops := make([]op, 1000) - maxPerOp := 10 - maxIndx := 20000 - for i := range ops { - o := &ops[i] - o.del = r.Intn(10) < 4 - o.idxs = make([]uint64, r.Intn(maxPerOp)) - for j := range o.idxs { - o.idxs[j] = uint64(r.Intn(maxIndx)) - } - } - - testMap := make(map[uint64]struct{}) - - for i, o := range ops { - a, err = LoadAMT(ctx, bs, c) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + seed := time.Now().UnixNano() + ctx := context.Background() + // seed = 1579200312848358622 // FIXED + // seed = 1579202116615474412 + // seed = 1579202774458659521 + // all above are with ops=100,maxIndx=2000 + r := rand.New(rand.NewSource(seed)) + t.Logf("seed: %d", seed) + + a, err := NewAMT(bs, opts...) + require.NoError(t, err) + c, err := a.Flush(ctx) assert.NoError(t, err) - for _, index := range o.idxs { - if !o.del { - err := a.Set(ctx, index, cborstr("test")) - testMap[index] = struct{}{} - assert.NoError(t, err) - } else { - _, err := a.Delete(ctx, index) - delete(testMap, index) - require.NoError(t, err) + ops := make([]op, 1000) + maxPerOp := 10 + maxIndx := 20000 + for i := range ops { + o := &ops[i] + o.del = r.Intn(10) < 4 + o.idxs = make([]uint64, r.Intn(maxPerOp)) + for j := range o.idxs { + o.idxs[j] = uint64(r.Intn(maxIndx)) } } - fail := false - correctLen := uint64(len(testMap)) - if correctLen != a.Len() { - t.Errorf("bad length before flush, correct: %d, Count: %d, i: %d", correctLen, a.Len(), i) - fail = true - } + testMap := make(map[uint64]struct{}) + + for i, o := range ops { + a, err = LoadAMT(ctx, bs, c, opts...) + assert.NoError(t, err) + + for _, index := range o.idxs { + if !o.del { + err := a.Set(ctx, index, cborstr("test")) + testMap[index] = struct{}{} + assert.NoError(t, err) + } else { + _, err := a.Delete(ctx, index) + delete(testMap, index) + require.NoError(t, err) + } + } - c, err = a.Flush(ctx) - assert.NoError(t, err) + fail := false + correctLen := uint64(len(testMap)) + if correctLen != a.Len() { + t.Errorf("bad length before flush, correct: %d, Count: %d, i: %d", correctLen, a.Len(), i) + fail = true + } - a, err = LoadAMT(ctx, bs, c) - assert.NoError(t, err) - if correctLen != a.Len() { - t.Errorf("bad length after flush, correct: %d, Count: %d, i: %d", correctLen, a.Len(), i) - fail = true - } + c, err = a.Flush(ctx) + assert.NoError(t, err) - var feCount uint64 - a.ForEach(ctx, func(_ uint64, _ *cbg.Deferred) error { - feCount++ - return nil - }) - if correctLen != feCount { - t.Errorf("bad fe length after flush, correct: %d, Count: %d, i: %d", correctLen, feCount, i) - fail = true - } - if fail { - t.Logf("%+v", o) - t.FailNow() + a, err = LoadAMT(ctx, bs, c, opts...) + assert.NoError(t, err) + if correctLen != a.Len() { + t.Errorf("bad length after flush, correct: %d, Count: %d, i: %d", correctLen, a.Len(), i) + fail = true + } + + var feCount uint64 + a.ForEach(ctx, func(_ uint64, _ *cbg.Deferred) error { + feCount++ + return nil + }) + if correctLen != feCount { + t.Errorf("bad fe length after flush, correct: %d, Count: %d, i: %d", correctLen, feCount, i) + fail = true + } + if fail { + t.Logf("%+v", o) + t.FailNow() + } } - } + }) } func TestInsertABunchWithDelete(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - num := 12000 - originSet := make(map[uint64]bool, num) - removeSet := make(map[uint64]bool, num) - seed := time.Now().UnixNano() - r := rand.New(rand.NewSource(seed)) - t.Logf("seed: %d", seed) + num := 12000 + originSet := make(map[uint64]bool, num) + removeSet := make(map[uint64]bool, num) + seed := time.Now().UnixNano() + r := rand.New(rand.NewSource(seed)) + t.Logf("seed: %d", seed) - for i := 0; i < num; i++ { - originSet[uint64(r.Intn(num))] = true - } + for i := 0; i < num; i++ { + originSet[uint64(r.Intn(num))] = true + } - for i := 0; i < 660; i++ { - k := uint64(r.Intn(num)) - if originSet[k] { - removeSet[k] = true + for i := 0; i < 660; i++ { + k := uint64(r.Intn(num)) + if originSet[k] { + removeSet[k] = true + } } - } - for i := uint64(0); i < uint64(num); i++ { - if originSet[i] { - assertSet(t, a, i, "foo foo bar") + for i := uint64(0); i < uint64(num); i++ { + if originSet[i] { + assertSet(t, a, i, "foo foo bar") + } } - } - for i := uint64(0); i < uint64(num); i++ { - if originSet[i] { - assertGet(ctx, t, a, i, "foo foo bar") + for i := uint64(0); i < uint64(num); i++ { + if originSet[i] { + assertGet(ctx, t, a, i, "foo foo bar") + } } - } - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - na, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + t.Fatal(err) + } - for i := uint64(0); i < uint64(num); i++ { - if removeSet[i] { - assertDelete(t, na, i) + for i := uint64(0); i < uint64(num); i++ { + if removeSet[i] { + assertDelete(t, na, i) + } } - } - c, err = na.Flush(ctx) - if err != nil { - t.Fatal(err) - } - n2a, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } + c, err = na.Flush(ctx) + if err != nil { + t.Fatal(err) + } + n2a, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + t.Fatal(err) + } - t.Logf("originSN: %d, removeSN: %d; expected: %d, actual len(n2a): %d", - len(originSet), len(removeSet), len(originSet)-len(removeSet), n2a.Len()) - assertCount(t, n2a, uint64(len(originSet)-len(removeSet))) + t.Logf("originSN: %d, removeSN: %d; expected: %d, actual len(n2a): %d", + len(originSet), len(removeSet), len(originSet)-len(removeSet), n2a.Len()) + assertCount(t, n2a, uint64(len(originSet)-len(removeSet))) - for i := uint64(0); i < uint64(num); i++ { - if originSet[i] && !removeSet[i] { - assertGet(ctx, t, n2a, i, "foo foo bar") + for i := uint64(0); i < uint64(num); i++ { + if originSet[i] && !removeSet[i] { + assertGet(ctx, t, n2a, i, "foo foo bar") + } } - } + }) } func TestDeleteFirstEntry(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - assertSet(t, a, 0, "cat") - assertSet(t, a, 27, "cat") + assertSet(t, a, 0, "cat") + assertSet(t, a, 27, "cat") - assertDelete(t, a, 27) + assertDelete(t, a, 27) - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - na, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + t.Fatal(err) + } - assertCount(t, na, 1) + assertCount(t, na, 1) + }) } func TestDelete(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - // Check that deleting out of range of the current AMT returns not found - found, err := a.Delete(ctx, 200) - require.NoError(t, err) - require.False(t, found) + // Check that deleting out of range of the current AMT returns not found + found, err := a.Delete(ctx, 200) + require.NoError(t, err) + require.False(t, found) - assertSet(t, a, 0, "cat") - assertSet(t, a, 1, "cat") - assertSet(t, a, 2, "cat") - assertSet(t, a, 3, "cat") + assertSet(t, a, 0, "cat") + assertSet(t, a, 1, "cat") + assertSet(t, a, 2, "cat") + assertSet(t, a, 3, "cat") - assertDelete(t, a, 1) + assertDelete(t, a, 1) - assertGet(ctx, t, a, 0, "cat") - assertGet(ctx, t, a, 2, "cat") - assertGet(ctx, t, a, 3, "cat") + assertGet(ctx, t, a, 0, "cat") + assertGet(ctx, t, a, 2, "cat") + assertGet(ctx, t, a, 3, "cat") - assertDelete(t, a, 0) - assertDelete(t, a, 2) - assertDelete(t, a, 3) + assertDelete(t, a, 0) + assertDelete(t, a, 2) + assertDelete(t, a, 3) - assertCount(t, a, 0) - t.Logf("trying deeper operations now") + assertCount(t, a, 0) + t.Logf("trying deeper operations now") - assertSet(t, a, 23, "dog") - assertSet(t, a, 24, "dog") + assertSet(t, a, 23, "dog") + assertSet(t, a, 24, "dog") - assertDelete(t, a, 23) + assertDelete(t, a, 23) - assertCount(t, a, 1) + assertCount(t, a, 1) - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - na, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + t.Fatal(err) + } - assertCount(t, na, 1) + assertCount(t, na, 1) - a2, err := NewAMT(bs) - require.NoError(t, err) - assertSet(t, a2, 24, "dog") + a2, err := NewAMT(bs, opts...) + require.NoError(t, err) + assertSet(t, a2, 24, "dog") - a2c, err := a2.Flush(ctx) - if err != nil { - t.Fatal(err) - } + a2c, err := a2.Flush(ctx) + if err != nil { + t.Fatal(err) + } - if c != a2c { - t.Logf("%#v\n", a) - t.Logf("%#v\n", na) - t.Logf("%#v\n", a2) - t.Fatal("unexpected cid", c, a2c) - } + if c != a2c { + t.Logf("%#v\n", a) + t.Logf("%#v\n", na) + t.Logf("%#v\n", a2) + t.Fatal("unexpected cid", c, a2c) + } + }) } func TestDeleteReduceHeight(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - assertSet(t, a, 1, "thing") + assertSet(t, a, 1, "thing") - c1, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c1, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - assertSet(t, a, 37, "other") + assertSet(t, a, 37, "other") - c2, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c2, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) + } - a2, err := LoadAMT(ctx, bs, c2) - if err != nil { - t.Fatal(err) - } + a2, err := LoadAMT(ctx, bs, c2, opts...) + if err != nil { + t.Fatal(err) + } - assertDelete(t, a2, 37) - assertCount(t, a2, 1) + assertDelete(t, a2, 37) + assertCount(t, a2, 1) - c3, err := a2.Flush(ctx) - if err != nil { - t.Fatal(err) - } + c3, err := a2.Flush(ctx) + if err != nil { + t.Fatal(err) + } - if c1 != c3 { - t.Fatal("structures did not match after insert/delete") - } + if c1 != c3 { + t.Fatal("structures did not match after insert/delete") + } + }) } func BenchmarkAMTInsertBulk(b *testing.B) { - mock := newMockBlocks() - defer mock.report(b) + runBenchmarkWithBitWidths(b, bitWidths2to18, func(b *testing.B, opts ...Option) { + mock := newMockBlocks() + defer mock.report(b) - bs := cbor.NewCborStore(mock) - ctx := context.Background() + bs := cbor.NewCborStore(mock) + ctx := context.Background() - for i := 0; i < b.N; i++ { - a, err := NewAMT(bs) - require.NoError(b, err) + for i := 0; i < b.N; i++ { + a, err := NewAMT(bs, opts...) + require.NoError(b, err) - num := uint64(5000) + num := uint64(5000) - for i := uint64(0); i < num; i++ { - if err := a.Set(ctx, i, cborstr("foo foo bar")); err != nil { - b.Fatal(err) + for i := uint64(0); i < num; i++ { + if err := a.Set(ctx, i, cborstr("foo foo bar")); err != nil { + b.Fatal(err) + } } - } - for i := uint64(0); i < num; i++ { - assertGet(ctx, b, a, i, "foo foo bar") - } + for i := uint64(0); i < num; i++ { + assertGet(ctx, b, a, i, "foo foo bar") + } - c, err := a.Flush(ctx) - if err != nil { - b.Fatal(err) - } + c, err := a.Flush(ctx) + if err != nil { + b.Fatal(err) + } - na, err := LoadAMT(ctx, bs, c) - if err != nil { - b.Fatal(err) - } + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + b.Fatal(err) + } - for i := uint64(0); i < num; i++ { - assertGet(ctx, b, na, i, "foo foo bar") - } + for i := uint64(0); i < num; i++ { + assertGet(ctx, b, na, i, "foo foo bar") + } - assertCount(b, na, num) - } + assertCount(b, na, num) + } + }) } func BenchmarkAMTLoadAndInsert(b *testing.B) { - mock := newMockBlocks() - defer mock.report(b) - - bs := cbor.NewCborStore(mock) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(b, err) + runBenchmarkWithBitWidths(b, bitWidths2to18, func(b *testing.B, opts ...Option) { + mock := newMockBlocks() + defer mock.report(b) - c, err := a.Flush(ctx) - if err != nil { - b.Fatal(err) - } + bs := cbor.NewCborStore(mock) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(b, err) - for i := uint64(b.N); i > 0; i-- { - na, err := LoadAMT(ctx, bs, c) + c, err := a.Flush(ctx) if err != nil { b.Fatal(err) } - if err := na.Set(ctx, i, cborstr("some value")); err != nil { - b.Fatal(err) - } - c, err = na.Flush(ctx) - if err != nil { - b.Fatal(err) + for i := uint64(b.N); i > 0; i-- { + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { + b.Fatal(err) + } + + if err := na.Set(ctx, i, cborstr("some value")); err != nil { + b.Fatal(err) + } + c, err = na.Flush(ctx) + if err != nil { + b.Fatal(err) + } } - } + }) } func TestForEach(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) + runTestWithBitWidths(t, bitWidths2to18, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) - r := rand.New(rand.NewSource(101)) + r := rand.New(rand.NewSource(101)) - var indexes []uint64 - for i := 0; i < 10000; i++ { - if r.Intn(2) == 0 { - indexes = append(indexes, uint64(i)) + var indexes []uint64 + for i := 0; i < 10000; i++ { + if r.Intn(2) == 0 { + indexes = append(indexes, uint64(i)) + } } - } - for _, i := range indexes { - if err := a.Set(ctx, i, cborstr("value")); err != nil { - t.Fatal(err) + for _, i := range indexes { + if err := a.Set(ctx, i, cborstr("value")); err != nil { + t.Fatal(err) + } } - } - for _, i := range indexes { - assertGet(ctx, t, a, i, "value") - } - - assertCount(t, a, uint64(len(indexes))) - - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } - - na, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } - - assertCount(t, na, uint64(len(indexes))) - - var x int - err = na.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { - if i != indexes[x] { - t.Fatal("got wrong index", i, indexes[x], x) + for _, i := range indexes { + assertGet(ctx, t, a, i, "value") } - x++ - return nil - }) - if err != nil { - t.Fatal(err) - } - if x != len(indexes) { - t.Fatal("didnt see enough values") - } -} -func TestForEachAt(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) - - r := rand.New(rand.NewSource(101)) + assertCount(t, a, uint64(len(indexes))) - var indexes []uint64 - for i := 0; i < 10000; i++ { - if r.Intn(2) == 0 { - indexes = append(indexes, uint64(i)) + c, err := a.Flush(ctx) + if err != nil { + t.Fatal(err) } - } - for _, i := range indexes { - if err := a.Set(ctx, i, cborstr(fmt.Sprint(i))); err != nil { + na, err := LoadAMT(ctx, bs, c, opts...) + if err != nil { t.Fatal(err) } - } - - for _, i := range indexes { - assertGet(ctx, t, a, i, fmt.Sprint(i)) - } - assertCount(t, a, uint64(len(indexes))) - - c, err := a.Flush(ctx) - if err != nil { - t.Fatal(err) - } - - na, err := LoadAMT(ctx, bs, c) - if err != nil { - t.Fatal(err) - } - - assertCount(t, na, uint64(len(indexes))) - - for try := 0; try < 10; try++ { - start := uint64(r.Intn(10000)) + assertCount(t, na, uint64(len(indexes))) var x int - for ; indexes[x] < start; x++ { - } - - err = na.ForEachAt(ctx, start, func(i uint64, v *cbg.Deferred) error { + err = na.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { if i != indexes[x] { t.Fatal("got wrong index", i, indexes[x], x) } @@ -808,82 +783,150 @@ func TestForEachAt(t *testing.T) { if x != len(indexes) { t.Fatal("didnt see enough values") } - } + }) } -func TestFirstSetIndex(t *testing.T) { - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - - vals := []uint64{0, 1, 5, 1 << uint64(defaultBitWidth), 1<= 2 { - t.Skip("test only valid for widths less than 16") - } - bs := cbor.NewCborStore(newMockBlocks()) - ctx := context.Background() - a, err := NewAMT(bs) - require.NoError(t, err) - err = a.Set(ctx, 15, cborstr("")) - require.NoError(t, err) - - a.height = 2 - c, err := a.Flush(ctx) - require.NoError(t, err) - after, err := LoadAMT(ctx, bs, c) - require.NoError(t, err) - - var out CborByteArray - found, err := after.Get(ctx, 31, &out) - require.NoError(t, err) - require.False(t, found) + // test only valid for widths less than 16 (2^4) + runTestWithBitWidths(t, bitWidths2to3, func(t *testing.T, opts ...Option) { + bs := cbor.NewCborStore(newMockBlocks()) + ctx := context.Background() + a, err := NewAMT(bs, opts...) + require.NoError(t, err) + err = a.Set(ctx, 15, cborstr("")) + require.NoError(t, err) + + a.height = 2 + c, err := a.Flush(ctx) + require.NoError(t, err) + after, err := LoadAMT(ctx, bs, c, opts...) + require.NoError(t, err) + + var out CborByteArray + found, err := after.Get(ctx, 31, &out) + require.NoError(t, err) + require.False(t, found) + }) }