@lichtblick/cdr
Version:
Common Data Representation serialization and deserialization library
282 lines • 13.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require(".");
const CdrReader_1 = require("./CdrReader");
const CdrWriter_1 = require("./CdrWriter");
// Example tf2_msgs/TFMessage
const tf2_msg__TFMessage = "0001000001000000cce0d158f08cf9060a000000626173655f6c696e6b000000060000007261646172000000ae47e17a14ae0e4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f03f";
describe("CdrReader", () => {
it("parses an example tf2_msgs/TFMessage message", () => {
const data = Uint8Array.from(Buffer.from(tf2_msg__TFMessage, "hex"));
const reader = new CdrReader_1.CdrReader(data);
expect(reader.decodedBytes).toBe(4);
// geometry_msgs/TransformStamped[] transforms
expect(reader.sequenceLength()).toEqual(1);
// std_msgs/Header header
// time stamp
expect(reader.uint32()).toEqual(1490149580); // uint32 sec
expect(reader.uint32()).toEqual(117017840); // uint32 nsec
expect(reader.string()).toEqual("base_link"); // string frame_id
expect(reader.string()).toEqual("radar"); // string child_frame_id
// geometry_msgs/Transform transform
// geometry_msgs/Vector3 translation
expect(reader.float64()).toBeCloseTo(3.835); // float64 x
expect(reader.float64()).toBeCloseTo(0); // float64 y
expect(reader.float64()).toBeCloseTo(0); // float64 z
// geometry_msgs/Quaternion rotation
expect(reader.float64()).toBeCloseTo(0); // float64 x
expect(reader.float64()).toBeCloseTo(0); // float64 y
expect(reader.float64()).toBeCloseTo(0); // float64 z
expect(reader.float64()).toBeCloseTo(1); // float64 w
expect(reader.offset).toBe(data.length);
expect(reader.kind).toBe(_1.EncapsulationKind.CDR_LE);
expect(reader.decodedBytes).toBe(data.length);
expect(reader.byteLength).toBe(data.length);
});
it("parses an example rcl_interfaces/ParameterEvent", () => {
const data = Uint8Array.from(Buffer.from("00010000a9b71561a570ea01110000002f5f726f7332636c695f33373833363300000000010000000d0000007573655f73696d5f74696d650001000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000", "hex"));
const reader = new CdrReader_1.CdrReader(data);
// builtin_interfaces/Time stamp
expect(reader.uint32()).toEqual(1628813225); // uint32 sec
expect(reader.uint32()).toEqual(32141477); // uint32 nsec
// string node
expect(reader.string()).toEqual("/_ros2cli_378363");
// Parameter[] new_parameters
expect(reader.sequenceLength()).toEqual(1);
expect(reader.string()).toEqual("use_sim_time"); // string name
// ParameterValue value
expect(reader.uint8()).toEqual(1); // uint8 type
expect(reader.int8()).toEqual(0); // bool bool_value
expect(reader.int64()).toEqual(0n); // int64 integer_value
expect(reader.float64()).toEqual(0); // float64 double_value
expect(reader.string()).toEqual(""); // string string_value
expect(reader.int8Array()).toEqual(new Int8Array()); // byte[] byte_array_value
expect(reader.uint8Array()).toEqual(new Uint8Array()); // bool[] bool_array_value
expect(reader.int64Array()).toEqual(new BigInt64Array()); // int64[] integer_array_value
expect(reader.float64Array()).toEqual(new Float64Array()); // float64[] double_array_value
expect(reader.stringArray()).toEqual([]); // string[] string_array_value
// Parameter[] changed_parameters
expect(reader.sequenceLength()).toEqual(0);
// Parameter[] deleted_parameters
expect(reader.sequenceLength()).toEqual(0);
expect(reader.offset).toBe(data.length);
});
it("reads big endian values", () => {
const data = Uint8Array.from(Buffer.from("000100001234000056789abcdef0000000000000", "hex"));
const reader = new CdrReader_1.CdrReader(data);
expect(reader.uint16BE()).toEqual(0x1234);
expect(reader.uint32BE()).toEqual(0x56789abc);
expect(reader.uint64BE()).toEqual(0xdef0000000000000n);
});
it("seeks to absolute and relative positions", () => {
const data = Uint8Array.from(Buffer.from(tf2_msg__TFMessage, "hex"));
const reader = new CdrReader_1.CdrReader(data);
reader.seekTo(4 + 4 + 4 + 4 + 4 + 10 + 4 + 6);
expect(reader.float64()).toBeCloseTo(3.835);
// This works due to aligned reads
reader.seekTo(4 + 4 + 4 + 4 + 4 + 10 + 4 + 3);
expect(reader.float64()).toBeCloseTo(3.835);
reader.seek(-8);
expect(reader.float64()).toBeCloseTo(3.835);
expect(reader.float64()).toBeCloseTo(0);
});
it.each([
["int8Array", "int8", [-128, 127, 3]],
["uint8Array", "uint8", [0, 255, 3]],
["int16Array", "int16", [-32768, 32767, -3]],
["uint16Array", "uint16", [0, 65535, 3]],
["int32Array", "int32", [-2147483648, 2147483647, 3]],
["uint32Array", "uint32", [0, 4294967295, 3]],
])("reads int %s", (getter, setter, expected) => {
const writer = new CdrWriter_1.CdrWriter();
writeArray(writer, setter, expected);
const reader = new CdrReader_1.CdrReader(writer.data);
const array = reader[getter](reader.sequenceLength());
expect(Array.from(array.values())).toEqual(expected);
});
it.each([
["float32Array", "float32", [-3.835, 0, Math.PI], 6],
["float64Array", "float64", [-3.835, 0, Math.PI], 15],
// eslint-disable-next-line @typescript-eslint/no-loss-of-precision
["float64Array", "float64", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -0.123456789121212121212], 15],
])("reads float %s", (getter, setter, expected, numDigits) => {
const writer = new CdrWriter_1.CdrWriter();
writeArray(writer, setter, expected);
const reader = new CdrReader_1.CdrReader(writer.data);
const array = reader[getter](reader.sequenceLength());
expect(array).toBeDefined();
expectToBeCloseToArray(Array.from(array.values()), expected, numDigits);
});
it.each([
["int64Array", "int64", [-9223372036854775808n, 9223372036854775807n, 3n]],
["uint64Array", "uint64", [0n, 18446744073709551615n, 3n]],
["uint64Array", "uint64", [1n, 2n, 3n, 4n, 5n, 6n, 7n, 8n, 9n, 10n, 11n, 12n]],
])("reads %s", (getter, setter, expected) => {
const writer = new CdrWriter_1.CdrWriter();
writeBigArray(writer, setter, expected);
const reader = new CdrReader_1.CdrReader(writer.data);
const array = reader[getter](reader.sequenceLength());
expect(Array.from(array.values())).toEqual(expected);
});
it("reads multiple arrays", () => {
const writer = new CdrWriter_1.CdrWriter();
writer.float32Array([5.5, 6.5], true);
writer.float32Array([7.5, 8.5], true);
const reader = new CdrReader_1.CdrReader(writer.data);
expect(reader).toBeDefined();
expectToBeCloseToArray(Array.from(reader.float32Array().values()), [5.5, 6.5], 6);
expectToBeCloseToArray(Array.from(reader.float32Array().values()), [7.5, 8.5], 6);
expect(reader.offset).toBe(writer.data.length);
});
it("reads stringArray", () => {
const writer = new CdrWriter_1.CdrWriter();
writer.sequenceLength(3);
writer.string("abc");
writer.string("");
writer.string("test string");
const reader = new CdrReader_1.CdrReader(writer.data);
expect(reader.stringArray(reader.sequenceLength())).toEqual(["abc", "", "test string"]);
expect(reader.offset).toBe(writer.data.length);
});
it.each([
"int8Array",
"uint8Array",
"int16Array",
"uint16Array",
"int32Array",
"uint32Array",
"int64Array",
"uint64Array",
"float32Array",
"float64Array",
])("handles alignment correctly for empty %s", (key) => {
const writer = new CdrWriter_1.CdrWriter();
writer[key]([], true);
expect(writer.data.length).toBe(8);
const reader = new CdrReader_1.CdrReader(writer.data);
expect(reader[key]().length).toEqual(0);
expect(reader.offset).toEqual(writer.data.length);
});
it.each([
[true, 100, 1],
[false, 200, 2],
[false, 1028, 4],
[false, 65, 8],
[true, 63, 9],
[false, 127, 0xffff],
[false, 127, 0x1ffff], // extended PID
[true, 700000, 0xffff], // extended PID
[false, 700000, 0x1ffff], // extended PID
])("round trips XCDR1 parameter header values with mustUnderstand: %d, id: %d, and size: %d", (mustUnderstand, id, objectSize) => {
const writer = new CdrWriter_1.CdrWriter({ kind: _1.EncapsulationKind.PL_CDR_BE });
writer.emHeader(mustUnderstand, id, objectSize);
const reader = new CdrReader_1.CdrReader(writer.data);
const header = reader.emHeader();
expect(header).toEqual({
objectSize,
id,
mustUnderstand,
});
});
it("converts extended PID", () => {
const buffer = new Uint8Array(Buffer.from("00030000017f080064000000400000000", "hex"));
const reader = new CdrReader_1.CdrReader(buffer);
expect(reader.emHeader()).toMatchInlineSnapshot(`
{
"id": 100,
"mustUnderstand": true,
"objectSize": 64,
}
`);
});
it("takes a length when reading a string and doesn't read the sequence length again", () => {
const writer = new CdrWriter_1.CdrWriter();
const testString = "test";
writer.string(testString);
const reader = new CdrReader_1.CdrReader(writer.data);
const length = reader.sequenceLength();
expect(reader.string(length)).toEqual("test");
});
it("returns readSentinelHeader==true if the emHeader read a sentinel header", () => {
const writer = new CdrWriter_1.CdrWriter({ kind: _1.EncapsulationKind.PL_CDR_LE });
writer.sentinelHeader();
const reader = new CdrReader_1.CdrReader(writer.data);
const emHeader = reader.emHeader();
expect(emHeader.readSentinelHeader).toEqual(true);
});
it("errors when expecting to read a sentinel header but receives non-sentinel_PID value", () => {
const writer = new CdrWriter_1.CdrWriter({ kind: _1.EncapsulationKind.PL_CDR_LE });
writer.emHeader(false, 100, 4);
const reader = new CdrReader_1.CdrReader(writer.data);
expect(() => {
reader.sentinelHeader();
}).toThrow(/Expected sentinel_pid/i);
});
it.each([[1], [2], [4], [8], [0x7fffffff]])("round trips DHEADER values of size %d", (objectSize) => {
const writer = new CdrWriter_1.CdrWriter({ kind: _1.EncapsulationKind.DELIMITED_CDR2_LE });
writer.dHeader(objectSize);
const reader = new CdrReader_1.CdrReader(writer.data);
expect(reader.dHeader()).toEqual(objectSize);
});
it.each([
[true, 100, 1],
[false, 200, 2],
[false, 1028, 4],
[false, 65, 8],
[true, 63, 9],
[false, 127, 0xffffffff],
])("round trips EMHEADER values with mustUnderstand: %d, id: %d, and size: %d without lengthCode", (mustUnderstand, id, objectSize) => {
const writer = new CdrWriter_1.CdrWriter({ kind: _1.EncapsulationKind.PL_CDR2_LE });
writer.emHeader(mustUnderstand, id, objectSize);
const reader = new CdrReader_1.CdrReader(writer.data);
// don't want to test default assignment of length code here
const { lengthCode, ...headerNoLengthCode } = reader.emHeader();
expect(headerNoLengthCode).toEqual({
objectSize,
id,
mustUnderstand,
});
// should be defined because of CDR2
expect(lengthCode).toBeDefined();
});
it.each([
[true, 100, 1, 0], // LC 0, 1 byte
[false, 200, 2, 1], // LC 1, 2 bytes
[false, 1028, 4, 2], // LC 2, 4 bytes
[false, 65, 8, 3], // LC 3, 8 bytes
[true, 63, 9, 4], // LC 4, any size
[false, 127, 0xffffffff, 5], // LC 5, any size
[false, 65, 12, 6], // LC 6, multiple of 4 bytes
[false, 65, 32, 7], // LC 7, multiple of 8 bytes
])("round trips EMHEADER values with mustUnderstand: %d, id: %d, size: %d, and lengthCode: %d", (mustUnderstand, id, objectSize, lengthCode) => {
const writer = new CdrWriter_1.CdrWriter({ kind: _1.EncapsulationKind.PL_CDR2_LE });
writer.emHeader(mustUnderstand, id, objectSize, lengthCode);
const reader = new CdrReader_1.CdrReader(writer.data);
const header = reader.emHeader();
expect(header).toEqual({
objectSize,
id,
mustUnderstand,
lengthCode,
});
});
});
function writeArray(writer, setter, array) {
writer.sequenceLength(array.length);
for (const value of array) {
writer[setter](value);
}
}
function writeBigArray(writer, setter, array) {
writer.sequenceLength(array.length);
for (const value of array) {
writer[setter](value);
}
}
function expectToBeCloseToArray(actual, expected, numDigits) {
expect(actual.length).toBe(expected.length);
actual.forEach((x, i) => {
expect(x).toBeCloseTo(expected[i], numDigits);
});
}
//# sourceMappingURL=CdrReader.test.js.map