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