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  }