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
import (
"bytes"
"flag"
"io/ioutil"
"os"
"path/filepath"
"strings"
"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
*simplifyAST = false
*rewriteRule = ""
stdin := false
for _, flag := range strings.Split(flags, " ") {
for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
elts := strings.SplitN(flag, "=", 2)
name := elts[0]
value := ""
......@@ -56,6 +98,17 @@ func runTest(t *testing.T, in, out, flags string) {
}
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)
d, err := diff(expected, got)
if err == nil {
......@@ -67,53 +120,37 @@ func runTest(t *testing.T, in, out, flags string) {
}
}
var tests = []struct {
in, flags string
}{
{"gofmt.go", ""},
{"gofmt_test.go", ""},
{"testdata/composites.input", "-s"},
{"testdata/slices1.input", "-s"},
{"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
}
// TestRewrite processes testdata/*.input files and compares them to the
// corresponding testdata/*.golden files. The gofmt flags used to process
// a file must be provided via a comment of the form
//
// //gofmt flags
//
// in the processed file within the first 20 lines, if any.
func TestRewrite(t *testing.T) {
for _, test := range tests {
match, err := filepath.Glob(test.in)
if err != nil {
t.Error(err)
continue
// determine input files
match, err := filepath.Glob("testdata/*.input")
if err != nil {
t.Fatal(err)
}
// 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 {
out := in
if strings.HasSuffix(in, ".input") {
out = in[:len(in)-len(".input")] + ".golden"
}
runTest(t, in, out, test.flags)
if in != out {
// Check idempotence.
runTest(t, out, out, test.flags)
}
runTest(t, in, out)
if in != out {
// Check idempotence.
runTest(t, out, out)
}
}
}
// Test case for issue 3961.
func TestCRLF(t *testing.T) {
const input = "testdata/crlf.input" // must contain CR/LF's
const golden = "testdata/crlf.golden" // must not contain any CR's
......
//gofmt -s
package P
type T struct {
......
//gofmt -s
package P
type T struct {
......
......@@ -2,6 +2,7 @@
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
Test case for issue 3961.
*/
package main
......
......@@ -2,6 +2,7 @@
Source containing CR/LF line endings.
The gofmt'ed output must only have LF
line endings.
Test case for issue 3961.
*/
package main
......
//gofmt -s
// Test case for issue 7631.
package main
// Keep this declaration
......
//gofmt -s
// Test case for issue 7631.
package main
// Keep this declaration
......
//gofmt -s
// Test cases for range simplification.
package p
......
//gofmt -s
// Test cases for range simplification.
package p
......
//gofmt -r=Foo->Bar
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=Foo->Bar
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=int->bool
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=int->bool
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=x->x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=x->x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=(x)->x
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=(x)->x
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=x+x->2*x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=x+x->2*x
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=fun(x)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=fun(x)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=fun(x...)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=fun(x...)->Fun(x)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=interface{}->int
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -r=interface{}->int
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
......
//gofmt -s
// Test cases for slice expression simplification.
package p
......
//gofmt -s
// Test cases for slice expression simplification.
package p
......
//gofmt -s
// Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched.
package p
......
//gofmt -s
// Test cases for slice expression simplification.
// Because of a dot import, these slices must remain untouched.
package p
......
//gofmt -stdin
/* note: no newline at end of file */
for i := 0; i < 10; i++ {
......
//gofmt -stdin
/* note: no newline at end of file */
for i := 0; i < 10; i++ { s += i }
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