pickleparser
Version:
A pure Javascript implemented parser for Python pickle format
255 lines (229 loc) • 9.58 kB
text/typescript
import { Parser } from '../../src/parser';
import { basic } from './basic';
import { PROTOCOL, PROTOCOLS, caller } from './_caller';
import { NameRegistry } from '../../src/nameRegistry';
describe('basic with version', () => {
it.each(
Object.keys(basic).reduce((a: Array<[string, PROTOCOL]>, c) => {
PROTOCOLS.forEach((p) => {
a.push([c, p]);
});
return a;
}, []),
)('correctly unpickled (%s) with protocol %s', async (func, protocol) => {
const data = await caller('basic', func, protocol);
const expected = basic[func]();
const obj = new Parser().parse(data);
expect(obj).toStrictEqual(expected);
});
});
describe('klass', () => {
it('correctly unpickl class', async () => {
const expected = {
array: [1, true, false, null, 4294967295],
fruits: ['apple', 'banana', 'cherry'],
str: 'test',
};
const data = await caller('klass', 'klass');
const obj = new Parser().parse(data);
expect(obj).toMatchObject(expected);
const prototype = Object.getPrototypeOf(obj);
expect(prototype).toHaveProperty('__module__', 'klass');
expect(prototype).toHaveProperty('__name__', 'MyClass');
});
it('correctly unpickl reduce', async () => {
const expected = ['379', 'acd'];
const data = await caller('klass', 'reduce');
const obj = new Parser().parse<{
args: typeof expected;
}>(data);
expect(obj.args).toStrictEqual(expected);
const prototype = Object.getPrototypeOf(obj);
expect(prototype).toHaveProperty('__module__', 'klass');
expect(prototype).toHaveProperty('__name__', 'Reduce');
});
it('correctly unpickl with customized reduce', async () => {
const expected = ['379', 'acd'].join(',');
const data = await caller('klass', 'reduce');
const obj = new Parser({
nameResolver: {
resolve:
() =>
(...args) =>
args.join(','),
},
}).parse(data);
expect(obj).toStrictEqual(expected);
});
it('with NameRegistry', async () => {
class MyClass {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
array: any[] = [];
fruits: string[] = [];
str: string | undefined;
}
const expected = new MyClass();
expected.array = [1, true, false, null, 4294967295];
expected.fruits = ['apple', 'banana', 'cherry'];
expected.str = 'test';
const registry = new NameRegistry().register('klass', 'MyClass', MyClass);
const data = await caller('klass', 'klass');
const obj = new Parser({
nameResolver: registry,
}).parse(data);
expect(obj).toStrictEqual(expected);
});
});
describe('long', () => {
it('correctly unpickl long4', async () => {
const expected =
'398975380292520334652879605459872453583337697310312075368132832107577484344336733631267656030491697975730319706482065334076861898105601071965378874928385172947532987811819170262577671821213107453864961626619206677733226746811432113436292476143879109827341785450751168773699095642803230314850775984760865060210698176217969616820780411226838820532294252280967457872536334204782734733250992661824578272424009848363696719993178605177831220265480726240392211861785871121272419902398980354868722930075005775349612053991637884090384318432325292289645358976894389564741519731777181442461757394830856205901222601730755928883177016176597856688472084971520';
const data = await caller('long', 'long4');
const obj = new Parser().parse<bigint>(data);
expect(obj.toString()).toStrictEqual(expected);
});
});
describe('protocol5', () => {
it('correctly unpickl bytearray8', async () => {
const expected = Buffer.from([1, 2, 3]);
const data = await caller('protocol5', 'bytearray8');
const obj = new Parser().parse<Buffer>(data);
expect(obj).toStrictEqual(expected);
});
it('correctly unpickl next_buffer', async () => {
const expected = 123;
const data = await caller('protocol5', 'next_buffer');
const obj = new Parser({
buffers: (function* () {
yield expected;
})(),
}).parse(data);
expect(obj).toStrictEqual(expected);
});
it('correctly unpickl multi_next_buffer', async () => {
const expected = [123, 'str'];
const data = await caller('protocol5', 'multi_next_buffer');
const obj = new Parser({
buffers: expected.values(),
}).parse(data);
expect(obj).toStrictEqual(expected);
});
it('correctly unpickl readonly_buffer', async () => {
const expected = 123;
const data = await caller('protocol5', 'readonly_buffer');
const obj = new Parser({
buffers: (function* () {
yield expected;
})(),
}).parse(data);
expect(obj).toStrictEqual(expected);
});
it('correctly unpickl next_buffer_and_readonly_buffer', async () => {
const expected = [123, [1, '22', null]];
const data = await caller('protocol5', 'next_buffer_and_readonly_buffer');
const obj = new Parser({
buffers: expected.values(),
}).parse(data);
expect(obj).toStrictEqual(expected);
});
it('correctly unpickl next_buffer_with_reduce_ex', async () => {
class mybytearray {
public args: number[];
constructor(args: number[]) {
this.args = args;
}
static __reduce_ex__(args: number[]) {
return new mybytearray(args);
}
}
const externalData = [1, 2, 3, 4];
const expected = new mybytearray(externalData);
const registry = new NameRegistry();
registry.register('protocol5', 'mybytearray', mybytearray.__reduce_ex__);
const data = await caller('protocol5', 'next_buffer_with_reduce_ex');
const obj = new Parser({
nameResolver: registry,
buffers: (function* () {
yield externalData;
})(),
}).parse<mybytearray>(data);
expect(obj).toStrictEqual(expected);
});
});
describe('dict', () => {
it.each(PROTOCOLS)('correctly unpickl emptydict', async (protocol) => {
const data = await caller('dict', 'emptydict', protocol);
const obj = new Parser().parse(data);
expect(obj).toStrictEqual({});
});
it.each(PROTOCOLS)('correctly unpickl emptydict with Map (protocol: %d)', async (protocol) => {
const data = await caller('dict', 'emptydict', protocol);
const obj = new Parser({
unpicklingTypeOfDictionary: 'Map',
}).parse(data);
expect(obj).toStrictEqual(new Map());
});
it.each(PROTOCOLS)('correctly unpickl dict w/ data', async (protocol) => {
const data = await caller('dict', 'dict1', protocol);
const obj = new Parser().parse(data);
expect(obj).toStrictEqual({
key: 'foo',
});
});
it.each(PROTOCOLS)('correctly unpickl dict w/ multidata', async (protocol) => {
const data = await caller('dict', 'dict2', protocol);
const obj = new Parser().parse(data);
expect(obj).toStrictEqual({
key: 'foo',
key2: 123,
key3: {},
});
});
});
describe('set', () => {
it.each(['0', '1', '2'] as const)('correctly unpickl emptyset with p/ 0,1,2', async (protocol) => {
const registry = new NameRegistry().register('__builtin__', 'set', Array.from);
const data = await caller('set', 'emptyset', protocol);
const obj = new Parser({
nameResolver: registry,
}).parse(data);
expect(obj).toStrictEqual([]);
});
it('correctly unpickl emptyset with p/ 3', async () => {
const registry = new NameRegistry().register('builtins', 'set', Array.from);
const data = await caller('set', 'emptyset', '3');
const obj = new Parser({
nameResolver: registry,
unpicklingTypeOfSet: 'Set',
}).parse(data);
expect(obj).toStrictEqual([]);
});
it('correctly unpickl emptyset with p/ 5', async () => {
const data = await caller('set', 'emptyset', '5');
const obj = new Parser({
unpicklingTypeOfSet: 'Set',
}).parse(data);
expect(obj).toStrictEqual(new Set());
});
it('correctly unpickl emptyset with p/ 5 and array', async () => {
const data = await caller('set', 'emptyset', '5');
const obj = new Parser({
unpicklingTypeOfSet: 'array',
}).parse(data);
expect(obj).toStrictEqual([]);
});
it('correctly unpickl set with data with p/ 5', async () => {
const data = await caller('set', 'set1', '5');
const obj = new Parser({
unpicklingTypeOfSet: 'Set',
}).parse(data);
expect(obj).toStrictEqual(new Set(['apple', 'banana', 'cherry']));
});
it('correctly unpickl frozenset', async () => {
const data = await caller('set', 'frozenset1');
const obj = new Parser({
unpicklingTypeOfSet: 'Set',
}).parse(data);
expect(obj).toStrictEqual(new Set([1, 2]));
});
});