UNPKG

agentsqripts

Version:

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

341 lines (273 loc) 11.3 kB
/** * @file Unit tests for scalability file analyzer * @description Tests file-level scalability analysis and issue detection */ const { analyzeFileScalability } = require('./scalabilityFileAnalyzer'); const qtests = require('qtests'); const fs = require('fs'); const path = require('path'); /** * Test runner for scalability file analyzer */ async function runTests() { console.log('=== Testing Scalability File Analyzer ==='); const results = { total: 0, passed: 0 }; // Test analysis of file with blocking sync operations results.total++; try { const tempFile = path.join(__dirname, 'temp-sync-test.js'); const syncCode = ` const fs = require('fs'); function processFiles() { // Blocking sync operations - scalability issue const data1 = fs.readFileSync('./file1.txt'); const data2 = fs.readFileSync('./file2.txt'); const data3 = fs.readFileSync('./file3.txt'); return data1 + data2 + data3; } // More sync operations const config = JSON.parse(fs.readFileSync('./config.json')); `; fs.writeFileSync(tempFile, syncCode); const analysis = await analyzeFileScalability(tempFile); qtests.assert(typeof analysis === 'object', 'analyzeFileScalability should return object'); qtests.assert(typeof analysis.summary === 'object', 'Analysis should include summary'); qtests.assert(Array.isArray(analysis.issues), 'Analysis should include issues array'); qtests.assert(analysis.issues.length > 0, 'Should detect sync I/O scalability issues'); qtests.assert(analysis.issues.some(issue => issue.type.includes('sync')), 'Should identify sync operations'); fs.unlinkSync(tempFile); console.log('✓ analyzeFileScalability correctly detects blocking sync operations'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability sync operations test failed: ${error.message}`); } // Test analysis of file with N+1 query patterns results.total++; try { const tempFile = path.join(__dirname, 'temp-n-plus-one-test.js'); const nPlusOneCode = ` async function getUsersWithPosts() { const users = await db.query('SELECT * FROM users'); // N+1 query pattern - scalability issue for (const user of users) { const posts = await db.query('SELECT * FROM posts WHERE user_id = ?', [user.id]); user.posts = posts; } return users; } async function getCommentsForPosts(posts) { // Another N+1 pattern for (const post of posts) { post.comments = await db.query('SELECT * FROM comments WHERE post_id = ?', [post.id]); } } `; fs.writeFileSync(tempFile, nPlusOneCode); const analysis = await analyzeFileScalability(tempFile); qtests.assert(analysis.issues.length > 0, 'Should detect N+1 query patterns'); qtests.assert(analysis.issues.some(issue => issue.type.includes('n_plus_one') || issue.category === 'Database'), 'Should identify database scalability issues'); fs.unlinkSync(tempFile); console.log('✓ analyzeFileScalability correctly detects N+1 query patterns'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability N+1 patterns test failed: ${error.message}`); } // Test analysis of file with memory growth issues results.total++; try { const tempFile = path.join(__dirname, 'temp-memory-test.js'); const memoryCode = ` let globalCache = {}; let unboundedArray = []; function cacheData(key, value) { // Unbounded cache growth - scalability issue globalCache[key] = value; } function addToArray(item) { // Unbounded array growth unboundedArray.push(item); } setInterval(() => { // Memory leak through closure const largeObject = new Array(1000000).fill('data'); addToArray(largeObject); }, 1000); `; fs.writeFileSync(tempFile, memoryCode); const analysis = await analyzeFileScalability(tempFile); qtests.assert(analysis.issues.some(issue => issue.type.includes('memory') || issue.type.includes('unbounded') || issue.category === 'Memory' ), 'Should detect memory growth scalability issues'); fs.unlinkSync(tempFile); console.log('✓ analyzeFileScalability correctly detects memory growth issues'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability memory growth test failed: ${error.message}`); } // Test analysis of file with heavy computation loops results.total++; try { const tempFile = path.join(__dirname, 'temp-computation-test.js'); const computationCode = ` function processLargeDataset(data) { // Heavy nested loops - scalability issue for (let i = 0; i < data.length; i++) { for (let j = 0; j < data.length; j++) { for (let k = 0; k < data.length; k++) { // O(n³) computation if (data[i] === data[j] && data[j] === data[k]) { console.log('Match found'); } } } } } function inefficientSearch(array, target) { // Inefficient linear search in loop for (let i = 0; i < 1000; i++) { const found = array.find(item => item.id === target.id); if (found) return found; } } `; fs.writeFileSync(tempFile, computationCode); const analysis = await analyzeFileScalability(tempFile); qtests.assert(analysis.issues.some(issue => issue.type.includes('loop') || issue.type.includes('computation') || issue.category === 'Algorithm' ), 'Should detect heavy computation scalability issues'); fs.unlinkSync(tempFile); console.log('✓ analyzeFileScalability correctly detects heavy computation patterns'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability computation test failed: ${error.message}`); } // Test analysis of file with event loop blocking results.total++; try { const tempFile = path.join(__dirname, 'temp-blocking-test.js'); const blockingCode = ` function blockingOperation() { // CPU-intensive blocking operation const start = Date.now(); while (Date.now() - start < 5000) { // Blocking the event loop for 5 seconds Math.random(); } } function cryptoBlocking() { const crypto = require('crypto'); // Synchronous crypto operations block event loop for (let i = 0; i < 1000; i++) { crypto.pbkdf2Sync('password', 'salt', 10000, 64, 'sha512'); } } `; fs.writeFileSync(tempFile, blockingCode); const analysis = await analyzeFileScalability(tempFile); qtests.assert(analysis.issues.some(issue => issue.type.includes('blocking') || issue.type.includes('event_loop') || issue.category === 'Event Loop' ), 'Should detect event loop blocking issues'); fs.unlinkSync(tempFile); console.log('✓ analyzeFileScalability correctly detects event loop blocking'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability event loop blocking test failed: ${error.message}`); } // Test analysis of file with global variable issues results.total++; try { const tempFile = path.join(__dirname, 'temp-globals-test.js'); const globalsCode = ` // Global state issues - scalability concerns var globalCounter = 0; let sharedState = {}; const globalConnections = []; function incrementGlobal() { globalCounter++; // Race condition potential } function addConnection(conn) { globalConnections.push(conn); // Unbounded growth } window.myGlobalVar = 'browser global'; // Browser global `; fs.writeFileSync(tempFile, globalsCode); const analysis = await analyzeFileScalability(tempFile); qtests.assert(analysis.issues.some(issue => issue.type.includes('global') || issue.category === 'Global State' ), 'Should detect global variable scalability issues'); fs.unlinkSync(tempFile); console.log('✓ analyzeFileScalability correctly detects global variable issues'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability global variables test failed: ${error.message}`); } // Test analysis of clean, scalable file results.total++; try { const tempFile = path.join(__dirname, 'temp-clean-test.js'); const cleanCode = ` // Well-structured, scalable code const { promisify } = require('util'); const fs = require('fs'); const readFile = promisify(fs.readFile); async function processFilesEfficiently() { try { // Async operations for scalability const files = await Promise.all([ readFile('./file1.txt'), readFile('./file2.txt'), readFile('./file3.txt') ]); return files.join(''); } catch (error) { console.error('Error processing files:', error); return null; } } // Efficient data processing with streaming function processDataStream(stream) { return new Promise((resolve, reject) => { let result = ''; stream.on('data', chunk => result += chunk); stream.on('end', () => resolve(result)); stream.on('error', reject); }); } `; fs.writeFileSync(tempFile, cleanCode); const analysis = await analyzeFileScalability(tempFile); qtests.assert(typeof analysis === 'object', 'Should analyze clean code successfully'); qtests.assert(analysis.summary.totalIssues === 0 || analysis.summary.totalIssues < 2, 'Clean code should have minimal scalability issues'); fs.unlinkSync(tempFile); console.log('✓ analyzeFileScalability correctly identifies clean, scalable code'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability clean code test failed: ${error.message}`); } // Test error handling for non-existent file results.total++; try { const analysis = await analyzeFileScalability('/non/existent/file.js'); qtests.assert(analysis.summary.totalIssues === 0, 'Should handle non-existent files gracefully'); qtests.assert(Array.isArray(analysis.issues), 'Should return empty issues array for non-existent files'); console.log('✓ analyzeFileScalability handles non-existent files gracefully'); results.passed++; } catch (error) { console.log(`✗ analyzeFileScalability error handling test failed: ${error.message}`); } console.log(`=== Scalability File Analyzer 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 };