package lang import ( "strings" "testing" ) func TestGenerateRustStyleEnumAndExhaustiveMatch(t *testing.T) { prog, err := Parse(` package demo enum PaymentResult { Accepted(String), Rejected(String), Pending } fun describe(result: PaymentResult): String { var description = "" match (result) { PaymentResult::Accepted(id) -> { description = id } PaymentResult::Rejected(reason) -> { description = reason } PaymentResult::Pending -> { description = "pending" } } return description } fun main() { println(describe(PaymentResult::Accepted("p1"))) } `) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{"type PaymentResult interface", "type PaymentResultAccepted struct", "&PaymentResultAccepted{Value0: \"p1\"}", "case *PaymentResultRejected:", "reason := gotlinMatch1.Value0"} { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestRejectNonExhaustiveEnumMatch(t *testing.T) { prog, err := Parse(`package demo enum Result { Ok, Error(String) } fun use(result: Result) { match (result) { Result::Ok -> { println("ok") } } }`) if err != nil { t.Fatal(err) } _, err = GenerateGo(prog) if err == nil || !strings.Contains(err.Error(), "missing Error") { t.Fatalf("expected exhaustive-match error, got %v", err) } } func TestRejectWrongVariantPayloadCount(t *testing.T) { prog, err := Parse(`package demo enum Outcome { Ok(String) } fun main() { val result = Outcome::Ok() }`) if err != nil { t.Fatal(err) } _, err = GenerateGo(prog) if err == nil || !strings.Contains(err.Error(), "expects 1 values") { t.Fatalf("expected payload error, got %v", err) } } func TestPayloadlessEnumUsesExactVariantStrings(t *testing.T) { prog, err := Parse(`package demo enum Status { PendingReservation, Initiated } fun main() { println(Status::PendingReservation) }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{`type Status string`, `StatusPendingReservation`, `"PendingReservation"`, `StatusInitiated`, `"Initiated"`} { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestGenerateExhaustiveMatchExpression(t *testing.T) { prog, err := Parse(`package demo enum AccountType { BASIC, SAVINGS } fun interestRate(accountType: AccountType): Double { return match (accountType) { AccountType::BASIC -> 0.0 AccountType::SAVINGS -> 0.02 } }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{"func() float64", "case AccountTypeBASIC:", "return 0.0", "case AccountTypeSAVINGS:", "return 0.02", `panic("unreachable exhaustive match")`} { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestGeneratePayloadMatchExpression(t *testing.T) { prog, err := Parse(`package demo enum Outcome { Success(String), Failure(String) } fun message(outcome: Outcome): String { return match (outcome) { Outcome::Success(value) -> value Outcome::Failure(reason) -> reason } }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{"switch gotlinMatch", "value := gotlinMatch", "return value", "return reason"} { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestRejectInvalidMatchExpression(t *testing.T) { for _, test := range []struct { source string want string }{ {`package demo enum State { On, Off } fun value(state: State): Int { return match (state) { State::On -> 1 } }`, "missing Off"}, {`package demo enum State { On, Off } fun value(state: State): Int { return match (state) { State::On -> 1 State::Off -> "off" } }`, "has type String, expected Int"}, } { prog, err := Parse(test.source) if err != nil { t.Fatal(err) } _, err = GenerateGo(prog) if err == nil || !strings.Contains(err.Error(), test.want) { t.Fatalf("expected %q, got %v", test.want, err) } } }