package models import ( "encoding/json" "testing" ) func TestDirectiveKey(t *testing.T) { cases := map[string]string{ "partition by RANGE (created_at)": "partition", "WITHOUT ROWID": "without", " strict ": "strict", "": "", } for args, want := range cases { if got := DirectiveKey(args); got != want { t.Errorf("DirectiveKey(%q) = %q, want %q", args, got, want) } } } func TestAddDirectiveDerivesKey(t *testing.T) { meta := map[string]any{} AddDirective(meta, Directive{Namespace: "postgres", Args: "partition by RANGE (x)", Line: 2}) AddDirective(meta, Directive{Namespace: "postgres", Key: "tablespace", Args: "tablespace fast", Line: 3}) got := GetDirectives(meta) if len(got) != 2 { t.Fatalf("got %d directives, want 2", len(got)) } if got[0].Key != "partition" { t.Errorf("derived key = %q, want %q", got[0].Key, "partition") } if got[1].Key != "tablespace" { t.Errorf("explicit key = %q, want %q", got[1].Key, "tablespace") } } func TestAddDirectiveNilMeta(t *testing.T) { // Must not panic. AddDirective(nil, Directive{Namespace: "postgres", Args: "strict"}) } func TestGetDirectivesOrdering(t *testing.T) { meta := map[string]any{} AddDirective(meta, Directive{Namespace: "sqlite", Args: "strict", Line: 9}) AddDirective(meta, Directive{Namespace: "postgres", Args: "with (b)", Line: 5}) AddDirective(meta, Directive{Namespace: "postgres", Args: "with (a)", Line: 5}) AddDirective(meta, Directive{Namespace: "postgres", Args: "partition by x", Line: 2}) got := GetDirectives(meta) wantArgs := []string{"partition by x", "with (a)", "with (b)", "strict"} if len(got) != len(wantArgs) { t.Fatalf("got %d directives, want %d", len(got), len(wantArgs)) } for i, w := range wantArgs { if got[i].Args != w { t.Errorf("directive[%d].Args = %q, want %q", i, got[i].Args, w) } } } func TestGetDirectivesTolerantDecodeAfterJSON(t *testing.T) { meta := map[string]any{} AddDirective(meta, Directive{Namespace: "postgres", Args: "partition by RANGE (created_at)", Line: 4}) AddDirective(meta, Directive{Namespace: "sqlite", Args: "without rowid", Line: 6}) blob, err := json.Marshal(meta) if err != nil { t.Fatalf("marshal: %v", err) } var round map[string]any if err := json.Unmarshal(blob, &round); err != nil { t.Fatalf("unmarshal: %v", err) } got := GetDirectives(round) if len(got) != 2 { t.Fatalf("got %d directives after JSON round-trip, want 2", len(got)) } if got[0].Namespace != "postgres" || got[0].Key != "partition" || got[0].Line != 4 { t.Errorf("post-JSON directive[0] = %+v", got[0]) } if got[0].Args != "partition by RANGE (created_at)" { t.Errorf("post-JSON args not verbatim: %q", got[0].Args) } if got[1].Namespace != "sqlite" || got[1].Key != "without" { t.Errorf("post-JSON directive[1] = %+v", got[1]) } } func TestDirectivesForNamespaceAndHasDirective(t *testing.T) { meta := map[string]any{} AddDirective(meta, Directive{Namespace: "postgres", Args: "partition by x", Line: 1}) AddDirective(meta, Directive{Namespace: "sqlite", Args: "strict", Line: 2}) pg := DirectivesForNamespace(meta, "postgres") if len(pg) != 1 || pg[0].Key != "partition" { t.Errorf("DirectivesForNamespace(postgres) = %+v", pg) } if !HasDirective(meta, "sqlite", "strict") { t.Error("HasDirective(sqlite, strict) = false, want true") } if HasDirective(meta, "postgres", "tablespace") { t.Error("HasDirective(postgres, tablespace) = true, want false") } } func TestDirectiveLocationAllowed(t *testing.T) { if !DirectiveLocationAllowed("postgres", "partition", DirectiveLocationTable) { t.Error("partition should be allowed at table level") } if DirectiveLocationAllowed("postgres", "partition", DirectiveLocationColumn) { t.Error("partition should not be allowed at column level") } // Unknown directives are allowed everywhere so they can be preserved. if !DirectiveLocationAllowed("postgres", "bogus", DirectiveLocationDatabase) { t.Error("unknown key should be allowed everywhere") } if !DirectiveLocationAllowed("madeup", "x", DirectiveLocationTable) { t.Error("unknown namespace should be allowed everywhere") } } func TestFormatDirectiveLine(t *testing.T) { d := Directive{Namespace: "postgres", Key: "identity", Args: "identity always"} if got := FormatDirectiveLine(d, ""); got != "@postgres: identity always" { t.Errorf("FormatDirectiveLine no target = %q", got) } if got := FormatDirectiveLine(d, "id"); got != "@postgres(id): identity always" { t.Errorf("FormatDirectiveLine with target = %q", got) } }