codekingpro/portable-devtools
114k
1// Copyright 2012 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package format6 7import (8 "bytes"9 "go/ast"10 "go/parser"11 "go/token"12 "os"13 "strings"14 "testing"15)16 17const testfile = "format_test.go"18 19func diff(t *testing.T, dst, src []byte) {20 line := 121 offs := 0 // line offset22 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 return29 }30 if s == '\n' {31 line++32 offs = i + 133 }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 40func 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.Buffer53 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.63func 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 node76 // 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.Value79 80 var buf bytes.Buffer81 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.Value89 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 98func 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.114var tests = []string{115 // declaration lists116 `import "go/format"`,117 "var x int",118 "var x int\n\ntype T struct{}",119 120 // statement lists121 "x := 0",122 "f(a, b, c)\nvar x int = f(1, 2, 3)",123 124 // indentation, leading and trailing space125 "\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 strings130 "\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 strings131 132 // comments133 "/* Comment */",134 "\t/* Comment */ ",135 "\n/* Comment */ ",136 "i := 5 /* Comment */", // issue #5551137 "\ta()\n//line :1", // issue #11276138 "\t//xxx\n\ta()\n//line :2", // issue #11276139 "\ta() //line :1\n\tb()\n", // issue #11276140 "x := 0\n//line :1\n//line :2", // issue #11276141 142 // whitespace143 "", // issue #11275144 " ", // issue #11275145 "\t", // issue #11275146 "\t\t", // issue #11275147 "\n", // issue #11275148 "\n\n", // issue #11275149 "\t\n", // issue #11275150 151 // erroneous programs152 "ERROR1 + 2 +",153 "ERRORx := 0",154 155 // build comments156 "// 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 160func String(s string) (string, error) {161 res, err := Source([]byte(s))162 if err != nil {163 return "", err164 }165 return string(res), nil166}167 168func TestPartial(t *testing.T) {169 for _, src := range tests {170 if strings.HasPrefix(src, "ERROR") {171 // test expected to fail172 src = src[5:] // remove ERROR prefix173 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 succeed179 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 