| #!/usr/bin/env node |
|
|
| |
| |
| |
| |
|
|
| const fs = require('fs'); |
| const path = require('path'); |
|
|
| |
| const colors = { |
| reset: '\x1b[0m', |
| bright: '\x1b[1m', |
| green: '\x1b[32m', |
| red: '\x1b[31m', |
| yellow: '\x1b[33m', |
| blue: '\x1b[34m', |
| cyan: '\x1b[36m' |
| }; |
|
|
| function log(message, color = 'reset') { |
| console.log(`${colors[color]}${message}${colors.reset}`); |
| } |
|
|
| function logSuccess(message) { |
| log(`✅ ${message}`, 'green'); |
| } |
|
|
| function logError(message) { |
| log(`❌ ${message}`, 'red'); |
| } |
|
|
| function logInfo(message) { |
| log(`ℹ️ ${message}`, 'cyan'); |
| } |
|
|
| function logWarning(message) { |
| log(`⚠️ ${message}`, 'yellow'); |
| } |
|
|
| function logHeader(message) { |
| log(`\n${'='.repeat(60)}`, 'blue'); |
| log(message, 'bright'); |
| log('='.repeat(60), 'blue'); |
| } |
|
|
| |
| const tests = { |
| passed: 0, |
| failed: 0, |
| total: 0 |
| }; |
|
|
| function runTest(testName, testFn) { |
| tests.total++; |
| try { |
| testFn(); |
| tests.passed++; |
| logSuccess(`${testName}`); |
| return true; |
| } catch (error) { |
| tests.failed++; |
| logError(`${testName}`); |
| logError(` Error: ${error.message}`); |
| return false; |
| } |
| } |
|
|
| |
| function testFilesExist() { |
| logHeader('Test 1: Checking Required Files'); |
| |
| const requiredFiles = [ |
| 'generate-academic-report.js', |
| 'sample-config.json', |
| 'package.json', |
| 'README.md', |
| 'QUICKSTART.md', |
| 'index.html' |
| ]; |
| |
| requiredFiles.forEach(file => { |
| runTest(`File exists: ${file}`, () => { |
| if (!fs.existsSync(file)) { |
| throw new Error(`File not found: ${file}`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function testSampleConfig() { |
| logHeader('Test 2: Validating Sample Configuration'); |
| |
| runTest('sample-config.json is valid JSON', () => { |
| const content = fs.readFileSync('sample-config.json', 'utf8'); |
| const config = JSON.parse(content); |
| |
| |
| const requiredFields = [ |
| 'studentName', 'studentId', 'department', 'university', |
| 'courseTitle', 'courseCode', 'teacherName', 'reportTitle', 'topic' |
| ]; |
| |
| requiredFields.forEach(field => { |
| if (!config[field]) { |
| throw new Error(`Missing required field: ${field}`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function testPackageJson() { |
| logHeader('Test 3: Validating package.json'); |
| |
| runTest('package.json is valid', () => { |
| const content = fs.readFileSync('package.json', 'utf8'); |
| const pkg = JSON.parse(content); |
| |
| if (!pkg.name) throw new Error('Missing package name'); |
| if (!pkg.version) throw new Error('Missing version'); |
| if (!pkg.dependencies) throw new Error('Missing dependencies'); |
| if (!pkg.dependencies.docx) throw new Error('Missing docx dependency'); |
| }); |
| } |
|
|
| |
| function testScriptPermissions() { |
| logHeader('Test 4: Checking Script Permissions'); |
| |
| runTest('generate-academic-report.js is readable', () => { |
| try { |
| fs.accessSync('generate-academic-report.js', fs.constants.R_OK); |
| } catch (err) { |
| throw new Error('Script is not readable'); |
| } |
| }); |
| } |
|
|
| |
| function testConfigurationOptions() { |
| logHeader('Test 5: Testing Configuration Options'); |
| |
| const testConfigs = [ |
| { |
| name: 'Minimum config', |
| config: { |
| studentName: 'Test Student', |
| studentId: 'TEST-001', |
| department: 'Test Dept', |
| university: 'Test University', |
| courseTitle: 'Test Course', |
| courseCode: 'TST 101', |
| teacherName: 'Test Teacher', |
| reportTitle: 'Test Report', |
| topic: 'Test Topic' |
| } |
| }, |
| { |
| name: 'Full config with all options', |
| config: { |
| studentName: 'Test Student', |
| studentId: 'TEST-001', |
| department: 'Test Dept', |
| university: 'Test University', |
| courseTitle: 'Test Course', |
| courseCode: 'TST 101', |
| teacherName: 'Test Teacher', |
| teacherDesignation: 'Professor', |
| submissionDate: '2026-02-14', |
| reportType: 'assignment', |
| reportTitle: 'Test Report', |
| topic: 'Test Topic', |
| includeAbstract: true, |
| includeTOC: true, |
| includeReferences: true, |
| pageNumbers: true, |
| fontFamily: 'Times New Roman', |
| fontSize: '12', |
| lineSpacing: '1.5' |
| } |
| } |
| ]; |
| |
| testConfigs.forEach(({ name, config }) => { |
| runTest(`Config validation: ${name}`, () => { |
| const jsonStr = JSON.stringify(config, null, 2); |
| JSON.parse(jsonStr); |
| }); |
| }); |
| } |
|
|
| |
| function testReportTypes() { |
| logHeader('Test 6: Testing Report Types'); |
| |
| const reportTypes = [ |
| 'assignment', |
| 'project', |
| 'thesis', |
| 'research', |
| 'case-study', |
| 'lab-report' |
| ]; |
| |
| reportTypes.forEach(type => { |
| runTest(`Report type: ${type}`, () => { |
| |
| if (typeof type !== 'string') { |
| throw new Error(`Invalid report type: ${type}`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function testFontFamilies() { |
| logHeader('Test 7: Testing Font Families'); |
| |
| const fontFamilies = [ |
| 'Times New Roman', |
| 'Arial', |
| 'Calibri', |
| 'Georgia' |
| ]; |
| |
| fontFamilies.forEach(font => { |
| runTest(`Font family: ${font}`, () => { |
| if (typeof font !== 'string' || font.length === 0) { |
| throw new Error(`Invalid font family: ${font}`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function testDateFormats() { |
| logHeader('Test 8: Testing Date Formats'); |
| |
| const testDates = [ |
| { date: '2026-02-14', valid: true, name: 'ISO format (YYYY-MM-DD)' }, |
| { date: '2026-12-31', valid: true, name: 'End of year' }, |
| { date: '2026-01-01', valid: true, name: 'Start of year' } |
| ]; |
| |
| testDates.forEach(({ date, valid, name }) => { |
| runTest(`Date format: ${name}`, () => { |
| const d = new Date(date); |
| if (isNaN(d.getTime()) && valid) { |
| throw new Error(`Invalid date: ${date}`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function testOutputDirectory() { |
| logHeader('Test 9: Checking Output Directory'); |
| |
| runTest('Output directory structure', () => { |
| const outputDir = '/mnt/user-data/outputs'; |
| |
| const isValidPath = outputDir.startsWith('/'); |
| if (!isValidPath) { |
| throw new Error('Invalid output path'); |
| } |
| }); |
| } |
|
|
| |
| function testDocumentation() { |
| logHeader('Test 10: Checking Documentation'); |
| |
| const docs = [ |
| { file: 'README.md', minLength: 1000 }, |
| { file: 'QUICKSTART.md', minLength: 500 } |
| ]; |
| |
| docs.forEach(({ file, minLength }) => { |
| runTest(`Documentation: ${file}`, () => { |
| const content = fs.readFileSync(file, 'utf8'); |
| if (content.length < minLength) { |
| throw new Error(`${file} seems incomplete (${content.length} chars)`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function testHTMLInterface() { |
| logHeader('Test 11: Validating HTML Interface'); |
| |
| runTest('index.html structure', () => { |
| const content = fs.readFileSync('index.html', 'utf8'); |
| |
| |
| const requiredElements = [ |
| '<form', |
| 'studentName', |
| 'studentId', |
| 'department', |
| 'university', |
| 'courseTitle', |
| 'reportTitle', |
| 'submit' |
| ]; |
| |
| requiredElements.forEach(element => { |
| if (!content.includes(element)) { |
| throw new Error(`Missing element in HTML: ${element}`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function testConfigFieldTypes() { |
| logHeader('Test 12: Testing Configuration Field Types'); |
| |
| runTest('String fields validation', () => { |
| const stringFields = [ |
| 'studentName', 'studentId', 'department', 'university', |
| 'courseTitle', 'courseCode', 'teacherName', 'reportTitle', 'topic' |
| ]; |
| |
| stringFields.forEach(field => { |
| const value = 'Test Value'; |
| if (typeof value !== 'string') { |
| throw new Error(`Field ${field} should be string`); |
| } |
| }); |
| }); |
| |
| runTest('Boolean fields validation', () => { |
| const booleanFields = [ |
| 'includeAbstract', 'includeTOC', 'includeReferences', 'pageNumbers' |
| ]; |
| |
| booleanFields.forEach(field => { |
| const value = true; |
| if (typeof value !== 'boolean') { |
| throw new Error(`Field ${field} should be boolean`); |
| } |
| }); |
| }); |
| } |
|
|
| |
| function runAllTests() { |
| console.clear(); |
| logHeader('🎓 Smart Academic Report Generator - Test Suite'); |
| logInfo('Running comprehensive tests...\n'); |
| |
| |
| testFilesExist(); |
| testSampleConfig(); |
| testPackageJson(); |
| testScriptPermissions(); |
| testConfigurationOptions(); |
| testReportTypes(); |
| testFontFamilies(); |
| testDateFormats(); |
| testOutputDirectory(); |
| testDocumentation(); |
| testHTMLInterface(); |
| testConfigFieldTypes(); |
| |
| |
| logHeader('Test Summary'); |
| log(`\nTotal Tests: ${tests.total}`, 'bright'); |
| logSuccess(`Passed: ${tests.passed}`); |
| |
| if (tests.failed > 0) { |
| logError(`Failed: ${tests.failed}`); |
| log(`\nSuccess Rate: ${((tests.passed / tests.total) * 100).toFixed(1)}%`, 'yellow'); |
| process.exit(1); |
| } else { |
| log('\n🎉 All tests passed! System is ready to use.', 'green'); |
| log('\nTo generate a report, run:', 'cyan'); |
| log(' node generate-academic-report.js --config sample-config.json\n', 'bright'); |
| process.exit(0); |
| } |
| } |
|
|
| |
| if (require.main === module) { |
| runAllTests(); |
| } |
|
|
| module.exports = { runAllTests }; |
|
|