Source file src/go/format/format_test.go

     1  // Copyright 2012 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 format
     6  
     7  import (
     8  	"bytes"
     9  	"go/ast"
    10  	"go/parser"
    11  	"go/token"
    12  	"os"
    13  	"strings"
    14  	"testing"
    15  )
    16  
    17  const testfile = "format_test.go"
    18  
    19  func diff(t *testing.T, dst, src []byte) {
    20  	line := 1
    21  	offs := 0 // line offset
    22  	for i := 0; i < len(dst) && i < len(src); i++ {
    23  		d := dst[i]
    24  		s := src[i]
    25  		if d != s {
    26  			t.Errorf("dst:%d: %s\n", line, dst[offs:i+1])
    27  			t.Errorf("src:%d: %s\n", line, src[offs:i+1])
    28  			return
    29  		}
    30  		if s == '\n' {
    31  			line++
    32  			offs = i + 1
    33  		}
    34  	}
    35  	if len(dst) != len(src) {
    36  		t.Errorf("len(dst) = %d, len(src) = %d\nsrc = %q", len(dst), len(src), src)
    37  	}
    38  }
    39  
    40  func TestNode(t *testing.T) {
    41  	src, err := os.ReadFile(testfile)
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  
    46  	fset := token.NewFileSet()
    47  	file, err := parser.ParseFile(fset, testfile, src, parser.ParseComments)
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  
    52  	var buf bytes.Buffer
    53  
    54  	if err = Node(&buf, fset, file); err != nil {
    55  		t.Fatal("Node failed:", err)
    56  	}
    57  
    58  	diff(t, buf.Bytes(), src)
    59  }
    60  
    61  // Node is documented to not modify the AST.
    62  // Test that it is so even when numbers are normalized.
    63  func TestNodeNoModify(t *testing.T) {
    64  	const (
    65  		src    = "package p\n\nconst _ = 0000000123i\n"
    66  		golden = "package p\n\nconst _ = 123i\n"
    67  	)
    68  
    69  	fset := token.NewFileSet()
    70  	file, err := parser.ParseFile(fset, "", src, parser.ParseComments)
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  
    75  	// Capture original address and value of a BasicLit node
    76  	// which will undergo formatting changes during printing.
    77  	wantLit := file.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0].(*ast.BasicLit)
    78  	wantVal := wantLit.Value
    79  
    80  	var buf bytes.Buffer
    81  	if err = Node(&buf, fset, file); err != nil {
    82  		t.Fatal("Node failed:", err)
    83  	}
    84  	diff(t, buf.Bytes(), []byte(golden))
    85  
    86  	// Check if anything changed after Node returned.
    87  	gotLit := file.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0].(*ast.BasicLit)
    88  	gotVal := gotLit.Value
    89  
    90  	if gotLit != wantLit {
    91  		t.Errorf("got *ast.BasicLit address %p, want %p", gotLit, wantLit)
    92  	}
    93  	if gotVal != wantVal {
    94  		t.Errorf("got *ast.BasicLit value %q, want %q", gotVal, wantVal)
    95  	}
    96  }
    97  
    98  func TestSource(t *testing.T) {
    99  	src, err := os.ReadFile(testfile)
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  
   104  	res, err := Source(src)
   105  	if err != nil {
   106  		t.Fatal("Source failed:", err)
   107  	}
   108  
   109  	diff(t, res, src)
   110  }
   111  
   112  // Test cases that are expected to fail are marked by the prefix "ERROR".
   113  // The formatted result must look the same as the input for successful tests.
   114  var tests = []string{
   115  	// declaration lists
   116  	`import "go/format"`,
   117  	"var x int",
   118  	"var x int\n\ntype T struct{}",
   119  
   120  	// statement lists
   121  	"x := 0",
   122  	"f(a, b, c)\nvar x int = f(1, 2, 3)",
   123  
   124  	// indentation, leading and trailing space
   125  	"\tx := 0\n\tgo f()",
   126  	"\tx := 0\n\tgo f()\n\n\n",
   127  	"\n\t\t\n\n\tx := 0\n\tgo f()\n\n\n",
   128  	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tgo f()\n\n\n",
   129  	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n",     // no indentation added inside raw strings
   130  	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\n\t\tfoo\n`\n\n\n", // no indentation removed inside raw strings
   131  
   132  	// comments
   133  	"/* Comment */",
   134  	"\t/* Comment */ ",
   135  	"\n/* Comment */ ",
   136  	"i := 5 /* Comment */",         // issue #5551
   137  	"\ta()\n//line :1",             // issue #11276
   138  	"\t//xxx\n\ta()\n//line :2",    // issue #11276
   139  	"\ta() //line :1\n\tb()\n",     // issue #11276
   140  	"x := 0\n//line :1\n//line :2", // issue #11276
   141  
   142  	// whitespace
   143  	"",     // issue #11275
   144  	" ",    // issue #11275
   145  	"\t",   // issue #11275
   146  	"\t\t", // issue #11275
   147  	"\n",   // issue #11275
   148  	"\n\n", // issue #11275
   149  	"\t\n", // issue #11275
   150  
   151  	// erroneous programs
   152  	"ERROR1 + 2 +",
   153  	"ERRORx :=  0",
   154  
   155  	// build comments
   156  	"// copyright\n\n//go:build x\n\npackage p\n",
   157  	"// copyright\n\n//go:build x\n// +build x\n\npackage p\n",
   158  }
   159  
   160  func String(s string) (string, error) {
   161  	res, err := Source([]byte(s))
   162  	if err != nil {
   163  		return "", err
   164  	}
   165  	return string(res), nil
   166  }
   167  
   168  func TestPartial(t *testing.T) {
   169  	for _, src := range tests {
   170  		if strings.HasPrefix(src, "ERROR") {
   171  			// test expected to fail
   172  			src = src[5:] // remove ERROR prefix
   173  			res, err := String(src)
   174  			if err == nil && res == src {
   175  				t.Errorf("formatting succeeded but was expected to fail:\n%q", src)
   176  			}
   177  		} else {
   178  			// test expected to succeed
   179  			res, err := String(src)
   180  			if err != nil {
   181  				t.Errorf("formatting failed (%s):\n%q", err, src)
   182  			} else if res != src {
   183  				t.Errorf("formatting incorrect:\nsource: %q\nresult: %q", src, res)
   184  			}
   185  		}
   186  	}
   187  }
   188  

View as plain text