import * as vscode from 'vscode' ; import * as RegExpEscape from 'escape-string-regexp' ; import { TestExplorer } from './testExplorer' ; import { TreeNode } from './tree/treeNode' ; import { TestNode } from './tree/testNode' ; import { ErrorNode } from './tree/errorNode' ; import { TestSuiteInfo , TestInfo } from 'vscode-test-adapter-api' ; export function * allTests ( treeNode ) { if ( treeNode . info . type === 'suite' ) { for ( const child of treeNode . children ) { yield * allTests ( child ) ; } } else { yield < TestNode > treeNode ; } } export function isAncestor ( node , otherNode ) { return ! ! otherNode && ( ( node === otherNode ) || isAncestor ( node , otherNode . parent ) ) ; } export function intersect ( mainNode , nodes ) { for ( const node of nodes ) { if ( isAncestor ( node , mainNode ) ) { return [ mainNode ] ; } } return nodes . filter ( node => isAncestor ( mainNode , node ) ) ; } export function runTestsInFile ( fileUri , testExplorer ) { if ( ! fileUri && vscode . window . activeTextEditor ) { fileUri = vscode . window . activeTextEditor . document . uri . toString ( ) ; } if ( fileUri ) { for ( const collection of testExplorer . collections . values ( ) ) { if ( collection . suite ) { const found = findFileNodes ( fileUri , collection . suite ) ; if ( found . length > 0 ) { testExplorer . run ( found , false ) ; return ; } } } } } export function debugTestsInFile ( fileUri , testExplorer ) { if ( ! fileUri && vscode . window . activeTextEditor ) { fileUri = vscode . window . activeTextEditor . document . uri . toString ( ) ; } if ( fileUri ) { for ( const collection of testExplorer . collections . values ( ) ) { if ( collection . suite && collection . adapter . debug ) { const found = findFileNodes ( fileUri , collection . suite ) ; if ( found . length > 0 ) { testExplorer . debug ( found , false ) ; return ; } } } } } function findFileNodes ( fileUri , searchNode ) { if ( searchNode . fileUri ) { if ( searchNode . fileUri === fileUri ) { return [ searchNode ] ; } else { return [ ] ; } } else { return ( [ ] as TreeNode [ ] ) . concat ( ... searchNode . children . map ( childNode => findFileNodes ( fileUri , childNode ) ) ) ; } } export function runTestAtCursor ( testExplorer ) { const editor = vscode . window . activeTextEditor ; if ( editor ) { const nodes = findNodesLocatedAboveCursor ( editor . document . uri . toString ( ) , editor . selection . active . line , testExplorer ) ; if ( nodes . length > 0 ) { testExplorer . run ( nodes ) ; } } } export function debugTestAtCursor ( testExplorer ) { const editor = vscode . window . activeTextEditor ; if ( editor ) { const nodes = findNodesLocatedAboveCursor ( editor . document . uri . toString ( ) , editor . selection . active . line , testExplorer ) ; if ( nodes . length > 0 ) { testExplorer . debug ( nodes ) ; } } } function findNodesLocatedAboveCursor ( fileUri , cursorLine , testExplorer ) { let currentLine = - 1 ; let currentNodes = [ ] ; for ( const collection of testExplorer . collections . values ( ) ) { const locatedNodes = collection . getLocatedNodes ( fileUri ) ; if ( locatedNodes ) { for ( const line of locatedNodes . keys ( ) ) { if ( ( line > cursorLine ) || ( line < currentLine ) ) continue ; const lineNodes = locatedNodes . get ( line ) ! ; if ( line === currentLine ) { currentNodes . push ( ... lineNodes ) ; } else { currentLine = line ; currentNodes = [ ... lineNodes ] ; } } } } return currentNodes ; } export function findLineContaining ( needle , haystack ) { if ( ! haystack ) return undefined ; const index = haystack . search ( RegExpEscape ( needle ) ) ; if ( index < 0 ) return undefined ; return haystack . substr ( 0 , index ) . split ( '\n' ) . length - 1 ; } export async function pickNodes ( nodes ) { if ( nodes . length > 1 ) { const labels = nodes . map ( node => node . getFullLabel ( ) ) ; labels . push ( "All of them" ) ; const pickedLabel = await vscode . window . showQuickPick ( labels ) ; if ( pickedLabel === "All of them" ) { return nodes ; } else { return nodes . filter ( node => ( node . getFullLabel ( ) === pickedLabel ) ) ; } } else { return nodes ; } } export function createRunCodeLens ( line , nodes ) { const range = new vscode . Range ( line , 0 , line , 0 ) ; return new vscode . CodeLens ( range , { title : 'Run' , command : 'test-explorer.pick-and-run' , arguments : [ nodes ] } ) ; } export function createDebugCodeLens ( line , nodes ) { const range = new vscode . Range ( line , 0 , line , 0 ) ; return new vscode . CodeLens ( range , { title : 'Debug' , command : 'test-explorer.pick-and-debug' , arguments : [ nodes ] } ) ; } export function createLogCodeLens ( line , nodes ) { const range = new vscode . Range ( line , 0 , line , 0 ) ; return new vscode . CodeLens ( range , { title : 'Show Log' , command : 'test-explorer.show-log' , arguments : [ nodes ] } ) ; } export function createRevealCodeLens ( line , node ) { const range = new vscode . Range ( line , 0 , line , 0 ) ; return new vscode . CodeLens ( range , { title : 'Show in Test Explorer' , command : 'test-explorer.reveal' , arguments : [ node ] } ) ; } const schemeMatcher = /^[a-z][a-z0-9+-.]+:/ ; export function normalizeFilename ( file ) { if ( file === undefined ) return undefined ; if ( schemeMatcher . test ( file ) ) { return vscode . Uri . parse ( file ) . toString ( ) ; } else { return vscode . Uri . file ( file ) . toString ( ) ; } } export function expand ( testExplorer , treeView , levels ) { for ( const node of testExplorer . getChildren ( ) ) { treeView . reveal ( node , { expand : levels } ) ; } } export function groupSuitesByLabel ( nodes ) { const grouped = new Map < string , TestSuiteInfo [ ] | TestInfo > ( ) ; let testCount = 0 ; for ( const node of nodes ) { if ( node . type === 'test' ) { const key = `t${ testCount ++ }` ; grouped . set ( key , node ) ; } else { const key = `s${ node . label }` ; if ( ! grouped . has ( key ) ) { grouped . set ( key , [ node ] ) ; } else { ( grouped . get ( key ) as TestSuiteInfo [ ] ) . push ( node ) ; } } } return [ ... grouped . values ( ) ] ; } export function mergeSuiteInfos ( suites ) { if ( suites . length === 1 ) { return suites [ 0 ] ; } else { return { type : 'suite' , id : JSON . stringify ( suites . map ( suite => suite . id ) . sort ( ) ) , label : suites [ 0 ] . label , children : ( [ ] as ( TestSuiteInfo | TestInfo ) [ ] ) . concat ( ... suites . map ( suite => suite . children ) ) } ; } } export function getAdapterIds ( nodes ) { return ( [ ] as string [ ] ) . concat ( ... nodes . map ( node => node . adapterIds ) ) ; }