Files
relspecgo/pkg/models/sorting_test.go
T
warkanum 495a21b67b test: expand coverage across readers, writers, cmd, ui, diff and merge
Implements tests/_plans and previously deferred packages; updates plan
README with new coverage numbers.
2026-10-03 21:33:59 +02:00

171 lines
5.8 KiB
Go

package models
import (
"reflect"
"testing"
)
type sortCase struct {
name string
seq uint
}
var sortFixture = []sortCase{{"Banana", 3}, {"apple", 1}, {"Cherry", 2}}
var (
wantNameAsc = []string{"apple", "Banana", "Cherry"}
wantNameDesc = []string{"Cherry", "Banana", "apple"}
wantSeqAsc = []string{"apple", "Cherry", "Banana"}
wantSeqDesc = []string{"Banana", "Cherry", "apple"}
)
func checkNames(t *testing.T, label string, got, want []string) {
t.Helper()
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: got %v, want %v", label, got, want)
}
}
// runSortSuite exercises a by-name and by-sequence sorter pair over the shared fixture.
func runSortSuite[T any](t *testing.T, build func(sortCase) T, name func(T) string,
byName func([]T, bool) error, bySeq func([]T, bool) error) {
t.Helper()
mk := func() []T {
out := make([]T, 0, len(sortFixture))
for _, c := range sortFixture {
out = append(out, build(c))
}
return out
}
names := func(items []T) []string {
out := make([]string, 0, len(items))
for _, it := range items {
out = append(out, name(it))
}
return out
}
if byName != nil {
items := mk()
_ = byName(items, false)
checkNames(t, "name asc", names(items), wantNameAsc)
_ = byName(items, true)
checkNames(t, "name desc", names(items), wantNameDesc)
_ = byName(nil, false)
_ = byName([]T{}, true)
}
if bySeq != nil {
items := mk()
_ = bySeq(items, false)
checkNames(t, "seq asc", names(items), wantSeqAsc)
_ = bySeq(items, true)
checkNames(t, "seq desc", names(items), wantSeqDesc)
_ = bySeq(nil, false)
}
}
func TestSortSchemas(t *testing.T) {
runSortSuite(t, func(c sortCase) *Schema { return &Schema{Name: c.name, Sequence: c.seq} },
func(s *Schema) string { return s.Name }, SortSchemasByName, SortSchemasBySequence)
}
func TestSortTables(t *testing.T) {
runSortSuite(t, func(c sortCase) *Table { return &Table{Name: c.name, Sequence: c.seq} },
func(s *Table) string { return s.Name }, SortTablesByName, SortTablesBySequence)
}
func TestSortColumns(t *testing.T) {
runSortSuite(t, func(c sortCase) *Column { return &Column{Name: c.name, Sequence: c.seq} },
func(s *Column) string { return s.Name }, SortColumnsByName, SortColumnsBySequence)
}
func TestSortViews(t *testing.T) {
runSortSuite(t, func(c sortCase) *View { return &View{Name: c.name, Sequence: c.seq} },
func(s *View) string { return s.Name }, SortViewsByName, SortViewsBySequence)
}
func TestSortSequences(t *testing.T) {
runSortSuite(t, func(c sortCase) *Sequence { return &Sequence{Name: c.name, Sequence: c.seq} },
func(s *Sequence) string { return s.Name }, SortSequencesByName, SortSequencesBySequence)
}
func TestSortIndexes(t *testing.T) {
runSortSuite(t, func(c sortCase) *Index { return &Index{Name: c.name, Sequence: c.seq} },
func(s *Index) string { return s.Name }, SortIndexesByName, SortIndexesBySequence)
}
func TestSortNameOnly(t *testing.T) {
runSortSuite(t, func(c sortCase) *Constraint { return &Constraint{Name: c.name} },
func(s *Constraint) string { return s.Name }, SortConstraintsByName, nil)
runSortSuite(t, func(c sortCase) *Relationship { return &Relationship{Name: c.name} },
func(s *Relationship) string { return s.Name }, SortRelationshipsByName, nil)
runSortSuite(t, func(c sortCase) *Script { return &Script{Name: c.name} },
func(s *Script) string { return s.Name }, SortScriptsByName, nil)
runSortSuite(t, func(c sortCase) *Enum { return &Enum{Name: c.name} },
func(s *Enum) string { return s.Name }, SortEnumsByName, nil)
}
func TestSortStableForTies(t *testing.T) {
cols := []*Column{{Name: "x", Description: "first"}, {Name: "X", Description: "second"}, {Name: "x", Description: "third"}}
_ = SortColumnsByName(cols, false)
if cols[0].Description != "first" || cols[1].Description != "second" || cols[2].Description != "third" {
t.Errorf("ties must keep input order: %v %v %v", cols[0].Description, cols[1].Description, cols[2].Description)
}
_ = SortColumnsBySequence(cols, true)
if cols[0].Description != "first" || cols[2].Description != "third" {
t.Errorf("sequence ties must keep input order")
}
}
func TestSortMapVariants(t *testing.T) {
cols := map[string]*Column{}
idx := map[string]*Index{}
cons := map[string]*Constraint{}
rels := map[string]*Relationship{}
for _, c := range sortFixture {
cols[c.name] = &Column{Name: c.name, Sequence: c.seq}
idx[c.name] = &Index{Name: c.name, Sequence: c.seq}
cons[c.name] = &Constraint{Name: c.name}
rels[c.name] = &Relationship{Name: c.name}
}
colNames := func(l []*Column) (o []string) {
for _, x := range l {
o = append(o, x.Name)
}
return
}
idxNames := func(l []*Index) (o []string) {
for _, x := range l {
o = append(o, x.Name)
}
return
}
conNames := func(l []*Constraint) (o []string) {
for _, x := range l {
o = append(o, x.Name)
}
return
}
relNames := func(l []*Relationship) (o []string) {
for _, x := range l {
o = append(o, x.Name)
}
return
}
checkNames(t, "cols name", colNames(SortColumnsMapByName(cols, false)), wantNameAsc)
checkNames(t, "cols name desc", colNames(SortColumnsMapByName(cols, true)), wantNameDesc)
checkNames(t, "cols seq", colNames(SortColumnsMapBySequence(cols, false)), wantSeqAsc)
checkNames(t, "cols seq desc", colNames(SortColumnsMapBySequence(cols, true)), wantSeqDesc)
checkNames(t, "idx name", idxNames(SortIndexesMapByName(idx, false)), wantNameAsc)
checkNames(t, "idx seq", idxNames(SortIndexesMapBySequence(idx, true)), wantSeqDesc)
checkNames(t, "con name", conNames(SortConstraintsMapByName(cons, false)), wantNameAsc)
checkNames(t, "rel name", relNames(SortRelationshipsMapByName(rels, true)), wantNameDesc)
if got := SortColumnsMapByName(nil, false); got == nil || len(got) != 0 {
t.Errorf("nil map must give non-nil empty slice")
}
if len(cols) != 3 {
t.Error("input map must not be modified")
}
}