gotlin/internal/lang/compiler_test.go

1199 lines
23 KiB
Go

package lang
import (
"strings"
"testing"
)
func TestGenerateGoHello(t *testing.T) {
src := `
package demo
fun greet(name: String): String {
return "hello, " + name
}
fun main() {
val message = greet("world")
println(message)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`package demo`,
`func greet(name string) string`,
`return "hello, " + name`,
`fmt.Println(message)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoImports(t *testing.T) {
src := `
package demo
import strings
import rand math.rand
fun main() {
val upper = strings.ToUpper("go")
println(upper)
println(rand.Intn(3))
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`"strings"`,
`rand "math/rand"`,
`upper := strings.ToUpper("go")`,
`fmt.Println(rand.Intn(3))`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoQualifiedTypes(t *testing.T) {
src := `
package demo.web
import fmt
import net.http
fun helloHandler(w: http.ResponseWriter, r: *http.Request) {
fmt.Fprintln(w, "hello")
}
fun main() {
http.HandleFunc("/", helloHandler)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`package web`,
`func helloHandler(w http.ResponseWriter, r *http.Request)`,
`fmt.Fprintln(w, "hello")`,
`http.HandleFunc("/", helloHandler)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoTypedLambda(t *testing.T) {
src := `
package demo
import fmt
import net.http
fun main() {
http.HandleFunc("/", { w: http.ResponseWriter, r: *http.Request ->
fmt.Fprintln(w, "hello from lambda")
})
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {`,
`fmt.Fprintln(w, "hello from lambda")`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoTrailingLambda(t *testing.T) {
src := `
package demo
fun apply(value: String, fn: (String) -> Unit) {
fn(value)
}
fun main() {
apply("world") { value -> println(value) }
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`apply("world", func(value string) {`,
`fmt.Println(value)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoHandleFuncKotlinSyntax(t *testing.T) {
src := `
package demo
import fmt
import net.http
fun helloHandler(w: http.ResponseWriter, r: *http.Request) {
fmt.Fprintln(w, "hello")
}
fun main() {
http.HandleFunc("/") { w, r -> helloHandler(w, r) }
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {`,
`helloHandler(w, r)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoImplicitItLambda(t *testing.T) {
src := `
package demo
fun apply(value: String, fn: (String) -> Unit) {
fn(value)
}
fun main() {
apply("world", { println(it) })
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`func apply(value string, fn func(string))`,
`apply("world", func(it string) {`,
`fmt.Println(it)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoClass(t *testing.T) {
src := `
package demo
class Greeter(val name: String) {
fun greet() {
println("hello, " + name)
println(this.name)
}
}
fun main() {
val greeter = Greeter("world")
greeter.greet()
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`type Greeter struct {`,
`name string`,
`func NewGreeter(name string) *Greeter`,
`func (self *Greeter) greet() {`,
`fmt.Println("hello, " + self.name)`,
`fmt.Println(self.name)`,
`greeter := NewGreeter("world")`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoInterface(t *testing.T) {
src := `
package demo
interface Greeter {
fun greet(name: String): String
}
class ConsoleGreeter(val prefix: String) {
fun greet(name: String): String {
return prefix + name
}
}
fun greetAll(greeter: Greeter) {
println(greeter.greet("world"))
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`type Greeter interface {`,
`greet(name string) string`,
`type ConsoleGreeter struct {`,
`func (self *ConsoleGreeter) greet(name string) string {`,
`return self.prefix + name`,
`func greetAll(greeter Greeter)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoHTTPServerWithInterfaceMethodHandler(t *testing.T) {
src := `
package examples.http
import fmt
import net.http
interface EpicController {
fun hello(w: http.ResponseWriter, r: *http.Request)
}
class EpicControllerImpl: EpicController {
override fun hello(w: http.ResponseWriter, r: *http.Request) {
fmt.Fprintln(w, "hello from gotlin")
}
}
fun main() {
val epicController: EpicController = EpicControllerImpl()
fmt.Println("serving http://localhost:8080")
http.HandleFunc("/", epicController.hello)
http.ListenAndServe(":8080", http.DefaultServeMux)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`type EpicController interface {`,
`hello(w http.ResponseWriter, r *http.Request)`,
`type EpicControllerImpl struct {`,
`func NewEpicControllerImpl() *EpicControllerImpl`,
`func (self *EpicControllerImpl) hello(w http.ResponseWriter, r *http.Request) {`,
`var epicController EpicController = NewEpicControllerImpl()`,
`http.HandleFunc("/", epicController.hello)`,
`http.ListenAndServe(":8080", http.DefaultServeMux)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoAliasedStringImport(t *testing.T) {
src := `
package demo
import _ github.com.lib.pq
import database.sql
fun main() {
println(sql.Drivers())
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`_ "github.com/lib/pq"`,
`"database/sql"`,
`fmt.Println(sql.Drivers())`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoMultiAssignAndNull(t *testing.T) {
src := `
package demo
import database.sql
fun main() {
val db, err = sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")
if (err != null) {
return
}
db.Close()
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`db, err := sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")`,
`if err != nil {`,
`db.Close()`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoAutoBlankImportForSideEffects(t *testing.T) {
src := `
package demo
import github.com.lib.pq
import database.sql
fun main() {
val db, err = sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")
if (err != null) {
return
}
db.Close()
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`_ "github.com/lib/pq"`,
`"database/sql"`,
`db, err := sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoExceptionsAndRunCatching(t *testing.T) {
src := `
package demo
fun mayFail() {
throw "boom"
}
fun main() {
val result = runCatching({ mayFail() })
if (result.isSuccess()) {
println("ok")
} else {
println(result.exceptionOrNull())
}
try {
mayFail()
} catch (e: String) {
println(e)
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`type gotlinResult struct {`,
`func gotlinRunCatching(fn func()) (result gotlinResult) {`,
`panic("boom")`,
`result := gotlinRunCatching(func() {`,
`if recovered := recover(); recovered != nil {`,
`e := recovered`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoExplicitErrorsForGoErrorResults(t *testing.T) {
src := `
package demo
import database.sql
fun main() {
val db = sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")
val err = db.Ping()
if (err != null) {
throw err
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`db := sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")`,
`err := db.Ping()`,
`if err != nil {`,
`panic(err)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoMigrationInteropHelpers(t *testing.T) {
prog, err := Parse(`package demo
data class Versioned(var version: Long)
fun names(values: Map<String, Int>): List<String> { return keys(values) }
fun buffer(): ByteSlice { return ByteSlice(32) }
fun optionalError(): Error? { return null }`)
if err != nil {
t.Fatal(err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatal(err)
}
for _, want := range []string{
"Version int64",
"for key := range values",
"return make([]byte, 32)",
"func optionalError() error",
} {
if !strings.Contains(string(out), want) {
t.Fatalf("generated Go missing %q:\n%s", want, out)
}
}
}
func TestGenerateGoExplicitErrorsForErrorExprStmt(t *testing.T) {
src := `
package demo
import database.sql
fun main() {
val db = sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")
db.Ping()
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`db := sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")`,
`db.Ping()`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoClassWithoutBodyBraces(t *testing.T) {
src := `
package demo
class User(val Name: String)
fun main() {
val user = User("alice")
println(user.Name)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`type User struct {`,
`func NewUser(Name string) *User`,
`user := NewUser("alice")`,
`fmt.Println(user.Name)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoGenericListAndMapTypes(t *testing.T) {
src := `
package demo
class Store(val names: List<String>, val counts: Map<String, Int>)
fun apply(values: List<String>, f: (Map<String, Int>) -> Unit) {
f(null)
println(values)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`type Store struct {`,
`names []string`,
`counts map[string]int`,
`func NewStore(names []string, counts map[string]int) *Store`,
`func apply(values []string, f func(map[string]int))`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoListAndMapLiterals(t *testing.T) {
src := `
package demo
fun main() {
val names: List<String> = listOf("alice", "bob")
val ages: Map<String, Int> = mapOf("alice", 30, "bob", 25)
println(names)
println(ages)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`var names []string = []string{"alice", "bob"}`,
`var ages map[string]int = map[string]int{"alice": 30, "bob": 25}`,
`fmt.Println(names)`,
`fmt.Println(ages)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoListAndMapLiteralsWithCallTypeArgs(t *testing.T) {
src := `
package demo
fun main() {
val test = listOf<Int>()
val labels = mapOf<String, Int>()
println(test)
println(labels)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`test := []int{}`,
`labels := map[string]int{}`,
`fmt.Println(test)`,
`fmt.Println(labels)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoUnusedLocalDoesNotEmitNamedVariable(t *testing.T) {
src := `
package demo
fun main() {
val test = listOf<Int>(1, 7)
println("ok")
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`_ = []int{1, 7}`,
`fmt.Println("ok")`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
if strings.Contains(code, `test :=`) || strings.Contains(code, `var test `) {
t.Fatalf("generated Go should not contain named unused local:\n%s", code)
}
}
func TestGenerateGoGoStatement(t *testing.T) {
src := `
package demo
import fmt
fun runWorker(name: String) {
fmt.Println(name)
}
fun main() {
runBlocking { launch { runWorker("alice") } }
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`func runWorker(name string)`,
`fmt.Println(name)`,
`gotlinScope.Launch`,
`runWorker("alice")`,
`gotlinRunBlocking`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoForbidsWorkerSelfCalls(t *testing.T) {
src := `
package demo
worker Counter {
val n = 0
fun inc() {
inc()
}
}
`
_, err := Parse(src)
if err == nil {
t.Fatal("expected removed worker syntax error")
}
}
func TestGenerateGoRejectsValReassignment(t *testing.T) {
src := `
package demo
fun main() {
val count = 0
count = 1
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
_, err = GenerateGo(prog)
if err == nil {
t.Fatal("expected val reassignment error")
}
if !strings.Contains(err.Error(), "cannot reassign immutable name count") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestGenerateGoDefer(t *testing.T) {
src := `
package demo
import database.sql
fun main() {
val rows = sql.Open("postgres", "dsn")
defer rows.Close()
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
if !strings.Contains(string(out), "defer rows.Close()") {
t.Fatalf("generated Go missing defer:\n%s", out)
}
}
func TestGenerateGoDecimalLiteral(t *testing.T) {
src := `
package demo
fun interest(): Double {
return 0.025
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
for _, want := range []string{"func interest() float64", "return 0.025"} {
if !strings.Contains(string(out), want) {
t.Fatalf("generated Go missing %q:\n%s", want, out)
}
}
}
func TestGenerateGoRejectsMultiValReassignment(t *testing.T) {
src := `
package demo
import database.sql
fun main() {
val db, err = sql.Open("postgres", "postgres://localhost/postgres?sslmode=disable")
err = nil
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
_, err = GenerateGo(prog)
if err == nil {
t.Fatal("expected multi-val reassignment error")
}
if !strings.Contains(err.Error(), "cannot reassign immutable name err") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestGenerateGoAllowsVarReassignment(t *testing.T) {
src := `
package demo
fun main() {
var count = 0
count = 1
count += 2
println(count)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`count := 0`,
`count = 1`,
`count += 2`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoRejectsReassignmentToImmutableClassField(t *testing.T) {
src := `
package demo
class Counter(val count: Int, var total: Int) {
fun freeze() {
count = 1
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
_, err = GenerateGo(prog)
if err == nil {
t.Fatal("expected immutable class field reassignment error")
}
if !strings.Contains(err.Error(), "cannot reassign immutable name count") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestGenerateGoAllowsReassignmentToMutableClassField(t *testing.T) {
src := `
package demo
class Counter(var count: Int) {
fun inc() {
count += 1
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
if !strings.Contains(string(out), `self.count += 1`) {
t.Fatalf("generated Go missing mutable field assignment:\n%s", string(out))
}
}
func TestGenerateGoWorkerSyncPanicPropagationScaffolding(t *testing.T) {
src := `
package demo
worker Counter {
fun boom() {
throw "x"
}
}
`
_, err := Parse(src)
if err == nil {
t.Fatal("expected removed worker syntax error")
}
}
func TestParseGoStatementRequiresCall(t *testing.T) {
src := `
package demo
fun main() {
go 123
}
`
_, err := Parse(src)
if err == nil {
t.Fatal("expected parse error")
}
if !strings.Contains(err.Error(), "bare go is removed") {
t.Fatalf("unexpected parse error: %v", err)
}
}
func TestGenerateGoChannelSendAndRead(t *testing.T) {
src := `
package demo
fun writer(ch: Channel<Int>) {
ch.send(7)
}
fun main() {
val ch = Channel<Int>(1)
writer(ch)
val v = ch.read()
println(v)
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`func writer(ch chan int)`,
`ch <- 7`,
`ch := make(chan int, 1)`,
`writer(ch)`,
`v := <-ch`,
`fmt.Println(v)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}
func TestGenerateGoNoTimeImportWhenUnused(t *testing.T) {
src := `
package demo
fun main() {
println("ok")
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
if strings.Contains(code, `"time"`) {
t.Fatalf("unexpected time import in generated code:\n%s", code)
}
}
func TestGenerateGoExplicitErrorsForBunStyleCalls(t *testing.T) {
src := `
package demo
import context
import github.com.uptrace.bun
class Repo(val db: *bun.DB) {
fun run() {
val ctx = context.Background()
db.NewSelect().ColumnExpr("1").Scan(ctx)
val total = db.NewSelect().ColumnExpr("1").Count(ctx)
println(total)
}
}
`
prog, err := Parse(src)
if err != nil {
t.Fatalf("parse failed: %v", err)
}
out, err := GenerateGo(prog)
if err != nil {
t.Fatalf("go generation failed: %v", err)
}
code := string(out)
for _, want := range []string{
`self.db.NewSelect().ColumnExpr("1").Scan(ctx)`,
`total := self.db.NewSelect().ColumnExpr("1").Count(ctx)`,
`fmt.Println(total)`,
} {
if !strings.Contains(code, want) {
t.Fatalf("generated Go missing %q:\n%s", want, code)
}
}
}