@@ -5,7 +5,7 @@ import * as Path from 'path';
55import * as vscode from 'vscode' ;
66
77suite ( 'Extension Smoke' , ( ) => {
8- test ( 'activates and publishes diagnostics for Java files' , async ( ) => {
8+ test ( 'activates, resolves definitions, and publishes diagnostics for Java files' , async ( ) => {
99 const extension = vscode . extensions . getExtension ( 'georgewfraser.vscode-javac' ) ;
1010 assert . ok ( extension , 'Extension georgewfraser.vscode-javac was not found' ) ;
1111
@@ -28,9 +28,67 @@ suite('Extension Smoke', () => {
2828 diagnostics . some ( d => d . severity === vscode . DiagnosticSeverity . Error ) ,
2929 `Expected an error diagnostic for HelloError.java, got: ${ messages || '<none>' } `
3030 ) ;
31+
32+ const definitionUri = vscode . Uri . file ( Path . join ( folders [ 0 ] . uri . fsPath , 'GotoDefinition.java' ) ) ;
33+ const definitionDocument = await vscode . workspace . openTextDocument ( definitionUri ) ;
34+ const definitionEditor = await vscode . window . showTextDocument ( definitionDocument ) ;
35+
36+ const definitionLine = definitionDocument . lineAt ( 2 ) . text ;
37+ const definitionOffset = definitionLine . indexOf ( 'goToHere' ) ;
38+ assert . ok ( definitionOffset >= 0 , 'Expected goToHere call in GotoDefinition.java' ) ;
39+
40+ const definitionPosition = new vscode . Position ( 2 , definitionOffset + 2 ) ;
41+ definitionEditor . selection = new vscode . Selection ( definitionPosition , definitionPosition ) ;
42+ definitionEditor . revealRange ( new vscode . Range ( definitionPosition , definitionPosition ) ) ;
43+
44+ const definitions = await waitForDefinitions ( definitionUri , definitionPosition , 30000 ) ;
45+ const target = definitionTarget ( definitions [ 0 ] ) ;
46+ const targetDocument = target . uri . toString ( ) === definitionDocument . uri . toString ( )
47+ ? definitionDocument
48+ : await vscode . workspace . openTextDocument ( target . uri ) ;
49+ const targetLine = targetDocument . lineAt ( target . range . start . line ) . text ;
50+ assert . ok (
51+ targetLine . includes ( 'void goToHere()' ) ,
52+ `Expected definition for goToHere, got line: ${ targetLine || '<none>' } `
53+ ) ;
3154 } ) ;
3255} ) ;
3356
57+ async function waitForDefinitions (
58+ uri : vscode . Uri ,
59+ position : vscode . Position ,
60+ timeoutMs : number
61+ ) : Promise < Array < vscode . Location | vscode . LocationLink > > {
62+ const start = Date . now ( ) ;
63+
64+ while ( Date . now ( ) - start < timeoutMs ) {
65+ const definitions = await withTimeout (
66+ vscode . commands . executeCommand < Array < vscode . Location | vscode . LocationLink > > (
67+ 'vscode.executeDefinitionProvider' ,
68+ uri ,
69+ position
70+ ) ,
71+ 5000 ,
72+ 'Definition request timed out'
73+ ) ;
74+ if ( ( definitions ?. length ?? 0 ) > 0 ) {
75+ return definitions ?? [ ] ;
76+ }
77+ await delay ( 250 ) ;
78+ }
79+
80+ const definitions = await withTimeout (
81+ vscode . commands . executeCommand < Array < vscode . Location | vscode . LocationLink > > (
82+ 'vscode.executeDefinitionProvider' ,
83+ uri ,
84+ position
85+ ) ,
86+ 5000 ,
87+ 'Definition request timed out'
88+ ) ;
89+ return definitions ?? [ ] ;
90+ }
91+
3492async function waitForDiagnostics ( uri : vscode . Uri , timeoutMs : number ) : Promise < vscode . Diagnostic [ ] > {
3593 const start = Date . now ( ) ;
3694
@@ -45,6 +103,34 @@ async function waitForDiagnostics(uri: vscode.Uri, timeoutMs: number): Promise<v
45103 return vscode . languages . getDiagnostics ( uri ) ;
46104}
47105
106+ function definitionTarget ( definition : vscode . Location | vscode . LocationLink ) : { uri : vscode . Uri ; range : vscode . Range } {
107+ if ( 'targetUri' in definition ) {
108+ return {
109+ uri : definition . targetUri ,
110+ range : definition . targetRange
111+ } ;
112+ }
113+
114+ return {
115+ uri : definition . uri ,
116+ range : definition . range
117+ } ;
118+ }
119+
48120function delay ( ms : number ) : Promise < void > {
49121 return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
50122}
123+
124+ async function withTimeout < T > ( promise : Thenable < T > , timeoutMs : number , message : string ) : Promise < T > {
125+ let timeoutId : NodeJS . Timeout | undefined ;
126+ try {
127+ return await Promise . race ( [
128+ promise ,
129+ new Promise < T > ( ( _ , reject ) => {
130+ timeoutId = setTimeout ( ( ) => reject ( new Error ( message ) ) , timeoutMs ) ;
131+ } )
132+ ] ) ;
133+ } finally {
134+ if ( timeoutId ) clearTimeout ( timeoutId ) ;
135+ }
136+ }
0 commit comments