@@ -5,7 +5,7 @@ import * as fs from 'fs';
55import * as path from 'path' ;
66import * as vscode from 'vscode' ;
77import { TestItem } from 'vscode' ;
8- import { integer } from 'vscode-languageclient' ;
8+ import { CancellationToken } from 'vscode-languageclient' ;
99import { adaExtState } from './extension' ;
1010import { exe , getObjectDir } from './helpers' ;
1111
@@ -197,8 +197,8 @@ export function parseResults(
197197 for ( const e of tests ) {
198198 // Check if the result line is for the test 'e'
199199 const test_src = getParentTestSourceName ( e ) ;
200- const p : integer | undefined = e . parent ?. range ?. start . line ;
201- const test_line : integer = p ? p + 1 : 0 ;
200+ const p : number | undefined = e . parent ?. range ?. start . line ;
201+ const test_line : number = p ? p + 1 : 0 ;
202202 const check_line = matchs [ i ] . match ( test_src . label + ':' + test_line . toString ( ) ) ;
203203 // update the state of the test
204204 if ( check_line != null && run != undefined ) {
@@ -438,7 +438,11 @@ export function pathIsReadable(p: string): boolean {
438438 * @param item - the TestItem whose children must be computed, or `undefined` if
439439 * we should compute the root items of the tree.
440440 */
441- async function resolveHandler ( item : TestItem | undefined , recursive = false ) {
441+ async function resolveHandler (
442+ item : TestItem | undefined ,
443+ recursive = false ,
444+ token ?: CancellationToken
445+ ) {
442446 if ( ! item ) {
443447 if ( ! watcher ) {
444448 /**
@@ -474,7 +478,12 @@ async function resolveHandler(item: TestItem | undefined, recursive = false) {
474478
475479 if ( recursive ) {
476480 const promises : Promise < void > [ ] = [ ] ;
477- item . children . forEach ( ( i ) => promises . push ( resolveHandler ( i , true ) ) ) ;
481+ item . children . forEach ( ( i ) => {
482+ if ( token ?. isCancellationRequested ) {
483+ throw new vscode . CancellationError ( ) ;
484+ }
485+ promises . push ( resolveHandler ( i , true , token ) ) ;
486+ } ) ;
478487 await Promise . all ( promises ) ;
479488 }
480489 }
@@ -496,17 +505,17 @@ function configureTestExecution(controller: vscode.TestController) {
496505}
497506
498507async function runHandler ( request : vscode . TestRunRequest , token : vscode . CancellationToken ) {
499- if ( request . include == undefined && request . exclude == undefined ) {
508+ if ( ( request . include ?. length ?? 0 ) === 0 && ( request . exclude ?. length ?? 0 ) === 0 ) {
500509 /**
501510 * Run all tests. This ignores request.exclude which is why we only use
502511 * it in this branch.
503512 */
504- await handleRunAll ( request ) ;
513+ await handleRunAll ( request , token ) ;
505514 } else {
506515 /**
507516 * Run a specific set of tests
508517 */
509- await handleRunRequestedTests ( request ) ;
518+ await handleRunRequestedTests ( request , token ) ;
510519 }
511520}
512521
@@ -515,36 +524,46 @@ async function runHandler(request: vscode.TestRunRequest, token: vscode.Cancella
515524 * controller.items) and request.exclude. It then runs the test driver for each
516525 * test, using the --routines argument at each run to select a specific test.
517526 */
518- async function handleRunRequestedTests ( request : vscode . TestRunRequest ) {
519- const requestedRootTests = [ ] ;
527+ async function handleRunRequestedTests ( request : vscode . TestRunRequest , token : CancellationToken ) {
528+ const run = controller . createTestRun ( request , undefined , false ) ;
529+ try {
530+ const requestedRootTests = [ ] ;
531+
532+ if ( request . include ) {
533+ requestedRootTests . push ( ...request . include ) ;
534+ } else {
535+ /**
536+ * Consider all tests as included
537+ */
538+ controller . items . forEach ( ( i ) => requestedRootTests . push ( i ) ) ;
539+ }
520540
521- if ( request . include ) {
522- requestedRootTests . push ( ...request . include ) ;
523- } else {
524541 /**
525- * Consider all tests as included
542+ * First resolve included tests as the API says that it is the
543+ * responsibility of the run handler.
526544 */
527- controller . items . forEach ( ( i ) => requestedRootTests . push ( i ) ) ;
528- }
545+ await Promise . all ( requestedRootTests . map ( ( i ) => resolveHandler ( i , true , token ) ) ) ;
529546
530- /**
531- * First resolve included tests as the API says that it is the
532- * responsibility of the run handler.
533- */
534- await Promise . all ( requestedRootTests . map ( ( i ) => resolveHandler ( i , true ) ) ) ;
535-
536- /**
537- * Collect and filter tests to run.
538- */
539- const requestedLeafTests = requestedRootTests . flatMap ( collectLeafItems ) ;
540- const excludedLeafTests = request . exclude ? request . exclude . flatMap ( collectLeafItems ) : [ ] ;
541- const testsToRun = requestedLeafTests . filter ( ( t ) => ! excludedLeafTests ?. includes ( t ) ) ;
542-
543- const run = controller . createTestRun ( request , undefined , false ) ;
547+ /**
548+ * Collect and filter tests to run.
549+ */
550+ const requestedLeafTests = requestedRootTests . flatMap ( ( i ) => collectLeafItems ( i , token ) ) ;
551+ const excludedLeafTests = request . exclude
552+ ? request . exclude . flatMap ( ( i ) => collectLeafItems ( i , token ) )
553+ : [ ] ;
554+ const testsToRun = requestedLeafTests . filter ( ( t ) => {
555+ if ( token ?. isCancellationRequested ) {
556+ throw new vscode . CancellationError ( ) ;
557+ }
558+ return ! excludedLeafTests ?. includes ( t ) ;
559+ } ) ;
544560
545- try {
546561 await buildTestDriver ( run ) ;
547562
563+ if ( token ?. isCancellationRequested ) {
564+ throw new vscode . CancellationError ( ) ;
565+ }
566+
548567 /**
549568 * Mark tests as queued for execution
550569 */
@@ -555,6 +574,9 @@ async function handleRunRequestedTests(request: vscode.TestRunRequest) {
555574 */
556575 const execPath = await getGnatTestDriverExecPath ( ) ;
557576 for ( const test of testsToRun ) {
577+ if ( token ?. isCancellationRequested ) {
578+ throw new vscode . CancellationError ( ) ;
579+ }
558580 const start = Date . now ( ) ;
559581 run . started ( test ) ;
560582 const cmd = [ execPath , '--passed-tests=show' , `--routines=${ test . id } ` ] ;
@@ -592,30 +614,43 @@ function prepareAndAppendOutput(run: vscode.TestRun, out: string) {
592614 * in {@link handleRunRequestedTests} fails because of GNATtest shortcomings, we
593615 * still have this approach of running all tests as a backup.
594616 */
595- async function handleRunAll ( request : vscode . TestRunRequest ) {
617+ async function handleRunAll ( request : vscode . TestRunRequest , token : CancellationToken ) {
596618 const run = controller . createTestRun ( request , undefined , false ) ;
597619 try {
598620 /**
599621 * First we need to build the test driver project.
600622 */
601623 await buildTestDriver ( run ) ;
602624
625+ if ( token ?. isCancellationRequested ) {
626+ throw new vscode . CancellationError ( ) ;
627+ }
628+
603629 /**
604630 * Resolve all the test tree before collecting tests
605631 */
606632 const promises : Promise < void > [ ] = [ ] ;
607- controller . items . forEach ( ( i ) => promises . push ( resolveHandler ( i , true ) ) ) ;
633+ controller . items . forEach ( ( i ) => promises . push ( resolveHandler ( i , true , token ) ) ) ;
608634 await Promise . all ( promises ) ;
609635
636+ if ( token ?. isCancellationRequested ) {
637+ throw new vscode . CancellationError ( ) ;
638+ }
639+
610640 /**
611641 * Now let's collect all tests, i.e. all leafs of the TestItem tree.
612642 */
613- const allTests : TestItem [ ] = collectLeafsFromCollection ( controller . items ) ;
643+ const allTests : TestItem [ ] = collectLeafsFromCollection ( controller . items , token ) ;
614644
615645 /**
616646 * Mark all tests as started.
617647 */
618- allTests . forEach ( ( t ) => run . started ( t ) ) ;
648+ allTests . forEach ( ( t ) => {
649+ if ( token ?. isCancellationRequested ) {
650+ throw new vscode . CancellationError ( ) ;
651+ }
652+ run . started ( t ) ;
653+ } ) ;
619654
620655 /**
621656 * Invoke the test driver
@@ -628,6 +663,9 @@ async function handleRunAll(request: vscode.TestRunRequest) {
628663 prepareAndAppendOutput ( run , driver . stderr . toLocaleString ( ) ) ;
629664
630665 for ( const test of allTests ) {
666+ if ( token ?. isCancellationRequested ) {
667+ throw new vscode . CancellationError ( ) ;
668+ }
631669 determineTestOutcome ( test , driverOutput , run ) ;
632670 }
633671
@@ -736,19 +774,28 @@ function determineTestOutcome(
736774 }
737775}
738776
739- function collectLeafsFromCollection ( items : vscode . TestItemCollection ) : vscode . TestItem [ ] {
777+ function collectLeafsFromCollection (
778+ items : vscode . TestItemCollection ,
779+ token ?: CancellationToken
780+ ) : vscode . TestItem [ ] {
740781 const res : vscode . TestItem [ ] = [ ] ;
741782 items . forEach ( ( i ) => {
742- res . push ( ...collectLeafItems ( i ) ) ;
783+ if ( token ?. isCancellationRequested ) {
784+ throw new vscode . CancellationError ( ) ;
785+ }
786+ res . push ( ...collectLeafItems ( i , token ) ) ;
743787 } ) ;
744788 return res ;
745789}
746790
747- function collectLeafItems ( item : TestItem ) : vscode . TestItem [ ] {
791+ function collectLeafItems ( item : TestItem , token ?: CancellationToken ) : vscode . TestItem [ ] {
748792 if ( item . children . size > 0 ) {
749793 const res : vscode . TestItem [ ] = [ ] ;
750794 item . children . forEach ( ( i ) => {
751- res . push ( ...collectLeafItems ( i ) ) ;
795+ if ( token ?. isCancellationRequested ) {
796+ throw new vscode . CancellationError ( ) ;
797+ }
798+ res . push ( ...collectLeafItems ( i , token ) ) ;
752799 } ) ;
753800 return res ;
754801 } else {
@@ -760,40 +807,6 @@ function escapeRegExp(text: string) {
760807 return text . replace ( / [ - [ \] { } ( ) * + ? . , \\ ^ $ | # \s ] / g, '\\$&' ) ;
761808}
762809
763- /*
764- test unit/case run handler
765- */
766- function handleUnitRun (
767- tests : vscode . TestItem [ ] ,
768- run : vscode . TestRun ,
769- terminalName : string ,
770- gnattestPath : string
771- ) {
772- const terminal = vscode . window . createTerminal ( terminalName ) ;
773- const ext : string = process . platform == 'win32' ? '.exe' : '' ;
774- // clean the previous results
775- terminal . sendText ( '> ' + path . join ( gnattestPath , 'result.txt' ) ) ;
776- // run every test case seperatly and append the results
777- for ( const test of tests ) {
778- run . appendOutput ( `Running ${ test . id } \r\n` ) ;
779- run . started ( test ) ;
780- const parent = getParentTestSourceName ( test ) ;
781- const p : integer | undefined = test . parent ?. range ?. start . line ;
782- const line : integer = p ? p + 1 : 0 ;
783- terminal . sendText ( 'gprbuild -P ' + path . join ( gnattestPath , 'harness' , 'test_driver.gpr' ) ) ;
784- terminal . sendText (
785- path . join ( gnattestPath , 'harness' , 'test_runner' + ext ) +
786- ' --routines=' +
787- parent . id +
788- ':' +
789- line . toString ( ) +
790- ' >> ' +
791- path . join ( gnattestPath , 'result.txt' )
792- ) ;
793- }
794- terminal . sendText ( 'exit' ) ;
795- }
796-
797810function logAndRun ( run : vscode . TestRun , cmd : string [ ] ) {
798811 run . appendOutput ( `$ ${ cmd . map ( ( arg ) => `"${ arg } "` ) . join ( ' ' ) } \r\n` ) ;
799812 return cp . spawnSync ( cmd [ 0 ] , cmd . slice ( 1 ) ) ;
0 commit comments