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 }