// Copyright 2019 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 mod import ( "context" "io/ioutil" "os" "path/filepath" "testing" "golang.org/x/tools/internal/lsp/cache" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/tests" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/testenv" ) func TestMain(m *testing.M) { testenv.ExitIfSmallMachine() os.Exit(m.Run()) } // TODO(golang/go#36091): This file can be refactored to look like lsp_test.go // when marker support gets added for go.mod files. func TestModfileRemainsUnchanged(t *testing.T) { ctx := tests.Context(t) cache := cache.New(nil) session := cache.NewSession(ctx) options := tests.DefaultOptions() options.TempModfile = true options.Env = append(os.Environ(), "GOPACKAGESDRIVER=off", "GOROOT=") // Make sure to copy the test directory to a temporary directory so we do not // modify the test code or add go.sum files when we run the tests. folder, err := tests.CopyFolderToTempDir(filepath.Join("testdata", "unchanged")) if err != nil { t.Fatal(err) } defer os.RemoveAll(folder) before, err := ioutil.ReadFile(filepath.Join(folder, "go.mod")) if err != nil { t.Fatal(err) } _, snapshot, err := session.NewView(ctx, "diagnostics_test", span.FileURI(folder), options) if err != nil { t.Fatal(err) } if !hasTempModfile(ctx, snapshot) { return } after, err := ioutil.ReadFile(filepath.Join(folder, "go.mod")) if err != nil { t.Fatal(err) } if string(before) != string(after) { t.Errorf("the real go.mod file was changed even when tempModfile=true") } } // TODO(golang/go#36091): This file can be refactored to look like lsp_test.go // when marker support gets added for go.mod files. func TestDiagnostics(t *testing.T) { ctx := tests.Context(t) cache := cache.New(nil) session := cache.NewSession(ctx) options := tests.DefaultOptions() options.TempModfile = true options.Env = append(os.Environ(), "GOPACKAGESDRIVER=off", "GOROOT=") for _, tt := range []struct { testdir string want []source.Diagnostic }{ { testdir: "indirect", want: []source.Diagnostic{ { Message: "golang.org/x/tools should be a direct dependency.", Source: "go mod tidy", // TODO(golang/go#36091): When marker support gets added for go.mod files, we // can remove these hard coded positions. Range: protocol.Range{Start: getRawPos(4, 62), End: getRawPos(4, 73)}, Severity: protocol.SeverityWarning, }, }, }, { testdir: "unused", want: []source.Diagnostic{ { Message: "golang.org/x/tools is not used in this module.", Source: "go mod tidy", Range: protocol.Range{Start: getRawPos(4, 0), End: getRawPos(4, 61)}, Severity: protocol.SeverityWarning, }, }, }, { testdir: "invalidrequire", want: []source.Diagnostic{ { Message: "usage: require module/path v1.2.3", Source: "syntax", Range: protocol.Range{Start: getRawPos(4, 0), End: getRawPos(4, 16)}, Severity: protocol.SeverityError, }, }, }, { testdir: "invalidgo", want: []source.Diagnostic{ { Message: "usage: go 1.23", Source: "syntax", Range: protocol.Range{Start: getRawPos(2, 0), End: getRawPos(2, 3)}, Severity: protocol.SeverityError, }, }, }, { testdir: "unknowndirective", want: []source.Diagnostic{ { Message: "unknown directive: yo", Source: "syntax", Range: protocol.Range{Start: getRawPos(6, 0), End: getRawPos(6, 1)}, Severity: protocol.SeverityError, }, }, }, } { t.Run(tt.testdir, func(t *testing.T) { // TODO: Once we refactor this to work with go/packages/packagestest. We do not // need to copy to a temporary directory. folder, err := tests.CopyFolderToTempDir(filepath.Join("testdata", tt.testdir)) if err != nil { t.Fatal(err) } defer os.RemoveAll(folder) _, snapshot, err := session.NewView(ctx, "diagnostics_test", span.FileURI(folder), options) if err != nil { t.Fatal(err) } // TODO: Add testing for when the -modfile flag is turned off and we still get diagnostics. if !hasTempModfile(ctx, snapshot) { return } reports, err := Diagnostics(ctx, snapshot) if err != nil { t.Fatal(err) } if len(reports) != 1 { t.Errorf("expected 1 diagnostic, got %d", len(reports)) } for fh, got := range reports { if diff := tests.DiffDiagnostics(fh.URI, tt.want, got); diff != "" { t.Error(diff) } } }) } } func hasTempModfile(ctx context.Context, snapshot source.Snapshot) bool { _, t, _ := snapshot.ModFiles(ctx) return t != nil } func getRawPos(line, character int) protocol.Position { return protocol.Position{ Line: float64(line), Character: float64(character), } }