Skip to main content
Glama
edge-cases.test.js16.4 kB
import { describe, test, expect, beforeEach, afterEach } from '@jest/globals'; import { AudioInspector } from '../lib/inspector.js'; import { promises as fs } from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); describe('Audio Inspector Edge Cases and Error Conditions', () => { let inspector; let testDir; beforeEach(async () => { inspector = new AudioInspector(); testDir = path.join(__dirname, 'edge-cases'); await fs.mkdir(testDir, { recursive: true }); }); afterEach(async () => { await fs.rmdir(testDir, { recursive: true }).catch(() => {}); }); describe('File System Edge Cases', () => { test('should handle zero-byte files', async () => { const emptyFile = path.join(testDir, 'empty.mp3'); await fs.writeFile(emptyFile, ''); const result = await inspector.analyzeFile(emptyFile); expect(result).toBeDefined(); expect(result.file.size).toBe(0); if (result.error) { expect(result.message).toBeDefined(); } }); test('should handle files with only metadata headers', async () => { const headerOnlyFile = path.join(testDir, 'header-only.mp3'); // Create file with just ID3 header but no audio data await fs.writeFile(headerOnlyFile, 'ID3\x03\x00\x00\x00\x00\x00\x00\x00'); const result = await inspector.analyzeFile(headerOnlyFile); expect(result).toBeDefined(); expect(result.file.size).toBeGreaterThan(0); }); test('should handle extremely long file paths', async () => { // Create a very long path (but within OS limits) let longPath = testDir; const maxSegments = 10; // Reasonable limit for testing for (let i = 0; i < maxSegments; i++) { const segment = `very-long-directory-name-segment-${i}`.repeat(3); longPath = path.join(longPath, segment); await fs.mkdir(longPath, { recursive: true }); } const longFileName = 'extremely-long-audio-file-name-for-testing-edge-cases.mp3'; const longFilePath = path.join(longPath, longFileName); await fs.writeFile(longFilePath, 'long path test content'); const result = await inspector.analyzeFile(longFilePath); expect(result).toBeDefined(); expect(result.file.path).toContain(longFileName); }); test('should handle files with special characters in names', async () => { const specialNames = [ 'file@with#special$chars%.mp3', 'file[with]brackets.mp3', 'file{with}braces.mp3', 'file(with)parentheses.mp3' ]; for (const fileName of specialNames) { try { const filePath = path.join(testDir, fileName); await fs.writeFile(filePath, 'special chars test'); const result = await inspector.analyzeFile(filePath); expect(result).toBeDefined(); expect(result.file.name).toBe(fileName); } catch (error) { // Some special characters might not be supported on all filesystems console.warn(`Special character test skipped for ${fileName}: ${error.message}`); } } }); test('should handle symbolic links appropriately', async () => { const originalFile = path.join(testDir, 'original.mp3'); const symlinkFile = path.join(testDir, 'symlink.mp3'); await fs.writeFile(originalFile, 'original file content'); try { await fs.symlink(originalFile, symlinkFile); const originalResult = await inspector.analyzeFile(originalFile); const symlinkResult = await inspector.analyzeFile(symlinkFile); expect(originalResult).toBeDefined(); expect(symlinkResult).toBeDefined(); // Both should have the same content size expect(symlinkResult.file.size).toBe(originalResult.file.size); } catch (error) { // Symbolic links might not be supported on all platforms console.warn(`Symbolic link test skipped: ${error.message}`); } }); }); describe('Malformed Audio Data', () => { test('should handle truncated audio files', async () => { const truncatedFile = path.join(testDir, 'truncated.mp3'); // Create file that starts like MP3 but is truncated await fs.writeFile(truncatedFile, 'ID3\x03\x00\x00\x00\x00\x00\x10\x00TRUNC'); const result = await inspector.analyzeFile(truncatedFile); expect(result).toBeDefined(); // Should handle gracefully, either with error or fallback if (result.error) { expect(result.message).toContain('ID3'); } else { expect(result.source).toBeDefined(); } }); test('should handle files with wrong extensions', async () => { const wrongExtensions = [ { name: 'text-as-audio.mp3', content: 'This is actually a text file' }, { name: 'binary-as-audio.wav', content: '\x00\x01\x02\x03\x04\x05\x06\x07' }, { name: 'html-as-audio.flac', content: '<html><body>Not audio</body></html>' } ]; for (const testCase of wrongExtensions) { const filePath = path.join(testDir, testCase.name); await fs.writeFile(filePath, testCase.content); const result = await inspector.analyzeFile(filePath); expect(result).toBeDefined(); // Should attempt analysis but likely fail or fallback expect(result.file.name).toBe(testCase.name); } }); test('should handle corrupted metadata tags', async () => { const corruptedFile = path.join(testDir, 'corrupted-metadata.mp3'); // Create file with corrupted ID3 tag structure const corruptedData = 'ID3\x04\x00\x00\x00\x00\x00\xFF\xFF' + '\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' + 'corrupted tag data'; await fs.writeFile(corruptedFile, corruptedData); const result = await inspector.analyzeFile(corruptedFile); expect(result).toBeDefined(); // Should handle corrupted metadata gracefully if (!result.error) { expect(result.tags).toBeDefined(); } }); test('should handle extremely large metadata blocks', async () => { const largeMetadataFile = path.join(testDir, 'large-metadata.mp3'); // Create file with very large metadata block const largeMetadata = 'A'.repeat(1024 * 1024); // 1MB of metadata const fileContent = 'ID3\x03\x00\x00\x00\x00\x00\x00' + largeMetadata; await fs.writeFile(largeMetadataFile, fileContent); const result = await inspector.analyzeFile(largeMetadataFile); expect(result).toBeDefined(); expect(result.file.size).toBeGreaterThan(1024 * 1024); }); }); describe('Unusual Audio Characteristics', () => { test('should handle files with extreme sample rates', async () => { // Test with mock metadata for extreme cases const extremeCases = [ { sampleRate: 8000, description: 'Very low sample rate' }, { sampleRate: 192000, description: 'Very high sample rate' }, { sampleRate: 0, description: 'Zero sample rate' }, { sampleRate: -1, description: 'Negative sample rate' } ]; for (const testCase of extremeCases) { const mockMetadata = { format: { sampleRate: testCase.sampleRate, numberOfChannels: 2, duration: 10 } }; const formatInfo = inspector.extractFormatInfo(mockMetadata); expect(formatInfo.sampleRate).toBe(testCase.sampleRate); // Game analysis should handle extreme values const gameAnalysis = await inspector.analyzeForGameAudio( { format: formatInfo, file: { size: 100000 } }, 'extreme-test.mp3' ); expect(gameAnalysis).toBeDefined(); } }); test('should handle files with unusual channel configurations', async () => { const channelConfigs = [ { channels: 0, description: 'No channels' }, { channels: 1, description: 'Mono' }, { channels: 8, description: 'Surround 7.1' }, { channels: 32, description: 'Many channels' } ]; for (const config of channelConfigs) { const mockMetadata = { format: { numberOfChannels: config.channels, sampleRate: 44100, duration: 60 } }; const formatInfo = inspector.extractFormatInfo(mockMetadata); expect(formatInfo.channels).toBe(config.channels); const gameAnalysis = await inspector.analyzeForGameAudio( { format: formatInfo, file: { size: 1000000 } }, 'channel-test.mp3' ); expect(gameAnalysis.platformOptimizations).toBeDefined(); expect(gameAnalysis.platformOptimizations.console).toBeDefined(); } }); test('should handle files with extreme durations', async () => { const durationCases = [ { duration: 0, description: 'Zero duration' }, { duration: 0.01, description: 'Very short' }, { duration: 86400, description: '24 hours' }, { duration: -1, description: 'Negative duration' } ]; for (const testCase of durationCases) { const mockBasicInfo = { format: { duration: testCase.duration, sampleRate: 44100, channels: 2 }, file: { size: 1000000 } }; const gameAnalysis = await inspector.analyzeForGameAudio(mockBasicInfo, 'duration-test.mp3'); expect(gameAnalysis).toBeDefined(); expect(typeof gameAnalysis.suitableForLoop).toBe('boolean'); } }); }); describe('System Resource Limits', () => { test('should handle insufficient disk space scenarios', async () => { // This test simulates behavior when disk space is low // In real scenarios, this would involve actual disk space constraints const testFile = path.join(testDir, 'disk-space-test.mp3'); await fs.writeFile(testFile, 'disk space test content'); // Simulate the analysis continuing normally const result = await inspector.analyzeFile(testFile); expect(result).toBeDefined(); // Should complete analysis even with disk constraints expect(result.file.name).toBe('disk-space-test.mp3'); }); test('should handle concurrent access to the same file', async () => { const sharedFile = path.join(testDir, 'shared-file.mp3'); await fs.writeFile(sharedFile, 'shared file content for concurrent access'); // Attempt multiple concurrent analyses of the same file const concurrentPromises = Array.from({ length: 5 }, () => inspector.analyzeFile(sharedFile) ); const results = await Promise.all(concurrentPromises); // All analyses should complete successfully expect(results.length).toBe(5); results.forEach(result => { expect(result).toBeDefined(); expect(result.file.name).toBe('shared-file.mp3'); }); }); }); describe('Network and Remote File Scenarios', () => { test('should handle UNC paths appropriately', async () => { // Test with UNC-style paths (Windows network paths) if (process.platform === 'win32') { const uncStylePath = '\\\\server\\share\\audio\\test.mp3'; // Since we can't create actual UNC paths in tests, test path handling const result = await inspector.analyzeFile(uncStylePath); // Should handle the path format, even if file doesn't exist expect(result).toBeDefined(); expect(result.file.path).toContain('test.mp3'); } }); }); describe('Memory and Performance Edge Cases', () => { test('should handle rapid successive analyses', async () => { const rapidFile = path.join(testDir, 'rapid-test.mp3'); await fs.writeFile(rapidFile, 'content for rapid testing'); const rapidCount = 20; const startTime = Date.now(); // Perform rapid successive analyses const results = []; for (let i = 0; i < rapidCount; i++) { const result = await inspector.analyzeFile(rapidFile); results.push(result); } const endTime = Date.now(); const totalTime = endTime - startTime; expect(results.length).toBe(rapidCount); expect(totalTime).toBeLessThan(10000); // Should complete within 10 seconds // All results should be consistent const firstResult = results[0]; results.forEach(result => { expect(result.file.size).toBe(firstResult.file.size); }); }); test('should handle analysis interruption gracefully', async () => { const interruptFile = path.join(testDir, 'interrupt-test.mp3'); await fs.writeFile(interruptFile, 'interrupt test content'); // Start analysis and immediately start another const promise1 = inspector.analyzeFile(interruptFile); const promise2 = inspector.analyzeFile(interruptFile); const [result1, result2] = await Promise.all([promise1, promise2]); expect(result1).toBeDefined(); expect(result2).toBeDefined(); // Both should complete successfully expect(result1.file.name).toBe('interrupt-test.mp3'); expect(result2.file.name).toBe('interrupt-test.mp3'); }); }); describe('Data Validation Edge Cases', () => { test('should handle null and undefined metadata gracefully', async () => { const nullCases = [ null, undefined, {}, { format: null }, { common: null }, { format: {}, common: undefined } ]; for (const testCase of nullCases) { expect(() => inspector.extractFormatInfo(testCase)).not.toThrow(); expect(() => inspector.extractTags(testCase)).not.toThrow(); const formatInfo = inspector.extractFormatInfo(testCase); const tags = inspector.extractTags(testCase); expect(formatInfo).toBeDefined(); expect(tags).toBeDefined(); } }); test('should handle circular references in metadata', async () => { // Create object with circular reference const circularMetadata = { format: { container: 'MP3', codec: 'mp3' } }; circularMetadata.format.self = circularMetadata.format; // Should handle without throwing expect(() => inspector.extractFormatInfo(circularMetadata)).not.toThrow(); const formatInfo = inspector.extractFormatInfo(circularMetadata); expect(formatInfo.container).toBe('MP3'); }); test('should handle extremely nested metadata structures', async () => { // Create deeply nested metadata let deepMetadata = { format: {} }; let current = deepMetadata.format; for (let i = 0; i < 100; i++) { current.nested = { level: i }; current = current.nested; } deepMetadata.format.container = 'DEEP'; deepMetadata.format.codec = 'nested'; const formatInfo = inspector.extractFormatInfo(deepMetadata); expect(formatInfo.container).toBe('DEEP'); expect(formatInfo.codec).toBe('nested'); }); }); describe('Format-Specific Edge Cases', () => { test('should handle unknown audio formats gracefully', async () => { const unknownFile = path.join(testDir, 'unknown.xyz'); await fs.writeFile(unknownFile, 'unknown format content'); const result = await inspector.analyzeFile(unknownFile); expect(result).toBeDefined(); // Should attempt analysis even for unknown extensions expect(result.file.name).toBe('unknown.xyz'); }); test('should handle mixed format signatures', async () => { const mixedFile = path.join(testDir, 'mixed-format.mp3'); // Create file with conflicting format signatures const mixedContent = 'ID3\x03\x00\x00RIFF\x24\x08\x00\x00WAVEfLaC'; await fs.writeFile(mixedFile, mixedContent); const result = await inspector.analyzeFile(mixedFile); expect(result).toBeDefined(); // Should handle conflicting signatures gracefully expect(result.file.name).toBe('mixed-format.mp3'); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DeveloperZo/mcp-audio-inspector'

If you have feedback or need assistance with the MCP directory API, please join our Discord server