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
5package regtest
6
7import (
8	"flag"
9	"fmt"
10	"testing"
11
12	"golang.org/x/tools/internal/lsp/protocol"
13)
14
15func printBenchmarkResults(result testing.BenchmarkResult) {
16	fmt.Println("Benchmark Statistics:")
17	fmt.Println(result.String())
18	fmt.Println(result.MemString())
19}
20
21var iwlOptions struct {
22	workdir string
23}
24
25func init() {
26	flag.StringVar(&iwlOptions.workdir, "iwl_workdir", "", "if set, run IWL benchmark in this directory")
27}
28
29func TestBenchmarkIWL(t *testing.T) {
30	if iwlOptions.workdir == "" {
31		t.Skip("-iwl_workdir not configured")
32	}
33
34	opts := stressTestOptions(iwlOptions.workdir)
35	// Don't skip hooks, so that we can wait for IWL.
36	opts = append(opts, SkipHooks(false))
37
38	results := testing.Benchmark(func(b *testing.B) {
39		for i := 0; i < b.N; i++ {
40			withOptions(opts...).run(t, "", func(t *testing.T, env *Env) {})
41		}
42	})
43
44	printBenchmarkResults(results)
45}
46
47var symbolOptions struct {
48	workdir, query, matcher, style string
49	printResults                   bool
50}
51
52func init() {
53	flag.StringVar(&symbolOptions.workdir, "symbol_workdir", "", "if set, run symbol benchmark in this directory")
54	flag.StringVar(&symbolOptions.query, "symbol_query", "test", "symbol query to use in benchmark")
55	flag.StringVar(&symbolOptions.matcher, "symbol_matcher", "", "symbol matcher to use in benchmark")
56	flag.StringVar(&symbolOptions.style, "symbol_style", "", "symbol style to use in benchmark")
57	flag.BoolVar(&symbolOptions.printResults, "symbol_print_results", false, "whether to print symbol query results")
58}
59
60func TestBenchmarkSymbols(t *testing.T) {
61	if symbolOptions.workdir == "" {
62		t.Skip("-symbol_workdir not configured")
63	}
64
65	opts := stressTestOptions(symbolOptions.workdir)
66	conf := EditorConfig{}
67	if symbolOptions.matcher != "" {
68		conf.SymbolMatcher = &symbolOptions.matcher
69	}
70	if symbolOptions.style != "" {
71		conf.SymbolStyle = &symbolOptions.style
72	}
73	opts = append(opts, conf)
74
75	withOptions(opts...).run(t, "", func(t *testing.T, env *Env) {
76		// We can't Await in this test, since we have disabled hooks. Instead, run
77		// one symbol request to completion to ensure all necessary cache entries
78		// are populated.
79		symbols, err := env.Editor.Server.Symbol(env.Ctx, &protocol.WorkspaceSymbolParams{
80			Query: symbolOptions.query,
81		})
82		if err != nil {
83			t.Fatal(err)
84		}
85
86		if symbolOptions.printResults {
87			fmt.Println("Results:")
88			for i := 0; i < len(symbols); i++ {
89				fmt.Printf("\t%d. %s (%s)\n", i, symbols[i].Name, symbols[i].ContainerName)
90			}
91		}
92
93		results := testing.Benchmark(func(b *testing.B) {
94			for i := 0; i < b.N; i++ {
95				if _, err := env.Editor.Server.Symbol(env.Ctx, &protocol.WorkspaceSymbolParams{
96					Query: symbolOptions.query,
97				}); err != nil {
98					t.Fatal(err)
99				}
100			}
101		})
102		printBenchmarkResults(results)
103	})
104}
105