Skip to main content
Glama
validation.test.ts15.9 kB
import { describe, it, expect } from '@jest/globals'; import { FilePathSchema, VolumeOperationSchema, FormatOperationSchema, EffectsOperationSchema, AudioOperationsSchema, ProcessingInputSchema, ProcessingOutputSchema, PresetNameSchema, ProcessAudioFileInputSchema, BatchProcessAudioInputSchema, ApplyPresetInputSchema, validateFilePath, validateAudioOperations, validateProcessingParameters } from '../../src/schemas/validation.js'; describe('Validation Schemas', () => { describe('FilePathSchema', () => { it('should validate supported audio file extensions', () => { const validPaths = [ 'audio.mp3', 'music.wav', 'sound.ogg', 'voice.flac', 'track.m4a', 'clip.aac', '/path/to/file.MP3', 'C:\\Windows\\audio.WAV' ]; validPaths.forEach(path => { expect(() => FilePathSchema.parse(path)).not.toThrow(); }); }); it('should reject unsupported file extensions', () => { const invalidPaths = [ 'document.txt', 'image.jpg', 'video.mp4', 'data.json', 'file.pdf', 'audio', '', 'audio.', '.mp3' ]; invalidPaths.forEach(path => { expect(() => FilePathSchema.parse(path)).toThrow(); }); }); it('should handle case insensitive extensions', () => { const casePaths = [ 'file.MP3', 'file.Mp3', 'file.mP3', 'file.WAV', 'file.OGG', 'file.FLAC', 'file.M4A', 'file.AAC' ]; casePaths.forEach(path => { expect(() => FilePathSchema.parse(path)).not.toThrow(); }); }); }); describe('VolumeOperationSchema', () => { it('should validate volume adjustment within range', () => { const validOperations = [ { adjust: -60 }, { adjust: 0 }, { adjust: 20 }, { adjust: -10.5 }, { normalize: true }, { normalize: false }, { targetLUFS: -23 }, { targetLUFS: -16 }, { adjust: -6, normalize: true, targetLUFS: -20 } ]; validOperations.forEach(op => { expect(() => VolumeOperationSchema.parse(op)).not.toThrow(); }); }); it('should reject volume adjustment outside range', () => { const invalidOperations = [ { adjust: -61 }, { adjust: 21 }, { adjust: 100 }, { adjust: -100 } ]; invalidOperations.forEach(op => { expect(() => VolumeOperationSchema.parse(op)).toThrow(); }); }); it('should apply default values correctly', () => { const result = VolumeOperationSchema.parse({ normalize: true }); expect(result.normalize).toBe(true); }); it('should handle empty object', () => { const result = VolumeOperationSchema.parse({}); expect(result).toEqual({}); }); }); describe('FormatOperationSchema', () => { it('should validate all format parameters', () => { const validFormats = [ { sampleRate: 44100 }, { bitrate: 192 }, { channels: 2 }, { codec: 'mp3' }, { sampleRate: 48000, bitrate: 320, channels: 1, codec: 'aac' } ]; validFormats.forEach(format => { expect(() => FormatOperationSchema.parse(format)).not.toThrow(); }); }); it('should reject invalid sample rates', () => { const invalidSampleRates = [ { sampleRate: 32000 }, { sampleRate: 11025 }, { sampleRate: 88200 } ]; invalidSampleRates.forEach(format => { expect(() => FormatOperationSchema.parse(format)).toThrow(); }); }); it('should reject invalid bitrates', () => { const invalidBitrates = [ { bitrate: 32 }, { bitrate: 63 }, { bitrate: 321 }, { bitrate: 1000 } ]; invalidBitrates.forEach(format => { expect(() => FormatOperationSchema.parse(format)).toThrow(); }); }); it('should reject invalid channel counts', () => { const invalidChannels = [ { channels: 0 }, { channels: 3 }, { channels: 4 }, { channels: 5 }, { channels: 7 }, { channels: 16 } ]; invalidChannels.forEach(format => { expect(() => FormatOperationSchema.parse(format)).toThrow(); }); }); it('should reject invalid codecs', () => { const invalidCodecs = [ { codec: 'mp4' }, { codec: 'wav' }, { codec: 'unknown' }, { codec: '' } ]; invalidCodecs.forEach(format => { expect(() => FormatOperationSchema.parse(format)).toThrow(); }); }); }); describe('EffectsOperationSchema', () => { it('should validate fade effects', () => { const validEffects = [ { fadeIn: 0 }, { fadeIn: 2.5 }, { fadeOut: 1.0 }, { fadeIn: 1, fadeOut: 2 } ]; validEffects.forEach(effect => { expect(() => EffectsOperationSchema.parse(effect)).not.toThrow(); }); }); it('should validate trim effects', () => { const validTrims = [ { trim: { start: 0, end: 10 } }, { trim: { start: 5.5, end: 15.2 } }, { trim: { start: 0, end: 0 } } ]; validTrims.forEach(effect => { expect(() => EffectsOperationSchema.parse(effect)).not.toThrow(); }); }); it('should validate loop effects', () => { const validLoops = [ { loop: { enabled: true, count: 1 } }, { loop: { enabled: false, count: 1 } }, { loop: { enabled: true, count: 5 } } ]; validLoops.forEach(effect => { expect(() => EffectsOperationSchema.parse(effect)).not.toThrow(); }); }); it('should reject negative fade values', () => { const invalidFades = [ { fadeIn: -1 }, { fadeOut: -0.1 } ]; invalidFades.forEach(effect => { expect(() => EffectsOperationSchema.parse(effect)).toThrow(); }); }); it('should reject negative trim values', () => { const invalidTrims = [ { trim: { start: -1, end: 10 } }, { trim: { start: 0, end: -1 } }, { trim: { start: -5, end: -1 } } ]; invalidTrims.forEach(effect => { expect(() => EffectsOperationSchema.parse(effect)).toThrow(); }); }); it('should reject invalid loop counts', () => { const invalidLoops = [ { loop: { enabled: true, count: 0 } }, { loop: { enabled: true, count: -1 } } ]; invalidLoops.forEach(effect => { expect(() => EffectsOperationSchema.parse(effect)).toThrow(); }); }); }); describe('AudioOperationsSchema', () => { it('should validate complete operations', () => { const validOperations = [ {}, { volume: { adjust: -3 } }, { format: { sampleRate: 44100 } }, { effects: { fadeIn: 1 } }, { volume: { adjust: -6, normalize: true }, format: { sampleRate: 48000, channels: 2 }, effects: { fadeIn: 1, fadeOut: 2, trim: { start: 0, end: 30 } } } ]; validOperations.forEach(ops => { expect(() => AudioOperationsSchema.parse(ops)).not.toThrow(); }); }); it('should allow empty operations object', () => { const result = AudioOperationsSchema.parse({}); expect(result).toEqual({}); }); }); describe('ProcessingInputSchema', () => { it('should validate file input', () => { const validInputs = [ { file: '/path/to/audio.mp3' }, { file: 'audio.wav', pattern: '*.wav' } ]; validInputs.forEach(input => { expect(() => ProcessingInputSchema.parse(input)).not.toThrow(); }); }); it('should validate directory input', () => { const validInputs = [ { directory: '/path/to/audio' }, { directory: '/audio', pattern: '*.mp3' } ]; validInputs.forEach(input => { expect(() => ProcessingInputSchema.parse(input)).not.toThrow(); }); }); it('should reject input without file or directory', () => { const invalidInputs = [ {}, { pattern: '*.mp3' }, { file: '', directory: '' } ]; invalidInputs.forEach(input => { expect(() => ProcessingInputSchema.parse(input)).toThrow(); }); }); }); describe('ProcessingOutputSchema', () => { it('should validate output configurations', () => { const validOutputs = [ { file: '/output/audio.mp3' }, { directory: '/output' }, { directory: '/output', suffix: '_processed' }, { directory: '/output', format: 'mp3' }, { directory: '/output', suffix: '_optimized', format: 'wav' } ]; validOutputs.forEach(output => { expect(() => ProcessingOutputSchema.parse(output)).not.toThrow(); }); }); it('should apply default suffix', () => { const result = ProcessingOutputSchema.parse({ directory: '/output' }); expect(result.suffix).toBe('_processed'); }); it('should allow empty output for defaults', () => { const result = ProcessingOutputSchema.parse({}); expect(result.suffix).toBe('_processed'); }); }); describe('PresetNameSchema', () => { it('should validate all preset names', () => { const validPresets = [ 'game-audio-mobile', 'game-audio-desktop', 'game-audio-console', 'elevenLabs-optimize', 'voice-processing', 'music-mastering', 'sfx-optimization' ]; validPresets.forEach(preset => { expect(() => PresetNameSchema.parse(preset)).not.toThrow(); }); }); it('should reject invalid preset names', () => { const invalidPresets = [ 'invalid-preset', 'game-audio', 'optimization', '', 'custom-preset' ]; invalidPresets.forEach(preset => { expect(() => PresetNameSchema.parse(preset)).toThrow(); }); }); }); describe('MCP Tool Input Schemas', () => { describe('ProcessAudioFileInputSchema', () => { it('should validate process audio file input', () => { const validInput = { inputFile: 'audio.mp3', outputFile: 'processed.mp3', operations: { volume: { adjust: -3 }, format: { sampleRate: 44100 } } }; expect(() => ProcessAudioFileInputSchema.parse(validInput)).not.toThrow(); }); it('should reject invalid input file', () => { const invalidInput = { inputFile: 'document.txt', outputFile: 'processed.mp3', operations: {} }; expect(() => ProcessAudioFileInputSchema.parse(invalidInput)).toThrow(); }); }); describe('BatchProcessAudioInputSchema', () => { it('should validate batch processing input', () => { const validInput = { inputDirectory: '/input', outputDirectory: '/output', operations: { volume: { normalize: true } } }; expect(() => BatchProcessAudioInputSchema.parse(validInput)).not.toThrow(); }); it('should apply default file pattern', () => { const input = { inputDirectory: '/input', outputDirectory: '/output', operations: {} }; const result = BatchProcessAudioInputSchema.parse(input); expect(result.filePattern).toBe('*.{mp3,wav,ogg,flac,m4a,aac}'); }); }); describe('ApplyPresetInputSchema', () => { it('should validate preset application input', () => { const validInput = { inputFile: 'audio.mp3', outputFile: 'processed.mp3', preset: 'game-audio-mobile' }; expect(() => ApplyPresetInputSchema.parse(validInput)).not.toThrow(); }); it('should reject invalid preset', () => { const invalidInput = { inputFile: 'audio.mp3', outputFile: 'processed.mp3', preset: 'invalid-preset' }; expect(() => ApplyPresetInputSchema.parse(invalidInput)).toThrow(); }); }); }); describe('Validation Helper Functions', () => { describe('validateFilePath', () => { it('should return true for valid paths', () => { expect(validateFilePath('audio.mp3')).toBe(true); expect(validateFilePath('sound.wav')).toBe(true); expect(validateFilePath('/path/to/music.flac')).toBe(true); }); it('should return false for invalid paths', () => { expect(validateFilePath('document.txt')).toBe(false); expect(validateFilePath('')).toBe(false); expect(validateFilePath('audio')).toBe(false); }); }); describe('validateAudioOperations', () => { it('should return true for valid operations', () => { const validOps = { volume: { adjust: -3 }, format: { sampleRate: 44100 } }; expect(validateAudioOperations(validOps)).toBe(true); expect(validateAudioOperations({})).toBe(true); }); it('should return false for invalid operations', () => { const invalidOps = { volume: { adjust: 100 }, format: { sampleRate: 32000 } }; expect(validateAudioOperations(invalidOps)).toBe(false); expect(validateAudioOperations(null)).toBe(false); expect(validateAudioOperations(undefined)).toBe(false); }); }); describe('validateProcessingParameters', () => { it('should return true for valid parameters', () => { const validParams = { input: { file: 'audio.mp3' }, output: { directory: '/output' }, operations: { volume: { adjust: -3 } } }; expect(validateProcessingParameters(validParams)).toBe(true); }); it('should return false for invalid parameters', () => { const invalidParams = { input: {}, output: { directory: '/output' } }; expect(validateProcessingParameters(invalidParams)).toBe(false); expect(validateProcessingParameters(null)).toBe(false); }); }); }); describe('Edge Cases and Boundary Values', () => { it('should handle volume adjustment boundary values', () => { expect(() => VolumeOperationSchema.parse({ adjust: -60 })).not.toThrow(); expect(() => VolumeOperationSchema.parse({ adjust: 20 })).not.toThrow(); expect(() => VolumeOperationSchema.parse({ adjust: -60.1 })).toThrow(); expect(() => VolumeOperationSchema.parse({ adjust: 20.1 })).toThrow(); }); it('should handle bitrate boundary values', () => { expect(() => FormatOperationSchema.parse({ bitrate: 64 })).not.toThrow(); expect(() => FormatOperationSchema.parse({ bitrate: 320 })).not.toThrow(); expect(() => FormatOperationSchema.parse({ bitrate: 63 })).toThrow(); expect(() => FormatOperationSchema.parse({ bitrate: 321 })).toThrow(); }); it('should handle zero values appropriately', () => { expect(() => EffectsOperationSchema.parse({ fadeIn: 0 })).not.toThrow(); expect(() => EffectsOperationSchema.parse({ trim: { start: 0, end: 0 } })).not.toThrow(); expect(() => EffectsOperationSchema.parse({ loop: { enabled: true, count: 1 } })).not.toThrow(); }); it('should handle very large valid values', () => { expect(() => FormatOperationSchema.parse({ sampleRate: 192000 })).not.toThrow(); expect(() => EffectsOperationSchema.parse({ fadeIn: 999999 })).not.toThrow(); expect(() => EffectsOperationSchema.parse({ trim: { start: 0, end: 999999 } })).not.toThrow(); }); }); });

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-tweaker'

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