Skip to content

Commit fdf79f0

Browse files
authored
Add unsorted expected completions (#1351)
1 parent de7975a commit fdf79f0

18 files changed

+1090
-2
lines changed

internal/fourslash/_scripts/convertFourslash.mts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ function parseVerifyCompletionArg(arg: ts.Expression): VerifyCompletionsCmd | un
304304
break;
305305
case "exact":
306306
case "includes":
307+
case "unsorted":
307308
if (init.getText() === "undefined") {
308309
return {
309310
kind: "verifyCompletions",
@@ -385,9 +386,12 @@ function parseVerifyCompletionArg(arg: ts.Expression): VerifyCompletionsCmd | un
385386
if (propName === "includes") {
386387
(goArgs ??= {}).includes = expected;
387388
}
388-
else {
389+
else if (propName === "exact") {
389390
(goArgs ??= {}).exact = expected;
390391
}
392+
else {
393+
(goArgs ??= {}).unsorted = expected;
394+
}
391395
break;
392396
case "excludes":
393397
let excludes = "[]string{";
@@ -659,6 +663,7 @@ interface VerifyCompletionsArgs {
659663
includes?: string;
660664
excludes?: string;
661665
exact?: string;
666+
unsorted?: string;
662667
}
663668

664669
interface GoToMarkerCmd {
@@ -680,6 +685,7 @@ function generateVerifyCompletions({ marker, args, isNewIdentifierLocation }: Ve
680685
if (args.includes) expected.push(`Includes: ${args.includes},`);
681686
if (args.excludes) expected.push(`Excludes: ${args.excludes},`);
682687
if (args.exact) expected.push(`Exact: ${args.exact},`);
688+
if (args.unsorted) expected.push(`Unsorted: ${args.unsorted},`);
683689
// !!! isIncomplete
684690
const commitCharacters = isNewIdentifierLocation ? "[]string{}" : "defaultCommitCharacters";
685691
expectedList = `&fourslash.CompletionsExpectedList{

internal/fourslash/_scripts/failingTests.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ TestCompletionListAndMemberListOnCommentedWhiteSpace
6262
TestCompletionListAtInvalidLocations
6363
TestCompletionListBuilderLocations_VariableDeclarations
6464
TestCompletionListCladule
65+
TestCompletionListClassMembers
6566
TestCompletionListForExportEquals
6667
TestCompletionListForTransitivelyExportedMembers01
6768
TestCompletionListForTransitivelyExportedMembers04
@@ -93,6 +94,10 @@ TestCompletionListInUnclosedTemplate01
9394
TestCompletionListInUnclosedTemplate02
9495
TestCompletionListInvalidMemberNames2
9596
TestCompletionListInvalidMemberNames_withExistingIdentifier
97+
TestCompletionListOnAliases2
98+
TestCompletionListPrivateNames
99+
TestCompletionListPrivateNamesAccessors
100+
TestCompletionListPrivateNamesMethods
96101
TestCompletionListStaticMembers
97102
TestCompletionListStaticProtectedMembers
98103
TestCompletionListStaticProtectedMembers2

internal/fourslash/fourslash.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package fourslash
33
import (
44
"fmt"
55
"io"
6+
"maps"
7+
"slices"
68
"strings"
79
"testing"
810
"unicode"
@@ -392,11 +394,11 @@ type CompletionsExpectedItemDefaults struct {
392394
// *lsproto.CompletionItem | string
393395
type CompletionsExpectedItem = any
394396

395-
// !!! unsorted completions
396397
type CompletionsExpectedItems struct {
397398
Includes []CompletionsExpectedItem
398399
Excludes []string
399400
Exact []CompletionsExpectedItem
401+
Unsorted []CompletionsExpectedItem
400402
}
401403

402404
// string | *Marker | []string | []*Marker
@@ -520,6 +522,9 @@ func verifyCompletionsItems(t *testing.T, prefix string, actual []*lsproto.Compl
520522
if expected.Excludes != nil {
521523
t.Fatal(prefix + "Expected exact completion list but also specified 'excludes'.")
522524
}
525+
if expected.Unsorted != nil {
526+
t.Fatal(prefix + "Expected exact completion list but also specified 'unsorted'.")
527+
}
523528
if len(actual) != len(expected.Exact) {
524529
t.Fatalf(prefix+"Expected %d exact completion items but got %d: %s", len(expected.Exact), len(actual), cmp.Diff(actual, expected.Exact))
525530
}
@@ -532,6 +537,38 @@ func verifyCompletionsItems(t *testing.T, prefix string, actual []*lsproto.Compl
532537
for _, item := range actual {
533538
nameToActualItem[item.Label] = item
534539
}
540+
if expected.Unsorted != nil {
541+
if expected.Includes != nil {
542+
t.Fatal(prefix + "Expected unsorted completion list but also specified 'includes'.")
543+
}
544+
if expected.Excludes != nil {
545+
t.Fatal(prefix + "Expected unsorted completion list but also specified 'excludes'.")
546+
}
547+
for _, item := range expected.Unsorted {
548+
switch item := item.(type) {
549+
case string:
550+
_, ok := nameToActualItem[item]
551+
if !ok {
552+
t.Fatalf("%sLabel '%s' not found in actual items. Actual items: %s", prefix, item, cmp.Diff(actual, nil))
553+
}
554+
delete(nameToActualItem, item)
555+
case *lsproto.CompletionItem:
556+
actualItem, ok := nameToActualItem[item.Label]
557+
if !ok {
558+
t.Fatalf("%sLabel '%s' not found in actual items. Actual items: %s", prefix, item.Label, cmp.Diff(actual, nil))
559+
}
560+
delete(nameToActualItem, item.Label)
561+
verifyCompletionItem(t, prefix+"Includes completion item mismatch for label "+item.Label, actualItem, item)
562+
default:
563+
t.Fatalf("%sExpected completion item to be a string or *lsproto.CompletionItem, got %T", prefix, item)
564+
}
565+
}
566+
if len(expected.Unsorted) != len(actual) {
567+
unmatched := slices.Collect(maps.Keys(nameToActualItem))
568+
t.Fatalf("%sAdditional completions found but not included in 'unsorted': %s", prefix, strings.Join(unmatched, "\n"))
569+
}
570+
return
571+
}
535572
if expected.Includes != nil {
536573
for _, item := range expected.Includes {
537574
switch item := item.(type) {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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 TestCompletionForStringLiteralRelativeImport5(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `// @rootDirs: /repo/src1,/repo/src2/,/repo/generated1,/repo/generated2/
15+
// @Filename: /dir/secret_file.ts
16+
/*secret_file*/
17+
// @Filename: /repo/src1/dir/test1.ts
18+
import * as foo1 from ".//*import_as1*/
19+
import foo2 = require(".//*import_equals1*/
20+
var foo3 = require(".//*require1*/
21+
// @Filename: /repo/src2/dir/test2.ts
22+
import * as foo1 from "..//*import_as2*/
23+
import foo2 = require("..//*import_equals2*/
24+
var foo3 = require("..//*require2*/
25+
// @Filename: /repo/src2/index.ts
26+
import * as foo1 from ".//*import_as3*/
27+
import foo2 = require(".//*import_equals3*/
28+
var foo3 = require(".//*require3*/
29+
// @Filename: /repo/generated1/dir/f1.ts
30+
/*f1*/
31+
// @Filename: /repo/generated2/dir/f2.ts
32+
/*f2*/`
33+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
34+
f.VerifyCompletions(t, []string{"import_as1", "import_equals1", "require1"}, &fourslash.CompletionsExpectedList{
35+
IsIncomplete: false,
36+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
37+
CommitCharacters: &[]string{},
38+
EditRange: ignored,
39+
},
40+
Items: &fourslash.CompletionsExpectedItems{
41+
Unsorted: []fourslash.CompletionsExpectedItem{"f1", "f2", "test2"},
42+
},
43+
})
44+
f.VerifyCompletions(t, []string{"import_as2", "import_equals2", "require2"}, &fourslash.CompletionsExpectedList{
45+
IsIncomplete: false,
46+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
47+
CommitCharacters: &[]string{},
48+
EditRange: ignored,
49+
},
50+
Items: &fourslash.CompletionsExpectedItems{
51+
Unsorted: []fourslash.CompletionsExpectedItem{"dir", "index"},
52+
},
53+
})
54+
f.VerifyCompletions(t, []string{"import_as3", "import_equals3", "require3"}, &fourslash.CompletionsExpectedList{
55+
IsIncomplete: false,
56+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
57+
CommitCharacters: &[]string{},
58+
EditRange: ignored,
59+
},
60+
Items: &fourslash.CompletionsExpectedItems{
61+
Unsorted: []fourslash.CompletionsExpectedItem{"dir"},
62+
},
63+
})
64+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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/ls"
8+
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
9+
"github.com/microsoft/typescript-go/internal/testutil"
10+
)
11+
12+
func TestCompletionListClassMembers(t *testing.T) {
13+
t.Parallel()
14+
t.Skip()
15+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
16+
const content = `class Class {
17+
private privateInstanceMethod() { }
18+
public publicInstanceMethod() { }
19+
20+
private privateProperty = 1;
21+
public publicProperty = 1;
22+
23+
private static privateStaticProperty = 1;
24+
public static publicStaticProperty = 1;
25+
26+
private static privateStaticMethod() { }
27+
public static publicStaticMethod() {
28+
Class./*staticsInsideClassScope*/publicStaticMethod();
29+
var c = new Class();
30+
c./*instanceMembersInsideClassScope*/privateProperty;
31+
}
32+
}
33+
34+
Class./*staticsOutsideClassScope*/publicStaticMethod();
35+
var c = new Class();
36+
c./*instanceMembersOutsideClassScope*/privateProperty;`
37+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
38+
f.VerifyCompletions(t, "staticsInsideClassScope", &fourslash.CompletionsExpectedList{
39+
IsIncomplete: false,
40+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
41+
CommitCharacters: &defaultCommitCharacters,
42+
EditRange: ignored,
43+
},
44+
Items: &fourslash.CompletionsExpectedItems{
45+
Exact: completionFunctionMembersPlus([]fourslash.CompletionsExpectedItem{&lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocalDeclarationPriority)), Label: "privateStaticMethod"}, &lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocalDeclarationPriority)), Label: "privateStaticProperty"}, &lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocalDeclarationPriority)), Label: "publicStaticMethod"}, &lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocalDeclarationPriority)), Label: "publicStaticProperty"}, &lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocationPriority)), Label: "prototype"}}),
46+
},
47+
})
48+
f.VerifyCompletions(t, "instanceMembersInsideClassScope", &fourslash.CompletionsExpectedList{
49+
IsIncomplete: false,
50+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
51+
CommitCharacters: &defaultCommitCharacters,
52+
EditRange: ignored,
53+
},
54+
Items: &fourslash.CompletionsExpectedItems{
55+
Unsorted: []fourslash.CompletionsExpectedItem{"privateInstanceMethod", "publicInstanceMethod", "privateProperty", "publicProperty"},
56+
},
57+
})
58+
f.VerifyCompletions(t, "staticsOutsideClassScope", &fourslash.CompletionsExpectedList{
59+
IsIncomplete: false,
60+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
61+
CommitCharacters: &defaultCommitCharacters,
62+
EditRange: ignored,
63+
},
64+
Items: &fourslash.CompletionsExpectedItems{
65+
Exact: completionFunctionMembersPlus([]fourslash.CompletionsExpectedItem{&lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocalDeclarationPriority)), Label: "publicStaticMethod"}, &lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocalDeclarationPriority)), Label: "publicStaticProperty"}, &lsproto.CompletionItem{SortText: ptrTo(string(ls.SortTextLocationPriority)), Label: "prototype"}}),
66+
},
67+
})
68+
f.VerifyCompletions(t, "instanceMembersOutsideClassScope", &fourslash.CompletionsExpectedList{
69+
IsIncomplete: false,
70+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
71+
CommitCharacters: &defaultCommitCharacters,
72+
EditRange: ignored,
73+
},
74+
Items: &fourslash.CompletionsExpectedItems{
75+
Exact: []fourslash.CompletionsExpectedItem{"publicInstanceMethod", "publicProperty"},
76+
},
77+
})
78+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 TestCompletionListEnumMembers(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `enum Foo {
15+
bar,
16+
baz
17+
}
18+
19+
var v = Foo./*valueReference*/ba;
20+
var t :Foo./*typeReference*/ba;
21+
Foo.bar./*enumValueReference*/;`
22+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
23+
f.VerifyCompletions(t, []string{"valueReference", "typeReference"}, &fourslash.CompletionsExpectedList{
24+
IsIncomplete: false,
25+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
26+
CommitCharacters: &defaultCommitCharacters,
27+
EditRange: ignored,
28+
},
29+
Items: &fourslash.CompletionsExpectedItems{
30+
Exact: []fourslash.CompletionsExpectedItem{"bar", "baz"},
31+
},
32+
})
33+
f.VerifyCompletions(t, "enumValueReference", &fourslash.CompletionsExpectedList{
34+
IsIncomplete: false,
35+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
36+
CommitCharacters: &defaultCommitCharacters,
37+
EditRange: ignored,
38+
},
39+
Items: &fourslash.CompletionsExpectedItems{
40+
Unsorted: []fourslash.CompletionsExpectedItem{"toString", "toFixed", "toExponential", "toPrecision", "valueOf", "toLocaleString"},
41+
},
42+
})
43+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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 TestCompletionListInObjectBindingPattern15(t *testing.T) {
11+
t.Parallel()
12+
13+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
14+
const content = `class Foo {
15+
private xxx1 = 1;
16+
protected xxx2 = 2;
17+
public xxx3 = 3;
18+
private static xxx4 = 4;
19+
protected static xxx5 = 5;
20+
public static xxx6 = 6;
21+
foo() {
22+
const { /*1*/ } = this;
23+
const { /*2*/ } = Foo;
24+
}
25+
}
26+
27+
const { /*3*/ } = new Foo();
28+
const { /*4*/ } = Foo;`
29+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
30+
f.VerifyCompletions(t, "1", &fourslash.CompletionsExpectedList{
31+
IsIncomplete: false,
32+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
33+
CommitCharacters: &defaultCommitCharacters,
34+
EditRange: ignored,
35+
},
36+
Items: &fourslash.CompletionsExpectedItems{
37+
Unsorted: []fourslash.CompletionsExpectedItem{"xxx1", "xxx2", "xxx3", "foo"},
38+
},
39+
})
40+
f.VerifyCompletions(t, "2", &fourslash.CompletionsExpectedList{
41+
IsIncomplete: false,
42+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
43+
CommitCharacters: &defaultCommitCharacters,
44+
EditRange: ignored,
45+
},
46+
Items: &fourslash.CompletionsExpectedItems{
47+
Unsorted: []fourslash.CompletionsExpectedItem{"prototype", "xxx4", "xxx5", "xxx6"},
48+
},
49+
})
50+
f.VerifyCompletions(t, "3", &fourslash.CompletionsExpectedList{
51+
IsIncomplete: false,
52+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
53+
CommitCharacters: &defaultCommitCharacters,
54+
EditRange: ignored,
55+
},
56+
Items: &fourslash.CompletionsExpectedItems{
57+
Unsorted: []fourslash.CompletionsExpectedItem{"xxx3", "foo"},
58+
},
59+
})
60+
f.VerifyCompletions(t, "4", &fourslash.CompletionsExpectedList{
61+
IsIncomplete: false,
62+
ItemDefaults: &fourslash.CompletionsExpectedItemDefaults{
63+
CommitCharacters: &defaultCommitCharacters,
64+
EditRange: ignored,
65+
},
66+
Items: &fourslash.CompletionsExpectedItems{
67+
Unsorted: []fourslash.CompletionsExpectedItem{"prototype", "xxx6"},
68+
},
69+
})
70+
}

0 commit comments

Comments
 (0)