131 lines
4.6 KiB
Go
131 lines
4.6 KiB
Go
package rows
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/larvit/fejkdata/internal/drawstate"
|
|
)
|
|
|
|
func parse(t *testing.T, segment, data string, o Options) *Table[string] {
|
|
t.Helper()
|
|
tb, err := Parse(segment, segment, "g."+segment, segment+".tsv", data, o)
|
|
if err != nil {
|
|
t.Fatalf("Parse(%s): %v", segment, err)
|
|
}
|
|
return tb
|
|
}
|
|
|
|
// family is a country table, SE and NO, and a city table linked to it, where Borg names a city in each country.
|
|
func family(t *testing.T) (country, city *Table[string]) {
|
|
t.Helper()
|
|
country = parse(t, "country", "code\tname\nSE\tSweden\nNO\tNorway\n", Options{Key: "code"})
|
|
city = parse(t, "city", "country\tname\nSE\tBorg\nNO\tBorg\nSE\tLund\n", Options{Name: "name", Parent: "country"})
|
|
if err := city.Link(country, func(string) *Table[string] { return nil }); err != nil {
|
|
t.Fatalf("Link: %v", err)
|
|
}
|
|
return country, city
|
|
}
|
|
|
|
func TestParseRefuses(t *testing.T) {
|
|
for _, c := range []struct {
|
|
name, data string
|
|
o Options
|
|
want string
|
|
}{
|
|
{"no header", "", Options{}, "no header line"},
|
|
{"no rows", "a\n", Options{}, "has no rows below its header"},
|
|
{"a short row", "a\tb\n1\t2\n3\n", Options{}, "line 3 has fewer cells"},
|
|
{"a repeated key", "k\nx\nx\n", Options{Key: "k"}, `key "x" repeats line 2`},
|
|
{"every weight zero", "k\tw\nx\t0\ny\t0\n", Options{Weight: "w"}, "every weight is 0"},
|
|
{"a negative weight", "k\tw\nx\t1\ny\t-1\n", Options{Weight: "w"}, `weight "-1" is not a number of 0 or more`},
|
|
{"a key a selector cannot spell", "k\nx\ny|z\n", Options{Key: "k"}, `contains "|"`},
|
|
{"an option naming no column", "k\nx\ny\n", Options{Key: "nope"}, `key names no column "nope"`},
|
|
} {
|
|
if _, err := Parse("o", "t", "g.t", "t.tsv", c.data, c.o); err == nil || !strings.Contains(err.Error(), c.want) {
|
|
t.Errorf("%s: Parse = %v, want %q", c.name, err, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLinkRefusesAParentRowNoChildLinksTo(t *testing.T) {
|
|
country := parse(t, "country", "code\nSE\nNO\n", Options{Key: "code"})
|
|
city := parse(t, "city", "country\tname\nSE\tLund\nSE\tBorg\n", Options{Parent: "country"})
|
|
if err := city.Link(country, func(string) *Table[string] { return nil }); err == nil || !strings.Contains(err.Error(), `country "NO"`) {
|
|
t.Errorf("Link = %v, want the unlinked row NO named", err)
|
|
}
|
|
if city.Parent() != nil {
|
|
t.Error("a refused link set the parent")
|
|
}
|
|
}
|
|
|
|
func TestOwnerIsWhatParseWasGiven(t *testing.T) {
|
|
if _, city := family(t); city.Parent().Owner() != "country" {
|
|
t.Errorf("Owner = %q, want country", city.Parent().Owner())
|
|
}
|
|
}
|
|
|
|
func TestSelectResolvesANameInsideThePinnedParent(t *testing.T) {
|
|
country, city := family(t)
|
|
var p Pins[string]
|
|
if _, err := p.Select(city, "Borg"); err == nil || !strings.Contains(err.Error(), "names 2 rows") {
|
|
t.Fatalf("Select(Borg) with no country pinned = %v, want it ambiguous", err)
|
|
}
|
|
if _, err := p.Select(country, "NO"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r, err := p.Select(city, "Borg")
|
|
if err != nil || r != 1 {
|
|
t.Fatalf("Select(Borg) inside NO = %d, %v, want row 1", r, err)
|
|
}
|
|
if err := p.PinRow(city, 2); err == nil || !strings.Contains(err.Error(), "two rows of g.city") {
|
|
t.Errorf("PinRow(Lund) over Borg = %v, want a clash", err)
|
|
}
|
|
}
|
|
|
|
func TestPinRowRefusesARowOutsideThePinnedParent(t *testing.T) {
|
|
country, city := family(t)
|
|
var p Pins[string]
|
|
if err := p.PinRow(country, 1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := p.PinRow(city, 2); err == nil || !strings.Contains(err.Error(), "is not inside g.country[NO]") {
|
|
t.Errorf("PinRow(Lund) inside NO = %v, want it refused", err)
|
|
}
|
|
}
|
|
|
|
func TestDrawInDrawsInsideThePinnedParentAndPinsItsAncestors(t *testing.T) {
|
|
country, city := family(t)
|
|
s := drawstate.New(1)
|
|
for i := 0; i < 50; i++ {
|
|
var p Pins[string]
|
|
if err := p.PinRow(country, 0); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if r := city.DrawIn(s, &p); city.Cell(r, 0) != "SE" {
|
|
t.Fatalf("DrawIn inside SE drew a city of %s", city.Cell(r, 0))
|
|
}
|
|
var q Pins[string]
|
|
r := city.DrawIn(s, &q)
|
|
if pr := q.MustRow(country); country.Cell(pr, 0) != city.Cell(r, 0) {
|
|
t.Fatalf("DrawIn pinned country %s above a city of %s", country.Cell(pr, 0), city.Cell(r, 0))
|
|
}
|
|
if _, ok := q.Above(country).Pinned(city); ok {
|
|
t.Fatal("Above(country) kept the city's pin")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestProveStepUpNamesTheParent(t *testing.T) {
|
|
country, city := family(t)
|
|
if err := city.ProveStepUp([]string{"country", "name"}); err != nil {
|
|
t.Errorf("ProveStepUp(country.name) = %v", err)
|
|
}
|
|
if err := city.ProveStepUp([]string{"name"}); err == nil || !strings.Contains(err.Error(), "..country") {
|
|
t.Errorf("ProveStepUp(name) = %v, want ..country named", err)
|
|
}
|
|
if err := country.ProveStepUp([]string{"x"}); err == nil {
|
|
t.Error("ProveStepUp from a table with no parent passed")
|
|
}
|
|
}
|