diff --git a/java/fory-core/src/test/java/org/apache/fory/CPPXlangTest.java b/java/fory-core/src/test/java/org/apache/fory/CPPXlangTest.java index 05175abba8..0886d6100f 100644 --- a/java/fory-core/src/test/java/org/apache/fory/CPPXlangTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/CPPXlangTest.java @@ -130,4 +130,16 @@ private void runBazelCommand(String... args) throws IOException { public void testConsistentNamed() throws java.io.IOException { super.testConsistentNamed(); } + + @Test + @Override + public void testStructWithUnionFields() throws java.io.IOException { + throw new SkipException("Union types not yet supported in C++"); + } + + @Test + @Override + public void testTopLevelUnion() throws java.io.IOException { + throw new SkipException("Union types not yet supported in C++"); + } } diff --git a/java/fory-core/src/test/java/org/apache/fory/GoXlangTest.java b/java/fory-core/src/test/java/org/apache/fory/GoXlangTest.java index efdef16a01..e4e5e17018 100644 --- a/java/fory-core/src/test/java/org/apache/fory/GoXlangTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/GoXlangTest.java @@ -233,4 +233,16 @@ public void testTwoEnumFieldCompatible() throws java.io.IOException { public void testEnumSchemaEvolutionCompatible() throws java.io.IOException { super.testEnumSchemaEvolutionCompatible(); } + + @Test + @Override + public void testStructWithUnionFields() throws java.io.IOException { + throw new SkipException("Union types not yet supported in Go"); + } + + @Test + @Override + public void testTopLevelUnion() throws java.io.IOException { + throw new SkipException("Union types not yet supported in Go"); + } } diff --git a/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java b/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java index 58f09e3770..51ad37553d 100644 --- a/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java +++ b/java/fory-core/src/test/java/org/apache/fory/RustXlangTest.java @@ -86,4 +86,16 @@ protected CommandContext buildCommandContext(String caseName, Path dataFile) { .build(); return new CommandContext(command, env, new File("../../rust")); } + + @Test + @Override + public void testStructWithUnionFields() throws java.io.IOException { + throw new SkipException("Union types not yet supported in Rust"); + } + + @Test + @Override + public void testTopLevelUnion() throws java.io.IOException { + throw new SkipException("Union types not yet supported in Rust"); + } } diff --git a/java/fory-core/src/test/java/org/apache/fory/XlangTestBase.java b/java/fory-core/src/test/java/org/apache/fory/XlangTestBase.java index 516a9ac9e2..6b86a37e32 100644 --- a/java/fory-core/src/test/java/org/apache/fory/XlangTestBase.java +++ b/java/fory-core/src/test/java/org/apache/fory/XlangTestBase.java @@ -39,6 +39,12 @@ import org.apache.fory.memory.MemoryUtils; import org.apache.fory.serializer.Serializer; import org.apache.fory.test.TestUtils; +import org.apache.fory.type.union.Union; +import org.apache.fory.type.union.Union2; +import org.apache.fory.type.union.Union3; +import org.apache.fory.type.union.Union4; +import org.apache.fory.type.union.Union5; +import org.apache.fory.type.union.Union6; import org.apache.fory.util.MurmurHash3; import org.testng.Assert; import org.testng.annotations.BeforeClass; @@ -1575,6 +1581,107 @@ public void testEnumSchemaEvolutionCompatible() throws java.io.IOException { Assert.assertNull(result2.f2); } + // ============================================================================ + // Union type tests + // ============================================================================ + + /** Struct containing Union fields of different arities (Union through Union6). */ + @Data + public static class StructWithUnionFields { + public Union union; + public Union2 union2; + public Union3 union3; + public Union4 union4; + public Union5 union5; + public Union6 union6; + } + + @Test + public void testStructWithUnionFields() throws java.io.IOException { + String caseName = "test_struct_with_union_fields"; + Fory fory = + Fory.builder() + .withLanguage(Language.XLANG) + .withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT) + .withCodegen(false) + .build(); + fory.register(StructWithUnionFields.class, 200); + + StructWithUnionFields obj = new StructWithUnionFields(); + obj.union = new Union(0, 42); + obj.union2 = Union2.ofT1("hello"); + obj.union3 = Union3.ofT2("world"); + obj.union4 = Union4.ofT3(3.14); + obj.union5 = Union5.ofT4(true); + obj.union6 = Union6.ofT5(999L); + + MemoryBuffer buffer = MemoryUtils.buffer(128); + fory.serialize(buffer, obj); + + ExecutionContext ctx = prepareExecution(caseName, buffer.getBytes(0, buffer.writerIndex())); + runPeer(ctx); + + MemoryBuffer buffer2 = readBuffer(ctx.dataFile()); + StructWithUnionFields result = (StructWithUnionFields) fory.deserialize(buffer2); + + Assert.assertEquals(result.union.getIndex(), 0); + Assert.assertEquals(result.union.getValue(), 42); + Assert.assertEquals(result.union2.getIndex(), 0); + Assert.assertEquals(result.union2.getValue(), "hello"); + Assert.assertTrue(result.union2.isT1()); + Assert.assertEquals(result.union3.getIndex(), 1); + Assert.assertEquals(result.union3.getValue(), "world"); + Assert.assertTrue(result.union3.isT2()); + Assert.assertEquals(result.union4.getIndex(), 2); + Assert.assertEquals((Double) result.union4.getValue(), 3.14, 0.001); + Assert.assertTrue(result.union4.isT3()); + Assert.assertEquals(result.union5.getIndex(), 3); + Assert.assertEquals(result.union5.getValue(), true); + Assert.assertTrue(result.union5.isT4()); + Assert.assertEquals(result.union6.getIndex(), 4); + Assert.assertEquals(result.union6.getValue(), 999L); + Assert.assertTrue(result.union6.isT5()); + } + + @Test + public void testTopLevelUnion() throws java.io.IOException { + String caseName = "test_top_level_union"; + Fory fory = + Fory.builder() + .withLanguage(Language.XLANG) + .withCompatibleMode(CompatibleMode.SCHEMA_CONSISTENT) + .withCodegen(false) + .build(); + + // Test Union with integer value + Union union1 = new Union(0, 42); + MemoryBuffer buffer = MemoryUtils.buffer(64); + fory.serialize(buffer, union1); + + ExecutionContext ctx1 = + prepareExecution(caseName + "_int", buffer.getBytes(0, buffer.writerIndex())); + runPeer(ctx1); + + MemoryBuffer buffer2 = readBuffer(ctx1.dataFile()); + Union result1 = (Union) fory.deserialize(buffer2); + Assert.assertEquals(result1.getIndex(), 0); + Assert.assertEquals(result1.getValue(), 42); + + // Test Union with string value + Union union2 = new Union(1, "hello"); + buffer = MemoryUtils.buffer(64); + fory.serialize(buffer, union2); + + ExecutionContext ctx2 = + prepareExecution(caseName + "_str", buffer.getBytes(0, buffer.writerIndex())); + runPeer(ctx2); + + MemoryBuffer buffer3 = readBuffer(ctx2.dataFile()); + Union result2 = (Union) fory.deserialize(buffer3); + Assert.assertEquals(result2.getIndex(), 1); + Assert.assertEquals(result2.getValue(), "hello"); + } + @SuppressWarnings("unchecked") private void assertStringEquals(Object actual, Object expected, boolean useToString) { if (useToString) {