blob: 0dfd5bdcbd46f3274299aad381f5a8f93dd82a7a [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Error handling tests for GraphBinaryV4 serializers. Validates behavior for
* malformed input: invalid buffers, unknown type codes, bad value flags,
* truncated data, negative lengths, and unsupported types.
*/
import { assert } from 'chai';
import { Buffer } from 'buffer';
import ioc from '../../../lib/structure/io/binary/GraphBinary.js';
import StreamReader from '../../../lib/structure/io/binary/internals/StreamReader.js';
import { P, TextP, Traverser } from '../../../lib/process/traversal.js';
import { OptionsStrategy } from '../../../lib/process/traversal-strategy.js';
const { anySerializer, intSerializer, longSerializer, stringSerializer, listSerializer, mapSerializer, uuidSerializer, dateTimeSerializer, floatSerializer, shortSerializer, byteSerializer, bigIntegerSerializer, binarySerializer, setSerializer, enumSerializer, edgeSerializer, vertexSerializer, vertexPropertySerializer, propertySerializer, pathSerializer, markerSerializer } = ioc;
/** Helper: assert that an async call rejects with a message matching the pattern */
async function assertRejects(fn, pattern) {
try {
await fn();
assert.fail('Expected an error to be thrown');
} catch (e) {
if (pattern) assert.match(e.message, pattern);
}
}
describe('GraphBinary v4 Error Cases', () => {
describe('Buffer validation', () => {
it('undefined buffer throws error', async () => {
await assertRejects(() => anySerializer.deserialize(StreamReader.fromBuffer(undefined)));
});
it('null buffer throws error', async () => {
await assertRejects(() => anySerializer.deserialize(StreamReader.fromBuffer(null)));
});
it('non-Buffer object throws error', async () => {
await assertRejects(() => anySerializer.deserialize(StreamReader.fromBuffer('not a buffer')));
});
it('empty buffer throws error', async () => {
await assertRejects(() => anySerializer.deserialize(StreamReader.fromBuffer(Buffer.alloc(0))), /Unexpected end of buffer/);
});
it('buffer with only type_code, no value_flag throws error', async () => {
await assertRejects(() => anySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01]))), /Unexpected end of buffer/);
});
it('individual serializer with undefined buffer throws error', async () => {
await assertRejects(() => intSerializer.deserialize(StreamReader.fromBuffer(undefined)));
});
it('individual serializer with null buffer throws error', async () => {
await assertRejects(() => intSerializer.deserialize(StreamReader.fromBuffer(null)));
});
it('individual serializer with empty buffer throws error', async () => {
await assertRejects(() => intSerializer.deserialize(StreamReader.fromBuffer(Buffer.alloc(0))), /Unexpected end of buffer/);
});
});
describe('Type code errors', () => {
it('unknown type code throws error', async () => {
await assertRejects(() => anySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x99, 0x00]))), /unknown.*type_code/);
});
it('wrong type code for INT throws error', async () => {
await assertRejects(() => intSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x02, 0x00, 0x00, 0x00, 0x00, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for LONG throws error', async () => {
await assertRejects(() => longSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for STRING throws error', async () => {
await assertRejects(() => stringSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for DOUBLE throws error', async () => {
await assertRejects(() => ioc.doubleSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for BOOLEAN throws error', async () => {
await assertRejects(() => ioc.booleanSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for UUID throws error', async () => {
await assertRejects(() => uuidSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for LIST throws error', async () => {
await assertRejects(() => listSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for MAP throws error', async () => {
await assertRejects(() => mapSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for FLOAT throws error', async () => {
await assertRejects(() => floatSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x09, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for SHORT throws error', async () => {
await assertRejects(() => shortSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x27, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for BYTE throws error', async () => {
await assertRejects(() => byteSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x25, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for BIGINTEGER throws error', async () => {
await assertRejects(() => bigIntegerSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x24, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for BINARY throws error', async () => {
await assertRejects(() => binarySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x26, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for SET throws error', async () => {
await assertRejects(() => setSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0C, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for DATETIME throws error', async () => {
await assertRejects(() => dateTimeSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x05, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for ENUM throws error', async () => {
await assertRejects(() => enumSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x19, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for EDGE throws error', async () => {
await assertRejects(() => edgeSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for VERTEX throws error', async () => {
await assertRejects(() => vertexSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for VERTEXPROPERTY throws error', async () => {
await assertRejects(() => vertexPropertySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for PROPERTY throws error', async () => {
await assertRejects(() => propertySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for PATH throws error', async () => {
await assertRejects(() => pathSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
it('wrong type code for MARKER throws error', async () => {
await assertRejects(() => markerSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00]))), /unexpected.*type_code/);
});
});
describe('Value flag errors', () => {
it('invalid value_flag 0x03 for INT throws error', async () => {
await assertRejects(() => intSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x0F for STRING throws error', async () => {
await assertRejects(() => stringSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x03, 0x0F]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0xFF for LIST throws error', async () => {
await assertRejects(() => listSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x09, 0xFF]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x05 for MAP throws error', async () => {
await assertRejects(() => mapSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0A, 0x05]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x10 for DOUBLE throws error', async () => {
await assertRejects(() => ioc.doubleSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x07, 0x10]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x04 for FLOAT throws error', async () => {
await assertRejects(() => floatSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x08, 0x04]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x06 for SHORT throws error', async () => {
await assertRejects(() => shortSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x26, 0x06]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x07 for BYTE throws error', async () => {
await assertRejects(() => byteSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x24, 0x07]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x08 for BIGINTEGER throws error', async () => {
await assertRejects(() => bigIntegerSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x23, 0x08]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x09 for BINARY throws error', async () => {
await assertRejects(() => binarySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x25, 0x09]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x0A for SET throws error', async () => {
await assertRejects(() => setSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0B, 0x0A]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x0B for DATETIME throws error', async () => {
await assertRejects(() => dateTimeSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x04, 0x0B]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x0C for UUID throws error', async () => {
await assertRejects(() => uuidSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0C, 0x0C]))), /unexpected.*value_flag/);
});
it('invalid value_flag 0x0D for ENUM throws error', async () => {
await assertRejects(() => enumSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x18, 0x0D]))), /unexpected.*value_flag/);
});
it('invalid value_flag for EDGE throws error', async () => {
await assertRejects(() => edgeSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0D, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag for VERTEX throws error', async () => {
await assertRejects(() => vertexSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x11, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag for VERTEXPROPERTY throws error', async () => {
await assertRejects(() => vertexPropertySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x12, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag for PROPERTY throws error', async () => {
await assertRejects(() => propertySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0F, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag for PATH throws error', async () => {
await assertRejects(() => pathSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0E, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag for MARKER throws error', async () => {
await assertRejects(() => markerSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0xFD, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag for BOOLEAN throws error', async () => {
await assertRejects(() => ioc.booleanSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x27, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag for LONG throws error', async () => {
await assertRejects(() => longSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x02, 0x03]))), /unexpected.*value_flag/);
});
it('invalid value_flag dispatched via anySerializer throws error', async () => {
await assertRejects(() => anySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x0D]))), /unexpected.*value_flag/);
});
it('missing value_flag for INT throws error', async () => {
await assertRejects(() => intSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01]))), /Unexpected end of buffer/);
});
it('missing value_flag for STRING throws error', async () => {
await assertRejects(() => stringSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x03]))), /Unexpected end of buffer/);
});
it('missing value_flag for LIST throws error', async () => {
await assertRejects(() => listSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x09]))), /Unexpected end of buffer/);
});
it('missing value_flag for MAP throws error', async () => {
await assertRejects(() => mapSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x0A]))), /Unexpected end of buffer/);
});
});
describe('Truncated data', () => {
it('INT with only 2 of 4 value bytes throws error', async () => {
await assertRejects(() => intSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x01, 0x00, 0x00, 0x01]))), /Unexpected end of buffer/);
});
it('LONG with only 4 of 8 value bytes throws error', async () => {
await assertRejects(() => longSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]))), /Unexpected end of buffer/);
});
it('DOUBLE with only 4 of 8 value bytes throws error', async () => {
await assertRejects(() => ioc.doubleSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x07, 0x00, 0x00, 0x00, 0x00, 0x01]))), /Unexpected end of buffer/);
});
it('FLOAT with only 2 of 4 value bytes throws error', async () => {
await assertRejects(() => ioc.floatSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x08, 0x00, 0x00, 0x01]))), /Unexpected end of buffer/);
});
it('SHORT with only 1 of 2 value bytes throws error', async () => {
await assertRejects(() => ioc.shortSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x26, 0x00, 0x01]))), /Unexpected end of buffer/);
});
it('STRING with length 10 but only 3 bytes throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x03, 0x00]), // STRING, value_flag=0x00
Buffer.from([0x00, 0x00, 0x00, 0x0A]), // length=10
Buffer.from([0x41, 0x42, 0x43]) // only 3 bytes: "ABC"
]);
await assertRejects(() => stringSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('LIST with length 5 but only 1 item throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x09, 0x00]), // LIST, value_flag=0x00
Buffer.from([0x00, 0x00, 0x00, 0x05]), // length=5
Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x01]) // only 1 INT item
]);
await assertRejects(() => listSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('MAP with length 3 but only 1 entry throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x0A, 0x00]), // MAP, value_flag=0x00
Buffer.from([0x00, 0x00, 0x00, 0x03]), // length=3
Buffer.from([0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x6B, 0x65, 0x79]), // key: "key"
Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x01]) // value: 1
]);
await assertRejects(() => mapSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('UUID with only 8 of 16 bytes throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x0C, 0x00]), // UUID, value_flag=0x00
Buffer.from([0x41, 0xD2, 0xE2, 0x8A, 0x20, 0x13, 0x4E, 0x35]) // only 8 bytes
]);
await assertRejects(() => uuidSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('DATETIME with only 10 of 18 bytes throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x04, 0x00]), // DATETIME, value_flag=0x00
Buffer.from([0x07, 0xB2, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) // only 10 bytes
]);
await assertRejects(() => dateTimeSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('BOOLEAN with no value byte throws error', async () => {
await assertRejects(() => ioc.booleanSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x27, 0x00]))), /Unexpected end of buffer/);
});
it('BYTE with no value byte throws error', async () => {
await assertRejects(() => ioc.byteSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x24, 0x00]))), /Unexpected end of buffer/);
});
it('BIGINTEGER with truncated length throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x23, 0x00]), // BIGINTEGER, value_flag=0x00
Buffer.from([0x00, 0x00]) // only 2 bytes of length instead of 4
]);
await assertRejects(() => bigIntegerSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('BIGINTEGER with length=0 throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x23, 0x00]), // BIGINTEGER, value_flag=0x00
Buffer.from([0x00, 0x00, 0x00, 0x00]) // length=0
]);
await assertRejects(() => bigIntegerSerializer.deserialize(StreamReader.fromBuffer(buffer)), /length.*less than one|length.*0/);
});
it('BINARY with truncated value data throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x25, 0x00]), // BINARY, value_flag=0x00
Buffer.from([0x00, 0x00, 0x00, 0x05]), // length=5
Buffer.from([0x01, 0x02]) // only 2 bytes instead of 5
]);
await assertRejects(() => binarySerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('SET with length 5 but only 1 item throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x0B, 0x00]), // SET, value_flag=0x00
Buffer.from([0x00, 0x00, 0x00, 0x05]), // length=5
Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x01]) // only 1 INT item
]);
await assertRejects(() => setSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('ENUM with truncated elementName throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x18, 0x00]), // DIRECTION, value_flag=0x00
Buffer.from([0x03, 0x00, 0x00, 0x00, 0x00, 0x05]) // STRING with length=5 but no data
]);
await assertRejects(() => enumSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
});
describe('Negative lengths', () => {
it('STRING with negative length throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x03, 0x00]), // STRING, value_flag=0x00
Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]) // length=-1
]);
await assertRejects(() => stringSerializer.deserialize(StreamReader.fromBuffer(buffer)), /length.*less than zero/);
});
it('LIST with negative length throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x09, 0x00]), // LIST, value_flag=0x00
Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]) // length=-1
]);
await assertRejects(() => listSerializer.deserialize(StreamReader.fromBuffer(buffer)), /length.*less than zero/);
});
it('MAP with negative length throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x0A, 0x00]), // MAP, value_flag=0x00
Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]) // length=-1
]);
await assertRejects(() => mapSerializer.deserialize(StreamReader.fromBuffer(buffer)), /length.*less than zero/);
});
it('SET with negative length throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x0B, 0x00]), // SET, value_flag=0x00
Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]) // length=-1
]);
await assertRejects(() => setSerializer.deserialize(StreamReader.fromBuffer(buffer)), /length.*less than zero/);
});
it('BINARY with negative length throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x25, 0x00]), // BINARY, value_flag=0x00
Buffer.from([0xFF, 0xFF, 0xFF, 0xFF]) // length=-1
]);
await assertRejects(() => binarySerializer.deserialize(StreamReader.fromBuffer(buffer)), /length.*less than zero/);
});
});
describe('Bulk flag errors', () => {
it('LIST with bulk flag but missing bulk count data throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x09, 0x02]), // LIST, value_flag=0x02 (bulk)
Buffer.from([0x00, 0x00, 0x00, 0x01]), // length=1
Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x01]) // 1 INT item but no bulk count
]);
await assertRejects(() => listSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
it('SET with bulk flag but missing bulk count data throws error', async () => {
const buffer = Buffer.concat([
Buffer.from([0x0B, 0x02]), // SET, value_flag=0x02 (bulk)
Buffer.from([0x00, 0x00, 0x00, 0x01]), // length=1
Buffer.from([0x01, 0x00, 0x00, 0x00, 0x00, 0x01]) // 1 INT item but no bulk count
]);
await assertRejects(() => setSerializer.deserialize(StreamReader.fromBuffer(buffer)), /Unexpected end of buffer/);
});
});
describe('UnspecifiedNull errors', () => {
it('UnspecifiedNull with value_flag=0x00 throws error', async () => {
// type_code=0xFE (UNSPECIFIED_NULL), value_flag=0x00 (non-null) — invalid
await assertRejects(
() => anySerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0xFE, 0x00]))),
/UnspecifiedNull should always have value_flag=0x01/,
);
});
});
describe('Boolean value errors', () => {
it('unexpected boolean byte 0x02 throws error', async () => {
await assertRejects(
() => ioc.booleanSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0x27, 0x00, 0x02]))),
/unexpected boolean byte/,
);
});
});
describe('Marker value errors', () => {
it('unexpected marker value throws error', async () => {
// type_code=0xFD (MARKER), value_flag=0x00, value=0x01 (should be 0x00)
await assertRejects(
() => markerSerializer.deserialize(StreamReader.fromBuffer(Buffer.from([0xFD, 0x00, 0x01]))),
/unexpected marker value/,
);
});
});
describe('Serialization rejection for unsupported types', () => {
it('Symbol throws error', () => {
assert.throws(() => anySerializer.serialize(Symbol('test')), /No serializer found to support item/);
});
it('function throws error', () => {
assert.throws(() => anySerializer.serialize(() => {}), /No serializer found to support item/);
});
it('arrow function throws error', () => {
assert.throws(() => anySerializer.serialize((x) => x + 1), /No serializer found to support item/);
});
it('async function throws error', () => {
assert.throws(() => anySerializer.serialize(async () => {}), /No serializer found to support item/);
});
it('generator function throws error', () => {
assert.throws(() => anySerializer.serialize(function* () {}), /No serializer found to support item/);
});
it('class constructor throws error', () => {
class TestClass {}
assert.throws(() => anySerializer.serialize(TestClass), /No serializer found to support item/);
});
});
describe('v1-removed types serialization behavior', () => {
it('P.eq("cole") serializes as Map (v1 types fall through to MapSerializer)', () => {
// v1 P types no longer have dedicated serializers, so they serialize as Maps
const result = anySerializer.serialize(P.eq('cole'));
assert.ok(result.length > 0, 'Should serialize successfully as Map');
});
it('TextP.containing("x") serializes as Map (v1 types fall through to MapSerializer)', () => {
// v1 TextP types no longer have dedicated serializers, so they serialize as Maps
const result = anySerializer.serialize(TextP.containing('x'));
assert.ok(result.length > 0, 'Should serialize successfully as Map');
});
it('new Traverser("cole", 1) serializes as Map (v1 types fall through to MapSerializer)', () => {
// v1 Traverser types no longer have dedicated serializers, so they serialize as Maps
const result = anySerializer.serialize(new Traverser('cole', 1));
assert.ok(result.length > 0, 'Should serialize successfully as Map');
});
it('new OptionsStrategy({}) serializes as Map (v1 types fall through to MapSerializer)', () => {
// v1 OptionsStrategy types no longer have dedicated serializers, so they serialize as Maps
const result = anySerializer.serialize(new OptionsStrategy({}));
assert.ok(result.length > 0, 'Should serialize successfully as Map');
});
});
});