1+ import * as vscode from 'vscode' ;
2+ import { loadedTestController } from './extension' ;
3+ import { replaceRootItems , serverSpec } from './historyExplorer' ;
4+ import logger from './logger' ;
5+ import { makeRESTRequest } from './makeRESTRequest' ;
6+
7+ const isResolvedMap = new WeakMap < vscode . TestItem , boolean > ( ) ;
8+
9+ async function resolveItemChildren ( item : vscode . TestItem ) {
10+ if ( item ) {
11+ item . busy = true ;
12+ const spec = await serverSpec ( item ) ;
13+ const parts = item . id . split ( ':' ) ;
14+ const namespace = parts [ 1 ] ;
15+ if ( spec ) {
16+ if ( parts . length === 2 ) {
17+ // Find all TestCase classes
18+ const response = await makeRESTRequest (
19+ "POST" ,
20+ spec ,
21+ { apiVersion : 1 , namespace, path : "/action/query" } ,
22+ { query : `CALL %Dictionary.ClassDefinition_SubclassOf('%UnitTest.TestCase', '${ ( namespace === "%SYS" ? "" : "@" ) } ')` } ,
23+ ) ;
24+ if ( response ) {
25+ response ?. data ?. result ?. content ?. forEach ( async element => {
26+ const fullClassName = element . Name ;
27+
28+ const response = await makeRESTRequest (
29+ "POST" ,
30+ spec ,
31+ { apiVersion : 1 , namespace, path : "/action/query" } ,
32+ { query : `SELECT Name FROM %Dictionary.MethodDefinition WHERE parent='${ fullClassName } ' AND Name %STARTSWITH 'Test'` } ,
33+ ) ;
34+ if ( response ?. data ?. result ?. content ?. length > 0 ) {
35+ const tiClass = loadedTestController . createTestItem (
36+ `${ item . id } :${ fullClassName } ` ,
37+ fullClassName
38+ ) ;
39+ //tiClass.description = `Class ${fullClassName}`;
40+ response ?. data ?. result ?. content ?. forEach ( element => {
41+ const testMethodSuffix = element . Name . slice ( 4 ) ;
42+ const tiMethod = loadedTestController . createTestItem (
43+ `${ item . id } :${ element . Name } ` ,
44+ testMethodSuffix
45+ ) ;
46+ tiClass . children . add ( tiMethod ) ;
47+ } ) ;
48+ item . children . add ( tiClass ) ;
49+ }
50+ } ) ;
51+ }
52+ }
53+ else if ( parts . length === 3 ) {
54+ // Find all Test* methods in a class
55+ const fullClassName = parts [ 2 ] ;
56+ const response = await makeRESTRequest (
57+ "POST" ,
58+ spec ,
59+ { apiVersion : 1 , namespace, path : "/action/query" } ,
60+ { query : `SELECT Name FROM %Dictionary.MethodDefinition WHERE parent='${ fullClassName } ' AND Name %STARTSWITH 'Test'` } ,
61+ ) ;
62+ if ( response ) {
63+ response ?. data ?. result ?. content ?. forEach ( element => {
64+ const testMethodSuffix = element . Name . slice ( 4 ) ;
65+ const child = loadedTestController . createTestItem (
66+ `${ item . id } :${ element . Name } ` ,
67+ testMethodSuffix
68+ ) ;
69+ child . canResolveChildren = false ;
70+ item . children . add ( child ) ;
71+ } ) ;
72+ }
73+ }
74+ }
75+ item . busy = false ;
76+ }
77+ else {
78+ // Root items
79+ replaceRootItems ( loadedTestController ) ;
80+ }
81+ }
82+
83+ export async function setupServerTestsController ( ) {
84+ logger . info ( 'setupServerTestsController invoked' ) ;
85+
86+ loadedTestController . createRunProfile ( 'Run Tests' , vscode . TestRunProfileKind . Run , runTestsHandler , true ) ;
87+ loadedTestController . createRunProfile ( 'Debug Tests' , vscode . TestRunProfileKind . Debug , runTestsHandler ) ;
88+ //testController.createRunProfile('Test Coverage', vscode.TestRunProfileKind.Coverage, runTestsHandler);
89+
90+ loadedTestController . resolveHandler = resolveItemChildren ;
91+ loadedTestController . items . replace ( [ loadedTestController . createTestItem ( '-' , 'loading...' ) ] ) ;
92+ }
93+
94+ export async function runTestsHandler ( request : vscode . TestRunRequest , cancellation : vscode . CancellationToken ) {
95+ logger . info ( 'runTestsHandler invoked' ) ;
96+
97+ const run = loadedTestController . createTestRun (
98+ request ,
99+ 'Fake Test Results' ,
100+ true
101+ ) ;
102+ run . appendOutput ( 'Fake output from fake run of fake server tests.\r\nTODO' ) ;
103+ const queue : vscode . TestItem [ ] = [ ] ;
104+
105+ // Loop through all included tests, or all known tests, and add them to our queue
106+ if ( request . include ) {
107+ request . include . forEach ( test => queue . push ( test ) ) ;
108+ } else {
109+ loadedTestController . items . forEach ( test => queue . push ( test ) ) ;
110+ }
111+
112+ // For every test that was queued, try to run it. Call run.passed() or run.failed().
113+ // The `TestMessage` can contain extra information, like a failing location or
114+ // a diff output. But here we'll just give it a textual message.
115+ while ( queue . length > 0 && ! cancellation . isCancellationRequested ) {
116+ const test = queue . pop ( ) ! ;
117+
118+ // Skip tests the user asked to exclude
119+ if ( request . exclude ?. includes ( test ) ) {
120+ continue ;
121+ }
122+
123+ // Resolve children if not already done
124+ if ( test . canResolveChildren && ! isResolvedMap . get ( test ) ) {
125+ resolveItemChildren ( test ) ;
126+ }
127+
128+ // Return result for leaf items
129+ if ( test . children . size === 0 ) {
130+ const suffix = test . id . split ( '.' ) . pop ( )
131+ switch ( suffix ) {
132+ case '1' :
133+ run . skipped ( test ) ;
134+ break ;
135+
136+ case '2' :
137+ run . failed ( test , new vscode . TestMessage ( 'fake failure' ) , 12300 ) ;
138+ break ;
139+
140+ case '3' :
141+ run . errored ( test , new vscode . TestMessage ( 'fake error' ) , 900 ) ;
142+ break ;
143+
144+ case '4' :
145+ run . enqueued ( test ) ;
146+ break ;
147+
148+ default :
149+ run . passed ( test , 45600 ) ;
150+ break ;
151+ }
152+ }
153+
154+ // Queue any children
155+ test . children . forEach ( test => queue . push ( test ) ) ;
156+ }
157+
158+ await new Promise ( resolve => setTimeout ( resolve , 5000 ) ) ;
159+ run . end ( ) ;
160+ }
0 commit comments