github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/nix/nix_test.go (about)

     1  package nix
     2  
     3  import (
     4  	"html/template"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/goreleaser/goreleaser/internal/artifact"
    12  	"github.com/goreleaser/goreleaser/internal/client"
    13  	"github.com/goreleaser/goreleaser/internal/golden"
    14  	"github.com/goreleaser/goreleaser/internal/skips"
    15  	"github.com/goreleaser/goreleaser/internal/testctx"
    16  	"github.com/goreleaser/goreleaser/pkg/config"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestContinueOnError(t *testing.T) {
    21  	require.True(t, Pipe{}.ContinueOnError())
    22  }
    23  
    24  func TestString(t *testing.T) {
    25  	require.NotEmpty(t, Pipe{}.String())
    26  }
    27  
    28  func TestSkip(t *testing.T) {
    29  	t.Run("no-nix", func(t *testing.T) {
    30  		require.True(t, Pipe{}.Skip(testctx.New()))
    31  	})
    32  	t.Run("skip flag", func(t *testing.T) {
    33  		require.True(t, NewPublish().Skip(testctx.NewWithCfg(config.Project{
    34  			Nix: []config.Nix{{}},
    35  		}, testctx.Skip(skips.Nix))))
    36  	})
    37  	t.Run("nix-all-good", func(t *testing.T) {
    38  		require.False(t, NewPublish().Skip(testctx.NewWithCfg(config.Project{
    39  			Nix: []config.Nix{{}},
    40  		})))
    41  	})
    42  	t.Run("prefetcher-not-in-path", func(t *testing.T) {
    43  		t.Setenv("PATH", "nope")
    44  		require.True(t, NewPublish().Skip(testctx.NewWithCfg(config.Project{
    45  			Nix: []config.Nix{{}},
    46  		})))
    47  	})
    48  }
    49  
    50  const fakeNixPrefetchURLBin = "fake-nix-prefetch-url"
    51  
    52  func TestPrefetcher(t *testing.T) {
    53  	t.Run("prefetch", func(t *testing.T) {
    54  		t.Run("build", func(t *testing.T) {
    55  			sha, err := buildShaPrefetcher{}.Prefetch("any")
    56  			require.NoError(t, err)
    57  			require.Equal(t, zeroHash, sha)
    58  		})
    59  		t.Run("publish", func(t *testing.T) {
    60  			t.Run("no-nix-prefetch-url", func(t *testing.T) {
    61  				_, err := publishShaPrefetcher{fakeNixPrefetchURLBin}.Prefetch("any")
    62  				require.ErrorIs(t, err, exec.ErrNotFound)
    63  			})
    64  			t.Run("valid", func(t *testing.T) {
    65  				sha, err := publishShaPrefetcher{nixPrefetchURLBin}.Prefetch("https://github.com/goreleaser/goreleaser/releases/download/v1.18.2/goreleaser_Darwin_arm64.tar.gz")
    66  				require.NoError(t, err)
    67  				require.Equal(t, "0girjxp07srylyq36xk1ska8p68m2fhp05xgyv4wkcl61d6rzv3y", sha)
    68  			})
    69  		})
    70  	})
    71  	t.Run("available", func(t *testing.T) {
    72  		t.Run("build", func(t *testing.T) {
    73  			require.True(t, buildShaPrefetcher{}.Available())
    74  		})
    75  		t.Run("publish", func(t *testing.T) {
    76  			t.Run("no-nix-prefetch-url", func(t *testing.T) {
    77  				require.False(t, publishShaPrefetcher{fakeNixPrefetchURLBin}.Available())
    78  			})
    79  			t.Run("valid", func(t *testing.T) {
    80  				require.True(t, publishShaPrefetcher{nixPrefetchURLBin}.Available())
    81  			})
    82  		})
    83  	})
    84  }
    85  
    86  func TestRunPipe(t *testing.T) {
    87  	for _, tt := range []struct {
    88  		name                 string
    89  		expectDefaultErrorIs error
    90  		expectRunErrorIs     error
    91  		expectPublishErrorIs error
    92  		nix                  config.Nix
    93  	}{
    94  		{
    95  			name: "minimal",
    96  			nix: config.Nix{
    97  				IDs: []string{"foo"},
    98  				Repository: config.RepoRef{
    99  					Owner: "foo",
   100  					Name:  "bar",
   101  				},
   102  			},
   103  		},
   104  		{
   105  			name:                 "invalid license",
   106  			expectDefaultErrorIs: errInvalidLicense,
   107  			nix: config.Nix{
   108  				IDs:     []string{"foo"},
   109  				License: "mitt",
   110  				Repository: config.RepoRef{
   111  					Owner: "foo",
   112  					Name:  "bar",
   113  				},
   114  			},
   115  		},
   116  		{
   117  			name: "deps",
   118  			nix: config.Nix{
   119  				IDs: []string{"foo"},
   120  				Repository: config.RepoRef{
   121  					Owner: "foo",
   122  					Name:  "bar",
   123  				},
   124  				Dependencies: []config.NixDependency{
   125  					{Name: "fish"},
   126  					{Name: "bash"},
   127  					linuxDep("ttyd"),
   128  					darwinDep("chromium"),
   129  				},
   130  			},
   131  		},
   132  		{
   133  			name: "extra-install",
   134  			nix: config.Nix{
   135  				IDs: []string{"foo"},
   136  				Repository: config.RepoRef{
   137  					Owner: "foo",
   138  					Name:  "bar",
   139  				},
   140  				Dependencies: []config.NixDependency{
   141  					{Name: "fish"},
   142  					{Name: "bash"},
   143  					linuxDep("ttyd"),
   144  					darwinDep("chromium"),
   145  				},
   146  				ExtraInstall: "installManPage ./manpages/foo.1.gz",
   147  			},
   148  		},
   149  		{
   150  			name: "open-pr",
   151  			nix: config.Nix{
   152  				Name:        "foo",
   153  				IDs:         []string{"foo"},
   154  				Description: "my test",
   155  				Homepage:    "https://goreleaser.com",
   156  				License:     "mit",
   157  				Path:        "pkgs/foo.nix",
   158  				Repository: config.RepoRef{
   159  					Owner:  "foo",
   160  					Name:   "bar",
   161  					Branch: "update-{{.Version}}",
   162  					PullRequest: config.PullRequest{
   163  						Enabled: true,
   164  					},
   165  				},
   166  			},
   167  		},
   168  		{
   169  			name: "wrapped-in-dir",
   170  			nix: config.Nix{
   171  				Name:        "wrapped-in-dir",
   172  				IDs:         []string{"wrapped-in-dir"},
   173  				Description: "my test",
   174  				Homepage:    "https://goreleaser.com",
   175  				License:     "mit",
   176  				PostInstall: `
   177  					echo "do something"
   178  				`,
   179  				Install: `
   180  					mkdir -p $out/bin
   181  					cp foo $out/bin/foo
   182  				`,
   183  				ExtraInstall: "installManPage ./manpages/foo.1.gz",
   184  				Repository: config.RepoRef{
   185  					Owner: "foo",
   186  					Name:  "bar",
   187  				},
   188  			},
   189  		},
   190  		{
   191  			name: "zip",
   192  			nix: config.Nix{
   193  				Name:        "foozip",
   194  				IDs:         []string{"foo-zip"},
   195  				Description: "my test",
   196  				Homepage:    "https://goreleaser.com",
   197  				License:     "mit",
   198  				Repository: config.RepoRef{
   199  					Owner: "foo",
   200  					Name:  "bar",
   201  				},
   202  			},
   203  		},
   204  		{
   205  			name: "zip-with-dependencies",
   206  			nix: config.Nix{
   207  				Name:        "foozip",
   208  				IDs:         []string{"foo-zip"},
   209  				Description: "my test",
   210  				Homepage:    "https://goreleaser.com",
   211  				License:     "mit",
   212  				Dependencies: []config.NixDependency{
   213  					{Name: "git"},
   214  				},
   215  				Repository: config.RepoRef{
   216  					Owner: "foo",
   217  					Name:  "bar",
   218  				},
   219  			},
   220  		},
   221  		{
   222  			name: "zip-and-tar",
   223  			nix: config.Nix{
   224  				Name:        "foozip",
   225  				IDs:         []string{"zip-and-tar"},
   226  				Description: "my test",
   227  				Homepage:    "https://goreleaser.com",
   228  				License:     "mit",
   229  				Repository: config.RepoRef{
   230  					Owner: "foo",
   231  					Name:  "bar",
   232  				},
   233  			},
   234  		},
   235  		{
   236  			name:             "unibin",
   237  			expectRunErrorIs: ErrMultipleArchivesSamePlatform,
   238  			nix: config.Nix{
   239  				Name:        "unibin",
   240  				IDs:         []string{"unibin"},
   241  				Description: "my test",
   242  				Homepage:    "https://goreleaser.com",
   243  				License:     "mit",
   244  				Repository: config.RepoRef{
   245  					Owner: "foo",
   246  					Name:  "bar",
   247  				},
   248  			},
   249  		},
   250  		{
   251  			name: "no-archives",
   252  			expectRunErrorIs: errNoArchivesFound{
   253  				goamd64: "v2",
   254  				ids:     []string{"nopenopenope"},
   255  			},
   256  			nix: config.Nix{
   257  				Name:    "no-archives",
   258  				IDs:     []string{"nopenopenope"},
   259  				Goamd64: "v2",
   260  				Repository: config.RepoRef{
   261  					Owner: "foo",
   262  					Name:  "bar",
   263  				},
   264  			},
   265  		},
   266  		{
   267  			name: "unibin-replaces",
   268  			nix: config.Nix{
   269  				Name:        "unibin-replaces",
   270  				IDs:         []string{"unibin-replaces"},
   271  				Description: "my test",
   272  				Homepage:    "https://goreleaser.com",
   273  				License:     "mit",
   274  				Repository: config.RepoRef{
   275  					Owner: "foo",
   276  					Name:  "bar",
   277  				},
   278  			},
   279  		},
   280  		{
   281  			name: "partial",
   282  			nix: config.Nix{
   283  				Name: "partial",
   284  				IDs:  []string{"partial"},
   285  				Repository: config.RepoRef{
   286  					Owner: "foo",
   287  					Name:  "bar",
   288  				},
   289  			},
   290  		},
   291  		{
   292  			name:             "no-repo-name",
   293  			expectRunErrorIs: errNoRepoName,
   294  			nix: config.Nix{
   295  				Name: "doesnotmatter",
   296  				Repository: config.RepoRef{
   297  					Owner: "foo",
   298  				},
   299  			},
   300  		},
   301  		{
   302  			name:             "bad-name-tmpl",
   303  			expectRunErrorIs: &template.Error{},
   304  			nix: config.Nix{
   305  				Name: "{{ .Nope }}",
   306  				Repository: config.RepoRef{
   307  					Owner: "foo",
   308  					Name:  "bar",
   309  				},
   310  			},
   311  		},
   312  		{
   313  			name:             "bad-description-tmpl",
   314  			expectRunErrorIs: &template.Error{},
   315  			nix: config.Nix{
   316  				Description: "{{ .Nope }}",
   317  				Repository: config.RepoRef{
   318  					Owner: "foo",
   319  					Name:  "bar",
   320  				},
   321  			},
   322  		},
   323  		{
   324  			name:             "bad-homepage-tmpl",
   325  			expectRunErrorIs: &template.Error{},
   326  			nix: config.Nix{
   327  				Homepage: "{{ .Nope }}",
   328  				Repository: config.RepoRef{
   329  					Owner: "foo",
   330  					Name:  "bar",
   331  				},
   332  			},
   333  		},
   334  		{
   335  			name:             "bad-repo-tmpl",
   336  			expectRunErrorIs: &template.Error{},
   337  			nix: config.Nix{
   338  				Name: "doesnotmatter",
   339  				Repository: config.RepoRef{
   340  					Owner: "foo",
   341  					Name:  "{{ .Nope }}",
   342  				},
   343  			},
   344  		},
   345  		{
   346  			name:             "bad-skip-upload-tmpl",
   347  			expectRunErrorIs: &template.Error{},
   348  			nix: config.Nix{
   349  				Name:       "doesnotmatter",
   350  				SkipUpload: "{{ .Nope }}",
   351  				Repository: config.RepoRef{
   352  					Owner: "foo",
   353  					Name:  "bar",
   354  				},
   355  			},
   356  		},
   357  		{
   358  			name:             "bad-install-tmpl",
   359  			expectRunErrorIs: &template.Error{},
   360  			nix: config.Nix{
   361  				Name:    "foo",
   362  				Install: `{{.NoInstall}}`,
   363  				Repository: config.RepoRef{
   364  					Owner: "foo",
   365  					Name:  "bar",
   366  				},
   367  			},
   368  		},
   369  		{
   370  			name:             "bad-post-install-tmpl",
   371  			expectRunErrorIs: &template.Error{},
   372  			nix: config.Nix{
   373  				Name:        "foo",
   374  				PostInstall: `{{.NoPostInstall}}`,
   375  				Repository: config.RepoRef{
   376  					Owner: "foo",
   377  					Name:  "bar",
   378  				},
   379  			},
   380  		},
   381  		{
   382  			name:             "bad-path-tmpl",
   383  			expectRunErrorIs: &template.Error{},
   384  			nix: config.Nix{
   385  				Name: "foo",
   386  				Path: `{{.Foo}}/bar/foo.nix`,
   387  				Repository: config.RepoRef{
   388  					Owner: "foo",
   389  					Name:  "bar",
   390  				},
   391  			},
   392  		},
   393  		{
   394  			name:             "bad-release-url-tmpl",
   395  			expectRunErrorIs: &template.Error{},
   396  			nix: config.Nix{
   397  				Name:        "foo",
   398  				URLTemplate: "{{.BadURL}}",
   399  				Repository: config.RepoRef{
   400  					Owner: "foo",
   401  					Name:  "bar",
   402  				},
   403  			},
   404  		},
   405  		{
   406  			name:                 "skip-upload",
   407  			expectPublishErrorIs: errSkipUpload,
   408  			nix: config.Nix{
   409  				Name:       "doesnotmatter",
   410  				SkipUpload: "true",
   411  				IDs:        []string{"foo"},
   412  				Repository: config.RepoRef{
   413  					Owner: "foo",
   414  					Name:  "bar",
   415  				},
   416  			},
   417  		},
   418  		{
   419  			name:                 "skip-upload-auto",
   420  			expectPublishErrorIs: errSkipUploadAuto,
   421  			nix: config.Nix{
   422  				Name:       "doesnotmatter",
   423  				SkipUpload: "auto",
   424  				IDs:        []string{"foo"},
   425  				Repository: config.RepoRef{
   426  					Owner: "foo",
   427  					Name:  "bar",
   428  				},
   429  			},
   430  		},
   431  	} {
   432  		t.Run(tt.name, func(t *testing.T) {
   433  			folder := t.TempDir()
   434  			ctx := testctx.NewWithCfg(
   435  				config.Project{
   436  					Dist:        folder,
   437  					ProjectName: "foo",
   438  					Nix:         []config.Nix{tt.nix},
   439  				},
   440  				testctx.WithVersion("1.2.1"),
   441  				testctx.WithCurrentTag("v1.2.1"),
   442  				testctx.WithSemver(1, 2, 1, "rc1"),
   443  			)
   444  			createFakeArtifact := func(id, goos, goarch, goamd64, goarm, format string, extra map[string]any) {
   445  				if goarch != "arm" {
   446  					goarm = ""
   447  				}
   448  				if goarch != "amd64" {
   449  					goamd64 = ""
   450  				}
   451  				path := filepath.Join(folder, "dist/foo_"+goos+goarch+goamd64+goarm+"."+format)
   452  				art := artifact.Artifact{
   453  					Name:    "foo_" + goos + "_" + goarch + goamd64 + goarm + "." + format,
   454  					Path:    path,
   455  					Goos:    goos,
   456  					Goarch:  goarch,
   457  					Goarm:   goarm,
   458  					Goamd64: goamd64,
   459  					Type:    artifact.UploadableArchive,
   460  					Extra: map[string]interface{}{
   461  						artifact.ExtraID:        id,
   462  						artifact.ExtraFormat:    format,
   463  						artifact.ExtraBinaries:  []string{"foo"},
   464  						artifact.ExtraWrappedIn: "",
   465  					},
   466  				}
   467  				for k, v := range extra {
   468  					art.Extra[k] = v
   469  				}
   470  				ctx.Artifacts.Add(&art)
   471  
   472  				require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755))
   473  				f, err := os.Create(path)
   474  				require.NoError(t, err)
   475  				require.NoError(t, f.Close())
   476  			}
   477  
   478  			createFakeArtifact("unibin-replaces", "darwin", "all", "", "", "tar.gz", map[string]any{artifact.ExtraReplaces: true})
   479  			createFakeArtifact("unibin", "darwin", "all", "", "", "tar.gz", nil)
   480  			for _, goos := range []string{"linux", "darwin", "windows"} {
   481  				for _, goarch := range []string{"amd64", "arm64", "386", "arm"} {
   482  					if goos+goarch == "darwin386" {
   483  						continue
   484  					}
   485  					if goarch == "amd64" {
   486  						createFakeArtifact("partial", goos, goarch, "v1", "", "tar.gz", nil)
   487  						createFakeArtifact("foo", goos, goarch, "v1", "", "tar.gz", nil)
   488  						createFakeArtifact("unibin", goos, goarch, "v1", "", "tar.gz", nil)
   489  						if goos != "darwin" {
   490  							createFakeArtifact("unibin-replaces", goos, goarch, "v1", "", "tar.gz", nil)
   491  						}
   492  						createFakeArtifact("wrapped-in-dir", goos, goarch, "v1", "", "tar.gz", map[string]any{artifact.ExtraWrappedIn: "./foo_" + goarch})
   493  						createFakeArtifact("foo-zip", goos, goarch, "v1", "", "zip", nil)
   494  						continue
   495  					}
   496  					if goarch == "arm" {
   497  						if goos != "linux" {
   498  							continue
   499  						}
   500  						createFakeArtifact("foo", goos, goarch, "", "6", "tar.gz", nil)
   501  						createFakeArtifact("foo", goos, goarch, "", "7", "tar.gz", nil)
   502  						createFakeArtifact("foo-zip", goos, goarch, "", "", "zip", nil)
   503  						createFakeArtifact("unibin-replaces", goos, goarch, "", "", "tar.gz", nil)
   504  						continue
   505  					}
   506  					createFakeArtifact("foo", goos, goarch, "", "", "tar.gz", nil)
   507  					createFakeArtifact("unibin", goos, goarch, "", "", "tar.gz", nil)
   508  					if goos != "darwin" {
   509  						createFakeArtifact("unibin-replaces", goos, goarch, "", "", "tar.gz", nil)
   510  					}
   511  					createFakeArtifact("wrapped-in-dir", goos, goarch, "", "", "tar.gz", map[string]any{artifact.ExtraWrappedIn: "./foo_" + goarch})
   512  					createFakeArtifact("foo-zip", goos, goarch, "v1", "", "zip", nil)
   513  					if goos == "darwin" {
   514  						createFakeArtifact("zip-and-tar", goos, goarch, "v1", "", "zip", nil)
   515  					} else {
   516  						createFakeArtifact("zip-and-tar", goos, goarch, "v1", "", "tar.gz", nil)
   517  					}
   518  				}
   519  			}
   520  
   521  			client := client.NewMock()
   522  			bpipe := NewBuild()
   523  			ppipe := Pipe{
   524  				fakeNixShaPrefetcher{
   525  					"https://dummyhost/download/v1.2.1/foo_linux_amd64v1.tar.gz":  "sha1",
   526  					"https://dummyhost/download/v1.2.1/foo_linux_arm64.tar.gz":    "sha2",
   527  					"https://dummyhost/download/v1.2.1/foo_darwin_amd64v1.tar.gz": "sha3",
   528  					"https://dummyhost/download/v1.2.1/foo_darwin_arm64.tar.gz":   "sha4",
   529  					"https://dummyhost/download/v1.2.1/foo_darwin_all.tar.gz":     "sha5",
   530  					"https://dummyhost/download/v1.2.1/foo_linux_arm6.tar.gz":     "sha6",
   531  					"https://dummyhost/download/v1.2.1/foo_linux_arm7.tar.gz":     "sha7",
   532  					"https://dummyhost/download/v1.2.1/foo_linux_amd64v1.zip":     "sha8",
   533  					"https://dummyhost/download/v1.2.1/foo_linux_arm64.zip":       "sha9",
   534  					"https://dummyhost/download/v1.2.1/foo_darwin_amd64v1.zip":    "sha10",
   535  					"https://dummyhost/download/v1.2.1/foo_darwin_arm64.zip":      "sha11",
   536  					"https://dummyhost/download/v1.2.1/foo_darwin_all.zip":        "sha12",
   537  					"https://dummyhost/download/v1.2.1/foo_linux_arm6.zip":        "sha13",
   538  					"https://dummyhost/download/v1.2.1/foo_linux_arm7.zip":        "sha14",
   539  					"https://dummyhost/download/v1.2.1/foo_linux_386.zip":         "sha15",
   540  					"https://dummyhost/download/v1.2.1/foo_linux_386.tar.gz":      "sha16",
   541  				},
   542  			}
   543  
   544  			// default
   545  			if tt.expectDefaultErrorIs != nil {
   546  				err := bpipe.Default(ctx)
   547  				require.ErrorAs(t, err, &tt.expectDefaultErrorIs)
   548  				return
   549  
   550  			}
   551  			require.NoError(t, bpipe.Default(ctx))
   552  
   553  			// run
   554  			if tt.expectRunErrorIs != nil {
   555  				err := bpipe.runAll(ctx, client)
   556  				require.ErrorAs(t, err, &tt.expectRunErrorIs)
   557  				return
   558  			}
   559  			require.NoError(t, bpipe.runAll(ctx, client))
   560  			bts, err := os.ReadFile(ctx.Artifacts.Filter(artifact.ByType(artifact.Nixpkg)).Paths()[0])
   561  			require.NoError(t, err)
   562  			golden.RequireEqualExt(t, bts, "_build.nix")
   563  
   564  			// publish
   565  			if tt.expectPublishErrorIs != nil {
   566  				err := ppipe.publishAll(ctx, client)
   567  				require.ErrorAs(t, err, &tt.expectPublishErrorIs)
   568  				return
   569  			}
   570  			require.NoError(t, ppipe.publishAll(ctx, client))
   571  			require.True(t, client.CreatedFile)
   572  			golden.RequireEqualExt(t, []byte(client.Content), "_publish.nix")
   573  			require.NotContains(t, client.Content, strings.Repeat("0", 52))
   574  
   575  			if tt.nix.Repository.PullRequest.Enabled {
   576  				require.True(t, client.OpenedPullRequest)
   577  				require.True(t, client.SyncedFork)
   578  			}
   579  			if tt.nix.Path != "" {
   580  				require.Equal(t, tt.nix.Path, client.Path)
   581  			} else {
   582  				if tt.nix.Name == "" {
   583  					tt.nix.Name = "foo"
   584  				}
   585  				require.Equal(t, "pkgs/"+tt.nix.Name+"/default.nix", client.Path)
   586  			}
   587  		})
   588  	}
   589  }
   590  
   591  func TestErrNoArchivesFound(t *testing.T) {
   592  	require.EqualError(t, errNoArchivesFound{
   593  		goamd64: "v1",
   594  		ids:     []string{"foo", "bar"},
   595  	}, "no archives found matching goos=[darwin linux] goarch=[amd64 arm arm64 386] goarm=[6 7] goamd64=v1 ids=[foo bar]")
   596  }
   597  
   598  func TestDependencies(t *testing.T) {
   599  	require.Equal(t, []string{"nix-prefetch-url"}, Pipe{}.Dependencies(nil))
   600  }
   601  
   602  func TestBinInstallFormats(t *testing.T) {
   603  	t.Run("no-deps", func(t *testing.T) {
   604  		golden.RequireEqual(t, []byte(strings.Join(
   605  			binInstallFormats(config.Nix{}),
   606  			"\n",
   607  		)))
   608  	})
   609  	t.Run("deps", func(t *testing.T) {
   610  		golden.RequireEqual(t, []byte(strings.Join(
   611  			binInstallFormats(config.Nix{
   612  				Dependencies: []config.NixDependency{
   613  					{Name: "fish"},
   614  					{Name: "bash"},
   615  					{Name: "zsh"},
   616  				},
   617  			}),
   618  			"\n",
   619  		)))
   620  	})
   621  	t.Run("linux-only-deps", func(t *testing.T) {
   622  		golden.RequireEqual(t, []byte(strings.Join(
   623  			binInstallFormats(config.Nix{
   624  				Dependencies: []config.NixDependency{
   625  					linuxDep("foo"),
   626  					linuxDep("bar"),
   627  				},
   628  			}),
   629  			"\n",
   630  		)))
   631  	})
   632  	t.Run("darwin-only-deps", func(t *testing.T) {
   633  		golden.RequireEqual(t, []byte(strings.Join(
   634  			binInstallFormats(config.Nix{
   635  				Dependencies: []config.NixDependency{
   636  					darwinDep("foo"),
   637  					darwinDep("bar"),
   638  				},
   639  			}),
   640  			"\n",
   641  		)))
   642  	})
   643  	t.Run("mixed-deps", func(t *testing.T) {
   644  		golden.RequireEqual(t, []byte(strings.Join(
   645  			binInstallFormats(config.Nix{
   646  				Dependencies: []config.NixDependency{
   647  					{Name: "fish"},
   648  					linuxDep("foo"),
   649  					darwinDep("bar"),
   650  				},
   651  			}),
   652  			"\n",
   653  		)))
   654  	})
   655  }
   656  
   657  func darwinDep(s string) config.NixDependency {
   658  	return config.NixDependency{
   659  		Name: s,
   660  		OS:   "darwin",
   661  	}
   662  }
   663  
   664  func linuxDep(s string) config.NixDependency {
   665  	return config.NixDependency{
   666  		Name: s,
   667  		OS:   "linux",
   668  	}
   669  }
   670  
   671  type fakeNixShaPrefetcher map[string]string
   672  
   673  func (m fakeNixShaPrefetcher) Prefetch(url string) (string, error) {
   674  	return m[url], nil
   675  }
   676  func (m fakeNixShaPrefetcher) Available() bool { return true }