github.com/v2fly/tools@v0.100.0/internal/lsp/cmd/test/cmdtest.go (about)

     1  // Copyright 2019 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 cmdtest contains the test suite for the command line behavior of gopls.
     6  package cmdtest
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"fmt"
    12  	"io"
    13  	"os"
    14  	"sync"
    15  	"testing"
    16  
    17  	"github.com/v2fly/tools/internal/jsonrpc2/servertest"
    18  	"github.com/v2fly/tools/internal/lsp/cache"
    19  	"github.com/v2fly/tools/internal/lsp/cmd"
    20  	"github.com/v2fly/tools/internal/lsp/debug"
    21  	"github.com/v2fly/tools/internal/lsp/lsprpc"
    22  	"github.com/v2fly/tools/internal/lsp/protocol"
    23  	"github.com/v2fly/tools/internal/lsp/source"
    24  	"github.com/v2fly/tools/internal/lsp/tests"
    25  	"github.com/v2fly/tools/internal/span"
    26  	"github.com/v2fly/tools/internal/tool"
    27  )
    28  
    29  type runner struct {
    30  	data        *tests.Data
    31  	ctx         context.Context
    32  	options     func(*source.Options)
    33  	normalizers []tests.Normalizer
    34  	remote      string
    35  }
    36  
    37  func TestCommandLine(t *testing.T, testdata string, options func(*source.Options)) {
    38  	// On Android, the testdata directory is not copied to the runner.
    39  	if stat, err := os.Stat(testdata); err != nil || !stat.IsDir() {
    40  		t.Skip("testdata directory not present")
    41  	}
    42  	tests.RunTests(t, testdata, false, func(t *testing.T, datum *tests.Data) {
    43  		ctx := tests.Context(t)
    44  		ts := NewTestServer(ctx, options)
    45  		tests.Run(t, NewRunner(datum, ctx, ts.Addr, options), datum)
    46  		cmd.CloseTestConnections(ctx)
    47  	})
    48  }
    49  
    50  func NewTestServer(ctx context.Context, options func(*source.Options)) *servertest.TCPServer {
    51  	ctx = debug.WithInstance(ctx, "", "")
    52  	cache := cache.New(options)
    53  	ss := lsprpc.NewStreamServer(cache, false)
    54  	return servertest.NewTCPServer(ctx, ss, nil)
    55  }
    56  
    57  func NewRunner(data *tests.Data, ctx context.Context, remote string, options func(*source.Options)) *runner {
    58  	return &runner{
    59  		data:        data,
    60  		ctx:         ctx,
    61  		options:     options,
    62  		normalizers: tests.CollectNormalizers(data.Exported),
    63  		remote:      remote,
    64  	}
    65  }
    66  
    67  func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) {
    68  	//TODO: add command line completions tests when it works
    69  }
    70  
    71  func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
    72  	//TODO: add command line completions tests when it works
    73  }
    74  
    75  func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) {
    76  	//TODO: add command line completions tests when it works
    77  }
    78  
    79  func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
    80  	//TODO: add command line completions tests when it works
    81  }
    82  
    83  func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
    84  	//TODO: add command line completions tests when it works
    85  }
    86  
    87  func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
    88  	//TODO: add command line completions tests when it works
    89  }
    90  
    91  func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
    92  	//TODO: add command line completions tests when it works
    93  }
    94  
    95  func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
    96  	//TODO: add command line completions tests when it works
    97  }
    98  
    99  func (r *runner) FunctionExtraction(t *testing.T, start span.Span, end span.Span) {
   100  	//TODO: function extraction not supported on command line
   101  }
   102  
   103  func (r *runner) runGoplsCmd(t testing.TB, args ...string) (string, string) {
   104  	rStdout, wStdout, err := os.Pipe()
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  	oldStdout := os.Stdout
   109  	rStderr, wStderr, err := os.Pipe()
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  	oldStderr := os.Stderr
   114  	stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
   115  	var wg sync.WaitGroup
   116  	wg.Add(2)
   117  	go func() {
   118  		io.Copy(stdout, rStdout)
   119  		wg.Done()
   120  	}()
   121  	go func() {
   122  		io.Copy(stderr, rStderr)
   123  		wg.Done()
   124  	}()
   125  	os.Stdout, os.Stderr = wStdout, wStderr
   126  	app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env, r.options)
   127  	remote := r.remote
   128  	err = tool.Run(tests.Context(t),
   129  		app,
   130  		append([]string{fmt.Sprintf("-remote=internal@%s", remote)}, args...))
   131  	if err != nil {
   132  		fmt.Fprint(os.Stderr, err)
   133  	}
   134  	wStdout.Close()
   135  	wStderr.Close()
   136  	wg.Wait()
   137  	os.Stdout, os.Stderr = oldStdout, oldStderr
   138  	rStdout.Close()
   139  	rStderr.Close()
   140  	return stdout.String(), stderr.String()
   141  }
   142  
   143  // NormalizeGoplsCmd runs the gopls command and normalizes its output.
   144  func (r *runner) NormalizeGoplsCmd(t testing.TB, args ...string) (string, string) {
   145  	stdout, stderr := r.runGoplsCmd(t, args...)
   146  	return r.Normalize(stdout), r.Normalize(stderr)
   147  }
   148  
   149  func (r *runner) Normalize(s string) string {
   150  	return tests.Normalize(s, r.normalizers)
   151  }
   152  
   153  func (r *runner) NormalizePrefix(s string) string {
   154  	return tests.NormalizePrefix(s, r.normalizers)
   155  }