1
0
Fork 0
mirror of https://github.com/marcrobledo/RomPatcher.js.git synced 2025-06-27 16:25:54 +00:00
RomPatcher.js/test.js
2024-08-09 19:30:49 +02:00

171 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Test battery for Rom Patcher JS
https://github.com/marcrobledo/RomPatcher.js
by Marc Robledo, released under MIT license: https://github.com/marcrobledo/RomPatcher.js/blob/master/LICENSE
Usage:
> npm install
> npm run test
You need to provide the following ROMs and patches, unzip them in
_test_files/roms and _test_files/patches folders respectively:
- IPS test
- Patch: https://www.romhacking.net/hacks/3784/
- ROM: Super Mario Land 2 - 6 Golden Coins (USA, Europe).gb [CRC32=d5ec24e4]
- BPS test
- Patch: https://www.romhacking.net/translations/6297/
- ROM: Samurai Kid (Japan).gbc [CRC32=44a9ddfb]
- UPS test
- Patch: https://mother3.fobby.net/
- ROM: Mother 3 (Japan).gba [CRC32=42ac9cb9]
- APS test
- Patch: http://dorando.emuverse.com/projects/eduardo_a2j/zelda-ocarina-of-time.html
- ROM: Legend of Zelda, The - Ocarina of Time (USA).z64 [CRC32=7e107c35]
- RUP test
- Patch: https://www.romhacking.net/translations/843/
- ROM: Uchuu no Kishi - Tekkaman Blade (Japan).sfc [CRC32=cd16c529]
*/
const chalk=require('chalk');
const { existsSync }=require('fs');
const BinFile = require('./app/modules/BinFile');
const HashCalculator = require('./app/modules/HashCalculator');
const RomPatcher = require('./app/RomPatcher');
const TEST_PATH='_test_files/';
const TEST_PATCHES=[
{
title:'IPS - Super Mario Land 2 DX',
romFile:'Super Mario Land 2 - 6 Golden Coins (USA, Europe).gb',
romCrc32:0xd5ec24e4,
patchFile:'SML2DXv181.ips',
patchCrc32:0x0b742316,
patchDownload:'https://www.romhacking.net/hacks/3784/',
outputCrc32:0xf0799017
},{
title:'BPS - Samurai Kid translation',
romFile:'Samurai Kid (Japan).gbc',
romCrc32:0x44a9ddfb,
patchFile:'samurai_kid_en_v1.bps',
patchCrc32:0x2144df1c,
patchDownload:'https://www.romhacking.net/translations/6297/',
outputCrc32:0xed238edb
},{
title:'UPS - Mother 3 translation',
romFile:'Mother 3 (Japan).gba',
romCrc32:0x42ac9cb9,
patchFile:'mother3.ups',
patchCrc32:0x2144df1c,
patchDownload:'https://mother3.fobby.net/',
outputCrc32:0x8a3bc5a8
},{
title:'APS - Zelda OoT spanish translation',
romFile:'Legend of Zelda, The - Ocarina of Time (USA).z64',
romCrc32:0xcd16c529,
patchFile:'ZELDA64.APS',
patchCrc32:0x7b70119d,
patchDownload:'http://dorando.emuverse.com/projects/eduardo_a2j/zelda-ocarina-of-time.html',
outputCrc32:0x7866f1ca
},{
title:'Tekkaman Blade translation',
romFile:'Uchuu no Kishi - Tekkaman Blade (Japan).sfc',
romCrc32:0x7e107c35,
patchFile:'Tekkaman Blade v1.0.rup',
patchCrc32:0x621ab323,
patchDownload:'https://www.romhacking.net/hacks/4633/',
outputCrc32:0xe83e9b0a
}
];
const _test=function(title, testFunction){
try{
const startTime=(new Date()).getTime();
const result=testFunction.call();
const executionTime=((new Date()).getTime() - startTime) / 1000;
console.log(chalk.greenBright('√ '+title + ' ('+executionTime+'s)'));
}catch(err){
console.log(chalk.redBright('× '+title + ' - failed with error: '+err.message));
}
};
const TEST_DATA = (new Uint8Array([
98, 91, 64, 8, 35, 53, 122, 167, 52, 253, 222, 156, 247, 82, 227, 213, 22, 221, 17, 247, 107, 102, 164, 254, 221, 102, 207, 63, 117, 164, 223, 10, 223, 200, 150, 4, 77, 250, 111, 64, 233, 118, 1, 36, 1, 60, 208, 245, 136, 126, 29, 231, 168, 18, 125, 172, 11, 184, 81, 20, 16, 30, 154, 16, 236, 21, 5, 74, 255, 112, 171, 198, 185, 89, 2, 98, 45, 164, 214, 55, 103, 15, 217, 95, 212, 133, 184, 21, 67, 144, 198, 163, 76, 35, 248, 229, 163, 37, 103, 33, 193, 160, 161, 245, 125, 144, 193, 178, 31, 253, 119, 168, 169, 187, 195, 165, 205, 140, 222, 134, 249, 68, 224, 248, 144, 207, 18, 126
])).buffer;
_test('HashCalculator integrity', function(){
if(HashCalculator.md5(TEST_DATA) !== '55c76e7e683fd7cd63c673c5df3efa6e')
throw new Error('invalid MD5');
if(HashCalculator.crc32(TEST_DATA).toString(16) !== '903a031b')
throw new Error('invalid CRC32');
if(HashCalculator.adler32(TEST_DATA).toString(16) !== 'ef984205')
throw new Error('invalid ADLER32');
if(HashCalculator.crc16(TEST_DATA).toString(16) !== '96e4')
throw new Error('invalid SHA1');
});
const MODIFIED_TEST_DATA = (new Uint8Array([
98, 91, 64, 8, 35, 53, 122, 167, 52, 253, 222, 156, 247, 82, 227, 213, 22, 221, 17, 247, 107, 102, 164, 254, 221, 8, 207, 63, 117, 164, 223, 10, 1, 77, 87, 123, 48, 9, 111, 64, 233, 118, 1, 36, 1, 60, 208, 245, 136, 126, 29, 231, 168, 18, 125, 172, 11, 184, 81, 20, 16, 30, 154, 16, 236, 21, 5, 74, 255, 112, 171, 198, 185, 89, 2, 98, 45, 164, 214, 55, 103, 15, 217, 95, 212, 133, 184, 21, 67, 144, 198, 163, 76, 35, 248, 229, 163, 37, 103, 33, 193, 96, 77, 255, 117, 89, 193, 61, 64, 253, 119, 82, 49, 187, 195, 165, 205, 140, 222, 134, 249, 68, 224, 248, 144, 207, 18, 126
])).buffer;
['ips','bps','ppf','ups','aps','rup'].forEach(function(patchFormat){
_test('create and apply '+patchFormat.toUpperCase(), function(){
const originalFile=new BinFile(TEST_DATA);
const modifiedFile=new BinFile(MODIFIED_TEST_DATA);
const patch=RomPatcher.createPatch(originalFile, modifiedFile, patchFormat);
const patchedFile=RomPatcher.applyPatch(originalFile, patch, {requireValidation:true});
if(patchedFile.hashCRC32() !== modifiedFile.hashCRC32())
throw new Error('modified and patched files\' crc32 do not match');
})
});
TEST_PATCHES.forEach(function(patchInfo){
const patchPath=TEST_PATH+'patches/'+patchInfo.patchFile;
if(!existsSync(patchPath)){
console.log(chalk.yellow('! skipping patch '+patchInfo.title));
console.log(chalk.yellow(' patch file not found: '+patchInfo.patchFile));
console.log(chalk.yellow(' download patch at '+patchInfo.patchDownload));
return false;
}
const patchFile=new BinFile(patchPath);
if(patchFile.hashCRC32() !== patchInfo.patchCrc32){
console.log(patchFile.hashCRC32().toString(16));
console.log(chalk.yellow('! skipping '+patchInfo.title+' test: invalid patch crc32'));
console.log(chalk.yellow(' download correct patch at '+patchInfo.patchDownload));
return false;
}
const romPath=TEST_PATH+'roms/'+patchInfo.romFile;
if(!existsSync(romPath)){
console.log(chalk.yellow('! skipping patch '+patchInfo.title));
console.log(chalk.yellow(' ROM file not found: '+patchInfo.romFile));
return false;
}
const romFile=new BinFile(romPath);
if(romFile.hashCRC32() !== patchInfo.romCrc32){
console.log(chalk.yellow('! skipping '+patchInfo.title+' test: invalid ROM crc32'));
return false;
}
_test('patch '+patchInfo.title, function(){
const patch=RomPatcher.parsePatchFile(patchFile);
const patchedRom=RomPatcher.applyPatch(romFile, patch, {requireValidation:true});
if(patchedRom.hashCRC32() !== patchInfo.outputCrc32)
throw new Error('invalid patched file crc32');
});
});