golang.org/x/tools/gopls@v0.15.3/internal/cache/port_test.go (about)

     1  // Copyright 2023 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 cache
     6  
     7  import (
     8  	"os"
     9  	"testing"
    10  
    11  	"github.com/google/go-cmp/cmp"
    12  	"golang.org/x/sync/errgroup"
    13  	"golang.org/x/tools/go/packages"
    14  	"golang.org/x/tools/gopls/internal/file"
    15  	"golang.org/x/tools/gopls/internal/protocol"
    16  	"golang.org/x/tools/gopls/internal/util/bug"
    17  	"golang.org/x/tools/internal/testenv"
    18  )
    19  
    20  func TestMain(m *testing.M) {
    21  	bug.PanicOnBugs = true
    22  	os.Exit(m.Run())
    23  }
    24  
    25  func TestMatchingPortsStdlib(t *testing.T) {
    26  	// This test checks that we don't encounter a bug when matching ports, and
    27  	// sanity checks that the optimization to use trimmed/fake file content
    28  	// before delegating to go/build.Context.MatchFile does not affect
    29  	// correctness.
    30  	if testing.Short() {
    31  		t.Skip("skipping in short mode: takes to long on slow file systems")
    32  	}
    33  
    34  	testenv.NeedsTool(t, "go")
    35  
    36  	// Load, parse and type-check the program.
    37  	cfg := &packages.Config{
    38  		Mode:  packages.LoadFiles,
    39  		Tests: true,
    40  	}
    41  	pkgs, err := packages.Load(cfg, "std", "cmd")
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  
    46  	var g errgroup.Group
    47  	packages.Visit(pkgs, nil, func(pkg *packages.Package) {
    48  		for _, f := range pkg.CompiledGoFiles {
    49  			f := f
    50  			g.Go(func() error {
    51  				content, err := os.ReadFile(f)
    52  				// We report errors via t.Error, not by returning,
    53  				// so that a single test can report multiple test failures.
    54  				if err != nil {
    55  					t.Errorf("failed to read %s: %v", f, err)
    56  					return nil
    57  				}
    58  				fh := makeFakeFileHandle(protocol.URIFromPath(f), content)
    59  				fastPorts := matchingPreferredPorts(t, fh, true)
    60  				slowPorts := matchingPreferredPorts(t, fh, false)
    61  				if diff := cmp.Diff(fastPorts, slowPorts); diff != "" {
    62  					t.Errorf("%s: ports do not match (-trimmed +untrimmed):\n%s", f, diff)
    63  					return nil
    64  				}
    65  				return nil
    66  			})
    67  		}
    68  	})
    69  	g.Wait()
    70  }
    71  
    72  func matchingPreferredPorts(tb testing.TB, fh file.Handle, trimContent bool) map[port]unit {
    73  	content, err := fh.Content()
    74  	if err != nil {
    75  		tb.Fatal(err)
    76  	}
    77  	if trimContent {
    78  		content = trimContentForPortMatch(content)
    79  	}
    80  	path := fh.URI().Path()
    81  	matching := make(map[port]unit)
    82  	for _, port := range preferredPorts {
    83  		if port.matches(path, content) {
    84  			matching[port] = unit{}
    85  		}
    86  	}
    87  	return matching
    88  }
    89  
    90  func BenchmarkMatchingPreferredPorts(b *testing.B) {
    91  	// Copy of robustio_posix.go
    92  	const src = `
    93  // Copyright 2022 The Go Authors. All rights reserved.
    94  // Use of this source code is governed by a BSD-style
    95  // license that can be found in the LICENSE file.
    96  
    97  //go:build !windows && !plan9
    98  // +build !windows,!plan9
    99  
   100  // TODO(adonovan): use 'unix' tag when go1.19 can be assumed.
   101  
   102  package robustio
   103  
   104  import (
   105  	"os"
   106  	"syscall"
   107  	"time"
   108  )
   109  
   110  func getFileID(filename string) (FileID, time.Time, error) {
   111  	fi, err := os.Stat(filename)
   112  	if err != nil {
   113  		return FileID{}, time.Time{}, err
   114  	}
   115  	stat := fi.Sys().(*syscall.Stat_t)
   116  	return FileID{
   117  		device: uint64(stat.Dev), // (int32 on darwin, uint64 on linux)
   118  		inode:  stat.Ino,
   119  	}, fi.ModTime(), nil
   120  }
   121  `
   122  	fh := makeFakeFileHandle("file:///path/to/test/file.go", []byte(src))
   123  	for i := 0; i < b.N; i++ {
   124  		_ = matchingPreferredPorts(b, fh, true)
   125  	}
   126  }