@@ -2,10 +2,20 @@ package minformat
22
33import (
44 "bytes"
5+ "fmt"
6+ "go/ast"
7+ "go/format"
8+ "go/parser"
59 "go/token"
10+ "io/fs"
11+ "os"
12+ "os/exec"
13+ "path/filepath"
14+ "strings"
615 "testing"
716
817 "github.com/go-toolsmith/strparse"
18+ "github.com/google/go-cmp/cmp"
919)
1020
1121func TestMinifyDecl (t * testing.T ) {
@@ -20,6 +30,8 @@ func TestMinifyDecl(t *testing.T) {
2030 {`type x = int` , `type x=int` },
2131 {`type (a [2] int; b [ ]int)` , `type(a [2]int;b []int)` },
2232
33+ {`type _ struct { x int "struct tag" }` , `type _ struct{x int"struct tag"}` },
34+
2335 {`const x, y = 1, 2` , `const x,y=1,2` },
2436 {`const (x = 1; y = 2)` , `const(x=1;y=2)` },
2537 {`const x int = 1` , `const x int=1` },
@@ -78,6 +90,8 @@ func TestMinifyStmt(t *testing.T) {
7890
7991 {`if cond { return nil }` , `if cond{return nil}` },
8092 {`if x := f(); !x { return nil }` , `if x:=f();!x{return nil}` },
93+ {`if cond { f(); } else { g(); }` , `if cond{f()}else{g()}` },
94+ {`if cond { f(); } else if cond { g(); }` , `if cond{f()}else if cond{g()}` },
8195
8296 {`switch {default: return 1}` , `switch{default:return 1}` },
8397 {`switch tag {case 1, 2: return 0}` , `switch tag{case 1,2:return 0}` },
@@ -151,6 +165,10 @@ func TestMinifyExpr(t *testing.T) {
151165 {`[] int` , `[]int` },
152166 {`[ 2 ] int` , `[2]int` },
153167
168+ {`x &^ y` , `x&^y` },
169+ {`x & ^y` , `x& ^y` },
170+ {`x & (^y)` , `x&(^y)` },
171+
154172 {`func () ` , `func()` },
155173 {`func ( int ) (int, int)` , `func(int)(int,int)` },
156174 {`func ( int, int ) (int)` , `func(int,int)int` },
@@ -183,6 +201,7 @@ func TestMinifyExpr(t *testing.T) {
183201 {`f(1, 2)` , `f(1,2)` },
184202 {`f(1, g(2, 3))` , `f(1,g(2,3))` },
185203 {`f( 1 )( 2, 3 )` , `f(1)(2,3)` },
204+ {`foo(1, args...)` , `foo(1,args...)` },
186205
187206 {`struct { }` , `struct{}` },
188207 {`struct{ int }` , `struct{int}` },
@@ -218,3 +237,69 @@ func TestMinifyExpr(t *testing.T) {
218237 }
219238 }
220239}
240+
241+ func TestGoroot (t * testing.T ) {
242+ var goroot string
243+ {
244+ out , err := exec .Command ("go" , "env" , "GOROOT" ).CombinedOutput ()
245+ if err != nil {
246+ t .Fatal (err )
247+ }
248+ goroot = strings .TrimSpace (string (out ))
249+ }
250+
251+ visitFile := func (filename string ) error {
252+ fset := token .NewFileSet ()
253+ fileContents , err := os .ReadFile (filename )
254+ if err != nil {
255+ return err
256+ }
257+ f , err := parser .ParseFile (fset , filename , fileContents , 0 )
258+ if err != nil {
259+ return nil
260+ }
261+ var minified bytes.Buffer
262+ if err := Node (& minified , fset , f ); err != nil {
263+ return err
264+ }
265+ fset2 := token .NewFileSet ()
266+ f2 , err := parser .ParseFile (fset2 , filename , minified .Bytes (), 0 )
267+ if err != nil {
268+ return fmt .Errorf ("re-parse minified: %w" , err )
269+ }
270+ if diff := astDiff (f , f2 ); diff != "" {
271+ return fmt .Errorf ("minified code produced different AST:\n %s" , diff )
272+ }
273+ return nil
274+ }
275+
276+ srcDir := filepath .Join (goroot , "src" )
277+ err := filepath .WalkDir (srcDir , func (path string , info fs.DirEntry , err error ) error {
278+ if err != nil {
279+ return err
280+ }
281+ if info .IsDir () {
282+ return nil
283+ }
284+ if ! strings .HasSuffix (info .Name (), ".go" ) {
285+ return nil
286+ }
287+ if err := visitFile (path ); err != nil {
288+ return fmt .Errorf ("%s: %w" , path , err )
289+ }
290+ return nil
291+ })
292+ if err != nil {
293+ t .Fatal (err )
294+ }
295+ }
296+
297+ func astDiff (x , y ast.Node ) string {
298+ var buf bytes.Buffer
299+ format .Node (& buf , token .NewFileSet (), x )
300+ s1 := buf .String ()
301+ buf .Reset ()
302+ format .Node (& buf , token .NewFileSet (), y )
303+ s2 := buf .String ()
304+ return cmp .Diff (s1 , s2 )
305+ }
0 commit comments