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
JavaScript
/**
* @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 };