.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / go / packages / packagestest / export.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/packages/packagestest/export.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/packages/packagestest/export.go
new file mode 100644 (file)
index 0000000..6b03926
--- /dev/null
@@ -0,0 +1,514 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package packagestest creates temporary projects on disk for testing go tools on.
+
+By changing the exporter used, you can create projects for multiple build
+systems from the same description, and run the same tests on them in many
+cases.
+
+Example
+
+As an example of packagestest use, consider the following test that runs
+the 'go list' command on the specified modules:
+
+       // TestGoList exercises the 'go list' command in module mode and in GOPATH mode.
+       func TestGoList(t *testing.T) { packagestest.TestAll(t, testGoList) }
+       func testGoList(t *testing.T, x packagestest.Exporter) {
+               e := packagestest.Export(t, x, []packagestest.Module{
+                       {
+                               Name: "gopher.example/repoa",
+                               Files: map[string]interface{}{
+                                       "a/a.go": "package a",
+                               },
+                       },
+                       {
+                               Name: "gopher.example/repob",
+                               Files: map[string]interface{}{
+                                       "b/b.go": "package b",
+                               },
+                       },
+               })
+               defer e.Cleanup()
+
+               cmd := exec.Command("go", "list", "gopher.example/...")
+               cmd.Dir = e.Config.Dir
+               cmd.Env = e.Config.Env
+               out, err := cmd.Output()
+               if err != nil {
+                       t.Fatal(err)
+               }
+               t.Logf("'go list gopher.example/...' with %s mode layout:\n%s", x.Name(), out)
+       }
+
+TestGoList uses TestAll to exercise the 'go list' command with all
+exporters known to packagestest. Currently, packagestest includes
+exporters that produce module mode layouts and GOPATH mode layouts.
+Running the test with verbose output will print:
+
+       === RUN   TestGoList
+       === RUN   TestGoList/GOPATH
+       === RUN   TestGoList/Modules
+       --- PASS: TestGoList (0.21s)
+           --- PASS: TestGoList/GOPATH (0.03s)
+               main_test.go:36: 'go list gopher.example/...' with GOPATH mode layout:
+                   gopher.example/repoa/a
+                   gopher.example/repob/b
+           --- PASS: TestGoList/Modules (0.18s)
+               main_test.go:36: 'go list gopher.example/...' with Modules mode layout:
+                   gopher.example/repoa/a
+                   gopher.example/repob/b
+
+*/
+package packagestest
+
+import (
+       "flag"
+       "fmt"
+       "go/token"
+       "io/ioutil"
+       "log"
+       "os"
+       "path/filepath"
+       "strings"
+       "testing"
+
+       "golang.org/x/tools/go/expect"
+       "golang.org/x/tools/go/packages"
+       "golang.org/x/tools/internal/span"
+       "golang.org/x/tools/internal/testenv"
+)
+
+var (
+       skipCleanup = flag.Bool("skip-cleanup", false, "Do not delete the temporary export folders") // for debugging
+)
+
+// Module is a representation of a go module.
+type Module struct {
+       // Name is the base name of the module as it would be in the go.mod file.
+       Name string
+       // Files is the set of source files for all packages that make up the module.
+       // The keys are the file fragment that follows the module name, the value can
+       // be a string or byte slice, in which case it is the contents of the
+       // file, otherwise it must be a Writer function.
+       Files map[string]interface{}
+
+       // Overlay is the set of source file overlays for the module.
+       // The keys are the file fragment as in the Files configuration.
+       // The values are the in memory overlay content for the file.
+       Overlay map[string][]byte
+}
+
+// A Writer is a function that writes out a test file.
+// It is provided the name of the file to write, and may return an error if it
+// cannot write the file.
+// These are used as the content of the Files map in a Module.
+type Writer func(filename string) error
+
+// Exported is returned by the Export function to report the structure that was produced on disk.
+type Exported struct {
+       // Config is a correctly configured packages.Config ready to be passed to packages.Load.
+       // Exactly what it will contain varies depending on the Exporter being used.
+       Config *packages.Config
+
+       // Modules is the module description that was used to produce this exported data set.
+       Modules []Module
+
+       ExpectFileSet *token.FileSet // The file set used when parsing expectations
+
+       Exporter Exporter                     // the exporter used
+       temp     string                       // the temporary directory that was exported to
+       primary  string                       // the first non GOROOT module that was exported
+       written  map[string]map[string]string // the full set of exported files
+       notes    []*expect.Note               // The list of expectations extracted from go source files
+       markers  map[string]span.Range        // The set of markers extracted from go source files
+}
+
+// Exporter implementations are responsible for converting from the generic description of some
+// test data to a driver specific file layout.
+type Exporter interface {
+       // Name reports the name of the exporter, used in logging and sub-test generation.
+       Name() string
+       // Filename reports the system filename for test data source file.
+       // It is given the base directory, the module the file is part of and the filename fragment to
+       // work from.
+       Filename(exported *Exported, module, fragment string) string
+       // Finalize is called once all files have been written to write any extra data needed and modify
+       // the Config to match. It is handed the full list of modules that were encountered while writing
+       // files.
+       Finalize(exported *Exported) error
+}
+
+// All is the list of known exporters.
+// This is used by TestAll to run tests with all the exporters.
+var All []Exporter
+
+// TestAll invokes the testing function once for each exporter registered in
+// the All global.
+// Each exporter will be run as a sub-test named after the exporter being used.
+func TestAll(t *testing.T, f func(*testing.T, Exporter)) {
+       t.Helper()
+       for _, e := range All {
+               t.Run(e.Name(), func(t *testing.T) {
+                       t.Helper()
+                       f(t, e)
+               })
+       }
+}
+
+// BenchmarkAll invokes the testing function once for each exporter registered in
+// the All global.
+// Each exporter will be run as a sub-test named after the exporter being used.
+func BenchmarkAll(b *testing.B, f func(*testing.B, Exporter)) {
+       b.Helper()
+       for _, e := range All {
+               b.Run(e.Name(), func(b *testing.B) {
+                       b.Helper()
+                       f(b, e)
+               })
+       }
+}
+
+// Export is called to write out a test directory from within a test function.
+// It takes the exporter and the build system agnostic module descriptions, and
+// uses them to build a temporary directory.
+// It returns an Exported with the results of the export.
+// The Exported.Config is prepared for loading from the exported data.
+// You must invoke Exported.Cleanup on the returned value to clean up.
+// The file deletion in the cleanup can be skipped by setting the skip-cleanup
+// flag when invoking the test, allowing the temporary directory to be left for
+// debugging tests.
+func Export(t testing.TB, exporter Exporter, modules []Module) *Exported {
+       t.Helper()
+       if exporter == Modules {
+               testenv.NeedsTool(t, "go")
+       }
+
+       dirname := strings.Replace(t.Name(), "/", "_", -1)
+       dirname = strings.Replace(dirname, "#", "_", -1) // duplicate subtests get a #NNN suffix.
+       temp, err := ioutil.TempDir("", dirname)
+       if err != nil {
+               t.Fatal(err)
+       }
+       exported := &Exported{
+               Config: &packages.Config{
+                       Dir:     temp,
+                       Env:     append(os.Environ(), "GOPACKAGESDRIVER=off", "GOROOT="), // Clear GOROOT to work around #32849.
+                       Overlay: make(map[string][]byte),
+                       Tests:   true,
+                       Mode:    packages.LoadImports,
+               },
+               Modules:       modules,
+               Exporter:      exporter,
+               temp:          temp,
+               primary:       modules[0].Name,
+               written:       map[string]map[string]string{},
+               ExpectFileSet: token.NewFileSet(),
+       }
+       defer func() {
+               if t.Failed() || t.Skipped() {
+                       exported.Cleanup()
+               }
+       }()
+       for _, module := range modules {
+               for fragment, value := range module.Files {
+                       fullpath := exporter.Filename(exported, module.Name, filepath.FromSlash(fragment))
+                       written, ok := exported.written[module.Name]
+                       if !ok {
+                               written = map[string]string{}
+                               exported.written[module.Name] = written
+                       }
+                       written[fragment] = fullpath
+                       if err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil {
+                               t.Fatal(err)
+                       }
+                       switch value := value.(type) {
+                       case Writer:
+                               if err := value(fullpath); err != nil {
+                                       t.Fatal(err)
+                               }
+                       case string:
+                               if err := ioutil.WriteFile(fullpath, []byte(value), 0644); err != nil {
+                                       t.Fatal(err)
+                               }
+                       default:
+                               t.Fatalf("Invalid type %T in files, must be string or Writer", value)
+                       }
+               }
+               for fragment, value := range module.Overlay {
+                       fullpath := exporter.Filename(exported, module.Name, filepath.FromSlash(fragment))
+                       exported.Config.Overlay[fullpath] = value
+               }
+       }
+       if err := exporter.Finalize(exported); err != nil {
+               t.Fatal(err)
+       }
+       testenv.NeedsGoPackagesEnv(t, exported.Config.Env)
+       return exported
+}
+
+// Script returns a Writer that writes out contents to the file and sets the
+// executable bit on the created file.
+// It is intended for source files that are shell scripts.
+func Script(contents string) Writer {
+       return func(filename string) error {
+               return ioutil.WriteFile(filename, []byte(contents), 0755)
+       }
+}
+
+// Link returns a Writer that creates a hard link from the specified source to
+// the required file.
+// This is used to link testdata files into the generated testing tree.
+func Link(source string) Writer {
+       return func(filename string) error {
+               return os.Link(source, filename)
+       }
+}
+
+// Symlink returns a Writer that creates a symlink from the specified source to the
+// required file.
+// This is used to link testdata files into the generated testing tree.
+func Symlink(source string) Writer {
+       if !strings.HasPrefix(source, ".") {
+               if abspath, err := filepath.Abs(source); err == nil {
+                       if _, err := os.Stat(source); !os.IsNotExist(err) {
+                               source = abspath
+                       }
+               }
+       }
+       return func(filename string) error {
+               return os.Symlink(source, filename)
+       }
+}
+
+// Copy returns a Writer that copies a file from the specified source to the
+// required file.
+// This is used to copy testdata files into the generated testing tree.
+func Copy(source string) Writer {
+       return func(filename string) error {
+               stat, err := os.Stat(source)
+               if err != nil {
+                       return err
+               }
+               if !stat.Mode().IsRegular() {
+                       // cannot copy non-regular files (e.g., directories,
+                       // symlinks, devices, etc.)
+                       return fmt.Errorf("cannot copy non regular file %s", source)
+               }
+               contents, err := ioutil.ReadFile(source)
+               if err != nil {
+                       return err
+               }
+               return ioutil.WriteFile(filename, contents, stat.Mode())
+       }
+}
+
+// GroupFilesByModules attempts to map directories to the modules within each directory.
+// This function assumes that the folder is structured in the following way:
+// - dir
+//   - primarymod
+//     - .go files
+//              - packages
+//              - go.mod (optional)
+//      - modules
+//              - repoa
+//                - mod1
+//            - .go files
+//                        -  packages
+//                      - go.mod (optional)
+// It scans the directory tree anchored at root and adds a Copy writer to the
+// map for every file found.
+// This is to enable the common case in tests where you have a full copy of the
+// package in your testdata.
+func GroupFilesByModules(root string) ([]Module, error) {
+       root = filepath.FromSlash(root)
+       primarymodPath := filepath.Join(root, "primarymod")
+
+       _, err := os.Stat(primarymodPath)
+       if os.IsNotExist(err) {
+               return nil, fmt.Errorf("could not find primarymod folder within %s", root)
+       }
+
+       primarymod := &Module{
+               Name:    root,
+               Files:   make(map[string]interface{}),
+               Overlay: make(map[string][]byte),
+       }
+       mods := map[string]*Module{
+               root: primarymod,
+       }
+       modules := []Module{*primarymod}
+
+       if err := filepath.Walk(primarymodPath, func(path string, info os.FileInfo, err error) error {
+               if err != nil {
+                       return err
+               }
+               if info.IsDir() {
+                       return nil
+               }
+               fragment, err := filepath.Rel(primarymodPath, path)
+               if err != nil {
+                       return err
+               }
+               primarymod.Files[filepath.ToSlash(fragment)] = Copy(path)
+               return nil
+       }); err != nil {
+               return nil, err
+       }
+
+       modulesPath := filepath.Join(root, "modules")
+       if _, err := os.Stat(modulesPath); os.IsNotExist(err) {
+               return modules, nil
+       }
+
+       var currentRepo, currentModule string
+       updateCurrentModule := func(dir string) {
+               if dir == currentModule {
+                       return
+               }
+               // Handle the case where we step into a nested directory that is a module
+               // and then step out into the parent which is also a module.
+               // Example:
+               // - repoa
+               //   - moda
+               //     - go.mod
+               //     - v2
+               //       - go.mod
+               //     - what.go
+               //   - modb
+               for dir != root {
+                       if mods[dir] != nil {
+                               currentModule = dir
+                               return
+                       }
+                       dir = filepath.Dir(dir)
+               }
+       }
+
+       if err := filepath.Walk(modulesPath, func(path string, info os.FileInfo, err error) error {
+               if err != nil {
+                       return err
+               }
+               enclosingDir := filepath.Dir(path)
+               // If the path is not a directory, then we want to add the path to
+               // the files map of the currentModule.
+               if !info.IsDir() {
+                       updateCurrentModule(enclosingDir)
+                       fragment, err := filepath.Rel(currentModule, path)
+                       if err != nil {
+                               return err
+                       }
+                       mods[currentModule].Files[filepath.ToSlash(fragment)] = Copy(path)
+                       return nil
+               }
+               // If the path is a directory and it's enclosing folder is equal to
+               // the modules folder, then the path is a new repo.
+               if enclosingDir == modulesPath {
+                       currentRepo = path
+                       return nil
+               }
+               // If the path is a directory and it's enclosing folder is not the same
+               // as the current repo and it is not of the form `v1`,`v2`,...
+               // then the path is a folder/package of the current module.
+               if enclosingDir != currentRepo && !versionSuffixRE.MatchString(filepath.Base(path)) {
+                       return nil
+               }
+               // If the path is a directory and it's enclosing folder is the current repo
+               // then the path is a new module.
+               module, err := filepath.Rel(modulesPath, path)
+               if err != nil {
+                       return err
+               }
+               mods[path] = &Module{
+                       Name:    filepath.ToSlash(module),
+                       Files:   make(map[string]interface{}),
+                       Overlay: make(map[string][]byte),
+               }
+               currentModule = path
+               modules = append(modules, *mods[path])
+               return nil
+       }); err != nil {
+               return nil, err
+       }
+       return modules, nil
+}
+
+// MustCopyFileTree returns a file set for a module based on a real directory tree.
+// It scans the directory tree anchored at root and adds a Copy writer to the
+// map for every file found.
+// This is to enable the common case in tests where you have a full copy of the
+// package in your testdata.
+// This will panic if there is any kind of error trying to walk the file tree.
+func MustCopyFileTree(root string) map[string]interface{} {
+       result := map[string]interface{}{}
+       if err := filepath.Walk(filepath.FromSlash(root), func(path string, info os.FileInfo, err error) error {
+               if err != nil {
+                       return err
+               }
+               if info.IsDir() {
+                       return nil
+               }
+               fragment, err := filepath.Rel(root, path)
+               if err != nil {
+                       return err
+               }
+               result[filepath.ToSlash(fragment)] = Copy(path)
+               return nil
+       }); err != nil {
+               log.Panic(fmt.Sprintf("MustCopyFileTree failed: %v", err))
+       }
+       return result
+}
+
+// Cleanup removes the temporary directory (unless the --skip-cleanup flag was set)
+// It is safe to call cleanup multiple times.
+func (e *Exported) Cleanup() {
+       if e.temp == "" {
+               return
+       }
+       if *skipCleanup {
+               log.Printf("Skipping cleanup of temp dir: %s", e.temp)
+               return
+       }
+       // Make everything read-write so that the Module exporter's module cache can be deleted.
+       filepath.Walk(e.temp, func(path string, info os.FileInfo, err error) error {
+               if err != nil {
+                       return nil
+               }
+               if info.IsDir() {
+                       os.Chmod(path, 0777)
+               }
+               return nil
+       })
+       os.RemoveAll(e.temp) // ignore errors
+       e.temp = ""
+}
+
+// Temp returns the temporary directory that was generated.
+func (e *Exported) Temp() string {
+       return e.temp
+}
+
+// File returns the full path for the given module and file fragment.
+func (e *Exported) File(module, fragment string) string {
+       if m := e.written[module]; m != nil {
+               return m[fragment]
+       }
+       return ""
+}
+
+// FileContents returns the contents of the specified file.
+// It will use the overlay if the file is present, otherwise it will read it
+// from disk.
+func (e *Exported) FileContents(filename string) ([]byte, error) {
+       if content, found := e.Config.Overlay[filename]; found {
+               return content, nil
+       }
+       content, err := ioutil.ReadFile(filename)
+       if err != nil {
+               return nil, err
+       }
+       return content, nil
+}