| /* |
| * 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. |
| */ |
| |
| import Fory, { |
| Type, |
| BFloat16Array, |
| BoolArray, |
| Float16Array, |
| ForyFloat16Array, |
| } from '../packages/core/index'; |
| import { TypeId } from '../packages/core/lib/type'; |
| import { describe, expect, test } from '@jest/globals'; |
| import * as beautify from 'js-beautify'; |
| |
| describe('array', () => { |
| test('should distinguish list and dense array schema builders', () => { |
| expect(Type.list(Type.int32()).typeId).toBe(TypeId.LIST); |
| expect(Type.int32Array().typeId).toBe(TypeId.INT32_ARRAY); |
| expect(Type.uint8Array().typeId).toBe(TypeId.UINT8_ARRAY); |
| expect(Type.boolArray().typeId).toBe(TypeId.BOOL_ARRAY); |
| }); |
| |
| test('should expose dense arrays only through element-specific builders', () => { |
| expect((Type as Record<string, unknown>).array).toBeUndefined(); |
| expect(() => Type.map(Type.uint8Array(), Type.string())).toThrow('map key'); |
| }); |
| |
| test('should array work', () => { |
| |
| |
| const typeinfo = Type.struct({ |
| typeName: "example.bar" |
| }, { |
| c: Type.list(Type.struct({ |
| typeName: "example.foo" |
| }, { |
| a: Type.string() |
| })) |
| }); |
| const fory = new Fory({ compatible: false, ref: true, hooks: { |
| afterCodeGenerated: (code: string) => { |
| return beautify.js(code, { indent_size: 2, space_in_empty_paren: true, indent_empty_lines: true }); |
| } |
| } }); |
| const { serialize, deserialize } = fory.register(typeinfo); |
| const o = { a: "123" }; |
| expect(deserialize(serialize({ c: [o, o] }))).toEqual({ c: [o, o] }) |
| }); |
| test('should typedarray work', () => { |
| const typeinfo = Type.struct({ |
| typeName: "example.foo", |
| }, { |
| a: Type.boolArray(), |
| a2: Type.int16Array(), |
| a3: Type.int32Array(), |
| a4: Type.int64Array(), |
| a6: Type.float64Array() |
| }); |
| |
| const fory = new Fory({ compatible: false, ref: true }); |
| const serializer = fory.register(typeinfo).serializer; |
| const input = fory.serialize({ |
| a: [true, false], |
| a2: new Int16Array([1, 2, 3]), |
| a3: new Int32Array([3, 5, 76]), |
| a4: new BigInt64Array([634n, 564n, 76n]), |
| a6: new Float64Array([234243.555, 55654.679]), |
| }, serializer); |
| const result = fory.deserialize( |
| input |
| ); |
| expect(result.a).toBeInstanceOf(BoolArray); |
| expect(Array.from(result.a)).toEqual([true, false]); |
| expect(result.a2).toEqual(new Int16Array([1, 2, 3])); |
| expect(result.a3).toEqual(new Int32Array([3, 5, 76])); |
| expect(result.a4).toEqual(new BigInt64Array([634n, 564n, 76n])); |
| expect(result.a6).toEqual(new Float64Array([234243.555, 55654.679])); |
| }); |
| |
| |
| test('should floatarray work', () => { |
| const typeinfo = Type.struct({ |
| typeName: "example.foo" |
| }, { |
| a5: Type.float32Array(), |
| }) |
| |
| const fory = new Fory({ compatible: false, ref: true }); const serialize = fory.register(typeinfo).serializer; |
| const input = fory.serialize({ |
| a5: new Float32Array([2.43, 654.4, 55]), |
| }, serialize); |
| const result = fory.deserialize( |
| input |
| ); |
| expect(result.a5[0]).toBeCloseTo(2.43) |
| expect(result.a5[1]).toBeCloseTo(654.4) |
| expect(result.a5[2]).toBeCloseTo(55) |
| }); |
| |
| test('should float16Array work', () => { |
| const typeinfo = Type.struct({ |
| typeName: "example.foo" |
| }, { |
| a6: Type.float16Array(), |
| }) |
| |
| const fory = new Fory({ compatible: false, ref: true }); const serialize = fory.register(typeinfo).serializer; |
| const input = fory.serialize({ |
| a6: [1.5, 2.5, -4.5], |
| }, serialize); |
| const result = fory.deserialize( |
| input |
| ); |
| expect(result.a6).toBeInstanceOf(Float16Array as any); |
| expect(Array.from(result.a6 as Iterable<number>)[0]).toBeCloseTo(1.5, 1) |
| expect(Array.from(result.a6 as Iterable<number>)[1]).toBeCloseTo(2.5, 1) |
| expect(Array.from(result.a6 as Iterable<number>)[2]).toBeCloseTo(-4.5, 1) |
| }); |
| |
| test('should bfloat16Array work', () => { |
| const typeinfo = Type.struct({ |
| typeName: "example.foo" |
| }, { |
| a7: Type.bfloat16Array(), |
| }); |
| const fory = new Fory({ compatible: false, ref: true }); |
| const serialize = fory.register(typeinfo).serializer; |
| const input = fory.serialize({ |
| a7: [1.5, 2.5, -4.5], |
| }, serialize); |
| const result = fory.deserialize(input); |
| expect(result.a7).toBeInstanceOf(BFloat16Array); |
| expect(result.a7).toHaveLength(3); |
| expect(result.a7.get(0)).toBeCloseTo(1.5, 2); |
| expect(result.a7.get(1)).toBeCloseTo(2.5, 2); |
| expect(result.a7.get(2)).toBeCloseTo(-4.5, 2); |
| }); |
| |
| test('should bfloat16Array accept BFloat16Array', () => { |
| const typeinfo = Type.struct({ |
| typeName: "example.foo" |
| }, { |
| a7: Type.bfloat16Array(), |
| }); |
| const fory = new Fory({ compatible: false, ref: true }); |
| const serialize = fory.register(typeinfo).serializer; |
| const arr = new BFloat16Array([1.25, -2.5, 0]); |
| const input = fory.serialize({ a7: arr }, serialize); |
| const result = fory.deserialize(input); |
| expect(result.a7).toBeInstanceOf(BFloat16Array); |
| expect(result.a7).toHaveLength(3); |
| expect(result.a7.get(0)).toBeCloseTo(1.25, 2); |
| expect(result.a7.get(1)).toBeCloseTo(-2.5, 2); |
| expect(result.a7.get(2)).toBe(0); |
| }); |
| |
| test('should expose bool and reduced-precision array carriers', () => { |
| const bools = new BoolArray([true, false, true]); |
| bools.setValue(1, true); |
| expect(Array.from(bools)).toEqual([true, true, true]); |
| expect(bools.raw).toEqual(new Uint8Array([1, 1, 1])); |
| |
| const f16 = new ForyFloat16Array([1.5, -2]); |
| expect(f16.get(0)).toBeCloseTo(1.5, 1); |
| expect(f16.get(1)).toBeCloseTo(-2, 1); |
| |
| const bf16 = new BFloat16Array([1.5, -2]); |
| expect(Array.from(bf16)).toEqual([1.5, -2]); |
| }); |
| |
| test('should write dense array protocol bytes in little-endian order', () => { |
| const fory = new Fory({ compatible: false, ref: true }); |
| |
| const uint16Type = Type.struct({ typeName: 'example.uint16array' }, { |
| values: Type.uint16Array(), |
| }); |
| const uint16Serializer = fory.register(uint16Type).serializer; |
| const uint16Bytes = fory.serialize({ |
| values: new Uint16Array([0x1234, 0xabcd]), |
| }, uint16Serializer); |
| expect(containsBytes(uint16Bytes, [0x34, 0x12, 0xcd, 0xab])).toBe(true); |
| |
| const float16Type = Type.struct({ typeName: 'example.float16array' }, { |
| values: Type.float16Array(), |
| }); |
| const float16Serializer = fory.register(float16Type).serializer; |
| const float16Bytes = fory.serialize({ |
| values: new ForyFloat16Array([1, -2]), |
| }, float16Serializer); |
| expect(containsBytes(float16Bytes, [0x00, 0x3c, 0x00, 0xc0])).toBe(true); |
| |
| const bfloat16Type = Type.struct({ typeName: 'example.bfloat16array' }, { |
| values: Type.bfloat16Array(), |
| }); |
| const bfloat16Serializer = fory.register(bfloat16Type).serializer; |
| const bfloat16Bytes = fory.serialize({ |
| values: new BFloat16Array([1, -2]), |
| }, bfloat16Serializer); |
| expect(containsBytes(bfloat16Bytes, [0x80, 0x3f, 0x00, 0xc0])).toBe(true); |
| }); |
| }); |
| |
| function containsBytes(bytes: Uint8Array, needle: number[]) { |
| outer: |
| for (let i = 0; i <= bytes.length - needle.length; i++) { |
| for (let j = 0; j < needle.length; j++) { |
| if (bytes[i + j] !== needle[j]) { |
| continue outer; |
| } |
| } |
| return true; |
| } |
| return false; |
| } |