fix(thrift): preserve inner object structure for LIST, SET, and MAP to ensure correct round-tripping

This commit is contained in:
engin0223 2026-06-27 12:58:51 +03:00
parent 4a9fd9016e
commit b88ef53b78
2 changed files with 73 additions and 8 deletions

View File

@ -193,29 +193,34 @@ export function readBinaryType(data, offset, type) {
case 13: { // MAP
const keyType = data.getUint8(offset++);
const valType = data.getUint8(offset++);
const keyTypeName = getBinaryTypeName(keyType);
const valTypeName = getBinaryTypeName(valType);
const mapSize = data.getInt32(offset);
offset += 4;
value = [];
const elements = [];
for (let i = 0; i < mapSize; i++) {
const k = readBinaryType(data, offset, keyType);
offset = k.offset;
const v = readBinaryType(data, offset, valType);
offset = v.offset;
value.push({ key: k.value, val: v.value });
elements.push({ key: k.value, val: v.value });
}
value = { keyType: keyTypeName, valType: valTypeName, elements: elements };
break;
}
case 14: // SET
case 15: { // LIST
const elemType = data.getUint8(offset++);
const elemTypeName = getBinaryTypeName(elemType);
const listSize = data.getInt32(offset);
offset += 4;
value = [];
const elements = [];
for (let i = 0; i < listSize; i++) {
const elem = readBinaryType(data, offset, elemType);
value.push(elem.value);
elements.push(elem.value);
offset = elem.offset;
}
value = { elementType: elemTypeName, elements: elements };
break;
}
default:
@ -298,10 +303,18 @@ export function readCompactType(data, offset, type) {
value = data.getInt8(offset++);
break;
case 4: // I16
varintParsed = readVarint(data, offset);
value = Number(fromZigZag(varintParsed.value));
offset = varintParsed.offset;
break;
case 5: // I32
varintParsed = readVarint(data, offset);
value = Number(fromZigZag(varintParsed.value));
offset = varintParsed.offset;
break;
case 6: // I64
varintParsed = readVarint(data, offset);
value = fromZigZag(varintParsed.value); // Decodes ZigZag
value = fromZigZag(varintParsed.value).toString();
offset = varintParsed.offset;
break;
case 7: // DOUBLE

View File

@ -28,7 +28,7 @@ TestRegister.addTests([
// STOP: 00
expectedOutput: "08 00 01 00 00 05 39 0b 00 02 00 00 00 04 54 65 73 74 02 00 03 01 00",
recipeConfig: [
{ op: "Thrift Serialize", args: ["TBinaryProtocol"] },
{ op: "Thrift Serialize", args: [] },
{ op: "To Hex", args: ["Space", 0] }
]
},
@ -50,7 +50,30 @@ TestRegister.addTests([
// STOP: 00
expectedOutput: "0f 00 01 08 00 00 00 02 00 00 00 0a 00 00 00 14 00",
recipeConfig: [
{ op: "Thrift Serialize", args: ["TBinaryProtocol"] },
{ op: "Thrift Serialize", args: [] },
{ op: "To Hex", args: ["Space", 0] }
]
},
{
name: "Thrift Serialize: TBinaryProtocol (Set of BINARY)",
input: JSON.stringify({
"field_1": {
"type": "SET",
"value": {
"elementType": "BINARY",
"elements": ["a", "b"]
}
}
}),
// Hex breakdown:
// Field 1 (SET): 0e 00 01
// Element Type (BINARY = 0b), Size (2 = 00 00 00 02)
// Values: 00 00 00 01 61, 00 00 00 01 62
// STOP: 00
expectedOutput: "0e 00 01 0b 00 00 00 02 00 00 00 01 61 00 00 00 01 62 00",
recipeConfig: [
{ op: "Thrift Serialize", args: [] },
{ op: "To Hex", args: ["Space", 0] }
]
},
@ -77,7 +100,10 @@ TestRegister.addTests([
expectedOutput: formatJson({
"field_1": {
"type": "LIST",
"value": [10, 20]
"value": {
"elementType": "I32",
"elements": [10, 20]
}
}
}),
recipeConfig: [
@ -132,5 +158,31 @@ TestRegister.addTests([
{ "op": "Thrift Serialize", "args": [] },
{ "op": "To Hex", "args": ["Space", 0] }
]
},
{
name: "Thrift Deserialize/Serialize: TBinaryProtocol Set round-trip",
// Validates that a TBinaryProtocal SET is successfully deserialised
// and that the result can be Serialized back into the original binary data
input: "0e 00 01 0b 00 00 00 02 00 00 00 01 61 00 00 00 01 62 00",
expectedOutput: "0e 00 01 0b 00 00 00 02 00 00 00 01 61 00 00 00 01 62 00",
recipeConfig: [
{ "op": "From Hex", "args": ["Auto"] },
{ "op": "Thrift Deserialize", "args": ["TBinaryProtocol"] },
{ "op": "Thrift Serialize", "args": [] },
{ "op": "To Hex", "args": ["Space", 0] }
]
},
{
name: "Thrift Deserialize/Serialize: TBinaryProtocol Map round-trip",
// Validates that a TBinaryProtocal MAP is successfully deserialised
// and that the result can be Serialized back into the original binary data
input: "0d 00 01 08 0b 00 00 00 01 00 00 00 01 00 00 00 01 61 00",
expectedOutput: "0d 00 01 08 0b 00 00 00 01 00 00 00 01 00 00 00 01 61 00",
recipeConfig: [
{ "op": "From Hex", "args": ["Auto"] },
{ "op": "Thrift Deserialize", "args": ["TBinaryProtocol"] },
{ "op": "Thrift Serialize", "args": [] },
{ "op": "To Hex", "args": ["Space", 0] }
]
}
]);