UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

290 lines (243 loc) 10.8 kB
/** * @file Unit tests for issue factory utility * @description Tests issue creation, validation, and standardization across analysis modules */ const { createIssue, createSecurityIssue, createPerformanceIssue, createBugIssue, validateIssue, normalizeIssue, mergeIssues } = require('./issueFactory'); const qtests = require('qtests'); /** * Test runner for issue factory */ async function runTests() { console.log('=== Testing Issue Factory Utilities ==='); const results = { total: 0, passed: 0 }; // Test createIssue function results.total++; try { const issueData = { type: 'test_issue', severity: 'MEDIUM', category: 'Testing', file: '/path/to/file.js', line: 42, column: 10, summary: 'Test issue summary', description: 'Detailed description of the test issue', recommendation: 'Fix the test issue' }; const issue = createIssue(issueData); qtests.assert(typeof issue === 'object', 'createIssue should return object'); qtests.assert(issue.type === 'test_issue', 'Issue should have correct type'); qtests.assert(issue.severity === 'MEDIUM', 'Issue should have correct severity'); qtests.assert(issue.category === 'Testing', 'Issue should have correct category'); qtests.assert(issue.file === '/path/to/file.js', 'Issue should have correct file path'); qtests.assert(issue.line === 42, 'Issue should have correct line number'); qtests.assert(typeof issue.id === 'string', 'Issue should have generated ID'); qtests.assert(typeof issue.timestamp === 'number', 'Issue should have timestamp'); console.log('✓ createIssue correctly creates standardized issue objects'); results.passed++; } catch (error) { console.log(`✗ createIssue test failed: ${error.message}`); } // Test createSecurityIssue function results.total++; try { const securityData = { type: 'xss_vulnerability', confidence: 'HIGH', cwe: 'CWE-79', file: '/path/to/vulnerable.js', line: 15, pattern: 'innerHTML assignment', context: 'user input directly assigned to innerHTML' }; const securityIssue = createSecurityIssue(securityData); qtests.assert(securityIssue.category === 'Security', 'Security issue should have Security category'); qtests.assert(securityIssue.confidence === 'HIGH', 'Security issue should preserve confidence'); qtests.assert(securityIssue.cwe === 'CWE-79', 'Security issue should preserve CWE identifier'); qtests.assert(securityIssue.pattern === 'innerHTML assignment', 'Security issue should preserve pattern'); qtests.assert(typeof securityIssue.riskLevel === 'string', 'Security issue should calculate risk level'); console.log('✓ createSecurityIssue correctly creates security-specific issues'); results.passed++; } catch (error) { console.log(`✗ createSecurityIssue test failed: ${error.message}`); } // Test createPerformanceIssue function results.total++; try { const performanceData = { type: 'o_n_squared', impact: 8, effort: 3, file: '/path/to/slow.js', line: 25, algorithm: 'nested loop', complexity: 'O(n²)', suggestion: 'Use Map for O(1) lookup' }; const performanceIssue = createPerformanceIssue(performanceData); qtests.assert(performanceIssue.category === 'Performance', 'Performance issue should have Performance category'); qtests.assert(performanceIssue.impact === 8, 'Performance issue should preserve impact score'); qtests.assert(performanceIssue.effort === 3, 'Performance issue should preserve effort level'); qtests.assert(performanceIssue.algorithm === 'nested loop', 'Performance issue should preserve algorithm type'); qtests.assert(performanceIssue.complexity === 'O(n²)', 'Performance issue should preserve complexity notation'); console.log('✓ createPerformanceIssue correctly creates performance-specific issues'); results.passed++; } catch (error) { console.log(`✗ createPerformanceIssue test failed: ${error.message}`); } // Test createBugIssue function results.total++; try { const bugData = { type: 'null_reference', severity: 'HIGH', file: '/path/to/buggy.js', line: 33, variable: 'user', operator: '.', errorType: 'TypeError', fix: 'Add null check before property access' }; const bugIssue = createBugIssue(bugData); qtests.assert(bugIssue.category === 'Bug', 'Bug issue should have Bug category'); qtests.assert(bugIssue.variable === 'user', 'Bug issue should preserve variable name'); qtests.assert(bugIssue.operator === '.', 'Bug issue should preserve operator'); qtests.assert(bugIssue.errorType === 'TypeError', 'Bug issue should preserve error type'); qtests.assert(bugIssue.fix === 'Add null check before property access', 'Bug issue should preserve fix suggestion'); console.log('✓ createBugIssue correctly creates bug-specific issues'); results.passed++; } catch (error) { console.log(`✗ createBugIssue test failed: ${error.message}`); } // Test validateIssue function results.total++; try { const validIssue = { type: 'test_issue', severity: 'MEDIUM', category: 'Testing', file: '/path/to/file.js', summary: 'Valid issue' }; const invalidIssue = { // Missing required fields type: 'incomplete_issue' }; const malformedIssue = { type: 'malformed', severity: 'INVALID_SEVERITY', category: 'Testing', file: '/path/to/file.js', line: 'not_a_number' }; const validResult = validateIssue(validIssue); const invalidResult = validateIssue(invalidIssue); const malformedResult = validateIssue(malformedIssue); qtests.assert(validResult.isValid === true, 'validateIssue should accept valid issues'); qtests.assert(validResult.errors.length === 0, 'Valid issues should have no errors'); qtests.assert(invalidResult.isValid === false, 'validateIssue should reject incomplete issues'); qtests.assert(invalidResult.errors.length > 0, 'Invalid issues should have errors'); qtests.assert(malformedResult.isValid === false, 'validateIssue should reject malformed issues'); qtests.assert(malformedResult.errors.some(e => e.includes('severity')), 'Should validate severity values'); console.log('✓ validateIssue correctly validates issue structure and content'); results.passed++; } catch (error) { console.log(`✗ validateIssue test failed: ${error.message}`); } // Test normalizeIssue function results.total++; try { const unnormalizedIssue = { type: 'Test_Issue', severity: 'medium', category: 'TESTING', file: '\\path\\to\\file.js', summary: ' Extra whitespace ', description: '\n\nMultiple newlines\n\n' }; const normalizedIssue = normalizeIssue(unnormalizedIssue); qtests.assert(normalizedIssue.type === 'test_issue', 'Should normalize type to lowercase with underscores'); qtests.assert(normalizedIssue.severity === 'MEDIUM', 'Should normalize severity to uppercase'); qtests.assert(normalizedIssue.category === 'Testing', 'Should normalize category to title case'); qtests.assert(normalizedIssue.file.includes('/'), 'Should normalize file path separators'); qtests.assert(normalizedIssue.summary === 'Extra whitespace', 'Should trim whitespace from summary'); qtests.assert(!normalizedIssue.description.startsWith('\n'), 'Should normalize description formatting'); console.log('✓ normalizeIssue correctly normalizes issue properties'); results.passed++; } catch (error) { console.log(`✗ normalizeIssue test failed: ${error.message}`); } // Test mergeIssues function results.total++; try { const issues1 = [ { id: '1', type: 'issue_a', severity: 'HIGH' }, { id: '2', type: 'issue_b', severity: 'MEDIUM' } ]; const issues2 = [ { id: '3', type: 'issue_c', severity: 'LOW' }, { id: '4', type: 'issue_d', severity: 'HIGH' } ]; const issues3 = [ { id: '5', type: 'issue_e', severity: 'MEDIUM' } ]; const mergedIssues = mergeIssues([issues1, issues2, issues3]); qtests.assert(Array.isArray(mergedIssues), 'mergeIssues should return array'); qtests.assert(mergedIssues.length === 5, 'Should merge all issues from all arrays'); qtests.assert(mergedIssues.every(issue => typeof issue.id === 'string'), 'All merged issues should have IDs'); // Check that issues are sorted by severity (HIGH first) const highSeverityIssues = mergedIssues.filter(issue => issue.severity === 'HIGH'); qtests.assert(highSeverityIssues.length === 2, 'Should preserve all HIGH severity issues'); console.log('✓ mergeIssues correctly merges and sorts issue arrays'); results.passed++; } catch (error) { console.log(`✗ mergeIssues test failed: ${error.message}`); } // Test issue ID generation uniqueness results.total++; try { const issue1 = createIssue({ type: 'test', severity: 'LOW', category: 'Test' }); const issue2 = createIssue({ type: 'test', severity: 'LOW', category: 'Test' }); const issue3 = createIssue({ type: 'test', severity: 'LOW', category: 'Test' }); qtests.assert(issue1.id !== issue2.id, 'Issue IDs should be unique'); qtests.assert(issue1.id !== issue3.id, 'Issue IDs should be unique'); qtests.assert(issue2.id !== issue3.id, 'Issue IDs should be unique'); // Test that IDs are deterministic for same content const contentBasedIssue1 = createIssue({ type: 'deterministic', file: '/same/file.js', line: 10, severity: 'MEDIUM', category: 'Test' }); const contentBasedIssue2 = createIssue({ type: 'deterministic', file: '/same/file.js', line: 10, severity: 'MEDIUM', category: 'Test' }); // IDs should be the same for identical content (to avoid duplicates) qtests.assert(contentBasedIssue1.id === contentBasedIssue2.id, 'Issues with identical content should have same ID'); console.log('✓ Issue ID generation works correctly for uniqueness and deduplication'); results.passed++; } catch (error) { console.log(`✗ Issue ID generation test failed: ${error.message}`); } console.log(`=== Issue Factory Test Results ===`); console.log(`Tests passed: ${results.passed}/${results.total}`); console.log(`Success rate: ${((results.passed / results.total) * 100).toFixed(1)}%`); return results; } module.exports = { runTests };