150 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as plugins from './tstest.plugins.js';
 | |
| import * as paths from './tstest.paths.js';
 | |
| import { SmartFile } from '@push.rocks/smartfile';
 | |
| import { TestExecutionMode } from './index.js';
 | |
| 
 | |
| // tap related stuff
 | |
| import { TapCombinator } from './tstest.classes.tap.combinator.js';
 | |
| import { TapParser } from './tstest.classes.tap.parser.js';
 | |
| import { TapTestResult } from './tstest.classes.tap.testresult.js';
 | |
| 
 | |
| export class TestDirectory {
 | |
|   /**
 | |
|    * the current working directory
 | |
|    */
 | |
|   cwd: string;
 | |
| 
 | |
|   /**
 | |
|    * the test path or pattern
 | |
|    */
 | |
|   testPath: string;
 | |
| 
 | |
|   /**
 | |
|    * the execution mode
 | |
|    */
 | |
|   executionMode: TestExecutionMode;
 | |
| 
 | |
|   /**
 | |
|    * an array of Smartfiles
 | |
|    */
 | |
|   testfileArray: SmartFile[] = [];
 | |
| 
 | |
|   /**
 | |
|    * the constructor for TestDirectory
 | |
|    * @param cwdArg - the current working directory
 | |
|    * @param testPathArg - the test path/pattern
 | |
|    * @param executionModeArg - the execution mode
 | |
|    */
 | |
|   constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode) {
 | |
|     this.cwd = cwdArg;
 | |
|     this.testPath = testPathArg;
 | |
|     this.executionMode = executionModeArg;
 | |
|   }
 | |
| 
 | |
|   private async _init() {
 | |
|     switch (this.executionMode) {
 | |
|       case TestExecutionMode.FILE:
 | |
|         // Single file mode
 | |
|         const filePath = plugins.path.isAbsolute(this.testPath) 
 | |
|           ? this.testPath 
 | |
|           : plugins.path.join(this.cwd, this.testPath);
 | |
|         
 | |
|         if (await plugins.smartfile.fs.fileExists(filePath)) {
 | |
|           this.testfileArray = [await plugins.smartfile.SmartFile.fromFilePath(filePath)];
 | |
|         } else {
 | |
|           throw new Error(`Test file not found: ${filePath}`);
 | |
|         }
 | |
|         break;
 | |
|         
 | |
|       case TestExecutionMode.GLOB:
 | |
|         // Glob pattern mode - use listFileTree which supports glob patterns
 | |
|         const globPattern = this.testPath;
 | |
|         const matchedFiles = await plugins.smartfile.fs.listFileTree(this.cwd, globPattern);
 | |
|         
 | |
|         this.testfileArray = await Promise.all(
 | |
|           matchedFiles.map(async (filePath) => {
 | |
|             const absolutePath = plugins.path.isAbsolute(filePath) 
 | |
|               ? filePath 
 | |
|               : plugins.path.join(this.cwd, filePath);
 | |
|             return await plugins.smartfile.SmartFile.fromFilePath(absolutePath);
 | |
|           })
 | |
|         );
 | |
|         break;
 | |
|         
 | |
|       case TestExecutionMode.DIRECTORY:
 | |
|         // Directory mode - now recursive with ** pattern
 | |
|         const dirPath = plugins.path.join(this.cwd, this.testPath);
 | |
| 
 | |
|         // Search for both TypeScript test files and Docker shell test files
 | |
|         const tsPattern = '**/test*.ts';
 | |
|         const dockerPattern = '**/*.docker.sh';
 | |
| 
 | |
|         const [tsFiles, dockerFiles] = await Promise.all([
 | |
|           plugins.smartfile.fs.listFileTree(dirPath, tsPattern),
 | |
|           plugins.smartfile.fs.listFileTree(dirPath, dockerPattern),
 | |
|         ]);
 | |
| 
 | |
|         const allTestFiles = [...tsFiles, ...dockerFiles];
 | |
| 
 | |
|         this.testfileArray = await Promise.all(
 | |
|           allTestFiles.map(async (filePath) => {
 | |
|             const absolutePath = plugins.path.isAbsolute(filePath)
 | |
|               ? filePath
 | |
|               : plugins.path.join(dirPath, filePath);
 | |
|             return await plugins.smartfile.SmartFile.fromFilePath(absolutePath);
 | |
|           })
 | |
|         );
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   async getTestFilePathArray() {
 | |
|     await this._init();
 | |
|     const testFilePaths: string[] = [];
 | |
|     for (const testFile of this.testfileArray) {
 | |
|       // Use the path directly from the SmartFile
 | |
|       testFilePaths.push(testFile.path);
 | |
|     }
 | |
|     return testFilePaths;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get test files organized by parallel execution groups
 | |
|    * @returns An object with grouped tests
 | |
|    */
 | |
|   async getTestFileGroups(): Promise<{
 | |
|     serial: string[];
 | |
|     parallelGroups: { [groupName: string]: string[] };
 | |
|   }> {
 | |
|     await this._init();
 | |
|     
 | |
|     const result = {
 | |
|       serial: [] as string[],
 | |
|       parallelGroups: {} as { [groupName: string]: string[] }
 | |
|     };
 | |
|     
 | |
|     for (const testFile of this.testfileArray) {
 | |
|       const filePath = testFile.path;
 | |
|       const fileName = plugins.path.basename(filePath);
 | |
|       
 | |
|       // Check if file has parallel group pattern
 | |
|       const parallelMatch = fileName.match(/\.para__(\d+)\./);
 | |
|       
 | |
|       if (parallelMatch) {
 | |
|         const groupNumber = parallelMatch[1];
 | |
|         const groupName = `para__${groupNumber}`;
 | |
|         
 | |
|         if (!result.parallelGroups[groupName]) {
 | |
|           result.parallelGroups[groupName] = [];
 | |
|         }
 | |
|         result.parallelGroups[groupName].push(filePath);
 | |
|       } else {
 | |
|         // File runs serially
 | |
|         result.serial.push(filePath);
 | |
|       }
 | |
|     }
 | |
|     
 | |
|     return result;
 | |
|   }
 | |
| }
 |