UNPKG

ts-ritofile

Version:

TypeScript library for reading and writing League of Legends game file formats

273 lines (228 loc) โ€ข 10 kB
#!/usr/bin/env node /** * Integration test for ts-ritofile * Tests complete system functionality and cross-format compatibility */ const pyritofile = require('./dist/index.js'); const fs = require('fs'); const path = require('path'); console.log('๐Ÿ”ง ts-ritofile Integration Test'); console.log('===============================\n'); let testsPassed = 0; let testsFailed = 0; function test(name, fn) { try { console.log(`๐Ÿงช ${name}`); fn(); console.log(' โœ… PASSED\n'); testsPassed++; } catch (error) { console.log(` โŒ FAILED: ${error.message}\n`); testsFailed++; } } function assert(condition, message) { if (!condition) { throw new Error(message); } } // Test 1: API Surface Completeness test('API Surface Completeness', () => { // File format classes assert(typeof pyritofile.SKL === 'function', 'SKL class not exported'); assert(typeof pyritofile.BIN === 'function', 'BIN class not exported'); assert(typeof pyritofile.WAD === 'function', 'WAD class not exported'); // Hash functions assert(typeof pyritofile.FNV1 === 'function', 'FNV1 function not exported'); assert(typeof pyritofile.bin_hash === 'function', 'bin_hash function not exported'); // Convenience functions assert(typeof pyritofile.read_skl === 'function', 'read_skl function not exported'); assert(typeof pyritofile.write_bin === 'function', 'write_bin function not exported'); // JSON encoder assert(typeof pyritofile.PRFEncoder === 'function', 'PRFEncoder not exported'); assert(typeof pyritofile.to_json === 'function', 'to_json function not exported'); // Version assert(pyritofile.__version__ === '0.2.4', 'Version mismatch'); }); // Test 2: Hash Function Consistency test('Hash Function Consistency', () => { const testStrings = ['', 'test', 'Hello, World!', '๐ŸŽฎ๐ŸŽฏ๐ŸŽฒ']; testStrings.forEach(str => { // Test consistency assert(pyritofile.FNV1(str) === pyritofile.FNV1(str), `FNV1 inconsistent for "${str}"`); assert(pyritofile.FNV1a(str) === pyritofile.FNV1a(str), `FNV1a inconsistent for "${str}"`); assert(pyritofile.bin_hash(str) === pyritofile.bin_hash(str), `bin_hash inconsistent for "${str}"`); // Test output format assert(/^[0-9a-f]{8}$/.test(pyritofile.bin_hash(str)), `bin_hash invalid format for "${str}"`); assert(/^[0-9a-f]{16}$/.test(pyritofile.wad_hash(str)), `wad_hash invalid format for "${str}"`); }); }); // Test 3: Object Creation and Basic Operations test('Object Creation and Basic Operations', () => { // Create format objects const skl = new pyritofile.SKL(); const bin = new pyritofile.BIN(); const wad = new pyritofile.WAD(); const tex = new pyritofile.TEX(); const rst = new pyritofile.RST(); // Verify they're instances of correct classes assert(skl instanceof pyritofile.SKL, 'SKL instance check failed'); assert(bin instanceof pyritofile.BIN, 'BIN instance check failed'); assert(wad instanceof pyritofile.WAD, 'WAD instance check failed'); // Verify they have expected properties assert(Array.isArray(skl.joints), 'SKL joints not an array'); assert(Array.isArray(bin.entries), 'BIN entries not an array'); assert(Array.isArray(wad.chunks), 'WAD chunks not an array'); // Test toString methods assert(typeof skl.toString() === 'string', 'SKL toString failed'); assert(typeof bin.toString() === 'string', 'BIN toString failed'); assert(typeof wad.toString() === 'string', 'WAD toString failed'); }); // Test 4: JSON Encoding test('JSON Encoding', () => { // Test basic object encoding const obj = { name: 'test', value: 42, data: [1, 2, 3] }; const json = pyritofile.PRFEncoder.stringify(obj); const parsed = JSON.parse(json); assert(parsed.name === 'test', 'JSON encoding failed for basic object'); assert(parsed.value === 42, 'JSON encoding failed for number'); // Test Buffer encoding const buffer = Buffer.from([0x01, 0x02, 0x03]); const bufferJson = pyritofile.PRFEncoder.stringify({ data: buffer }); const bufferParsed = JSON.parse(bufferJson); assert(bufferParsed.data === '01 02 03', 'Buffer encoding failed'); // Test format object encoding const skl = new pyritofile.SKL(); const sklJson = pyritofile.to_json(skl); assert(typeof sklJson === 'string', 'Format object JSON encoding failed'); assert(JSON.parse(sklJson), 'Format object JSON parsing failed'); }); // Test 5: CACHED_BIN_HASHES test('CACHED_BIN_HASHES Functionality', () => { const cache = new pyritofile.CACHED_BIN_HASHES(); // Test basic functionality const key = 'test_key'; const hash1 = cache.get(key); const hash2 = cache.get(key); assert(hash1 === hash2, 'Cache not working - different values returned'); assert(hash1 === pyritofile.bin_hash(key), 'Cache value does not match direct hash'); assert(cache.has(key), 'Cache.has() not working for existing key'); assert(!cache.has('nonexistent'), 'Cache.has() not working for non-existing key'); // Test keys method const keys = Array.from(cache.keys()); assert(Array.isArray(keys), 'Cache.keys() not returning array'); assert(keys.includes(key), 'Cache.keys() not including added key'); }); // Test 6: Error Handling test('Error Handling', () => { // Test invalid file operations let errorThrown = false; try { pyritofile.read_skl('/nonexistent/path/file.skl'); } catch (error) { errorThrown = true; } assert(errorThrown, 'No error thrown for invalid file path'); // Test malformed data errorThrown = false; try { pyritofile.read_bin('', Buffer.from([0x00, 0x01])); } catch (error) { errorThrown = true; } assert(errorThrown, 'No error thrown for malformed data'); }); // Test 7: Enum Validation test('Enum Validation', () => { // Test BINType enum assert(typeof pyritofile.BINType === 'object', 'BINType not exported as object'); assert(pyritofile.BINType.hasOwnProperty('Empty'), 'BINType missing Empty value'); assert(pyritofile.BINType.hasOwnProperty('Bool'), 'BINType missing Bool value'); // Test WADCompressionType enum assert(typeof pyritofile.WADCompressionType === 'object', 'WADCompressionType not exported'); assert(pyritofile.WADCompressionType.hasOwnProperty('Raw'), 'WADCompressionType missing Raw'); assert(pyritofile.WADCompressionType.hasOwnProperty('Gzip'), 'WADCompressionType missing Gzip'); assert(pyritofile.WADCompressionType.hasOwnProperty('Zstd'), 'WADCompressionType missing Zstd'); }); // Test 8: Performance Validation test('Performance Validation', () => { const iterations = 10000; const testString = 'performance_test'; // Hash function performance const start = Date.now(); for (let i = 0; i < iterations; i++) { pyritofile.FNV1(testString + i); } const hashTime = Date.now() - start; assert(hashTime < 1000, `Hash functions too slow: ${hashTime}ms for ${iterations} operations`); // Object creation performance const objStart = Date.now(); for (let i = 0; i < iterations; i++) { const skl = new pyritofile.SKL(); skl.toString(); } const objTime = Date.now() - objStart; assert(objTime < 100, `Object creation too slow: ${objTime}ms for ${iterations} operations`); }); // Test 9: Memory Usage Validation test('Memory Usage Validation', () => { const initialMemory = process.memoryUsage().heapUsed; // Perform memory-intensive operations for (let i = 0; i < 1000; i++) { const skl = new pyritofile.SKL(); const bin = new pyritofile.BIN(); pyritofile.FNV1(`memory_test_${i}`); pyritofile.bin_hash(`memory_test_${i}`); // Use objects to prevent optimization skl.toString(); bin.toString(); } // Force garbage collection if available if (global.gc) { global.gc(); } const finalMemory = process.memoryUsage().heapUsed; const memoryIncrease = finalMemory - initialMemory; // Memory increase should be reasonable (less than 20MB) assert(memoryIncrease < 20 * 1024 * 1024, `Memory usage too high: ${Math.round(memoryIncrease / 1024 / 1024)}MB increase`); }); // Test 10: Cross-format Compatibility test('Cross-format Compatibility', () => { // Test that all convenience functions exist const readFunctions = [ 'read_skl', 'read_skn', 'read_sco', 'read_scb', 'read_anm', 'read_mapgeo', 'read_bin', 'read_bnk', 'read_wpk', 'read_tex', 'read_wad', 'read_rst' ]; const writeFunctions = [ 'write_skl', 'write_skn', 'write_sco', 'write_scb', 'write_anm', 'write_mapgeo', 'write_bin', 'write_bnk', 'write_wpk', 'write_wad', 'write_rst' ]; readFunctions.forEach(funcName => { assert(typeof pyritofile[funcName] === 'function', `${funcName} not exported`); }); writeFunctions.forEach(funcName => { assert(typeof pyritofile[funcName] === 'function', `${funcName} not exported`); }); // Test guess_extension const buffer = Buffer.from('test.bin'); const result = pyritofile.guess_extension(buffer); assert(typeof result === 'string' || result === undefined, 'guess_extension invalid return type'); }); // Test Results Summary console.log('๐Ÿ“Š Integration Test Results'); console.log('==========================='); console.log(`โœ… Tests Passed: ${testsPassed}`); console.log(`โŒ Tests Failed: ${testsFailed}`); console.log(`๐Ÿ“ˆ Success Rate: ${Math.round((testsPassed / (testsPassed + testsFailed)) * 100)}%\n`); if (testsFailed === 0) { console.log('๐ŸŽ‰ All integration tests passed!'); console.log('The TypeScript pyritofile library is fully functional and ready for production use.'); process.exit(0); } else { console.log('โš ๏ธ Some integration tests failed.'); console.log('Please review the failed tests and fix any issues before using in production.'); process.exit(1); }