gopkg.in/tools/godep.v21@v21.0.0-20151104013723-2cf1d6e3f557/save_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io/ioutil"
     7  	"math"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"reflect"
    12  	"strings"
    13  	"testing"
    14  	"text/template"
    15  )
    16  
    17  // node represents a file tree or a VCS repo
    18  type node struct {
    19  	path    string      // file name or commit type
    20  	body    interface{} // file contents or commit tag
    21  	entries []*node     // nil if the entry is a file
    22  }
    23  
    24  var (
    25  	pkgtpl = template.Must(template.New("package").Parse(`package {{.Name}}
    26  
    27  import (
    28  {{range .Imports}}	{{printf "%q" .}}
    29  {{end}})
    30  `))
    31  )
    32  
    33  func pkg(name string, pkg ...string) string {
    34  	v := struct {
    35  		Name    string
    36  		Imports []string
    37  	}{name, pkg}
    38  	var buf bytes.Buffer
    39  	err := pkgtpl.Execute(&buf, v)
    40  	if err != nil {
    41  		panic(err)
    42  	}
    43  	return buf.String()
    44  }
    45  
    46  func decl(name string) string {
    47  	return "var " + name + " int\n"
    48  }
    49  
    50  func godeps(importpath string, keyval ...string) *Godeps {
    51  	g := &Godeps{
    52  		ImportPath: importpath,
    53  	}
    54  	for i := 0; i < len(keyval); i += 2 {
    55  		g.Deps = append(g.Deps, Dependency{
    56  			ImportPath: keyval[i],
    57  			Comment:    keyval[i+1],
    58  		})
    59  	}
    60  	return g
    61  }
    62  
    63  func TestSave(t *testing.T) {
    64  	var cases = []struct {
    65  		cwd      string
    66  		args     []string
    67  		flagR    bool
    68  		flagT    bool
    69  		start    []*node
    70  		altstart []*node
    71  		want     []*node
    72  		wdep     Godeps
    73  		werr     bool
    74  	}{
    75  		{ // simple case, one dependency
    76  			cwd: "C",
    77  			start: []*node{
    78  				{
    79  					"C",
    80  					"",
    81  					[]*node{
    82  						{"main.go", pkg("main", "D"), nil},
    83  						{"+git", "", nil},
    84  					},
    85  				},
    86  				{
    87  					"D",
    88  					"",
    89  					[]*node{
    90  						{"main.go", pkg("D"), nil},
    91  						{"+git", "D1", nil},
    92  					},
    93  				},
    94  			},
    95  			want: []*node{
    96  				{"C/main.go", pkg("main", "D"), nil},
    97  				{"C/Godeps/_workspace/src/D/main.go", pkg("D"), nil},
    98  			},
    99  			wdep: Godeps{
   100  				ImportPath: "C",
   101  				Deps: []Dependency{
   102  					{ImportPath: "D", Comment: "D1"},
   103  				},
   104  			},
   105  		},
   106  		{ // strip import comment
   107  			cwd: "C",
   108  			start: []*node{
   109  				{
   110  					"C",
   111  					"",
   112  					[]*node{
   113  						{"main.go", pkg("main", "D"), nil},
   114  						{"+git", "", nil},
   115  					},
   116  				},
   117  				{
   118  					"D",
   119  					"",
   120  					[]*node{
   121  						{"main.go", `package D // import "D"`, nil},
   122  						{"+git", "D1", nil},
   123  					},
   124  				},
   125  			},
   126  			want: []*node{
   127  				{"C/main.go", pkg("main", "D"), nil},
   128  				{"C/Godeps/_workspace/src/D/main.go", "package D\n", nil},
   129  			},
   130  			wdep: Godeps{
   131  				ImportPath: "C",
   132  				Deps: []Dependency{
   133  					{ImportPath: "D", Comment: "D1"},
   134  				},
   135  			},
   136  		},
   137  		{
   138  			// dependency in same repo with existing manifest
   139  			// see bug https://github.com/tools/godep/issues/69
   140  			cwd:  "P",
   141  			args: []string{"./..."},
   142  			start: []*node{
   143  				{
   144  					"P",
   145  					"",
   146  					[]*node{
   147  						{"main.go", pkg("P", "P/Q"), nil},
   148  						{"Q/main.go", pkg("Q"), nil},
   149  						{"Godeps/Godeps.json", `{}`, nil},
   150  						{"+git", "C1", nil},
   151  					},
   152  				},
   153  			},
   154  			want: []*node{
   155  				{"P/main.go", pkg("P", "P/Q"), nil},
   156  				{"P/Q/main.go", pkg("Q"), nil},
   157  			},
   158  			wdep: Godeps{
   159  				ImportPath: "P",
   160  				Deps:       []Dependency{},
   161  			},
   162  		},
   163  		{
   164  			// dependency on parent directory in same repo
   165  			// see bug https://github.com/tools/godep/issues/70
   166  			cwd:  "P",
   167  			args: []string{"./..."},
   168  			start: []*node{
   169  				{
   170  					"P",
   171  					"",
   172  					[]*node{
   173  						{"main.go", pkg("P"), nil},
   174  						{"Q/main.go", pkg("Q", "P"), nil},
   175  						{"+git", "C1", nil},
   176  					},
   177  				},
   178  			},
   179  			want: []*node{
   180  				{"P/main.go", pkg("P"), nil},
   181  				{"P/Q/main.go", pkg("Q", "P"), nil},
   182  			},
   183  			wdep: Godeps{
   184  				ImportPath: "P",
   185  				Deps:       []Dependency{},
   186  			},
   187  		},
   188  		{ // transitive dependency
   189  			cwd: "C",
   190  			start: []*node{
   191  				{
   192  					"C",
   193  					"",
   194  					[]*node{
   195  						{"main.go", pkg("main", "D"), nil},
   196  						{"+git", "", nil},
   197  					},
   198  				},
   199  				{
   200  					"D",
   201  					"",
   202  					[]*node{
   203  						{"main.go", pkg("D", "T"), nil},
   204  						{"+git", "D1", nil},
   205  					},
   206  				},
   207  				{
   208  					"T",
   209  					"",
   210  					[]*node{
   211  						{"main.go", pkg("T"), nil},
   212  						{"+git", "T1", nil},
   213  					},
   214  				},
   215  			},
   216  			want: []*node{
   217  				{"C/main.go", pkg("main", "D"), nil},
   218  				{"C/Godeps/_workspace/src/D/main.go", pkg("D", "T"), nil},
   219  				{"C/Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   220  			},
   221  			wdep: Godeps{
   222  				ImportPath: "C",
   223  				Deps: []Dependency{
   224  					{ImportPath: "D", Comment: "D1"},
   225  					{ImportPath: "T", Comment: "T1"},
   226  				},
   227  			},
   228  		},
   229  		{ // two packages, one in a subdirectory
   230  			cwd: "C",
   231  			start: []*node{
   232  				{
   233  					"C",
   234  					"",
   235  					[]*node{
   236  						{"main.go", pkg("main", "D", "D/P"), nil},
   237  						{"+git", "", nil},
   238  					},
   239  				},
   240  				{
   241  					"D",
   242  					"",
   243  					[]*node{
   244  						{"main.go", pkg("D"), nil},
   245  						{"P/main.go", pkg("P"), nil},
   246  						{"+git", "D1", nil},
   247  					},
   248  				},
   249  			},
   250  			want: []*node{
   251  				{"C/main.go", pkg("main", "D", "D/P"), nil},
   252  				{"C/Godeps/_workspace/src/D/main.go", pkg("D"), nil},
   253  				{"C/Godeps/_workspace/src/D/P/main.go", pkg("P"), nil},
   254  			},
   255  			wdep: Godeps{
   256  				ImportPath: "C",
   257  				Deps: []Dependency{
   258  					{ImportPath: "D", Comment: "D1"},
   259  				},
   260  			},
   261  		},
   262  		{ // repo root is not a package (no go files)
   263  			cwd: "C",
   264  			start: []*node{
   265  				{
   266  					"C",
   267  					"",
   268  					[]*node{
   269  						{"main.go", pkg("main", "D/P", "D/Q"), nil},
   270  						{"+git", "", nil},
   271  					},
   272  				},
   273  				{
   274  					"D",
   275  					"",
   276  					[]*node{
   277  						{"P/main.go", pkg("P"), nil},
   278  						{"Q/main.go", pkg("Q"), nil},
   279  						{"+git", "D1", nil},
   280  					},
   281  				},
   282  			},
   283  			want: []*node{
   284  				{"C/main.go", pkg("main", "D/P", "D/Q"), nil},
   285  				{"C/Godeps/_workspace/src/D/P/main.go", pkg("P"), nil},
   286  				{"C/Godeps/_workspace/src/D/Q/main.go", pkg("Q"), nil},
   287  			},
   288  			wdep: Godeps{
   289  				ImportPath: "C",
   290  				Deps: []Dependency{
   291  					{ImportPath: "D/P", Comment: "D1"},
   292  					{ImportPath: "D/Q", Comment: "D1"},
   293  				},
   294  			},
   295  		},
   296  		{ // symlink
   297  			cwd: "C",
   298  			start: []*node{
   299  				{
   300  					"C",
   301  					"",
   302  					[]*node{
   303  						{"main.x", pkg("main", "D"), nil},
   304  						{"main.go", "symlink:main.x", nil},
   305  						{"+git", "", nil},
   306  					},
   307  				},
   308  				{
   309  					"D",
   310  					"",
   311  					[]*node{
   312  						{"main.go", pkg("D"), nil},
   313  						{"+git", "D1", nil},
   314  					},
   315  				},
   316  			},
   317  			want: []*node{
   318  				{"C/main.go", pkg("main", "D"), nil},
   319  				{"C/Godeps/_workspace/src/D/main.go", pkg("D"), nil},
   320  			},
   321  			wdep: Godeps{
   322  				ImportPath: "C",
   323  				Deps: []Dependency{
   324  					{ImportPath: "D", Comment: "D1"},
   325  				},
   326  			},
   327  		},
   328  		{ // add one dependency; keep other dependency version
   329  			cwd: "C",
   330  			start: []*node{
   331  				{
   332  					"D",
   333  					"",
   334  					[]*node{
   335  						{"main.go", pkg("D") + decl("D1"), nil},
   336  						{"+git", "D1", nil},
   337  						{"main.go", pkg("D") + decl("D2"), nil},
   338  						{"+git", "D2", nil},
   339  					},
   340  				},
   341  				{
   342  					"E",
   343  					"",
   344  					[]*node{
   345  						{"main.go", pkg("E"), nil},
   346  						{"+git", "E1", nil},
   347  					},
   348  				},
   349  				{
   350  					"C",
   351  					"",
   352  					[]*node{
   353  						{"main.go", pkg("main", "D", "E"), nil},
   354  						{"Godeps/Godeps.json", godeps("C", "D", "D1"), nil},
   355  						{"Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   356  						{"+git", "", nil},
   357  					},
   358  				},
   359  			},
   360  			want: []*node{
   361  				{"C/main.go", pkg("main", "D", "E"), nil},
   362  				{"C/Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   363  				{"C/Godeps/_workspace/src/E/main.go", pkg("E"), nil},
   364  			},
   365  			wdep: Godeps{
   366  				ImportPath: "C",
   367  				Deps: []Dependency{
   368  					{ImportPath: "D", Comment: "D1"},
   369  					{ImportPath: "E", Comment: "E1"},
   370  				},
   371  			},
   372  		},
   373  		{ // remove one dependency; keep other dependency version
   374  			cwd: "C",
   375  			start: []*node{
   376  				{
   377  					"D",
   378  					"",
   379  					[]*node{
   380  						{"main.go", pkg("D") + decl("D1"), nil},
   381  						{"+git", "D1", nil},
   382  						{"main.go", pkg("D") + decl("D2"), nil},
   383  						{"+git", "D2", nil},
   384  					},
   385  				},
   386  				{
   387  					"E",
   388  					"",
   389  					[]*node{
   390  						{"main.go", pkg("E") + decl("E1"), nil},
   391  						{"+git", "E1", nil},
   392  					},
   393  				},
   394  				{
   395  					"C",
   396  					"",
   397  					[]*node{
   398  						{"main.go", pkg("main", "D"), nil},
   399  						{"Godeps/Godeps.json", godeps("C", "D", "D1", "E", "E1"), nil},
   400  						{"Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   401  						{"Godeps/_workspace/src/E/main.go", pkg("E") + decl("E1"), nil},
   402  						{"+git", "", nil},
   403  					},
   404  				},
   405  			},
   406  			want: []*node{
   407  				{"C/Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   408  				{"C/Godeps/_workspace/src/E/main.go", "(absent)", nil},
   409  			},
   410  			wdep: Godeps{
   411  				ImportPath: "C",
   412  				Deps: []Dependency{
   413  					{ImportPath: "D", Comment: "D1"},
   414  				},
   415  			},
   416  		},
   417  		{ // add one dependency from same repo
   418  			cwd: "C",
   419  			start: []*node{
   420  				{
   421  					"D",
   422  					"",
   423  					[]*node{
   424  						{"A/main.go", pkg("A") + decl("A1"), nil},
   425  						{"B/main.go", pkg("B") + decl("B1"), nil},
   426  						{"+git", "D1", nil},
   427  					},
   428  				},
   429  				{
   430  					"C",
   431  					"",
   432  					[]*node{
   433  						{"main.go", pkg("main", "D/A", "D/B"), nil},
   434  						{"Godeps/Godeps.json", godeps("C", "D/A", "D1"), nil},
   435  						{"Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   436  						{"+git", "", nil},
   437  					},
   438  				},
   439  			},
   440  			want: []*node{
   441  				{"C/Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   442  				{"C/Godeps/_workspace/src/D/B/main.go", pkg("B") + decl("B1"), nil},
   443  			},
   444  			wdep: Godeps{
   445  				ImportPath: "C",
   446  				Deps: []Dependency{
   447  					{ImportPath: "D/A", Comment: "D1"},
   448  					{ImportPath: "D/B", Comment: "D1"},
   449  				},
   450  			},
   451  		},
   452  		{ // add one dependency from same repo, require same version
   453  			cwd: "C",
   454  			start: []*node{
   455  				{
   456  					"D",
   457  					"",
   458  					[]*node{
   459  						{"A/main.go", pkg("A") + decl("A1"), nil},
   460  						{"B/main.go", pkg("B") + decl("B1"), nil},
   461  						{"+git", "D1", nil},
   462  						{"A/main.go", pkg("A") + decl("A2"), nil},
   463  						{"B/main.go", pkg("B") + decl("B2"), nil},
   464  						{"+git", "D2", nil},
   465  					},
   466  				},
   467  				{
   468  					"C",
   469  					"",
   470  					[]*node{
   471  						{"main.go", pkg("main", "D/A", "D/B"), nil},
   472  						{"Godeps/Godeps.json", godeps("C", "D/A", "D1"), nil},
   473  						{"Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   474  						{"+git", "", nil},
   475  					},
   476  				},
   477  			},
   478  			want: []*node{
   479  				{"C/Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   480  			},
   481  			wdep: Godeps{
   482  				ImportPath: "C",
   483  				Deps: []Dependency{
   484  					{ImportPath: "D/A", Comment: "D1"},
   485  				},
   486  			},
   487  			werr: true,
   488  		},
   489  		{ // replace dependency from same repo parent dir
   490  			cwd: "C",
   491  			start: []*node{
   492  				{
   493  					"D",
   494  					"",
   495  					[]*node{
   496  						{"main.go", pkg("D") + decl("D1"), nil},
   497  						{"A/main.go", pkg("A") + decl("A1"), nil},
   498  						{"+git", "D1", nil},
   499  					},
   500  				},
   501  				{
   502  					"C",
   503  					"",
   504  					[]*node{
   505  						{"main.go", pkg("main", "D"), nil},
   506  						{"Godeps/Godeps.json", godeps("C", "D/A", "D1"), nil},
   507  						{"Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   508  						{"+git", "", nil},
   509  					},
   510  				},
   511  			},
   512  			want: []*node{
   513  				{"C/Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   514  				{"C/Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   515  			},
   516  			wdep: Godeps{
   517  				ImportPath: "C",
   518  				Deps: []Dependency{
   519  					{ImportPath: "D", Comment: "D1"},
   520  				},
   521  			},
   522  		},
   523  		{ // replace dependency from same repo parent dir, require same version
   524  			cwd: "C",
   525  			start: []*node{
   526  				{
   527  					"D",
   528  					"",
   529  					[]*node{
   530  						{"main.go", pkg("D") + decl("D1"), nil},
   531  						{"A/main.go", pkg("A") + decl("A1"), nil},
   532  						{"+git", "D1", nil},
   533  						{"main.go", pkg("D") + decl("D2"), nil},
   534  						{"A/main.go", pkg("A") + decl("A2"), nil},
   535  						{"+git", "D2", nil},
   536  					},
   537  				},
   538  				{
   539  					"C",
   540  					"",
   541  					[]*node{
   542  						{"main.go", pkg("main", "D"), nil},
   543  						{"Godeps/Godeps.json", godeps("C", "D/A", "D1"), nil},
   544  						{"Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   545  						{"+git", "", nil},
   546  					},
   547  				},
   548  			},
   549  			want: []*node{
   550  				{"C/Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   551  			},
   552  			wdep: Godeps{
   553  				ImportPath: "C",
   554  				Deps: []Dependency{
   555  					{ImportPath: "D/A", Comment: "D1"},
   556  				},
   557  			},
   558  			werr: true,
   559  		},
   560  		{ // replace dependency from same repo child dir
   561  			cwd: "C",
   562  			start: []*node{
   563  				{
   564  					"D",
   565  					"",
   566  					[]*node{
   567  						{"main.go", pkg("D") + decl("D1"), nil},
   568  						{"A/main.go", pkg("A") + decl("A1"), nil},
   569  						{"+git", "D1", nil},
   570  					},
   571  				},
   572  				{
   573  					"C",
   574  					"",
   575  					[]*node{
   576  						{"main.go", pkg("main", "D/A"), nil},
   577  						{"Godeps/Godeps.json", godeps("C", "D", "D1"), nil},
   578  						{"Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   579  						{"Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   580  						{"+git", "", nil},
   581  					},
   582  				},
   583  			},
   584  			want: []*node{
   585  				{"C/Godeps/_workspace/src/D/main.go", "(absent)", nil},
   586  				{"C/Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   587  			},
   588  			wdep: Godeps{
   589  				ImportPath: "C",
   590  				Deps: []Dependency{
   591  					{ImportPath: "D/A", Comment: "D1"},
   592  				},
   593  			},
   594  		},
   595  		{ // replace dependency from same repo child dir, require same version
   596  			cwd: "C",
   597  			start: []*node{
   598  				{
   599  					"D",
   600  					"",
   601  					[]*node{
   602  						{"main.go", pkg("D") + decl("D1"), nil},
   603  						{"A/main.go", pkg("A") + decl("A1"), nil},
   604  						{"+git", "D1", nil},
   605  						{"main.go", pkg("D") + decl("D2"), nil},
   606  						{"A/main.go", pkg("A") + decl("A2"), nil},
   607  						{"+git", "D2", nil},
   608  					},
   609  				},
   610  				{
   611  					"C",
   612  					"",
   613  					[]*node{
   614  						{"main.go", pkg("main", "D/A"), nil},
   615  						{"Godeps/Godeps.json", godeps("C", "D", "D1"), nil},
   616  						{"Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   617  						{"Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   618  						{"+git", "", nil},
   619  					},
   620  				},
   621  			},
   622  			want: []*node{
   623  				{"C/Godeps/_workspace/src/D/main.go", pkg("D") + decl("D1"), nil},
   624  				{"C/Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   625  			},
   626  			wdep: Godeps{
   627  				ImportPath: "C",
   628  				Deps: []Dependency{
   629  					{ImportPath: "D", Comment: "D1"},
   630  				},
   631  			},
   632  			werr: true,
   633  		},
   634  		{ // Bug https://github.com/tools/godep/issues/85
   635  			cwd: "C",
   636  			start: []*node{
   637  				{
   638  					"D",
   639  					"",
   640  					[]*node{
   641  						{"A/main.go", pkg("A") + decl("A1"), nil},
   642  						{"B/main.go", pkg("B") + decl("B1"), nil},
   643  						{"+git", "D1", nil},
   644  						{"A/main.go", pkg("A") + decl("A2"), nil},
   645  						{"B/main.go", pkg("B") + decl("B2"), nil},
   646  						{"+git", "D2", nil},
   647  					},
   648  				},
   649  				{
   650  					"C",
   651  					"",
   652  					[]*node{
   653  						{"main.go", pkg("main", "D/A", "D/B"), nil},
   654  						{"Godeps/Godeps.json", godeps("C", "D/A", "D1", "D/B", "D1"), nil},
   655  						{"Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   656  						{"Godeps/_workspace/src/D/B/main.go", pkg("B") + decl("B1"), nil},
   657  						{"+git", "", nil},
   658  					},
   659  				},
   660  			},
   661  			want: []*node{
   662  				{"C/Godeps/_workspace/src/D/A/main.go", pkg("A") + decl("A1"), nil},
   663  				{"C/Godeps/_workspace/src/D/B/main.go", pkg("B") + decl("B1"), nil},
   664  			},
   665  			wdep: Godeps{
   666  				ImportPath: "C",
   667  				Deps: []Dependency{
   668  					{ImportPath: "D/A", Comment: "D1"},
   669  					{ImportPath: "D/B", Comment: "D1"},
   670  				},
   671  			},
   672  		},
   673  		{ // intermediate dependency that uses godep save -r, main -r=false
   674  			cwd: "C",
   675  			start: []*node{
   676  				{
   677  					"C",
   678  					"",
   679  					[]*node{
   680  						{"main.go", pkg("main", "D"), nil},
   681  						{"+git", "", nil},
   682  					},
   683  				},
   684  				{
   685  					"T",
   686  					"",
   687  					[]*node{
   688  						{"main.go", pkg("T"), nil},
   689  						{"+git", "T1", nil},
   690  					},
   691  				},
   692  				{
   693  					"D",
   694  					"",
   695  					[]*node{
   696  						{"main.go", pkg("D", "D/Godeps/_workspace/src/T"), nil},
   697  						{"Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   698  						{"Godeps/Godeps.json", godeps("D", "T", "T1"), nil},
   699  						{"+git", "D1", nil},
   700  					},
   701  				},
   702  			},
   703  			want: []*node{
   704  				{"C/main.go", pkg("main", "D"), nil},
   705  				{"C/Godeps/_workspace/src/D/main.go", pkg("D", "T"), nil},
   706  				{"C/Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   707  			},
   708  			wdep: Godeps{
   709  				ImportPath: "C",
   710  				Deps: []Dependency{
   711  					{ImportPath: "D", Comment: "D1"},
   712  					{ImportPath: "T", Comment: "T1"},
   713  				},
   714  			},
   715  		},
   716  		{ // intermediate dependency that uses godep save -r, main -r too
   717  			cwd:   "C",
   718  			flagR: true,
   719  			start: []*node{
   720  				{
   721  					"C",
   722  					"",
   723  					[]*node{
   724  						{"main.go", pkg("main", "D"), nil},
   725  						{"+git", "", nil},
   726  					},
   727  				},
   728  				{
   729  					"T",
   730  					"",
   731  					[]*node{
   732  						{"main.go", pkg("T"), nil},
   733  						{"+git", "T1", nil},
   734  					},
   735  				},
   736  				{
   737  					"D",
   738  					"",
   739  					[]*node{
   740  						{"main.go", pkg("D", "D/Godeps/_workspace/src/T"), nil},
   741  						{"Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   742  						{"Godeps/Godeps.json", godeps("D", "T", "T1"), nil},
   743  						{"+git", "D1", nil},
   744  					},
   745  				},
   746  			},
   747  			want: []*node{
   748  				{"C/main.go", pkg("main", "C/Godeps/_workspace/src/D"), nil},
   749  				{"C/Godeps/_workspace/src/D/main.go", pkg("D", "C/Godeps/_workspace/src/T"), nil},
   750  				{"C/Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   751  			},
   752  			wdep: Godeps{
   753  				ImportPath: "C",
   754  				Deps: []Dependency{
   755  					{ImportPath: "D", Comment: "D1"},
   756  					{ImportPath: "T", Comment: "T1"},
   757  				},
   758  			},
   759  		},
   760  		{ // rewrite files under build constraints
   761  			cwd:   "C",
   762  			flagR: true,
   763  			start: []*node{
   764  				{
   765  					"C",
   766  					"",
   767  					[]*node{
   768  						{"main.go", pkg("main", "D"), nil},
   769  						{"x.go", "// +build x\n\n" + pkg("main", "D"), nil},
   770  						{"+git", "", nil},
   771  					},
   772  				},
   773  				{
   774  					"D",
   775  					"",
   776  					[]*node{
   777  						{"main.go", pkg("D"), nil},
   778  						{"+git", "D1", nil},
   779  					},
   780  				},
   781  			},
   782  			want: []*node{
   783  				{"C/main.go", pkg("main", "C/Godeps/_workspace/src/D"), nil},
   784  				{"C/x.go", "// +build x\n\n" + pkg("main", "C/Godeps/_workspace/src/D"), nil},
   785  				{"C/Godeps/_workspace/src/D/main.go", pkg("D"), nil},
   786  			},
   787  			wdep: Godeps{
   788  				ImportPath: "C",
   789  				Deps: []Dependency{
   790  					{ImportPath: "D", Comment: "D1"},
   791  				},
   792  			},
   793  		},
   794  		{ // exclude dependency subdirectories even when obtained by a rewritten import path
   795  			cwd: "C",
   796  			start: []*node{
   797  				{
   798  					"C",
   799  					"",
   800  					[]*node{
   801  						{"main.go", pkg("main", "D", "T"), nil},
   802  						{"+git", "", nil},
   803  					},
   804  				},
   805  				{
   806  					"T",
   807  					"",
   808  					[]*node{
   809  						{"main.go", pkg("T"), nil},
   810  						{"X/main.go", pkg("X"), nil},
   811  						{"+git", "T1", nil},
   812  					},
   813  				},
   814  				{
   815  					"D",
   816  					"",
   817  					[]*node{
   818  						{"main.go", pkg("D", "D/Godeps/_workspace/src/T/X"), nil},
   819  						{"Godeps/_workspace/src/T/X/main.go", pkg("X"), nil},
   820  						{"Godeps/Godeps.json", godeps("D", "T/X", "T1"), nil},
   821  						{"+git", "D1", nil},
   822  					},
   823  				},
   824  			},
   825  			want: []*node{
   826  				{"C/main.go", pkg("main", "D", "T"), nil},
   827  				{"C/Godeps/_workspace/src/D/main.go", pkg("D", "T/X"), nil},
   828  				{"C/Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   829  			},
   830  			wdep: Godeps{
   831  				ImportPath: "C",
   832  				Deps: []Dependency{
   833  					{ImportPath: "D", Comment: "D1"},
   834  					{ImportPath: "T", Comment: "T1"},
   835  				},
   836  			},
   837  		},
   838  		{ // find transitive dependencies across roots
   839  			cwd:   "C",
   840  			flagR: true,
   841  			altstart: []*node{
   842  				{
   843  					"T",
   844  					"",
   845  					[]*node{
   846  						{"main.go", pkg("T"), nil},
   847  						{"+git", "T1", nil},
   848  					},
   849  				},
   850  			},
   851  			start: []*node{
   852  				{
   853  					"C",
   854  					"",
   855  					[]*node{
   856  						{"main.go", pkg("main", "D"), nil},
   857  						{"+git", "", nil},
   858  					},
   859  				},
   860  				{
   861  					"D",
   862  					"",
   863  					[]*node{
   864  						{"main.go", pkg("D", "D/Godeps/_workspace/src/T"), nil},
   865  						{"Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   866  						{"Godeps/Godeps.json", godeps("D", "T", "T1"), nil},
   867  						{"+git", "D1", nil},
   868  					},
   869  				},
   870  			},
   871  			want: []*node{
   872  				{"C/main.go", pkg("main", "C/Godeps/_workspace/src/D"), nil},
   873  				{"C/Godeps/_workspace/src/D/main.go", pkg("D", "C/Godeps/_workspace/src/T"), nil},
   874  				{"C/Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   875  			},
   876  			wdep: Godeps{
   877  				ImportPath: "C",
   878  				Deps: []Dependency{
   879  					{ImportPath: "D", Comment: "D1"},
   880  					{ImportPath: "T", Comment: "T1"},
   881  				},
   882  			},
   883  		},
   884  		{ // pull in minimal dependencies, see https://github.com/tools/godep/issues/93
   885  			cwd:   "C",
   886  			flagR: true,
   887  			start: []*node{
   888  				{
   889  					"C",
   890  					"",
   891  					[]*node{
   892  						{"main.go", pkg("main", "D/X"), nil},
   893  						{"+git", "", nil},
   894  					},
   895  				},
   896  				{
   897  					"T",
   898  					"",
   899  					[]*node{
   900  						{"main.go", pkg("T"), nil},
   901  						{"+git", "T1", nil},
   902  					},
   903  				},
   904  				{
   905  					"D",
   906  					"",
   907  					[]*node{
   908  						{"main.go", pkg("D", "D/Godeps/_workspace/src/T"), nil},
   909  						{"X/main.go", pkg("X"), nil},
   910  						{"Godeps/_workspace/src/T/main.go", pkg("T"), nil},
   911  						{"Godeps/Godeps.json", godeps("D", "T", "T1"), nil},
   912  						{"+git", "D1", nil},
   913  					},
   914  				},
   915  			},
   916  			want: []*node{
   917  				{"C/main.go", pkg("main", "C/Godeps/_workspace/src/D/X"), nil},
   918  				{"C/Godeps/_workspace/src/D/X/main.go", pkg("X"), nil},
   919  			},
   920  			wdep: Godeps{
   921  				ImportPath: "C",
   922  				Deps: []Dependency{
   923  					{ImportPath: "D/X", Comment: "D1"},
   924  				},
   925  			},
   926  		},
   927  		{ // don't require packages contained in dest to be in VCS
   928  			cwd:   "C",
   929  			flagR: true,
   930  			start: []*node{
   931  				{
   932  					"C",
   933  					"",
   934  					[]*node{
   935  						{"main.go", pkg("main"), nil},
   936  					},
   937  				},
   938  			},
   939  			want: []*node{
   940  				{"C/main.go", pkg("main"), nil},
   941  			},
   942  			wdep: Godeps{
   943  				ImportPath: "C",
   944  				Deps:       []Dependency{},
   945  			},
   946  		},
   947  		{ // include command line packages in the set to be copied
   948  			cwd:   "C",
   949  			args:  []string{"P"},
   950  			flagR: true,
   951  			start: []*node{
   952  				{
   953  					"C",
   954  					"",
   955  					[]*node{
   956  						{"main.go", pkg("main"), nil},
   957  					},
   958  				},
   959  				{
   960  					"P",
   961  					"",
   962  					[]*node{
   963  						{"main.go", pkg("P"), nil},
   964  						{"+git", "P1", nil},
   965  					},
   966  				},
   967  			},
   968  			want: []*node{
   969  				{"C/main.go", pkg("main"), nil},
   970  				{"C/Godeps/_workspace/src/P/main.go", pkg("P"), nil},
   971  			},
   972  			wdep: Godeps{
   973  				ImportPath: "C",
   974  				Deps: []Dependency{
   975  					{ImportPath: "P", Comment: "P1"},
   976  				},
   977  			},
   978  		},
   979  		{ // don't copy untracked files in the source directory
   980  			cwd: "C",
   981  			start: []*node{
   982  				{
   983  					"C",
   984  					"",
   985  					[]*node{
   986  						{"main.go", pkg("main", "D"), nil},
   987  						{"+git", "", nil},
   988  					},
   989  				},
   990  				{
   991  					"D",
   992  					"",
   993  					[]*node{
   994  						{"main.go", pkg("D"), nil},
   995  						{"+git", "D1", nil},
   996  						{"untracked", "garbage", nil},
   997  					},
   998  				},
   999  			},
  1000  			want: []*node{
  1001  				{"C/main.go", pkg("main", "D"), nil},
  1002  				{"C/Godeps/_workspace/src/D/main.go", pkg("D"), nil},
  1003  				{"C/Godeps/_workspace/src/D/untracked", "(absent)", nil},
  1004  			},
  1005  			wdep: Godeps{
  1006  				ImportPath: "C",
  1007  				Deps: []Dependency{
  1008  					{ImportPath: "D", Comment: "D1"},
  1009  				},
  1010  			},
  1011  		},
  1012  		{ // don't copy _test.go files
  1013  			cwd: "C",
  1014  			start: []*node{
  1015  				{
  1016  					"C",
  1017  					"",
  1018  					[]*node{
  1019  						{"main.go", pkg("main", "D"), nil},
  1020  						{"+git", "", nil},
  1021  					},
  1022  				},
  1023  				{
  1024  					"D",
  1025  					"",
  1026  					[]*node{
  1027  						{"main.go", pkg("D"), nil},
  1028  						{"main_test.go", pkg("D"), nil},
  1029  						{"+git", "D1", nil},
  1030  					},
  1031  				},
  1032  			},
  1033  			want: []*node{
  1034  				{"C/main.go", pkg("main", "D"), nil},
  1035  				{"C/Godeps/_workspace/src/D/main.go", pkg("D"), nil},
  1036  			},
  1037  			wdep: Godeps{
  1038  				ImportPath: "C",
  1039  				Deps: []Dependency{
  1040  					{ImportPath: "D", Comment: "D1"},
  1041  				},
  1042  			},
  1043  		},
  1044  		{ // do copy _test.go files
  1045  			cwd:   "C",
  1046  			flagT: true,
  1047  			start: []*node{
  1048  				{
  1049  					"C",
  1050  					"",
  1051  					[]*node{
  1052  						{"main.go", pkg("main", "D"), nil},
  1053  						{"+git", "", nil},
  1054  					},
  1055  				},
  1056  				{
  1057  					"D",
  1058  					"",
  1059  					[]*node{
  1060  						{"main.go", pkg("D"), nil},
  1061  						{"main_test.go", pkg("D"), nil},
  1062  						{"+git", "D1", nil},
  1063  					},
  1064  				},
  1065  			},
  1066  			want: []*node{
  1067  				{"C/main.go", pkg("main", "D"), nil},
  1068  				{"C/Godeps/_workspace/src/D/main.go", pkg("D"), nil},
  1069  				{"C/Godeps/_workspace/src/D/main_test.go", pkg("D"), nil},
  1070  			},
  1071  			wdep: Godeps{
  1072  				ImportPath: "C",
  1073  				Deps: []Dependency{
  1074  					{ImportPath: "D", Comment: "D1"},
  1075  				},
  1076  			},
  1077  		},
  1078  		{ // Copy legal files in parent and dependency directory
  1079  			cwd: "C",
  1080  			start: []*node{
  1081  				{
  1082  					"C",
  1083  					"",
  1084  					[]*node{
  1085  						{"main.go", pkg("main", "D/P", "D/Q"), nil},
  1086  						{"+git", "", nil},
  1087  					},
  1088  				},
  1089  				{
  1090  					"D",
  1091  					"",
  1092  					[]*node{
  1093  						{"LICENSE", pkg("D"), nil},
  1094  						{"P/main.go", pkg("P"), nil},
  1095  						{"P/LICENSE", pkg("P"), nil},
  1096  						{"Q/main.go", pkg("Q"), nil},
  1097  						{"+git", "D1", nil},
  1098  					},
  1099  				},
  1100  			},
  1101  			want: []*node{
  1102  				{"C/main.go", pkg("main", "D/P", "D/Q"), nil},
  1103  				{"C/Godeps/_workspace/src/D/LICENSE", pkg("D"), nil},
  1104  				{"C/Godeps/_workspace/src/D/P/main.go", pkg("P"), nil},
  1105  				{"C/Godeps/_workspace/src/D/P/LICENSE", pkg("P"), nil},
  1106  				{"C/Godeps/_workspace/src/D/Q/main.go", pkg("Q"), nil},
  1107  			},
  1108  			wdep: Godeps{
  1109  				ImportPath: "C",
  1110  				Deps: []Dependency{
  1111  					{ImportPath: "D/P", Comment: "D1"},
  1112  					{ImportPath: "D/Q", Comment: "D1"},
  1113  				},
  1114  			},
  1115  		},
  1116  	}
  1117  
  1118  	wd, err := os.Getwd()
  1119  	if err != nil {
  1120  		t.Fatal(err)
  1121  	}
  1122  	const scratch = "godeptest"
  1123  	defer os.RemoveAll(scratch)
  1124  	for pos, test := range cases {
  1125  		err = os.RemoveAll(scratch)
  1126  		if err != nil {
  1127  			t.Fatal(err)
  1128  		}
  1129  		altsrc := filepath.Join(scratch, "r2", "src")
  1130  		if test.altstart != nil {
  1131  			makeTree(t, &node{altsrc, "", test.altstart}, "")
  1132  		}
  1133  		src := filepath.Join(scratch, "r1", "src")
  1134  		makeTree(t, &node{src, "", test.start}, altsrc)
  1135  
  1136  		dir := filepath.Join(wd, src, test.cwd)
  1137  		err = os.Chdir(dir)
  1138  		if err != nil {
  1139  			panic(err)
  1140  		}
  1141  		root1 := filepath.Join(wd, scratch, "r1")
  1142  		root2 := filepath.Join(wd, scratch, "r2")
  1143  		err = os.Setenv("GOPATH", root1+string(os.PathListSeparator)+root2)
  1144  		if err != nil {
  1145  			panic(err)
  1146  		}
  1147  		saveR = test.flagR
  1148  		saveT = test.flagT
  1149  		err = save(test.args)
  1150  		if g := err != nil; g != test.werr {
  1151  			if err != nil {
  1152  				t.Log(err)
  1153  			}
  1154  			t.Errorf("save err = %v want %v", g, test.werr)
  1155  		}
  1156  		err = os.Chdir(wd)
  1157  		if err != nil {
  1158  			panic(err)
  1159  		}
  1160  
  1161  		checkTree(t, pos, &node{src, "", test.want})
  1162  
  1163  		f, err := os.Open(filepath.Join(dir, "Godeps/Godeps.json"))
  1164  		if err != nil {
  1165  			t.Error(err)
  1166  		}
  1167  		g := new(Godeps)
  1168  		err = json.NewDecoder(f).Decode(g)
  1169  		if err != nil {
  1170  			t.Error(err)
  1171  		}
  1172  		f.Close()
  1173  
  1174  		if g.ImportPath != test.wdep.ImportPath {
  1175  			t.Errorf("ImportPath = %s want %s", g.ImportPath, test.wdep.ImportPath)
  1176  		}
  1177  		for i := range g.Deps {
  1178  			g.Deps[i].Rev = ""
  1179  		}
  1180  		if !reflect.DeepEqual(g.Deps, test.wdep.Deps) {
  1181  			t.Errorf("Deps = %v want %v", g.Deps, test.wdep.Deps)
  1182  		}
  1183  	}
  1184  }
  1185  
  1186  func makeTree(t *testing.T, tree *node, altpath string) (gopath string) {
  1187  	walkTree(tree, tree.path, func(path string, n *node) {
  1188  		g, isGodeps := n.body.(*Godeps)
  1189  		body, _ := n.body.(string)
  1190  		switch {
  1191  		case isGodeps:
  1192  			for i, dep := range g.Deps {
  1193  				rel := filepath.FromSlash(dep.ImportPath)
  1194  				dir := filepath.Join(tree.path, rel)
  1195  				if _, err := os.Stat(dir); os.IsNotExist(err) {
  1196  					dir = filepath.Join(altpath, rel)
  1197  				}
  1198  				tag := dep.Comment
  1199  				rev := strings.TrimSpace(run(t, dir, "git", "rev-parse", tag))
  1200  				g.Deps[i].Rev = rev
  1201  			}
  1202  			os.MkdirAll(filepath.Dir(path), 0770)
  1203  			f, err := os.Create(path)
  1204  			if err != nil {
  1205  				t.Errorf("makeTree: %v", err)
  1206  				return
  1207  			}
  1208  			defer f.Close()
  1209  			err = json.NewEncoder(f).Encode(g)
  1210  			if err != nil {
  1211  				t.Errorf("makeTree: %v", err)
  1212  			}
  1213  		case n.path == "+git":
  1214  			dir := filepath.Dir(path)
  1215  			run(t, dir, "git", "init") // repo might already exist, but ok
  1216  			run(t, dir, "git", "add", ".")
  1217  			run(t, dir, "git", "commit", "-m", "godep")
  1218  			if body != "" {
  1219  				run(t, dir, "git", "tag", body)
  1220  			}
  1221  		case n.entries == nil && strings.HasPrefix(body, "symlink:"):
  1222  			target := strings.TrimPrefix(body, "symlink:")
  1223  			os.Symlink(target, path)
  1224  		case n.entries == nil && body == "(absent)":
  1225  			panic("is this gonna be forever")
  1226  		case n.entries == nil:
  1227  			os.MkdirAll(filepath.Dir(path), 0770)
  1228  			err := ioutil.WriteFile(path, []byte(body), 0660)
  1229  			if err != nil {
  1230  				t.Errorf("makeTree: %v", err)
  1231  			}
  1232  		default:
  1233  			os.MkdirAll(path, 0770)
  1234  		}
  1235  	})
  1236  	return gopath
  1237  }
  1238  
  1239  func checkTree(t *testing.T, pos int, want *node) {
  1240  	walkTree(want, want.path, func(path string, n *node) {
  1241  		body := n.body.(string)
  1242  		switch {
  1243  		case n.path == "+git":
  1244  			panic("is this real life")
  1245  		case n.entries == nil && strings.HasPrefix(body, "symlink:"):
  1246  			panic("why is this happening to me")
  1247  		case n.entries == nil && body == "(absent)":
  1248  			body, err := ioutil.ReadFile(path)
  1249  			if !os.IsNotExist(err) {
  1250  				t.Errorf("%d checkTree: %s = %s want absent", pos, path, string(body))
  1251  				return
  1252  			}
  1253  		case n.entries == nil:
  1254  			gbody, err := ioutil.ReadFile(path)
  1255  			if err != nil {
  1256  				t.Errorf("%d checkTree: %v", pos, err)
  1257  				return
  1258  			}
  1259  			if got := string(gbody); got != body {
  1260  				t.Errorf("%d %s = got: %q want: %q", pos, path, got, body)
  1261  			}
  1262  		default:
  1263  			os.MkdirAll(path, 0770)
  1264  		}
  1265  	})
  1266  }
  1267  
  1268  func walkTree(n *node, path string, f func(path string, n *node)) {
  1269  	f(path, n)
  1270  	for _, e := range n.entries {
  1271  		walkTree(e, filepath.Join(path, filepath.FromSlash(e.path)), f)
  1272  	}
  1273  }
  1274  
  1275  func run(t *testing.T, dir, name string, args ...string) string {
  1276  	cmd := exec.Command(name, args...)
  1277  	cmd.Dir = dir
  1278  	cmd.Stderr = os.Stderr
  1279  	out, err := cmd.Output()
  1280  	if err != nil {
  1281  		panic(name + " " + strings.Join(args, " ") + ": " + err.Error())
  1282  	}
  1283  	return string(out)
  1284  }
  1285  
  1286  func TestStripImportComment(t *testing.T) {
  1287  	var cases = []struct{ s, w string }{
  1288  		{`package foo`, `package foo`},
  1289  		{`anything else`, `anything else`},
  1290  		{`package foo // import "bar/foo"`, `package foo`},
  1291  		{`package foo /* import "bar/foo" */`, `package foo`},
  1292  		{`package  foo  //  import  "bar/foo" `, `package  foo`},
  1293  		{"package foo // import `bar/foo`", `package foo`},
  1294  		{`package foo /* import "bar/foo" */; var x int`, `package foo; var x int`},
  1295  		{`package foo // import "bar/foo" garbage`, `package foo // import "bar/foo" garbage`},
  1296  		{`package xpackage foo // import "bar/foo"`, `package xpackage foo // import "bar/foo"`},
  1297  	}
  1298  
  1299  	for _, test := range cases {
  1300  		g := string(stripImportComment([]byte(test.s)))
  1301  		if g != test.w {
  1302  			t.Errorf("stripImportComment(%q) = %q want %q", test.s, g, test.w)
  1303  		}
  1304  	}
  1305  }
  1306  
  1307  func TestCopyWithoutImportCommentLongLines(t *testing.T) {
  1308  	tmp := make([]byte, int(math.Pow(2, 16)))
  1309  	for i := range tmp {
  1310  		tmp[i] = 111 // fill it with "o"s
  1311  	}
  1312  
  1313  	iStr := `package foo` + string(tmp) + `\n`
  1314  
  1315  	o := new(bytes.Buffer)
  1316  	i := strings.NewReader(iStr)
  1317  	err := copyWithoutImportComment(o, i)
  1318  	if err != nil {
  1319  		t.Fatalf("copyWithoutImportComment errored: %s", err.Error())
  1320  	}
  1321  }