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) { log.console(`\nDetailed Failure Report for ${testName}:`); log.console(`Input: ${JSON.stringify(test.input)}`); if (test.replacer) log.console(`Replacer: ${test.replacer.toString()}`); if (test.reviver) log.console(`Reviver: ${test.reviver.toString()}`); log.console(messages.join("\n")); log.console(""); } } // Summary log.console("\nTest Summary:"); results.forEach(result => { log.console(`${result.testName} - ${result.passed ? "Passed" : "Failed"}`); if (!result.passed) log.console(result.messages) }); let passedCount = results.filter(r => r.passed).length; log.console(`\nResult: ${passedCount}/${testCount} tests passed`); if (passedCount < testCount) { log.console("Overall: FAILED"); // os.exit(1); } else { log.console("Overall: PASSED"); // os.exit(0); }