.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / internal / lsp / tests / tests.go
1 // Copyright 2019 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 tests exports functionality to be used across a variety of gopls tests.
6 package tests
7
8 import (
9         "bytes"
10         "context"
11         "flag"
12         "fmt"
13         "go/ast"
14         "go/token"
15         "io/ioutil"
16         "os"
17         "path/filepath"
18         "regexp"
19         "sort"
20         "strconv"
21         "strings"
22         "sync"
23         "testing"
24         "time"
25
26         "golang.org/x/tools/go/expect"
27         "golang.org/x/tools/go/packages"
28         "golang.org/x/tools/go/packages/packagestest"
29         "golang.org/x/tools/internal/lsp/protocol"
30         "golang.org/x/tools/internal/lsp/source"
31         "golang.org/x/tools/internal/lsp/source/completion"
32         "golang.org/x/tools/internal/span"
33         "golang.org/x/tools/internal/testenv"
34         "golang.org/x/tools/txtar"
35 )
36
37 const (
38         overlayFileSuffix = ".overlay"
39         goldenFileSuffix  = ".golden"
40         inFileSuffix      = ".in"
41         summaryFile       = "summary.txt"
42         testModule        = "golang.org/x/tools/internal/lsp"
43 )
44
45 var UpdateGolden = flag.Bool("golden", false, "Update golden files")
46
47 type CallHierarchy map[span.Span]*CallHierarchyResult
48 type CodeLens map[span.URI][]protocol.CodeLens
49 type Diagnostics map[span.URI][]*source.Diagnostic
50 type CompletionItems map[token.Pos]*completion.CompletionItem
51 type Completions map[span.Span][]Completion
52 type CompletionSnippets map[span.Span][]CompletionSnippet
53 type UnimportedCompletions map[span.Span][]Completion
54 type DeepCompletions map[span.Span][]Completion
55 type FuzzyCompletions map[span.Span][]Completion
56 type CaseSensitiveCompletions map[span.Span][]Completion
57 type RankCompletions map[span.Span][]Completion
58 type FoldingRanges []span.Span
59 type Formats []span.Span
60 type Imports []span.Span
61 type SemanticTokens []span.Span
62 type SuggestedFixes map[span.Span][]string
63 type FunctionExtractions map[span.Span]span.Span
64 type Definitions map[span.Span]Definition
65 type Implementations map[span.Span][]span.Span
66 type Highlights map[span.Span][]span.Span
67 type References map[span.Span][]span.Span
68 type Renames map[span.Span]string
69 type PrepareRenames map[span.Span]*source.PrepareItem
70 type Symbols map[span.URI][]protocol.DocumentSymbol
71 type SymbolsChildren map[string][]protocol.DocumentSymbol
72 type SymbolInformation map[span.Span]protocol.SymbolInformation
73 type WorkspaceSymbols map[WorkspaceSymbolsTestType]map[span.URI][]string
74 type Signatures map[span.Span]*protocol.SignatureHelp
75 type Links map[span.URI][]Link
76
77 type Data struct {
78         Config                   packages.Config
79         Exported                 *packagestest.Exported
80         CallHierarchy            CallHierarchy
81         CodeLens                 CodeLens
82         Diagnostics              Diagnostics
83         CompletionItems          CompletionItems
84         Completions              Completions
85         CompletionSnippets       CompletionSnippets
86         UnimportedCompletions    UnimportedCompletions
87         DeepCompletions          DeepCompletions
88         FuzzyCompletions         FuzzyCompletions
89         CaseSensitiveCompletions CaseSensitiveCompletions
90         RankCompletions          RankCompletions
91         FoldingRanges            FoldingRanges
92         Formats                  Formats
93         Imports                  Imports
94         SemanticTokens           SemanticTokens
95         SuggestedFixes           SuggestedFixes
96         FunctionExtractions      FunctionExtractions
97         Definitions              Definitions
98         Implementations          Implementations
99         Highlights               Highlights
100         References               References
101         Renames                  Renames
102         PrepareRenames           PrepareRenames
103         Symbols                  Symbols
104         symbolsChildren          SymbolsChildren
105         symbolInformation        SymbolInformation
106         WorkspaceSymbols         WorkspaceSymbols
107         Signatures               Signatures
108         Links                    Links
109
110         t         testing.TB
111         fragments map[string]string
112         dir       string
113         golden    map[string]*Golden
114         mode      string
115
116         ModfileFlagAvailable bool
117
118         mappersMu sync.Mutex
119         mappers   map[span.URI]*protocol.ColumnMapper
120 }
121
122 type Tests interface {
123         CallHierarchy(*testing.T, span.Span, *CallHierarchyResult)
124         CodeLens(*testing.T, span.URI, []protocol.CodeLens)
125         Diagnostics(*testing.T, span.URI, []*source.Diagnostic)
126         Completion(*testing.T, span.Span, Completion, CompletionItems)
127         CompletionSnippet(*testing.T, span.Span, CompletionSnippet, bool, CompletionItems)
128         UnimportedCompletion(*testing.T, span.Span, Completion, CompletionItems)
129         DeepCompletion(*testing.T, span.Span, Completion, CompletionItems)
130         FuzzyCompletion(*testing.T, span.Span, Completion, CompletionItems)
131         CaseSensitiveCompletion(*testing.T, span.Span, Completion, CompletionItems)
132         RankCompletion(*testing.T, span.Span, Completion, CompletionItems)
133         FoldingRanges(*testing.T, span.Span)
134         Format(*testing.T, span.Span)
135         Import(*testing.T, span.Span)
136         SemanticTokens(*testing.T, span.Span)
137         SuggestedFix(*testing.T, span.Span, []string, int)
138         FunctionExtraction(*testing.T, span.Span, span.Span)
139         Definition(*testing.T, span.Span, Definition)
140         Implementation(*testing.T, span.Span, []span.Span)
141         Highlight(*testing.T, span.Span, []span.Span)
142         References(*testing.T, span.Span, []span.Span)
143         Rename(*testing.T, span.Span, string)
144         PrepareRename(*testing.T, span.Span, *source.PrepareItem)
145         Symbols(*testing.T, span.URI, []protocol.DocumentSymbol)
146         WorkspaceSymbols(*testing.T, span.URI, string, WorkspaceSymbolsTestType)
147         SignatureHelp(*testing.T, span.Span, *protocol.SignatureHelp)
148         Link(*testing.T, span.URI, []Link)
149 }
150
151 type Definition struct {
152         Name      string
153         IsType    bool
154         OnlyHover bool
155         Src, Def  span.Span
156 }
157
158 type CompletionTestType int
159
160 const (
161         // Default runs the standard completion tests.
162         CompletionDefault = CompletionTestType(iota)
163
164         // Unimported tests the autocompletion of unimported packages.
165         CompletionUnimported
166
167         // Deep tests deep completion.
168         CompletionDeep
169
170         // Fuzzy tests deep completion and fuzzy matching.
171         CompletionFuzzy
172
173         // CaseSensitive tests case sensitive completion.
174         CompletionCaseSensitive
175
176         // CompletionRank candidates in test must be valid and in the right relative order.
177         CompletionRank
178 )
179
180 type WorkspaceSymbolsTestType int
181
182 const (
183         // Default runs the standard workspace symbols tests.
184         WorkspaceSymbolsDefault = WorkspaceSymbolsTestType(iota)
185
186         // Fuzzy tests workspace symbols with fuzzy matching.
187         WorkspaceSymbolsFuzzy
188
189         // CaseSensitive tests workspace symbols with case sensitive.
190         WorkspaceSymbolsCaseSensitive
191 )
192
193 type Completion struct {
194         CompletionItems []token.Pos
195 }
196
197 type CompletionSnippet struct {
198         CompletionItem     token.Pos
199         PlainSnippet       string
200         PlaceholderSnippet string
201 }
202
203 type CallHierarchyResult struct {
204         IncomingCalls, OutgoingCalls []protocol.CallHierarchyItem
205 }
206
207 type Link struct {
208         Src          span.Span
209         Target       string
210         NotePosition token.Position
211 }
212
213 type Golden struct {
214         Filename string
215         Archive  *txtar.Archive
216         Modified bool
217 }
218
219 func Context(t testing.TB) context.Context {
220         return context.Background()
221 }
222
223 func DefaultOptions(o *source.Options) {
224         o.SupportedCodeActions = map[source.FileKind]map[protocol.CodeActionKind]bool{
225                 source.Go: {
226                         protocol.SourceOrganizeImports: true,
227                         protocol.QuickFix:              true,
228                         protocol.RefactorRewrite:       true,
229                         protocol.RefactorExtract:       true,
230                         protocol.SourceFixAll:          true,
231                 },
232                 source.Mod: {
233                         protocol.SourceOrganizeImports: true,
234                 },
235                 source.Sum: {},
236         }
237         o.UserOptions.Codelenses[source.CommandTest.Name] = true
238         o.HoverKind = source.SynopsisDocumentation
239         o.InsertTextFormat = protocol.SnippetTextFormat
240         o.CompletionBudget = time.Minute
241         o.HierarchicalDocumentSymbolSupport = true
242         o.ExperimentalWorkspaceModule = true
243         o.SemanticTokens = true
244 }
245
246 func RunTests(t *testing.T, dataDir string, includeMultiModule bool, f func(*testing.T, *Data)) {
247         t.Helper()
248         modes := []string{"Modules", "GOPATH"}
249         if includeMultiModule {
250                 modes = append(modes, "MultiModule")
251         }
252         for _, mode := range modes {
253                 t.Run(mode, func(t *testing.T) {
254                         t.Helper()
255                         if mode == "MultiModule" {
256                                 // Some bug in 1.12 breaks reading markers, and it's not worth figuring out.
257                                 testenv.NeedsGo1Point(t, 13)
258                         }
259                         datum := load(t, mode, dataDir)
260                         f(t, datum)
261                 })
262         }
263 }
264
265 func load(t testing.TB, mode string, dir string) *Data {
266         t.Helper()
267
268         datum := &Data{
269                 CallHierarchy:            make(CallHierarchy),
270                 CodeLens:                 make(CodeLens),
271                 Diagnostics:              make(Diagnostics),
272                 CompletionItems:          make(CompletionItems),
273                 Completions:              make(Completions),
274                 CompletionSnippets:       make(CompletionSnippets),
275                 UnimportedCompletions:    make(UnimportedCompletions),
276                 DeepCompletions:          make(DeepCompletions),
277                 FuzzyCompletions:         make(FuzzyCompletions),
278                 RankCompletions:          make(RankCompletions),
279                 CaseSensitiveCompletions: make(CaseSensitiveCompletions),
280                 Definitions:              make(Definitions),
281                 Implementations:          make(Implementations),
282                 Highlights:               make(Highlights),
283                 References:               make(References),
284                 Renames:                  make(Renames),
285                 PrepareRenames:           make(PrepareRenames),
286                 SuggestedFixes:           make(SuggestedFixes),
287                 FunctionExtractions:      make(FunctionExtractions),
288                 Symbols:                  make(Symbols),
289                 symbolsChildren:          make(SymbolsChildren),
290                 symbolInformation:        make(SymbolInformation),
291                 WorkspaceSymbols:         make(WorkspaceSymbols),
292                 Signatures:               make(Signatures),
293                 Links:                    make(Links),
294
295                 t:         t,
296                 dir:       dir,
297                 fragments: map[string]string{},
298                 golden:    map[string]*Golden{},
299                 mode:      mode,
300                 mappers:   map[span.URI]*protocol.ColumnMapper{},
301         }
302
303         if !*UpdateGolden {
304                 summary := filepath.Join(filepath.FromSlash(dir), summaryFile+goldenFileSuffix)
305                 if _, err := os.Stat(summary); os.IsNotExist(err) {
306                         t.Fatalf("could not find golden file summary.txt in %#v", dir)
307                 }
308                 archive, err := txtar.ParseFile(summary)
309                 if err != nil {
310                         t.Fatalf("could not read golden file %v/%v: %v", dir, summary, err)
311                 }
312                 datum.golden[summaryFile] = &Golden{
313                         Filename: summary,
314                         Archive:  archive,
315                 }
316         }
317
318         files := packagestest.MustCopyFileTree(dir)
319         overlays := map[string][]byte{}
320         for fragment, operation := range files {
321                 if trimmed := strings.TrimSuffix(fragment, goldenFileSuffix); trimmed != fragment {
322                         delete(files, fragment)
323                         goldFile := filepath.Join(dir, fragment)
324                         archive, err := txtar.ParseFile(goldFile)
325                         if err != nil {
326                                 t.Fatalf("could not read golden file %v: %v", fragment, err)
327                         }
328                         datum.golden[trimmed] = &Golden{
329                                 Filename: goldFile,
330                                 Archive:  archive,
331                         }
332                 } else if trimmed := strings.TrimSuffix(fragment, inFileSuffix); trimmed != fragment {
333                         delete(files, fragment)
334                         files[trimmed] = operation
335                 } else if index := strings.Index(fragment, overlayFileSuffix); index >= 0 {
336                         delete(files, fragment)
337                         partial := fragment[:index] + fragment[index+len(overlayFileSuffix):]
338                         contents, err := ioutil.ReadFile(filepath.Join(dir, fragment))
339                         if err != nil {
340                                 t.Fatal(err)
341                         }
342                         overlays[partial] = contents
343                 }
344         }
345
346         modules := []packagestest.Module{
347                 {
348                         Name:    testModule,
349                         Files:   files,
350                         Overlay: overlays,
351                 },
352         }
353         switch mode {
354         case "Modules":
355                 datum.Exported = packagestest.Export(t, packagestest.Modules, modules)
356         case "GOPATH":
357                 datum.Exported = packagestest.Export(t, packagestest.GOPATH, modules)
358         case "MultiModule":
359                 files := map[string]interface{}{}
360                 for k, v := range modules[0].Files {
361                         files[filepath.Join("testmodule", k)] = v
362                 }
363                 modules[0].Files = files
364
365                 overlays := map[string][]byte{}
366                 for k, v := range modules[0].Overlay {
367                         overlays[filepath.Join("testmodule", k)] = v
368                 }
369                 modules[0].Overlay = overlays
370
371                 golden := map[string]*Golden{}
372                 for k, v := range datum.golden {
373                         if k == summaryFile {
374                                 golden[k] = v
375                         } else {
376                                 golden[filepath.Join("testmodule", k)] = v
377                         }
378                 }
379                 datum.golden = golden
380
381                 datum.Exported = packagestest.Export(t, packagestest.Modules, modules)
382         default:
383                 panic("unknown mode " + mode)
384         }
385
386         for _, m := range modules {
387                 for fragment := range m.Files {
388                         filename := datum.Exported.File(m.Name, fragment)
389                         datum.fragments[filename] = fragment
390                 }
391         }
392
393         // Turn off go/packages debug logging.
394         datum.Exported.Config.Logf = nil
395         datum.Config.Logf = nil
396
397         // Merge the exported.Config with the view.Config.
398         datum.Config = *datum.Exported.Config
399         datum.Config.Fset = token.NewFileSet()
400         datum.Config.Context = Context(nil)
401         datum.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
402                 panic("ParseFile should not be called")
403         }
404
405         // Do a first pass to collect special markers for completion and workspace symbols.
406         if err := datum.Exported.Expect(map[string]interface{}{
407                 "item": func(name string, r packagestest.Range, _ []string) {
408                         datum.Exported.Mark(name, r)
409                 },
410                 "symbol": func(name string, r packagestest.Range, _ []string) {
411                         datum.Exported.Mark(name, r)
412                 },
413         }); err != nil {
414                 t.Fatal(err)
415         }
416
417         // Collect any data that needs to be used by subsequent tests.
418         if err := datum.Exported.Expect(map[string]interface{}{
419                 "codelens":        datum.collectCodeLens,
420                 "diag":            datum.collectDiagnostics,
421                 "item":            datum.collectCompletionItems,
422                 "complete":        datum.collectCompletions(CompletionDefault),
423                 "unimported":      datum.collectCompletions(CompletionUnimported),
424                 "deep":            datum.collectCompletions(CompletionDeep),
425                 "fuzzy":           datum.collectCompletions(CompletionFuzzy),
426                 "casesensitive":   datum.collectCompletions(CompletionCaseSensitive),
427                 "rank":            datum.collectCompletions(CompletionRank),
428                 "snippet":         datum.collectCompletionSnippets,
429                 "fold":            datum.collectFoldingRanges,
430                 "format":          datum.collectFormats,
431                 "import":          datum.collectImports,
432                 "semantic":        datum.collectSemanticTokens,
433                 "godef":           datum.collectDefinitions,
434                 "implementations": datum.collectImplementations,
435                 "typdef":          datum.collectTypeDefinitions,
436                 "hover":           datum.collectHoverDefinitions,
437                 "highlight":       datum.collectHighlights,
438                 "refs":            datum.collectReferences,
439                 "rename":          datum.collectRenames,
440                 "prepare":         datum.collectPrepareRenames,
441                 "symbol":          datum.collectSymbols,
442                 "signature":       datum.collectSignatures,
443                 "link":            datum.collectLinks,
444                 "suggestedfix":    datum.collectSuggestedFixes,
445                 "extractfunc":     datum.collectFunctionExtractions,
446                 "incomingcalls":   datum.collectIncomingCalls,
447                 "outgoingcalls":   datum.collectOutgoingCalls,
448         }); err != nil {
449                 t.Fatal(err)
450         }
451         for _, symbols := range datum.Symbols {
452                 for i := range symbols {
453                         children := datum.symbolsChildren[symbols[i].Name]
454                         symbols[i].Children = children
455                 }
456         }
457         // Collect names for the entries that require golden files.
458         if err := datum.Exported.Expect(map[string]interface{}{
459                 "godef":                        datum.collectDefinitionNames,
460                 "hover":                        datum.collectDefinitionNames,
461                 "workspacesymbol":              datum.collectWorkspaceSymbols(WorkspaceSymbolsDefault),
462                 "workspacesymbolfuzzy":         datum.collectWorkspaceSymbols(WorkspaceSymbolsFuzzy),
463                 "workspacesymbolcasesensitive": datum.collectWorkspaceSymbols(WorkspaceSymbolsCaseSensitive),
464         }); err != nil {
465                 t.Fatal(err)
466         }
467         if mode == "MultiModule" {
468                 if err := os.Rename(filepath.Join(datum.Config.Dir, "go.mod"), filepath.Join(datum.Config.Dir, "testmodule/go.mod")); err != nil {
469                         t.Fatal(err)
470                 }
471         }
472
473         return datum
474 }
475
476 func Run(t *testing.T, tests Tests, data *Data) {
477         t.Helper()
478         checkData(t, data)
479
480         eachCompletion := func(t *testing.T, cases map[span.Span][]Completion, test func(*testing.T, span.Span, Completion, CompletionItems)) {
481                 t.Helper()
482
483                 for src, exp := range cases {
484                         for i, e := range exp {
485                                 t.Run(SpanName(src)+"_"+strconv.Itoa(i), func(t *testing.T) {
486                                         t.Helper()
487                                         if strings.Contains(t.Name(), "cgo") {
488                                                 testenv.NeedsTool(t, "cgo")
489                                         }
490                                         if strings.Contains(t.Name(), "declarecgo") {
491                                                 testenv.NeedsGo1Point(t, 15)
492                                         }
493                                         test(t, src, e, data.CompletionItems)
494                                 })
495                         }
496
497                 }
498         }
499
500         t.Run("CallHierarchy", func(t *testing.T) {
501                 t.Helper()
502                 for spn, callHierarchyResult := range data.CallHierarchy {
503                         t.Run(SpanName(spn), func(t *testing.T) {
504                                 t.Helper()
505                                 tests.CallHierarchy(t, spn, callHierarchyResult)
506                         })
507                 }
508         })
509
510         t.Run("Completion", func(t *testing.T) {
511                 t.Helper()
512                 eachCompletion(t, data.Completions, tests.Completion)
513         })
514
515         t.Run("CompletionSnippets", func(t *testing.T) {
516                 t.Helper()
517                 for _, placeholders := range []bool{true, false} {
518                         for src, expecteds := range data.CompletionSnippets {
519                                 for i, expected := range expecteds {
520                                         name := SpanName(src) + "_" + strconv.Itoa(i+1)
521                                         if placeholders {
522                                                 name += "_placeholders"
523                                         }
524
525                                         t.Run(name, func(t *testing.T) {
526                                                 t.Helper()
527                                                 tests.CompletionSnippet(t, src, expected, placeholders, data.CompletionItems)
528                                         })
529                                 }
530                         }
531                 }
532         })
533
534         t.Run("UnimportedCompletion", func(t *testing.T) {
535                 t.Helper()
536                 eachCompletion(t, data.UnimportedCompletions, tests.UnimportedCompletion)
537         })
538
539         t.Run("DeepCompletion", func(t *testing.T) {
540                 t.Helper()
541                 eachCompletion(t, data.DeepCompletions, tests.DeepCompletion)
542         })
543
544         t.Run("FuzzyCompletion", func(t *testing.T) {
545                 t.Helper()
546                 eachCompletion(t, data.FuzzyCompletions, tests.FuzzyCompletion)
547         })
548
549         t.Run("CaseSensitiveCompletion", func(t *testing.T) {
550                 t.Helper()
551                 eachCompletion(t, data.CaseSensitiveCompletions, tests.CaseSensitiveCompletion)
552         })
553
554         t.Run("RankCompletions", func(t *testing.T) {
555                 t.Helper()
556                 eachCompletion(t, data.RankCompletions, tests.RankCompletion)
557         })
558
559         t.Run("CodeLens", func(t *testing.T) {
560                 t.Helper()
561                 for uri, want := range data.CodeLens {
562                         // Check if we should skip this URI if the -modfile flag is not available.
563                         if shouldSkip(data, uri) {
564                                 continue
565                         }
566                         t.Run(uriName(uri), func(t *testing.T) {
567                                 t.Helper()
568                                 tests.CodeLens(t, uri, want)
569                         })
570                 }
571         })
572
573         t.Run("Diagnostics", func(t *testing.T) {
574                 t.Helper()
575                 for uri, want := range data.Diagnostics {
576                         // Check if we should skip this URI if the -modfile flag is not available.
577                         if shouldSkip(data, uri) {
578                                 continue
579                         }
580                         t.Run(uriName(uri), func(t *testing.T) {
581                                 t.Helper()
582                                 tests.Diagnostics(t, uri, want)
583                         })
584                 }
585         })
586
587         t.Run("FoldingRange", func(t *testing.T) {
588                 t.Helper()
589                 for _, spn := range data.FoldingRanges {
590                         t.Run(uriName(spn.URI()), func(t *testing.T) {
591                                 t.Helper()
592                                 tests.FoldingRanges(t, spn)
593                         })
594                 }
595         })
596
597         t.Run("Format", func(t *testing.T) {
598                 t.Helper()
599                 for _, spn := range data.Formats {
600                         t.Run(uriName(spn.URI()), func(t *testing.T) {
601                                 t.Helper()
602                                 tests.Format(t, spn)
603                         })
604                 }
605         })
606
607         t.Run("Import", func(t *testing.T) {
608                 t.Helper()
609                 for _, spn := range data.Imports {
610                         t.Run(uriName(spn.URI()), func(t *testing.T) {
611                                 t.Helper()
612                                 tests.Import(t, spn)
613                         })
614                 }
615         })
616
617         t.Run("SemanticTokens", func(t *testing.T) {
618                 t.Helper()
619                 for _, spn := range data.SemanticTokens {
620                         t.Run(uriName(spn.URI()), func(t *testing.T) {
621                                 t.Helper()
622                                 tests.SemanticTokens(t, spn)
623                         })
624                 }
625         })
626
627         t.Run("SuggestedFix", func(t *testing.T) {
628                 t.Helper()
629                 for spn, actionKinds := range data.SuggestedFixes {
630                         // Check if we should skip this spn if the -modfile flag is not available.
631                         if shouldSkip(data, spn.URI()) {
632                                 continue
633                         }
634                         t.Run(SpanName(spn), func(t *testing.T) {
635                                 t.Helper()
636                                 tests.SuggestedFix(t, spn, actionKinds, 1)
637                         })
638                 }
639         })
640
641         t.Run("FunctionExtraction", func(t *testing.T) {
642                 t.Helper()
643                 for start, end := range data.FunctionExtractions {
644                         // Check if we should skip this spn if the -modfile flag is not available.
645                         if shouldSkip(data, start.URI()) {
646                                 continue
647                         }
648                         t.Run(SpanName(start), func(t *testing.T) {
649                                 t.Helper()
650                                 tests.FunctionExtraction(t, start, end)
651                         })
652                 }
653         })
654
655         t.Run("Definition", func(t *testing.T) {
656                 t.Helper()
657                 for spn, d := range data.Definitions {
658                         t.Run(SpanName(spn), func(t *testing.T) {
659                                 t.Helper()
660                                 if strings.Contains(t.Name(), "cgo") {
661                                         testenv.NeedsTool(t, "cgo")
662                                 }
663                                 if strings.Contains(t.Name(), "declarecgo") {
664                                         testenv.NeedsGo1Point(t, 15)
665                                 }
666                                 tests.Definition(t, spn, d)
667                         })
668                 }
669         })
670
671         t.Run("Implementation", func(t *testing.T) {
672                 t.Helper()
673                 for spn, m := range data.Implementations {
674                         t.Run(SpanName(spn), func(t *testing.T) {
675                                 t.Helper()
676                                 tests.Implementation(t, spn, m)
677                         })
678                 }
679         })
680
681         t.Run("Highlight", func(t *testing.T) {
682                 t.Helper()
683                 for pos, locations := range data.Highlights {
684                         t.Run(SpanName(pos), func(t *testing.T) {
685                                 t.Helper()
686                                 tests.Highlight(t, pos, locations)
687                         })
688                 }
689         })
690
691         t.Run("References", func(t *testing.T) {
692                 t.Helper()
693                 for src, itemList := range data.References {
694                         t.Run(SpanName(src), func(t *testing.T) {
695                                 t.Helper()
696                                 tests.References(t, src, itemList)
697                         })
698                 }
699         })
700
701         t.Run("Renames", func(t *testing.T) {
702                 t.Helper()
703                 for spn, newText := range data.Renames {
704                         t.Run(uriName(spn.URI())+"_"+newText, func(t *testing.T) {
705                                 t.Helper()
706                                 tests.Rename(t, spn, newText)
707                         })
708                 }
709         })
710
711         t.Run("PrepareRenames", func(t *testing.T) {
712                 t.Helper()
713                 for src, want := range data.PrepareRenames {
714                         t.Run(SpanName(src), func(t *testing.T) {
715                                 t.Helper()
716                                 tests.PrepareRename(t, src, want)
717                         })
718                 }
719         })
720
721         t.Run("Symbols", func(t *testing.T) {
722                 t.Helper()
723                 for uri, expectedSymbols := range data.Symbols {
724                         t.Run(uriName(uri), func(t *testing.T) {
725                                 t.Helper()
726                                 tests.Symbols(t, uri, expectedSymbols)
727                         })
728                 }
729         })
730
731         t.Run("WorkspaceSymbols", func(t *testing.T) {
732                 t.Helper()
733
734                 for _, typ := range []WorkspaceSymbolsTestType{
735                         WorkspaceSymbolsDefault,
736                         WorkspaceSymbolsCaseSensitive,
737                         WorkspaceSymbolsFuzzy,
738                 } {
739                         for uri, cases := range data.WorkspaceSymbols[typ] {
740                                 for _, query := range cases {
741                                         name := query
742                                         if name == "" {
743                                                 name = "EmptyQuery"
744                                         }
745                                         t.Run(name, func(t *testing.T) {
746                                                 t.Helper()
747                                                 tests.WorkspaceSymbols(t, uri, query, typ)
748                                         })
749                                 }
750                         }
751                 }
752
753         })
754
755         t.Run("SignatureHelp", func(t *testing.T) {
756                 t.Helper()
757                 for spn, expectedSignature := range data.Signatures {
758                         t.Run(SpanName(spn), func(t *testing.T) {
759                                 t.Helper()
760                                 tests.SignatureHelp(t, spn, expectedSignature)
761                         })
762                 }
763         })
764
765         t.Run("Link", func(t *testing.T) {
766                 t.Helper()
767                 for uri, wantLinks := range data.Links {
768                         // If we are testing GOPATH, then we do not want links with the versions
769                         // attached (pkg.go.dev/repoa/moda@v1.1.0/pkg), unless the file is a
770                         // go.mod, then we can skip it altogether.
771                         if data.Exported.Exporter == packagestest.GOPATH {
772                                 if strings.HasSuffix(uri.Filename(), ".mod") {
773                                         continue
774                                 }
775                                 re := regexp.MustCompile(`@v\d+\.\d+\.[\w-]+`)
776                                 for i, link := range wantLinks {
777                                         wantLinks[i].Target = re.ReplaceAllString(link.Target, "")
778                                 }
779                         }
780                         t.Run(uriName(uri), func(t *testing.T) {
781                                 t.Helper()
782                                 tests.Link(t, uri, wantLinks)
783                         })
784                 }
785         })
786
787         if *UpdateGolden {
788                 for _, golden := range data.golden {
789                         if !golden.Modified {
790                                 continue
791                         }
792                         sort.Slice(golden.Archive.Files, func(i, j int) bool {
793                                 return golden.Archive.Files[i].Name < golden.Archive.Files[j].Name
794                         })
795                         if err := ioutil.WriteFile(golden.Filename, txtar.Format(golden.Archive), 0666); err != nil {
796                                 t.Fatal(err)
797                         }
798                 }
799         }
800 }
801
802 func checkData(t *testing.T, data *Data) {
803         buf := &bytes.Buffer{}
804         diagnosticsCount := 0
805         for _, want := range data.Diagnostics {
806                 diagnosticsCount += len(want)
807         }
808         linksCount := 0
809         for _, want := range data.Links {
810                 linksCount += len(want)
811         }
812         definitionCount := 0
813         typeDefinitionCount := 0
814         for _, d := range data.Definitions {
815                 if d.IsType {
816                         typeDefinitionCount++
817                 } else {
818                         definitionCount++
819                 }
820         }
821
822         snippetCount := 0
823         for _, want := range data.CompletionSnippets {
824                 snippetCount += len(want)
825         }
826
827         countCompletions := func(c map[span.Span][]Completion) (count int) {
828                 for _, want := range c {
829                         count += len(want)
830                 }
831                 return count
832         }
833
834         countCodeLens := func(c map[span.URI][]protocol.CodeLens) (count int) {
835                 for _, want := range c {
836                         count += len(want)
837                 }
838                 return count
839         }
840
841         countWorkspaceSymbols := func(c map[WorkspaceSymbolsTestType]map[span.URI][]string) (count int) {
842                 for _, typs := range c {
843                         for _, queries := range typs {
844                                 count += len(queries)
845                         }
846                 }
847                 return count
848         }
849
850         fmt.Fprintf(buf, "CallHierarchyCount = %v\n", len(data.CallHierarchy))
851         fmt.Fprintf(buf, "CodeLensCount = %v\n", countCodeLens(data.CodeLens))
852         fmt.Fprintf(buf, "CompletionsCount = %v\n", countCompletions(data.Completions))
853         fmt.Fprintf(buf, "CompletionSnippetCount = %v\n", snippetCount)
854         fmt.Fprintf(buf, "UnimportedCompletionsCount = %v\n", countCompletions(data.UnimportedCompletions))
855         fmt.Fprintf(buf, "DeepCompletionsCount = %v\n", countCompletions(data.DeepCompletions))
856         fmt.Fprintf(buf, "FuzzyCompletionsCount = %v\n", countCompletions(data.FuzzyCompletions))
857         fmt.Fprintf(buf, "RankedCompletionsCount = %v\n", countCompletions(data.RankCompletions))
858         fmt.Fprintf(buf, "CaseSensitiveCompletionsCount = %v\n", countCompletions(data.CaseSensitiveCompletions))
859         fmt.Fprintf(buf, "DiagnosticsCount = %v\n", diagnosticsCount)
860         fmt.Fprintf(buf, "FoldingRangesCount = %v\n", len(data.FoldingRanges))
861         fmt.Fprintf(buf, "FormatCount = %v\n", len(data.Formats))
862         fmt.Fprintf(buf, "ImportCount = %v\n", len(data.Imports))
863         fmt.Fprintf(buf, "SemanticTokenCount = %v\n", len(data.SemanticTokens))
864         fmt.Fprintf(buf, "SuggestedFixCount = %v\n", len(data.SuggestedFixes))
865         fmt.Fprintf(buf, "FunctionExtractionCount = %v\n", len(data.FunctionExtractions))
866         fmt.Fprintf(buf, "DefinitionsCount = %v\n", definitionCount)
867         fmt.Fprintf(buf, "TypeDefinitionsCount = %v\n", typeDefinitionCount)
868         fmt.Fprintf(buf, "HighlightsCount = %v\n", len(data.Highlights))
869         fmt.Fprintf(buf, "ReferencesCount = %v\n", len(data.References))
870         fmt.Fprintf(buf, "RenamesCount = %v\n", len(data.Renames))
871         fmt.Fprintf(buf, "PrepareRenamesCount = %v\n", len(data.PrepareRenames))
872         fmt.Fprintf(buf, "SymbolsCount = %v\n", len(data.Symbols))
873         fmt.Fprintf(buf, "WorkspaceSymbolsCount = %v\n", countWorkspaceSymbols(data.WorkspaceSymbols))
874         fmt.Fprintf(buf, "SignaturesCount = %v\n", len(data.Signatures))
875         fmt.Fprintf(buf, "LinksCount = %v\n", linksCount)
876         fmt.Fprintf(buf, "ImplementationsCount = %v\n", len(data.Implementations))
877
878         want := string(data.Golden("summary", summaryFile, func() ([]byte, error) {
879                 return buf.Bytes(), nil
880         }))
881         got := buf.String()
882         if want != got {
883                 t.Errorf("test summary does not match:\n%s", Diff(t, want, got))
884         }
885 }
886
887 func (data *Data) Mapper(uri span.URI) (*protocol.ColumnMapper, error) {
888         data.mappersMu.Lock()
889         defer data.mappersMu.Unlock()
890
891         if _, ok := data.mappers[uri]; !ok {
892                 content, err := data.Exported.FileContents(uri.Filename())
893                 if err != nil {
894                         return nil, err
895                 }
896                 converter := span.NewContentConverter(uri.Filename(), content)
897                 data.mappers[uri] = &protocol.ColumnMapper{
898                         URI:       uri,
899                         Converter: converter,
900                         Content:   content,
901                 }
902         }
903         return data.mappers[uri], nil
904 }
905
906 func (data *Data) Golden(tag string, target string, update func() ([]byte, error)) []byte {
907         data.t.Helper()
908         fragment, found := data.fragments[target]
909         if !found {
910                 if filepath.IsAbs(target) {
911                         data.t.Fatalf("invalid golden file fragment %v", target)
912                 }
913                 fragment = target
914         }
915         golden := data.golden[fragment]
916         if golden == nil {
917                 if !*UpdateGolden {
918                         data.t.Fatalf("could not find golden file %v: %v", fragment, tag)
919                 }
920                 golden = &Golden{
921                         Filename: filepath.Join(data.dir, fragment+goldenFileSuffix),
922                         Archive:  &txtar.Archive{},
923                         Modified: true,
924                 }
925                 data.golden[fragment] = golden
926         }
927         var file *txtar.File
928         for i := range golden.Archive.Files {
929                 f := &golden.Archive.Files[i]
930                 if f.Name == tag {
931                         file = f
932                         break
933                 }
934         }
935         if *UpdateGolden {
936                 if file == nil {
937                         golden.Archive.Files = append(golden.Archive.Files, txtar.File{
938                                 Name: tag,
939                         })
940                         file = &golden.Archive.Files[len(golden.Archive.Files)-1]
941                 }
942                 contents, err := update()
943                 if err != nil {
944                         data.t.Fatalf("could not update golden file %v: %v", fragment, err)
945                 }
946                 file.Data = append(contents, '\n') // add trailing \n for txtar
947                 golden.Modified = true
948
949         }
950         if file == nil {
951                 data.t.Fatalf("could not find golden contents %v: %v", fragment, tag)
952         }
953         if len(file.Data) == 0 {
954                 return file.Data
955         }
956         return file.Data[:len(file.Data)-1] // drop the trailing \n
957 }
958
959 func (data *Data) collectCodeLens(spn span.Span, title, cmd string) {
960         if _, ok := data.CodeLens[spn.URI()]; !ok {
961                 data.CodeLens[spn.URI()] = []protocol.CodeLens{}
962         }
963         m, err := data.Mapper(spn.URI())
964         if err != nil {
965                 return
966         }
967         rng, err := m.Range(spn)
968         if err != nil {
969                 return
970         }
971         data.CodeLens[spn.URI()] = append(data.CodeLens[spn.URI()], protocol.CodeLens{
972                 Range: rng,
973                 Command: protocol.Command{
974                         Title:   title,
975                         Command: cmd,
976                 },
977         })
978 }
979
980 func (data *Data) collectDiagnostics(spn span.Span, msgSource, msg, msgSeverity string) {
981         if _, ok := data.Diagnostics[spn.URI()]; !ok {
982                 data.Diagnostics[spn.URI()] = []*source.Diagnostic{}
983         }
984         m, err := data.Mapper(spn.URI())
985         if err != nil {
986                 return
987         }
988         rng, err := m.Range(spn)
989         if err != nil {
990                 return
991         }
992         severity := protocol.SeverityError
993         switch msgSeverity {
994         case "error":
995                 severity = protocol.SeverityError
996         case "warning":
997                 severity = protocol.SeverityWarning
998         case "hint":
999                 severity = protocol.SeverityHint
1000         case "information":
1001                 severity = protocol.SeverityInformation
1002         }
1003         // This is not the correct way to do this, but it seems excessive to do the full conversion here.
1004         want := &source.Diagnostic{
1005                 Range:    rng,
1006                 Severity: severity,
1007                 Source:   msgSource,
1008                 Message:  msg,
1009         }
1010         data.Diagnostics[spn.URI()] = append(data.Diagnostics[spn.URI()], want)
1011 }
1012
1013 func (data *Data) collectCompletions(typ CompletionTestType) func(span.Span, []token.Pos) {
1014         result := func(m map[span.Span][]Completion, src span.Span, expected []token.Pos) {
1015                 m[src] = append(m[src], Completion{
1016                         CompletionItems: expected,
1017                 })
1018         }
1019         switch typ {
1020         case CompletionDeep:
1021                 return func(src span.Span, expected []token.Pos) {
1022                         result(data.DeepCompletions, src, expected)
1023                 }
1024         case CompletionUnimported:
1025                 return func(src span.Span, expected []token.Pos) {
1026                         result(data.UnimportedCompletions, src, expected)
1027                 }
1028         case CompletionFuzzy:
1029                 return func(src span.Span, expected []token.Pos) {
1030                         result(data.FuzzyCompletions, src, expected)
1031                 }
1032         case CompletionRank:
1033                 return func(src span.Span, expected []token.Pos) {
1034                         result(data.RankCompletions, src, expected)
1035                 }
1036         case CompletionCaseSensitive:
1037                 return func(src span.Span, expected []token.Pos) {
1038                         result(data.CaseSensitiveCompletions, src, expected)
1039                 }
1040         default:
1041                 return func(src span.Span, expected []token.Pos) {
1042                         result(data.Completions, src, expected)
1043                 }
1044         }
1045 }
1046
1047 func (data *Data) collectCompletionItems(pos token.Pos, args []string) {
1048         if len(args) < 3 {
1049                 loc := data.Exported.ExpectFileSet.Position(pos)
1050                 data.t.Fatalf("%s:%d: @item expects at least 3 args, got %d",
1051                         loc.Filename, loc.Line, len(args))
1052         }
1053         label, detail, kind := args[0], args[1], args[2]
1054         var documentation string
1055         if len(args) == 4 {
1056                 documentation = args[3]
1057         }
1058         data.CompletionItems[pos] = &completion.CompletionItem{
1059                 Label:         label,
1060                 Detail:        detail,
1061                 Kind:          protocol.ParseCompletionItemKind(kind),
1062                 Documentation: documentation,
1063         }
1064 }
1065
1066 func (data *Data) collectFoldingRanges(spn span.Span) {
1067         data.FoldingRanges = append(data.FoldingRanges, spn)
1068 }
1069
1070 func (data *Data) collectFormats(spn span.Span) {
1071         data.Formats = append(data.Formats, spn)
1072 }
1073
1074 func (data *Data) collectImports(spn span.Span) {
1075         data.Imports = append(data.Imports, spn)
1076 }
1077
1078 func (data *Data) collectSemanticTokens(spn span.Span) {
1079         data.SemanticTokens = append(data.SemanticTokens, spn)
1080 }
1081
1082 func (data *Data) collectSuggestedFixes(spn span.Span, actionKind string) {
1083         if _, ok := data.SuggestedFixes[spn]; !ok {
1084                 data.SuggestedFixes[spn] = []string{}
1085         }
1086         data.SuggestedFixes[spn] = append(data.SuggestedFixes[spn], actionKind)
1087 }
1088
1089 func (data *Data) collectFunctionExtractions(start span.Span, end span.Span) {
1090         if _, ok := data.FunctionExtractions[start]; !ok {
1091                 data.FunctionExtractions[start] = end
1092         }
1093 }
1094
1095 func (data *Data) collectDefinitions(src, target span.Span) {
1096         data.Definitions[src] = Definition{
1097                 Src: src,
1098                 Def: target,
1099         }
1100 }
1101
1102 func (data *Data) collectImplementations(src span.Span, targets []span.Span) {
1103         data.Implementations[src] = targets
1104 }
1105
1106 func (data *Data) collectIncomingCalls(src span.Span, calls []span.Span) {
1107         for _, call := range calls {
1108                 m, err := data.Mapper(call.URI())
1109                 if err != nil {
1110                         data.t.Fatal(err)
1111                 }
1112                 rng, err := m.Range(call)
1113                 if err != nil {
1114                         data.t.Fatal(err)
1115                 }
1116                 // we're only comparing protocol.range
1117                 if data.CallHierarchy[src] != nil {
1118                         data.CallHierarchy[src].IncomingCalls = append(data.CallHierarchy[src].IncomingCalls,
1119                                 protocol.CallHierarchyItem{
1120                                         URI:   protocol.DocumentURI(call.URI()),
1121                                         Range: rng,
1122                                 })
1123                 } else {
1124                         data.CallHierarchy[src] = &CallHierarchyResult{
1125                                 IncomingCalls: []protocol.CallHierarchyItem{
1126                                         {URI: protocol.DocumentURI(call.URI()), Range: rng},
1127                                 },
1128                         }
1129                 }
1130         }
1131 }
1132
1133 func (data *Data) collectOutgoingCalls(src span.Span, calls []span.Span) {
1134         if data.CallHierarchy[src] == nil {
1135                 data.CallHierarchy[src] = &CallHierarchyResult{}
1136         }
1137         for _, call := range calls {
1138                 m, err := data.Mapper(call.URI())
1139                 if err != nil {
1140                         data.t.Fatal(err)
1141                 }
1142                 rng, err := m.Range(call)
1143                 if err != nil {
1144                         data.t.Fatal(err)
1145                 }
1146                 // we're only comparing protocol.range
1147                 data.CallHierarchy[src].OutgoingCalls = append(data.CallHierarchy[src].OutgoingCalls,
1148                         protocol.CallHierarchyItem{
1149                                 URI:   protocol.DocumentURI(call.URI()),
1150                                 Range: rng,
1151                         })
1152         }
1153 }
1154
1155 func (data *Data) collectHoverDefinitions(src, target span.Span) {
1156         data.Definitions[src] = Definition{
1157                 Src:       src,
1158                 Def:       target,
1159                 OnlyHover: true,
1160         }
1161 }
1162
1163 func (data *Data) collectTypeDefinitions(src, target span.Span) {
1164         data.Definitions[src] = Definition{
1165                 Src:    src,
1166                 Def:    target,
1167                 IsType: true,
1168         }
1169 }
1170
1171 func (data *Data) collectDefinitionNames(src span.Span, name string) {
1172         d := data.Definitions[src]
1173         d.Name = name
1174         data.Definitions[src] = d
1175 }
1176
1177 func (data *Data) collectHighlights(src span.Span, expected []span.Span) {
1178         // Declaring a highlight in a test file: @highlight(src, expected1, expected2)
1179         data.Highlights[src] = append(data.Highlights[src], expected...)
1180 }
1181
1182 func (data *Data) collectReferences(src span.Span, expected []span.Span) {
1183         data.References[src] = expected
1184 }
1185
1186 func (data *Data) collectRenames(src span.Span, newText string) {
1187         data.Renames[src] = newText
1188 }
1189
1190 func (data *Data) collectPrepareRenames(src span.Span, rng span.Range, placeholder string) {
1191         m, err := data.Mapper(src.URI())
1192         if err != nil {
1193                 data.t.Fatal(err)
1194         }
1195         // Convert range to span and then to protocol.Range.
1196         spn, err := rng.Span()
1197         if err != nil {
1198                 data.t.Fatal(err)
1199         }
1200         prng, err := m.Range(spn)
1201         if err != nil {
1202                 data.t.Fatal(err)
1203         }
1204         data.PrepareRenames[src] = &source.PrepareItem{
1205                 Range: prng,
1206                 Text:  placeholder,
1207         }
1208 }
1209
1210 // collectSymbols is responsible for collecting @symbol annotations.
1211 func (data *Data) collectSymbols(name string, spn span.Span, kind string, parentName string, siName string) {
1212         m, err := data.Mapper(spn.URI())
1213         if err != nil {
1214                 data.t.Fatal(err)
1215         }
1216         rng, err := m.Range(spn)
1217         if err != nil {
1218                 data.t.Fatal(err)
1219         }
1220         sym := protocol.DocumentSymbol{
1221                 Name:           name,
1222                 Kind:           protocol.ParseSymbolKind(kind),
1223                 SelectionRange: rng,
1224         }
1225         if parentName == "" {
1226                 data.Symbols[spn.URI()] = append(data.Symbols[spn.URI()], sym)
1227         } else {
1228                 data.symbolsChildren[parentName] = append(data.symbolsChildren[parentName], sym)
1229         }
1230
1231         // Reuse @symbol in the workspace symbols tests.
1232         si := protocol.SymbolInformation{
1233                 Name: siName,
1234                 Kind: sym.Kind,
1235                 Location: protocol.Location{
1236                         URI:   protocol.URIFromSpanURI(spn.URI()),
1237                         Range: sym.SelectionRange,
1238                 },
1239         }
1240         data.symbolInformation[spn] = si
1241 }
1242
1243 func (data *Data) collectWorkspaceSymbols(typ WorkspaceSymbolsTestType) func(*expect.Note, string) {
1244         return func(note *expect.Note, query string) {
1245                 if data.WorkspaceSymbols[typ] == nil {
1246                         data.WorkspaceSymbols[typ] = make(map[span.URI][]string)
1247                 }
1248                 pos := data.Exported.ExpectFileSet.Position(note.Pos)
1249                 uri := span.URIFromPath(pos.Filename)
1250                 data.WorkspaceSymbols[typ][uri] = append(data.WorkspaceSymbols[typ][uri], query)
1251         }
1252 }
1253
1254 func (data *Data) collectSignatures(spn span.Span, signature string, activeParam int64) {
1255         data.Signatures[spn] = &protocol.SignatureHelp{
1256                 Signatures: []protocol.SignatureInformation{
1257                         {
1258                                 Label: signature,
1259                         },
1260                 },
1261                 ActiveParameter: float64(activeParam),
1262         }
1263         // Hardcode special case to test the lack of a signature.
1264         if signature == "" && activeParam == 0 {
1265                 data.Signatures[spn] = nil
1266         }
1267 }
1268
1269 func (data *Data) collectCompletionSnippets(spn span.Span, item token.Pos, plain, placeholder string) {
1270         data.CompletionSnippets[spn] = append(data.CompletionSnippets[spn], CompletionSnippet{
1271                 CompletionItem:     item,
1272                 PlainSnippet:       plain,
1273                 PlaceholderSnippet: placeholder,
1274         })
1275 }
1276
1277 func (data *Data) collectLinks(spn span.Span, link string, note *expect.Note, fset *token.FileSet) {
1278         position := fset.Position(note.Pos)
1279         uri := spn.URI()
1280         data.Links[uri] = append(data.Links[uri], Link{
1281                 Src:          spn,
1282                 Target:       link,
1283                 NotePosition: position,
1284         })
1285 }
1286
1287 func uriName(uri span.URI) string {
1288         return filepath.Base(strings.TrimSuffix(uri.Filename(), ".go"))
1289 }
1290
1291 func SpanName(spn span.Span) string {
1292         return fmt.Sprintf("%v_%v_%v", uriName(spn.URI()), spn.Start().Line(), spn.Start().Column())
1293 }
1294
1295 func CopyFolderToTempDir(folder string) (string, error) {
1296         if _, err := os.Stat(folder); err != nil {
1297                 return "", err
1298         }
1299         dst, err := ioutil.TempDir("", "modfile_test")
1300         if err != nil {
1301                 return "", err
1302         }
1303         fds, err := ioutil.ReadDir(folder)
1304         if err != nil {
1305                 return "", err
1306         }
1307         for _, fd := range fds {
1308                 srcfp := filepath.Join(folder, fd.Name())
1309                 stat, err := os.Stat(srcfp)
1310                 if err != nil {
1311                         return "", err
1312                 }
1313                 if !stat.Mode().IsRegular() {
1314                         return "", fmt.Errorf("cannot copy non regular file %s", srcfp)
1315                 }
1316                 contents, err := ioutil.ReadFile(srcfp)
1317                 if err != nil {
1318                         return "", err
1319                 }
1320                 if err := ioutil.WriteFile(filepath.Join(dst, fd.Name()), contents, stat.Mode()); err != nil {
1321                         return "", err
1322                 }
1323         }
1324         return dst, nil
1325 }
1326
1327 func shouldSkip(data *Data, uri span.URI) bool {
1328         if data.ModfileFlagAvailable {
1329                 return false
1330         }
1331         // If the -modfile flag is not available, then we do not want to run
1332         // any tests on the go.mod file.
1333         if strings.HasSuffix(uri.Filename(), ".mod") {
1334                 return true
1335         }
1336         // If the -modfile flag is not available, then we do not want to test any
1337         // uri that contains "go mod tidy".
1338         m, err := data.Mapper(uri)
1339         return err == nil && strings.Contains(string(m.Content), ", \"go mod tidy\",")
1340 }