ts-ritofile
Version:
TypeScript library for reading and writing League of Legends game file formats
273 lines (228 loc) โข 10 kB
JavaScript
/**
* 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);
}