From ae036d15f275396f566fe38005ba2f34e7b37532 Mon Sep 17 00:00:00 2001 From: ~wispem-wantex Date: Sat, 14 Feb 2026 18:33:41 -0800 Subject: [PATCH] codegen: make test fixture factory function intelligent about what fields and values it assigns --- .../modelgenerate/generate_testfile.go | 148 +++++++++++++----- 1 file changed, 108 insertions(+), 40 deletions(-) diff --git a/pkg/codegen/modelgenerate/generate_testfile.go b/pkg/codegen/modelgenerate/generate_testfile.go index a40187c..db5a825 100644 --- a/pkg/codegen/modelgenerate/generate_testfile.go +++ b/pkg/codegen/modelgenerate/generate_testfile.go @@ -4,6 +4,7 @@ import ( "fmt" "go/ast" "go/token" + "strings" "github.com/jinzhu/inflection" @@ -11,6 +12,80 @@ import ( "git.offline-twitter.com/offline-labs/gas-stack/pkg/textutils" ) +// SampleValue returns a deterministic value of the appropriate type for the given column. +func SampleValue(c pkgschema.Column, offset int) ast.Expr { + switch c.Type { + case "integer", "int": + if strings.HasPrefix(c.Name, "is_") || strings.HasPrefix(c.Name, "has_") { + // Boolean case + if offset%2 == 0 { + return ast.NewIdent("false") + } + return ast.NewIdent("true") + } else if strings.HasSuffix(c.Name, "_at") { + // Timestamp case + return &ast.CallExpr{ + Fun: ast.NewIdent("TimestampFromUnix"), + Args: []ast.Expr{ + &ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("%d", 10000+offset)}, + }, + } + } else { + // Regular integer case + return &ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("%d", 10+offset)} + } + case "text": + if offset == 0 { + return &ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf("%q", "asdf")} + } + return &ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf("%q", fmt.Sprintf("asdf%d", offset))} + case "real": + return &ast.BasicLit{Kind: token.FLOAT, Value: fmt.Sprintf("%.2f", 1.23+float64(offset))} + case "blob": + return &ast.CompositeLit{ + Type: &ast.ArrayType{ + Elt: ast.NewIdent("byte"), + }, + Elts: func() []ast.Expr { + ret := []ast.Expr{ + &ast.BasicLit{Kind: token.INT, Value: "72"}, // 'H' + &ast.BasicLit{Kind: token.INT, Value: "105"}, // 'i' + &ast.BasicLit{Kind: token.INT, Value: "33"}, // '!' + } + for range offset { + ret = append(ret, + &ast.BasicLit{Kind: token.INT, Value: "33"}, // '!' + ) + } + return ret + }(), + } + default: + panic("Unrecognized sqlite column type: " + c.Type) + } +} + +// UpdateTestFields returns the columns for which the test generator should assign its own +// sample values, in the MakeXyz() factory and in the create/update test: the same columns +// that GenerateSaveItemFunc's "update" branch writes to, minus foreign keys (which can't be +// given plausible values here) and the auto-managed "created_at"/"updated_at" columns. +func UpdateTestFields(tbl pkgschema.Table) (ret []pkgschema.Column) { + hasCreatedAt, hasUpdatedAt := tbl.HasAutoTimestamps() + for _, c := range tbl.Columns { + if c.Name == "rowid" || c.IsPrimaryKey || c.IsForeignKey { + continue + } + if c.Name == "created_at" && hasCreatedAt { + continue + } + if c.Name == "updated_at" && hasUpdatedAt { + continue + } + ret = append(ret, c) + } + return +} + // GenerateModelTestAST produces an AST for a starter test file for a given model. func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodName string) *ast.File { packageName := "db" @@ -18,6 +93,9 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam makeHelperName := ast.NewIdent("Make" + tbl.GoTypeName) + hasCreatedAt, hasUpdatedAt := tbl.HasAutoTimestamps() + updateTestFields := UpdateTestFields(tbl) + // func MakeItem() Item { return Item{} } makeItemFunc := &ast.FuncDecl{ Name: makeHelperName, @@ -35,24 +113,15 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam Results: []ast.Expr{ &ast.CompositeLit{ Type: ast.NewIdent(tbl.GoTypeName), - Elts: []ast.Expr{ - &ast.KeyValueExpr{ - Key: ast.NewIdent("Data"), - Value: &ast.CompositeLit{ - Type: &ast.ArrayType{ - Elt: ast.NewIdent("byte"), - }, - Elts: []ast.Expr{}, - }, - }, - &ast.KeyValueExpr{ - Key: ast.NewIdent("Description"), - Value: &ast.BasicLit{ - Kind: token.STRING, - Value: `""`, - }, - }, - }, + Elts: func() (ret []ast.Expr) { + for _, c := range updateTestFields { + ret = append(ret, &ast.KeyValueExpr{ + Key: ast.NewIdent(c.GoFieldName()), + Value: SampleValue(c, 0), + }) + } + return + }(), }, }, }, @@ -62,13 +131,8 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam testObj := ast.NewIdent(textutils.CamelToPascal(tbl.GoTypeName)) testObj2 := ast.NewIdent(textutils.CamelToPascal(tbl.GoTypeName) + "2") - fieldName := ast.NewIdent("Description") // TODO - description1 := "an item" - description2 := "a big item" testDB := ast.NewIdent("TestDB") - hasCreatedAt, hasUpdatedAt := tbl.HasAutoTimestamps() - makeDeepEqual := func(obj1 *ast.Ident, obj2 *ast.Ident) *ast.IfStmt { return &ast.IfStmt{ Init: &ast.AssignStmt{ @@ -236,23 +300,22 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam Tok: token.DEFINE, Rhs: []ast.Expr{&ast.CallExpr{Fun: makeHelperName, Args: nil}}, }, - // item.Description = "an item" - &ast.AssignStmt{ + // item.Description = + // ...one assignment per updatable field + } + for _, c := range updateTestFields { + stmts = append(stmts, &ast.AssignStmt{ Lhs: []ast.Expr{ &ast.SelectorExpr{ X: testObj, - Sel: ast.NewIdent("Description"), + Sel: ast.NewIdent(c.GoFieldName()), }, }, Tok: token.ASSIGN, - Rhs: []ast.Expr{ - &ast.BasicLit{ - Kind: token.STRING, - Value: fmt.Sprintf("%q", description1), - }, - }, - }, - + Rhs: []ast.Expr{SampleValue(c, 1)}, + }) + } + stmts = append(stmts, // TestDB.SaveItem(&item), possibly with error check &ast.ExprStmt{X: func() *ast.CallExpr { mainExpr := &ast.CallExpr{ @@ -274,7 +337,7 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam Fun: &ast.SelectorExpr{X: ast.NewIdent("require"), Sel: ast.NewIdent("NotZero")}, Args: []ast.Expr{ast.NewIdent("t"), &ast.SelectorExpr{X: testObj, Sel: ast.NewIdent("ID")}}, }}, - } + ) // After create: assert timestamps are set if hasCreatedAt { @@ -305,14 +368,19 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam stmts = append(stmts, BlankLine(), Comment("Update"), + ) - // item.Description = "a big item" - &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: fieldName}}, + // item.Description = + // ...one assignment per updatable field + for _, c := range updateTestFields { + stmts = append(stmts, &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.SelectorExpr{X: testObj, Sel: ast.NewIdent(c.GoFieldName())}}, Tok: token.ASSIGN, - Rhs: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf("%q", description2)}}, - }, + Rhs: []ast.Expr{SampleValue(c, 2)}, + }) + } + stmts = append(stmts, // TestDB.SaveItem(&item) &ast.ExprStmt{X: &ast.CallExpr{ Fun: &ast.SelectorExpr{X: testDB, Sel: ast.NewIdent("Save" + tbl.GoTypeName)},