Files
mc-bot/test/packets.test.js
2026-08-22 11:09:05 -05:00

120 lines
3.7 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert');
const {
encodeVarInt,
parseVarInt,
encodeString,
readString,
buildPacket,
buildMCFrame,
parseMCFrame,
drainMCFrames,
} = require('../src/bot/packets');
test('encodeVarInt: 0', () => {
assert.deepStrictEqual([...encodeVarInt(0)], [0x00]);
});
test('encodeVarInt: 127', () => {
assert.deepStrictEqual([...encodeVarInt(127)], [0x7F]);
});
test('encodeVarInt: 128', () => {
assert.deepStrictEqual([...encodeVarInt(128)], [0x80, 0x01]);
});
test('encodeVarInt: 16383', () => {
assert.deepStrictEqual([...encodeVarInt(16383)], [0xFF, 0x7F]);
});
test('encodeVarInt: 16384', () => {
assert.deepStrictEqual([...encodeVarInt(16384)], [0x80, 0x80, 0x01]);
});
test('encodeVarInt: 2^31-1', () => {
assert.deepStrictEqual([...encodeVarInt(0x7FFFFFFF)], [0xFF, 0xFF, 0xFF, 0xFF, 0x07]);
});
test('parseVarInt: round-trip', () => {
for (const v of [0, 1, 127, 128, 255, 16383, 16384, 2 ** 31 - 1]) {
const buf = encodeVarInt(v);
const r = parseVarInt(buf, 0);
assert.strictEqual(r.value, v, `round-trip ${v}`);
assert.strictEqual(r.bytesRead, buf.length, `bytes ${v}`);
}
});
test('parseVarInt: incomplete returns 0 bytes', () => {
const buf = Buffer.from([0x80]);
const r = parseVarInt(buf, 0);
assert.strictEqual(r.bytesRead, 0);
});
test('encodeString/readString: ASCII', () => {
const s = 'Hello';
const buf = encodeString(s);
const r = readString(buf, 0);
assert.strictEqual(r.value, s);
assert.strictEqual(r.bytesRead, buf.length);
});
test('encodeString/readString: UTF-8 multibyte', () => {
const s = 'héllo★world';
const buf = encodeString(s);
const r = readString(buf, 0);
assert.strictEqual(r.value, s);
assert.strictEqual(r.bytesRead, buf.length);
});
test('buildPacket: id + data', () => {
const buf = buildPacket(0x02, encodeString('hi'));
assert.strictEqual(buf[0], 0x02);
assert.strictEqual(buf[1], 2);
assert.strictEqual(buf[2], 0x68);
assert.strictEqual(buf[3], 0x69);
});
test('buildMCFrame + parseMCFrame round-trip', () => {
const frame = buildMCFrame(0x1F, Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]));
const r = parseMCFrame(frame, 0);
assert.strictEqual(r.complete, true);
assert.strictEqual(r.packetId, 0x1F);
assert.deepStrictEqual([...r.data], [1, 2, 3, 4, 5, 6, 7, 8]);
assert.strictEqual(r.bytesRead, frame.length);
});
test('parseMCFrame: incomplete returns complete=false', () => {
const frame = buildMCFrame(0x1F, Buffer.from([1, 2, 3]));
const partial = frame.slice(0, frame.length - 2);
const r = parseMCFrame(partial, 0);
assert.strictEqual(r.complete, false);
assert.strictEqual(r.bytesRead, 0);
});
test('drainMCFrames: consumes multiple', () => {
const f1 = buildMCFrame(0x1F, Buffer.from([0xAA, 0xBB]));
const f2 = buildMCFrame(0x23, Buffer.from([0x01]));
const f3 = buildMCFrame(0x2F, Buffer.alloc(33));
const combined = Buffer.concat([f1, f2, f3]);
const seen = [];
const { consumed, frames } = drainMCFrames(combined, (id, data) => seen.push({ id, data }));
assert.strictEqual(consumed, combined.length);
assert.strictEqual(frames, 3);
assert.strictEqual(seen[0].id, 0x1F);
assert.strictEqual(seen[1].id, 0x23);
assert.strictEqual(seen[2].id, 0x2F);
});
test('drainMCFrames: partial at end', () => {
const f1 = buildMCFrame(0x1F, Buffer.from([0xAA]));
const f2 = buildMCFrame(0x23, Buffer.from([0x01]));
const partial = Buffer.concat([f1, f2]).slice(0, f1.length + 2);
const seen = [];
const { consumed, frames } = drainMCFrames(partial, (id, data) => seen.push({ id }));
assert.strictEqual(frames, 1);
assert.strictEqual(seen[0].id, 0x1F);
assert.strictEqual(consumed, f1.length);
});