.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.6.9 / test / debug / debug_test.go
1 // Copyright 2020 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 debug_test
6
7 // Provide 'static type checking' of the templates. This guards against changes is various
8 // gopls datastructures causing template execution to fail. The checking is done by
9 // the github.com/jba/templatecheck pacakge. Before that is run, the test checks that
10 // its list of templates and their arguments corresponds to the arguments in
11 // calls to render(). The test assumes that all uses of templates are done through render().
12
13 import (
14         "go/ast"
15         "html/template"
16         "log"
17         "runtime"
18         "sort"
19         "strings"
20         "testing"
21
22         "github.com/jba/templatecheck"
23         "golang.org/x/tools/go/packages"
24         "golang.org/x/tools/internal/lsp/cache"
25         "golang.org/x/tools/internal/lsp/debug"
26         "golang.org/x/tools/internal/lsp/source"
27         "golang.org/x/tools/internal/span"
28 )
29
30 type tdata struct {
31         tmpl *template.Template
32         data interface{} // a value of the needed type
33 }
34
35 var templates = map[string]tdata{
36         "MainTmpl":    {debug.MainTmpl, &debug.Instance{}},
37         "DebugTmpl":   {debug.DebugTmpl, nil},
38         "RPCTmpl":     {debug.RPCTmpl, &debug.Rpcs{}},
39         "TraceTmpl":   {debug.TraceTmpl, debug.TraceResults{}},
40         "CacheTmpl":   {debug.CacheTmpl, &cache.Cache{}},
41         "SessionTmpl": {debug.SessionTmpl, &cache.Session{}},
42         "ViewTmpl":    {debug.ViewTmpl, &cache.View{}},
43         "ClientTmpl":  {debug.ClientTmpl, &debug.Client{}},
44         "ServerTmpl":  {debug.ServerTmpl, &debug.Server{}},
45         //"FileTmpl":    {FileTmpl, source.Overlay{}}, // need to construct a source.Overlay in init
46         "InfoTmpl":   {debug.InfoTmpl, "something"},
47         "MemoryTmpl": {debug.MemoryTmpl, runtime.MemStats{}},
48 }
49
50 // construct a source.Overlay for fileTmpl
51 type fakeOverlay struct{}
52
53 func (fakeOverlay) Version() int32 {
54         return 0
55 }
56 func (fakeOverlay) Session() string {
57         return ""
58 }
59 func (fakeOverlay) VersionedFileIdentity() source.VersionedFileIdentity {
60         return source.VersionedFileIdentity{}
61 }
62 func (fakeOverlay) FileIdentity() source.FileIdentity {
63         return source.FileIdentity{}
64 }
65 func (fakeOverlay) Kind() source.FileKind {
66         return 0
67 }
68 func (fakeOverlay) Read() ([]byte, error) {
69         return nil, nil
70 }
71 func (fakeOverlay) Saved() bool {
72         return true
73 }
74 func (fakeOverlay) URI() span.URI {
75         return ""
76 }
77
78 var _ source.Overlay = fakeOverlay{}
79
80 func init() {
81         log.SetFlags(log.Lshortfile)
82         var v fakeOverlay
83         templates["FileTmpl"] = tdata{debug.FileTmpl, v}
84 }
85
86 func TestTemplates(t *testing.T) {
87         if runtime.GOOS == "android" {
88                 t.Skip("this test is not supported for Android")
89         }
90         cfg := &packages.Config{
91                 Mode: packages.NeedTypesInfo | packages.LoadAllSyntax, // figure out what's necessary PJW
92         }
93         pkgs, err := packages.Load(cfg, "golang.org/x/tools/internal/lsp/debug")
94         if err != nil {
95                 t.Fatal(err)
96         }
97         if len(pkgs) != 1 {
98                 t.Fatalf("expected a single package, but got %d", len(pkgs))
99         }
100         p := pkgs[0]
101         if len(p.Errors) != 0 {
102                 t.Fatalf("compiler error, e.g. %v", p.Errors[0])
103         }
104         // find the calls to render in serve.go
105         tree := treeOf(p, "serve.go")
106         if tree == nil {
107                 t.Fatalf("found no syntax tree for %s", "serve.go")
108         }
109         renders := callsOf(p, tree, "render")
110         if len(renders) == 0 {
111                 t.Fatalf("found no calls to render")
112         }
113         var found = make(map[string]bool)
114         for _, r := range renders {
115                 if len(r.Args) != 2 {
116                         // template, func
117                         t.Fatalf("got %d args, expected 2", len(r.Args))
118                 }
119                 t0, ok := p.TypesInfo.Types[r.Args[0]]
120                 if !ok || !t0.IsValue() || t0.Type.String() != "*html/template.Template" {
121                         t.Fatalf("no type info for template")
122                 }
123                 if id, ok := r.Args[0].(*ast.Ident); !ok {
124                         t.Errorf("expected *ast.Ident, got %T", r.Args[0])
125                 } else {
126                         found[id.Name] = true
127                 }
128         }
129         // make sure found and templates have the same templates
130         for k := range found {
131                 if _, ok := templates[k]; !ok {
132                         t.Errorf("code has template %s, but test does not", k)
133                 }
134         }
135         for k := range templates {
136                 if _, ok := found[k]; !ok {
137                         t.Errorf("test has template %s, code does not", k)
138                 }
139         }
140         // now check all the known templates, in alphabetic order, for determinacy
141         keys := []string{}
142         for k := range templates {
143                 keys = append(keys, k)
144         }
145         sort.Strings(keys)
146         for _, k := range keys {
147                 v := templates[k]
148                 // the FuncMap is an annoyance; should not be necessary
149                 if err := templatecheck.CheckHTML(v.tmpl, v.data); err != nil {
150                         t.Errorf("%s: %v", k, err)
151                 }
152         }
153 }
154
155 func callsOf(p *packages.Package, tree *ast.File, name string) []*ast.CallExpr {
156         var ans []*ast.CallExpr
157         f := func(n ast.Node) bool {
158                 x, ok := n.(*ast.CallExpr)
159                 if !ok {
160                         return true
161                 }
162                 if y, ok := x.Fun.(*ast.Ident); ok {
163                         if y.Name == name {
164                                 ans = append(ans, x)
165                         }
166                 }
167                 return true
168         }
169         ast.Inspect(tree, f)
170         return ans
171 }
172 func treeOf(p *packages.Package, fname string) *ast.File {
173         for _, tree := range p.Syntax {
174                 loc := tree.Package
175                 pos := p.Fset.PositionFor(loc, false)
176                 if strings.HasSuffix(pos.Filename, fname) {
177                         return tree
178                 }
179         }
180         return nil
181 }