@@ -257,7 +257,6 @@ export async function goTest(testconfig: TestConfig): Promise<boolean> {
257257 return Promise . resolve ( false ) ;
258258 }
259259
260- const tmpCoverPath = testconfig . applyCodeCoverage ? getTempFilePath ( 'go-code-cover' ) : undefined ;
261260 // We do not want to clear it if tests are already running, as that could
262261 // lose valuable output.
263262 if ( runningTestProcesses . length < 1 ) {
@@ -268,90 +267,15 @@ export async function goTest(testconfig: TestConfig): Promise<boolean> {
268267 outputChannel . show ( true ) ;
269268 }
270269
271- const testTags : string = getTestTags ( testconfig . goConfig ) ;
272- const args : Array < string > = [ 'test' ] ;
273270 const testType : string = testconfig . isBenchmark ? 'Benchmarks' : 'Tests' ;
274271
275- if ( testconfig . isBenchmark ) {
276- args . push ( '-benchmem' , '-run=^$' ) ;
277- } else {
278- args . push ( '-timeout' , testconfig . goConfig [ 'testTimeout' ] ) ;
279- if ( testconfig . applyCodeCoverage ) {
280- args . push ( '-coverprofile=' + tmpCoverPath ) ;
281- const coverMode = testconfig . goConfig [ 'coverMode' ] ;
282- switch ( coverMode ) {
283- case 'default' :
284- break ;
285- case 'set' : case 'count' : case 'atomic' :
286- args . push ( '-covermode' , coverMode ) ;
287- break ;
288- default :
289- vscode . window . showWarningMessage (
290- `go.coverMode=${ coverMode } is illegal. Use 'set', 'count', 'atomic', or 'default'.`
291- ) ;
292- }
293- }
294- }
295-
296- if ( testTags && testconfig . flags . indexOf ( '-tags' ) === - 1 ) {
297- args . push ( '-tags' , testTags ) ;
298- }
272+ // compute test target package
273+ const { targets, pkgMap, currentGoWorkspace } = await getTestTargetPackages ( testconfig , outputChannel ) ;
299274
300- const targets = testconfig . includeSubDirectories ? [ './...' ] : targetArgs ( testconfig ) ;
275+ // generate full test args.
276+ const { args, outArgs, tmpCoverPath, addJSONFlag } = computeTestCommand ( testconfig , targets ) ;
301277
302- let currentGoWorkspace = '' ;
303- let getCurrentPackagePromise : Promise < string > ;
304- let pkgMapPromise : Promise < Map < string , string > > ;
305- if ( testconfig . isMod ) {
306- getCurrentPackagePromise = getCurrentPackage ( testconfig . dir ) ;
307- // We need the mapping to get absolute paths for the files in the test output.
308- pkgMapPromise = getNonVendorPackages ( testconfig . dir , ! ! testconfig . includeSubDirectories ) ;
309- } else { // GOPATH mode
310- currentGoWorkspace = getCurrentGoWorkspaceFromGOPATH ( getCurrentGoPath ( ) , testconfig . dir ) ;
311- getCurrentPackagePromise = Promise . resolve (
312- currentGoWorkspace ? testconfig . dir . substr ( currentGoWorkspace . length + 1 ) : '' ) ;
313- // We dont need mapping, as we can derive the absolute paths from package path
314- pkgMapPromise = Promise . resolve ( null ) ;
315- }
316-
317- let pkgMap = new Map < string , string > ( ) ;
318- // run go list to populate pkgMap and currentPackage necessary to adjust the test output later.
319- try {
320- const [ pkgMap0 , currentPackage ] = await Promise . all ( [ pkgMapPromise , getCurrentPackagePromise ] ) ;
321- if ( pkgMap0 ) {
322- pkgMap = pkgMap0 ;
323- }
324- // Use the package name to be in the args to enable running tests in symlinked directories
325- // TODO(hyangah): check why modules mode didn't set currentPackage.
326- if ( ! testconfig . includeSubDirectories && currentPackage ) {
327- targets . splice ( 0 , 0 , currentPackage ) ;
328- }
329- } catch ( err ) {
330- outputChannel . appendLine ( `warning: failed to compute package mapping... ${ err } ` ) ;
331- }
332-
333- const outTargets = args . slice ( 0 ) ;
334- if ( targets . length > 4 ) {
335- outTargets . push ( '<long arguments omitted>' ) ;
336- } else {
337- outTargets . push ( ...targets ) ;
338- }
339-
340- if ( args . includes ( '-v' ) && ! args . includes ( '-json' ) ) {
341- args . push ( '-json' ) ;
342- }
343-
344- args . push ( ...targets ) ;
345-
346- // ensure that user provided flags are appended last (allow use of -args ...)
347- // ignore user provided -run flag if we are already using it
348- if ( args . indexOf ( '-run' ) > - 1 ) {
349- removeRunFlag ( testconfig . flags ) ;
350- }
351- args . push ( ...testconfig . flags ) ;
352- outTargets . push ( ...testconfig . flags ) ;
353-
354- outputChannel . appendLine ( [ 'Running tool:' , goRuntimePath , ...outTargets ] . join ( ' ' ) ) ;
278+ outputChannel . appendLine ( [ 'Running tool:' , goRuntimePath , ...outArgs ] . join ( ' ' ) ) ;
355279 outputChannel . appendLine ( '' ) ;
356280
357281 let testResult = false ;
@@ -363,7 +287,7 @@ export async function goTest(testconfig: TestConfig): Promise<boolean> {
363287 const errBuf = new LineBuffer ( ) ;
364288
365289 const testResultLines : string [ ] = [ ] ;
366- const processTestResultLine = args . includes ( '-json' ) ?
290+ const processTestResultLine = addJSONFlag ?
367291 processTestResultLineInJSONMode ( pkgMap , currentGoWorkspace , outputChannel ) :
368292 processTestResultLineInStandardMode ( pkgMap , currentGoWorkspace , testResultLines , outputChannel ) ;
369293
@@ -410,12 +334,133 @@ export async function goTest(testconfig: TestConfig): Promise<boolean> {
410334 outputChannel . appendLine ( `Error: ${ testType } failed.` ) ;
411335 outputChannel . appendLine ( err ) ;
412336 }
413- if ( testconfig . applyCodeCoverage ) {
337+ if ( tmpCoverPath ) {
414338 await applyCodeCoverageToAllEditors ( tmpCoverPath , testconfig . dir ) ;
415339 }
416340 return testResult ;
417341}
418342
343+ async function getTestTargetPackages ( testconfig : TestConfig , outputChannel : vscode . OutputChannel ) {
344+ const targets = testconfig . includeSubDirectories ? [ './...' ] : [ ] ;
345+ let currentGoWorkspace = '' ;
346+ let getCurrentPackagePromise : Promise < string > ;
347+ let pkgMapPromise : Promise < Map < string , string > > ;
348+ if ( testconfig . isMod ) {
349+ getCurrentPackagePromise = getCurrentPackage ( testconfig . dir ) ;
350+ // We need the mapping to get absolute paths for the files in the test output.
351+ pkgMapPromise = getNonVendorPackages ( testconfig . dir , ! ! testconfig . includeSubDirectories ) ;
352+ } else { // GOPATH mode
353+ currentGoWorkspace = getCurrentGoWorkspaceFromGOPATH ( getCurrentGoPath ( ) , testconfig . dir ) ;
354+ getCurrentPackagePromise = Promise . resolve (
355+ currentGoWorkspace ? testconfig . dir . substr ( currentGoWorkspace . length + 1 ) : '' ) ;
356+ // We dont need mapping, as we can derive the absolute paths from package path
357+ pkgMapPromise = Promise . resolve ( null ) ;
358+ }
359+
360+ let pkgMap = new Map < string , string > ( ) ;
361+ // run go list to populate pkgMap and currentPackage necessary to adjust the test output later.
362+ try {
363+ const [ pkgMap0 , currentPackage ] = await Promise . all ( [ pkgMapPromise , getCurrentPackagePromise ] ) ;
364+ if ( pkgMap0 ) {
365+ pkgMap = pkgMap0 ;
366+ }
367+ // Use the package name to be in the args to enable running tests in symlinked directories
368+ // TODO(hyangah): check why modules mode didn't set currentPackage.
369+ if ( ! testconfig . includeSubDirectories && currentPackage ) {
370+ targets . splice ( 0 , 0 , currentPackage ) ;
371+ }
372+ } catch ( err ) {
373+ outputChannel . appendLine ( `warning: failed to compute package mapping... ${ err } ` ) ;
374+ }
375+ return { targets, pkgMap, currentGoWorkspace } ;
376+ }
377+
378+ // computeTestCommand returns the test command argument list and extra info necessary
379+ // to post process the test results.
380+ // Exported for testing.
381+ export function computeTestCommand ( testconfig : TestConfig , targets : string [ ] )
382+ : {
383+ args : Array < string > , // test command args.
384+ outArgs : Array < string > , // compact test command args to show to user.
385+ tmpCoverPath ?: string , // coverage file path if coverage info is necessary.
386+ addJSONFlag : boolean // true if we add extra -json flag for stream processing.
387+ } {
388+ const args : Array < string > = [ 'test' ] ;
389+ // user-specified flags
390+ const argsFlagIdx = testconfig . flags ?. indexOf ( '-args' ) ?? - 1 ;
391+ const userFlags = argsFlagIdx < 0 ? testconfig . flags : testconfig . flags . slice ( 0 , argsFlagIdx ) ;
392+ const userArgsFlags = argsFlagIdx < 0 ? [ ] : testconfig . flags . slice ( argsFlagIdx ) ;
393+
394+ // flags to limit test time
395+ if ( testconfig . isBenchmark ) {
396+ args . push ( '-benchmem' , '-run=^$' ) ;
397+ } else {
398+ args . push ( '-timeout' , testconfig . goConfig [ 'testTimeout' ] ) ;
399+ }
400+
401+ // tags flags only if user didn't set -tags yet.
402+ const testTags : string = getTestTags ( testconfig . goConfig ) ;
403+ if ( testTags && userFlags . indexOf ( '-tags' ) === - 1 ) {
404+ args . push ( '-tags' , testTags ) ;
405+ }
406+
407+ // coverage flags
408+ let tmpCoverPath : string ;
409+ if ( testconfig . applyCodeCoverage ) {
410+ tmpCoverPath = getTempFilePath ( 'go-code-cover' ) ;
411+ args . push ( '-coverprofile=' + tmpCoverPath ) ;
412+ const coverMode = testconfig . goConfig [ 'coverMode' ] ;
413+ switch ( coverMode ) {
414+ case 'default' :
415+ break ;
416+ case 'set' : case 'count' : case 'atomic' :
417+ args . push ( '-covermode' , coverMode ) ;
418+ break ;
419+ default :
420+ vscode . window . showWarningMessage (
421+ `go.coverMode=${ coverMode } is illegal. Use 'set', 'count', 'atomic', or 'default'.`
422+ ) ;
423+ }
424+ }
425+
426+ // all other test run/benchmark flags
427+ args . push ( ...targetArgs ( testconfig ) ) ;
428+
429+ const outArgs = args . slice ( 0 ) ; // command to show
430+
431+ // if user set -v, set -json to emulate streaming test output
432+ const addJSONFlag = userFlags . includes ( '-v' ) && ! userFlags . includes ( '-json' ) ;
433+ if ( addJSONFlag ) {
434+ args . push ( '-json' ) ; // this is not shown to the user.
435+ }
436+
437+ if ( targets . length > 4 ) {
438+ outArgs . push ( '<long arguments omitted>' ) ;
439+ } else {
440+ outArgs . push ( ...targets ) ;
441+ }
442+ args . push ( ...targets ) ;
443+
444+ // ensure that user provided flags are appended last (allow use of -args ...)
445+ // ignore user provided -run flag if we are already using it
446+ if ( args . indexOf ( '-run' ) > - 1 ) {
447+ removeRunFlag ( userFlags ) ;
448+ }
449+
450+ args . push ( ...userFlags ) ;
451+ outArgs . push ( ...userFlags ) ;
452+
453+ args . push ( ...userArgsFlags ) ;
454+ outArgs . push ( ...userArgsFlags ) ;
455+
456+ return {
457+ args,
458+ outArgs,
459+ tmpCoverPath,
460+ addJSONFlag
461+ } ;
462+ }
463+
419464function processTestResultLineInJSONMode (
420465 pkgMap : Map < string , string > ,
421466 currentGoWorkspace : string ,
0 commit comments