golang.org/x/tools/gopls@v0.15.3/internal/test/integration/misc/formatting_test.go (about)

     1  // Copyright 2020 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 misc
     6  
     7  import (
     8  	"strings"
     9  	"testing"
    10  
    11  	"golang.org/x/tools/gopls/internal/test/compare"
    12  	. "golang.org/x/tools/gopls/internal/test/integration"
    13  	"golang.org/x/tools/internal/testenv"
    14  )
    15  
    16  const unformattedProgram = `
    17  -- main.go --
    18  package main
    19  import "fmt"
    20  func main(  ) {
    21  	fmt.Println("Hello World.")
    22  }
    23  -- main.go.golden --
    24  package main
    25  
    26  import "fmt"
    27  
    28  func main() {
    29  	fmt.Println("Hello World.")
    30  }
    31  `
    32  
    33  func TestFormatting(t *testing.T) {
    34  	Run(t, unformattedProgram, func(t *testing.T, env *Env) {
    35  		env.OpenFile("main.go")
    36  		env.FormatBuffer("main.go")
    37  		got := env.BufferText("main.go")
    38  		want := env.ReadWorkspaceFile("main.go.golden")
    39  		if got != want {
    40  			t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got))
    41  		}
    42  	})
    43  }
    44  
    45  // Tests golang/go#36824.
    46  func TestFormattingOneLine36824(t *testing.T) {
    47  	const onelineProgram = `
    48  -- a.go --
    49  package main; func f() {}
    50  
    51  -- a.go.formatted --
    52  package main
    53  
    54  func f() {}
    55  `
    56  	Run(t, onelineProgram, func(t *testing.T, env *Env) {
    57  		env.OpenFile("a.go")
    58  		env.FormatBuffer("a.go")
    59  		got := env.BufferText("a.go")
    60  		want := env.ReadWorkspaceFile("a.go.formatted")
    61  		if got != want {
    62  			t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got))
    63  		}
    64  	})
    65  }
    66  
    67  // Tests golang/go#36824.
    68  func TestFormattingOneLineImports36824(t *testing.T) {
    69  	const onelineProgramA = `
    70  -- a.go --
    71  package x; func f() {fmt.Println()}
    72  
    73  -- a.go.imported --
    74  package x
    75  
    76  import "fmt"
    77  
    78  func f() { fmt.Println() }
    79  `
    80  	Run(t, onelineProgramA, func(t *testing.T, env *Env) {
    81  		env.OpenFile("a.go")
    82  		env.OrganizeImports("a.go")
    83  		got := env.BufferText("a.go")
    84  		want := env.ReadWorkspaceFile("a.go.imported")
    85  		if got != want {
    86  			t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got))
    87  		}
    88  	})
    89  }
    90  
    91  func TestFormattingOneLineRmImports36824(t *testing.T) {
    92  	const onelineProgramB = `
    93  -- a.go --
    94  package x; import "os"; func f() {}
    95  
    96  -- a.go.imported --
    97  package x
    98  
    99  func f() {}
   100  `
   101  	Run(t, onelineProgramB, func(t *testing.T, env *Env) {
   102  		env.OpenFile("a.go")
   103  		env.OrganizeImports("a.go")
   104  		got := env.BufferText("a.go")
   105  		want := env.ReadWorkspaceFile("a.go.imported")
   106  		if got != want {
   107  			t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got))
   108  		}
   109  	})
   110  }
   111  
   112  const disorganizedProgram = `
   113  -- main.go --
   114  package main
   115  
   116  import (
   117  	"fmt"
   118  	"errors"
   119  )
   120  func main(  ) {
   121  	fmt.Println(errors.New("bad"))
   122  }
   123  -- main.go.organized --
   124  package main
   125  
   126  import (
   127  	"errors"
   128  	"fmt"
   129  )
   130  func main(  ) {
   131  	fmt.Println(errors.New("bad"))
   132  }
   133  -- main.go.formatted --
   134  package main
   135  
   136  import (
   137  	"errors"
   138  	"fmt"
   139  )
   140  
   141  func main() {
   142  	fmt.Println(errors.New("bad"))
   143  }
   144  `
   145  
   146  func TestOrganizeImports(t *testing.T) {
   147  	Run(t, disorganizedProgram, func(t *testing.T, env *Env) {
   148  		env.OpenFile("main.go")
   149  		env.OrganizeImports("main.go")
   150  		got := env.BufferText("main.go")
   151  		want := env.ReadWorkspaceFile("main.go.organized")
   152  		if got != want {
   153  			t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got))
   154  		}
   155  	})
   156  }
   157  
   158  func TestFormattingOnSave(t *testing.T) {
   159  	Run(t, disorganizedProgram, func(t *testing.T, env *Env) {
   160  		env.OpenFile("main.go")
   161  		env.SaveBuffer("main.go")
   162  		got := env.BufferText("main.go")
   163  		want := env.ReadWorkspaceFile("main.go.formatted")
   164  		if got != want {
   165  			t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got))
   166  		}
   167  	})
   168  }
   169  
   170  // Tests various possibilities for comments in files with CRLF line endings.
   171  // Import organization in these files has historically been a source of bugs.
   172  func TestCRLFLineEndings(t *testing.T) {
   173  	for _, tt := range []struct {
   174  		issue, input, want string
   175  	}{
   176  		{
   177  			issue: "41057",
   178  			want: `package main
   179  
   180  /*
   181  Hi description
   182  */
   183  func Hi() {
   184  }
   185  `,
   186  		},
   187  		{
   188  			issue: "42646",
   189  			want: `package main
   190  
   191  import (
   192  	"fmt"
   193  )
   194  
   195  /*
   196  func upload(c echo.Context) error {
   197  	if err := r.ParseForm(); err != nil {
   198  		fmt.Fprintf(w, "ParseForm() err: %v", err)
   199  		return
   200  	}
   201  	fmt.Fprintf(w, "POST request successful")
   202  	path_ver := r.FormValue("path_ver")
   203  	ukclin_ver := r.FormValue("ukclin_ver")
   204  
   205  	fmt.Fprintf(w, "Name = %s\n", path_ver)
   206  	fmt.Fprintf(w, "Address = %s\n", ukclin_ver)
   207  }
   208  */
   209  
   210  func main() {
   211  	const server_port = 8080
   212  	fmt.Printf("port: %d\n", server_port)
   213  }
   214  `,
   215  		},
   216  		{
   217  			issue: "42923",
   218  			want: `package main
   219  
   220  // Line 1.
   221  // aa
   222  type Tree struct {
   223  	arr []string
   224  }
   225  `,
   226  		},
   227  		{
   228  			issue: "47200",
   229  			input: `package main
   230  
   231  import "fmt"
   232  
   233  func main() {
   234  	math.Sqrt(9)
   235  	fmt.Println("hello")
   236  }
   237  `,
   238  			want: `package main
   239  
   240  import (
   241  	"fmt"
   242  	"math"
   243  )
   244  
   245  func main() {
   246  	math.Sqrt(9)
   247  	fmt.Println("hello")
   248  }
   249  `,
   250  		},
   251  	} {
   252  		t.Run(tt.issue, func(t *testing.T) {
   253  			Run(t, "-- main.go --", func(t *testing.T, env *Env) {
   254  				input := tt.input
   255  				if input == "" {
   256  					input = tt.want
   257  				}
   258  				crlf := strings.ReplaceAll(input, "\n", "\r\n")
   259  				env.CreateBuffer("main.go", crlf)
   260  				env.Await(env.DoneWithOpen())
   261  				env.OrganizeImports("main.go")
   262  				got := env.BufferText("main.go")
   263  				got = strings.ReplaceAll(got, "\r\n", "\n") // convert everything to LF for simplicity
   264  				if tt.want != got {
   265  					t.Errorf("unexpected content after save:\n%s", compare.Text(tt.want, got))
   266  				}
   267  			})
   268  		})
   269  	}
   270  }
   271  
   272  func TestFormattingOfGeneratedFile_Issue49555(t *testing.T) {
   273  	const input = `
   274  -- main.go --
   275  // Code generated by generator.go. DO NOT EDIT.
   276  
   277  package main
   278  
   279  import "fmt"
   280  
   281  func main() {
   282  
   283  
   284  
   285  
   286  	fmt.Print("hello")
   287  }
   288  `
   289  
   290  	Run(t, input, func(t *testing.T, env *Env) {
   291  		wantErrSuffix := "file is generated"
   292  
   293  		env.OpenFile("main.go")
   294  		err := env.Editor.FormatBuffer(env.Ctx, "main.go")
   295  		if err == nil {
   296  			t.Fatal("expected error, got nil")
   297  		}
   298  		// Check only the suffix because an error contains a dynamic path to main.go
   299  		if !strings.HasSuffix(err.Error(), wantErrSuffix) {
   300  			t.Fatalf("unexpected error %q, want suffix %q", err.Error(), wantErrSuffix)
   301  		}
   302  	})
   303  }
   304  
   305  func TestGofumptFormatting(t *testing.T) {
   306  	testenv.NeedsGo1Point(t, 20) // gofumpt requires go 1.20+
   307  	// Exercise some gofumpt formatting rules:
   308  	//  - No empty lines following an assignment operator
   309  	//  - Octal integer literals should use the 0o prefix on modules using Go
   310  	//    1.13 and later. Requires LangVersion to be correctly resolved.
   311  	//  - std imports must be in a separate group at the top. Requires ModulePath
   312  	//    to be correctly resolved.
   313  	const input = `
   314  -- go.mod --
   315  module foo
   316  
   317  go 1.17
   318  -- foo.go --
   319  package foo
   320  
   321  import (
   322  	"foo/bar"
   323  	"fmt"
   324  )
   325  
   326  const perm = 0755
   327  
   328  func foo() {
   329  	foo :=
   330  		"bar"
   331  	fmt.Println(foo, bar.Bar)
   332  }
   333  -- foo.go.formatted --
   334  package foo
   335  
   336  import (
   337  	"fmt"
   338  
   339  	"foo/bar"
   340  )
   341  
   342  const perm = 0o755
   343  
   344  func foo() {
   345  	foo := "bar"
   346  	fmt.Println(foo, bar.Bar)
   347  }
   348  -- bar/bar.go --
   349  package bar
   350  
   351  const Bar = 42
   352  `
   353  
   354  	WithOptions(
   355  		Settings{
   356  			"gofumpt": true,
   357  		},
   358  	).Run(t, input, func(t *testing.T, env *Env) {
   359  		env.OpenFile("foo.go")
   360  		env.FormatBuffer("foo.go")
   361  		got := env.BufferText("foo.go")
   362  		want := env.ReadWorkspaceFile("foo.go.formatted")
   363  		if got != want {
   364  			t.Errorf("unexpected formatting result:\n%s", compare.Text(want, got))
   365  		}
   366  	})
   367  }
   368  
   369  func TestGofumpt_Issue61692(t *testing.T) {
   370  	testenv.NeedsGo1Point(t, 21)
   371  
   372  	const input = `
   373  -- go.mod --
   374  module foo
   375  
   376  go 1.21rc3
   377  -- foo.go --
   378  package foo
   379  
   380  func _() {
   381  	foo :=
   382  		"bar"
   383  }
   384  `
   385  
   386  	WithOptions(
   387  		Settings{
   388  			"gofumpt": true,
   389  		},
   390  	).Run(t, input, func(t *testing.T, env *Env) {
   391  		env.OpenFile("foo.go")
   392  		env.FormatBuffer("foo.go") // golang/go#61692: must not panic
   393  	})
   394  }