Skip to content

Commit c018483

Browse files
Add baseline tests from signature help (#1485)
1 parent f188316 commit c018483

File tree

58 files changed

+8152
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+8152
-1
lines changed

internal/fourslash/_scripts/convertFourslash.mts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ function parseFourslashStatement(statement: ts.Statement): Cmd[] | undefined {
173173
return [parseBaselineFindAllReferencesArgs(callExpression.arguments)];
174174
case "baselineQuickInfo":
175175
return [parseBaselineQuickInfo(callExpression.arguments)];
176+
case "baselineSignatureHelp":
177+
return [parseBaselineSignatureHelp(callExpression.arguments)];
176178
case "baselineGoToDefinition":
177179
case "baselineGetDefinitionAtPosition":
178180
// Both of these take the same arguments, but differ in that...
@@ -856,6 +858,16 @@ function parseQuickInfoArgs(funcName: string, args: readonly ts.Expression[]): V
856858
return undefined;
857859
}
858860

861+
function parseBaselineSignatureHelp(args: ts.NodeArray<ts.Expression>): Cmd {
862+
if (args.length !== 0) {
863+
// All calls are currently empty!
864+
throw new Error("Expected no arguments in verify.baselineSignatureHelp");
865+
}
866+
return {
867+
kind: "verifyBaselineSignatureHelp",
868+
};
869+
}
870+
859871
function parseKind(expr: ts.Expression): string | undefined {
860872
if (!ts.isStringLiteral(expr)) {
861873
console.error(`Expected string literal for kind, got ${expr.getText()}`);
@@ -1007,6 +1019,10 @@ interface VerifyBaselineQuickInfoCmd {
10071019
kind: "verifyBaselineQuickInfo";
10081020
}
10091021

1022+
interface VerifyBaselineSignatureHelpCmd {
1023+
kind: "verifyBaselineSignatureHelp";
1024+
}
1025+
10101026
interface GoToCmd {
10111027
kind: "goTo";
10121028
// !!! `selectRange` and `rangeStart` require parsing variables and `test.ranges()[n]`
@@ -1031,6 +1047,7 @@ type Cmd =
10311047
| VerifyBaselineFindAllReferencesCmd
10321048
| VerifyBaselineGoToDefinitionCmd
10331049
| VerifyBaselineQuickInfoCmd
1050+
| VerifyBaselineSignatureHelpCmd
10341051
| GoToCmd
10351052
| EditCmd
10361053
| VerifyQuickInfoCmd;
@@ -1105,6 +1122,8 @@ function generateCmd(cmd: Cmd): string {
11051122
case "verifyBaselineQuickInfo":
11061123
// Quick Info -> Hover
11071124
return `f.VerifyBaselineHover(t)`;
1125+
case "verifyBaselineSignatureHelp":
1126+
return `f.VerifyBaselineSignatureHelp(t)`;
11081127
case "goTo":
11091128
return generateGoToCommand(cmd);
11101129
case "edit":
@@ -1127,7 +1146,7 @@ interface GoTest {
11271146
}
11281147

11291148
function generateGoTest(failingTests: Set<string>, test: GoTest): string {
1130-
const testName = test.name[0].toUpperCase() + test.name.substring(1);
1149+
const testName = (test.name[0].toUpperCase() + test.name.substring(1)).replaceAll("-", "_");
11311150
const content = test.content;
11321151
const commands = test.commands.map(cmd => generateCmd(cmd)).join("\n");
11331152
const imports = [`"github.com/microsoft/typescript-go/internal/fourslash"`];

internal/fourslash/_scripts/failingTests.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ TestReferencesIsAvailableThroughGlobalNoCrash
463463
TestRegexDetection
464464
TestReverseMappedTypeQuickInfo
465465
TestSelfReferencedExternalModule
466+
TestSignatureHelpInferenceJsDocImportTag
466467
TestStringCompletionsImportOrExportSpecifier
467468
TestStringCompletionsVsEscaping
468469
TestSyntheticImportFromBabelGeneratedFile1

internal/fourslash/fourslash.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,136 @@ func appendLinesForMarkedStringWithLanguage(result []string, ms *lsproto.MarkedS
996996
return result
997997
}
998998

999+
func (f *FourslashTest) VerifyBaselineSignatureHelp(t *testing.T) {
1000+
if f.baseline != nil {
1001+
t.Fatalf("Error during test '%s': Another baseline is already in progress", t.Name())
1002+
} else {
1003+
f.baseline = &baselineFromTest{
1004+
content: &strings.Builder{},
1005+
baselineName: "signatureHelp/" + strings.TrimPrefix(t.Name(), "Test"),
1006+
ext: ".baseline",
1007+
}
1008+
}
1009+
1010+
// empty baseline after test completes
1011+
defer func() {
1012+
f.baseline = nil
1013+
}()
1014+
1015+
markersAndItems := core.MapFiltered(f.Markers(), func(marker *Marker) (markerAndItem[*lsproto.SignatureHelp], bool) {
1016+
if marker.Name == nil {
1017+
return markerAndItem[*lsproto.SignatureHelp]{}, false
1018+
}
1019+
1020+
params := &lsproto.SignatureHelpParams{
1021+
TextDocument: lsproto.TextDocumentIdentifier{
1022+
Uri: ls.FileNameToDocumentURI(f.activeFilename),
1023+
},
1024+
Position: marker.LSPosition,
1025+
}
1026+
1027+
resMsg, result, resultOk := sendRequest(t, f, lsproto.TextDocumentSignatureHelpInfo, params)
1028+
var prefix string
1029+
if f.lastKnownMarkerName != nil {
1030+
prefix = fmt.Sprintf("At marker '%s': ", *f.lastKnownMarkerName)
1031+
} else {
1032+
prefix = fmt.Sprintf("At position (Ln %d, Col %d): ", f.currentCaretPosition.Line, f.currentCaretPosition.Character)
1033+
}
1034+
if resMsg == nil {
1035+
t.Fatalf(prefix+"Nil response received for signature help request", f.lastKnownMarkerName)
1036+
}
1037+
if !resultOk {
1038+
t.Fatalf(prefix+"Unexpected response type for signature help request: %T", resMsg.AsResponse().Result)
1039+
}
1040+
1041+
return markerAndItem[*lsproto.SignatureHelp]{Marker: marker, Item: result.SignatureHelp}, true
1042+
})
1043+
1044+
getRange := func(item *lsproto.SignatureHelp) *lsproto.Range {
1045+
// SignatureHelp doesn't have a range like hover does
1046+
return nil
1047+
}
1048+
1049+
getTooltipLines := func(item, _prev *lsproto.SignatureHelp) []string {
1050+
if item == nil || len(item.Signatures) == 0 {
1051+
return []string{"No signature help available"}
1052+
}
1053+
1054+
// Show active signature if specified, otherwise first signature
1055+
activeSignature := 0
1056+
if item.ActiveSignature != nil && int(*item.ActiveSignature) < len(item.Signatures) {
1057+
activeSignature = int(*item.ActiveSignature)
1058+
}
1059+
1060+
sig := item.Signatures[activeSignature]
1061+
1062+
// Build signature display
1063+
signatureLine := sig.Label
1064+
activeParamLine := ""
1065+
1066+
// Show active parameter if specified, and the signature text.
1067+
if item.ActiveParameter != nil && sig.Parameters != nil {
1068+
activeParamIndex := int(*item.ActiveParameter.Uinteger)
1069+
if activeParamIndex >= 0 && activeParamIndex < len(*sig.Parameters) {
1070+
activeParam := (*sig.Parameters)[activeParamIndex]
1071+
1072+
// Get the parameter label and bold the
1073+
// parameter text within the original string.
1074+
activeParamLabel := ""
1075+
if activeParam.Label.String != nil {
1076+
activeParamLabel = *activeParam.Label.String
1077+
} else if activeParam.Label.Tuple != nil {
1078+
activeParamLabel = signatureLine[(*activeParam.Label.Tuple)[0]:(*activeParam.Label.Tuple)[1]]
1079+
} else {
1080+
t.Fatal("Unsupported param label kind.")
1081+
}
1082+
signatureLine = strings.Replace(signatureLine, activeParamLabel, "**"+activeParamLabel+"**", 1)
1083+
1084+
if activeParam.Documentation != nil {
1085+
if activeParam.Documentation.MarkupContent != nil {
1086+
activeParamLine = activeParam.Documentation.MarkupContent.Value
1087+
} else if activeParam.Documentation.String != nil {
1088+
activeParamLine = *activeParam.Documentation.String
1089+
}
1090+
1091+
activeParamLine = fmt.Sprintf("- `%s`: %s", activeParamLabel, activeParamLine)
1092+
}
1093+
1094+
}
1095+
}
1096+
1097+
result := make([]string, 0, 16)
1098+
result = append(result, signatureLine)
1099+
if activeParamLine != "" {
1100+
result = append(result, activeParamLine)
1101+
}
1102+
1103+
// ORIGINALLY we would "only display signature documentation on the last argument when multiple arguments are marked".
1104+
// !!!
1105+
// Note that this is harder than in Strada, because LSP signature help has no concept of
1106+
// applicable spans.
1107+
if sig.Documentation != nil {
1108+
if sig.Documentation.MarkupContent != nil {
1109+
result = append(result, strings.Split(sig.Documentation.MarkupContent.Value, "\n")...)
1110+
} else if sig.Documentation.String != nil {
1111+
result = append(result, strings.Split(*sig.Documentation.String, "\n")...)
1112+
} else {
1113+
t.Fatal("Unsupported documentation format.")
1114+
}
1115+
}
1116+
1117+
return result
1118+
}
1119+
1120+
f.baseline.addResult("SignatureHelp", annotateContentWithTooltips(t, f, markersAndItems, "signaturehelp", getRange, getTooltipLines))
1121+
if jsonStr, err := core.StringifyJson(markersAndItems, "", " "); err == nil {
1122+
f.baseline.content.WriteString(jsonStr)
1123+
} else {
1124+
t.Fatalf("Failed to stringify markers and items for baseline: %v", err)
1125+
}
1126+
baseline.Run(t, f.baseline.getBaselineFileName(), f.baseline.content.String(), baseline.Options{})
1127+
}
1128+
9991129
// Collects all named markers if provided, or defaults to anonymous ranges
10001130
func (f *FourslashTest) lookupMarkersOrGetRanges(t *testing.T, markers []string) []MarkerOrRange {
10011131
var referenceLocations []MarkerOrRange
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/testutil"
8+
)
9+
10+
func TestJsDocDontBreakWithNamespaces(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `// @allowJs: true
15+
// @Filename: jsDocDontBreakWithNamespaces.js
16+
/**
17+
* @returns {module:@nodefuel/web~Webserver~wsServer#hello} Websocket server object
18+
*/
19+
function foo() { }
20+
foo(''/*foo*/);
21+
22+
/**
23+
* @type {module:xxxxx} */
24+
*/
25+
function bar() { }
26+
bar(''/*bar*/);
27+
28+
/** @type {function(module:xxxx, module:xxxx): module:xxxxx} */
29+
function zee() { }
30+
zee(''/*zee*/);`
31+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
32+
f.VerifyBaselineSignatureHelp(t)
33+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/testutil"
8+
)
9+
10+
func TestJsDocFunctionSignatures5(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `// @allowJs: true
15+
// @Filename: Foo.js
16+
/**
17+
* Filters a path based on a regexp or glob pattern.
18+
* @param {String} basePath The base path where the search will be performed.
19+
* @param {String} pattern A string defining a regexp of a glob pattern.
20+
* @param {String} type The search pattern type, can be a regexp or a glob.
21+
* @param {Object} options A object containing options to the search.
22+
* @return {Array} A list containing the filtered paths.
23+
*/
24+
function pathFilter(basePath, pattern, type, options){
25+
//...
26+
}
27+
pathFilter(/**/'foo', 'bar', 'baz', {});`
28+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
29+
f.VerifyBaselineSignatureHelp(t)
30+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/testutil"
8+
)
9+
10+
func TestJsDocFunctionSignatures6(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `// @allowJs: true
15+
// @Filename: Foo.js
16+
/**
17+
* @param {string} p1 - A string param
18+
* @param {string?} p2 - An optional param
19+
* @param {string} [p3] - Another optional param
20+
* @param {string} [p4="test"] - An optional param with a default value
21+
*/
22+
function f1(p1, p2, p3, p4){}
23+
f1(/*1*/'foo', /*2*/'bar', /*3*/'baz', /*4*/'qux');`
24+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
25+
f.VerifyBaselineSignatureHelp(t)
26+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/testutil"
8+
)
9+
10+
func TestJsDocSignature_43394(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `/**
15+
* @typedef {Object} Foo
16+
* @property {number} ...
17+
* /**/@typedef {number} Bar
18+
*/`
19+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
20+
f.VerifyBaselineSignatureHelp(t)
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/testutil"
8+
)
9+
10+
func TestJsdocReturnsTag(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `// @allowJs: true
15+
// @Filename: dummy.js
16+
/**
17+
* Find an item
18+
* @template T
19+
* @param {T[]} l
20+
* @param {T} x
21+
* @returns {?T} The names of the found item(s).
22+
*/
23+
function find(l, x) {
24+
}
25+
find(''/**/);`
26+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
27+
f.VerifyBaselineSignatureHelp(t)
28+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/microsoft/typescript-go/internal/fourslash"
7+
"github.com/microsoft/typescript-go/internal/testutil"
8+
)
9+
10+
func TestQuickInfoJsDocTags13(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `// @allowJs: true
15+
// @checkJs: true
16+
// @filename: ./a.js
17+
/**
18+
* First overload
19+
* @overload
20+
* @param {number} a
21+
* @returns {void}
22+
*/
23+
24+
/**
25+
* Second overload
26+
* @overload
27+
* @param {string} a
28+
* @returns {void}
29+
*/
30+
31+
/**
32+
* @param {string | number} a
33+
* @returns {void}
34+
*/
35+
function f(a) {}
36+
37+
f(/*a*/1);
38+
f(/*b*/"");`
39+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
40+
f.VerifyBaselineSignatureHelp(t)
41+
}

0 commit comments

Comments
 (0)