Commit 67812a7c authored by Robert Griesemer's avatar Robert Griesemer

cmd/gofmt: make test files self-describing

1) Interpret a comment of the form

//gofmt <flags>

in test files to drive the respective
gofmt command. Eliminates the need to
enumerate all test files in the test
harness.

2) Added -update flag to make it easier
to update test cases.

LGTM=josharian
R=golang-codereviews, josharian
CC=golang-codereviews
https://golang.org/cl/130440043
parent bc64c078
...@@ -6,18 +6,60 @@ package main ...@@ -6,18 +6,60 @@ package main
import ( import (
"bytes" "bytes"
"flag"
"io/ioutil" "io/ioutil"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
"text/scanner"
) )
func runTest(t *testing.T, in, out, flags string) { var update = flag.Bool("update", false, "update .golden files")
// gofmtFlags looks for a comment of the form
//
// //gofmt flags
//
// within the first maxLines lines of the given file,
// and returns the flags string, if any. Otherwise it
// returns the empty string.
func gofmtFlags(filename string, maxLines int) string {
f, err := os.Open(filename)
if err != nil {
return "" // ignore errors - they will be found later
}
defer f.Close()
// initialize scanner
var s scanner.Scanner
s.Init(f)
s.Error = func(*scanner.Scanner, string) {} // ignore errors
s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments
// look for //gofmt comment
for s.Line <= maxLines {
switch s.Scan() {
case scanner.Comment:
const prefix = "//gofmt "
if t := s.TokenText(); strings.HasPrefix(t, prefix) {
return strings.TrimSpace(t[len(prefix):])
}
case scanner.EOF:
return ""
}
}
return ""
}
func runTest(t *testing.T, in, out string) {
// process flags // process flags
*simplifyAST = false *simplifyAST = false
*rewriteRule = "" *rewriteRule = ""
stdin := false stdin := false
for _, flag := range strings.Split(flags, " ") { for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
elts := strings.SplitN(flag, "=", 2) elts := strings.SplitN(flag, "=", 2)
name := elts[0] name := elts[0]
value := "" value := ""
...@@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) { ...@@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) {
} }
if got := buf.Bytes(); !bytes.Equal(got, expected) { if got := buf.Bytes(); !bytes.Equal(got, expected) {
if *update {
if in != out {
if err := ioutil.WriteFile(out, got, 0666); err != nil {
t.Error(err)
}
return
}
// in == out: don't accidentally destroy input
t.Errorf("WARNING: -update did not rewrite input file %s", in)
}
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in) t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
d, err := diff(expected, got) d, err := diff(expected, got)
if err == nil { if err == nil {
...@@ -67,53 +120,37 @@ func runTest(t *testing.T, in, out, flags string) { ...@@ -67,53 +120,37 @@ func runTest(t *testing.T, in, out, flags string) {
} }
} }
var tests = []struct { // TestRewrite processes testdata/*.input files and compares them to the
in, flags string // corresponding testdata/*.golden files. The gofmt flags used to process
}{ // a file must be provided via a comment of the form
{"gofmt.go", ""}, //
{"gofmt_test.go", ""}, // //gofmt flags
{"testdata/composites.input", "-s"}, //
{"testdata/slices1.input", "-s"}, // in the processed file within the first 20 lines, if any.
{"testdata/slices2.input", "-s"},
{"testdata/ranges.input", "-s"},
{"testdata/old.input", ""},
{"testdata/rewrite1.input", "-r=Foo->Bar"},
{"testdata/rewrite2.input", "-r=int->bool"},
{"testdata/rewrite3.input", "-r=x->x"},
{"testdata/rewrite4.input", "-r=(x)->x"},
{"testdata/rewrite5.input", "-r=x+x->2*x"},
{"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"},
{"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"},
{"testdata/rewrite8.input", "-r=interface{}->int"},
{"testdata/stdin*.input", "-stdin"},
{"testdata/comments.input", ""},
{"testdata/import.input", ""},
{"testdata/crlf.input", ""}, // test case for issue 3961; see also TestCRLF
{"testdata/typeswitch.input", ""}, // test case for issue 4470
{"testdata/emptydecl.input", "-s"}, // test case for issue 7631
}
func TestRewrite(t *testing.T) { func TestRewrite(t *testing.T) {
for _, test := range tests { // determine input files
match, err := filepath.Glob(test.in) match, err := filepath.Glob("testdata/*.input")
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
continue }
// add larger examples
match = append(match, "gofmt.go", "gofmt_test.go")
for _, in := range match {
out := in // for files where input and output are identical
if strings.HasSuffix(in, ".input") {
out = in[:len(in)-len(".input")] + ".golden"
} }
for _, in := range match { runTest(t, in, out)
out := in if in != out {
if strings.HasSuffix(in, ".input") { // Check idempotence.
out = in[:len(in)-len(".input")] + ".golden" runTest(t, out, out)
}
runTest(t, in, out, test.flags)
if in != out {
// Check idempotence.
runTest(t, out, out, test.flags)
}
} }
} }
} }
// Test case for issue 3961.
func TestCRLF(t *testing.T) { func TestCRLF(t *testing.T) {
const input = "testdata/crlf.input" // must contain CR/LF's const input = "testdata/crlf.input" // must contain CR/LF's
const golden = "testdata/crlf.golden" // must not contain any CR's const golden = "testdata/crlf.golden" // must not contain any CR's
......
//gofmt -s
package P package P
type T struct { type T struct {
......
//gofmt -s
package P package P
type T struct { type T struct {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
Source containing CR/LF line endings. Source containing CR/LF line endings.
The gofmt'ed output must only have LF The gofmt'ed output must only have LF
line endings. line endings.
Test case for issue 3961.
*/ */
package main package main
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
Source containing CR/LF line endings. Source containing CR/LF line endings.
The gofmt'ed output must only have LF The gofmt'ed output must only have LF
line endings. line endings.
Test case for issue 3961.
*/ */
package main package main
......
//gofmt -s
// Test case for issue 7631.
package main package main
// Keep this declaration // Keep this declaration
......
//gofmt -s
// Test case for issue 7631.
package main package main
// Keep this declaration // Keep this declaration
......
//gofmt -s
// Test cases for range simplification. // Test cases for range simplification.
package p package p
......
//gofmt -s
// Test cases for range simplification. // Test cases for range simplification.
package p package p
......
//gofmt -r=Foo->Bar
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=Foo->Bar
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=int->bool
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=int->bool
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=x->x
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=x->x
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=(x)->x
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=(x)->x
// Copyright 2012 The Go Authors. All rights reserved. // Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=x+x->2*x
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=x+x->2*x
// Copyright 2011 The Go Authors. All rights reserved. // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=fun(x)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=fun(x)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=fun(x...)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=fun(x...)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=interface{}->int
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -r=interface{}->int
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
//gofmt -s
// Test cases for slice expression simplification. // Test cases for slice expression simplification.
package p package p
......
//gofmt -s
// Test cases for slice expression simplification. // Test cases for slice expression simplification.
package p package p
......
//gofmt -s
// Test cases for slice expression simplification. // Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched. // Because of a dot import, these slices must remain untouched.
package p package p
......
//gofmt -s
// Test cases for slice expression simplification. // Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched. // Because of a dot import, these slices must remain untouched.
package p package p
......
//gofmt -stdin
var x int var x int
......
//gofmt -stdin
var x int var x int
......
//gofmt -stdin
/* note: no newline at end of file */ /* note: no newline at end of file */
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
......
//gofmt -stdin
/* note: no newline at end of file */ /* note: no newline at end of file */
for i := 0; i < 10; i++ { s += i } for i := 0; i < 10; i++ { s += i }
//gofmt -stdin
// comment // comment
i := 0 i := 0
//gofmt -stdin
// comment // comment
i := 0 i := 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment