UNPKG

agentic-qe

Version:

Agentic Quality Engineering Fleet System - AI-driven quality management platform

163 lines 5.98 kB
"use strict"; /** * Test Mutate Command * Perform mutation testing to assess test quality */ Object.defineProperty(exports, "__esModule", { value: true }); exports.mutate = void 0; const Logger_1 = require("../../../utils/Logger"); async function mutate(options) { const logger = Logger_1.Logger.getInstance(); try { // Generate mutants from source code const mutants = generateMutants(options.sourceCode); // Simulate test execution against each mutant const results = await testMutants(mutants, options.testSuite); // Calculate mutation score const killedMutants = results.filter(m => m.killed).length; const mutationScore = mutants.length > 0 ? (killedMutants / mutants.length) * 100 : 0; // Identify surviving mutants const survivingMutants = results.filter(m => !m.killed); // Generate test suggestions const testSuggestions = generateTestSuggestions(survivingMutants); logger.info(`Mutation testing: ${killedMutants}/${mutants.length} mutants killed (${mutationScore.toFixed(1)}%)`); return { success: true, mutants: results, mutationScore: parseFloat(mutationScore.toFixed(2)), survivingMutants, testSuggestions }; } catch (error) { logger.error('Failed to perform mutation testing:', error); throw error; } } exports.mutate = mutate; function generateMutants(sourceCode) { const mutants = []; const lines = sourceCode.split('\n'); let mutantId = 0; for (let lineNum = 0; lineNum < lines.length; lineNum++) { const line = lines[lineNum]; // Arithmetic operator mutations const arithmeticMutations = [ { from: '+', to: '-', type: 'arithmetic' }, { from: '-', to: '+', type: 'arithmetic' }, { from: '*', to: '/', type: 'arithmetic' }, { from: '/', to: '*', type: 'arithmetic' } ]; for (const mutation of arithmeticMutations) { if (line.includes(mutation.from)) { mutants.push({ id: mutantId++, type: mutation.type, original: mutation.from, mutated: mutation.to, line: lineNum + 1, killed: false }); } } // Comparison operator mutations const comparisonMutations = [ { from: '>', to: '<', type: 'comparison' }, { from: '<', to: '>', type: 'comparison' }, { from: '>=', to: '<=', type: 'comparison' }, { from: '<=', to: '>=', type: 'comparison' }, { from: '==', to: '!=', type: 'comparison' }, { from: '!=', to: '==', type: 'comparison' } ]; for (const mutation of comparisonMutations) { if (line.includes(mutation.from)) { mutants.push({ id: mutantId++, type: mutation.type, original: mutation.from, mutated: mutation.to, line: lineNum + 1, killed: false }); } } // Return value mutations if (line.includes('return')) { mutants.push({ id: mutantId++, type: 'return', original: 'return', mutated: 'return null', line: lineNum + 1, killed: false }); } // Conditional mutations if (line.includes('if')) { mutants.push({ id: mutantId++, type: 'conditional', original: 'if', mutated: 'if (true)', line: lineNum + 1, killed: false }); } } return mutants; } async function testMutants(mutants, testSuite) { // Simulate test execution // In a real implementation, this would actually run tests against each mutant return mutants.map(mutant => { // Simulate 70% kill rate const killed = Math.random() > 0.3; return { ...mutant, killed, killedBy: killed ? testSuite : undefined }; }); } function generateTestSuggestions(survivingMutants) { const suggestions = []; const mutantsByType = {}; // Group surviving mutants by type for (const mutant of survivingMutants) { if (!mutantsByType[mutant.type]) { mutantsByType[mutant.type] = []; } mutantsByType[mutant.type].push(mutant); } // Generate suggestions for (const [type, mutants] of Object.entries(mutantsByType)) { if (type === 'arithmetic') { suggestions.push(`Add tests for edge cases in arithmetic operations (${mutants.length} surviving mutants)`); } else if (type === 'comparison') { suggestions.push(`Test boundary conditions more thoroughly (${mutants.length} comparison mutants survived)`); } else if (type === 'return') { suggestions.push(`Add tests for return value validation (${mutants.length} return mutants survived)`); } else if (type === 'conditional') { suggestions.push(`Test both branches of conditionals (${mutants.length} conditional mutants survived)`); } } // Add specific line suggestions const linesByType = survivingMutants.reduce((acc, m) => { if (!acc[m.type]) acc[m.type] = []; acc[m.type].push(m.line); return acc; }, {}); for (const [type, lines] of Object.entries(linesByType)) { if (lines.length > 0) { suggestions.push(`Focus on lines ${lines.join(', ')} for ${type} coverage`); } } return suggestions; } //# sourceMappingURL=mutate.js.map