...
Run Format

Source file src/cmd/gofmt/gofmt_test.go

Documentation: cmd/gofmt

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bytes"
     9  	"flag"
    10  	"io/ioutil"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"runtime"
    15  	"strings"
    16  	"testing"
    17  	"text/scanner"
    18  )
    19  
    20  var update = flag.Bool("update", false, "update .golden files")
    21  
    22  // gofmtFlags looks for a comment of the form
    23  //
    24  //	//gofmt flags
    25  //
    26  // within the first maxLines lines of the given file,
    27  // and returns the flags string, if any. Otherwise it
    28  // returns the empty string.
    29  func gofmtFlags(filename string, maxLines int) string {
    30  	f, err := os.Open(filename)
    31  	if err != nil {
    32  		return "" // ignore errors - they will be found later
    33  	}
    34  	defer f.Close()
    35  
    36  	// initialize scanner
    37  	var s scanner.Scanner
    38  	s.Init(f)
    39  	s.Error = func(*scanner.Scanner, string) {}       // ignore errors
    40  	s.Mode = scanner.GoTokens &^ scanner.SkipComments // want comments
    41  
    42  	// look for //gofmt comment
    43  	for s.Line <= maxLines {
    44  		switch s.Scan() {
    45  		case scanner.Comment:
    46  			const prefix = "//gofmt "
    47  			if t := s.TokenText(); strings.HasPrefix(t, prefix) {
    48  				return strings.TrimSpace(t[len(prefix):])
    49  			}
    50  		case scanner.EOF:
    51  			return ""
    52  		}
    53  
    54  	}
    55  
    56  	return ""
    57  }
    58  
    59  func runTest(t *testing.T, in, out string) {
    60  	// process flags
    61  	*simplifyAST = false
    62  	*rewriteRule = ""
    63  	stdin := false
    64  	for _, flag := range strings.Split(gofmtFlags(in, 20), " ") {
    65  		elts := strings.SplitN(flag, "=", 2)
    66  		name := elts[0]
    67  		value := ""
    68  		if len(elts) == 2 {
    69  			value = elts[1]
    70  		}
    71  		switch name {
    72  		case "":
    73  			// no flags
    74  		case "-r":
    75  			*rewriteRule = value
    76  		case "-s":
    77  			*simplifyAST = true
    78  		case "-stdin":
    79  			// fake flag - pretend input is from stdin
    80  			stdin = true
    81  		default:
    82  			t.Errorf("unrecognized flag name: %s", name)
    83  		}
    84  	}
    85  
    86  	initParserMode()
    87  	initRewrite()
    88  
    89  	var buf bytes.Buffer
    90  	err := processFile(in, nil, &buf, stdin)
    91  	if err != nil {
    92  		t.Error(err)
    93  		return
    94  	}
    95  
    96  	expected, err := ioutil.ReadFile(out)
    97  	if err != nil {
    98  		t.Error(err)
    99  		return
   100  	}
   101  
   102  	if got := buf.Bytes(); !bytes.Equal(got, expected) {
   103  		if *update {
   104  			if in != out {
   105  				if err := ioutil.WriteFile(out, got, 0666); err != nil {
   106  					t.Error(err)
   107  				}
   108  				return
   109  			}
   110  			// in == out: don't accidentally destroy input
   111  			t.Errorf("WARNING: -update did not rewrite input file %s", in)
   112  		}
   113  
   114  		t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
   115  		d, err := diff(expected, got, in)
   116  		if err == nil {
   117  			t.Errorf("%s", d)
   118  		}
   119  		if err := ioutil.WriteFile(in+".gofmt", got, 0666); err != nil {
   120  			t.Error(err)
   121  		}
   122  	}
   123  }
   124  
   125  // TestRewrite processes testdata/*.input files and compares them to the
   126  // corresponding testdata/*.golden files. The gofmt flags used to process
   127  // a file must be provided via a comment of the form
   128  //
   129  //	//gofmt flags
   130  //
   131  // in the processed file within the first 20 lines, if any.
   132  func TestRewrite(t *testing.T) {
   133  	// determine input files
   134  	match, err := filepath.Glob("testdata/*.input")
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  
   139  	// add larger examples
   140  	match = append(match, "gofmt.go", "gofmt_test.go")
   141  
   142  	for _, in := range match {
   143  		out := in // for files where input and output are identical
   144  		if strings.HasSuffix(in, ".input") {
   145  			out = in[:len(in)-len(".input")] + ".golden"
   146  		}
   147  		runTest(t, in, out)
   148  		if in != out {
   149  			// Check idempotence.
   150  			runTest(t, out, out)
   151  		}
   152  	}
   153  }
   154  
   155  // Test case for issue 3961.
   156  func TestCRLF(t *testing.T) {
   157  	const input = "testdata/crlf.input"   // must contain CR/LF's
   158  	const golden = "testdata/crlf.golden" // must not contain any CR's
   159  
   160  	data, err := ioutil.ReadFile(input)
   161  	if err != nil {
   162  		t.Error(err)
   163  	}
   164  	if !bytes.Contains(data, []byte("\r\n")) {
   165  		t.Errorf("%s contains no CR/LF's", input)
   166  	}
   167  
   168  	data, err = ioutil.ReadFile(golden)
   169  	if err != nil {
   170  		t.Error(err)
   171  	}
   172  	if bytes.Contains(data, []byte("\r")) {
   173  		t.Errorf("%s contains CR's", golden)
   174  	}
   175  }
   176  
   177  func TestBackupFile(t *testing.T) {
   178  	dir, err := ioutil.TempDir("", "gofmt_test")
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	defer os.RemoveAll(dir)
   183  	name, err := backupFile(filepath.Join(dir, "foo.go"), []byte("  package main"), 0644)
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	t.Logf("Created: %s", name)
   188  }
   189  
   190  func TestDiff(t *testing.T) {
   191  	if _, err := exec.LookPath("diff"); err != nil {
   192  		t.Skipf("skip test on %s: diff command is required", runtime.GOOS)
   193  	}
   194  	in := []byte("first\nsecond\n")
   195  	out := []byte("first\nthird\n")
   196  	filename := "difftest.txt"
   197  	b, err := diff(in, out, filename)
   198  	if err != nil {
   199  		t.Fatal(err)
   200  	}
   201  
   202  	if runtime.GOOS == "windows" {
   203  		b = bytes.Replace(b, []byte{'\r', '\n'}, []byte{'\n'}, -1)
   204  	}
   205  
   206  	bs := bytes.SplitN(b, []byte{'\n'}, 3)
   207  	line0, line1 := bs[0], bs[1]
   208  
   209  	if prefix := "--- difftest.txt.orig"; !bytes.HasPrefix(line0, []byte(prefix)) {
   210  		t.Errorf("diff: first line should start with `%s`\ngot: %s", prefix, line0)
   211  	}
   212  
   213  	if prefix := "+++ difftest.txt"; !bytes.HasPrefix(line1, []byte(prefix)) {
   214  		t.Errorf("diff: second line should start with `%s`\ngot: %s", prefix, line1)
   215  	}
   216  
   217  	want := `@@ -1,2 +1,2 @@
   218   first
   219  -second
   220  +third
   221  `
   222  
   223  	if got := string(bs[2]); got != want {
   224  		t.Errorf("diff: got:\n%s\nwant:\n%s", got, want)
   225  	}
   226  }
   227  
   228  func TestReplaceTempFilename(t *testing.T) {
   229  	diff := []byte(`--- /tmp/tmpfile1	2017-02-08 00:53:26.175105619 +0900
   230  +++ /tmp/tmpfile2	2017-02-08 00:53:38.415151275 +0900
   231  @@ -1,2 +1,2 @@
   232   first
   233  -second
   234  +third
   235  `)
   236  	want := []byte(`--- path/to/file.go.orig	2017-02-08 00:53:26.175105619 +0900
   237  +++ path/to/file.go	2017-02-08 00:53:38.415151275 +0900
   238  @@ -1,2 +1,2 @@
   239   first
   240  -second
   241  +third
   242  `)
   243  	// Check path in diff output is always slash regardless of the
   244  	// os.PathSeparator (`/` or `\`).
   245  	sep := string(os.PathSeparator)
   246  	filename := strings.Join([]string{"path", "to", "file.go"}, sep)
   247  	got, err := replaceTempFilename(diff, filename)
   248  	if err != nil {
   249  		t.Fatal(err)
   250  	}
   251  	if !bytes.Equal(got, want) {
   252  		t.Errorf("os.PathSeparator='%s': replacedDiff:\ngot:\n%s\nwant:\n%s", sep, got, want)
   253  	}
   254  }
   255  

View as plain text