github.com/Ali-iotechsys/sqlboiler/v4@v4.0.0-20221208124957-6aec9a5f1f71/boilingcore/boilingcore_test.go (about) 1 package boilingcore 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "regexp" 11 "strconv" 12 "testing" 13 14 "github.com/volatiletech/sqlboiler/v4/importers" 15 16 "github.com/volatiletech/sqlboiler/v4/drivers" 17 "github.com/volatiletech/sqlboiler/v4/drivers/mocks" 18 ) 19 20 var state *State 21 var rgxHasSpaces = regexp.MustCompile(`^\s+`) 22 23 func TestNew(t *testing.T) { 24 testNew(t, Aliases{}) 25 } 26 27 func TestNewWithAliases(t *testing.T) { 28 aliases := Aliases{Tables: make(map[string]TableAlias)} 29 mockDriver := mocks.MockDriver{} 30 tableNames, err := mockDriver.TableNames("", nil, nil) 31 if err != nil { 32 t.Fatal(err) 33 } 34 35 for i, tableName := range tableNames { 36 tableAlias := TableAlias{ 37 UpPlural: fmt.Sprintf("Alias%vThings", i), 38 UpSingular: fmt.Sprintf("Alias%vThing", i), 39 DownPlural: fmt.Sprintf("alias%vThings", i), 40 DownSingular: fmt.Sprintf("alias%vThing", i), 41 } 42 columns, err := mockDriver.Columns("", tableName, nil, nil) 43 if err != nil { 44 t.Fatal(err) 45 } 46 tableAlias.Columns = make(map[string]string) 47 for j, column := range columns { 48 tableAlias.Columns[column.Name] = fmt.Sprintf("Alias%vThingColumn%v", i, j) 49 } 50 tableAlias.Relationships = make(map[string]RelationshipAlias) 51 52 aliases.Tables[tableName] = tableAlias 53 } 54 55 testNew(t, aliases) 56 } 57 58 func testNew(t *testing.T, aliases Aliases) { 59 if testing.Short() { 60 t.SkipNow() 61 } 62 63 var err error 64 out, err := os.MkdirTemp("", "boil_templates") 65 if err != nil { 66 t.Fatalf("unable to create tempdir: %s", err) 67 } 68 69 // Defer cleanup of the tmp folder 70 defer func() { 71 if t.Failed() { 72 t.Log("template test output:", state.Config.OutFolder) 73 return 74 } 75 os.RemoveAll(state.Config.OutFolder) 76 }() 77 78 config := &Config{ 79 DriverName: "mock", 80 PkgName: "models", 81 OutFolder: out, 82 NoTests: true, 83 DriverConfig: map[string]interface{}{ 84 drivers.ConfigSchema: "schema", 85 drivers.ConfigBlacklist: []string{"hangars"}, 86 }, 87 Imports: importers.NewDefaultImports(), 88 TagIgnore: []string{"pass"}, 89 Aliases: aliases, 90 } 91 92 state, err = New(config) 93 if err != nil { 94 t.Fatalf("Unable to create State using config: %s", err) 95 } 96 97 if err = state.Run(); err != nil { 98 t.Errorf("Unable to execute State.Run: %s", err) 99 } 100 101 buf := &bytes.Buffer{} 102 103 cmd := exec.Command("go", "env", "GOMOD") 104 goModFilePath, err := cmd.Output() 105 if err != nil { 106 t.Fatalf("go env GOMOD cmd execution failed: %s", err) 107 } 108 109 cmd = exec.Command("go", "mod", "init", "github.com/volatiletech/sqlboiler-test") 110 cmd.Dir = state.Config.OutFolder 111 cmd.Stderr = buf 112 113 if err = cmd.Run(); err != nil { 114 t.Errorf("go mod init cmd execution failed: %s", err) 115 outputCompileErrors(buf, state.Config.OutFolder) 116 fmt.Println() 117 } 118 119 cmd = exec.Command("go", "mod", "edit", fmt.Sprintf("-replace=github.com/volatiletech/sqlboiler/v4=%s", filepath.Dir(string(goModFilePath)))) 120 cmd.Dir = state.Config.OutFolder 121 cmd.Stderr = buf 122 123 if err = cmd.Run(); err != nil { 124 t.Errorf("go mod init cmd execution failed: %s", err) 125 outputCompileErrors(buf, state.Config.OutFolder) 126 fmt.Println() 127 } 128 129 // From go1.16 dependencies are not auto downloaded 130 cmd = exec.Command("go", "mod", "tidy") 131 cmd.Dir = state.Config.OutFolder 132 cmd.Stderr = buf 133 134 if err = cmd.Run(); err != nil { 135 t.Errorf("go mod tidy cmd execution failed: %s", err) 136 outputCompileErrors(buf, state.Config.OutFolder) 137 fmt.Println() 138 } 139 140 cmd = exec.Command("go", "test", "-c") 141 cmd.Dir = state.Config.OutFolder 142 cmd.Stderr = buf 143 144 if err = cmd.Run(); err != nil { 145 t.Errorf("go test cmd execution failed: %s", err) 146 outputCompileErrors(buf, state.Config.OutFolder) 147 fmt.Println() 148 } 149 } 150 151 func outputCompileErrors(buf *bytes.Buffer, outFolder string) { 152 type errObj struct { 153 errMsg string 154 fileName string 155 lineNumber int 156 } 157 158 var errObjects []errObj 159 lineBuf := &bytes.Buffer{} 160 161 bufLines := bytes.Split(buf.Bytes(), []byte{'\n'}) 162 for i := 0; i < len(bufLines); i++ { 163 lineBuf.Reset() 164 if !bytes.HasPrefix(bufLines[i], []byte("./")) { 165 continue 166 } 167 168 fmt.Fprintf(lineBuf, "%s\n", bufLines[i]) 169 170 splits := bytes.Split(bufLines[i], []byte{':'}) 171 lineNum, err := strconv.Atoi(string(splits[1])) 172 if err != nil { 173 panic(fmt.Sprintf("Cant convert line number to int: %s", bufLines[i])) 174 } 175 176 eObj := errObj{ 177 fileName: string(splits[0]), 178 lineNumber: lineNum, 179 } 180 181 for y := i; y < len(bufLines); y++ { 182 if !rgxHasSpaces.Match(bufLines[y]) { 183 break 184 } 185 fmt.Fprintf(lineBuf, "%s\n", bufLines[y]) 186 i++ 187 } 188 189 eObj.errMsg = lineBuf.String() 190 191 errObjects = append(errObjects, eObj) 192 } 193 194 for _, eObj := range errObjects { 195 fmt.Printf("-----------------\n") 196 fmt.Println(eObj.errMsg) 197 198 filePath := filepath.Join(outFolder, eObj.fileName) 199 fh, err := os.Open(filePath) 200 if err != nil { 201 panic(fmt.Sprintf("Cant open the file: %#v", eObj)) 202 } 203 204 scanner := bufio.NewScanner(fh) 205 throwaway := eObj.lineNumber - 5 206 for throwaway > 0 && scanner.Scan() { 207 throwaway-- 208 } 209 210 for i := 0; i < 6; i++ { 211 if scanner.Scan() { 212 b := scanner.Bytes() 213 if len(b) != 0 { 214 fmt.Printf("%s\n", b) 215 } else { 216 i-- 217 } 218 } 219 } 220 221 fh.Close() 222 } 223 } 224 225 func TestProcessTypeReplacements(t *testing.T) { 226 s := new(State) 227 s.Config = &Config{} 228 s.Config.Imports.BasedOnType = make(map[string]importers.Set) 229 domainStr := "a_domain" 230 s.Tables = []drivers.Table{ 231 { 232 Columns: []drivers.Column{ 233 { 234 Name: "id", 235 Type: "int", 236 DBType: "serial", 237 Default: "some db nonsense", 238 Nullable: false, 239 }, 240 { 241 Name: "name", 242 Type: "null.String", 243 DBType: "serial", 244 Default: "some db nonsense", 245 Nullable: true, 246 }, 247 { 248 Name: "domain", 249 Type: "int", 250 DBType: "numeric", 251 Default: "some db nonsense", 252 DomainName: &domainStr, 253 Nullable: false, 254 }, 255 }, 256 }, 257 { 258 Name: "named_table", 259 Columns: []drivers.Column{ 260 { 261 Name: "id", 262 Type: "int", 263 DBType: "serial", 264 Default: "some db nonsense", 265 Nullable: false, 266 }, 267 }, 268 }, 269 } 270 271 s.Config.TypeReplaces = []TypeReplace{ 272 { 273 Match: drivers.Column{ 274 DBType: "serial", 275 }, 276 Replace: drivers.Column{ 277 Type: "excellent.Type", 278 }, 279 Imports: importers.Set{ 280 ThirdParty: []string{`"rock.com/excellent"`}, 281 }, 282 }, 283 { 284 Tables: []string{"named_table"}, 285 Match: drivers.Column{ 286 DBType: "serial", 287 }, 288 Replace: drivers.Column{ 289 Type: "excellent.NamedType", 290 }, 291 Imports: importers.Set{ 292 ThirdParty: []string{`"rock.com/excellent-name"`}, 293 }, 294 }, 295 { 296 Match: drivers.Column{ 297 Type: "null.String", 298 Nullable: true, 299 }, 300 Replace: drivers.Column{ 301 Type: "int", 302 }, 303 Imports: importers.Set{ 304 Standard: []string{`"context"`}, 305 }, 306 }, 307 { 308 Match: drivers.Column{ 309 DomainName: &domainStr, 310 }, 311 Replace: drivers.Column{ 312 Type: "big.Int", 313 }, 314 Imports: importers.Set{ 315 Standard: []string{`"math/big"`}, 316 }, 317 }, 318 } 319 320 if err := s.processTypeReplacements(); err != nil { 321 t.Fatal(err) 322 } 323 324 if typ := s.Tables[0].Columns[0].Type; typ != "excellent.Type" { 325 t.Error("type was wrong:", typ) 326 } 327 if i := s.Config.Imports.BasedOnType["excellent.Type"].ThirdParty[0]; i != `"rock.com/excellent"` { 328 t.Error("imports were not adjusted") 329 } 330 331 if typ := s.Tables[0].Columns[1].Type; typ != "int" { 332 t.Error("type was wrong:", typ) 333 } 334 if i := s.Config.Imports.BasedOnType["int"].Standard[0]; i != `"context"` { 335 t.Error("imports were not adjusted") 336 } 337 338 if typ := s.Tables[0].Columns[2].Type; typ != "big.Int" { 339 t.Error("type was wrong:", typ) 340 } 341 if i := s.Config.Imports.BasedOnType["big.Int"].Standard[0]; i != `"math/big"` { 342 t.Error("imports were not adjusted") 343 } 344 345 if typ := s.Tables[1].Columns[0].Type; typ != "excellent.NamedType" { 346 t.Error("type was wrong:", typ) 347 } 348 if i := s.Config.Imports.BasedOnType["excellent.NamedType"].ThirdParty[0]; i != `"rock.com/excellent-name"` { 349 t.Error("imports were not adjusted") 350 } 351 }