golang.org/x/tools/gopls@v0.15.3/internal/test/marker/doc.go (about)

     1  // Copyright 2023 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  /*
     6  Package marker defines a framework for running "marker" tests, each
     7  defined by a file in the testdata subdirectory.
     8  
     9  Use this command to run the tests:
    10  
    11  	$ go test ./gopls/internal/test/marker [-update]
    12  
    13  A marker test uses the '//@' marker syntax of the x/tools/go/expect package
    14  to annotate source code with various information such as locations and
    15  arguments of LSP operations to be executed by the test. The syntax following
    16  '@' is parsed as a comma-separated list of ordinary Go function calls, for
    17  example
    18  
    19  	//@foo(a, "b", 3),bar(0)
    20  
    21  and delegates to a corresponding function to perform LSP-related operations.
    22  See the Marker types documentation below for a list of supported markers.
    23  
    24  Each call argument is converted to the type of the corresponding parameter of
    25  the designated function. The conversion logic may use the surrounding context,
    26  such as the position or nearby text. See the Argument conversion section below
    27  for the full set of special conversions. As a special case, the blank
    28  identifier '_' is treated as the zero value of the parameter type.
    29  
    30  The test runner collects test cases by searching the given directory for
    31  files with the .txt extension. Each file is interpreted as a txtar archive,
    32  which is extracted to a temporary directory. The relative path to the .txt
    33  file is used as the subtest name. The preliminary section of the file
    34  (before the first archive entry) is a free-form comment.
    35  
    36  # Special files
    37  
    38  There are several types of file within the test archive that are given special
    39  treatment by the test runner:
    40  
    41    - "skip": the presence of this file causes the test to be skipped, with
    42      the file content used as the skip message.
    43  
    44    - "flags": this file is treated as a whitespace-separated list of flags
    45      that configure the MarkerTest instance. Supported flags:
    46      -{min,max}_go=go1.20 sets the {min,max}imum Go version for the test
    47      (inclusive)
    48      -cgo requires that CGO_ENABLED is set and the cgo tool is available
    49      -write_sumfile=a,b,c instructs the test runner to generate go.sum files
    50      in these directories before running the test.
    51      -skip_goos=a,b,c instructs the test runner to skip the test for the
    52      listed GOOS values.
    53      -ignore_extra_diags suppresses errors for unmatched diagnostics
    54      TODO(rfindley): using build constraint expressions for -skip_goos would
    55      be clearer.
    56      -filter_builtins=false disables the filtering of builtins from
    57      completion results.
    58      -filter_keywords=false disables the filtering of keywords from
    59      completion results.
    60      TODO(rfindley): support flag values containing whitespace.
    61  
    62    - "settings.json": this file is parsed as JSON, and used as the
    63      session configuration (see gopls/doc/settings.md)
    64  
    65    - "capabilities.json": this file is parsed as JSON client capabilities,
    66      and applied as an overlay over the default editor client capabilities.
    67      see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#clientCapabilities
    68      for more details.
    69  
    70    - "env": this file is parsed as a list of VAR=VALUE fields specifying the
    71      editor environment.
    72  
    73    - Golden files: Within the archive, file names starting with '@' are
    74      treated as "golden" content, and are not written to disk, but instead are
    75      made available to test methods expecting an argument of type *Golden,
    76      using the identifier following '@'. For example, if the first parameter of
    77      Foo were of type *Golden, the test runner would convert the identifier a
    78      in the call @foo(a, "b", 3) into a *Golden by collecting golden file
    79      data starting with "@a/". As a special case, for tests that only need one
    80      golden file, the data contained in the file "@a" is indexed in the *Golden
    81      value by the empty string "".
    82  
    83    - proxy files: any file starting with proxy/ is treated as a Go proxy
    84      file. If present, these files are written to a separate temporary
    85      directory and GOPROXY is set to file://<proxy directory>.
    86  
    87  # Marker types
    88  
    89  Markers are of two kinds. A few are "value markers" (e.g. @item), which are
    90  processed in a first pass and each computes a value that may be referred to
    91  by name later. Most are "action markers", which are processed in a second
    92  pass and take some action such as testing an LSP operation; they may refer
    93  to values computed by value markers.
    94  
    95  The following markers are supported within marker tests:
    96  
    97    - acceptcompletion(location, label, golden): specifies that accepting the
    98      completion candidate produced at the given location with provided label
    99      results in the given golden state.
   100  
   101    - codeaction(start, end, kind, golden, ...titles): specifies a code action
   102      to request for the given range. To support multi-line ranges, the range
   103      is defined to be between start.Start and end.End. The golden directory
   104      contains changed file content after the code action is applied.
   105      If titles are provided, they are used to filter the matching code
   106      action.
   107  
   108      TODO(rfindley): consolidate with codeactionedit, via a @loc2 marker that
   109      allows binding multi-line locations.
   110  
   111    - codeactionedit(range, kind, golden, ...titles): a shorter form of
   112      codeaction. Invokes a code action of the given kind for the given
   113      in-line range, and compares the resulting formatted unified *edits*
   114      (notably, not the full file content) with the golden directory.
   115  
   116    - codeactionerr(start, end, kind, wantError): specifies a codeaction that
   117      fails with an error that matches the expectation.
   118  
   119    - codelens(location, title): specifies that a codelens is expected at the
   120      given location, with given title. Must be used in conjunction with
   121      @codelenses.
   122  
   123    - codelenses(): specifies that textDocument/codeLens should be run for the
   124      current document, with results compared to the @codelens annotations in
   125      the current document.
   126  
   127    - complete(location, ...items): specifies expected completion results at
   128      the given location. Must be used in conjunction with @item.
   129  
   130    - diag(location, regexp): specifies an expected diagnostic matching the
   131      given regexp at the given location. The test runner requires
   132      a 1:1 correspondence between observed diagnostics and diag annotations.
   133      The diagnostics source and kind fields are ignored, to reduce fuss.
   134  
   135      The specified location must match the start position of the diagnostic,
   136      but end positions are ignored.
   137  
   138      TODO(adonovan): in the older marker framework, the annotation asserted
   139      two additional fields (source="compiler", kind="error"). Restore them?
   140  
   141    - def(src, dst location): performs a textDocument/definition request at
   142      the src location, and check the result points to the dst location.
   143  
   144    - documentLink(golden): asserts that textDocument/documentLink returns
   145      links as described by the golden file.
   146  
   147    - foldingrange(golden): performs a textDocument/foldingRange for the
   148      current document, and compare with the golden content, which is the
   149      original source annotated with numbered tags delimiting the resulting
   150      ranges (e.g. <1 kind="..."> ... </1>).
   151  
   152    - format(golden): performs a textDocument/format request for the enclosing
   153      file, and compare against the named golden file. If the formatting
   154      request succeeds, the golden file must contain the resulting formatted
   155      source. If the formatting request fails, the golden file must contain
   156      the error message.
   157  
   158    - highlight(src location, dsts ...location): makes a
   159      textDocument/highlight request at the given src location, which should
   160      highlight the provided dst locations.
   161  
   162    - hover(src, dst location, sm stringMatcher): performs a textDocument/hover
   163      at the src location, and checks that the result is the dst location, with
   164      matching hover content.
   165  
   166    - hovererr(src, sm stringMatcher): performs a textDocument/hover at the src
   167      location, and checks that the error matches the given stringMatcher.
   168  
   169    - implementations(src location, want ...location): makes a
   170      textDocument/implementation query at the src location and
   171      checks that the resulting set of locations matches want.
   172  
   173    - incomingcalls(src location, want ...location): makes a
   174      callHierarchy/incomingCalls query at the src location, and checks that
   175      the set of call.From locations matches want.
   176  
   177    - item(label, details, kind): defines a completion item with the provided
   178      fields. This information is not positional, and therefore @item markers
   179      may occur anywhere in the source. Used in conjunction with @complete,
   180      snippet, or rank.
   181  
   182      TODO(rfindley): rethink whether floating @item annotations are the best
   183      way to specify completion results.
   184  
   185    - loc(name, location): specifies the name for a location in the source. These
   186      locations may be referenced by other markers.
   187  
   188    - outgoingcalls(src location, want ...location): makes a
   189      callHierarchy/outgoingCalls query at the src location, and checks that
   190      the set of call.To locations matches want.
   191  
   192    - preparerename(src, spn, placeholder): asserts that a textDocument/prepareRename
   193      request at the src location expands to the spn location, with given
   194      placeholder. If placeholder is "", this is treated as a negative
   195      assertion and prepareRename should return nil.
   196  
   197    - rename(location, new, golden): specifies a renaming of the
   198      identifier at the specified location to the new name.
   199      The golden directory contains the transformed files.
   200  
   201    - renameerr(location, new, wantError): specifies a renaming that
   202      fails with an error that matches the expectation.
   203  
   204    - signature(location, label, active): specifies that
   205      signatureHelp at the given location should match the provided string, with
   206      the active parameter (an index) highlighted.
   207  
   208    - suggestedfix(location, regexp, golden): like diag, the location and
   209      regexp identify an expected diagnostic. This diagnostic must
   210      to have exactly one associated code action of the specified kind.
   211      This action is executed for its editing effects on the source files.
   212      Like rename, the golden directory contains the expected transformed files.
   213  
   214    - suggestedfixerr(location, regexp, kind, wantError): specifies that the
   215      suggestedfix operation should fail with an error that matches the expectation.
   216      (Failures in the computation to offer a fix do not generally result
   217      in LSP errors, so this marker is not appropriate for testing them.)
   218  
   219    - rank(location, ...completionItem): executes a textDocument/completion
   220      request at the given location, and verifies that each expected
   221      completion item occurs in the results, in the expected order. Other
   222      unexpected completion items may occur in the results.
   223      TODO(rfindley): this exists for compatibility with the old marker tests.
   224      Replace this with rankl, and rename.
   225  
   226    - rankl(location, ...label): like rank, but only cares about completion
   227      item labels.
   228  
   229    - refs(location, want ...location): executes a textDocument/references
   230      request at the first location and asserts that the result is the set of
   231      'want' locations. The first want location must be the declaration
   232      (assumedly unique).
   233  
   234    - snippet(location, completionItem, snippet): executes a
   235      textDocument/completion request at the location, and searches for a
   236      result with label matching that of the provided completion item
   237      (TODO(rfindley): accept a label rather than a completion item). Check
   238      the the result snippet matches the provided snippet.
   239  
   240    - symbol(golden): makes a textDocument/documentSymbol request
   241      for the enclosing file, formats the response with one symbol
   242      per line, sorts it, and compares against the named golden file.
   243      Each line is of the form:
   244  
   245      dotted.symbol.name kind "detail" +n lines
   246  
   247      where the "+n lines" part indicates that the declaration spans
   248      several lines. The test otherwise makes no attempt to check
   249      location information. There is no point to using more than one
   250      @symbol marker in a given file.
   251  
   252    - token(location, tokenType, mod): makes a textDocument/semanticTokens/range
   253      request at the given location, and asserts that the result includes
   254      exactly one token with the given token type and modifier string.
   255  
   256    - workspacesymbol(query, golden): makes a workspace/symbol request for the
   257      given query, formats the response with one symbol per line, and compares
   258      against the named golden file. As workspace symbols are by definition a
   259      workspace-wide request, the location of the workspace symbol marker does
   260      not matter. Each line is of the form:
   261  
   262      location name kind
   263  
   264  # Argument conversion
   265  
   266  Marker arguments are first parsed by the go/expect package, which accepts
   267  the following tokens as defined by the Go spec:
   268    - string, int64, float64, and rune literals
   269    - true and false
   270    - nil
   271    - identifiers (type expect.Identifier)
   272    - regular expressions, denoted the two tokens re"abc" (type *regexp.Regexp)
   273  
   274  These values are passed as arguments to the corresponding parameter of the
   275  test function. Additional value conversions may occur for these argument ->
   276  parameter type pairs:
   277    - string->regexp: the argument is parsed as a regular expressions.
   278    - string->location: the argument is converted to the location of the first
   279      instance of the argument in the partial line preceding the note.
   280    - regexp->location: the argument is converted to the location of the first
   281      match for the argument in the partial line preceding the note. If the
   282      regular expression contains exactly one subgroup, the position of the
   283      subgroup is used rather than the position of the submatch.
   284    - name->location: the argument is replaced by the named location.
   285    - name->Golden: the argument is used to look up golden content prefixed by
   286      @<argument>.
   287    - {string,regexp,identifier}->stringMatcher: a stringMatcher type
   288      specifies an expected string, either in the form of a substring
   289      that must be present, a regular expression that it must match, or an
   290      identifier (e.g. foo) such that the archive entry @foo exists and
   291      contains the exact expected string.
   292      stringMatchers are used by some markers to match positive results
   293      (outputs) and by other markers to match error messages.
   294  
   295  # Example
   296  
   297  Here is a complete example:
   298  
   299  	This test checks hovering over constants.
   300  
   301  	-- a.go --
   302  	package a
   303  
   304  	const abc = 0x2a //@hover("b", "abc", abc),hover(" =", "abc", abc)
   305  
   306  	-- @abc --
   307  	```go
   308  	const abc untyped int = 42
   309  	```
   310  
   311  	@hover("b", "abc", abc),hover(" =", "abc", abc)
   312  
   313  In this example, the @hover annotation tells the test runner to run the
   314  hoverMarker function, which has parameters:
   315  
   316  	(mark marker, src, dsc protocol.Location, g *Golden).
   317  
   318  The first argument holds the test context, including fake editor with open
   319  files, and sandboxed directory.
   320  
   321  Argument converters translate the "b" and "abc" arguments into locations by
   322  interpreting each one as a substring (or as a regular expression, if of the
   323  form re"a|b") and finding the location of its first occurrence on the preceding
   324  portion of the line, and the abc identifier into a the golden content contained
   325  in the file @abc. Then the hoverMarker method executes a textDocument/hover LSP
   326  request at the src position, and ensures the result spans "abc", with the
   327  markdown content from @abc. (Note that the markdown content includes the expect
   328  annotation as the doc comment.)
   329  
   330  The next hover on the same line asserts the same result, but initiates the
   331  hover immediately after "abc" in the source. This tests that we find the
   332  preceding identifier when hovering.
   333  
   334  # Updating golden files
   335  
   336  To update golden content in the test archive, it is easier to regenerate
   337  content automatically rather than edit it by hand. To do this, run the
   338  tests with the -update flag. Only tests that actually run will be updated.
   339  
   340  In some cases, golden content will vary by Go version (for example, gopls
   341  produces different markdown at Go versions before the 1.19 go/doc update).
   342  By convention, the golden content in test archives should match the output
   343  at Go tip. Each test function can normalize golden content for older Go
   344  versions.
   345  
   346  Note that -update does not cause missing @diag or @loc markers to be added.
   347  
   348  # TODO
   349  
   350    - Rename the files .txtar.
   351    - Provide some means by which locations in the standard library
   352      (or builtin.go) can be named, so that, for example, we can we
   353      can assert that MyError implements the built-in error type.
   354    - If possible, improve handling for optional arguments. Rather than have
   355      multiple variations of a marker, it would be nice to support a more
   356      flexible signature: can codeaction, codeactionedit, codeactionerr, and
   357      suggestedfix be consolidated?
   358  */
   359  package marker