package tide import ( "strings" "testing" ) func TestDiffParityClasses(t *testing.T) { step := Step{ID: "d"} ct := jsonCT() check := func(name, want, got, path string) { t.Helper() diffs := compareBodies(Response{Headers: ct, Body: Body(want)}, Response{Headers: ct, Body: Body(got)}, step) if len(diffs) == 0 { t.Fatalf("%s: expected mismatch", name) } found := false for _, d := range diffs { if strings.Contains(d.Path, path) && d.Expected != d.Actual { found = true break } } if !found { t.Fatalf("%s: want path %s in %+v", name, path, diffs) } } check("null vs array", `{"tracklist":[]}`, `{"tracklist":null}`, "tracklist") check("money string vs number", `{"price":"1.5000"}`, `{"price":1.5}`, "price") check("null vs absent", `{"deleted_at":null}`, `{}`, "deleted_at") check("tri-state bool", `{"is_owner":null}`, `{"is_owner":false}`, "is_owner") check("conditional key", `{"data":{"name":"a"}}`, `{"data":{"name":"a","extra":1}}`, "extra") check("date vs Z", `{"created_at":"2026-01-01T00:00:00+00:00"}`, `{"created_at":"2026-01-01T00:00:00Z"}`, "created_at") } func TestDecodeJSONRejectsTrailingValue(t *testing.T) { if _, err := decodeJSON([]byte(`{"data":[]}`)); err != nil { t.Fatalf("single value: %v", err) } if _, err := decodeJSON([]byte(`{"data":[]}{"debug":true}`)); err == nil || !strings.Contains(err.Error(), "trailing JSON") { t.Fatalf("trailing value: %v", err) } want := Response{Headers: jsonCT(), Body: Body(`{"data":[]}{"debug":true}`)} got := Response{Headers: jsonCT(), Body: Body(`{"data":[]}`)} diffs := compareBodies(want, got, Step{ID: "trail"}) if len(diffs) == 0 { t.Fatal("trailing JSON envelope must mismatch") } }