github.com/droot/goreleaser@v0.66.2-0.20180420030140-c2db5fb17157/internal/builders/golang/build_test.go (about)

     1  package golang
     2  
     3  import (
     4  	"io/ioutil"
     5  	"path/filepath"
     6  	"runtime"
     7  	"strings"
     8  	"testing"
     9  
    10  	api "github.com/goreleaser/goreleaser/build"
    11  	"github.com/goreleaser/goreleaser/config"
    12  	"github.com/goreleaser/goreleaser/context"
    13  	"github.com/goreleaser/goreleaser/internal/artifact"
    14  	"github.com/goreleaser/goreleaser/internal/testlib"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  var runtimeTarget = runtime.GOOS + "_" + runtime.GOARCH
    19  
    20  func TestWithDefaults(t *testing.T) {
    21  	for name, testcase := range map[string]struct {
    22  		build   config.Build
    23  		targets []string
    24  	}{
    25  		"full": {
    26  			build: config.Build{
    27  				Binary: "foo",
    28  				Goos: []string{
    29  					"linux",
    30  					"windows",
    31  					"darwin",
    32  				},
    33  				Goarch: []string{
    34  					"amd64",
    35  					"arm",
    36  				},
    37  				Goarm: []string{
    38  					"6",
    39  				},
    40  			},
    41  			targets: []string{
    42  				"linux_amd64",
    43  				"darwin_amd64",
    44  				"windows_amd64",
    45  				"linux_arm_6",
    46  			},
    47  		},
    48  		"empty": {
    49  			build: config.Build{
    50  				Binary: "foo",
    51  			},
    52  			targets: []string{
    53  				"linux_amd64",
    54  				"linux_386",
    55  				"darwin_amd64",
    56  				"darwin_386",
    57  			},
    58  		},
    59  	} {
    60  		t.Run(name, func(tt *testing.T) {
    61  			var config = config.Project{
    62  				Builds: []config.Build{
    63  					testcase.build,
    64  				},
    65  			}
    66  			var ctx = context.New(config)
    67  			var build = Default.WithDefaults(ctx.Config.Builds[0])
    68  			assert.ElementsMatch(t, build.Targets, testcase.targets)
    69  		})
    70  	}
    71  }
    72  
    73  func TestBuild(t *testing.T) {
    74  	folder, back := testlib.Mktmp(t)
    75  	defer back()
    76  	writeGoodMain(t, folder)
    77  	var config = config.Project{
    78  		Builds: []config.Build{
    79  			{
    80  				Binary: "foo",
    81  				Targets: []string{
    82  					"linux_amd64",
    83  					"darwin_amd64",
    84  					"windows_amd64",
    85  					"linux_arm_6",
    86  				},
    87  			},
    88  		},
    89  	}
    90  	var ctx = context.New(config)
    91  	var build = ctx.Config.Builds[0]
    92  	for _, target := range build.Targets {
    93  		var ext string
    94  		if strings.HasPrefix(target, "windows") {
    95  			ext = ".exe"
    96  		}
    97  		var err = Default.Build(ctx, build, api.Options{
    98  			Target: target,
    99  			Name:   build.Binary,
   100  			Path:   filepath.Join(folder, "dist", target, build.Binary),
   101  			Ext:    ext,
   102  		})
   103  		assert.NoError(t, err)
   104  	}
   105  	assert.ElementsMatch(t, ctx.Artifacts.List(), []artifact.Artifact{
   106  		{
   107  			Name:   "foo",
   108  			Path:   filepath.Join(folder, "dist", "linux_amd64", "foo"),
   109  			Goos:   "linux",
   110  			Goarch: "amd64",
   111  			Type:   artifact.Binary,
   112  			Extra: map[string]string{
   113  				"Ext":    "",
   114  				"Binary": "foo",
   115  			},
   116  		},
   117  		{
   118  			Name:   "foo",
   119  			Path:   filepath.Join(folder, "dist", "darwin_amd64", "foo"),
   120  			Goos:   "darwin",
   121  			Goarch: "amd64",
   122  			Type:   artifact.Binary,
   123  			Extra: map[string]string{
   124  				"Ext":    "",
   125  				"Binary": "foo",
   126  			},
   127  		},
   128  		{
   129  			Name:   "foo",
   130  			Path:   filepath.Join(folder, "dist", "linux_arm_6", "foo"),
   131  			Goos:   "linux",
   132  			Goarch: "arm",
   133  			Goarm:  "6",
   134  			Type:   artifact.Binary,
   135  			Extra: map[string]string{
   136  				"Ext":    "",
   137  				"Binary": "foo",
   138  			},
   139  		},
   140  		{
   141  			Name:   "foo",
   142  			Path:   filepath.Join(folder, "dist", "windows_amd64", "foo"),
   143  			Goos:   "windows",
   144  			Goarch: "amd64",
   145  			Type:   artifact.Binary,
   146  			Extra: map[string]string{
   147  				"Ext":    ".exe",
   148  				"Binary": "foo",
   149  			},
   150  		},
   151  	})
   152  }
   153  
   154  func TestBuildFailed(t *testing.T) {
   155  	folder, back := testlib.Mktmp(t)
   156  	defer back()
   157  	writeGoodMain(t, folder)
   158  	var config = config.Project{
   159  		Builds: []config.Build{
   160  			{
   161  				Flags: "-flag-that-dont-exists-to-force-failure",
   162  				Targets: []string{
   163  					runtimeTarget,
   164  				},
   165  			},
   166  		},
   167  	}
   168  	var ctx = context.New(config)
   169  	var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   170  		Target: "darwin_amd64",
   171  	})
   172  	assertContainsError(t, err, `flag provided but not defined: -flag-that-dont-exists-to-force-failure`)
   173  	assert.Empty(t, ctx.Artifacts.List())
   174  }
   175  
   176  func TestBuildInvalidTarget(t *testing.T) {
   177  	folder, back := testlib.Mktmp(t)
   178  	defer back()
   179  	writeGoodMain(t, folder)
   180  	var target = "linux"
   181  	var config = config.Project{
   182  		Builds: []config.Build{
   183  			{
   184  				Binary:  "foo",
   185  				Targets: []string{target},
   186  			},
   187  		},
   188  	}
   189  	var ctx = context.New(config)
   190  	var build = ctx.Config.Builds[0]
   191  	var err = Default.Build(ctx, build, api.Options{
   192  		Target: target,
   193  		Name:   build.Binary,
   194  		Path:   filepath.Join(folder, "dist", target, build.Binary),
   195  	})
   196  	assert.EqualError(t, err, "linux is not a valid build target")
   197  	assert.Len(t, ctx.Artifacts.List(), 0)
   198  }
   199  
   200  func TestRunInvalidLdflags(t *testing.T) {
   201  	folder, back := testlib.Mktmp(t)
   202  	defer back()
   203  	writeGoodMain(t, folder)
   204  	var config = config.Project{
   205  		Builds: []config.Build{
   206  			{
   207  				Binary:  "nametest",
   208  				Flags:   "-v",
   209  				Ldflags: "-s -w -X main.version={{.Version}",
   210  				Targets: []string{
   211  					runtimeTarget,
   212  				},
   213  			},
   214  		},
   215  	}
   216  	var ctx = context.New(config)
   217  	var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   218  		Target: runtimeTarget,
   219  	})
   220  	assert.EqualError(t, err, `template: ldflags:1: unexpected "}" in operand`)
   221  }
   222  
   223  func TestRunPipeWithoutMainFunc(t *testing.T) {
   224  	folder, back := testlib.Mktmp(t)
   225  	defer back()
   226  	writeMainWithoutMainFunc(t, folder)
   227  	var config = config.Project{
   228  		Builds: []config.Build{
   229  			{
   230  				Binary: "no-main",
   231  				Hooks:  config.Hooks{},
   232  				Targets: []string{
   233  					runtimeTarget,
   234  				},
   235  			},
   236  		},
   237  	}
   238  	var ctx = context.New(config)
   239  	t.Run("empty", func(t *testing.T) {
   240  		ctx.Config.Builds[0].Main = ""
   241  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   242  			Target: runtimeTarget,
   243  		}), `build for no-main does not contain a main function`)
   244  	})
   245  	t.Run("not main.go", func(t *testing.T) {
   246  		ctx.Config.Builds[0].Main = "foo.go"
   247  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   248  			Target: runtimeTarget,
   249  		}), `stat foo.go: no such file or directory`)
   250  	})
   251  	t.Run("glob", func(t *testing.T) {
   252  		ctx.Config.Builds[0].Main = "."
   253  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   254  			Target: runtimeTarget,
   255  		}), `build for no-main does not contain a main function`)
   256  	})
   257  	t.Run("fixed main.go", func(t *testing.T) {
   258  		ctx.Config.Builds[0].Main = "main.go"
   259  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   260  			Target: runtimeTarget,
   261  		}), `build for no-main does not contain a main function`)
   262  	})
   263  }
   264  
   265  func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) {
   266  	folder, back := testlib.Mktmp(t)
   267  	defer back()
   268  	assert.NoError(t, ioutil.WriteFile(
   269  		filepath.Join(folder, "foo.go"),
   270  		[]byte("package main\nfunc main() {println(0)}"),
   271  		0644,
   272  	))
   273  	var config = config.Project{
   274  		Builds: []config.Build{
   275  			{
   276  				Binary: "foo",
   277  				Hooks:  config.Hooks{},
   278  				Targets: []string{
   279  					runtimeTarget,
   280  				},
   281  			},
   282  		},
   283  	}
   284  	var ctx = context.New(config)
   285  	t.Run("empty", func(t *testing.T) {
   286  		ctx.Config.Builds[0].Main = ""
   287  		assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   288  			Target: runtimeTarget,
   289  		}))
   290  	})
   291  	t.Run("foo.go", func(t *testing.T) {
   292  		ctx.Config.Builds[0].Main = "foo.go"
   293  		assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   294  			Target: runtimeTarget,
   295  		}))
   296  	})
   297  	t.Run("glob", func(t *testing.T) {
   298  		ctx.Config.Builds[0].Main = "."
   299  		assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   300  			Target: runtimeTarget,
   301  		}))
   302  	})
   303  }
   304  
   305  func TestLdFlagsFullTemplate(t *testing.T) {
   306  	var config = config.Project{
   307  		Builds: []config.Build{
   308  			{
   309  				Ldflags: `-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}" -X main.time={{ time "20060102" }}`,
   310  			},
   311  		},
   312  	}
   313  	var ctx = &context.Context{
   314  		Git: context.GitInfo{
   315  			CurrentTag: "v1.2.3",
   316  			Commit:     "123",
   317  		},
   318  		Version: "1.2.3",
   319  		Config:  config,
   320  		Env:     map[string]string{"FOO": "123"},
   321  	}
   322  	flags, err := ldflags(ctx, ctx.Config.Builds[0])
   323  	assert.NoError(t, err)
   324  	assert.Contains(t, flags, "-s -w")
   325  	assert.Contains(t, flags, "-X main.version=1.2.3")
   326  	assert.Contains(t, flags, "-X main.tag=v1.2.3")
   327  	assert.Contains(t, flags, "-X main.commit=123")
   328  	// TODO: this will break in 2019
   329  	assert.Contains(t, flags, "-X main.date=2018")
   330  	assert.Contains(t, flags, "-X main.time=2018")
   331  	assert.Contains(t, flags, `-X "main.foo=123"`)
   332  }
   333  
   334  func TestInvalidTemplate(t *testing.T) {
   335  	for template, eerr := range map[string]string{
   336  		"{{ .Nope }":    `template: ldflags:1: unexpected "}" in operand`,
   337  		"{{.Env.NOPE}}": `template: ldflags:1:6: executing "ldflags" at <.Env.NOPE>: map has no entry for key "NOPE"`,
   338  	} {
   339  		t.Run(template, func(tt *testing.T) {
   340  			var config = config.Project{
   341  				Builds: []config.Build{
   342  					{Ldflags: template},
   343  				},
   344  			}
   345  			var ctx = &context.Context{
   346  				Config: config,
   347  			}
   348  			flags, err := ldflags(ctx, ctx.Config.Builds[0])
   349  			assert.EqualError(tt, err, eerr)
   350  			assert.Empty(tt, flags)
   351  		})
   352  	}
   353  }
   354  
   355  //
   356  // Helpers
   357  //
   358  
   359  func writeMainWithoutMainFunc(t *testing.T, folder string) {
   360  	assert.NoError(t, ioutil.WriteFile(
   361  		filepath.Join(folder, "main.go"),
   362  		[]byte("package main\nconst a = 2\nfunc notMain() {println(0)}"),
   363  		0644,
   364  	))
   365  }
   366  
   367  func writeGoodMain(t *testing.T, folder string) {
   368  	assert.NoError(t, ioutil.WriteFile(
   369  		filepath.Join(folder, "main.go"),
   370  		[]byte("package main\nvar a = 1\nfunc main() {println(0)}"),
   371  		0644,
   372  	))
   373  }
   374  
   375  func assertContainsError(t *testing.T, err error, s string) {
   376  	assert.Error(t, err)
   377  	assert.Contains(t, err.Error(), s)
   378  }