hyparquet-writer/test/thrift.test.js

111 lines
3.7 KiB
JavaScript
Raw Permalink Normal View History

2025-03-25 17:27:15 +00:00
import { deserializeTCompactProtocol } from 'hyparquet/src/thrift.js'
import { describe, expect, it } from 'vitest'
import { serializeTCompactProtocol } from '../src/thrift.js'
2025-04-08 06:14:48 +00:00
import { ByteWriter } from '../src/bytewriter.js'
2025-10-23 17:46:27 +00:00
import { logicalType } from '../src/metadata.js'
2025-03-25 17:27:15 +00:00
/**
* Utility to decode a Thrift-serialized buffer and return the parsed object.
* @param {ArrayBuffer} buf
* @returns {Record<string, any>}
*/
function roundTripDeserialize(buf) {
const view = new DataView(buf)
const reader = { view, offset: 0 }
return deserializeTCompactProtocol(reader)
}
describe('serializeTCompactProtocol', () => {
it('serializes basic types correctly', () => {
const data = {
field_1: true, // BOOL -> TRUE
field_2: false, // BOOL -> FALSE
field_3: 127, // BYTE / I32
field_4: 0x7fff, // I16 / I32
field_5: 0x7fffffff, // I32
field_6: BigInt('0x7fffffffffffffff'), // I64
field_7: 123.456, // DOUBLE
2025-04-04 00:00:46 +00:00
field_8: 'Hello, Thrift!',
field_9: new TextEncoder().encode('Hello, Thrift!'),
2025-03-25 17:27:15 +00:00
}
2025-04-08 06:14:48 +00:00
const writer = new ByteWriter()
2025-03-25 17:27:15 +00:00
serializeTCompactProtocol(writer, data)
2025-10-23 17:46:27 +00:00
const result = roundTripDeserialize(writer.getBuffer())
2025-03-25 17:27:15 +00:00
expect(result.field_1).toBe(true)
expect(result.field_2).toBe(false)
expect(result.field_3).toBe(127)
expect(result.field_4).toBe(0x7fff)
expect(result.field_5).toBe(0x7fffffff)
expect(result.field_6).toBe(BigInt('0x7fffffffffffffff'))
expect(result.field_7).toBeCloseTo(123.456)
// Decode the binary back into a string
2025-04-04 00:00:46 +00:00
const decoder = new TextDecoder()
expect(decoder.decode(result.field_8)).toBe('Hello, Thrift!')
expect(decoder.decode(result.field_9)).toBe('Hello, Thrift!')
2025-03-25 17:27:15 +00:00
})
it('serializes a nested STRUCT and LIST of booleans', () => {
const data = {
field_1: {
field_1: 42,
field_2: {
field_1: true,
field_2: false,
},
},
// List of booleans
field_2: [true, false, true, false],
}
2025-04-08 06:14:48 +00:00
const writer = new ByteWriter()
2025-03-25 17:27:15 +00:00
serializeTCompactProtocol(writer, data)
2025-10-23 17:46:27 +00:00
const result = roundTripDeserialize(writer.getBuffer())
2025-03-25 17:27:15 +00:00
expect(result.field_1.field_1).toBe(42)
expect(result.field_1.field_2.field_1).toBe(true)
expect(result.field_1.field_2.field_2).toBe(false)
expect(result.field_2).toEqual([true, false, true, false])
})
it('handles empty object (only STOP)', () => {
const data = {}
2025-04-08 06:14:48 +00:00
const writer = new ByteWriter()
2025-03-25 17:27:15 +00:00
serializeTCompactProtocol(writer, data)
2025-10-23 17:46:27 +00:00
const arr = new Uint8Array(writer.getBuffer())
2025-03-25 17:27:15 +00:00
// The entire buffer should just be [0x00] = STOP
expect(arr).toEqual(new Uint8Array([0x00]))
// Round-trip: should deserialize to an empty object
2025-10-23 17:46:27 +00:00
const result = roundTripDeserialize(writer.getBuffer())
2025-03-25 17:27:15 +00:00
expect(result).toEqual({})
})
it('throws on non-monotonic field IDs', () => {
const invalidData = {
field_2: 2,
field_1: 1, // field_1 is out of order (less than field_2)
}
2025-04-08 06:14:48 +00:00
const writer = new ByteWriter()
2025-03-25 17:27:15 +00:00
expect(() => serializeTCompactProtocol(writer, invalidData)).toThrow()
})
2025-10-23 17:46:27 +00:00
it('serializes field IDs with gaps larger than 15', () => {
const data = { field_1: 1, field_17: 17 }
const writer = new ByteWriter()
serializeTCompactProtocol(writer, data)
const result = roundTripDeserialize(writer.getBuffer())
expect(result.field_1).toBe(1)
expect(result.field_17).toBe(17)
})
it('serializes GEOMETRY logicalType struct with field_17', () => {
const data = { field_1: logicalType({ type: 'GEOMETRY' }) }
const writer = new ByteWriter()
serializeTCompactProtocol(writer, data)
const result = roundTripDeserialize(writer.getBuffer())
expect(result.field_1.field_17).toEqual({})
})
2025-03-25 17:27:15 +00:00
})