UNPKG

testeranto

Version:

the AI powered BDD test framework for typescript projects

387 lines (329 loc) 13.3 kB
// For Golingvu, we need to generate a wrapper that imports and runs the original code // The entry point should be imported and its functionality tested // Include the signature in a comment for the watcher to detect changes // Use build tags to ensure it's only included when testeranto is specified // The package should be testeranto_test to avoid being treated as a main package /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ import path from "path"; import fs from "fs"; import { findProjectRoot } from "./golingvuMetafile/helpers"; import { GolingvuMetafile } from "./golingvuMetafile/types"; export function writeGolingvuMetafile( testName: string, metafile: GolingvuMetafile ): void { // Always use the original project root, not the current working directory // This assumes the project root is where package.json is located const projectRoot = findProjectRoot(); const metafilePath = path.join( "testeranto", "metafiles", "golang", "core.json" ); fs.writeFileSync(metafilePath, JSON.stringify(metafile, null, 2)); for (const [outputPath, outputInfo] of Object.entries( metafile.metafile.outputs )) { const entryPoint = (outputInfo as any).entryPoint; const signature = (outputInfo as any).signature; // For Go modules, the import path should be based on the module name + path from module root // First, find the module root by looking for go.mod in parent directories let moduleRoot = process.cwd(); let modulePath = ""; // Find the module root directory let currentDir = path.dirname(entryPoint); while (currentDir !== path.parse(currentDir).root) { const potentialGoMod = path.join(currentDir, "go.mod"); if (fs.existsSync(potentialGoMod)) { moduleRoot = currentDir; // Read the module path const goModContent = fs.readFileSync(potentialGoMod, "utf-8"); const moduleMatch = goModContent.match(/^module\s+(\S+)/m); if (moduleMatch && moduleMatch[1]) { modulePath = moduleMatch[1]; } break; } currentDir = path.dirname(currentDir); } // Read the original file to determine the package name let originalPackageName = "main"; try { const originalContent = fs.readFileSync(entryPoint, "utf-8"); const packageMatch = originalContent.match(/^package\s+(\w+)/m); if (packageMatch && packageMatch[1]) { originalPackageName = packageMatch[1]; } } catch (error) { console.warn( `Could not read original file ${entryPoint} to determine package name:`, error ); } // Generate a single consolidated wrapper that imports the implementation // Use the entry point from the output info to determine what to import // Get the entry point from the output info const entryPointValue = (outputInfo as any).entryPoint; if (!entryPointValue || entryPointValue === "") { throw new Error("No valid entry point found for generating wrapper"); } try { // Generate the wrapper content directly // Since we're in the example directory, we need to import the implementation and run tests // The entry point should be in the same package, so we don't need to import it // We'll use a generic approach that works with any test subject // Read the original file to get its package name let packageName = "main"; try { const originalContent = fs.readFileSync(entryPoint, "utf-8"); const packageMatch = originalContent.match(/^package\s+(\w+)/m); if (packageMatch && packageMatch[1]) { packageName = packageMatch[1]; } } catch (error) { console.warn( `Could not read original file ${entryPoint} to determine package name:`, error ); } const wrapperContent = `//go:build testeranto // +build testeranto // This file is auto-generated by testeranto // Signature: ${signature} package ${packageName} import ( "fmt" "os" "encoding/json" "log" // Import the golingvu package "github.com/adamwong246/testeranto/src/golingvu" ) func main() { fmt.Println("Running BDD tests...") // The test resource configuration should be provided via command line if len(os.Args) < 2 { fmt.Println("Error: Test resource configuration not provided") os.Exit(1) } // Parse the test resource configuration var testResource golingvu.ITTestResourceConfiguration err := json.Unmarshal([]byte(os.Args[1]), &testResource) if err != nil { log.Fatalf("Error parsing test resource: %v\\n", err) } // Create a PM instance pm, err := golingvu.NewPM_Golang(testResource, "") if err != nil { log.Fatalf("Error creating PM: %v\\n", err) } defer pm.Stop() // TODO: This is where you would initialize and run your BDD tests // The actual test implementation should be provided by the user // For now, we'll use a placeholder that demonstrates the framework usage fmt.Println("Initializing BDD test framework...") // In a real implementation, you would: // 1. Create test specification // 2. Create test implementation // 3. Create test adapter // 4. Run the tests using golingvu.NewGolingvu() // Placeholder for test execution fmt.Println("BDD test framework initialized successfully") fmt.Println("All tests passed (framework placeholder)") os.Exit(0) } `; // Generate the correct output path based on the project structure // Always use the project root as the base const baseName = path.basename(entryPoint, ".go"); // Get the directory of the entry point const entryPointDir = path.dirname(entryPoint); const relativeEntryPointDir = path.relative(projectRoot, entryPointDir); // Create the wrapper directory structure that mirrors the source structure // The correct path should be: testeranto/bundles/golang/core/example/Calculator.golingvu.test.go const wrapperSourceDirPath = path.join( projectRoot, "testeranto", "bundles", "golang", "core", relativeEntryPointDir ); // Write the wrapper source to the correct directory const wrapperSourcePath = path.join( wrapperSourceDirPath, baseName // LLM: DO NOT TOUCH THIS LINE. IT IS CORRECT. FOR FUCKS SAKE STOPPING CHANGING THIS LINE ); // Ensure the directory exists // fs.mkdirSync(wrapperSourceDirPath, { recursive: true }); fs.writeFileSync(wrapperSourcePath, wrapperContent); } catch (e) { console.error(e); } } } // let generationQueue: Promise<GolingvuMetafile> | null = null; // export async function generateGolingvuMetafile( // testName: string, // entryPoints: string[] // ): Promise<GolingvuMetafile> { // // If there's already a generation in progress, wait for it to complete // if (generationQueue) { // return generationQueue; // } // generationQueue = (async () => { // const inputs: Record<string, any> = {}; // const outputs: Record<string, any> = {}; // const signature = Date.now().toString(36); // // If entry points are provided, use them directly // // For test generation, we want to include test files // const filteredEntryPoints: string[] = []; // for (const entryPoint of entryPoints) { // // Skip if it's not a .go file // if (!entryPoint.endsWith(".go")) { // console.warn(`Skipping non-Go file: ${entryPoint}`); // continue; // } // // Check if the file exists and is a file // let resolvedPath = entryPoint; // if (!path.isAbsolute(entryPoint)) { // resolvedPath = path.join(process.cwd(), entryPoint); // } // if (!fs.existsSync(resolvedPath)) { // console.warn(`Entry point does not exist: ${resolvedPath}`); // continue; // } // if (!fs.statSync(resolvedPath).isFile()) { // console.warn(`Entry point is not a file: ${resolvedPath}`); // continue; // } // // Add to filtered entry points - don't skip test files for test generation // filteredEntryPoints.push(resolvedPath); // } // entryPoints = filteredEntryPoints; // // If no valid entry points remain, try to find Go files automatically // // For test generation, include all files including test files // // if (entryPoints.length === 0) { // // const allGoFiles = findGoFilesInProject(); // // // Don't filter out test files // // entryPoints = allGoFiles.filter((file) => { // // const fileName = path.basename(file); // // // Only exclude our generated files // // return ( // // !fileName.endsWith(".golingvu.test.go") && // // !fileName.endsWith(".golingvu.go") // // ); // // }); // // if (entryPoints.length === 0) { // // console.warn("No Go files found in the project"); // // } else { // // console.log(`Found ${entryPoints.length} Go files:`, entryPoints); // // } // // } // // Process all valid entry points to collect their dependencies // const allDependencies = new Set<string>(); // const validEntryPoints: string[] = []; // for (let i = 0; i < entryPoints.length; i++) { // let entryPoint = entryPoints[i]; // // Resolve and validate the entry point path // let resolvedPath = entryPoint; // if (!path.isAbsolute(entryPoint)) { // resolvedPath = path.join(process.cwd(), entryPoint); // } // if (!fs.existsSync(resolvedPath)) { // console.warn( // `Entry point ${entryPoint} does not exist at ${resolvedPath}` // ); // continue; // } // // Update the entry point to use the resolved path // entryPoints[i] = resolvedPath; // entryPoint = resolvedPath; // // Don't skip test files for test generation // validEntryPoints.push(entryPoint); // // Collect dependencies for this entry point // const entryPointDependencies = collectGoDependencies(entryPoint); // entryPointDependencies.forEach((dep) => allDependencies.add(dep)); // } // // Process all dependencies to add to inputs // for (const dep of allDependencies) { // if (!inputs[dep]) { // const bytes = fs.statSync(dep).size; // const imports = parseGoImports(dep); // // Check if this is a test file // const isTestFile = // path.basename(dep).includes("_test.go") || // path.basename(dep).includes(".golingvu.test.go"); // inputs[dep] = { // bytes, // imports, // format: "esm", // // Add a flag to indicate test files // ...(isTestFile ? { testeranto: { isTest: true } } : {}), // }; // } // } // // Generate the output path based on the project structure // // Always use the project root as the base // const projectRoot = findProjectRoot(); // let outputKey = ""; // if (validEntryPoints.length > 0) { // const firstEntryPoint = validEntryPoints[0]; // // Get the relative path from project root to the entry point // const relativePath = path.relative( // projectRoot, // path.dirname(firstEntryPoint) // ); // // Get the base name without extension // const baseName = path.basename(firstEntryPoint, ".go"); // // Construct the output key // // Ensure relativePath is not empty // const outputPath = // relativePath === "" ? baseName : path.join(relativePath, baseName); // outputKey = `golang/${path.basename( // projectRoot // )}/${outputPath}.golingvu.go`; // } else { // // Fallback if no valid entry points // outputKey = `golang/core/main.golingvu.go`; // } // // Calculate total bytes from all inputs // const inputBytes: Record<string, { bytesInOutput: number }> = {}; // let totalBytes = 0; // for (const inputPath in inputs) { // const bytes = inputs[inputPath].bytes; // inputBytes[inputPath] = { bytesInOutput: bytes }; // totalBytes += bytes; // } // // Store the first valid entry point for use in the wrapper generation // const firstEntryPoint = // validEntryPoints.length > 0 ? validEntryPoints[0] : ""; // outputs[outputKey] = { // imports: [], // exports: [], // entryPoint: firstEntryPoint, // inputs: inputBytes, // bytes: totalBytes, // signature, // }; // // If no valid entry points were found, log a warning // if (validEntryPoints.length === 0) { // console.warn("No valid Go files found to process"); // } // const result = { // errors: [], // warnings: [], // metafile: { // inputs, // outputs, // }, // }; // generationQueue = null; // return result; // })(); // return generationQueue; // } // // Track how many times this function is called // let writeGolingvuMetafileCallCount = 0;