blob: 1077c21ac36e9365c9f1f624ca4869b49bc47ac5 [file] [log] [blame]
// Copyright 2020 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 misc
import (
"testing"
. "golang.org/x/tools/gopls/internal/test/integration"
"golang.org/x/tools/internal/testenv"
)
// Test that enabling and disabling produces the expected results of showing
// and hiding staticcheck analysis results.
func TestChangeConfiguration(t *testing.T) {
const files = `
-- go.mod --
module mod.com
go 1.12
-- a/a.go --
package a
import "errors"
// FooErr should be called ErrFoo (ST1012)
var FooErr = errors.New("foo")
`
Run(t, files, func(t *testing.T, env *Env) {
env.OpenFile("a/a.go")
env.AfterChange(
NoDiagnostics(ForFile("a/a.go")),
)
cfg := env.Editor.Config()
cfg.Settings = map[string]any{
"staticcheck": true,
}
env.ChangeConfiguration(cfg)
env.AfterChange(
Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)")),
)
})
}
func TestIdenticalConfiguration(t *testing.T) {
// This test checks that changing configuration does not cause views to be
// recreated if there is no configuration change.
const files = `
-- a.go --
package p
func _() {
var x *int
y := *x
_ = y
}
`
Run(t, files, func(t *testing.T, env *Env) {
// Sanity check: before disabling the nilness analyzer, we should have a
// diagnostic for the nil dereference.
env.OpenFile("a.go")
env.AfterChange(
Diagnostics(
ForFile("a.go"),
WithMessage("nil dereference"),
),
)
// Collect the view ID before changing configuration.
viewID := func() string {
t.Helper()
views := env.Views()
if len(views) != 1 {
t.Fatalf("got %d views, want 1", len(views))
}
return views[0].ID
}
before := viewID()
// Now disable the nilness analyzer.
cfg := env.Editor.Config()
cfg.Settings = map[string]any{
"analyses": map[string]any{
"nilness": false,
},
}
// This should cause the diagnostic to disappear...
env.ChangeConfiguration(cfg)
env.AfterChange(
NoDiagnostics(),
)
// ...and we should be on the second view.
after := viewID()
if after == before {
t.Errorf("after configuration change, got view %q (same as before), want new view", after)
}
// Now change configuration again, this time with the same configuration as
// before. We should still have no diagnostics...
env.ChangeConfiguration(cfg)
env.AfterChange(
NoDiagnostics(),
)
// ...and we should still be on the second view.
if got := viewID(); got != after {
t.Errorf("after second configuration change, got view %q, want %q", got, after)
}
})
}
// Test that clients can configure per-workspace configuration, which is
// queried via the scopeURI of a workspace/configuration request.
// (this was broken in golang/go#65519).
func TestWorkspaceConfiguration(t *testing.T) {
const files = `
-- go.mod --
module example.com/config
go 1.18
-- a/a.go --
package a
import "example.com/config/b"
func _() {
_ = b.B{2}
}
-- b/b.go --
package b
type B struct {
F int
}
`
WithOptions(
WorkspaceFolders("a"),
FolderSettings{
"a": {
"analyses": map[string]bool{
"composites": false,
},
},
},
).Run(t, files, func(t *testing.T, env *Env) {
env.OpenFile("a/a.go")
env.AfterChange(NoDiagnostics())
})
}
// TestMajorOptionsChange is like TestChangeConfiguration, but modifies an
// an open buffer before making a major (but inconsequential) change that
// causes gopls to recreate the view.
//
// Gopls should not get confused about buffer content when recreating the view.
func TestMajorOptionsChange(t *testing.T) {
const files = `
-- go.mod --
module mod.com
go 1.12
-- a/a.go --
package a
import "errors"
var ErrFoo = errors.New("foo")
`
Run(t, files, func(t *testing.T, env *Env) {
env.OpenFile("a/a.go")
// Introduce a staticcheck diagnostic. It should be detected when we enable
// staticcheck later.
env.RegexpReplace("a/a.go", "ErrFoo", "FooErr")
env.AfterChange(
NoDiagnostics(ForFile("a/a.go")),
)
cfg := env.Editor.Config()
// Any change to environment recreates the view, but this should not cause
// gopls to get confused about the content of a/a.go: we should get the
// staticcheck diagnostic below.
cfg.Env = map[string]string{
"AN_ARBITRARY_VAR": "FOO",
}
cfg.Settings = map[string]interface{}{
"staticcheck": true,
}
env.ChangeConfiguration(cfg)
env.AfterChange(
Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)")),
)
})
}
func TestStaticcheckWarning(t *testing.T) {
// Note: keep this in sync with TestChangeConfiguration.
testenv.SkipAfterGo1Point(t, 19)
const files = `
-- go.mod --
module mod.com
go 1.12
-- a/a.go --
package a
import "errors"
// FooErr should be called ErrFoo (ST1012)
var FooErr = errors.New("foo")
`
WithOptions(
Settings{"staticcheck": true},
).Run(t, files, func(t *testing.T, env *Env) {
env.OnceMet(
InitialWorkspaceLoad,
ShownMessage("staticcheck is not supported"),
)
})
}
func TestDeprecatedSettings(t *testing.T) {
WithOptions(
Settings{
"experimentalUseInvalidMetadata": true,
"experimentalWatchedFileDelay": "1s",
"experimentalWorkspaceModule": true,
"tempModfile": true,
"allowModfileModifications": true,
"allowImplicitNetworkAccess": true,
},
).Run(t, "", func(t *testing.T, env *Env) {
env.OnceMet(
InitialWorkspaceLoad,
ShownMessage("experimentalWorkspaceModule"),
ShownMessage("experimentalUseInvalidMetadata"),
ShownMessage("experimentalWatchedFileDelay"),
ShownMessage("tempModfile"),
ShownMessage("allowModfileModifications"),
ShownMessage("allowImplicitNetworkAccess"),
)
})
}