From b7d05525337ae857b5cb38f26d9e5f644f34f419 Mon Sep 17 00:00:00 2001 From: ale Date: Sat, 6 Sep 2025 19:38:51 +0200 Subject: [PATCH] tests Signed-off-by: ale --- .gitignore | 3 +- package.json | 6 +- test/basic.test.js | 181 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 test/basic.test.js diff --git a/.gitignore b/.gitignore index ed57edc..37a3d45 100644 --- a/.gitignore +++ b/.gitignore @@ -60,8 +60,7 @@ tmp/ test_*.i2m example_*.i2m *_extracted* -*.test.js -*.spec.js +test/test_* # Example generated files examples/risitas_with_chiquito.i2m diff --git a/package.json b/package.json index df8ce6d..a72699b 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,11 @@ "main": "src/index.js", "types": "index.d.ts", "bin": { - "img2mp3": "./bin/cli.js" + "img2mp3": "bin/cli.js" }, "scripts": { "start": "node src/index.js", - "test": "echo \"Error: no test specified\" && exit 1", + "test": "node test/basic.test.js", "prepublishOnly": "npm run test", "example": "node examples/basic_usage.js" }, @@ -41,7 +41,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/ale/img2mp3.git" + "url": "git+https://github.com/ale/img2mp3.git" }, "bugs": { "url": "https://github.com/ale/img2mp3/issues" diff --git a/test/basic.test.js b/test/basic.test.js new file mode 100644 index 0000000..dbed51e --- /dev/null +++ b/test/basic.test.js @@ -0,0 +1,181 @@ +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const { IMG2MP3, MP3ImageEncoder, I2MPlayer } = require('../src/index'); + +// Test files paths +const testImagePath = path.join(__dirname, '..', 'examples', 'risitas.jpg'); +const testMp3Path = path.join(__dirname, '..', 'examples', 'chiquito-cobarde.mp3'); +const testOutputPath = path.join(__dirname, 'test_output.i2m'); +const testExtractedImagePath = path.join(__dirname, 'test_extracted_image.png'); +const testExtractedMp3Path = path.join(__dirname, 'test_extracted.mp3'); + +console.log('๐Ÿงช Running IMG2MP3 Test Suite...\n'); + +async function runAllTests() { + const img2mp3 = new IMG2MP3(); + let testsPassed = 0; + let totalTests = 0; + + function test(name, testFn) { + totalTests++; + try { + return Promise.resolve(testFn()).then(() => { + console.log(`โœ“ ${name}`); + testsPassed++; + }); + } catch (error) { + console.error(`โœ— ${name}: ${error.message}`); + throw error; + } + } + + try { + // Test 1: Class Instantiation + await test('IMG2MP3 class instantiation', () => { + assert(img2mp3 instanceof IMG2MP3, 'Should create IMG2MP3 instance'); + }); + + await test('MP3ImageEncoder class instantiation', () => { + const encoder = new MP3ImageEncoder(); + assert(encoder instanceof MP3ImageEncoder, 'Should create MP3ImageEncoder instance'); + }); + + await test('I2MPlayer class instantiation', () => { + const player = new I2MPlayer(); + assert(player instanceof I2MPlayer, 'Should create I2MPlayer instance'); + }); + + // Test 2: File Validation + await test('Test files existence', () => { + assert(fs.existsSync(testImagePath), 'Test image file should exist'); + assert(fs.existsSync(testMp3Path), 'Test MP3 file should exist'); + }); + + // Test 3: Encoding + await test('MP3 encoding into image', async () => { + const result = await img2mp3.encode(testImagePath, testMp3Path, testOutputPath); + + assert(result.success === true, 'Encoding should be successful'); + assert(typeof result.originalImageSize === 'number', 'Should return original image size'); + assert(typeof result.mp3Size === 'number', 'Should return MP3 size'); + assert(typeof result.outputSize === 'number', 'Should return output size'); + assert(typeof result.imageSize === 'string', 'Should return image dimensions'); + assert(fs.existsSync(testOutputPath), 'Output .i2m file should be created'); + }); + + // Test 4: File Information + await test('Get .i2m file information', async () => { + const info = await img2mp3.getInfo(testOutputPath); + + assert(info.isValid === true, 'File should be valid'); + assert(typeof info.mp3Size === 'number', 'Should return MP3 size'); + assert(typeof info.originalImageSize === 'number', 'Should return original image size'); + assert(typeof info.containerSize === 'number', 'Should return container size'); + assert(typeof info.format === 'string', 'Should return format'); + assert(typeof info.dimensions === 'string', 'Should return dimensions'); + }); + + // Test 5: Invalid file handling + await test('Invalid file detection', async () => { + const info = await img2mp3.getInfo(testImagePath); + assert(info.isValid === false, 'Non-.i2m file should be invalid'); + assert(typeof info.error === 'string', 'Should return error message'); + }); + + // Test 6: Decoding + await test('.i2m file decoding', async () => { + const result = await img2mp3.decode(testOutputPath, testExtractedImagePath, testExtractedMp3Path); + + assert(result.success === true, 'Decoding should be successful'); + assert(typeof result.extractedImageSize === 'number', 'Should return extracted image size'); + assert(typeof result.extractedMp3Size === 'number', 'Should return extracted MP3 size'); + assert(fs.existsSync(testExtractedImagePath), 'Extracted image should exist'); + assert(fs.existsSync(testExtractedMp3Path), 'Extracted MP3 should exist'); + }); + + // Test 7: File integrity + await test('File size preservation', () => { + const originalImageSize = fs.statSync(testImagePath).size; + const originalMp3Size = fs.statSync(testMp3Path).size; + const extractedImageSize = fs.statSync(testExtractedImagePath).size; + const extractedMp3Size = fs.statSync(testExtractedMp3Path).size; + + assert(originalImageSize === extractedImageSize, 'Image size should be preserved'); + assert(originalMp3Size === extractedMp3Size, 'MP3 size should be preserved'); + }); + + // Test 8: Player status + await test('Player status check', () => { + const status = img2mp3.getPlaybackStatus(); + assert(typeof status.isPlaying === 'boolean', 'Should return playing status'); + assert(typeof status.hasActiveProcess === 'boolean', 'Should return process status'); + }); + + // Test 9: Stop function + await test('Stop playback function', () => { + // This should not throw an error even if nothing is playing + assert.doesNotThrow(() => { + img2mp3.stop(); + }, 'Stop function should not throw error'); + }); + + // Test 10: Convenience functions + await test('Convenience functions export', () => { + const { encode, decode, getInfo, play } = require('../src/index'); + assert(typeof encode === 'function', 'Should export encode function'); + assert(typeof decode === 'function', 'Should export decode function'); + assert(typeof getInfo === 'function', 'Should export getInfo function'); + assert(typeof play === 'function', 'Should export play function'); + }); + + // Test 11: Error handling for non-existent files + await test('Error handling for missing files', async () => { + try { + await img2mp3.encode('nonexistent.jpg', testMp3Path, 'test.i2m'); + assert.fail('Should have thrown an error for missing image file'); + } catch (error) { + assert(error.message.includes('ENOENT') || error.message.includes('not found'), + 'Should throw file not found error'); + } + + try { + await img2mp3.encode(testImagePath, 'nonexistent.mp3', 'test.i2m'); + assert.fail('Should have thrown an error for missing MP3 file'); + } catch (error) { + assert(error.message.includes('ENOENT') || error.message.includes('not found'), + 'Should throw file not found error'); + } + }); + + console.log(`\n๐ŸŽ‰ All tests passed! (${testsPassed}/${totalTests})`); + console.log('โœ… IMG2MP3 is ready for publication'); + + } catch (error) { + console.error(`\nโŒ Test failed: ${error.message}`); + console.log(`๐Ÿ“Š Tests passed: ${testsPassed}/${totalTests}`); + process.exit(1); + } finally { + // Cleanup test files + const filesToClean = [ + testOutputPath, + testExtractedImagePath, + testExtractedMp3Path + ]; + + filesToClean.forEach(file => { + try { + if (fs.existsSync(file)) { + fs.unlinkSync(file); + } + } catch (error) { + console.warn(`Warning: Could not delete ${file}`); + } + }); + + img2mp3.cleanup(); + } +} + +// Run all tests +runAllTests();