package star import ( "encoding/json" "strings" "testing" "time" ) func TestBuildDeterministic(t *testing.T) { birth := time.Date(1990, 5, 12, 0, 0, 0, 0, time.UTC) asOf := time.Date(2026, 8, 2, 12, 0, 0, 0, time.UTC) opts := BuildOpts{Birth: birth, Name: "小愈", AsOf: asOf} a, err := BuildWith(opts) if err != nil { t.Fatal(err) } b, err := BuildWith(opts) if err != nil { t.Fatal(err) } if a.Summary["headline"] != b.Summary["headline"] { t.Fatal("not deterministic") } if a.Summary["sun_sign"] == nil || a.Detail["sections"] == nil { t.Fatal("missing fields") } if a.Summary["sign_cards"] == nil || a.Summary["outlook"] == nil || a.Summary["planets"] == nil { t.Fatal("missing sign_cards, outlook or planets") } if a.Summary["fortune"] != nil { t.Fatal("legacy fortune key must be removed (ECR-003)") } if a.Summary["aspects_preview"] == nil { t.Fatal("missing aspects_preview") } chart, _ := a.Summary["chart"].(map[string]any) if chart["asc_lon"] == nil { t.Fatal("missing chart.asc_lon") } if a.Detail["aspects"] == nil { t.Fatal("missing detail.aspects") } raw, _ := json.Marshal(a) blob := string(raw) for _, bad := range []string{"算命"} { if strings.Contains(blob, bad) { t.Fatalf("forbidden %q", bad) } } } func TestBuildWithBirthTimeChangesRise(t *testing.T) { birth := time.Date(1990, 5, 12, 0, 0, 0, 0, time.UTC) bt := "14:30" place := "北京" a, err := BuildWith(BuildOpts{Birth: birth, Name: "我"}) if err != nil { t.Fatal(err) } b, err := BuildWith(BuildOpts{Birth: birth, BirthTime: &bt, BirthPlace: &place, Name: "我"}) if err != nil { t.Fatal(err) } if a.Summary["planets"] == nil || b.Summary["planets"] == nil { t.Fatal("missing planets") } _ = a.Summary["rise_sign"] _ = b.Summary["rise_sign"] } func TestBuildOutlookScores(t *testing.T) { birth := time.Date(1990, 5, 12, 0, 0, 0, 0, time.UTC) out, err := BuildWith(BuildOpts{Birth: birth, Name: "测", AsOf: time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)}) if err != nil { t.Fatal(err) } bundle, ok := out.Summary["outlook"].(map[string]any) if !ok { t.Fatal("outlook missing") } daily, ok := bundle["daily"].(map[string]any) if !ok || daily["score"] == nil { t.Fatal("daily score missing") } if daily["lucky"] != nil { t.Fatal("legacy lucky key must be removed") } if daily["boost"] == nil { t.Fatal("boost missing") } if out.Detail["fortune_detail"] != nil { t.Fatal("legacy fortune_detail must be removed") } if out.Detail["outlook_detail"] == nil { t.Fatal("outlook_detail missing") } }