From cce42102182382b601c88a839e41fa16d92f5c2b Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Fri, 13 Dec 2024 13:21:12 -0600 Subject: [PATCH] Add an object test. Add a basic runtime test which generates byte code. These probably need to be sorted more. --- src/IKVM.Tests/Java/java/lang/ObjectTests.cs | 11 ++- src/IKVM.Tests/Runtime/RuntimeTests.cs | 94 ++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/IKVM.Tests/Runtime/RuntimeTests.cs diff --git a/src/IKVM.Tests/Java/java/lang/ObjectTests.cs b/src/IKVM.Tests/Java/java/lang/ObjectTests.cs index 97a7c7ca61..0d3cc90d2d 100644 --- a/src/IKVM.Tests/Java/java/lang/ObjectTests.cs +++ b/src/IKVM.Tests/Java/java/lang/ObjectTests.cs @@ -1,4 +1,6 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using FluentAssertions; + +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace IKVM.Tests.Java.java.lang { @@ -7,7 +9,12 @@ namespace IKVM.Tests.Java.java.lang public class ObjectTests { - + [TestMethod] + public void CanCreateObject() + { + var o = new global::java.lang.Object(); + o.Should().BeOfType(); + } } diff --git a/src/IKVM.Tests/Runtime/RuntimeTests.cs b/src/IKVM.Tests/Runtime/RuntimeTests.cs new file mode 100644 index 0000000000..e41a4076ba --- /dev/null +++ b/src/IKVM.Tests/Runtime/RuntimeTests.cs @@ -0,0 +1,94 @@ +using System; + +using FluentAssertions; + +using IKVM.ByteCode; +using IKVM.ByteCode.Buffers; +using IKVM.ByteCode.Encoding; + +using java.lang; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace IKVM.Tests.Runtime +{ + + [TestClass] + public class RuntimeTests + { + + /// + /// Simple implementation that loads a class from a builder. + /// + class ByteArrayClassLoader : ClassLoader + { + + /// + /// Loads the specified as a class. + /// + /// + /// + /// + public Class Load(ClassFileBuilder clazz, string name) + { + var clazzBuffer = new BlobBuilder(); + clazz.Serialize(clazzBuffer); + return defineClass(name, clazzBuffer.ToArray(), 0, clazzBuffer.Count); + } + + } + + /// + /// Adds a method and code. + /// + /// + /// + /// + /// + /// + /// + /// + void AddMethod(ClassFileBuilder clazz, AccessFlag flags, string name, string signature, Action code, ushort maxStack, ushort maxLocals) + { + var attributes = new AttributeTableBuilder(clazz.Constants); + var buffer = new BlobBuilder(); + code(new CodeBuilder(buffer)); + attributes.Code(maxStack, maxLocals, buffer, e => { }, null); + clazz.AddMethod(flags, name, signature, attributes); + } + + /// + /// Adds a default constrctor. + /// + /// + void AddDefaultConstructor(ClassFileBuilder clazz) + { + AddMethod(clazz, AccessFlag.Public, "", "()V", c => c + .Aload0() + .InvokeSpecial(clazz.Constants.GetOrAddMethodref(clazz.Constants.GetOrAddClass("java/lang/Object"), clazz.Constants.GetOrAddNameAndType("", "()V"))) + .Return(), 1, 1); + } + + [TestMethod] + public void NewDupInvokeSpecialAReturn() + { + var builder = new ClassFileBuilder(52, AccessFlag.Public, "Test", "java/lang/Object"); + AddDefaultConstructor(builder); + AddMethod(builder, AccessFlag.Public | AccessFlag.Static, "CreateObject", "()Ljava/lang/Object;", c => c + .New(builder.Constants.GetOrAddClass("java/lang/Object")) + .Dup() + .InvokeSpecial(builder.Constants.GetOrAddMethodref(builder.Constants.GetOrAddClass("java/lang/Object"), builder.Constants.GetOrAddNameAndType("", "()V"))) + .Areturn(), 2, 0); + + var cldr = new ByteArrayClassLoader(); + var clazz = cldr.Load(builder, "Test"); + + var instance = clazz.newInstance(); + var method = clazz.getMethod("CreateObject", []); + var result = method.invoke(instance, []); + result.Should().BeOfType(); + } + + } + +}