This is an automated email from the ASF dual-hosted git repository.

wangweipeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new cd2e0a47a feat(JavaScript): Align testcases (#3319)
cd2e0a47a is described below

commit cd2e0a47a00780d4a49b7e022cff1116c45247fb
Author: weipeng <[email protected]>
AuthorDate: Tue Feb 10 16:02:00 2026 +0800

    feat(JavaScript): Align testcases (#3319)
    
    ## Why?
    1. More testcases were passed, current progress 29/39
    
    
    ## What does this PR do?
    1. Support `TAGGED_INT64` and `TAGGED_UINT64`
    2. Fix float16 decode when the number is NaN or Infinity
    
    ## Related issues
    #3133
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 javascript/packages/fory/lib/gen/builder.ts   |  16 ++++
 javascript/packages/fory/lib/gen/number.ts    |  23 ++---
 javascript/packages/fory/lib/reader/index.ts  |  52 ++++++++++
 javascript/packages/fory/lib/writer/index.ts  |  63 +++++++++++-
 javascript/packages/fory/lib/writer/number.ts |   2 +-
 javascript/test/crossLanguage.test.ts         | 132 ++++++++++++++++++--------
 javascript/test/number.test.ts                |  30 ++++++
 7 files changed, 268 insertions(+), 50 deletions(-)

diff --git a/javascript/packages/fory/lib/gen/builder.ts 
b/javascript/packages/fory/lib/gen/builder.ts
index c03c9aba3..8138220f4 100644
--- a/javascript/packages/fory/lib/gen/builder.ts
+++ b/javascript/packages/fory/lib/gen/builder.ts
@@ -51,6 +51,14 @@ export class BinaryReaderBuilder {
     return `${this.holder}.varInt32()`;
   }
 
+  readTaggedInt64() {
+    return `${this.holder}.readTaggedInt64()`;
+  }
+
+  readTaggedUInt64() {
+    return `${this.holder}.readTaggedUInt64()`;
+  }
+
   varInt64() {
     return `${this.holder}.varInt64()`;
   }
@@ -205,6 +213,14 @@ class BinaryWriterBuilder {
     return `${this.holder}.varUInt64(${v})`;
   }
 
+  writeTaggedInt64(v: number | string) {
+    return `${this.holder}.writeTaggedInt64(${v})`;
+  }
+
+  writeTaggedUInt64(v: number | string) {
+    return `${this.holder}.writeTaggedUInt64(${v})`;
+  }
+
   varInt64(v: number | string) {
     return `${this.holder}.varInt64(${v})`;
   }
diff --git a/javascript/packages/fory/lib/gen/number.ts 
b/javascript/packages/fory/lib/gen/number.ts
index 83c3ffe27..dd3380d5a 100644
--- a/javascript/packages/fory/lib/gen/number.ts
+++ b/javascript/packages/fory/lib/gen/number.ts
@@ -77,17 +77,25 @@ CodegenRegistry.register(TypeId.VARINT32,
 
 CodegenRegistry.register(TypeId.INT64,
   buildNumberSerializer(
-    (builder, accessor) => builder.writer.sliInt64(accessor),
-    builder => builder.reader.sliInt64()
+    (builder, accessor) => builder.writer.int64(accessor),
+    builder => builder.reader.int64()
   )
 );
 
 CodegenRegistry.register(TypeId.TAGGED_INT64,
   buildNumberSerializer(
-    (builder, accessor) => builder.writer.sliInt64(accessor),
-    builder => builder.reader.sliInt64()
+    (builder, accessor) => builder.writer.writeTaggedInt64(accessor),
+    builder => builder.reader.readTaggedInt64()
   )
 );
+
+CodegenRegistry.register(TypeId.TAGGED_UINT64,
+  buildNumberSerializer(
+    (builder, accessor) => builder.writer.writeTaggedUInt64(accessor),
+    builder => builder.reader.readTaggedUInt64()
+  )
+);
+
 CodegenRegistry.register(TypeId.FLOAT16,
   buildNumberSerializer(
     (builder, accessor) => builder.writer.float16(accessor),
@@ -149,13 +157,6 @@ CodegenRegistry.register(TypeId.VAR_UINT64,
   )
 );
 
-CodegenRegistry.register(TypeId.TAGGED_UINT64,
-  buildNumberSerializer(
-    (builder, accessor) => builder.writer.varUInt64(accessor),
-    builder => builder.reader.varUInt64()
-  )
-);
-
 CodegenRegistry.register(TypeId.VARINT64,
   buildNumberSerializer(
     (builder, accessor) => builder.writer.varInt64(accessor),
diff --git a/javascript/packages/fory/lib/reader/index.ts 
b/javascript/packages/fory/lib/reader/index.ts
index 1fb970b71..d63cd2f15 100644
--- a/javascript/packages/fory/lib/reader/index.ts
+++ b/javascript/packages/fory/lib/reader/index.ts
@@ -104,6 +104,58 @@ export class BinaryReader {
     return this.varInt64();
   }
 
+  /**
+   * Read signed fory Tagged(Small Long as Int) encoded long.
+   * If the first bit is 0, it's a 4-byte int shifted left by 1 bit.
+   * If the first bit is 1, it's a 9-byte format with 0b1 flag + 8-byte long.
+   */
+  readTaggedInt64(): bigint {
+    const readIdx = this.cursor;
+    if (this.byteLength - readIdx < 4) {
+      throw new Error("Insufficient bytes for tagged int64");
+    }
+
+    const i = this.dataView.getInt32(readIdx, true);
+    if ((i & 0b1) !== 0b1) {
+      // Small long encoded as int
+      this.cursor = readIdx + 4;
+      return BigInt(i >> 1);
+    } else {
+      // Big long encoded as 8 bytes
+      if (this.byteLength - readIdx < 9) {
+        throw new Error("Insufficient bytes for big tagged int64");
+      }
+      this.cursor = readIdx + 1; // Skip the flag byte
+      return this.int64();
+    }
+  }
+
+  /**
+   * Read unsigned fory Tagged(Small Long as Int) encoded long.
+   * If the first bit is 0, it's a 4-byte uint shifted left by 1 bit.
+   * If the first bit is 1, it's a 9-byte format with 0b1 flag + 8-byte ulong.
+   */
+  readTaggedUInt64(): bigint {
+    const readIdx = this.cursor;
+    if (this.byteLength - readIdx < 4) {
+      throw new Error("Insufficient bytes for tagged uint64");
+    }
+
+    const i = this.dataView.getUint32(readIdx, true);
+    if ((i & 0b1) !== 0b1) {
+      // Small ulong encoded as uint
+      this.cursor = readIdx + 4;
+      return BigInt(i >>> 1); // unsigned right shift
+    } else {
+      // Big ulong encoded as 8 bytes
+      if (this.byteLength - readIdx < 9) {
+        throw new Error("Insufficient bytes for big tagged uint64");
+      }
+      this.cursor = readIdx + 1; // Skip the flag byte
+      return this.uint64();
+    }
+  }
+
   float32() {
     const result = this.dataView.getFloat32(this.cursor, true);
     this.cursor += 4;
diff --git a/javascript/packages/fory/lib/writer/index.ts 
b/javascript/packages/fory/lib/writer/index.ts
index 0ebd139c7..5c4036602 100644
--- a/javascript/packages/fory/lib/writer/index.ts
+++ b/javascript/packages/fory/lib/writer/index.ts
@@ -125,7 +125,11 @@ export class BinaryWriter {
   }
 
   int64(v: bigint) {
-    this.dataView.setBigInt64(this.cursor, v, true);
+    if (typeof v !== "bigint") {
+      this.dataView.setBigInt64(this.cursor, BigInt(v), true);
+    } else {
+      this.dataView.setBigInt64(this.cursor, v, true);
+    }
     this.cursor += 8;
   }
 
@@ -147,6 +151,63 @@ export class BinaryWriter {
     }
   }
 
+  /**
+   * Write signed long using fory Tagged(Small long as int) encoding.
+   * If long is in [0xc0000000, 0x3fffffff], encode as 4 bytes int: | 
little-endian: ((int) value) << 1 |
+   * Otherwise write as 9 bytes: | 0b1 | little-endian 8bytes long |
+   */
+  writeTaggedInt64(value: bigint | number): number {
+    if (typeof value !== "bigint") {
+      value = BigInt(value);
+    }
+
+    const halfMaxInt32 = 0x3fffffffn; // 0x3fffffff
+    const halfMinInt32 = -0x40000000n; // 0xc0000000 as signed
+
+    if (value >= halfMinInt32 && value <= halfMaxInt32) {
+      // Small long encoded as int
+      const v = Number(value) << 1; // bit 0 unset, means int
+      this.dataView.setInt32(this.cursor, v, true);
+      this.cursor += 4;
+      return 4;
+    } else {
+      // Big long encoded as 8 bytes
+      const BIG_LONG_FLAG = 0b1; // bit 0 set, means big long
+      this.dataView.setUint8(this.cursor, BIG_LONG_FLAG);
+      this.dataView.setBigInt64(this.cursor + 1, value, true);
+      this.cursor += 9;
+      return 9;
+    }
+  }
+
+  /**
+   * Write unsigned long using fory Tagged(Small long as int) encoding.
+   * If long is in [0, 0x7fffffff], encode as 4 bytes int: | little-endian: 
((int) value) << 1 |
+   * Otherwise write as 9 bytes: | 0b1 | little-endian 8bytes long |
+   */
+  writeTaggedUInt64(value: bigint | number): number {
+    if (typeof value !== "bigint") {
+      value = BigInt(value);
+    }
+
+    const maxUInt32 = 0x7fffffffn; // 0x7fffffff
+
+    if (value >= 0n && value <= maxUInt32) {
+      // Small ulong encoded as uint
+      const v = Number(value) << 1; // bit 0 unset, means int
+      this.dataView.setUint32(this.cursor, v, true);
+      this.cursor += 4;
+      return 4;
+    } else {
+      // Big ulong encoded as 8 bytes
+      const BIG_LONG_FLAG = 0b1; // bit 0 set, means big long
+      this.dataView.setUint8(this.cursor, BIG_LONG_FLAG);
+      this.dataView.setBigUint64(this.cursor + 1, value, true);
+      this.cursor += 9;
+      return 9;
+    }
+  }
+
   float32(v: number) {
     this.dataView.setFloat32(this.cursor, v, true);
     this.cursor += 4;
diff --git a/javascript/packages/fory/lib/writer/number.ts 
b/javascript/packages/fory/lib/writer/number.ts
index 55b81883d..8729dc372 100644
--- a/javascript/packages/fory/lib/writer/number.ts
+++ b/javascript/packages/fory/lib/writer/number.ts
@@ -28,7 +28,7 @@ export function toFloat16(value: number) {
   const significand = floatValue & 0x7fffff; // extract significand from 
floatValue
 
   if (exponent === 128) { // floatValue is NaN or Infinity
-    return sign | ((exponent === 128) ? 0x7c00 : 0x7fff);
+    return sign | 0x7c00 | (significand !== 0 ? 0x0200 : 0);
   }
 
   if (exponent > 15) {
diff --git a/javascript/test/crossLanguage.test.ts 
b/javascript/test/crossLanguage.test.ts
index 3f4f0b2a7..bd4c5ed5a 100644
--- a/javascript/test/crossLanguage.test.ts
+++ b/javascript/test/crossLanguage.test.ts
@@ -1483,23 +1483,21 @@ describe("bool", () => {
   });
 
   test("test_unsigned_schema_consistent_simple", () => {
-    if (Boolean("1")) { return; }
     const fory = new Fory({
-      mode: Mode.Compatible
+      mode: Mode.SchemaConsistent
     });
 
     @Type.struct(1, {
-      u64Tagged: Type.int64(),
-      u64TaggedNullable: Type.int64()
+      u64Tagged: Type.taggedUInt64(),
+      u64TaggedNullable: Type.taggedUInt64()
     })
-    class UnsignedStruct {
+    class UnsignedSchemaConsistentSimple {
       u64Tagged: bigint = 0n;
+
+      @ForyField({nullable: true})
       u64TaggedNullable: bigint | null = null;
     }
-    fory.registerSerializer(UnsignedStruct);
-
-    const reader = new BinaryReader({});
-    reader.reset(content);
+    fory.registerSerializer(UnsignedSchemaConsistentSimple);
 
     // Deserialize struct from Java
     let cursor = 0;
@@ -1512,27 +1510,57 @@ describe("bool", () => {
   });
 
   test("test_unsigned_schema_consistent", () => {
-    if (Boolean("1")) { return; }
     const fory = new Fory({
-      mode: Mode.Compatible
+      mode: Mode.SchemaConsistent
     });
 
     @Type.struct(501, {
       u8Field: Type.uint8(),
       u16Field: Type.uint16(),
-      u32Field: Type.uint32(),
-      u64Field: Type.uint64()
+      u32VarField: Type.varUInt32(),
+      u32FixedField: Type.uint32(),
+      u64VarField: Type.varUInt64(),
+      u64FixedField: Type.uint64(),
+      u64TaggedField: Type.taggedUInt64(),
     })
-    class UnsignedStruct {
+    class UnsignedSchemaConsistent {
       u8Field: number = 0;
       u16Field: number = 0;
-      u32Field: number = 0;
-      u64Field: bigint = 0n;
-    }
-    fory.registerSerializer(UnsignedStruct);
+      u32VarField: number = 0;
+      u32FixedField: bigint = 0n;
+      u64VarField: bigint = 0n;
+      u64FixedField: bigint = 0n;
+      u64TaggedField: bigint = 0n;
 
-    const reader = new BinaryReader({});
-    reader.reset(content);
+      @ForyField({nullable: true})
+      @Type.uint8()
+      u8NullableField: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.uint16()
+      u16NullableField: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.varUInt32()
+      u32VarNullableField: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.uint32()
+      u32FixedNullableField: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.varUInt64()
+      u64VarNullableField: bigint = 0n;
+
+      @ForyField({nullable: true})
+      @Type.uint64()
+      u64FixedNullableField: bigint = 0n;
+
+      @ForyField({nullable: true})
+      @Type.taggedUInt64()
+      u64TaggedNullableField: bigint = 0n;
+    }
+    fory.registerSerializer(UnsignedSchemaConsistent);
 
     // Deserialize struct from Java
     let cursor = 0;
@@ -1540,32 +1568,62 @@ describe("bool", () => {
     cursor += fory.binaryReader.getCursor();
 
     // Serialize the deserialized struct back
-    const serializedData = fory.serialize(deserializedStruct);
-    writeToFile(serializedData as Buffer);
+    const serializedBackData = fory.serialize(deserializedStruct);
+    writeToFile(serializedBackData as Buffer);
   });
 
   test("test_unsigned_schema_compatible", () => {
-    if (Boolean("1")) { return; }
     const fory = new Fory({
       mode: Mode.Compatible
     });
 
     @Type.struct(502, {
-      u8Field: Type.uint8(),
-      u16Field: Type.uint16(),
-      u32Field: Type.uint32(),
-      u64Field: Type.uint64()
+      u8Field1: Type.uint8(),
+      u16Field1: Type.uint16(),
+      u32VarField1: Type.varUInt32(),
+      u32FixedField1: Type.uint32(),
+      u64VarField1: Type.varUInt64(),
+      u64FixedField1: Type.uint64(),
+      u64TaggedField1: Type.taggedUInt64(),
     })
-    class UnsignedStruct {
-      u8Field: number = 0;
-      u16Field: number = 0;
-      u32Field: number = 0;
-      u64Field: bigint = 0n;
-    }
-    fory.registerSerializer(UnsignedStruct);
+    class UnsignedSchemaCompatible {
+      u8Field1: number = 0;
+      u16Field1: number = 0;
+      u32VarField1: number = 0;
+      u32FixedField1: bigint = 0n;
+      u64VarField1: bigint = 0n;
+      u64FixedField1: bigint = 0n;
+      u64TaggedField1: bigint = 0n;
 
-    const reader = new BinaryReader({});
-    reader.reset(content);
+      @ForyField({nullable: true})
+      @Type.uint8()
+      u8Field2: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.uint16()
+      u16Field2: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.varUInt32()
+      u32VarField2: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.uint32()
+      u32FixedField2: number = 0;
+
+      @ForyField({nullable: true})
+      @Type.varUInt64()
+      u64VarField2: bigint = 0n;
+
+      @ForyField({nullable: true})
+      @Type.uint64()
+      u64FixedField2: bigint = 0n;
+
+      @ForyField({nullable: true})
+      @Type.taggedUInt64()
+      u64TaggedField2: bigint = 0n;
+    }
+    fory.registerSerializer(UnsignedSchemaCompatible);
 
     // Deserialize struct from Java
     let cursor = 0;
@@ -1574,6 +1632,6 @@ describe("bool", () => {
 
     // Serialize the deserialized struct back
     const serializedData = fory.serialize(deserializedStruct);
-    // writeToFile(serializedData as Buffer);
+    writeToFile(serializedData as Buffer);
   });
 });
diff --git a/javascript/test/number.test.ts b/javascript/test/number.test.ts
index 37c15a9e4..a13185be9 100644
--- a/javascript/test/number.test.ts
+++ b/javascript/test/number.test.ts
@@ -123,6 +123,36 @@ describe('number', () => {
     expect(result.a).toBeCloseTo(1.2, 1)
   });
 
+  test('should float16 NAN work', () => {
+
+    const fory = new Fory({ refTracking: true });
+    const serializer = fory.registerSerializer(Type.struct({
+      typeName: "example.foo"
+    }, {
+      a: Type.float16()
+    })).serializer;
+    const input = fory.serialize({ a: NaN }, serializer);
+    const result = fory.deserialize(
+      input
+    );
+    expect(result.a).toBe(NaN)
+  });
+
+  test('should float16 Infinity work', () => {
+
+    const fory = new Fory({ refTracking: true });
+    const serializer = fory.registerSerializer(Type.struct({
+      typeName: "example.foo"
+    }, {
+      a: Type.float16()
+    })).serializer;
+    const input = fory.serialize({ a: Infinity }, serializer);
+    const result = fory.deserialize(
+      input
+    );
+    expect(result.a).toBeCloseTo(Infinity)
+  });
+
   test('should uint8 work', () => {
     const fory = new Fory({ refTracking: true });
     const serializer = fory.registerSerializer(Type.struct({


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to