Implements tests/_plans and previously deferred packages; updates plan README with new coverage numbers.
233 lines
7.1 KiB
Go
233 lines
7.1 KiB
Go
package models
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSQLNameLowercases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
got string
|
|
}{
|
|
{"database", (&Database{Name: "MyDB"}).SQLName()},
|
|
{"domain", (&Domain{Name: "MyDomain"}).SQLName()},
|
|
{"schema", (&Schema{Name: "MySchema"}).SQLName()},
|
|
{"table", (&Table{Name: "MyTable"}).SQLName()},
|
|
{"view", (&View{Name: "MyView"}).SQLName()},
|
|
{"sequence", (&Sequence{Name: "MySeq"}).SQLName()},
|
|
{"column", (&Column{Name: "MyCol"}).SQLName()},
|
|
{"index", (&Index{Name: "MyIdx"}).SQLName()},
|
|
{"relationship", (&Relationship{Name: "MyRel"}).SQLName()},
|
|
{"constraint", (&Constraint{Name: "MyCon"}).SQLName()},
|
|
{"enum", (&Enum{Name: "MyEnum"}).SQLName()},
|
|
{"script", (&Script{Name: "MyScript"}).SQLName()},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if tt.got == "" || tt.got != lower(tt.got) {
|
|
t.Errorf("SQLName not lowercase: %q", tt.got)
|
|
}
|
|
})
|
|
}
|
|
if got := (&Table{}).SQLName(); got != "" {
|
|
t.Errorf("empty name: %q", got)
|
|
}
|
|
if got := (&Table{Name: "MyTable"}).SQLName(); got != "mytable" {
|
|
t.Errorf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func lower(s string) string {
|
|
b := []byte(s)
|
|
for i, c := range b {
|
|
if c >= 'A' && c <= 'Z' {
|
|
b[i] = c + 32
|
|
}
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
func TestUpdateDatePropagates(t *testing.T) {
|
|
db := InitDatabase("d")
|
|
schema := InitSchema("s")
|
|
schema.RefDatabase = db
|
|
table := InitTable("t", "s")
|
|
table.RefSchema = schema
|
|
|
|
table.UpdateDate()
|
|
for name, v := range map[string]string{"table": table.UpdatedAt, "schema": schema.UpdatedAt, "database": db.UpdatedAt} {
|
|
ts, err := time.Parse(time.RFC3339, v)
|
|
if err != nil {
|
|
t.Fatalf("%s UpdatedAt %q: %v", name, v, err)
|
|
}
|
|
if time.Since(ts) > time.Minute {
|
|
t.Errorf("%s UpdatedAt too old: %v", name, ts)
|
|
}
|
|
}
|
|
|
|
// Without references only the receiver is updated.
|
|
lone := InitTable("lone", "s")
|
|
lone.UpdateDate()
|
|
if lone.UpdatedAt == "" {
|
|
t.Error("lone table not updated")
|
|
}
|
|
loneSchema := InitSchema("x")
|
|
loneSchema.UpdateDate()
|
|
if loneSchema.UpdatedAt == "" {
|
|
t.Error("lone schema not updated")
|
|
}
|
|
}
|
|
|
|
func TestGetPrimaryKey(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cols []*Column
|
|
want string
|
|
}{
|
|
{"none", []*Column{{Name: "a"}}, ""},
|
|
{"single", []*Column{{Name: "a"}, {Name: "id", IsPrimaryKey: true}}, "id"},
|
|
{"composite ordered by sequence", []*Column{
|
|
{Name: "a", IsPrimaryKey: true, Sequence: 2},
|
|
{Name: "b", IsPrimaryKey: true, Sequence: 1},
|
|
}, "b"},
|
|
{"composite without sequence falls back to name", []*Column{
|
|
{Name: "z", IsPrimaryKey: true},
|
|
{Name: "m", IsPrimaryKey: true},
|
|
}, "m"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tbl := InitTable("t", "s")
|
|
for _, c := range tt.cols {
|
|
tbl.Columns[c.Name] = c
|
|
}
|
|
got := tbl.GetPrimaryKey()
|
|
if tt.want == "" {
|
|
if got != nil {
|
|
t.Errorf("expected nil, got %s", got.Name)
|
|
}
|
|
return
|
|
}
|
|
if got == nil || got.Name != tt.want {
|
|
t.Errorf("got %v, want %s", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
if InitTable("empty", "s").GetPrimaryKey() != nil {
|
|
t.Error("empty table must have no PK")
|
|
}
|
|
}
|
|
|
|
func TestColumnLess(t *testing.T) {
|
|
tests := []struct {
|
|
a, b *Column
|
|
want bool
|
|
}{
|
|
{&Column{Name: "a", Sequence: 1}, &Column{Name: "b", Sequence: 2}, true},
|
|
{&Column{Name: "a", Sequence: 2}, &Column{Name: "b", Sequence: 1}, false},
|
|
{&Column{Name: "a"}, &Column{Name: "b"}, true},
|
|
{&Column{Name: "b"}, &Column{Name: "a"}, false},
|
|
{&Column{Name: "b", Sequence: 1}, &Column{Name: "a"}, false}, // one side unsequenced: by name
|
|
{&Column{Name: "a", Sequence: 1}, &Column{Name: "b"}, true},
|
|
}
|
|
for i, tt := range tests {
|
|
if got := columnLess(tt.a, tt.b); got != tt.want {
|
|
t.Errorf("case %d: got %v, want %v", i, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetForeignKeys(t *testing.T) {
|
|
tbl := InitTable("t", "s")
|
|
add := func(name string, typ ConstraintType, seq uint) {
|
|
c := InitConstraint(name, typ)
|
|
c.Sequence = seq
|
|
tbl.Constraints[name] = c
|
|
}
|
|
add("pk", PrimaryKeyConstraint, 0)
|
|
add("fk_b", ForeignKeyConstraint, 0)
|
|
add("fk_a", ForeignKeyConstraint, 0)
|
|
add("uq", UniqueConstraint, 0)
|
|
|
|
got := tbl.GetForeignKeys()
|
|
if len(got) != 2 || got[0].Name != "fk_a" || got[1].Name != "fk_b" {
|
|
t.Errorf("by name: %v", got)
|
|
}
|
|
|
|
tbl.Constraints["fk_a"].Sequence = 5
|
|
tbl.Constraints["fk_b"].Sequence = 2
|
|
got = tbl.GetForeignKeys()
|
|
if got[0].Name != "fk_b" || got[1].Name != "fk_a" {
|
|
t.Errorf("by sequence: %v", got)
|
|
}
|
|
|
|
if got := InitTable("e", "s").GetForeignKeys(); got == nil || len(got) != 0 {
|
|
t.Errorf("empty table must give non-nil empty slice, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestInitConstructors(t *testing.T) {
|
|
db := InitDatabase("db")
|
|
if db.Name != "db" || db.Schemas == nil || db.Domains == nil || db.Metadata == nil || db.GUID == "" {
|
|
t.Errorf("InitDatabase: %+v", db)
|
|
}
|
|
s := InitSchema("s")
|
|
if s.Name != "s" || s.Tables == nil || s.Views == nil || s.Sequences == nil || s.Permissions == nil || s.Metadata == nil || s.Scripts == nil || s.GUID == "" {
|
|
t.Errorf("InitSchema: %+v", s)
|
|
}
|
|
tb := InitTable("t", "s")
|
|
if tb.Name != "t" || tb.Schema != "s" || tb.Columns == nil || tb.Constraints == nil || tb.Indexes == nil || tb.Relationships == nil || tb.Metadata == nil || tb.GUID == "" {
|
|
t.Errorf("InitTable: %+v", tb)
|
|
}
|
|
c := InitColumn("c", "t", "s")
|
|
if c.Name != "c" || c.Table != "t" || c.Schema != "s" || c.Metadata == nil || c.GUID == "" {
|
|
t.Errorf("InitColumn: %+v", c)
|
|
}
|
|
ix := InitIndex("i", "t", "s")
|
|
if ix.Name != "i" || ix.Table != "t" || ix.Schema != "s" || ix.Columns == nil || ix.Include == nil || ix.Metadata == nil || ix.GUID == "" {
|
|
t.Errorf("InitIndex: %+v", ix)
|
|
}
|
|
r := InitRelation("r", "s")
|
|
if r.Name != "r" || r.FromSchema != "s" || r.ToSchema != "s" || r.Properties == nil || r.FromColumns == nil || r.ToColumns == nil || r.GUID == "" {
|
|
t.Errorf("InitRelation: %+v", r)
|
|
}
|
|
rel := InitRelationship("rel", RelationType("one_to_many"))
|
|
if rel.Name != "rel" || rel.Type != "one_to_many" || rel.Properties == nil || rel.GUID == "" {
|
|
t.Errorf("InitRelationship: %+v", rel)
|
|
}
|
|
con := InitConstraint("k", UniqueConstraint)
|
|
if con.Name != "k" || con.Type != UniqueConstraint || con.Columns == nil || con.ReferencedColumns == nil || con.GUID == "" {
|
|
t.Errorf("InitConstraint: %+v", con)
|
|
}
|
|
sc := InitScript("sc")
|
|
if sc.Name != "sc" || sc.RunAfter == nil || sc.Metadata == nil || sc.GUID == "" {
|
|
t.Errorf("InitScript: %+v", sc)
|
|
}
|
|
v := InitView("v", "s")
|
|
if v.Name != "v" || v.Schema != "s" || v.Columns == nil || v.Metadata == nil || v.GUID == "" {
|
|
t.Errorf("InitView: %+v", v)
|
|
}
|
|
sq := InitSequence("sq", "s")
|
|
if sq.Name != "sq" || sq.Schema != "s" || sq.IncrementBy != 1 || sq.StartValue != 1 || sq.GUID == "" {
|
|
t.Errorf("InitSequence: %+v", sq)
|
|
}
|
|
d := InitDomain("d")
|
|
if d.Name != "d" || d.Tables == nil || d.Metadata == nil || d.GUID == "" {
|
|
t.Errorf("InitDomain: %+v", d)
|
|
}
|
|
dt := InitDomainTable("t", "s")
|
|
if dt.TableName != "t" || dt.SchemaName != "s" || dt.GUID == "" {
|
|
t.Errorf("InitDomainTable: %+v", dt)
|
|
}
|
|
e := InitEnum("e", "s")
|
|
if e.Name != "e" || e.Schema != "s" || e.Values == nil || e.GUID == "" {
|
|
t.Errorf("InitEnum: %+v", e)
|
|
}
|
|
|
|
// GUIDs are unique per call.
|
|
if InitTable("t", "s").GUID == InitTable("t", "s").GUID {
|
|
t.Error("GUIDs must be unique")
|
|
}
|
|
}
|