// Copyright 2025 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package token import ( "math/rand/v2" "slices" "testing" ) // TestTree provides basic coverage of the AVL tree operations. func TestTree(t *testing.T) { // Use a reproducible PRNG. seed1, seed2 := rand.Uint64(), rand.Uint64() t.Logf("random seeds: %d, %d", seed1, seed2) rng := rand.New(rand.NewPCG(seed1, seed2)) // Create a number of Files of arbitrary size. files := make([]*File, 500) var base int for i := range files { base++ size := 1000 files[i] = &File{base: base, size: size} base += size } // Add them all to the tree in random order. var tr tree { files2 := slices.Clone(files) Shuffle(rng, files2) for _, f := range files2 { tr.add(f) } } // Randomly delete a subset of them. for range 100 { i := rng.IntN(len(files)) file := files[i] if file == nil { continue // already deleted } files[i] = nil pn, _ := tr.locate(file.key()) if (*pn).file != file { t.Fatalf("locate returned wrong file") } tr.delete(pn) } // Check some position lookups within each file. for _, file := range files { if file == nil { continue // deleted } for _, pos := range []int{ file.base, // start file.base + file.size/2, // midpoint file.base + file.size, // end } { pn, _ := tr.locate(key{pos, pos}) if (*pn).file != file { t.Fatalf("lookup %s@%d returned wrong file %s", file.name, pos, (*pn).file.name) } } } // Check that the sequence is the same. files = slices.DeleteFunc(files, func(f *File) bool { return f == nil }) if !slices.Equal(slices.Collect(tr.all()), files) { t.Fatalf("incorrect tree.all sequence") } } func Shuffle[T any](rng *rand.Rand, slice []*T) { rng.Shuffle(len(slice), func(i, j int) { slice[i], slice[j] = slice[j], slice[i] }) }