Poindexter/kdtree_nd_noerr_test.go

64 lines
2 KiB
Go
Raw Normal View History

package poindexter
import (
"fmt"
"math"
"testing"
)
// TestBuildNDNoErr_Parity checks that BuildNDNoErr matches BuildND on valid inputs.
func TestBuildNDNoErr_Parity(t *testing.T) {
type rec struct {
A, B, C float64
ID string
}
items := []rec{
{A: 10, B: 100, C: 1, ID: "x"},
{A: 20, B: 200, C: 2, ID: "y"},
{A: 30, B: 300, C: 3, ID: "z"},
}
features := []func(rec) float64{
func(r rec) float64 { return r.A },
func(r rec) float64 { return r.B },
func(r rec) float64 { return r.C },
}
weights := []float64{1, 0.5, 2}
invert := []bool{false, true, false}
idfn := func(r rec) string { return r.ID }
ptsStrict, err := BuildND(items, idfn, features, weights, invert)
if err != nil {
t.Fatalf("BuildND returned error: %v", err)
}
ptsLoose := BuildNDNoErr(items, idfn, features, weights, invert)
if len(ptsStrict) != len(ptsLoose) {
t.Fatalf("length mismatch: strict %d loose %d", len(ptsStrict), len(ptsLoose))
}
for i := range ptsStrict {
if ptsStrict[i].ID != ptsLoose[i].ID {
t.Fatalf("ID mismatch at %d: %s vs %s", i, ptsStrict[i].ID, ptsLoose[i].ID)
}
if len(ptsStrict[i].Coords) != len(ptsLoose[i].Coords) {
t.Fatalf("dim mismatch at %d: %d vs %d", i, len(ptsStrict[i].Coords), len(ptsLoose[i].Coords))
}
for d := range ptsStrict[i].Coords {
if math.Abs(ptsStrict[i].Coords[d]-ptsLoose[i].Coords[d]) > 1e-12 {
t.Fatalf("coord mismatch at %d dim %d: %v vs %v", i, d, ptsStrict[i].Coords[d], ptsLoose[i].Coords[d])
}
}
}
}
// TestBuildNDNoErr_Lenient ensures the no-error builder is lenient and returns nil on bad lengths.
func TestBuildNDNoErr_Lenient(t *testing.T) {
type rec struct{ A float64 }
items := []rec{{A: 1}, {A: 2}}
features := []func(rec) float64{func(r rec) float64 { return r.A }}
weightsBad := []float64{} // wrong length
invert := []bool{false}
pts := BuildNDNoErr(items, func(r rec) string { return fmt.Sprint(r.A) }, features, weightsBad, invert)
if pts != nil {
t.Fatalf("expected nil result on bad weights length, got %v", pts)
}
}