Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 6m16s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
272 lines
8.5 KiB
JavaScript
272 lines
8.5 KiB
JavaScript
var nota = use('nota');
|
|
var os = use('os');
|
|
|
|
// Helper function to convert hex string to ArrayBuffer
|
|
function hexToBuffer(hex) {
|
|
let bytes = new Uint8Array(hex.length / 2);
|
|
for (let i = 0; i < hex.length; i += 2)
|
|
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
|
|
return bytes.buffer;
|
|
}
|
|
|
|
// Helper function to convert ArrayBuffer to hex string
|
|
function bufferToHex(buffer) {
|
|
return Array.from(new Uint8Array(buffer))
|
|
.map(b => b.toString(16).padStart(2, '0'))
|
|
.join('')
|
|
.toLowerCase();
|
|
}
|
|
|
|
var EPSILON = 1e-12
|
|
|
|
// Deep comparison function for objects and arrays
|
|
function deepCompare(expected, actual, path = '') {
|
|
if (expected === actual) return { passed: true, messages: [] };
|
|
|
|
if (typeof expected === 'number' && typeof actual === 'number') {
|
|
if (isNaN(expected) && isNaN(actual))
|
|
return { passed: true, messages: [] };
|
|
|
|
const diff = Math.abs(expected - actual);
|
|
if (diff <= EPSILON)
|
|
return { passed: true, messages: [] };
|
|
|
|
return {
|
|
passed: false,
|
|
messages: [
|
|
`Value mismatch at ${path}: expected ${expected}, got ${actual}`,
|
|
`Difference of ${diff} is larger than tolerance ${EPSILON}`
|
|
]
|
|
};
|
|
}
|
|
|
|
if (expected instanceof ArrayBuffer && actual instanceof ArrayBuffer) {
|
|
const expArray = Array.from(new Uint8Array(expected));
|
|
const actArray = Array.from(new Uint8Array(actual));
|
|
return deepCompare(expArray, actArray, path);
|
|
}
|
|
|
|
if (actual instanceof ArrayBuffer)
|
|
actual = Array.from(new Uint8Array(actual));
|
|
|
|
if (Array.isArray(expected) && Array.isArray(actual)) {
|
|
if (expected.length !== actual.length)
|
|
return {
|
|
passed: false,
|
|
messages: [`Array length mismatch at ${path}: expected ${expected.length}, got ${actual.length}`]
|
|
};
|
|
let messages = [];
|
|
for (let i = 0; i < expected.length; i++) {
|
|
const result = deepCompare(expected[i], actual[i], `${path}[${i}]`);
|
|
if (!result.passed) messages.push(...result.messages);
|
|
}
|
|
return { passed: messages.length === 0, messages };
|
|
}
|
|
|
|
if (typeof expected === 'object' && expected !== null &&
|
|
typeof actual === 'object' && actual !== null) {
|
|
const expKeys = Object.keys(expected).sort();
|
|
const actKeys = Object.keys(actual).sort();
|
|
if (JSON.stringify(expKeys) !== JSON.stringify(actKeys))
|
|
return {
|
|
passed: false,
|
|
messages: [`Object keys mismatch at ${path}: expected ${expKeys}, got ${actKeys}`]
|
|
};
|
|
let messages = [];
|
|
for (let key of expKeys) {
|
|
const result = deepCompare(expected[key], actual[key], `${path}.${key}`);
|
|
if (!result.passed) messages.push(...result.messages);
|
|
}
|
|
return { passed: messages.length === 0, messages };
|
|
}
|
|
|
|
return {
|
|
passed: false,
|
|
messages: [`Value mismatch at ${path}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`]
|
|
};
|
|
}
|
|
|
|
// Extended test cases covering all Nota types from documentation
|
|
var testarr = []
|
|
var hex = "a374"
|
|
for (var i = 0; i < 500; i++) {
|
|
testarr.push(1)
|
|
hex += "61"
|
|
}
|
|
|
|
var testCases = [
|
|
// Integer tests
|
|
{ input: 0, expectedHex: "60" },
|
|
{ input: 2023, expectedHex: "e08f67" },
|
|
{ input: -1, expectedHex: "69" },
|
|
{ input: 7, expectedHex: "67" },
|
|
{ input: -7, expectedHex: "6f" },
|
|
{ input: 1023, expectedHex: "e07f" },
|
|
{ input: -1023, expectedHex: "ef7f" },
|
|
|
|
// Symbol tests
|
|
{ input: undefined, expectedHex: "70" },
|
|
{ input: false, expectedHex: "72" },
|
|
{ input: true, expectedHex: "73" },
|
|
|
|
// Floating Point tests
|
|
{ input: -1.01, expectedHex: "5a65" },
|
|
{ input: 98.6, expectedHex: "51875a" },
|
|
{ input: -0.5772156649, expectedHex: "d80a95c0b0bd69" },
|
|
{ input: -1.00000000000001, expectedHex: "d80e96deb183e98001" },
|
|
{ input: -10000000000000, expectedHex: "c80d01" },
|
|
|
|
// Text tests
|
|
{ input: "", expectedHex: "10" },
|
|
{ input: "cat", expectedHex: "13636174" },
|
|
{ input: "U+1F4A9 「うんち絵文字」 «💩»",
|
|
expectedHex: "9014552b314634413920e00ce046e113e06181fa7581cb0781b657e00d20812b87e929813b" },
|
|
|
|
// Blob tests
|
|
{ input: new Uint8Array([0xFF, 0xAA]).buffer, expectedHex: "8010ffaa" },
|
|
{ input: new Uint8Array([0b11110000, 0b11100011, 0b00100000, 0b10000000]).buffer,
|
|
expectedHex: "8019f0e32080" },
|
|
|
|
{ input: testarr, expectedHex: hex },
|
|
|
|
// Array tests
|
|
{ input: [], expectedHex: "20" },
|
|
{ input: [1, 2, 3], expectedHex: "23616263" },
|
|
{ input: [-1, 0, 1.5], expectedHex: "2369605043" },
|
|
|
|
// Record tests
|
|
{ input: {}, expectedHex: "30" },
|
|
{ input: { a: 1, b: 2 }, expectedHex: "32116161116262" },
|
|
|
|
// Complex nested structures
|
|
{ input: {
|
|
num: 42,
|
|
arr: [1, -1, 2.5],
|
|
str: "test",
|
|
obj: { x: true }
|
|
},
|
|
expectedHex: "34216e756d622a2173747214746573742161727223616965235840216f626a21117873" },
|
|
|
|
// Private prefix test
|
|
{ input: { private: { address: "test" } },
|
|
expectedHex: "317821616464726573731474657374" },
|
|
|
|
// System prefix test
|
|
{ input: { system: { msg: "hello" } },
|
|
expectedHex: "3179216d73671568656c6c6f" },
|
|
|
|
{ input: [{ system: {msg: "hello" } }, {
|
|
num: 42,
|
|
arr: [1, -1, 2.5],
|
|
str: "test",
|
|
obj: { x: true }
|
|
}], expectedHex: "223179216d73671568656c6c6f34216e756d622a2173747214746573742161727223616965235840216f626a21117873" },
|
|
|
|
// Additional edge cases
|
|
{ input: new Uint8Array([]).buffer, expectedHex: "00" },
|
|
{ input: [[]], expectedHex: "2120" },
|
|
{ input: { "": "" }, expectedHex: "311010" },
|
|
{ input: 1e-10, expectedHex: "d00a01" },
|
|
|
|
// Replacer tests
|
|
{ input: { a: 1, b: 2 },
|
|
replacer: (key, value) => typeof value === 'number' ? value * 2 : value,
|
|
expected: { a: 2, b: 4 },
|
|
testType: 'replacer' },
|
|
|
|
{ input: { x: "test", y: 5 },
|
|
replacer: (key, value) => key === 'x' ? value + "!" : value,
|
|
expected: { x: "test!", y: 5 },
|
|
testType: 'replacer' },
|
|
|
|
// Reviver tests
|
|
{ input: { a: 1, b: 2 },
|
|
reviver: (key, value) => typeof value === 'number' ? value * 3 : value,
|
|
expected: { a: 3, b: 6 },
|
|
testType: 'reviver' },
|
|
|
|
{ input: { x: "test", y: 10 },
|
|
reviver: (key, value) => key === 'y' ? value + 1 : value,
|
|
expected: { x: "test", y: 11 },
|
|
testType: 'reviver' }
|
|
];
|
|
|
|
// Run tests and collect results
|
|
let results = [];
|
|
let testCount = 0;
|
|
|
|
for (let test of testCases) {
|
|
testCount++;
|
|
let testName = `Test ${testCount}: ${JSON.stringify(test.input)}${test.testType ? ` (${test.testType})` : ''}`;
|
|
let passed = true;
|
|
let messages = [];
|
|
|
|
// Test encoding
|
|
let encoded = test.replacer ? nota.encode(test.input, test.replacer) : nota.encode(test.input);
|
|
if (!(encoded instanceof ArrayBuffer)) {
|
|
passed = false;
|
|
messages.push("Encode should return ArrayBuffer");
|
|
} else {
|
|
if (test.expectedHex) {
|
|
let encodedHex = bufferToHex(encoded);
|
|
if (encodedHex !== test.expectedHex.toLowerCase()) {
|
|
messages.push(
|
|
`Hex encoding differs (informational):
|
|
Expected: ${test.expectedHex}
|
|
Got: ${encodedHex}`
|
|
);
|
|
}
|
|
}
|
|
|
|
// Test decoding
|
|
let decoded = test.reviver ? nota.decode(encoded, test.reviver) : nota.decode(encoded);
|
|
let expected = test.expected || test.input;
|
|
|
|
// Normalize ArrayBuffer and special cases for comparison
|
|
if (expected instanceof ArrayBuffer)
|
|
expected = Array.from(new Uint8Array(expected));
|
|
if (decoded instanceof ArrayBuffer)
|
|
decoded = Array.from(new Uint8Array(decoded));
|
|
if (expected && (expected.private || expected.system)) {
|
|
const key = expected.private ? 'private' : 'system';
|
|
expected = { [key]: expected[key] };
|
|
}
|
|
|
|
const compareResult = deepCompare(expected, decoded);
|
|
if (!compareResult.passed) {
|
|
passed = false;
|
|
messages.push("Decoding failed:");
|
|
messages.push(...compareResult.messages);
|
|
}
|
|
}
|
|
|
|
results.push({ testName, passed, messages });
|
|
|
|
if (!passed) {
|
|
console.log(`\nDetailed Failure Report for ${testName}:`);
|
|
console.log(`Input: ${JSON.stringify(test.input)}`);
|
|
if (test.replacer) console.log(`Replacer: ${test.replacer.toString()}`);
|
|
if (test.reviver) console.log(`Reviver: ${test.reviver.toString()}`);
|
|
console.log(messages.join("\n"));
|
|
console.log("");
|
|
}
|
|
}
|
|
|
|
// Summary
|
|
console.log("\nTest Summary:");
|
|
results.forEach(result => {
|
|
console.log(`${result.testName} - ${result.passed ? "Passed" : "Failed"}`);
|
|
if (!result.passed)
|
|
console.log(result.messages)
|
|
});
|
|
|
|
let passedCount = results.filter(r => r.passed).length;
|
|
console.log(`\nResult: ${passedCount}/${testCount} tests passed`);
|
|
|
|
if (passedCount < testCount) {
|
|
console.log("Overall: FAILED");
|
|
// os.exit(1);
|
|
} else {
|
|
console.log("Overall: PASSED");
|
|
// os.exit(0);
|
|
} |