@@ -12,21 +12,22 @@ package eg_test
12
12
import (
13
13
"bytes"
14
14
"flag"
15
- "go/build "
15
+ "fmt "
16
16
"go/constant"
17
- "go/parser"
18
- "go/token"
17
+ "go/format"
19
18
"go/types"
20
19
"os"
21
- "os/exec"
22
20
"path/filepath"
23
21
"runtime"
24
22
"strings"
25
23
"testing"
26
24
27
- "golang.org/x/tools/go/loader"
25
+ "github.com/google/go-cmp/cmp"
26
+ "golang.org/x/tools/go/packages"
28
27
"golang.org/x/tools/internal/testenv"
28
+ "golang.org/x/tools/internal/testfiles"
29
29
"golang.org/x/tools/refactor/eg"
30
+ "golang.org/x/tools/txtar"
30
31
)
31
32
32
33
// TODO(adonovan): more tests:
@@ -41,80 +42,64 @@ var (
41
42
)
42
43
43
44
func Test (t * testing.T ) {
44
- testenv .NeedsTool ( t , "go" )
45
+ testenv .NeedsGoPackages ( t )
45
46
46
47
switch runtime .GOOS {
47
48
case "windows" :
48
49
t .Skipf ("skipping test on %q (no /usr/bin/diff)" , runtime .GOOS )
49
50
}
50
51
51
- ctx := build .Default // copy
52
- ctx .CgoEnabled = false // don't use cgo
53
- conf := loader.Config {
54
- Fset : token .NewFileSet (),
55
- ParserMode : parser .ParseComments ,
56
- Build : & ctx ,
57
- }
58
-
59
- // Each entry is a single-file package.
60
- // (Multi-file packages aren't interesting for this test.)
61
- // Order matters: each non-template package is processed using
62
- // the preceding template package.
52
+ // Each txtar defines a package example.com/template and zero
53
+ // or more input packages example.com/in/... on which to apply
54
+ // it. The outputs are compared with the corresponding files
55
+ // in example.com/out/...
63
56
for _ , filename := range []string {
64
- "testdata/A.template" ,
65
- "testdata/A1.go" ,
66
- "testdata/A2.go" ,
67
-
68
- "testdata/B.template" ,
69
- "testdata/B1.go" ,
70
-
71
- "testdata/C.template" ,
72
- "testdata/C1.go" ,
73
-
74
- "testdata/D.template" ,
75
- "testdata/D1.go" ,
76
-
77
- "testdata/E.template" ,
78
- "testdata/E1.go" ,
79
-
80
- "testdata/F.template" ,
81
- "testdata/F1.go" ,
82
-
83
- "testdata/G.template" ,
84
- "testdata/G1.go" ,
85
-
86
- "testdata/H.template" ,
87
- "testdata/H1.go" ,
88
-
89
- "testdata/I.template" ,
90
- "testdata/I1.go" ,
91
-
92
- "testdata/J.template" ,
93
- "testdata/J1.go" ,
94
-
95
- "testdata/bad_type.template" ,
96
- "testdata/no_before.template" ,
97
- "testdata/no_after_return.template" ,
98
- "testdata/type_mismatch.template" ,
99
- "testdata/expr_type_mismatch.template" ,
57
+ "testdata/a.txtar" ,
58
+ "testdata/b.txtar" ,
59
+ "testdata/c.txtar" ,
60
+ "testdata/d.txtar" ,
61
+ "testdata/e.txtar" ,
62
+ "testdata/f.txtar" ,
63
+ "testdata/g.txtar" ,
64
+ "testdata/h.txtar" ,
65
+ "testdata/i.txtar" ,
66
+ "testdata/j.txtar" ,
67
+ "testdata/bad_type.txtar" ,
68
+ "testdata/no_before.txtar" ,
69
+ "testdata/no_after_return.txtar" ,
70
+ "testdata/type_mismatch.txtar" ,
71
+ "testdata/expr_type_mismatch.txtar" ,
100
72
} {
101
- pkgname := strings .TrimSuffix (filepath .Base (filename ), ".go" )
102
- conf .CreateFromFilenames (pkgname , filename )
103
- }
104
- iprog , err := conf .Load ()
105
- if err != nil {
106
- t .Fatal (err )
107
- }
108
-
109
- var xform * eg.Transformer
110
- for _ , info := range iprog .Created {
111
- file := info .Files [0 ]
112
- filename := iprog .Fset .File (file .Pos ()).Name () // foo.go
73
+ t .Run (filename , func (t * testing.T ) {
74
+ // Extract and load packages from test archive.
75
+ dir := testfiles .ExtractTxtarFileToTmp (t , filename )
76
+ cfg := packages.Config {
77
+ Mode : packages .LoadAllSyntax ,
78
+ Dir : dir ,
79
+ }
80
+ pkgs , err := packages .Load (& cfg , "example.com/template" , "example.com/in/..." )
81
+ if err != nil {
82
+ t .Fatal (err )
83
+ }
84
+ if packages .PrintErrors (pkgs ) > 0 {
85
+ t .Fatal ("Load: there were errors" )
86
+ }
113
87
114
- if strings .HasSuffix (filename , "template" ) {
115
- // a new template
116
- shouldFail , _ := info .Pkg .Scope ().Lookup ("shouldFail" ).(* types.Const )
117
- xform , err = eg .NewTransformer (iprog .Fset , info .Pkg , file , & info .Info , * verboseFlag )
88
+ // Find and compile the template.
89
+ var template * packages.Package
90
+ var inputs []* packages.Package
91
+ for _ , pkg := range pkgs {
92
+ if pkg .Types .Name () == "template" {
93
+ template = pkg
94
+ } else {
95
+ inputs = append (inputs , pkg )
96
+ }
97
+ }
98
+ if template == nil {
99
+ t .Fatal ("no template package" )
100
+ }
101
+ shouldFail , _ := template .Types .Scope ().Lookup ("shouldFail" ).(* types.Const )
102
+ xform , err := eg .NewTransformer (template .Fset , template .Types , template .Syntax [0 ], template .TypesInfo , * verboseFlag )
118
103
if err != nil {
119
104
if shouldFail == nil {
120
105
t .Errorf ("NewTransformer(%s): %s" , filename , err )
@@ -125,55 +110,67 @@ func Test(t *testing.T) {
125
110
t .Errorf ("NewTransformer(%s) succeeded unexpectedly; want error %q" ,
126
111
filename , shouldFail .Val ())
127
112
}
128
- continue
129
- }
130
-
131
- if xform == nil {
132
- t .Errorf ("%s: no previous template" , filename )
133
- continue
134
- }
135
-
136
- // apply previous template to this package
137
- n := xform .Transform (& info .Info , info .Pkg , file )
138
- if n == 0 {
139
- t .Errorf ("%s: no matches" , filename )
140
- continue
141
- }
142
-
143
- gotf , err := os .CreateTemp ("" , filepath .Base (filename )+ "t" )
144
- if err != nil {
145
- t .Fatal (err )
146
- }
147
- got := gotf .Name () // foo.got
148
- golden := filename + "lden" // foo.golden
149
-
150
- // Write actual output to foo.got.
151
- if err := eg .WriteAST (iprog .Fset , got , file ); err != nil {
152
- t .Error (err )
153
- }
154
- defer os .Remove (got )
155
-
156
- // Compare foo.got with foo.golden.
157
- var cmd * exec.Cmd
158
- switch runtime .GOOS {
159
- case "plan9" :
160
- cmd = exec .Command ("/bin/diff" , "-c" , golden , got )
161
- default :
162
- cmd = exec .Command ("/usr/bin/diff" , "-u" , golden , got )
163
- }
164
- buf := new (bytes.Buffer )
165
- cmd .Stdout = buf
166
- cmd .Stderr = os .Stderr
167
- if err := cmd .Run (); err != nil {
168
- t .Errorf ("eg tests for %s failed: %s.\n %s\n " , filename , err , buf )
169
113
114
+ // Apply template to each input package.
115
+ updated := make (map [string ][]byte )
116
+ for _ , pkg := range inputs {
117
+ for _ , file := range pkg .Syntax {
118
+ filename , err := filepath .Rel (dir , pkg .Fset .File (file .FileStart ).Name ())
119
+ if err != nil {
120
+ t .Fatalf ("can't relativize filename: %v" , err )
121
+ }
122
+
123
+ // Apply the transform and reformat.
124
+ n := xform .Transform (pkg .TypesInfo , pkg .Types , file )
125
+ if n == 0 {
126
+ t .Fatalf ("%s: no replacements" , filename )
127
+ }
128
+ var got []byte
129
+ {
130
+ var out bytes.Buffer
131
+ format .Node (& out , pkg .Fset , file ) // ignore error
132
+ got = out .Bytes ()
133
+ }
134
+
135
+ // Compare formatted output with out/<filename>
136
+ // Errors here are not fatal, so we can proceed to -update.
137
+ outfile := strings .Replace (filename , "in" , "out" , 1 )
138
+ updated [outfile ] = got
139
+ want , err := os .ReadFile (filepath .Join (dir , outfile ))
140
+ if err != nil {
141
+ t .Errorf ("can't read output file: %v" , err )
142
+ } else if diff := cmp .Diff (want , got ); diff != "" {
143
+ t .Errorf ("Unexpected output:\n %s\n \n got %s:\n %s\n \n want %s:\n %s" ,
144
+ diff ,
145
+ filename , got , outfile , want )
146
+ }
147
+ }
148
+ }
149
+
150
+ // -update: replace the .txtar.
170
151
if * updateFlag {
171
- t .Logf ("Updating %s..." , golden )
172
- if err := exec .Command ("/bin/cp" , got , golden ).Run (); err != nil {
173
- t .Errorf ("Update failed: %s" , err )
152
+ ar , err := txtar .ParseFile (filename )
153
+ if err != nil {
154
+ t .Fatal (err )
155
+ }
156
+
157
+ var new bytes.Buffer
158
+ new .Write (ar .Comment )
159
+ for _ , file := range ar .Files {
160
+ data , ok := updated [file .Name ]
161
+ if ! ok {
162
+ data = file .Data
163
+ }
164
+ fmt .Fprintf (& new , "-- %s --\n %s" , file .Name , data )
165
+ }
166
+ t .Logf ("Updating %s..." , filename )
167
+ os .Remove (filename + ".bak" ) // ignore error
168
+ os .Rename (filename , filename + ".bak" ) // ignore error
169
+ if err := os .WriteFile (filename , new .Bytes (), 0666 ); err != nil {
170
+ t .Fatal (err )
174
171
}
175
172
}
176
- }
173
+ })
177
174
}
178
175
}
179
176
0 commit comments