package lang import ( "strings" "testing" ) func TestResultQuestionPropagatesGoError(t *testing.T) { prog, err := Parse(`package demo import strconv fun parse(value: String): Result { val parsed = strconv.atoi(value)? return Result.Ok(parsed) }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{"parsed, gotlinError1 := strconv.Atoi(value)", "if gotlinError1 != nil {", "GotlinResult[int]{Err: gotlinError1}", "GotlinResult[int]{Value: parsed}"} { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestGoValueAndErrorReturnConvertsToResult(t *testing.T) { prog, err := Parse(`package demo import strconv fun parse(value: String): Result { return strconv.atoi(value) } fun assign(value: String) { val result: Result = strconv.atoi(value); println(result.unwrapOr(0)) }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{ "value, err := strconv.Atoi(value)", "GotlinResult[int]{Value: value, Err: err}", "var result GotlinResult[int] = func() GotlinResult[int]", } { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestGoErrorOnlyReturnConvertsToUnitResult(t *testing.T) { prog, err := Parse(`package demo import os fun changeDirectory(path: String): Result { return os.chdir(path) }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{ "func changeDirectory(path string) GotlinResult[struct{}]", "err := os.Chdir(path)", "GotlinResult[struct{}]{Err: err}", } { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestResultQuestionPropagatesGotlinResult(t *testing.T) { prog, err := Parse(`package demo import errors fun inner(ok: Boolean): Result { if (!ok) { return Result.Err(errors.new("failed")) }; return Result.Ok("ok") } fun outer(): Result { val value = inner(true)?; return Result.Ok(value) }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{"gotlinResult1 := inner(true)", "gotlinResult1.Err", "value := gotlinResult1.Value"} { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestResultUnwrapAndUnwrapOr(t *testing.T) { prog, err := Parse(`package demo fun value(result: Result): String { return result.unwrapOr("fallback") } fun required(result: Result): String { return result.unwrap() }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } for _, want := range []string{"gotlinResultUnwrapOr(result, \"fallback\")", "gotlinResultUnwrap(result)"} { if !strings.Contains(string(out), want) { t.Fatalf("missing %q:\n%s", want, out) } } } func TestQuestionRequiresResultFunction(t *testing.T) { prog, err := Parse(`package demo import strconv fun parse(value: String): Int { val parsed = strconv.atoi(value)?; return parsed }`) if err != nil { t.Fatal(err) } _, err = GenerateGo(prog) if err == nil || !strings.Contains(err.Error(), "returning Result") { t.Fatalf("unexpected error: %v", err) } } func TestQuestionUseKeepsReferencedVariableLive(t *testing.T) { prog, err := Parse(`package demo import strconv fun parse(value: String): Result { val input = value val parsed = strconv.atoi(input)? return Result.Ok(parsed) }`) if err != nil { t.Fatal(err) } out, err := GenerateGo(prog) if err != nil { t.Fatal(err) } if !strings.Contains(string(out), "input := value") || strings.Contains(string(out), "_ = value") { t.Fatalf("variable used by ? expression was removed:\n%s", out) } }