From 2fe7535354c599830b17bb296369a94e43826cfb Mon Sep 17 00:00:00 2001 From: Joseph Moreno <44370115+josephmoresena@users.noreply.github.com> Date: Wed, 4 Sep 2024 21:55:50 -0500 Subject: [PATCH] Call tests (#21) * Improvements Get/Set IEnvironment.PendingException. * Improvements Get/Set primitive array region. * Span for Calls args. * Constructor, Method and Function call tests. * Get/Set field tests. * ThrowNew tests. --- .github/workflows/build.yml | 13 + .../README.md | 285 ++++++++++++++++++ .../GetObjectDefinition.cs | 6 +- .../README.md | 21 ++ .../IObject.cs | 10 + .../Access/JCallDefinition/Constructor.cs | 14 +- .../Native/Access/JCallDefinition/Private.cs | 2 +- .../Internal/NativeFunctionSetImpl.cs | 16 +- .../SingleObjectBuffer.cs | 18 ++ .../Internal/PrimitiveWrapperConstructor.cs | 2 +- .../Native/Access/JMainMethodDefinition.cs | 5 +- .../Proxies/EnvironmentProxy/AccessFeature.cs | 62 ++-- .../Internal/AccessFeature.cs | 54 +++- .../Internal/MetadataHelper.cs | 2 +- .../Internal/UnknownReflectionMetadata.cs | 4 +- .../JEnvironment/AccessFeature.cs | 29 +- .../JEnvironment/ArrayFeature.cs | 11 +- .../JEnvironment/EnvironmentCache.cs | 10 + .../JEnvironment/EnvironmentCache/Access.cs | 18 +- .../JEnvironment/EnvironmentCache/Arrays.cs | 18 +- .../EnvironmentCache/PrimitiveAccess.cs | 13 +- .../JEnvironment/EnvironmentCache/Private.cs | 6 +- .../EnvironmentCache/TransactionAccess.cs | 6 +- .../JEnvironment/Private.cs | 6 +- .../JEnvironment/ReferenceFeature.cs | 19 +- .../ILLink/ILLink.Substitutions.xml | 2 +- .../Internal/JTrace/Access.cs | 2 +- .../Lang/JEnumObject/EnumTypeMetadata.cs | 2 +- .../Lang/Reflect/JExecutableObject.cs | 6 +- .../Lang/Reflect/JFieldObject.cs | 6 +- .../Lang/Reflect/JMethodObject.cs | 4 +- .../Native/Access/JConstructorDefinition.cs | 13 +- .../JConstructorDefinition/Protected.cs | 21 +- .../Native/Access/JFunctionDefinition.cs | 12 +- .../Access/JFunctionDefinition/Protected.cs | 30 +- .../Access/JFunctionDefinition/Static.cs | 15 +- .../Access/JMethodDefinition/Internal.cs | 23 +- .../Access/JMethodDefinition/Protected.cs | 29 +- .../Access/JNonTypedFunctionDefinition.cs | 79 ++--- .../Native/JArrayObject/ArrayTypeMetadata.cs | 2 +- .../JArrayObject/InternalConstructor.cs | 2 +- .../InterfaceView/InterfaceTypeMetadata.cs | 2 +- .../Restricted/IAccessFeature.cs | 46 +-- .../Restricted/IAccessFeature/Internal.cs | 26 +- .../Types/Metadata/JClassTypeMetadata.cs | 2 +- .../JReferenceTypeMetadata/Internal.cs | 2 +- .../Internal/NativeFunctionSetImplTests.cs | 2 +- .../ReferenceHelper/NativeInterface.cs | 57 ++++ .../NativeInterfaceProxy.cs | 17 ++ ...erface.Implementation.Tests.Proxies.csproj | 7 + .../BooleanCallTests.cs | 145 +++++++++ .../BooleanFieldTests.cs | 120 ++++++++ .../ByteCallTests.cs | 145 +++++++++ .../ByteFieldTests.cs | 119 ++++++++ .../CallType.cs | 11 + .../CharCallTests.cs | 145 +++++++++ .../CharFieldTests.cs | 119 ++++++++ .../ConstructorCallTests.cs | 60 ++++ .../DoubleCallTests.cs | 145 +++++++++ .../DoubleFieldTests.cs | 119 ++++++++ .../ExceptionHandlingTests/ThrowNewTests.cs | 96 ++++++ .../FloatCallTests.cs | 145 +++++++++ .../FloatFieldTests.cs | 119 ++++++++ .../IntCallTests.cs | 145 +++++++++ .../IntFieldTests.cs | 119 ++++++++ .../LongCallTests.cs | 145 +++++++++ .../LongFieldTests.cs | 119 ++++++++ .../ObjectCallTests.cs | 155 ++++++++++ .../ObjectFieldTests.cs | 132 ++++++++ .../PrimitiveArrayMemoryTests.cs | 48 ++- ....JNetInterface.Implementation.Tests.csproj | 1 + .../ShortCallTests.cs | 145 +++++++++ .../ShortFieldTests.cs | 119 ++++++++ .../StringMemoryTests.cs | 59 ++++ .../TestUtilities.cs | 115 ++++++- .../VoidCallTests.cs | 136 +++++++++ .../Restricted/AccessFeatureProxy.cs | 30 +- .../Restricted/Legacy/AccessFeatureProxy.cs | 39 ++- .../Access/JConstructorDefinitionTests.cs | 27 +- .../Native/Access/JFunctionDefinitionTests.cs | 43 +-- .../Native/Access/JMethodDefinitionTests.cs | 37 ++- 81 files changed, 3800 insertions(+), 361 deletions(-) create mode 100644 src/ApplicationTest/Rxmxnx.JNetInterface.FsApplicationTest/README.md create mode 100644 src/ApplicationTest/Rxmxnx.JNetInterface.VbApplicationTest/README.md create mode 100644 src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl/SingleObjectBuffer.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CallType.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ConstructorCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ExceptionHandlingTests/ThrowNewTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortCallTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortFieldTests.cs create mode 100644 src/Test/Rxmxnx.JNetInterface.Implementation.Tests/VoidCallTests.cs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 10b1118a..74a4c3ac 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,6 +63,19 @@ jobs: if ($LastExitCode -ne 0) { exit $LastExitCode } .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" if ($LastExitCode -ne 0) { exit $LastExitCode } + + - name: Patch Native ILLink.Substitutions + working-directory: ./src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/ILLink + run: sed -i -z 's/Rxmxnx.JNetInterface.Native.Intermediate/Rxmxnx.JNetInterface.Core/g;' ILLink.Substitutions.xml + - name: Patch Implementation ILLink.Substitutions + working-directory: ./src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/ILLink + run: sed -i -z 's/Rxmxnx.JNetInterface.Implementation.Intermediate/Rxmxnx.JNetInterface/g;' ILLink.Substitutions.xml + - name: Pack core assembly + working-directory: ./package/Rxmxnx.JNetInterface.Core + run: dotnet pack -c Release -o ../Nuget /p:Version=9999.99.99.99-tmp + - name: Pack main assembly + working-directory: ./package/Rxmxnx.JNetInterface + run: dotnet pack -c Release -o ../Nuget /p:Version=9999.99.99.99-tmp run-linux: runs-on: ubuntu-latest diff --git a/src/ApplicationTest/Rxmxnx.JNetInterface.FsApplicationTest/README.md b/src/ApplicationTest/Rxmxnx.JNetInterface.FsApplicationTest/README.md new file mode 100644 index 00000000..ddd309de --- /dev/null +++ b/src/ApplicationTest/Rxmxnx.JNetInterface.FsApplicationTest/README.md @@ -0,0 +1,285 @@ +# F# Support + +To support the use of `JNetInterface` in F#, it is necessary to explicitly use some constructors and methods that are +not usually required in C# code. + +## Primitives +In C#, `JNetInterface` uses operators to convert from one primitive type to another. However, this functionality must +be done explicitly in F# using constructors. + +```fsharp +let booleanValue = JBoolean true +let byteValue = JByte -2y +let charValue = JChar '\n' +let doubleValue = JDouble 3.14159265359 +let floatValue = JFloat 2.71828f +let intValue = JInt 486 +let longValue = JLong 3000000000L +let shortValue = JShort 1024s +``` + +## Reference Types +To map reference types from Java through `JNetInterface`, it is necessary to create classes (according to the rules +established for each case) that implement the indicated interfaces according to the reference type to be mapped. + +Unlike C#, F# does not support virtual implementation of static methods in interfaces, so it may be necessary to +implement homonymous methods according to the `JNetInterface` hierarchy. + +### Extensible class (`java.lang.Package`) +```fsharp +type JPackageObject = + inherit JLocalObject + + static let typeMetadata = + JLocalObject.TypeMetadataBuilder + .Create("java/lang/Package"B) + .Build() + + new(initializer: IReferenceType.ClassInitializer) = { inherit JLocalObject(initializer) } + new(initializer: IReferenceType.GlobalInitializer) = { inherit JLocalObject(initializer) } + new(initializer: IReferenceType.ObjectInitializer) = { inherit JLocalObject(initializer) } + + interface IDataType with + static member get_Metadata() = typeMetadata + + interface IReferenceType with + static member Create(initializer: IReferenceType.ObjectInitializer) = new JPackageObject(initializer) + + interface IClassType with + static member get_Metadata() = typeMetadata + static member Create(initializer: IReferenceType.ClassInitializer) = new JPackageObject(initializer) + static member Create(initializer: IReferenceType.GlobalInitializer) = new JPackageObject(initializer) + static member Create(initializer: IReferenceType.ObjectInitializer) = new JPackageObject(initializer) + + static member GetPackage(env: IEnvironment, packageName: String) : JPackageObject = + GetPackageDefinition.GetPackage(env, packageName) + +and private GetPackageDefinition private () = + inherit JFunctionDefinition("getPackage"B, JArgumentMetadata.Get()) + + static member val private Instance = GetPackageDefinition() with get + + member this.GetPackage(packageName: JStringObject) : JPackageObject = + let env = packageName.Environment + let args = this.CreateArgumentsArray() + let packageClass = JClassObject.GetClass(env) + args.[0] <- packageName + this.StaticInvoke(packageClass, args) + + static member GetPackage(env: IEnvironment, packageName: String) : JPackageObject = + use jString = JStringObject.Create(env, packageName) + env.WithFrame(3, jString, GetPackageDefinition.Instance.GetPackage) +``` + +### Non-instantiable class (`java.lang.Math`): +```fsharp +[] +type JMathObject private () = + inherit JLocalObject.Uninstantiable() + + static let typeMetadata = + JLocalObject.TypeMetadataBuilder.Create("java/lang/Math"B).Build() + + static let eDef = JFieldDefinition("E"B) + static let piDef = JFieldDefinition("PI"B) + static let absDef = MathFuncDefinition("abs"B) + static let atan2Def = MathFuncDefinition("atan2"B) + + static member GetE(env: IEnvironment) : JDouble = JMathObject.GetField(env, eDef) + static member GetPi(env: IEnvironment) : JDouble = JMathObject.GetField(env, piDef) + static member Abs(env: IEnvironment, value: JDouble) : JDouble = absDef.Invoke(env, value) + static member Atan2(env: IEnvironment, y: JDouble, x: JDouble) : JDouble = atan2Def.Invoke(env, y, x) + + interface IDataType with + static member get_Metadata() = typeMetadata + + interface IReferenceType with + static member Create(initializer: IReferenceType.ObjectInitializer) = + IUninstantiableType.ThrowInstantiation() + + interface IUninstantiableType with + static member get_Metadata() = typeMetadata + + static member Create(initializer: IReferenceType.ClassInitializer) = + IUninstantiableType.ThrowInstantiation() + + static member Create(initializer: IReferenceType.GlobalInitializer) = + IUninstantiableType.ThrowInstantiation() + + static member Create(initializer: IReferenceType.ObjectInitializer) = + IUninstantiableType.ThrowInstantiation() + + static member private GetField<'T + when 'T: unmanaged and 'T :> IPrimitiveType<'T> and 'T: (new: unit -> 'T) and 'T :> ValueType> + ( + env: IEnvironment, + field: JFieldDefinition<'T> + ) : 'T = + let state = { Environment = env; Def = field } + env.WithFrame(2, state, JMathObject.GetField<'T>) + + static member private GetField<'T + when 'T: unmanaged and 'T :> IPrimitiveType<'T> and 'T: (new: unit -> 'T) and 'T :> ValueType> + (state: FieldState<'T>) + : 'T = + let mathClass = JClassObject.GetClass(state.Environment) + state.Def.StaticGet(mathClass) + +and [] FieldState<'T + when 'T: struct and 'T :> IPrimitiveType<'T> and 'T: unmanaged and 'T: (new: unit -> 'T) and 'T :> ValueType> = + { Environment: IEnvironment + Def: JFieldDefinition<'T> } + +and private MathFuncDefinition<'TF, 'TX when 'TF :> IDataType<'TF> and 'TX :> IDataType<'TX>> + (funcName: ReadOnlySpan) = + inherit JFunctionDefinition<'TF>(funcName, JArgumentMetadata.Get<'TX>()) + + member this.Invoke(env: IEnvironment, x: 'TX) : 'TF = + let state = { Environment = env; Def = this; X = x } + env.WithFrame(2, state, MathFuncDefinition<'TF, 'TX>.Invoke) + + static member Invoke(state: State<'TF, 'TX>) : 'TF = + let mathClass = JClassObject.GetClass(state.Environment) + let args = state.Def.CreateArgumentsArray() + args.[0] <- state.X :> IObject + state.Def.StaticInvoke(mathClass, args) + +and [] private State<'TF, 'TX when 'TF :> IDataType<'TF> and 'TX :> IDataType<'TX>> = + { Environment: IEnvironment + Def: MathFuncDefinition<'TF, 'TX> + X: 'TX } + +and private MathFuncDefinition<'TF, 'TX, 'TY + when 'TF :> IDataType<'TF> and 'TX :> IDataType<'TX> and 'TY :> IDataType<'TY>>(funcName: ReadOnlySpan) = + inherit JFunctionDefinition<'TF>(funcName, JArgumentMetadata.Get<'TX>(), JArgumentMetadata.Get<'TY>()) + + member this.Invoke(env: IEnvironment, x: 'TX, y: 'TY) : 'TF = + let state = + { Environment = env + Def = this + X = x + Y = y } + + env.WithFrame(2, state, MathFuncDefinition<'TF, 'TX, 'TY>.Invoke) + + static member Invoke(state: State<'TF, 'TX, 'TY>) : 'TF = + let mathClass = JClassObject.GetClass(state.Environment) + let args = state.Def.CreateArgumentsArray() + args.[0] <- state.X :> IObject + args.[1] <- state.Y :> IObject + state.Def.StaticInvoke(mathClass, args) + +and [] private State<'TF, 'TX, 'TY + when 'TF :> IDataType<'TF> and 'TX :> IDataType<'TX> and 'TY :> IDataType<'TY>> = + { Environment: IEnvironment + Def: MathFuncDefinition<'TF, 'TX, 'TY> + X: 'TX + Y: 'TY } +``` + +### Throwable class (`java.lang.CloneNotSupportedException`): +```fsharp +type JCloneNotSupportedExceptionObject = + inherit JExceptionObject + static let typeMetadata = + JThrowableObject.TypeMetadataBuilder + .Create("java/lang/CloneNotSupportedException"B) + .Build() + + new(initializer: IReferenceType.ClassInitializer) = { inherit JExceptionObject(initializer) } + new(initializer: IReferenceType.GlobalInitializer) = { inherit JExceptionObject(initializer) } + new(initializer: IReferenceType.ObjectInitializer) = { inherit JExceptionObject(initializer) } + + interface IDataType with + static member get_Metadata() = typeMetadata + + interface IReferenceType with + static member Create(initializer: IReferenceType.ObjectInitializer) = new JCloneNotSupportedExceptionObject(initializer) + + interface IClassType with + static member get_Metadata() = typeMetadata + static member Create(initializer: IReferenceType.ClassInitializer) = new JCloneNotSupportedExceptionObject(initializer) + static member Create(initializer: IReferenceType.GlobalInitializer) = new JCloneNotSupportedExceptionObject(initializer) + static member Create(initializer: IReferenceType.ObjectInitializer) = new JCloneNotSupportedExceptionObject(initializer) + + interface IThrowableType with + static member get_Metadata() = typeMetadata +``` + +### Enum class (`java.lang.Thread.State`): +Note that in this case, the enum values were not declared. However, this functionality is supported in F#. + +```fsharp +[] +type JThreadStateObject = + inherit JEnumObject + + static let typeMetadata = + JEnumObject.TypeMetadataBuilder + .Create("java/lang/Thread$State"B) + .Build() + + new(initializer: IReferenceType.ClassInitializer) = { inherit JEnumObject(initializer) } + new(initializer: IReferenceType.GlobalInitializer) = { inherit JEnumObject(initializer) } + new(initializer: IReferenceType.ObjectInitializer) = { inherit JEnumObject(initializer) } + + interface IDataType with + static member get_Metadata() = typeMetadata + + interface IReferenceType with + static member Create(initializer: IReferenceType.ObjectInitializer) = new JThreadStateObject(initializer) + + interface IEnumType with + static member get_Metadata() = typeMetadata + static member Create(initializer: IReferenceType.ClassInitializer) = new JThreadStateObject(initializer) + static member Create(initializer: IReferenceType.GlobalInitializer) = new JThreadStateObject(initializer) + static member Create(initializer: IReferenceType.ObjectInitializer) = new JThreadStateObject(initializer) +``` + +### Interface type (`java.lang.AutoCloseable`): +```fsharp +[] +type JAutoCloseableObject = + inherit JInterfaceObject + + static let typeMetadata = + JInterfaceObject.TypeMetadataBuilder + .Create("java/lang/AutoCloseable"B) + .Build() + + new(initializer: IReferenceType.ObjectInitializer) = { inherit JInterfaceObject(initializer) } + + interface IDataType with + static member get_Metadata() = typeMetadata + + interface IReferenceType with + static member Create(initializer: IReferenceType.ObjectInitializer) = new JAutoCloseableObject(initializer) + + interface IInterfaceType with + static member get_Metadata() = typeMetadata + static member Create(initializer: IReferenceType.ObjectInitializer) = new JAutoCloseableObject(initializer) +``` + +### Annotation type (`java.lang.Deprecated`): +```fsharp +[] +type JDeprecatedObject = + inherit JAnnotationObject + + static let typeMetadata = + JInterfaceObject.TypeMetadataBuilder + .Create("java/lang/Deprecated"B) + .Build() + + new(initializer: IReferenceType.ObjectInitializer) = { inherit JAnnotationObject(initializer) } + + interface IDataType with + static member get_Metadata() = typeMetadata + + interface IReferenceType with + static member Create(initializer: IReferenceType.ObjectInitializer) = new JDeprecatedObject(initializer) + + interface IInterfaceType with + static member get_Metadata() = typeMetadata + static member Create(initializer: IReferenceType.ObjectInitializer) = new JDeprecatedObject(initializer) +``` \ No newline at end of file diff --git a/src/ApplicationTest/Rxmxnx.JNetInterface.LibraryTest/GetObjectDefinition.cs b/src/ApplicationTest/Rxmxnx.JNetInterface.LibraryTest/GetObjectDefinition.cs index 40c2d397..ea827619 100644 --- a/src/ApplicationTest/Rxmxnx.JNetInterface.LibraryTest/GetObjectDefinition.cs +++ b/src/ApplicationTest/Rxmxnx.JNetInterface.LibraryTest/GetObjectDefinition.cs @@ -24,9 +24,5 @@ public class GetObjectDefinition : JFunctionDefinition private GetObjectDefinition() : base("getObject"u8, JArgumentMetadata.Get()) { } public JLocalObject? Invoke(JClassObject helloDotnetClass, JInt value) - { - IObject?[] invokeArgs = this.CreateArgumentsArray(); - invokeArgs[0] = value; - return this.StaticInvoke(helloDotnetClass, invokeArgs); - } + => this.StaticInvoke(helloDotnetClass, [value,]); } \ No newline at end of file diff --git a/src/ApplicationTest/Rxmxnx.JNetInterface.VbApplicationTest/README.md b/src/ApplicationTest/Rxmxnx.JNetInterface.VbApplicationTest/README.md new file mode 100644 index 00000000..3304453c --- /dev/null +++ b/src/ApplicationTest/Rxmxnx.JNetInterface.VbApplicationTest/README.md @@ -0,0 +1,21 @@ +# Visual Basic .NET Support + +`JNetInterface` is partially compatible with Visual Basic .NET because the latter does not support many of the modern +.NET features such as ref structs and static members in interfaces. + +Thus, any application or library in Visual Basic .NET can use the APIs and types exposed in `JNetInterface` (or in F# +or C# assemblies derived from it), but it will not be able to create Java reference types as in C# or F#. + +## Primitives +In C#, `JNetInterface` uses operators to convert from one primitive type to another. In Visual Basic .NET, `widening` can be used natively, but to use `narrowing` (which is implemented in C# through explicit operators), you must use the functions `CBool`, `CSByte`, `CChar`, `CDbl`, `CSng`, `CInt`, `CLng`, and `CShort` on the `Value` property of each primitive type. + +```vb +Dim booleanValue As JBoolean = True +Dim byteValue As JByte = CSByte(-2) +Dim charValue As JChar = "."C +Dim doubleValue As JDouble = 3.14159265359 +Dim floatValue As JFloat = 2.71828F +Dim intValue As JInt = 486 +Dim longValue As JLong = 3000000000L +Dim shortValue As JShort = 1024S +``` diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/IObject.cs b/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/IObject.cs index d6ace9ee..04298a64 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/IObject.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/IObject.cs @@ -39,4 +39,14 @@ internal void CopyTo(Span span) /// Binary span. /// Index to copy current value. internal void CopyTo(Span span, Int32 index); + /// + /// Indicates current instance is default value. + /// + /// if current instance is default; otherwise, . + internal Boolean IsDefault() + { + Span values = stackalloc Byte[JValue.Size]; + this.CopyTo(values); + return values.SequenceEqual(NativeUtilities.AsBytes(in JValue.Empty)); + } } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Constructor.cs b/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Constructor.cs index de4b6a77..37d392df 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Constructor.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Constructor.cs @@ -7,8 +7,8 @@ public abstract partial class JCallDefinition /// /// Call defined name. /// Metadata of the types of call arguments. - private protected JCallDefinition(ReadOnlySpan name, params JArgumentMetadata[] metadata) : this( - name, stackalloc Byte[1] { CommonNames.VoidSignatureChar, }, metadata) { } + private protected JCallDefinition(ReadOnlySpan name, ReadOnlySpan metadata = default) : + this(name, [CommonNames.VoidSignatureChar,], metadata) { } /// /// Internal constructor. /// @@ -16,11 +16,11 @@ private protected JCallDefinition(ReadOnlySpan name, params JArgumentMetad /// Method return type defined signature. /// Metadata of the types of call arguments. private protected JCallDefinition(ReadOnlySpan name, ReadOnlySpan returnTypeSignature, - params JArgumentMetadata[] metadata) : base(new CStringSequence( - name, - JCallDefinition.CreateDescriptor( - returnTypeSignature, out Int32 size, out Int32[] sizes, - out Int32 referenceCount, metadata))) + ReadOnlySpan metadata) : base(new CStringSequence( + name, + JCallDefinition.CreateDescriptor( + returnTypeSignature, out Int32 size, out Int32[] sizes, + out Int32 referenceCount, metadata))) { this._callSize = size; this._sizes = sizes; diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Private.cs b/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Private.cs index 513e4d58..9657c98d 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Private.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Base.Intermediate/Native/Access/JCallDefinition/Private.cs @@ -25,7 +25,7 @@ public abstract partial class JCallDefinition /// Metadata of the types of call arguments. /// Method descriptor. private static CString CreateDescriptor(ReadOnlySpan returnSignature, out Int32 totalSize, out Int32[] sizes, - out Int32 referenceCount, params JArgumentMetadata[] metadata) + out Int32 referenceCount, ReadOnlySpan metadata) { referenceCount = 0; totalSize = 0; diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl.cs b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl.cs index c8818aec..3c77cdc2 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl.cs @@ -32,8 +32,8 @@ public override Int32 GetOrdinal(JEnumObject jEnum) IEnvironment env = jEnum.Environment; JClassObject enumClass = env.ClassFeature.EnumObject; Span bytes = stackalloc Byte[sizeof(Int32)]; - env.AccessFeature.CallPrimitiveFunction(bytes, jEnum, enumClass, NativeFunctionSetImpl.OrdinalDefinition, false, - []); + env.AccessFeature.CallPrimitiveFunction(bytes, jEnum, enumClass, NativeFunctionSetImpl.OrdinalDefinition, + false); return bytes.AsValue(); } @@ -60,7 +60,7 @@ public override Int32 GetLineNumber(JStackTraceElementObject jStackTraceElement) Span bytes = stackalloc Byte[sizeof(Int32)]; JClassObject stackTraceElementClass = env.ClassFeature.StackTraceElementObject; env.AccessFeature.CallPrimitiveFunction(bytes, jStackTraceElement, stackTraceElementClass, - NativeFunctionSetImpl.GetLineNumberDefinition, false, []); + NativeFunctionSetImpl.GetLineNumberDefinition, false); return bytes.AsValue(); } /// @@ -86,7 +86,7 @@ public override Boolean IsNativeMethod(JStackTraceElementObject jStackTraceEleme Span bytes = stackalloc Byte[1]; JClassObject stackTraceElementClass = env.ClassFeature.StackTraceElementObject; env.AccessFeature.CallPrimitiveFunction(bytes, jStackTraceElement, stackTraceElementClass, - NativeFunctionSetImpl.IsNativeMethodDefinition, false, []); + NativeFunctionSetImpl.IsNativeMethodDefinition, false); return bytes[0] == JBoolean.TrueValue; } @@ -106,7 +106,7 @@ public override TPrimitive GetPrimitiveValue(JNumberObject jNumber) _ => NativeFunctionSetImpl.DoubleValueDefinition, }; Span bytes = stackalloc Byte[metadata.SizeOf]; - env.AccessFeature.CallPrimitiveFunction(bytes, jNumber, numberClass, functionDefinition, false, []); + env.AccessFeature.CallPrimitiveFunction(bytes, jNumber, numberClass, functionDefinition, false); return bytes.AsValue(); } @@ -131,7 +131,7 @@ public override Boolean IsPrimitiveClass(JClassObject jClass) Span bytes = stackalloc Byte[1]; JClassObject classClass = env.ClassFeature.ClassObject; env.AccessFeature.CallPrimitiveFunction(bytes, jClass, classClass, NativeFunctionSetImpl.IsPrimitiveDefinition, - false, []); + false); return bytes[0] == JBoolean.TrueValue; } /// @@ -157,7 +157,7 @@ public override Boolean IsDirectBuffer(JBufferObject jBuffer) IEnvironment env = jBuffer.Environment; Span bytes = stackalloc Byte[1]; env.AccessFeature.CallPrimitiveFunction(bytes, jBuffer, env.ClassFeature.BufferObject, - NativeFunctionSetImpl.IsDirectBufferDefinition, false, []); + NativeFunctionSetImpl.IsDirectBufferDefinition, false); return bytes[0] == JBoolean.TrueValue; } /// @@ -166,7 +166,7 @@ public override Int64 BufferCapacity(JBufferObject jBuffer) IEnvironment env = jBuffer.Environment; Span bytes = stackalloc Byte[sizeof(Int64)]; env.AccessFeature.CallPrimitiveFunction(bytes, jBuffer, env.ClassFeature.BufferObject, - NativeFunctionSetImpl.BufferCapacityDefinition, false, []); + NativeFunctionSetImpl.BufferCapacityDefinition, false); return bytes.AsValue(); } /// diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl/SingleObjectBuffer.cs b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl/SingleObjectBuffer.cs new file mode 100644 index 00000000..b3f61d1d --- /dev/null +++ b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/NativeFunctionSetImpl/SingleObjectBuffer.cs @@ -0,0 +1,18 @@ +namespace Rxmxnx.JNetInterface.Internal; + +internal partial class NativeFunctionSetImpl +{ + /// + /// Single object buffer. + /// + [SuppressMessage(CommonConstants.CSharpSquid, CommonConstants.CheckIdS1144, + Justification = CommonConstants.BinaryStructJustification)] + [InlineArray(1)] + public struct SingleObjectBuffer + { + private IObject? _value; + + public static Span GetSpan(ref SingleObjectBuffer buffer) + => MemoryMarshal.CreateSpan(ref Unsafe.As(ref buffer), 1); + } +} \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/PrimitiveWrapperConstructor.cs b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/PrimitiveWrapperConstructor.cs index 6ba7c48f..67df727c 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/PrimitiveWrapperConstructor.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Internal/PrimitiveWrapperConstructor.cs @@ -7,5 +7,5 @@ namespace Rxmxnx.JNetInterface.Internal; [SuppressMessage(CommonConstants.CSharpSquid, CommonConstants.CheckIdS2094, Justification = CommonConstants.ClassJustification)] internal sealed class PrimitiveWrapperConstructor() - : JConstructorDefinition(JArgumentMetadata.Get()) + : JConstructorDefinition([JArgumentMetadata.Get(),]) where TPrimitive : unmanaged, IPrimitiveType; \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Native/Access/JMainMethodDefinition.cs b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Native/Access/JMainMethodDefinition.cs index 99ef5f3a..eb8eb338 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Native/Access/JMainMethodDefinition.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Native/Access/JMainMethodDefinition.cs @@ -13,7 +13,7 @@ public sealed class JMainMethodDefinition : JMethodDefinition /// /// Constructor. /// - private JMainMethodDefinition() : base("main"u8, JArgumentMetadata.Get>()) { } + private JMainMethodDefinition() : base("main"u8, [JArgumentMetadata.Get>(),]) { } /// /// Invokes method defined in with null args. @@ -41,7 +41,8 @@ private void InvokeMain(JClassObject mainClass, JArrayObject? arg { try { - IObject?[] invokeArgs = this.CreateArgumentsArray(); + NativeFunctionSetImpl.SingleObjectBuffer buffer = new(); + Span invokeArgs = NativeFunctionSetImpl.SingleObjectBuffer.GetSpan(ref buffer); invokeArgs[0] = args; this.StaticInvoke(mainClass, invokeArgs); } diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/AccessFeature.cs b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/AccessFeature.cs index d1372bcb..052662cc 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/AccessFeature.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/AccessFeature.cs @@ -27,34 +27,6 @@ public abstract void SetStaticField(JClassObject jClass, JFieldDefinitio public abstract void SetStaticField(JFieldObject jField, JFieldDefinition definition, TField? value) where TField : IDataType, IObject; /// - public abstract TObject CallConstructor(JClassObject jClass, JConstructorDefinition definition, - IObject?[] args) where TObject : JLocalObject, IDataType; - /// - public abstract TObject CallConstructor(JConstructorObject jConstructor, JConstructorDefinition definition, - IObject?[] args) where TObject : JLocalObject, IClassType; - /// - public abstract TResult? CallStaticFunction(JClassObject jClass, JFunctionDefinition definition, - IObject?[] args) where TResult : IDataType; - /// - public abstract TResult? CallStaticFunction(JMethodObject jMethod, JFunctionDefinition definition, - IObject?[] args) where TResult : IDataType; - /// - public abstract void CallStaticMethod(JClassObject jClass, JMethodDefinition definition, IObject?[] args); - /// - public abstract void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, IObject?[] args); - /// - public abstract TResult? CallFunction(JLocalObject jLocal, JClassObject jClass, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) where TResult : IDataType; - /// - public abstract TResult? CallFunction(JMethodObject jMethod, JLocalObject jLocal, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) where TResult : IDataType; - /// - public abstract void CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, - Boolean nonVirtual, IObject?[] args); - /// - public abstract void CallMethod(JMethodObject jMethod, JLocalObject jLocal, JMethodDefinition definition, - Boolean nonVirtual, IObject?[] args); - /// public abstract void RegisterNatives(JClassObject jClass, IReadOnlyList calls); /// public abstract void ClearNatives(JClassObject jClass); @@ -79,4 +51,38 @@ public abstract JFieldObject GetReflectedField(JFieldDefinition definition, JCla public abstract JMethodId GetMethodId(JExecutableObject jExecutable); /// public abstract JFieldId GetFieldId(JFieldObject jField); + /// + public abstract TObject CallConstructor(JClassObject jClass, JConstructorDefinition definition, + IObject?[] args) where TObject : JLocalObject, IDataType; + /// + public abstract TObject CallConstructor(JConstructorObject jConstructor, JConstructorDefinition definition, + IObject?[] args) where TObject : JLocalObject, IClassType; + /// + public abstract TResult? CallStaticFunction(JClassObject jClass, JFunctionDefinition definition, + IObject?[] args) where TResult : IDataType; + /// + public abstract TResult? CallStaticFunction(JMethodObject jMethod, JFunctionDefinition definition, + IObject?[] args) where TResult : IDataType; + /// + public abstract void CallStaticMethod(JClassObject jClass, JMethodDefinition definition, IObject?[] args); + /// + public abstract void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, IObject?[] args); + /// + public abstract TResult? CallFunction(JLocalObject jLocal, JClassObject jClass, + JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) where TResult : IDataType; + /// + public abstract TResult? CallFunction(JMethodObject jMethod, JLocalObject jLocal, + JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) where TResult : IDataType; + /// + public abstract void CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, + Boolean nonVirtual, IObject?[] args); + /// + public abstract void CallMethod(JMethodObject jMethod, JLocalObject jLocal, JMethodDefinition definition, + Boolean nonVirtual, IObject?[] args); } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/Internal/AccessFeature.cs b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/Internal/AccessFeature.cs index bd3ec8cc..5175d875 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/Internal/AccessFeature.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Extensions.Intermediate/Proxies/EnvironmentProxy/Internal/AccessFeature.cs @@ -2,17 +2,47 @@ namespace Rxmxnx.JNetInterface.Proxies; public abstract partial class EnvironmentProxy { + TObject IAccessFeature.CallConstructor(JClassObject jClass, JConstructorDefinition definition, + ReadOnlySpan args) + => this.CallConstructor(jClass, definition, args.ToArray()); + TObject IAccessFeature.CallConstructor(JConstructorObject jConstructor, JConstructorDefinition definition, + ReadOnlySpan args) + => this.CallConstructor(jConstructor, definition, args.ToArray()); + TResult? IAccessFeature.CallStaticFunction(JClassObject jClass, JFunctionDefinition definition, + ReadOnlySpan args) where TResult : default + => this.CallStaticFunction(jClass, definition, args.ToArray()); + TResult? IAccessFeature.CallStaticFunction(JMethodObject jMethod, JFunctionDefinition definition, + ReadOnlySpan args) where TResult : default + => this.CallStaticFunction(jMethod, definition, args.ToArray()); + void IAccessFeature.CallStaticMethod(JClassObject jClass, JMethodDefinition definition, ReadOnlySpan args) + => this.CallStaticMethod(jClass, definition, args.ToArray()); + void IAccessFeature.CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, + ReadOnlySpan args) + => this.CallStaticMethod(jMethod, definition, args.ToArray()); + TResult? IAccessFeature.CallFunction(JLocalObject jLocal, JClassObject jClass, + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) where TResult : default + => this.CallFunction(jLocal, jClass, definition, nonVirtual, args.ToArray()); + TResult? IAccessFeature.CallFunction(JMethodObject jMethod, JLocalObject jLocal, + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) where TResult : default + => this.CallFunction(jMethod, jLocal, definition, nonVirtual, args.ToArray()); + void IAccessFeature.CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, + Boolean nonVirtual, ReadOnlySpan args) + => this.CallMethod(jLocal, jClass, definition, nonVirtual, args.ToArray()); + void IAccessFeature.CallMethod(JMethodObject jMethod, JLocalObject jLocal, JMethodDefinition definition, + Boolean nonVirtual, ReadOnlySpan args) + => this.CallMethod(jMethod, jLocal, definition, nonVirtual, args.ToArray()); TResult IAccessFeature.CallInternalStaticFunction(JClassObject jClass, JFunctionDefinition definition, - IObject?[] args) - => this.CallStaticFunction(jClass, definition, args.Normalize())!; - void IAccessFeature.CallInternalStaticMethod(JClassObject jClass, JMethodDefinition definition, IObject?[] args) - => this.CallStaticMethod(jClass, definition, args.Normalize()); + ReadOnlySpan args) + => this.CallStaticFunction(jClass, definition, args.ToArray().Normalize())!; + void IAccessFeature.CallInternalStaticMethod(JClassObject jClass, JMethodDefinition definition, + ReadOnlySpan args) + => this.CallStaticMethod(jClass, definition, args.ToArray().Normalize()); TResult IAccessFeature.CallInternalFunction(JLocalObject jLocal, JClassObject jClass, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) - => this.CallFunction(jLocal, jClass, definition, nonVirtual, args.Normalize())!; + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) + => this.CallFunction(jLocal, jClass, definition, nonVirtual, args.ToArray().Normalize())!; void IAccessFeature.CallInternalMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, - Boolean nonVirtual, IObject?[] args) - => this.CallMethod(jLocal, jClass, definition, nonVirtual, args.Normalize()); + Boolean nonVirtual, ReadOnlySpan args) + => this.CallMethod(jLocal, jClass, definition, nonVirtual, args.ToArray().Normalize()); void IAccessFeature.GetPrimitiveField(Span bytes, JLocalObject jLocal, JClassObject jClass, JFieldDefinition definition) @@ -27,9 +57,9 @@ void IAccessFeature.SetPrimitiveStaticField(JClassObject jClass, JFieldDefinitio => definition.PrimitiveStaticSet(jClass, bytes); void IAccessFeature.CallPrimitiveStaticFunction(Span bytes, JClassObject jClass, - JFunctionDefinition definition, IObject?[] args) - => definition.PrimitiveStaticInvoke(bytes, jClass, args); + JFunctionDefinition definition, ReadOnlySpan args) + => definition.PrimitiveStaticInvoke(bytes, jClass, args.ToArray()); void IAccessFeature.CallPrimitiveFunction(Span bytes, JLocalObject jLocal, JClassObject jClass, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) - => definition.PrimitiveInvoke(bytes, jLocal, jClass, nonVirtual, args); + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) + => definition.PrimitiveInvoke(bytes, jLocal, jClass, nonVirtual, args.ToArray()); } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/MetadataHelper.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/MetadataHelper.cs index 658b9c7b..b3d56dce 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/MetadataHelper.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/MetadataHelper.cs @@ -111,7 +111,7 @@ public static JFieldDefinition GetFieldDefinition(JClassObject jClass, ReadOnlyS /// Definition parameters metadata. /// A instance. public static JCallDefinition GetCallDefinition(JClassObject jClass, ReadOnlySpan callName, - JArgumentMetadata[] paramsMetadata) + ReadOnlySpan paramsMetadata) { switch (jClass.ClassSignature[0]) { diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/UnknownReflectionMetadata.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/UnknownReflectionMetadata.cs index 76e7e0a0..4108b472 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/UnknownReflectionMetadata.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/Internal/UnknownReflectionMetadata.cs @@ -14,9 +14,9 @@ internal readonly struct UnknownReflectionMetadata public UnknownReflectionMetadata(ReadOnlySpan signature) => this.ArgumentMetadata = JArgumentMetadata.Create(signature); - /// + /// public JFunctionDefinition CreateFunctionDefinition(ReadOnlySpan functionName, - JArgumentMetadata[] paramsMetadata) + ReadOnlySpan paramsMetadata) => new JNonTypedFunctionDefinition(functionName, this.ArgumentMetadata.Signature, paramsMetadata); /// public JFieldDefinition CreateFieldDefinition(ReadOnlySpan fieldName) diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/AccessFeature.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/AccessFeature.cs index 08de3586..bc6c5ae6 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/AccessFeature.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/AccessFeature.cs @@ -51,7 +51,7 @@ public void SetPrimitiveStaticField(JClassObject jClass, JFieldDefinition defini this.SetPrimitiveStaticField(jClass.Reference, bytes, definition.Descriptor[^1], fieldId); } public void CallPrimitiveStaticFunction(Span bytes, JClassObject jClass, JFunctionDefinition definition, - IObject?[] args) + ReadOnlySpan args = default) { ImplementationValidationUtilities.ThrowIfProxy(jClass); using INativeTransaction jniTransaction = @@ -59,7 +59,7 @@ public void CallPrimitiveStaticFunction(Span bytes, JClassObject jClass, J this.CallPrimitiveStaticFunction(bytes, definition, jClass.Reference, args, jniTransaction, methodId); } public void CallPrimitiveFunction(Span bytes, JLocalObject jLocal, JClassObject jClass, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args = default) { ImplementationValidationUtilities.ThrowIfProxy(jLocal); ImplementationValidationUtilities.ThrowIfProxy(jClass); @@ -223,15 +223,15 @@ public void SetStaticField(JFieldObject jField, JFieldDefinition definit this.SetPrimitiveStaticField(classRef, bytes, definition.Descriptor[^1], fieldId); } } - public TObject CallConstructor(JClassObject jClass, JConstructorDefinition definition, IObject?[] args) - where TObject : JLocalObject, IDataType + public TObject CallConstructor(JClassObject jClass, JConstructorDefinition definition, + ReadOnlySpan args) where TObject : JLocalObject, IDataType { JObjectLocalRef localRef = this.NewObject(jClass, definition, args); JTrace.CallMethod(default, jClass, definition, false, args); return this.CreateObject(localRef, true, true)!; } public TObject CallConstructor(JConstructorObject jConstructor, JConstructorDefinition definition, - IObject?[] args) where TObject : JLocalObject, IClassType + ReadOnlySpan args) where TObject : JLocalObject, IClassType { ImplementationValidationUtilities.ThrowIfProxy(jConstructor); ImplementationValidationUtilities.ThrowIfNotMatchDefinition(definition, jConstructor.Definition); @@ -245,7 +245,7 @@ public TObject CallConstructor(JConstructorObject jConstructor, JConstr return this.CreateObject(localRef, true, true)!; } public TResult? CallStaticFunction(JClassObject jClass, JFunctionDefinition definition, - IObject?[] args) where TResult : IDataType + ReadOnlySpan args) where TResult : IDataType { JDataTypeMetadata metadata = MetadataHelper.GetExactMetadata(); if (metadata is JPrimitiveTypeMetadata primitiveMetadata) @@ -261,7 +261,7 @@ public TObject CallConstructor(JConstructorObject jConstructor, JConstr return this.CallObjectStaticFunction(definition, jClass.Reference, args, jniTransaction, methodId); } public TResult? CallStaticFunction(JMethodObject jMethod, JFunctionDefinition definition, - IObject?[] args) where TResult : IDataType + ReadOnlySpan args) where TResult : IDataType { ImplementationValidationUtilities.ThrowIfProxy(jMethod); ImplementationValidationUtilities.ThrowIfNotMatchDefinition(definition, jMethod.Definition); @@ -278,7 +278,7 @@ public TObject CallConstructor(JConstructorObject jConstructor, JConstr this.CallPrimitiveStaticFunction(bytes, definition, classRef, args, jniTransaction, methodId); return (TResult)primitiveMetadata.CreateInstance(bytes); } - public void CallStaticMethod(JClassObject jClass, JMethodDefinition definition, IObject?[] args) + public void CallStaticMethod(JClassObject jClass, JMethodDefinition definition, ReadOnlySpan args) { ImplementationValidationUtilities.ThrowIfProxy(jClass); using INativeTransaction jniTransaction = @@ -286,7 +286,7 @@ public void CallStaticMethod(JClassObject jClass, JMethodDefinition definition, JTrace.CallMethod(default, jClass, definition, false, args); this.CallStaticMethod(definition, jClass.Reference, args, jniTransaction, methodId); } - public void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, IObject?[] args) + public void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, ReadOnlySpan args) { ImplementationValidationUtilities.ThrowIfProxy(jMethod); ImplementationValidationUtilities.ThrowIfNotMatchDefinition(definition, jMethod.Definition); @@ -299,7 +299,7 @@ public void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition this.CallStaticMethod(definition, classRef, args, jniTransaction, methodId); } public TResult? CallFunction(JLocalObject jLocal, JClassObject jClass, JFunctionDefinition definition, - Boolean nonVirtual, IObject?[] args) where TResult : IDataType + Boolean nonVirtual, ReadOnlySpan args) where TResult : IDataType { JDataTypeMetadata metadata = MetadataHelper.GetExactMetadata(); if (metadata is JPrimitiveTypeMetadata primitiveMetadata) @@ -318,7 +318,8 @@ public void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition return this.CallObjectFunction(definition, localRef, classRef, args, jniTransaction, methodId); } public TResult? CallFunction(JMethodObject jMethod, JLocalObject jLocal, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) where TResult : IDataType + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) + where TResult : IDataType { ImplementationValidationUtilities.ThrowIfProxy(jMethod); ImplementationValidationUtilities.ThrowIfProxy(jLocal); @@ -340,7 +341,7 @@ public void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition return (TResult)primitiveMetadata.CreateInstance(bytes); } public void CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, - Boolean nonVirtual, IObject?[] args) + Boolean nonVirtual, ReadOnlySpan args) { ImplementationValidationUtilities.ThrowIfProxy(jLocal); ImplementationValidationUtilities.ThrowIfProxy(jClass); @@ -352,7 +353,7 @@ public void CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefiniti this.CallMethod(definition, localRef, classRef, args, jniTransaction, methodId); } public void CallMethod(JMethodObject jMethod, JLocalObject jLocal, JMethodDefinition definition, - Boolean nonVirtual, IObject?[] args) + Boolean nonVirtual, ReadOnlySpan args) { ImplementationValidationUtilities.ThrowIfProxy(jMethod); ImplementationValidationUtilities.ThrowIfProxy(jLocal); @@ -417,7 +418,7 @@ public JCallDefinition GetDefinition(JStringObject memberName, JArrayObject mem = memberName.GetNativeUtf8Chars(); return MetadataHelper.GetCallDefinition(returnType, mem.Values, args); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ArrayFeature.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ArrayFeature.cs index 76a56ca3..88e28d87 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ArrayFeature.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ArrayFeature.cs @@ -51,7 +51,8 @@ public JArrayObject CreateArray(Int32 length, TElement initi if (MetadataHelper.GetExactMetadata() is JPrimitiveTypeMetadata metadata) { result = this.CreateArray(length); - this.FillPrimitiveArray(result, metadata, initialElement); + if (length > 0 && !initialElement.IsDefault()) + this.FillPrimitiveArray(result, metadata, initialElement); } else { @@ -80,7 +81,7 @@ public unsafe Int32 GetArrayLength(JReferenceObject jObject) { Span buffer = stackalloc Byte[primitiveMetadata.SizeOf]; fixed (Byte* ptr = &MemoryMarshal.GetReference(buffer)) - this.GetPrimitiveArrayRegion(jArray, primitiveMetadata.Signature, new(ptr), index); + this.GetPrimitiveArrayRegion(jArray, primitiveMetadata.Signature[0], new(ptr), index); this.CheckJniError(); return (TElement)primitiveMetadata.CreateInstance(buffer); } @@ -98,7 +99,7 @@ public unsafe void SetElement(JArrayObject jArray, Int32 ind Span buffer = stackalloc Byte[primitiveMetadata.SizeOf]; value!.CopyTo(buffer); fixed (Byte* ptr = &MemoryMarshal.GetReference(buffer)) - this.SetPrimitiveArrayRegion(jArray, primitiveMetadata.Signature, new(ptr), index); + this.SetPrimitiveArrayRegion(jArray, primitiveMetadata.Signature[0], new(ptr), index); this.CheckJniError(); } else @@ -215,7 +216,7 @@ public unsafe void GetCopy(JArrayObject jArray, Span(); fixed (TPrimitive* ptr = &MemoryMarshal.GetReference(elements)) - this.GetPrimitiveArrayRegion(jArray, metadata.Signature, new(ptr), startIndex, elements.Length); + this.GetPrimitiveArrayRegion(jArray, metadata.Signature[0], new(ptr), startIndex, elements.Length); this.CheckJniError(); } public unsafe void SetCopy(JArrayObject jArray, ReadOnlySpan elements, @@ -224,7 +225,7 @@ public unsafe void SetCopy(JArrayObject jArray, ReadOnly ImplementationValidationUtilities.ThrowIfProxy(jArray); JPrimitiveTypeMetadata metadata = IPrimitiveType.GetMetadata(); fixed (TPrimitive* ptr = &MemoryMarshal.GetReference(elements)) - this.SetPrimitiveArrayRegion(jArray, metadata.Signature, new(ptr), startIndex, elements.Length); + this.SetPrimitiveArrayRegion(jArray, metadata.Signature[0], new(ptr), startIndex, elements.Length); this.CheckJniError(); } } diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache.cs index 360b6836..7a4a175e 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache.cs @@ -125,6 +125,16 @@ public unsafe JThrowableLocalRef GetPendingException() return nativeInterface.ErrorFunctions.ExceptionOccurred(this.Reference); } /// + /// Checks if there is a pending JNI exception. + /// + /// if there is pending JNI exception; otherwise, . + public unsafe Boolean HasPendingException() + { + ref readonly NativeInterface nativeInterface = + ref this.GetNativeInterface(NativeInterface.ExceptionCheckInfo); + return nativeInterface.ExceptionCheck(this.Reference).Value; + } + /// /// Creates JNI exception from . /// /// A reference. diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Access.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Access.cs index c0d5a1e5..1bd71ee8 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Access.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Access.cs @@ -126,7 +126,7 @@ private unsafe JObjectLocalRef GetReflectedCall(JCallDefinition definition, JCla /// instance. /// identifier. private unsafe TResult? CallObjectFunction(JFunctionDefinition definition, JObjectLocalRef localRef, - JClassLocalRef classRef, IObject?[] args, INativeTransaction jniTransaction, JMethodId methodId) + JClassLocalRef classRef, ReadOnlySpan args, INativeTransaction jniTransaction, JMethodId methodId) where TResult : IDataType { ref readonly InstanceMethodFunctionSet instanceMethodFunctions = @@ -161,8 +161,8 @@ private unsafe JObjectLocalRef GetReflectedCall(JCallDefinition definition, JCla /// instance. /// identifier. private unsafe void CallPrimitiveFunction(Span bytes, JFunctionDefinition definition, - JObjectLocalRef localRef, JClassLocalRef classRef, IObject?[] args, INativeTransaction jniTransaction, - JMethodId methodId) + JObjectLocalRef localRef, JClassLocalRef classRef, ReadOnlySpan args, + INativeTransaction jniTransaction, JMethodId methodId) { using StackDisposable stackDisposable = this.GetStackDisposable(this.UseStackAlloc(definition, out Int32 requiredBytes), requiredBytes); @@ -191,7 +191,7 @@ private unsafe void CallPrimitiveFunction(Span bytes, JFunctionDefinition /// identifier. /// function result. private unsafe TResult? CallObjectStaticFunction(JFunctionDefinition definition, - JClassLocalRef classRef, IObject?[] args, INativeTransaction jniTransaction, JMethodId methodId) + JClassLocalRef classRef, ReadOnlySpan args, INativeTransaction jniTransaction, JMethodId methodId) where TResult : IDataType { ref readonly NativeInterface nativeInterface = @@ -222,7 +222,7 @@ private unsafe void CallPrimitiveFunction(Span bytes, JFunctionDefinition /// instance. /// identifier. private unsafe void CallMethod(JMethodDefinition definition, JObjectLocalRef localRef, JClassLocalRef classRef, - IObject?[] args, INativeTransaction jniTransaction, JMethodId methodId) + ReadOnlySpan args, INativeTransaction jniTransaction, JMethodId methodId) { ref readonly InstanceMethodFunctionSet instanceMethodFunctions = ref this.GetInstanceMethodFunctions(CommonNames.VoidSignatureChar, !classRef.IsDefault); @@ -252,8 +252,8 @@ private unsafe void CallMethod(JMethodDefinition definition, JObjectLocalRef loc /// The array with call arguments. /// instance. /// identifier. - private unsafe void CallStaticMethod(JMethodDefinition definition, JClassLocalRef classRef, IObject?[] args, - INativeTransaction jniTransaction, JMethodId methodId) + private unsafe void CallStaticMethod(JMethodDefinition definition, JClassLocalRef classRef, + ReadOnlySpan args, INativeTransaction jniTransaction, JMethodId methodId) { ref readonly NativeInterface nativeInterface = ref this.GetNativeInterface(NativeInterface.CallStaticVoidMethodInfo); @@ -277,7 +277,7 @@ private unsafe void CallStaticMethod(JMethodDefinition definition, JClassLocalRe /// The array with call arguments. /// A reference. private JObjectLocalRef NewObject(JClassObject jClass, JConstructorDefinition definition, - params IObject?[] args) + ReadOnlySpan args) { ImplementationValidationUtilities.ThrowIfProxy(jClass); using INativeTransaction jniTransaction = @@ -296,7 +296,7 @@ private JObjectLocalRef NewObject(JClassObject jClass, JConstructorDefinition de /// identifier. /// A reference. private unsafe JObjectLocalRef NewObject(JConstructorDefinition definition, JClassLocalRef classRef, - IObject?[] args, INativeTransaction jniTransaction, JMethodId methodId) + ReadOnlySpan args, INativeTransaction jniTransaction, JMethodId methodId) { ref readonly NativeInterface nativeInterface = ref this.GetNativeInterface(NativeInterface.NewObjectInfo); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Arrays.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Arrays.cs index a27ace65..a62f4fa3 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Arrays.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Arrays.cs @@ -263,13 +263,13 @@ private unsafe void ReleasePrimitiveArrayElements(JArrayLocalRef arrayRef, Byte /// Region start index. /// Number of elements in region. /// - private unsafe void GetPrimitiveArrayRegion(JArrayObject jArray, CString signature, IntPtr bufferPtr, - Int32 index, Int32 count = 1) + private unsafe void GetPrimitiveArrayRegion(JArrayObject jArray, Byte signature, IntPtr bufferPtr, Int32 index, + Int32 count = 1) { using INativeTransaction jniTransaction = this.VirtualMachine.CreateTransaction(1); ref readonly ArrayFunctionSet arrayFunctions = - ref this.GetArrayFunctions(signature[0], ArrayFunctionSet.PrimitiveFunction.GetRegion); - switch (signature[0]) + ref this.GetArrayFunctions(signature, ArrayFunctionSet.PrimitiveFunction.GetRegion); + switch (signature) { case CommonNames.BooleanSignatureChar: JBooleanArrayLocalRef jBooleanArrayRef = jniTransaction.Add(jArray); @@ -322,13 +322,13 @@ private unsafe void GetPrimitiveArrayRegion(JArrayObject jArray, CString signatu /// Region start index. /// Number of elements in region. /// - private unsafe void SetPrimitiveArrayRegion(JArrayObject jArray, CString signature, IntPtr bufferPtr, - Int32 index, Int32 count = 1) + private unsafe void SetPrimitiveArrayRegion(JArrayObject jArray, Byte signature, IntPtr bufferPtr, Int32 index, + Int32 count = 1) { using INativeTransaction jniTransaction = this.VirtualMachine.CreateTransaction(1); ref readonly ArrayFunctionSet arrayFunctions = - ref this.GetArrayFunctions(signature[0], ArrayFunctionSet.PrimitiveFunction.SetRegion); - switch (signature[0]) + ref this.GetArrayFunctions(signature, ArrayFunctionSet.PrimitiveFunction.SetRegion); + switch (signature) { case CommonNames.BooleanSignatureChar: JBooleanArrayLocalRef jBooleanArrayRef = jniTransaction.Add(jArray); @@ -413,7 +413,7 @@ private unsafe void FillPrimitiveArray(JArrayObject jArray, JDataTypeM while (offset < requiredBytes) initialElement.CopyTo(buffer, ref offset); fixed (Byte* ptr = &MemoryMarshal.GetReference(buffer)) - this.SetPrimitiveArrayRegion(jArray, metadata.Signature, new(ptr), 0, jArray.Length); + this.SetPrimitiveArrayRegion(jArray, metadata.Signature[0], new(ptr), 0, jArray.Length); } } } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/PrimitiveAccess.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/PrimitiveAccess.cs index 11af7c25..bcee566c 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/PrimitiveAccess.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/PrimitiveAccess.cs @@ -272,7 +272,7 @@ private unsafe void GetPrimitiveField(Span bytes, JObjectLocal /// instance. /// identifier. private unsafe void CallPrimitiveStaticFunction(Span bytes, JFunctionDefinition definition, - JClassLocalRef classRef, IObject?[] args, INativeTransaction jniTransaction, JMethodId methodId) + JClassLocalRef classRef, ReadOnlySpan args, INativeTransaction jniTransaction, JMethodId methodId) { Byte signature = definition.Descriptor[^1]; ref readonly MethodFunctionSet staticMethodFunctions = @@ -504,6 +504,16 @@ private unsafe void CallPrimitiveFunction(Span bytes, JObjectL private JArgumentMetadata[] GetCallMetadata(JArrayObject parameterTypes) { JArgumentMetadata[] args = new JArgumentMetadata[parameterTypes.Length]; + this.GetCallMetadata(parameterTypes, args); + return args; + } + /// + /// Fills with metadata types. + /// + /// A list. + /// A span. + private void GetCallMetadata(JArrayObject parameterTypes, Span args) + { JObjectArrayLocalRef objectArrayRef = parameterTypes.As(); for (Int32 i = 0; i < parameterTypes.Length; i++) { @@ -511,7 +521,6 @@ private JArgumentMetadata[] GetCallMetadata(JArrayObject parameter JClassObject jClass = this.GetClass(JClassLocalRef.FromReference(in localRef), true); args[i] = MetadataHelper.GetArgumentMetadata(jClass); } - return args; } } } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Private.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Private.cs index 6701f0d7..769865d4 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Private.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/Private.cs @@ -410,11 +410,9 @@ private void ExceptionOccurred() /// /// Checks and throws a JNI exception in critical or nested state. /// - private unsafe void ExceptionCheck() + private void ExceptionCheck() { - ref readonly NativeInterface nativeInterface = - ref this.GetNativeInterface(NativeInterface.ExceptionCheckInfo); - if (!nativeInterface.ExceptionCheck(this.Reference).Value) return; + if (!this.HasPendingException()) return; CriticalException criticalException = this._criticalCount > 0 ? CriticalException.Instance : CriticalException.UnknownInstance; diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/TransactionAccess.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/TransactionAccess.cs index d1652594..97c1eb0a 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/TransactionAccess.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/EnvironmentCache/TransactionAccess.cs @@ -41,14 +41,14 @@ private Boolean UseStackAlloc(JCallDefinition jCall, out Int32 requiredBytes) /// Retrieves as a span containing information. /// /// A transaction. - /// A array. + /// A span. /// Destination span. /// Invalid object. - private Span CopyAsJValue(INativeTransaction jniTransaction, IReadOnlyList args, + private Span CopyAsJValue(INativeTransaction jniTransaction, ReadOnlySpan args, Span argSpan) { Span result = argSpan.AsValues(); - for (Int32 i = 0; i < args.Count; i++) + for (Int32 i = 0; i < args.Length; i++) { switch (args[i]) { diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/Private.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/Private.cs index df2c3064..5b9fa3a0 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/Private.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/Private.cs @@ -172,7 +172,8 @@ private JArrayTypeMetadata GetArrayArrayTypeMetadata(ReadOnlySpan arrayArr { ThrowableException? jniException = this._cache.Thrown as ThrowableException; if (jniException is not null || this._cache.Thrown is null) return jniException; - if (!this._cache.JniSecure(JniSafetyLevels.ErrorSafe)) + if (!this._cache.JniSecure(JniSafetyLevels.ErrorSafe) && this._cache.HasPendingException()) + // Do not throw if not pending JNI exception. throw this._cache.Thrown; return this.ParseException(this._cache.GetPendingException()); } @@ -194,7 +195,8 @@ private JArrayTypeMetadata GetArrayArrayTypeMetadata(ReadOnlySpan arrayArr /// A instance. private void SetThrown(ThrowableException? throwableException) { - if (Object.ReferenceEquals(CriticalException.Instance, this._cache.Thrown)) + if (Object.ReferenceEquals(CriticalException.Instance, this._cache.Thrown) && this._cache.HasPendingException()) + // Do not throw if not pending JNI exception throw this._cache.Thrown; this._cache.ThrowJniException(throwableException, false); } diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ReferenceFeature.cs b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ReferenceFeature.cs index 921883c2..24bb785e 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ReferenceFeature.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Implementation.Intermediate/JEnvironment/ReferenceFeature.cs @@ -34,53 +34,56 @@ public JLocalObject CreateWrapper(TPrimitive primitive) JClassObject jClass; JObjectLocalRef localRef; JLocalObject result; + NativeFunctionSetImpl.SingleObjectBuffer buffer = new(); + Span span = NativeFunctionSetImpl.SingleObjectBuffer.GetSpan(ref buffer); + span[0] = primitive; switch (metadata.Signature[0]) { case CommonNames.BooleanSignatureChar: jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.BooleanConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.BooleanConstructor, span); result = new JBooleanObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; case CommonNames.ByteSignatureChar: jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.ByteConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.ByteConstructor, span); result = new JByteObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; case CommonNames.CharSignatureChar: jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.CharacterConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.CharacterConstructor, span); result = new JCharacterObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; case CommonNames.DoubleSignatureChar: jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.DoubleConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.DoubleConstructor, span); result = new JDoubleObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; case CommonNames.FloatSignatureChar: jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.FloatConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.FloatConstructor, span); result = new JFloatObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; case CommonNames.IntSignatureChar: jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.IntegerConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.IntegerConstructor, span); result = new JIntegerObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; case CommonNames.LongSignatureChar: jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.LongConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.LongConstructor, span); result = new JLongObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; case CommonNames.ShortSignatureChar: //S jClass = this.GetClass(); - localRef = this.NewObject(jClass, NativeFunctionSetImpl.ShortConstructor, primitive); + localRef = this.NewObject(jClass, NativeFunctionSetImpl.ShortConstructor, span); result = new JShortObject(jClass, localRef, NativeUtilities.Transform(in primitive)); break; diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/ILLink/ILLink.Substitutions.xml b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/ILLink/ILLink.Substitutions.xml index 8a548c35..6b3f2f95 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/ILLink/ILLink.Substitutions.xml +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/ILLink/ILLink.Substitutions.xml @@ -71,7 +71,7 @@ body="stub"/> - diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Internal/JTrace/Access.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Internal/JTrace/Access.cs index 7bebc4f3..3dc3d605 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Internal/JTrace/Access.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Internal/JTrace/Access.cs @@ -66,7 +66,7 @@ public static void SetField(JLocalObject? jLocal, JClassObject jClas /// Call parameters. /// Caller member name. internal static void CallMethod(JLocalObject? jLocal, JClassObject jClass, JCallDefinition definition, - Boolean nonVirtual, IObject?[] args, [CallerMemberName] String callerMethod = "") + Boolean nonVirtual, ReadOnlySpan args, [CallerMemberName] String callerMethod = "") { if (!IVirtualMachine.TraceEnabled) return; StringBuilder strBuilder = new(); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/JEnumObject/EnumTypeMetadata.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/JEnumObject/EnumTypeMetadata.cs index 77f7663d..a8b29e74 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/JEnumObject/EnumTypeMetadata.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/JEnumObject/EnumTypeMetadata.cs @@ -59,7 +59,7 @@ internal override JEnumObject CreateInstance(JClassObject jClass, JObjectLocalRe } /// internal override JFunctionDefinition CreateFunctionDefinition(ReadOnlySpan functionName, - JArgumentMetadata[] paramsMetadata) + ReadOnlySpan paramsMetadata) => JFunctionDefinition.Create(functionName, paramsMetadata); /// internal override JFieldDefinition CreateFieldDefinition(ReadOnlySpan fieldName) diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JExecutableObject.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JExecutableObject.cs index 38c3e421..220c8ce1 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JExecutableObject.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JExecutableObject.cs @@ -50,11 +50,11 @@ public JClassObject DeclaringClass /// Local object reference. /// Call definition. /// Declaring class. - private protected JExecutableObject(JClassObject jClass, JObjectLocalRef localRef, JCallDefinition definition, - JClassObject declaringClass) : base(jClass, localRef) + private protected JExecutableObject(JClassObject jClass, JObjectLocalRef localRef, JCallDefinition? definition, + JClassObject? declaringClass) : base(jClass, localRef) { this._callDefinition = definition; - this._classInformation = declaringClass.GetInformation(); + this._classInformation = declaringClass?.GetInformation(); } /// diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JFieldObject.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JFieldObject.cs index 3c6c88c0..9bae1107 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JFieldObject.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JFieldObject.cs @@ -48,11 +48,11 @@ public JClassObject DeclaringClass /// Local object reference. /// Field definition. /// Declaring class. - internal JFieldObject(JClassObject jClass, JObjectLocalRef localRef, JFieldDefinition definition, - JClassObject declaringClass) : base(jClass, localRef) + internal JFieldObject(JClassObject jClass, JObjectLocalRef localRef, JFieldDefinition? definition = default, + JClassObject? declaringClass = default) : base(jClass, localRef) { this._fieldDefinition = definition; - this._classInformation = declaringClass.GetInformation(); + this._classInformation = declaringClass?.GetInformation(); } /// diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JMethodObject.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JMethodObject.cs index ddafe72f..e7aeb1e8 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JMethodObject.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Lang/Reflect/JMethodObject.cs @@ -17,8 +17,8 @@ public sealed class JMethodObject : JExecutableObject, IClassType static TypeMetadata IClassType.Metadata => JMethodObject.typeMetadata; /// - internal JMethodObject(JClassObject jClass, JObjectLocalRef localRef, JCallDefinition definition, - JClassObject declaringClass) : base(jClass, localRef, definition, declaringClass) { } + internal JMethodObject(JClassObject jClass, JObjectLocalRef localRef, JCallDefinition? definition = default, + JClassObject? declaringClass = default) : base(jClass, localRef, definition, declaringClass) { } /// private JMethodObject(IReferenceType.ClassInitializer initializer) : base(initializer) { } diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition.cs index 4b5d5f07..8f93837f 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition.cs @@ -30,7 +30,7 @@ public JConstructorObject GetReflected(JClassObject declaringClass) /// An instance. /// A new instance. private protected JLocalObject New(JClassObject jClass) - => this.New(jClass, this.CreateArgumentsArray()); + => this.New(jClass, ReadOnlySpan.Empty); /// /// Creates a new instance using a constructor which matches with /// current definition passing the default value for each argument. @@ -39,7 +39,7 @@ private protected JLocalObject New(JClassObject jClass) /// instance. /// A new instance. private protected TObject New(IEnvironment env) where TObject : JLocalObject, IClassType - => this.New(env.ClassFeature.GetClass(), this.CreateArgumentsArray()); + => this.New(env.ClassFeature.GetClass(), ReadOnlySpan.Empty); /// /// Creates a new instance using a constructor on @@ -49,7 +49,8 @@ private protected TObject New(IEnvironment env) where TObject : JLocalO /// A instance. /// The arguments to pass to. /// A new . - private TObject New(JClassObject jClass, IObject?[] args) where TObject : JLocalObject, IClassType + private TObject New(JClassObject jClass, ReadOnlySpan args) + where TObject : JLocalObject, IClassType { NativeValidationUtilities.ThrowIfAbstractClass(IClassType.GetMetadata()); IEnvironment env = jClass.Environment; @@ -65,14 +66,14 @@ private TObject New(JClassObject jClass, IObject?[] args) where TObject /// A instance. /// The arguments to pass to. internal static TObject New(JConstructorDefinition definition, JClassObject jClass, - IObject?[]? args = default) where TObject : JLocalObject, IClassType - => definition.New(jClass, args ?? definition.CreateArgumentsArray()); + ReadOnlySpan args = default) where TObject : JLocalObject, IClassType + => definition.New(jClass, args); /// /// Create a instance for . /// /// Metadata of the types of call arguments. /// A instance. - internal static JConstructorDefinition Create(JArgumentMetadata[] metadata) + internal static JConstructorDefinition Create(ReadOnlySpan metadata) => metadata.Length > 0 ? new JConstructorDefinition(metadata) : new Parameterless(); } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition/Protected.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition/Protected.cs index 87395122..fcd11e8f 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition/Protected.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JConstructorDefinition/Protected.cs @@ -5,7 +5,12 @@ public partial class JConstructorDefinition /// /// Constructor. /// - protected JConstructorDefinition(params JArgumentMetadata[] metadata) : base(CommonNames.Constructor, metadata) { } + protected JConstructorDefinition(params JArgumentMetadata[] metadata) : this(metadata.AsSpan()) { } + /// + /// Constructor. + /// + protected JConstructorDefinition(ReadOnlySpan metadata) : + base(CommonNames.Constructor, metadata) { } /// /// Creates a new instance using a constructor on @@ -14,7 +19,8 @@ protected JConstructorDefinition(params JArgumentMetadata[] metadata) : base(Com /// An instance. /// The arguments to pass to. /// A new instance. - protected JLocalObject New(JClassObject jClass, IObject?[] args) => this.New(jClass, args); + protected JLocalObject New(JClassObject jClass, ReadOnlySpan args) + => this.New(jClass, args); /// /// Creates a new instance using a constructor which matches with /// current definition. @@ -23,7 +29,8 @@ protected JConstructorDefinition(params JArgumentMetadata[] metadata) : base(Com /// instance. /// The arguments to pass to. /// A new instance. - protected TObject New(IEnvironment env, IObject?[] args) where TObject : JLocalObject, IClassType + protected TObject New(IEnvironment env, ReadOnlySpan args) + where TObject : JLocalObject, IClassType => this.New(env.ClassFeature.GetClass(), args); /// /// Invokes a reflected constructor which matches with current definition @@ -32,7 +39,7 @@ protected TObject New(IEnvironment env, IObject?[] args) where TObject /// A instance. /// A new instance. protected JLocalObject NewReflected(JConstructorObject jConstructor) - => this.NewReflected(jConstructor, this.CreateArgumentsArray()); + => this.NewReflected(jConstructor, ReadOnlySpan.Empty); /// /// Invokes a reflected constructor which matches with current definition /// passing the default value for each argument. @@ -40,7 +47,7 @@ protected JLocalObject NewReflected(JConstructorObject jConstructor) /// A instance. /// The arguments to pass to. /// A new instance. - protected JLocalObject NewReflected(JConstructorObject jConstructor, IObject?[] args) + protected JLocalObject NewReflected(JConstructorObject jConstructor, ReadOnlySpan args) => this.NewReflected(jConstructor, args); /// /// Invokes a reflected constructor which matches with current definition. @@ -50,7 +57,7 @@ protected JLocalObject NewReflected(JConstructorObject jConstructor, IObject?[] /// A new instance. protected TObject NewReflected(JConstructorObject jConstructor) where TObject : JLocalObject, IClassType - => this.NewReflected(jConstructor, this.CreateArgumentsArray()); + => this.NewReflected(jConstructor, ReadOnlySpan.Empty); /// /// Invokes a reflected constructor which matches with current definition. /// @@ -58,7 +65,7 @@ protected TObject NewReflected(JConstructorObject jConstructor) /// A instance. /// The arguments to pass to. /// A new instance. - protected TObject NewReflected(JConstructorObject jConstructor, IObject?[] args) + protected TObject NewReflected(JConstructorObject jConstructor, ReadOnlySpan args) where TObject : JLocalObject, IClassType { NativeValidationUtilities.ThrowIfAbstractClass(IClassType.GetMetadata()); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition.cs index c295ad57..59928310 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition.cs @@ -12,7 +12,7 @@ public abstract partial class JFunctionDefinition : JCallDefinition /// Method return type defined signature. /// Metadata of the types of call arguments. private protected JFunctionDefinition(ReadOnlySpan functionName, ReadOnlySpan returnTypeSignature, - params JArgumentMetadata[] metadata) : base(functionName, returnTypeSignature, metadata) { } + ReadOnlySpan metadata = default) : base(functionName, returnTypeSignature, metadata) { } /// private protected JFunctionDefinition(JFunctionDefinition definition) : base(definition) { } @@ -60,7 +60,7 @@ private protected JFunctionDefinition(ReadOnlySpan functionName) : base(fu /// Method return type defined signature. /// Metadata of the types of call arguments. private protected JFunctionDefinition(ReadOnlySpan functionName, ReadOnlySpan returnTypeSignature, - params JArgumentMetadata[] metadata) : base(functionName, returnTypeSignature, metadata) { } + ReadOnlySpan metadata) : base(functionName, returnTypeSignature, metadata) { } /// /// Internal Constructor. /// @@ -73,7 +73,7 @@ internal JFunctionDefinition(JFunctionDefinition definition) : base(definition) /// /// A instance. /// function result. - private protected TResult? Invoke(JLocalObject jLocal) => this.Invoke(jLocal, this.CreateArgumentsArray()); + private protected TResult? Invoke(JLocalObject jLocal) => this.Invoke(jLocal, ReadOnlySpan.Empty); /// /// Invokes a function on which matches with current definition but using the /// implementation declared on passing the default value for each argument. @@ -82,7 +82,7 @@ internal JFunctionDefinition(JFunctionDefinition definition) : base(definition) /// A instance that class extends. /// function result. private protected TResult? Invoke(JLocalObject jLocal, JClassObject jClass) - => this.Invoke(jLocal, jClass, this.CreateArgumentsArray()); + => this.Invoke(jLocal, jClass, ReadOnlySpan.Empty); /// /// Invokes a function on which matches with current definition but using the /// implementation declared on passing the default value for each argument. @@ -91,12 +91,12 @@ internal JFunctionDefinition(JFunctionDefinition definition) : base(definition) /// A instance that class extends. /// function result. private protected TResult? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass) - => this.InvokeNonVirtual(jLocal, jClass, this.CreateArgumentsArray()); + => this.InvokeNonVirtual(jLocal, jClass, ReadOnlySpan.Empty); /// /// Invokes a static function on which matches with current definition. /// /// A instance. /// function result. private protected TResult? StaticInvoke(JClassObject jClass) - => this.StaticInvoke(jClass, this.CreateArgumentsArray()); + => this.StaticInvoke(jClass, ReadOnlySpan.Empty); } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Protected.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Protected.cs index 92983b3b..77d05add 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Protected.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Protected.cs @@ -7,7 +7,14 @@ public partial class JFunctionDefinition /// /// Function name. /// Metadata of the types of call arguments. - protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentMetadata[] metadata) : base( + protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentMetadata[] metadata) : this( + functionName, metadata.AsSpan()) { } + /// + /// Constructor. + /// + /// Function name. + /// Metadata of the types of call arguments. + protected JFunctionDefinition(ReadOnlySpan functionName, ReadOnlySpan metadata) : base( functionName, IDataType.GetMetadata().Signature, metadata) { } /// @@ -16,7 +23,7 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance. /// The arguments to pass to. /// function result. - protected TResult? Invoke(JLocalObject jLocal, IObject?[] args) + protected TResult? Invoke(JLocalObject jLocal, ReadOnlySpan args) { IEnvironment env = jLocal.Environment; return env.AccessFeature.CallFunction(jLocal, jLocal.Class, this, false, args); @@ -29,7 +36,7 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance that class extends. /// The arguments to pass to. /// function result. - protected TResult? Invoke(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + protected TResult? Invoke(JLocalObject jLocal, JClassObject jClass, ReadOnlySpan args) { IEnvironment env = jLocal.Environment; return env.AccessFeature.CallFunction(jLocal, jClass, this, false, args); @@ -42,7 +49,7 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance that class extends. /// The arguments to pass to. /// function result. - protected TResult? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + protected TResult? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, ReadOnlySpan args) { IEnvironment env = jLocal.Environment; return env.AccessFeature.CallFunction(jLocal, jClass, this, true, args); @@ -54,7 +61,7 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance. /// The arguments to pass to. /// function result. - protected TResult? StaticInvoke(JClassObject jClass, IObject?[] args) + protected TResult? StaticInvoke(JClassObject jClass, ReadOnlySpan args) { IEnvironment env = jClass.Environment; return env.AccessFeature.CallStaticFunction(jClass, this, args); @@ -66,7 +73,7 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance. /// function result. protected TResult? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal) - => this.InvokeReflected(jMethod, jLocal, this.CreateArgumentsArray()); + => this.InvokeReflected(jMethod, jLocal, ReadOnlySpan.Empty); /// /// Invokes a reflected function which matches with current definition. /// @@ -74,7 +81,7 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance. /// The arguments to pass to. /// function result. - protected TResult? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + protected TResult? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, ReadOnlySpan args) { IEnvironment env = jMethod.Environment; return env.AccessFeature.CallFunction(jMethod, jLocal, this, false, args); @@ -86,7 +93,7 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance. /// function result. protected TResult? InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal) - => this.InvokeNonVirtualReflected(jMethod, jLocal, this.CreateArgumentsArray()); + => this.InvokeNonVirtualReflected(jMethod, jLocal, ReadOnlySpan.Empty); /// /// Invokes a reflected function which matches with current definition. /// @@ -94,7 +101,8 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance. /// The arguments to pass to. /// function result. - protected TResult? InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + protected TResult? InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, + ReadOnlySpan args) { IEnvironment env = jMethod.Environment; return env.AccessFeature.CallFunction(jMethod, jLocal, this, true, args); @@ -105,14 +113,14 @@ protected JFunctionDefinition(ReadOnlySpan functionName, params JArgumentM /// A instance. /// function result. protected TResult? InvokeStaticReflected(JMethodObject jMethod) - => this.InvokeStaticReflected(jMethod, this.CreateArgumentsArray()); + => this.InvokeStaticReflected(jMethod, ReadOnlySpan.Empty); /// /// Invokes a reflected static function which matches with current definition. /// /// A instance. /// The arguments to pass to. /// function result. - protected TResult? InvokeStaticReflected(JMethodObject jMethod, IObject?[] args) + protected TResult? InvokeStaticReflected(JMethodObject jMethod, ReadOnlySpan args) { IEnvironment env = jMethod.Environment; return env.AccessFeature.CallStaticFunction(jMethod, this, args); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Static.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Static.cs index acdefd47..21f12b5d 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Static.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JFunctionDefinition/Static.cs @@ -13,7 +13,7 @@ public abstract partial class JFunctionDefinition /// The arguments to pass to. /// function result. internal static TResult? Invoke(JFunctionDefinition definition, JLocalObject jLocal, - JClassObject? jClass = default, Boolean nonVirtual = false, IObject?[]? args = default) + JClassObject? jClass = default, Boolean nonVirtual = false, ReadOnlySpan args = default) where TResult : IDataType => JFunctionDefinition.Invoke(definition, jLocal, jClass, nonVirtual, args); /// @@ -26,7 +26,7 @@ public abstract partial class JFunctionDefinition /// The arguments to pass to. /// function result. internal static TResult? StaticInvoke(JFunctionDefinition definition, JClassObject jClass, - IObject?[]? args = default) where TResult : IDataType + ReadOnlySpan args = default) where TResult : IDataType => JFunctionDefinition.StaticInvoke(definition, jClass, args); } @@ -42,11 +42,11 @@ public partial class JFunctionDefinition /// The arguments to pass to. /// function result. internal static TResult? Invoke(JFunctionDefinition definition, JLocalObject jLocal, - JClassObject? jClass = default, Boolean nonVirtual = false, IObject?[]? args = default) + JClassObject? jClass = default, Boolean nonVirtual = false, ReadOnlySpan args = default) { IEnvironment env = jLocal.Environment; return env.AccessFeature.CallInternalFunction(jLocal, jClass ?? jLocal.Class, definition, nonVirtual, - args ?? definition.CreateArgumentsArray()); + args); } /// /// Invokes on which matches with current definition @@ -57,11 +57,10 @@ public partial class JFunctionDefinition /// The arguments to pass to. /// function result. internal static TResult? StaticInvoke(JFunctionDefinition definition, JClassObject jClass, - IObject?[]? args = default) + ReadOnlySpan args = default) { IEnvironment env = jClass.Environment; - return env.AccessFeature.CallInternalStaticFunction(jClass, definition, - args ?? definition.CreateArgumentsArray()); + return env.AccessFeature.CallInternalStaticFunction(jClass, definition, args); } /// @@ -72,7 +71,7 @@ public partial class JFunctionDefinition /// A instance. /// function result. internal static JFunctionDefinition Create(ReadOnlySpan functionName, - params JArgumentMetadata[] metadata) + ReadOnlySpan metadata = default) => metadata.Length > 0 ? new JFunctionDefinition(functionName, metadata) : new Parameterless(functionName); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Internal.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Internal.cs index 193dbe74..c1a9c7c6 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Internal.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Internal.cs @@ -7,14 +7,14 @@ public partial class JMethodDefinition /// /// Method name. /// This constructor should be never inherited. - private protected JMethodDefinition(ReadOnlySpan methodName) : base(methodName) { } + private protected JMethodDefinition(ReadOnlySpan methodName) : base(methodName, []) { } /// /// Invokes a method on which matches with current definition passing the /// default value for each argument. /// /// A instance. - private protected void Invoke(JLocalObject jLocal) => this.Invoke(jLocal, this.CreateArgumentsArray()); + private protected void Invoke(JLocalObject jLocal) => this.Invoke(jLocal, ReadOnlySpan.Empty); /// /// Invokes a method on which matches with current definition but using the /// implementation declared on passing the default value for each argument. @@ -22,7 +22,7 @@ private protected JMethodDefinition(ReadOnlySpan methodName) : base(method /// A instance. /// A instance that class extends. private protected void Invoke(JLocalObject jLocal, JClassObject jClass) - => this.Invoke(jLocal, jClass, this.CreateArgumentsArray()); + => this.Invoke(jLocal, jClass, ReadOnlySpan.Empty); /// /// Invokes a method on which matches with current definition but using the /// implementation declared on passing the default value for each argument. @@ -30,13 +30,13 @@ private protected void Invoke(JLocalObject jLocal, JClassObject jClass) /// A instance. /// A instance that class extends. private protected void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass) - => this.InvokeNonVirtual(jLocal, jClass, this.CreateArgumentsArray()); + => this.InvokeNonVirtual(jLocal, jClass, ReadOnlySpan.Empty); /// /// Invokes a static method on which matches with current definition /// passing the default value for each argument. /// /// A instance. - private protected void StaticInvoke(JClassObject jClass) => this.StaticInvoke(jClass, this.CreateArgumentsArray()); + private protected void StaticInvoke(JClassObject jClass) => this.StaticInvoke(jClass, ReadOnlySpan.Empty); /// /// Invokes on which matches with current definition. @@ -47,11 +47,10 @@ private protected void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass /// Indicates whether current call must be non-virtual. /// The arguments to pass to. internal static void Invoke(JMethodDefinition definition, JLocalObject jLocal, JClassObject? jClass = default, - Boolean nonVirtual = false, IObject?[]? args = default) + Boolean nonVirtual = false, ReadOnlySpan args = default) { IEnvironment env = jLocal.Environment; - env.AccessFeature.CallInternalMethod(jLocal, jClass ?? jLocal.Class, definition, nonVirtual, - args ?? definition.CreateArgumentsArray()); + env.AccessFeature.CallInternalMethod(jLocal, jClass ?? jLocal.Class, definition, nonVirtual, args); } /// /// Invokes on which matches with current definition. @@ -59,10 +58,11 @@ internal static void Invoke(JMethodDefinition definition, JLocalObject jLocal, J /// A definition. /// A instance. /// The arguments to pass to. - internal static void StaticInvoke(JMethodDefinition definition, JClassObject jClass, IObject?[]? args = default) + internal static void StaticInvoke(JMethodDefinition definition, JClassObject jClass, + ReadOnlySpan args = default) { IEnvironment env = jClass.Environment; - env.AccessFeature.CallInternalStaticMethod(jClass, definition, args ?? definition.CreateArgumentsArray()); + env.AccessFeature.CallInternalStaticMethod(jClass, definition, args); } /// /// Create a instance for . @@ -70,6 +70,7 @@ internal static void StaticInvoke(JMethodDefinition definition, JClassObject jCl /// Method name. /// Metadata of the types of call arguments. /// A instance. - internal static JMethodDefinition Create(ReadOnlySpan methodName, params JArgumentMetadata[] metadata) + internal static JMethodDefinition Create(ReadOnlySpan methodName, + ReadOnlySpan metadata = default) => metadata.Length > 0 ? new JMethodDefinition(methodName, metadata) : new Parameterless(methodName); } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Protected.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Protected.cs index 26bcfff1..8f37a31e 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Protected.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JMethodDefinition/Protected.cs @@ -7,7 +7,14 @@ public partial class JMethodDefinition /// /// Function name. /// Metadata of the types of call arguments. - protected JMethodDefinition(ReadOnlySpan methodName, params JArgumentMetadata[] metadata) : base( + protected JMethodDefinition(ReadOnlySpan methodName, params JArgumentMetadata[] metadata) : this( + methodName, metadata.AsSpan()) { } + /// + /// Constructor. + /// + /// Function name. + /// Metadata of the types of call arguments. + protected JMethodDefinition(ReadOnlySpan methodName, ReadOnlySpan metadata) : base( methodName, metadata) { } /// @@ -15,7 +22,7 @@ protected JMethodDefinition(ReadOnlySpan methodName, params JArgumentMetad /// /// A instance. /// The arguments to pass to. - protected void Invoke(JLocalObject jLocal, IObject?[] args) + protected void Invoke(JLocalObject jLocal, ReadOnlySpan args) { IEnvironment env = jLocal.Environment; env.AccessFeature.CallMethod(jLocal, jLocal.Class, this, false, args); @@ -27,7 +34,7 @@ protected void Invoke(JLocalObject jLocal, IObject?[] args) /// A instance. /// A instance that class extends. /// The arguments to pass to. - protected void Invoke(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + protected void Invoke(JLocalObject jLocal, JClassObject jClass, ReadOnlySpan args) { IEnvironment env = jLocal.Environment; env.AccessFeature.CallMethod(jLocal, jClass, this, false, args); @@ -39,7 +46,7 @@ protected void Invoke(JLocalObject jLocal, JClassObject jClass, IObject?[] args) /// A instance. /// A instance that class extends. /// The arguments to pass to. - protected void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + protected void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, ReadOnlySpan args) { IEnvironment env = jLocal.Environment; env.AccessFeature.CallMethod(jLocal, jClass, this, true, args); @@ -49,7 +56,7 @@ protected void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, IObjec /// /// A instance. /// The arguments to pass to. - protected void StaticInvoke(JClassObject jClass, IObject?[] args) + protected void StaticInvoke(JClassObject jClass, ReadOnlySpan args) { IEnvironment env = jClass.Environment; env.AccessFeature.CallStaticMethod(jClass, this, args); @@ -60,14 +67,14 @@ protected void StaticInvoke(JClassObject jClass, IObject?[] args) /// A instance. /// A instance. protected void InvokeReflected(JMethodObject jMethod, JLocalObject jLocal) - => this.InvokeReflected(jMethod, jLocal, this.CreateArgumentsArray()); + => this.InvokeReflected(jMethod, jLocal, ReadOnlySpan.Empty); /// /// Invokes a reflected method which matches with current definition. /// /// A instance. /// A instance. /// The arguments to pass to. - protected void InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + protected void InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, ReadOnlySpan args) { IEnvironment env = jMethod.Environment; env.AccessFeature.CallMethod(jMethod, jLocal, this, false, args); @@ -78,14 +85,14 @@ protected void InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, IObje /// A instance. /// A instance. protected void InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal) - => this.InvokeNonVirtualReflected(jMethod, jLocal, this.CreateArgumentsArray()); + => this.InvokeNonVirtualReflected(jMethod, jLocal, ReadOnlySpan.Empty); /// /// Invokes a reflected method which matches with current definition. /// /// A instance. /// A instance. /// The arguments to pass to. - protected void InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + protected void InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, ReadOnlySpan args) { IEnvironment env = jMethod.Environment; env.AccessFeature.CallMethod(jMethod, jLocal, this, true, args); @@ -95,13 +102,13 @@ protected void InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLo /// /// A instance. protected void InvokeStaticReflected(JMethodObject jMethod) - => this.InvokeStaticReflected(jMethod, this.CreateArgumentsArray()); + => this.InvokeStaticReflected(jMethod, ReadOnlySpan.Empty); /// /// Invokes a reflected static method which matches with current definition. /// /// A instance. /// The arguments to pass to. - protected void InvokeStaticReflected(JMethodObject jMethod, IObject?[] args) + protected void InvokeStaticReflected(JMethodObject jMethod, ReadOnlySpan args) { IEnvironment env = jMethod.Environment; env.AccessFeature.CallStaticMethod(jMethod, this, args); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JNonTypedFunctionDefinition.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JNonTypedFunctionDefinition.cs index af6412b2..eb47a32f 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JNonTypedFunctionDefinition.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/Access/JNonTypedFunctionDefinition.cs @@ -12,60 +12,33 @@ namespace Rxmxnx.JNetInterface.Native.Access; internal sealed class JNonTypedFunctionDefinition( ReadOnlySpan functionName, ReadOnlySpan returnTypeSignature, - params JArgumentMetadata[] metadata) : JFunctionDefinition(functionName, - JAccessibleObjectDefinition - .ValidateSignature( - returnTypeSignature), metadata) + ReadOnlySpan metadata = default) : JFunctionDefinition(functionName, + JAccessibleObjectDefinition.ValidateSignature(returnTypeSignature), metadata) { - /// - public new JLocalObject? Invoke(JLocalObject jLocal, params IObject?[] args) - { - IObject?[] realArgs = this.CreateArgumentsArray(); - args.CopyTo(realArgs, 0); - return base.Invoke(jLocal, realArgs); - } - /// - public new JLocalObject? Invoke(JLocalObject jLocal, JClassObject jClass, params IObject?[] args) - { - IObject?[] realArgs = this.CreateArgumentsArray(); - args.CopyTo(realArgs, 0); - return base.Invoke(jLocal, jClass, realArgs); - } - /// - public new JLocalObject? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, params IObject?[] args) - { - IObject?[] realArgs = this.CreateArgumentsArray(); - args.CopyTo(realArgs, 0); - return base.InvokeNonVirtual(jLocal, jClass, realArgs); - } - /// - public new JLocalObject? StaticInvoke(JClassObject jClass, params IObject?[] args) - { - IObject?[] realArgs = this.CreateArgumentsArray(); - args.CopyTo(realArgs, 0); - return base.StaticInvoke(jClass, realArgs); - } + /// + public new JLocalObject? Invoke(JLocalObject jLocal, ReadOnlySpan args = default) + => base.Invoke(jLocal, args); + /// + public new JLocalObject? Invoke(JLocalObject jLocal, JClassObject jClass, ReadOnlySpan args = default) + => base.Invoke(jLocal, jClass, args); + /// + public new JLocalObject? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, + ReadOnlySpan args = default) + => base.InvokeNonVirtual(jLocal, jClass, args); + /// + public new JLocalObject? StaticInvoke(JClassObject jClass, ReadOnlySpan args = default) + => base.StaticInvoke(jClass, args); - /// - public new JLocalObject? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, params IObject?[] args) - { - IObject?[] realArgs = this.CreateArgumentsArray(); - args.CopyTo(realArgs, 0); - return base.InvokeReflected(jMethod, jLocal, realArgs); - } - /// + /// + public new JLocalObject? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, + ReadOnlySpan args = default) + => base.InvokeReflected(jMethod, jLocal, args); + /// public new JLocalObject? InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, - params IObject?[] args) - { - IObject?[] realArgs = this.CreateArgumentsArray(); - args.CopyTo(realArgs, 0); - return base.InvokeNonVirtualReflected(jMethod, jLocal, realArgs); - } - /// - public new JLocalObject? InvokeStaticReflected(JMethodObject jMethod, params IObject?[] args) - { - IObject?[] realArgs = this.CreateArgumentsArray(); - args.CopyTo(realArgs, 0); - return base.InvokeStaticReflected(jMethod, realArgs); - } + ReadOnlySpan args = default) + => base.InvokeNonVirtualReflected(jMethod, jLocal, args); + /// + public new JLocalObject? InvokeStaticReflected(JMethodObject jMethod, ReadOnlySpan args = default) + => base.InvokeStaticReflected(jMethod, args); } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/ArrayTypeMetadata.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/ArrayTypeMetadata.cs index 1157098e..a98553ac 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/ArrayTypeMetadata.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/ArrayTypeMetadata.cs @@ -70,7 +70,7 @@ internal override JLocalObject CreateInstance(JClassObject jClass, JObjectLocalR } /// internal override JFunctionDefinition> CreateFunctionDefinition( - ReadOnlySpan functionName, JArgumentMetadata[] paramsMetadata) + ReadOnlySpan functionName, ReadOnlySpan paramsMetadata) => JFunctionDefinition>.Create(functionName, paramsMetadata); /// internal override JFieldDefinition> CreateFieldDefinition(ReadOnlySpan fieldName) diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/InternalConstructor.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/InternalConstructor.cs index 40ab7832..b731cc10 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/InternalConstructor.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JArrayObject/InternalConstructor.cs @@ -35,7 +35,7 @@ public partial class JArrayObject /// instance. /// Local array reference. /// Array length. - internal JArrayObject(JClassObject jClass, JArrayLocalRef jArrayRef, Int32? length) : base( + internal JArrayObject(JClassObject jClass, JArrayLocalRef jArrayRef, Int32? length = default) : base( new Generic(jClass, jArrayRef, length)) { } /// private JArrayObject(JArrayObject jArray) : base(jArray) { } diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JLocalObject/InterfaceView/InterfaceTypeMetadata.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JLocalObject/InterfaceView/InterfaceTypeMetadata.cs index fb6f4d4f..5ba74db7 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JLocalObject/InterfaceView/InterfaceTypeMetadata.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Native/JLocalObject/InterfaceView/InterfaceTypeMetadata.cs @@ -65,7 +65,7 @@ internal override JLocalObject CreateInstance(JClassObject jClass, JObjectLocalR } /// internal override JFunctionDefinition CreateFunctionDefinition( - ReadOnlySpan functionName, JArgumentMetadata[] paramsMetadata) + ReadOnlySpan functionName, ReadOnlySpan paramsMetadata) => JFunctionDefinition.Create(functionName, paramsMetadata); /// internal override JFieldDefinition CreateFieldDefinition(ReadOnlySpan fieldName) diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature.cs index d594252e..666bb7aa 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature.cs @@ -86,54 +86,54 @@ void SetStaticField(JFieldObject jField, JFieldDefinition definition, TF /// type of created instance. /// instance. /// definition. - /// The array with call arguments. + /// The list with call arguments. /// The new instance. - TObject CallConstructor(JClassObject jClass, JConstructorDefinition definition, IObject?[] args) - where TObject : JLocalObject, IDataType; + TObject CallConstructor(JClassObject jClass, JConstructorDefinition definition, + ReadOnlySpan args) where TObject : JLocalObject, IDataType; /// /// Invokes a reflected constructor method on . /// /// type of created instance. /// A instance. /// definition. - /// The array with call arguments. + /// The list with call arguments. /// The new instance. TObject CallConstructor(JConstructorObject jConstructor, JConstructorDefinition definition, - IObject?[] args) where TObject : JLocalObject, IClassType; + ReadOnlySpan args) where TObject : JLocalObject, IClassType; /// /// Invokes a static function on instance. /// /// type of function result. /// instance. /// definition. - /// The array with call arguments. + /// The list with call arguments. /// function result. - TResult? CallStaticFunction(JClassObject jClass, JFunctionDefinition definition, IObject?[] args) - where TResult : IDataType; + TResult? CallStaticFunction(JClassObject jClass, JFunctionDefinition definition, + ReadOnlySpan args) where TResult : IDataType; /// /// Invokes a static function reflected on instance. /// /// type of function result. /// A instance. /// definition. - /// The array with call arguments. + /// The list with call arguments. /// function result. - TResult? CallStaticFunction(JMethodObject jMethod, JFunctionDefinition definition, IObject?[] args) - where TResult : IDataType; + TResult? CallStaticFunction(JMethodObject jMethod, JFunctionDefinition definition, + ReadOnlySpan args) where TResult : IDataType; /// /// Invokes a static method on given instance. /// /// instance. /// definition. - /// The array with call arguments. - void CallStaticMethod(JClassObject jClass, JMethodDefinition definition, IObject?[] args); + /// The list with call arguments. + void CallStaticMethod(JClassObject jClass, JMethodDefinition definition, ReadOnlySpan args); /// /// Invokes an static method reflected on . /// /// A instance. /// definition. - /// The array with call arguments. - void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, IObject?[] args); + /// The list with call arguments. + void CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, ReadOnlySpan args); /// /// Invokes a function on given instance and returns its result. /// @@ -142,10 +142,10 @@ TObject CallConstructor(JConstructorObject jConstructor, JConstructorDe /// instance. /// definition. /// Indicates whether current call must be non-virtual. - /// The array with call arguments. + /// The list with call arguments. /// function result. TResult? CallFunction(JLocalObject jLocal, JClassObject jClass, JFunctionDefinition definition, - Boolean nonVirtual, IObject?[] args) where TResult : IDataType; + Boolean nonVirtual, ReadOnlySpan args) where TResult : IDataType; /// /// Invokes a function reflected on and returns its result. /// @@ -154,10 +154,10 @@ TObject CallConstructor(JConstructorObject jConstructor, JConstructorDe /// instance. /// definition. /// Indicates whether current call must be non-virtual. - /// The array with call arguments. + /// The list with call arguments. /// function result. TResult? CallFunction(JMethodObject jMethod, JLocalObject jLocal, JFunctionDefinition definition, - Boolean nonVirtual, IObject?[] args) where TResult : IDataType; + Boolean nonVirtual, ReadOnlySpan args) where TResult : IDataType; /// /// Invokes a method on given instance. /// @@ -165,9 +165,9 @@ TObject CallConstructor(JConstructorObject jConstructor, JConstructorDe /// instance. /// definition. /// Indicates whether current call must be non-virtual. - /// The array with call arguments. + /// The list with call arguments. void CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, Boolean nonVirtual, - IObject?[] args); + ReadOnlySpan args); /// /// Invokes a method reflected on . /// @@ -175,9 +175,9 @@ void CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition defi /// instance. /// definition. /// Indicates whether current call must be non-virtual. - /// The array with call arguments. + /// The list with call arguments. void CallMethod(JMethodObject jMethod, JLocalObject jLocal, JMethodDefinition definition, Boolean nonVirtual, - IObject?[] args); + ReadOnlySpan args); /// /// Register as native methods in current class. /// diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature/Internal.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature/Internal.cs index 93c5551b..2d2c009d 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature/Internal.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Restricted/IAccessFeature/Internal.cs @@ -8,18 +8,19 @@ internal partial interface IAccessFeature /// type of function result. /// instance. /// definition. - /// The array with call arguments. + /// The list with call arguments. /// function result. internal TResult? CallInternalStaticFunction(JClassObject jClass, JFunctionDefinition definition, - IObject?[] args) where TResult : IDataType + ReadOnlySpan args) where TResult : IDataType => this.CallStaticFunction(jClass, definition, args); /// /// Invokes a static method on given instance. /// /// instance. /// definition. - /// The array with call arguments. - internal void CallInternalStaticMethod(JClassObject jClass, JMethodDefinition definition, IObject?[] args) + /// The list with call arguments. + internal void CallInternalStaticMethod(JClassObject jClass, JMethodDefinition definition, + ReadOnlySpan args) => this.CallStaticMethod(jClass, definition, args); /// /// Invokes a function on given instance and returns its result. @@ -29,10 +30,11 @@ internal void CallInternalStaticMethod(JClassObject jClass, JMethodDefinition de /// instance. /// definition. /// Indicates whether current call must be non-virtual. - /// The array with call arguments. + /// The list with call arguments. /// function result. internal TResult? CallInternalFunction(JLocalObject jLocal, JClassObject jClass, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) where TResult : IDataType + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) + where TResult : IDataType => this.CallFunction(jLocal, jClass, definition, nonVirtual, args); /// /// Invokes a method on given instance. @@ -41,9 +43,9 @@ internal void CallInternalStaticMethod(JClassObject jClass, JMethodDefinition de /// instance. /// definition. /// Indicates whether current call must be non-virtual. - /// The array with call arguments. + /// The list with call arguments. internal void CallInternalMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, - Boolean nonVirtual, IObject?[] args) + Boolean nonVirtual, ReadOnlySpan args) => this.CallMethod(jLocal, jClass, definition, nonVirtual, args); /// @@ -84,9 +86,9 @@ internal void SetPrimitiveField(JLocalObject jLocal, JClassObject jClass, JField /// Binary span to hold result. /// instance. /// definition. - /// The array with call arguments. + /// The list with call arguments. internal void CallPrimitiveStaticFunction(Span bytes, JClassObject jClass, JFunctionDefinition definition, - IObject?[] args); + ReadOnlySpan args = default); /// /// Invokes a primitive function on given instance and returns its result. /// @@ -95,7 +97,7 @@ internal void CallPrimitiveStaticFunction(Span bytes, JClassObject jClass, /// instance. /// definition. /// Indicates whether current call must be non-virtual. - /// The array with call arguments. + /// The list with call arguments. internal void CallPrimitiveFunction(Span bytes, JLocalObject jLocal, JClassObject jClass, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args); + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args = default); } \ No newline at end of file diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JClassTypeMetadata.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JClassTypeMetadata.cs index 1238dc45..cc775181 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JClassTypeMetadata.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JClassTypeMetadata.cs @@ -69,7 +69,7 @@ private protected JClassTypeMetadata(CStringSequence information) : base(informa internal override Boolean IsInstance(JReferenceObject jObject) => jObject is TClass || jObject.InstanceOf(); /// internal override JFunctionDefinition CreateFunctionDefinition(ReadOnlySpan functionName, - JArgumentMetadata[] paramsMetadata) + ReadOnlySpan paramsMetadata) => JFunctionDefinition.Create(functionName, paramsMetadata); /// internal override JFieldDefinition CreateFieldDefinition(ReadOnlySpan fieldName) => new(fieldName); diff --git a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JReferenceTypeMetadata/Internal.cs b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JReferenceTypeMetadata/Internal.cs index 21f0ae54..3a60f741 100644 --- a/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JReferenceTypeMetadata/Internal.cs +++ b/src/Intermediate/Rxmxnx.JNetInterface.Native.Intermediate/Types/Metadata/JReferenceTypeMetadata/Internal.cs @@ -61,7 +61,7 @@ internal abstract JLocalObject CreateInstance(JClassObject jClass, JObjectLocalR /// Metadata of the types of call arguments. /// A new instance. internal abstract JFunctionDefinition CreateFunctionDefinition(ReadOnlySpan functionName, - JArgumentMetadata[] paramsMetadata); + ReadOnlySpan paramsMetadata); /// /// Creates a instance from . /// diff --git a/src/Test/Rxmxnx.JNetInterface.Extensions.Tests/Internal/NativeFunctionSetImplTests.cs b/src/Test/Rxmxnx.JNetInterface.Extensions.Tests/Internal/NativeFunctionSetImplTests.cs index 6db86334..ea44f46b 100644 --- a/src/Test/Rxmxnx.JNetInterface.Extensions.Tests/Internal/NativeFunctionSetImplTests.cs +++ b/src/Test/Rxmxnx.JNetInterface.Extensions.Tests/Internal/NativeFunctionSetImplTests.cs @@ -338,7 +338,7 @@ internal void GetInterfacesTest() JArrayLocalRef arrayRef = NativeFunctionSetImplTests.fixture.Create(); using JClassObject jClass = new(env); using JClassObject jClassArrayClass = new(jClass, IClassType.GetMetadata().GetArrayMetadata()!); - using JArrayObject interfaces = new(jClassArrayClass, arrayRef, default); + using JArrayObject interfaces = new(jClassArrayClass, arrayRef); env.ClassFeature.GetClass().Returns(jClass); env.AccessFeature.CallFunction>(jClass, jClass, definition, false, []) diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Internal/ReferenceHelper/NativeInterface.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Internal/ReferenceHelper/NativeInterface.cs index 76cefb90..ab77cd64 100644 --- a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Internal/ReferenceHelper/NativeInterface.cs +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Internal/ReferenceHelper/NativeInterface.cs @@ -148,6 +148,14 @@ internal unsafe partial class ReferenceHelper GetLongArrayRegion = &ReferenceHelper.GetLongArrayRegion, GetFloatArrayRegion = &ReferenceHelper.GetFloatArrayRegion, GetDoubleArrayRegion = &ReferenceHelper.GetDoubleArrayRegion, + SetBooleanArrayRegion = &ReferenceHelper.SetBooleanArrayRegion, + SetByteArrayRegion = &ReferenceHelper.SetByteArrayRegion, + SetCharArrayRegion = &ReferenceHelper.SetCharArrayRegion, + SetShortArrayRegion = &ReferenceHelper.SetShortArrayRegion, + SetIntArrayRegion = &ReferenceHelper.SetIntArrayRegion, + SetLongArrayRegion = &ReferenceHelper.SetLongArrayRegion, + SetFloatArrayRegion = &ReferenceHelper.SetFloatArrayRegion, + SetDoubleArrayRegion = &ReferenceHelper.SetDoubleArrayRegion, RegisterNatives = &ReferenceHelper.RegisterNatives, UnregisterNatives = &ReferenceHelper.UnregisterNatives, MonitorEnter = &ReferenceHelper.MonitorEnter, @@ -312,6 +320,14 @@ internal unsafe partial class ReferenceHelper GetLongArrayRegion = &ReferenceHelper.GetLongArrayRegion, GetFloatArrayRegion = &ReferenceHelper.GetFloatArrayRegion, GetDoubleArrayRegion = &ReferenceHelper.GetDoubleArrayRegion, + SetBooleanArrayRegion = &ReferenceHelper.SetBooleanArrayRegion, + SetByteArrayRegion = &ReferenceHelper.SetByteArrayRegion, + SetCharArrayRegion = &ReferenceHelper.SetCharArrayRegion, + SetShortArrayRegion = &ReferenceHelper.SetShortArrayRegion, + SetIntArrayRegion = &ReferenceHelper.SetIntArrayRegion, + SetLongArrayRegion = &ReferenceHelper.SetLongArrayRegion, + SetFloatArrayRegion = &ReferenceHelper.SetFloatArrayRegion, + SetDoubleArrayRegion = &ReferenceHelper.SetDoubleArrayRegion, RegisterNatives = &ReferenceHelper.RegisterNatives, UnregisterNatives = &ReferenceHelper.UnregisterNatives, MonitorEnter = &ReferenceHelper.MonitorEnter, @@ -903,6 +919,47 @@ private static void GetDoubleArrayRegion(JEnvironmentRef envRef, JDoubleArrayLoc => ReferenceHelper.GetProxy(envRef) .GetDoubleArrayRegion(arrayRef, start, count, (ValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetBooleanArrayRegion(JEnvironmentRef envRef, JBooleanArrayLocalRef arrayRef, Int32 start, + Int32 count, JBoolean* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetBooleanArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetByteArrayRegion(JEnvironmentRef envRef, JByteArrayLocalRef arrayRef, Int32 start, + Int32 count, JByte* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetByteArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetCharArrayRegion(JEnvironmentRef envRef, JCharArrayLocalRef arrayRef, Int32 start, + Int32 count, JChar* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetCharArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetShortArrayRegion(JEnvironmentRef envRef, JShortArrayLocalRef arrayRef, Int32 start, + Int32 count, JShort* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetShortArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetIntArrayRegion(JEnvironmentRef envRef, JIntArrayLocalRef arrayRef, Int32 start, Int32 count, + JInt* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetIntArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetLongArrayRegion(JEnvironmentRef envRef, JLongArrayLocalRef arrayRef, Int32 start, + Int32 count, JLong* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetLongArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetFloatArrayRegion(JEnvironmentRef envRef, JFloatArrayLocalRef arrayRef, Int32 start, + Int32 count, JFloat* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetFloatArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] + private static void SetDoubleArrayRegion(JEnvironmentRef envRef, JDoubleArrayLocalRef arrayRef, Int32 start, + Int32 count, JDouble* buffer) + => ReferenceHelper.GetProxy(envRef) + .SetDoubleArrayRegion(arrayRef, start, count, (ReadOnlyValPtr)(IntPtr)buffer); + [UnmanagedCallersOnly] private static JResult RegisterNatives(JEnvironmentRef envRef, JClassLocalRef classRef, NativeMethodValueWrapper* methodEntries, Int32 count) diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/NativeInterfaceProxy.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/NativeInterfaceProxy.cs index 31aa85aa..44f6bbcf 100644 --- a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/NativeInterfaceProxy.cs +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/NativeInterfaceProxy.cs @@ -395,6 +395,23 @@ public abstract void GetFloatArrayRegion(JFloatArrayLocalRef arrayRef, Int32 sta public abstract void GetDoubleArrayRegion(JDoubleArrayLocalRef arrayRef, Int32 start, Int32 count, ValPtr buffer); + public abstract void SetBooleanArrayRegion(JBooleanArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract void SetByteArrayRegion(JByteArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract void SetCharArrayRegion(JCharArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract void SetShortArrayRegion(JShortArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract void SetIntArrayRegion(JIntArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract void SetLongArrayRegion(JLongArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract void SetFloatArrayRegion(JFloatArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract void SetDoubleArrayRegion(JDoubleArrayLocalRef arrayRef, Int32 start, Int32 count, + ReadOnlyValPtr buffer); + public abstract JResult RegisterNatives(JClassLocalRef classRef, ReadOnlyValPtr methodEntries, Int32 count); public abstract JResult UnregisterNatives(JClassLocalRef classRef); diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Rxmxnx.JNetInterface.Implementation.Tests.Proxies.csproj b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Rxmxnx.JNetInterface.Implementation.Tests.Proxies.csproj index bbccff67..52f63d8d 100644 --- a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Rxmxnx.JNetInterface.Implementation.Tests.Proxies.csproj +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests.Proxies/Rxmxnx.JNetInterface.Implementation.Tests.Proxies.csproj @@ -34,4 +34,11 @@ + + + + <_Parameter1>Rxmxnx.JNetInterface.Implementation.Tests + + + diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanCallTests.cs new file mode 100644 index 00000000..cf344654 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class BooleanCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, BooleanCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(BooleanCallTests.fixture.Create()); + BooleanCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(BooleanCallTests.fixture.Create()); + BooleanCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(BooleanCallTests.fixture.Create()); + BooleanCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)BooleanCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = BooleanCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JBoolean result = BooleanCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallBooleanMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualBooleanMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticBooleanMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallBooleanMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualBooleanMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticBooleanMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanFieldTests.cs new file mode 100644 index 00000000..e2cc6141 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/BooleanFieldTests.cs @@ -0,0 +1,120 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class BooleanFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = + TestUtilities.CreateString(proxyEnv, BooleanFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(BooleanFieldTests.fixture.Create()); + BooleanFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(BooleanFieldTests.fixture.Create()); + BooleanFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(BooleanFieldTests.fixture.Create()); + BooleanFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)BooleanFieldTests.fixture.Create()); + JFieldId fieldId = BooleanFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JBoolean result = BooleanFieldTests.fixture.Create(); + JBoolean setValue = BooleanFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetBooleanField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticBooleanField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetBooleanField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticBooleanField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetBooleanField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticBooleanField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteCallTests.cs new file mode 100644 index 00000000..1299138a --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class ByteCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, ByteCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ByteCallTests.fixture.Create()); + ByteCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ByteCallTests.fixture.Create()); + ByteCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ByteCallTests.fixture.Create()); + ByteCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)ByteCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = ByteCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JByte result = ByteCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallByteMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualByteMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticByteMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallByteMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualByteMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticByteMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteFieldTests.cs new file mode 100644 index 00000000..5caaadd3 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ByteFieldTests.cs @@ -0,0 +1,119 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class ByteFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, ByteFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ByteFieldTests.fixture.Create()); + ByteFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ByteFieldTests.fixture.Create()); + ByteFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ByteFieldTests.fixture.Create()); + ByteFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)ByteFieldTests.fixture.Create()); + JFieldId fieldId = ByteFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JByte result = ByteFieldTests.fixture.Create(); + JByte setValue = ByteFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetByteField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticByteField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetByteField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticByteField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetByteField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticByteField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CallType.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CallType.cs new file mode 100644 index 00000000..ea6f6bb3 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CallType.cs @@ -0,0 +1,11 @@ +namespace Rxmxnx.JNetInterface.Tests; + +public enum CallType +{ + Parameterless, + SingleObject, + SingleValue, + Values, + Objects, + Mixed, +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharCallTests.cs new file mode 100644 index 00000000..c4f8f785 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class CharCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, CharCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(CharCallTests.fixture.Create()); + CharCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(CharCallTests.fixture.Create()); + CharCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(CharCallTests.fixture.Create()); + CharCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)CharCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = CharCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JChar result = CharCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallCharMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualCharMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticCharMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallCharMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualCharMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticCharMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharFieldTests.cs new file mode 100644 index 00000000..35b1d7dc --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/CharFieldTests.cs @@ -0,0 +1,119 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class CharFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, CharFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(CharFieldTests.fixture.Create()); + CharFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(CharFieldTests.fixture.Create()); + CharFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(CharFieldTests.fixture.Create()); + CharFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)CharFieldTests.fixture.Create()); + JFieldId fieldId = CharFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JChar result = CharFieldTests.fixture.Create(); + JChar setValue = CharFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetCharField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticCharField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetCharField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticCharField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetCharField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticCharField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ConstructorCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ConstructorCallTests.cs new file mode 100644 index 00000000..e1ac2f2f --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ConstructorCallTests.cs @@ -0,0 +1,60 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class ConstructorCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void Test(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JConstructorDefinition def = JConstructorDefinition.Create(argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = ConstructorCallTests.fixture.Create(); + JDataTypeMetadata metadata = IDataType.GetMetadata(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + using IFixedPointer.IDisposable ctxClass = metadata.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JThrowableLocalRef result = ConstructorCallTests.fixture.Create(); + JClassLocalRef classRef = JClassLocalRef.FromReference(proxyEnv.VirtualMachine.ThrowableGlobalRef); + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(classRef, namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.NewObject(classRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result.Value); + + using JThrowableObject jThrowable = + JConstructorDefinition.New(def, env.ClassFeature.ThrowableObject, args); + + Assert.Equal(result.Value, jThrowable.Reference.Value); + + proxyEnv.Received(1).GetMethodId(classRef, namePtr, Arg.Any>()); + proxyEnv.Received(0).GetStaticMethodId(classRef, namePtr, Arg.Any>()); + + proxyEnv.Received(1).NewObject(classRef, methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleCallTests.cs new file mode 100644 index 00000000..03a4608f --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class DoubleCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, DoubleCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(DoubleCallTests.fixture.Create()); + DoubleCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(DoubleCallTests.fixture.Create()); + DoubleCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(DoubleCallTests.fixture.Create()); + DoubleCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)DoubleCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = DoubleCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JDouble result = DoubleCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallDoubleMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualDoubleMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticDoubleMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallDoubleMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualDoubleMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticDoubleMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleFieldTests.cs new file mode 100644 index 00000000..a9ff83a2 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/DoubleFieldTests.cs @@ -0,0 +1,119 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class DoubleFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, DoubleFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(DoubleFieldTests.fixture.Create()); + DoubleFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(DoubleFieldTests.fixture.Create()); + DoubleFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(DoubleFieldTests.fixture.Create()); + DoubleFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)DoubleFieldTests.fixture.Create()); + JFieldId fieldId = DoubleFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JDouble result = DoubleFieldTests.fixture.Create(); + JDouble setValue = DoubleFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetDoubleField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticDoubleField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetDoubleField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticDoubleField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetDoubleField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticDoubleField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ExceptionHandlingTests/ThrowNewTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ExceptionHandlingTests/ThrowNewTests.cs new file mode 100644 index 00000000..8a2daa29 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ExceptionHandlingTests/ThrowNewTests.cs @@ -0,0 +1,96 @@ +namespace Rxmxnx.JNetInterface.Tests; + +public partial class ExceptionHandlingTests +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(true, true)] + [InlineData(false, true)] + internal void ThrowNewThrowableTest(Boolean utf8Message, Boolean throwException = false) + => ExceptionHandlingTests.ThrowNewTest(utf8Message, throwException); + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(true, true)] + [InlineData(false, true)] + internal void ThrowNewErrorTest(Boolean utf8Message, Boolean throwException = false) + => ExceptionHandlingTests.ThrowNewTest(utf8Message, throwException); + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(true, true)] + [InlineData(false, true)] + internal void ThrowNewExceptionTest(Boolean utf8Message, Boolean throwException = false) + => ExceptionHandlingTests.ThrowNewTest(utf8Message, throwException); + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(true, true)] + [InlineData(false, true)] + internal void ThrowNewRuntimeExceptionTest(Boolean utf8Message, Boolean throwException = false) + => ExceptionHandlingTests.ThrowNewTest(utf8Message, throwException); + + private static void ThrowNewTest(Boolean utf8Message, Boolean throwException) + where TThrowable : JThrowableObject, IThrowableType + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + String message = ExceptionHandlingTests.fixture.Create(); + JClassLocalRef classRef = ExceptionHandlingTests.fixture.Create(); + + using IFixedPointer.IDisposable fMem = IDataType.GetMetadata().Information.GetFixedPointer(); + JThrowableLocalRef throwableRef = ExceptionHandlingTests.fixture.Create(); + JGlobalRef globalRef = ExceptionHandlingTests.fixture.Create(); + IMutableWrapper exceptionOccurred = IMutableWrapper.Create(); + + proxyEnv.FindClass((ReadOnlyValPtr)fMem.Pointer).Returns(classRef); + proxyEnv.ThrowNew(Arg.Any(), Arg.Any>()).Returns(JResult.Ok); + proxyEnv.NewGlobalRef(throwableRef.Value).Returns(globalRef); + proxyEnv.ExceptionOccurred().Returns(_ => exceptionOccurred.Value); + proxyEnv.ExceptionCheck().Returns(_ => !exceptionOccurred.Value.IsDefault); + proxyEnv.When(e => e.ThrowNew(Arg.Any(), Arg.Any>())) + .Do(_ => { exceptionOccurred.Value = throwableRef; }); + proxyEnv.When(e => e.ExceptionClear()).Do(_ => { exceptionOccurred.Value = default; }); + proxyEnv.When(e => e.Throw(Arg.Any())) + .Do(c => { exceptionOccurred.Value = (JThrowableLocalRef)c[0]; }); + + ThrowableException ex; + if (throwException) + { + ex = utf8Message ? + Assert.ThrowsAny( + () => JThrowableObject.ThrowNew(env, (CString)message, true)) : + Assert.ThrowsAny( + () => JThrowableObject.ThrowNew(env, message, true)); + } + else + { + if (utf8Message) + JThrowableObject.ThrowNew(env, (CString)message); + else + JThrowableObject.ThrowNew(env, message); + ex = env.PendingException!; + } + + Assert.Equal(globalRef.Value, ex.ThrowableRef.Value); + Assert.Equal(message, ex.Message); + + proxyEnv.Received(1).ThrowNew(Arg.Any(), Arg.Any>()); + + env.PendingException = default; + ex.GlobalThrowable.Dispose(); + env.ClassFeature.GetClass().Dispose(); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatCallTests.cs new file mode 100644 index 00000000..91b39ef1 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class FloatCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, FloatCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(FloatCallTests.fixture.Create()); + FloatCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(FloatCallTests.fixture.Create()); + FloatCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(FloatCallTests.fixture.Create()); + FloatCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)FloatCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = FloatCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JFloat result = FloatCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallFloatMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualFloatMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticFloatMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallFloatMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualFloatMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticFloatMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatFieldTests.cs new file mode 100644 index 00000000..3908fd75 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/FloatFieldTests.cs @@ -0,0 +1,119 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class FloatFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, FloatFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(FloatFieldTests.fixture.Create()); + FloatFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(FloatFieldTests.fixture.Create()); + FloatFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(FloatFieldTests.fixture.Create()); + FloatFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)FloatFieldTests.fixture.Create()); + JFieldId fieldId = FloatFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JFloat result = FloatFieldTests.fixture.Create(); + JFloat setValue = FloatFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetFloatField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticFloatField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetFloatField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticFloatField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetFloatField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticFloatField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntCallTests.cs new file mode 100644 index 00000000..97bea61a --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class IntCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, IntCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(IntCallTests.fixture.Create()); + IntCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(IntCallTests.fixture.Create()); + IntCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(IntCallTests.fixture.Create()); + IntCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)IntCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = IntCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JInt result = IntCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallIntMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualIntMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticIntMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallIntMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualIntMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticIntMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntFieldTests.cs new file mode 100644 index 00000000..f148010e --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/IntFieldTests.cs @@ -0,0 +1,119 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class IntFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, IntFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(IntFieldTests.fixture.Create()); + IntFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(IntFieldTests.fixture.Create()); + IntFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(IntFieldTests.fixture.Create()); + IntFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)IntFieldTests.fixture.Create()); + JFieldId fieldId = IntFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JInt result = IntFieldTests.fixture.Create(); + JInt setValue = IntFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetIntField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticIntField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetIntField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticIntField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetIntField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticIntField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongCallTests.cs new file mode 100644 index 00000000..f6eb5a3f --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class LongCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, LongCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(LongCallTests.fixture.Create()); + LongCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(LongCallTests.fixture.Create()); + LongCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(LongCallTests.fixture.Create()); + LongCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)LongCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = LongCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JLong result = LongCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallLongMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualLongMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticLongMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallLongMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualLongMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticLongMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongFieldTests.cs new file mode 100644 index 00000000..735ee902 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/LongFieldTests.cs @@ -0,0 +1,119 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class LongFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, LongFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(LongFieldTests.fixture.Create()); + LongFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(LongFieldTests.fixture.Create()); + LongFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(LongFieldTests.fixture.Create()); + LongFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)LongFieldTests.fixture.Create()); + JFieldId fieldId = LongFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JLong result = LongFieldTests.fixture.Create(); + JLong setValue = LongFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetLongField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticLongField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetLongField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticLongField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetLongField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticLongField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectCallTests.cs new file mode 100644 index 00000000..03404cc0 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectCallTests.cs @@ -0,0 +1,155 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class ObjectCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, ObjectCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ObjectCallTests.fixture.Create()); + ObjectCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ObjectCallTests.fixture.Create()); + ObjectCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ObjectCallTests.fixture.Create()); + ObjectCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)ObjectCallTests.fixture.Create(), + argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = ObjectCallTests.fixture.Create(); + JDataTypeMetadata metadata = IDataType.GetMetadata(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + using IFixedPointer.IDisposable ctxClass = metadata.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JThrowableLocalRef result = ObjectCallTests.fixture.Create(); + JStringLocalRef strRef = ObjectCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetObjectClass(result.Value).Returns(proxyEnv.ThrowableLocalRef); + proxyEnv.CallObjectMethod(proxyEnv.ThrowableLocalRef.Value, proxyEnv.VirtualMachine.ClassGetNameMethodId, + ReadOnlyValPtr.Zero).Returns(strRef.Value); + proxyEnv.GetStringUtfLength(strRef).Returns(metadata.ClassName.Length); + proxyEnv.GetStringUtfChars(strRef, Arg.Any>()).Returns((ReadOnlyValPtr)ctxClass.Pointer); + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallObjectMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result.Value); + proxyEnv.CallNonVirtualObjectMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result.Value); + proxyEnv.CallStaticObjectMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result.Value); + + using JThrowableObject? jThrowable = !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args); + + Assert.Equal(result.Value, jThrowable?.Reference.Value); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallObjectMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualObjectMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticObjectMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + jThrowable?.Class.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectFieldTests.cs new file mode 100644 index 00000000..3096bb50 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ObjectFieldTests.cs @@ -0,0 +1,132 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class ObjectFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, ObjectFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ObjectFieldTests.fixture.Create()); + ObjectFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ObjectFieldTests.fixture.Create()); + ObjectFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ObjectFieldTests.fixture.Create()); + ObjectFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)ObjectFieldTests.fixture.Create()); + JFieldId fieldId = ObjectFieldTests.fixture.Create(); + JDataTypeMetadata metadata = IDataType.GetMetadata(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + using IFixedPointer.IDisposable ctxClass = metadata.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JThrowableLocalRef result = ObjectFieldTests.fixture.Create(); + JStringLocalRef strRef = ObjectFieldTests.fixture.Create(); + using JThrowableObject setObject = TestUtilities.CreateThrowable(proxyEnv); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetObjectClass(result.Value).Returns(proxyEnv.ThrowableLocalRef); + proxyEnv.CallObjectMethod(proxyEnv.ThrowableLocalRef.Value, proxyEnv.VirtualMachine.ClassGetNameMethodId, + ReadOnlyValPtr.Zero).Returns(strRef.Value); + proxyEnv.GetStringUtfLength(strRef).Returns(metadata.ClassName.Length); + proxyEnv.GetStringUtfChars(strRef, Arg.Any>()).Returns((ReadOnlyValPtr)ctxClass.Pointer); + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetObjectField(localRef, fieldId).Returns(result.Value); + proxyEnv.GetStaticObjectField(Arg.Any(), fieldId).Returns(result.Value); + + using JThrowableObject? jThrowable = !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!); + + Assert.Equal(result.Value, jThrowable?.Reference.Value); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetObjectField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticObjectField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setObject, jClass); + else + def.StaticSet(jClass!, setObject); + + proxyEnv.Received(!isStatic ? 1 : 0).SetObjectField(localRef, fieldId, setObject.Reference.Value); + proxyEnv.Received(isStatic ? 1 : 0) + .SetStaticObjectField(Arg.Any(), fieldId, setObject.Reference.Value); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + jThrowable?.Class.Dispose(); + setObject.Class.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/PrimitiveArrayMemoryTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/PrimitiveArrayMemoryTests.cs index a41dcc70..67ec1a75 100644 --- a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/PrimitiveArrayMemoryTests.cs +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/PrimitiveArrayMemoryTests.cs @@ -247,7 +247,7 @@ private static void CriticalElementsTest(JMemoryReferenceKind refere TPrimitive[] value = PrimitiveArrayMemoryTests.fixture.CreateMany().ToArray(); using JClassObject arrayClass = JClassObject.GetClass>(env); - using JArrayObject jArray = new(arrayClass, arrayRef, default); + using JArrayObject jArray = new(arrayClass, arrayRef); using IFixedContext.IDisposable fMem = value.AsMemory().GetFixedContext(); ValPtr valPtr = fMem.AsBinaryContext().ValuePointer; Boolean isCopy = PrimitiveArrayMemoryTests.fixture.Create(); @@ -297,6 +297,7 @@ private static void CriticalElementsTest(JMemoryReferenceKind refere .GetPrimitiveArrayCritical(wArrayRef, Arg.Any>()); proxyEnv.Received(referenceKind is JMemoryReferenceKind.ThreadUnrestricted ? 1 : 0) .GetPrimitiveArrayCritical(gArrayRef, Arg.Any>()); + PrimitiveArrayMemoryTests.NestedFailTest(proxyEnv); } finally { @@ -333,7 +334,7 @@ private static void ElementTest(JMemoryReferenceKind referenceKind, TPrimitive[] value = PrimitiveArrayMemoryTests.fixture.CreateMany().ToArray(); using JClassObject arrayClass = JClassObject.GetClass>(env); - using JArrayObject jArray = new(arrayClass, arrayRef, default); + using JArrayObject jArray = new(arrayClass, arrayRef); using IFixedContext.IDisposable fMem = value.AsMemory().GetFixedContext(); ValPtr valPtr = fMem.AsBinaryContext().ValuePointer; @@ -508,4 +509,47 @@ private static void AssertReceivedReleaseElements(NativeInterfaceProxy proxyEnv, proxyEnv.Received(signature == CommonNames.ShortSignatureChar ? count : 0).ReleaseShortArrayElements( arrayRef.Transform(), Arg.Any>(), releaseMode); } + + private static void NestedFailTest(NativeInterfaceProxy proxyEnv) + where TPrimitive : unmanaged, IPrimitiveType + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + TPrimitive[] value = PrimitiveArrayMemoryTests.fixture.CreateMany().ToArray(); + JArrayLocalRef arrayRef = PrimitiveArrayMemoryTests.fixture.Create(); + + using JClassObject arrayClass = JClassObject.GetClass>(env); + using JArrayObject jArray = new(arrayClass, arrayRef); + using IFixedContext.IDisposable fMem = value.AsMemory().GetFixedContext(); + ValPtr valPtr = fMem.AsBinaryContext().ValuePointer; + + proxyEnv.GetArrayLength(arrayRef).Returns(value.Length); + proxyEnv.GetPrimitiveArrayCritical(arrayRef, Arg.Any>()).Returns(valPtr); + PrimitiveArrayMemoryTests.ConfigureGetElements(proxyEnv, ref arrayRef, false, valPtr.Pointer); + + // Clears non-existing exception. + env.PendingException = default; + + JNativeMemory seq = jArray.GetElements(); + Assert.Equal(value.Length, seq.Values.Length); + Assert.Equal(fMem.Pointer, seq.Pointer); + + JNativeMemory seqCritical = jArray.GetCriticalElements(JMemoryReferenceKind.Local); + Assert.Equal(value.Length, seq.Values.Length); + Assert.Equal(fMem.Pointer, seq.Pointer); + + proxyEnv.ExceptionCheck().Returns(true); + Assert.Throws(() => seq.Dispose()); + + proxyEnv.ExceptionCheck().Returns(false); + env.PendingException = default; + + proxyEnv.ExceptionCheck().Returns(true); + Assert.Throws(() => seqCritical.Dispose()); + + proxyEnv.ExceptionCheck().Returns(false); + env.PendingException = default; + + seq.Dispose(); + seqCritical.Dispose(); + } } \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/Rxmxnx.JNetInterface.Implementation.Tests.csproj b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/Rxmxnx.JNetInterface.Implementation.Tests.csproj index 69b40ee4..0a099520 100644 --- a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/Rxmxnx.JNetInterface.Implementation.Tests.csproj +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/Rxmxnx.JNetInterface.Implementation.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortCallTests.cs new file mode 100644 index 00000000..39a5ea40 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortCallTests.cs @@ -0,0 +1,145 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class ShortCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, ShortCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ShortCallTests.fixture.Create()); + ShortCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ShortCallTests.fixture.Create()); + ShortCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ShortCallTests.fixture.Create()); + ShortCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JFunctionDefinition def = + JFunctionDefinition.Create((CString)ShortCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = ShortCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + JShort result = ShortCallTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + proxyEnv.CallShortMethod(localRef, methodId, Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallNonVirtualShortMethod(localRef, Arg.Any(), methodId, + Arg.Is(TestUtilities.GetArgsPtr(args))).Returns(result); + proxyEnv.CallStaticShortMethod(Arg.Any(), methodId, Arg.Is(TestUtilities.GetArgsPtr(args))) + .Returns(result); + + Assert.Equal( + result, + !isStatic ? + JFunctionDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args) : + JFunctionDefinition.StaticInvoke(def, jClass!, args)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallShortMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualShortMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticShortMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortFieldTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortFieldTests.cs new file mode 100644 index 00000000..61d2be6e --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/ShortFieldTests.cs @@ -0,0 +1,119 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class ShortFieldTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Fact] + internal void InstanceTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, ShortFieldTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ShortFieldTests.fixture.Create()); + ShortFieldTests.Test(proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void ExtensionTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ShortFieldTests.fixture.Create()); + ShortFieldTests.Test(proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Fact] + internal void StaticTest() + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(ShortFieldTests.fixture.Create()); + ShortFieldTests.Test(proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JFieldDefinition def = new((CString)ShortFieldTests.fixture.Create()); + JFieldId fieldId = ShortFieldTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isStatic = jClass is not null && jLocal is null; + JShort result = ShortFieldTests.fixture.Create(); + JShort setValue = ShortFieldTests.fixture.Create(); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + proxyEnv.GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()).Returns(fieldId); + + proxyEnv.GetShortField(localRef, fieldId).Returns(result); + proxyEnv.GetStaticShortField(Arg.Any(), fieldId).Returns(result); + + Assert.Equal(result, !isStatic ? def.Get(jLocal!, jClass) : def.StaticGet(jClass!)); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetFieldId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticFieldId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(!isStatic ? 1 : 0).GetShortField(localRef, fieldId); + proxyEnv.Received(isStatic ? 1 : 0).GetStaticShortField(Arg.Any(), fieldId); + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + if (!isStatic) + def.Set(jLocal!, setValue, jClass); + else + def.StaticSet(jClass!, setValue); + + proxyEnv.Received(!isStatic ? 1 : 0).SetShortField(localRef, fieldId, setValue); + proxyEnv.Received(isStatic ? 1 : 0).SetStaticShortField(Arg.Any(), fieldId, setValue); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/StringMemoryTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/StringMemoryTests.cs index 3388d095..ddbaaed3 100644 --- a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/StringMemoryTests.cs +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/StringMemoryTests.cs @@ -116,6 +116,9 @@ internal void CriticalNestedFailTest(Boolean isCopy) Assert.Throws(() => env.PendingException = default); proxyEnv.ExceptionCheck().Returns(false); + + proxyEnv.ClearReceivedCalls(); + StringMemoryTests.NestedFailTest(proxyEnv); } finally { @@ -302,4 +305,60 @@ internal void UtfCharsTest(JMemoryReferenceKind referenceKind, Boolean isCopy = proxyEnv.FinalizeProxy(true); } } + private static void NestedFailTest(NativeInterfaceProxy proxyEnv) + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + String value = StringMemoryTests.fixture.Create(); + CStringSequence utf = new(value); + JStringLocalRef stringRef = StringMemoryTests.fixture.Create(); + + using JStringObject jString = new(env.ClassFeature.StringObject, stringRef); + using IReadOnlyFixedContext.IDisposable fMem = value.AsMemory().GetFixedContext(); + using IFixedPointer.IDisposable fUtfMem = utf.GetFixedPointer(); + ReadOnlyValPtr valPtr = fMem.ValuePointer; + ReadOnlyValPtr valUtfPtr = (ReadOnlyValPtr)fUtfMem.Pointer; + + proxyEnv.GetStringLength(stringRef).Returns(value.Length); + proxyEnv.GetStringUtfLength(stringRef).Returns(utf[0].Length); + proxyEnv.GetStringChars(stringRef, Arg.Any>()).Returns(valPtr); + proxyEnv.GetStringCritical(stringRef, Arg.Any>()).Returns(valPtr); + proxyEnv.GetStringUtfChars(stringRef, Arg.Any>()).Returns(valUtfPtr); + + // Clears non-existing exception. + env.PendingException = default; + + JNativeMemory seq = jString.GetNativeChars(); + Assert.Equal(value.Length, seq.Values.Length); + Assert.Equal(fMem.Pointer, seq.Pointer); + + JNativeMemory seqCritical = jString.GetCriticalChars(JMemoryReferenceKind.Local); + Assert.Equal(value.Length, seqCritical.Values.Length); + Assert.Equal(fMem.Pointer, seqCritical.Pointer); + + JNativeMemory seqUtf = jString.GetNativeUtf8Chars(); + Assert.Equal(utf[0].Length, seqUtf.Values.Length); + Assert.Equal(valUtfPtr.Pointer, seqUtf.Pointer); + + proxyEnv.ExceptionCheck().Returns(true); + Assert.Throws(() => seq.Dispose()); + + proxyEnv.ExceptionCheck().Returns(false); + env.PendingException = default; + + proxyEnv.ExceptionCheck().Returns(true); + Assert.Throws(() => seqCritical.Dispose()); + + proxyEnv.ExceptionCheck().Returns(false); + env.PendingException = default; + + proxyEnv.ExceptionCheck().Returns(true); + Assert.Throws(() => seqUtf.Dispose()); + + proxyEnv.ExceptionCheck().Returns(false); + env.PendingException = default; + + seq.Dispose(); + seqCritical.Dispose(); + seqUtf.Dispose(); + } } \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/TestUtilities.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/TestUtilities.cs index 7c1b6851..eda9712a 100644 --- a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/TestUtilities.cs +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/TestUtilities.cs @@ -34,7 +34,9 @@ public static JArrayObject CreateClassArray(NativeInterfaceProxy p JClassLocalRef classRef = JClassLocalRef.FromReference(in localRef); JObjectArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewObjectArray(length, classRef, Arg.Any()).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = + TestUtilities.CreateArray(env, length, withInitial, env.ClassFeature.ClassObject); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -43,7 +45,9 @@ public static JArrayObject CreateBooleanArray(NativeInterfaceProxy pro IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JBooleanArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewBooleanArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JBoolean value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -52,7 +56,9 @@ public static JArrayObject CreateByteArray(NativeInterfaceProxy proxyEnv, IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JByteArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewByteArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JByte value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -61,7 +67,9 @@ public static JArrayObject CreateCharArray(NativeInterfaceProxy proxyEnv, IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JCharArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewCharArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JChar value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -70,7 +78,9 @@ public static JArrayObject CreateDoubleArray(NativeInterfaceProxy proxy IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JDoubleArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewDoubleArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JDouble value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -79,7 +89,9 @@ public static JArrayObject CreateFloatArray(NativeInterfaceProxy proxyEn IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JFloatArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewFloatArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JFloat value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -88,7 +100,9 @@ public static JArrayObject CreateIntArray(NativeInterfaceProxy proxyEnv, I IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JIntArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewIntArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JInt value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -97,7 +111,9 @@ public static JArrayObject CreateLongArray(NativeInterfaceProxy proxyEnv, IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JLongArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewLongArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JLong value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -106,7 +122,9 @@ public static JArrayObject CreateShortArray(NativeInterfaceProxy proxyEn IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); JShortArrayLocalRef arrayRef = TestUtilities.fixture.Create(); proxyEnv.NewShortArray(length).Returns(arrayRef); - JArrayObject result = JArrayObject.Create(env, length); + JShort value = TestUtilities.fixture.Create(); + Boolean withInitial = Random.Shared.Next(0, 2) < 1; + JArrayObject result = TestUtilities.CreateArray(env, length, withInitial, value); Assert.Equal(arrayRef.ArrayValue, result.Reference); return result; } @@ -255,4 +273,83 @@ public static JNativeCallEntry GetStaticEntry(JMethodDefinition.Parameterless de tracker = new() { WeakReference = new(instanceMethod), FinalizerFlag = instanceMethod.IsDisposed, }; return JNativeCallEntry.CreateParameterless(definition, instanceMethod.VoidCall); } + public static JArgumentMetadata[] GetArgumentsMetadata(this CallType callType) + => callType switch + { + CallType.SingleValue => [JArgumentMetadata.Get(),], + CallType.SingleObject => [JArgumentMetadata.Get(),], + CallType.Values => + [ + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + ], + CallType.Objects => + [ + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + ], + CallType.Mixed => + [ + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + JArgumentMetadata.Get(), + ], + _ => [], + }; + public static IObject[] GetArgumentsValues(this CallType callType, NativeInterfaceProxy proxyEnv) + => callType switch + { + CallType.SingleValue => [(JInt)TestUtilities.fixture.Create(),], + CallType.SingleObject => [TestUtilities.CreateString(proxyEnv, TestUtilities.fixture.Create()),], + CallType.Values => + [ + (JInt)TestUtilities.fixture.Create(), (JDouble)TestUtilities.fixture.Create(), + (JBoolean)TestUtilities.fixture.Create(), + ], + CallType.Objects => + [ + TestUtilities.CreateString(proxyEnv, TestUtilities.fixture.Create()), + (JEnvironment.GetEnvironment(proxyEnv.Reference) as IEnvironment)!.ClassFeature.ClassObject, + TestUtilities.CreateThrowable(proxyEnv), + ], + CallType.Mixed => + [ + (JInt)TestUtilities.fixture.Create(), + TestUtilities.CreateString(proxyEnv, TestUtilities.fixture.Create()), + (JDouble)TestUtilities.fixture.Create(), + (JEnvironment.GetEnvironment(proxyEnv.Reference) as IEnvironment).ClassFeature.ClassObject, + (JBoolean)TestUtilities.fixture.Create(), TestUtilities.CreateThrowable(proxyEnv), + ], + _ => [], + }; + public static Expression>> GetArgsPtr(IObject[] args) + { + Func, Boolean> f = ptr => + { + using IReadOnlyFixedContext.IDisposable ctx = ptr.GetUnsafeFixedContext(args.Length); + Span byteSpan = stackalloc Byte[JValue.Size]; + ReadOnlySpan blank = stackalloc Byte[JValue.Size]; + for (Int32 i = 0; i < args.Length; i++) + { + blank.CopyTo(byteSpan); + args[i].CopyTo(byteSpan); + if (!NativeUtilities.AsBytes(in ctx.Values[i]).SequenceEqual(byteSpan)) + return false; + } + return true; + }; + ParameterExpression parameter = Expression.Parameter(typeof(ReadOnlyValPtr), "ptr"); + Expression body = Expression.Invoke(Expression.Constant(f), parameter); + return Expression.Lambda>>(body, parameter); + } + private static JArrayObject CreateArray(IEnvironment env, Int32 length, Boolean withInitial, + TElement? initial) where TElement : IDataType + => withInitial ? + JArrayObject.Create(env, length) : + JArrayObject.Create(env, length, initial!); } \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/VoidCallTests.cs b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/VoidCallTests.cs new file mode 100644 index 00000000..efb02dd9 --- /dev/null +++ b/src/Test/Rxmxnx.JNetInterface.Implementation.Tests/VoidCallTests.cs @@ -0,0 +1,136 @@ +namespace Rxmxnx.JNetInterface.Tests; + +[ExcludeFromCodeCoverage] +public sealed class VoidCallTests +{ + private static readonly IFixture fixture = new Fixture().RegisterReferences(); + + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void InstanceTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateString(proxyEnv, VoidCallTests.fixture.Create()); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(VoidCallTests.fixture.Create()); + VoidCallTests.Test(callType, proxyEnv, jLocal); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void NonVirtualTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + using JLocalObject jLocal = TestUtilities.CreateThrowable(proxyEnv); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(VoidCallTests.fixture.Create()); + VoidCallTests.Test(callType, proxyEnv, jLocal, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + [Theory] + [InlineData(CallType.Parameterless)] + [InlineData(CallType.SingleObject)] + [InlineData(CallType.SingleValue)] + [InlineData(CallType.Values)] + [InlineData(CallType.Objects)] + [InlineData(CallType.Mixed)] + internal void StaticTest(CallType callType) + { + NativeInterfaceProxy proxyEnv = NativeInterfaceProxy.CreateProxy(); + try + { + IEnvironment env = JEnvironment.GetEnvironment(proxyEnv.Reference); + using IFixedPointer.IDisposable ctx = IDataType.GetMetadata().Information.GetFixedPointer(); + proxyEnv.FindClass((ReadOnlyValPtr)ctx.Pointer) + .Returns(VoidCallTests.fixture.Create()); + VoidCallTests.Test(callType, proxyEnv, default, JClassObject.GetClass(env)); + } + finally + { + JVirtualMachine.RemoveEnvironment(proxyEnv.VirtualMachine.Reference, proxyEnv.Reference); + GC.Collect(); + GC.WaitForPendingFinalizers(); + Assert.True(JVirtualMachine.RemoveVirtualMachine(proxyEnv.VirtualMachine.Reference)); + proxyEnv.FinalizeProxy(true); + } + } + + private static void Test(CallType callType, NativeInterfaceProxy proxyEnv, JLocalObject? jLocal = default, + JClassObject? jClass = default) + { + JArgumentMetadata[] argsMetadata = callType.GetArgumentsMetadata(); + JMethodDefinition def = JMethodDefinition.Create((CString)VoidCallTests.fixture.Create(), argsMetadata); + IObject[] args = callType.GetArgumentsValues(proxyEnv); + JMethodId methodId = VoidCallTests.fixture.Create(); + using IFixedPointer.IDisposable infoDef = def.Information.GetFixedPointer(); + ReadOnlyValPtr namePtr = (ReadOnlyValPtr)infoDef.Pointer; + JObjectLocalRef localRef = jLocal?.Reference ?? default; + Boolean isNonVirtual = jClass is not null && jLocal is not null; + Boolean isStatic = jClass is not null && jLocal is null; + Boolean isInstance = !isNonVirtual && !isStatic; + + proxyEnv.ClearReceivedCalls(); + proxyEnv.VirtualMachine.ClearReceivedCalls(); + + proxyEnv.GetMethodId(Arg.Any(), namePtr, Arg.Any>()).Returns(methodId); + proxyEnv.GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()) + .Returns(methodId); + + if (!isStatic) + JMethodDefinition.Invoke(def, jLocal!, jClass, isNonVirtual, args); + else + JMethodDefinition.StaticInvoke(def, jClass!, args); + + proxyEnv.Received(!isStatic ? 1 : 0) + .GetMethodId(Arg.Any(), namePtr, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .GetStaticMethodId(Arg.Any(), namePtr, Arg.Any>()); + + proxyEnv.Received(isInstance ? 1 : 0) + .CallVoidMethod(localRef, methodId, Arg.Any>()); + proxyEnv.Received(isNonVirtual ? 1 : 0).CallNonVirtualVoidMethod( + localRef, Arg.Any(), methodId, Arg.Any>()); + proxyEnv.Received(isStatic ? 1 : 0) + .CallStaticVoidMethod(Arg.Any(), methodId, Arg.Any>()); + + foreach (IObject obj in args) + (obj as IDisposable)?.Dispose(); + + jClass?.Dispose(); + jLocal?.Class.Dispose(); + jLocal?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/AccessFeatureProxy.cs b/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/AccessFeatureProxy.cs index 87b6593b..594f04dd 100644 --- a/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/AccessFeatureProxy.cs +++ b/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/AccessFeatureProxy.cs @@ -19,6 +19,21 @@ public abstract void SetStaticField(JClassObject jClass, JFieldDefinitio where TField : IDataType; public abstract void SetStaticField(JFieldObject jField, JFieldDefinition definition, TField? value) where TField : IDataType, IObject; + public abstract void RegisterNatives(JClassObject jClass, IReadOnlyList calls); + public abstract void ClearNatives(JClassObject jClass); + public abstract JCallDefinition GetDefinition(JStringObject memberName, JArrayObject parameterTypes, + JClassObject? returnType); + public abstract JFieldDefinition GetDefinition(JStringObject memberName, JClassObject fieldType); + public abstract JMethodObject GetReflectedMethod(JMethodDefinition definition, JClassObject declaringClass, + Boolean isStatic); + public abstract JMethodObject GetReflectedFunction(JFunctionDefinition definition, JClassObject declaringClass, + Boolean isStatic); + public abstract JConstructorObject GetReflectedConstructor(JConstructorDefinition definition, + JClassObject declaringClass); + public abstract JFieldObject GetReflectedField(JFieldDefinition definition, JClassObject declaringClass, + Boolean isStatic); + public abstract JMethodId GetMethodId(JExecutableObject jExecutable); + public abstract JFieldId GetFieldId(JFieldObject jField); public abstract TObject CallConstructor(JClassObject jClass, JConstructorDefinition definition, IObject?[] args) where TObject : JLocalObject, IDataType; public abstract TObject CallConstructor(JConstructorObject jConstructor, JConstructorDefinition definition, @@ -37,21 +52,6 @@ public abstract void CallMethod(JLocalObject jLocal, JClassObject jClass, JMetho Boolean nonVirtual, IObject?[] args); public abstract void CallMethod(JMethodObject jMethod, JLocalObject jLocal, JMethodDefinition definition, Boolean nonVirtual, IObject?[] args); - public abstract void RegisterNatives(JClassObject jClass, IReadOnlyList calls); - public abstract void ClearNatives(JClassObject jClass); - public abstract JCallDefinition GetDefinition(JStringObject memberName, JArrayObject parameterTypes, - JClassObject? returnType); - public abstract JFieldDefinition GetDefinition(JStringObject memberName, JClassObject fieldType); - public abstract JMethodObject GetReflectedMethod(JMethodDefinition definition, JClassObject declaringClass, - Boolean isStatic); - public abstract JMethodObject GetReflectedFunction(JFunctionDefinition definition, JClassObject declaringClass, - Boolean isStatic); - public abstract JConstructorObject GetReflectedConstructor(JConstructorDefinition definition, - JClassObject declaringClass); - public abstract JFieldObject GetReflectedField(JFieldDefinition definition, JClassObject declaringClass, - Boolean isStatic); - public abstract JMethodId GetMethodId(JExecutableObject jExecutable); - public abstract JFieldId GetFieldId(JFieldObject jField); public abstract void GetPrimitiveField(IFixedMemory bytes, JLocalObject jLocal, JClassObject jClass, JFieldDefinition definition); public abstract void GetPrimitiveStaticField(IFixedMemory bytes, JClassObject jClass, JFieldDefinition definition); diff --git a/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/Legacy/AccessFeatureProxy.cs b/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/Legacy/AccessFeatureProxy.cs index de1bb6bd..499b9100 100644 --- a/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/Legacy/AccessFeatureProxy.cs +++ b/src/Test/Rxmxnx.JNetInterface.Native.Tests.Proxies/Restricted/Legacy/AccessFeatureProxy.cs @@ -16,12 +16,43 @@ void IAccessFeature.SetPrimitiveStaticField(JClassObject jClass, JFieldDefinitio => bytes.WithSafeFixed((this, jClass, definition), AccessFeatureProxy.SetPrimitiveStaticField); void IAccessFeature.CallPrimitiveFunction(Span bytes, JLocalObject jLocal, JClassObject jClass, - JFunctionDefinition definition, Boolean nonVirtual, IObject?[] args) - => bytes.WithSafeFixed((this, jLocal, jClass, definition, nonVirtual, args), + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) + => bytes.WithSafeFixed((this, jLocal, jClass, definition, nonVirtual, args.ToArray()), AccessFeatureProxy.CallPrimitiveFunction); void IAccessFeature.CallPrimitiveStaticFunction(Span bytes, JClassObject jClass, - JFunctionDefinition definition, IObject?[] args) - => bytes.WithSafeFixed((this, jClass, definition, args), AccessFeatureProxy.CallPrimitiveStaticFunction); + JFunctionDefinition definition, ReadOnlySpan args) + => bytes.WithSafeFixed((this, jClass, definition, args.ToArray()), + AccessFeatureProxy.CallPrimitiveStaticFunction); + + TObject IAccessFeature.CallConstructor(JClassObject jClass, JConstructorDefinition definition, + ReadOnlySpan args) + => this.CallConstructor(jClass, definition, args.ToArray()); + TObject IAccessFeature.CallConstructor(JConstructorObject jConstructor, JConstructorDefinition definition, + ReadOnlySpan args) + => this.CallConstructor(jConstructor, definition, args.ToArray()); + TResult? IAccessFeature.CallStaticFunction(JClassObject jClass, JFunctionDefinition definition, + ReadOnlySpan args) where TResult : default + => this.CallStaticFunction(jClass, definition, args.ToArray()); + TResult? IAccessFeature.CallStaticFunction(JMethodObject jMethod, JFunctionDefinition definition, + ReadOnlySpan args) where TResult : default + => this.CallStaticFunction(jMethod, definition, args.ToArray()); + void IAccessFeature.CallStaticMethod(JClassObject jClass, JMethodDefinition definition, ReadOnlySpan args) + => this.CallStaticMethod(jClass, definition, args.ToArray()); + void IAccessFeature.CallStaticMethod(JMethodObject jMethod, JMethodDefinition definition, + ReadOnlySpan args) + => this.CallStaticMethod(jMethod, definition, args.ToArray()); + TResult? IAccessFeature.CallFunction(JLocalObject jLocal, JClassObject jClass, + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) where TResult : default + => this.CallFunction(jLocal, jClass, definition, nonVirtual, args.ToArray()); + TResult? IAccessFeature.CallFunction(JMethodObject jMethod, JLocalObject jLocal, + JFunctionDefinition definition, Boolean nonVirtual, ReadOnlySpan args) where TResult : default + => this.CallFunction(jMethod, jLocal, definition, nonVirtual, args.ToArray()); + void IAccessFeature.CallMethod(JLocalObject jLocal, JClassObject jClass, JMethodDefinition definition, + Boolean nonVirtual, ReadOnlySpan args) + => this.CallMethod(jLocal, jClass, definition, nonVirtual, args.ToArray()); + void IAccessFeature.CallMethod(JMethodObject jMethod, JLocalObject jLocal, JMethodDefinition definition, + Boolean nonVirtual, ReadOnlySpan args) + => this.CallMethod(jMethod, jLocal, definition, nonVirtual, args.ToArray()); private static void GetPrimitiveField(in IFixedMemory mem, (AccessFeatureProxy feature, JLocalObject jLocal, JClassObject jClass, JFieldDefinition definition) args) diff --git a/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JConstructorDefinitionTests.cs b/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JConstructorDefinitionTests.cs index ab629f68..0780f8d2 100644 --- a/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JConstructorDefinitionTests.cs +++ b/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JConstructorDefinitionTests.cs @@ -182,13 +182,17 @@ private static void Test() where TDataType : JLocalObject, IClassType env.ClassFeature.ClearReceivedCalls(); env.AccessFeature.ClearReceivedCalls(); Assert.Equal(instance, constructorDefinition.New(jClass, parameters)); - env.AccessFeature.Received(1).CallConstructor(jClass, constructorDefinition, parameters); + env.AccessFeature.Received(1) + .CallConstructor(jClass, constructorDefinition, + Arg.Is(a => a.SequenceEqual(parameters))); env.ClassFeature.ClearReceivedCalls(); env.AccessFeature.ClearReceivedCalls(); Assert.Equal(instance, constructorDefinition.New(env, parameters)); env.ClassFeature.Received(1).GetClass(); - env.AccessFeature.Received(1).CallConstructor(jClass, constructorDefinition, parameters); + env.AccessFeature.Received(1) + .CallConstructor(jClass, constructorDefinition, + Arg.Is(a => a.SequenceEqual(parameters))); env.ClassFeature.ClearReceivedCalls(); env.AccessFeature.ClearReceivedCalls(); @@ -208,33 +212,36 @@ private static void Test() where TDataType : JLocalObject, IClassType env.ClassFeature.ClearReceivedCalls(); env.AccessFeature.ClearReceivedCalls(); Assert.Equal(instance, constructorDefinition.NewReflected(jConstructor, parameters)); - env.AccessFeature.Received(1).CallConstructor(jConstructor, constructorDefinition, parameters); + env.AccessFeature.Received(1) + .CallConstructor(jConstructor, constructorDefinition, + Arg.Is(a => a.SequenceEqual(parameters))); env.ClassFeature.ClearReceivedCalls(); env.AccessFeature.ClearReceivedCalls(); Assert.Equal(instance, constructorDefinition.NewReflected(jConstructor, parameters)); - env.AccessFeature.Received(1).CallConstructor(jConstructor, constructorDefinition, parameters); + env.AccessFeature.Received(1) + .CallConstructor(jConstructor, constructorDefinition, + Arg.Is(a => a.SequenceEqual(parameters))); } private static Boolean IsEmptyArgs(IReadOnlyCollection cArgs) - => cArgs.Count == JConstructorDefinitionTests.args.Length && cArgs.All(o => o is null); + => (cArgs.Count == JConstructorDefinitionTests.args.Length || cArgs.Count == 0) && cArgs.All(o => o is null); private class JFakeConstructor(params JArgumentMetadata[] metadata) : JConstructorDefinition(metadata) { public new JLocalObject New(JClassObject jClass) => base.New(jClass); public new TObject New(IEnvironment env) where TObject : JLocalObject, IClassType => base.New(env); - public new JLocalObject New(JClassObject jClass, IObject?[] args) => base.New(jClass, args); - public new TObject New(IEnvironment env, IObject?[] args) - where TObject : JLocalObject, IClassType + public JLocalObject New(JClassObject jClass, IObject?[] args) => base.New(jClass, args); + public TObject New(IEnvironment env, IObject?[] args) where TObject : JLocalObject, IClassType => base.New(env, args); public new JLocalObject NewReflected(JConstructorObject jConstructorObject) => base.NewReflected(jConstructorObject); - public new JLocalObject NewReflected(JConstructorObject jConstructorObject, IObject?[] args) + public JLocalObject NewReflected(JConstructorObject jConstructorObject, IObject?[] args) => base.NewReflected(jConstructorObject, args); public new TObject NewReflected(JConstructorObject jConstructorObject) where TObject : JLocalObject, IClassType => base.NewReflected(jConstructorObject); - public new TObject NewReflected(JConstructorObject jConstructorObject, IObject?[] args) + public TObject NewReflected(JConstructorObject jConstructorObject, IObject?[] args) where TObject : JLocalObject, IClassType => base.NewReflected(jConstructorObject, args); } diff --git a/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JFunctionDefinitionTests.cs b/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JFunctionDefinitionTests.cs index a977d02e..73d1a8d5 100644 --- a/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JFunctionDefinitionTests.cs +++ b/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JFunctionDefinitionTests.cs @@ -186,12 +186,13 @@ private static void Test() where TDataType : JReferenceObject, IRefer a => JFunctionDefinitionTests.IsEmptyArgs(a))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.Invoke(jMethod, parameters)); - env.AccessFeature.Received(1) - .CallFunction((JLocalObject)jMethod, jMethod.Class, functionDefinition, false, parameters); + env.AccessFeature.Received(1).CallFunction((JLocalObject)jMethod, jMethod.Class, functionDefinition, + false, + Arg.Is(a => a.SequenceEqual(parameters))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.Invoke(jMethod, jClass, parameters)); - env.AccessFeature.Received(1) - .CallFunction((JLocalObject)jMethod, jClass, functionDefinition, false, parameters); + env.AccessFeature.Received(1).CallFunction((JLocalObject)jMethod, jClass, functionDefinition, false, + Arg.Is(a => a.SequenceEqual(parameters))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeNonVirtual(jMethod, jClass)); env.AccessFeature.Received(1).CallFunction((JLocalObject)jMethod, jClass, functionDefinition, true, @@ -199,8 +200,8 @@ private static void Test() where TDataType : JReferenceObject, IRefer a => JFunctionDefinitionTests.IsEmptyArgs(a))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeNonVirtual(jMethod, jClass, parameters)); - env.AccessFeature.Received(1) - .CallFunction((JLocalObject)jMethod, jClass, functionDefinition, true, parameters); + env.AccessFeature.Received(1).CallFunction((JLocalObject)jMethod, jClass, functionDefinition, true, + Arg.Is(a => a.SequenceEqual(parameters))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.StaticInvoke(jMethodClass)); env.AccessFeature.Received(1).CallStaticFunction(jMethodClass, functionDefinition, @@ -208,7 +209,9 @@ private static void Test() where TDataType : JReferenceObject, IRefer a => JFunctionDefinitionTests.IsEmptyArgs(a))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.StaticInvoke(jClass, parameters)); - env.AccessFeature.Received(1).CallStaticFunction(jClass, functionDefinition, parameters); + env.AccessFeature.Received(1) + .CallStaticFunction(jClass, functionDefinition, + Arg.Is(a => a.SequenceEqual(parameters))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeReflected(jMethod, jClass)); env.AccessFeature.Received(1).CallFunction(jMethod, (JLocalObject)jClass, functionDefinition, false, @@ -216,7 +219,8 @@ private static void Test() where TDataType : JReferenceObject, IRefer a => JFunctionDefinitionTests.IsEmptyArgs(a))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeReflected(jMethod, jMethod, parameters)); - env.AccessFeature.Received(1).CallFunction(jMethod, jMethod, functionDefinition, false, parameters); + env.AccessFeature.Received(1).CallFunction(jMethod, jMethod, functionDefinition, false, + Arg.Is(a => a.SequenceEqual(parameters))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeNonVirtualReflected(jMethod, jMethodClass)); env.AccessFeature.Received(1).CallFunction(jMethod, (JLocalObject)jMethodClass, functionDefinition, @@ -225,7 +229,8 @@ private static void Test() where TDataType : JReferenceObject, IRefer a => JFunctionDefinitionTests.IsEmptyArgs(a))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeNonVirtualReflected(jMethod, jMethod, parameters)); - env.AccessFeature.Received(1).CallFunction(jMethod, jMethod, functionDefinition, true, parameters); + env.AccessFeature.Received(1).CallFunction(jMethod, jMethod, functionDefinition, true, + Arg.Is(a => a.SequenceEqual(parameters))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeStaticReflected(jMethod)); env.AccessFeature.Received(1).CallStaticFunction(jMethod, functionDefinition, @@ -233,7 +238,9 @@ private static void Test() where TDataType : JReferenceObject, IRefer a => JFunctionDefinitionTests.IsEmptyArgs(a))); env.AccessFeature.ClearReceivedCalls(); Assert.Null(functionDefinition.InvokeStaticReflected(jMethod, parameters)); - env.AccessFeature.Received(1).CallStaticFunction(jMethod, functionDefinition, parameters); + env.AccessFeature.Received(1) + .CallStaticFunction(jMethod, functionDefinition, + Arg.Is(a => a.SequenceEqual(parameters))); } private static void NonTypedTest() where TDataType : JReferenceObject, IReferenceType { @@ -343,32 +350,32 @@ private static void NonTypedTest() where TDataType : JReferenceObject Arg.Is(i => i.SequenceEqual(parameters))); } private static Boolean IsEmptyArgs(IReadOnlyCollection cArgs) - => cArgs.Count == JFunctionDefinitionTests.args.Length && cArgs.All(o => o is null); + => (cArgs.Count == JFunctionDefinitionTests.args.Length || cArgs.Count == 0) && cArgs.All(o => o is null); private class JFakeFunctionDefinition(ReadOnlySpan functionName, params JArgumentMetadata[] metadata) : JFunctionDefinition(functionName, metadata) where TResult : JReferenceObject, IReferenceType { public new TResult? Invoke(JLocalObject jLocal) => base.Invoke(jLocal); public new TResult? Invoke(JLocalObject jLocal, JClassObject jClass) => base.Invoke(jLocal, jClass); - public new TResult? Invoke(JLocalObject jLocal, IObject?[] args) => base.Invoke(jLocal, args); - public new TResult? Invoke(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + public TResult? Invoke(JLocalObject jLocal, IObject?[] args) => base.Invoke(jLocal, args); + public TResult? Invoke(JLocalObject jLocal, JClassObject jClass, IObject?[] args) => base.Invoke(jLocal, jClass, args); public new TResult? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass) => base.InvokeNonVirtual(jLocal, jClass); - public new TResult? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + public TResult? InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, IObject?[] args) => base.InvokeNonVirtual(jLocal, jClass, args); public new TResult? StaticInvoke(JClassObject jClass) => base.StaticInvoke(jClass); - public new TResult? StaticInvoke(JClassObject jClass, IObject?[] args) => base.StaticInvoke(jClass, args); + public TResult? StaticInvoke(JClassObject jClass, IObject?[] args) => base.StaticInvoke(jClass, args); public new TResult? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal) => base.InvokeReflected(jMethod, jLocal); - public new TResult? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + public TResult? InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) => base.InvokeReflected(jMethod, jLocal, args); public new TResult? InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal) => base.InvokeNonVirtualReflected(jMethod, jLocal); - public new TResult? InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + public TResult? InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) => base.InvokeNonVirtualReflected(jMethod, jLocal, args); public new TResult? InvokeStaticReflected(JMethodObject jMethod) => base.InvokeStaticReflected(jMethod); - public new TResult? InvokeStaticReflected(JMethodObject jMethod, IObject?[] args) + public TResult? InvokeStaticReflected(JMethodObject jMethod, IObject?[] args) => base.InvokeStaticReflected(jMethod, args); } } \ No newline at end of file diff --git a/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JMethodDefinitionTests.cs b/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JMethodDefinitionTests.cs index 7b88b2b2..e29bbb3c 100644 --- a/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JMethodDefinitionTests.cs +++ b/src/Test/Rxmxnx.JNetInterface.Native.Tests/Native/Access/JMethodDefinitionTests.cs @@ -102,74 +102,81 @@ internal void Test() Arg.Is(a => JMethodDefinitionTests.IsEmptyArgs(a))); methodDefinition.Invoke(jLocal, parameters); - env.AccessFeature.Received(1).CallMethod(jLocal, jLocal.Class, methodDefinition, false, parameters); + env.AccessFeature.Received(1).CallMethod(jLocal, jLocal.Class, methodDefinition, false, + Arg.Is(a => a.SequenceEqual(parameters))); methodDefinition.Invoke(jLocal, jClass, parameters); - env.AccessFeature.Received(1).CallMethod(jLocal, jClass, methodDefinition, false, parameters); + env.AccessFeature.Received(1).CallMethod(jLocal, jClass, methodDefinition, false, + Arg.Is(a => a.SequenceEqual(parameters))); methodDefinition.InvokeNonVirtual(jLocal, jClass); env.AccessFeature.Received(1).CallMethod(jLocal, jClass, methodDefinition, true, Arg.Is(a => JMethodDefinitionTests.IsEmptyArgs(a))); methodDefinition.InvokeNonVirtual(jLocal, jClass, parameters); - env.AccessFeature.Received(1).CallMethod(jLocal, jClass, methodDefinition, true, parameters); + env.AccessFeature.Received(1).CallMethod(jLocal, jClass, methodDefinition, true, + Arg.Is(a => a.SequenceEqual(parameters))); methodDefinition.StaticInvoke(jStringClass); env.AccessFeature.Received(1).CallStaticMethod(jStringClass, methodDefinition, Arg.Is(a => JMethodDefinitionTests.IsEmptyArgs(a))); methodDefinition.StaticInvoke(jClass, parameters); - env.AccessFeature.Received(1).CallStaticMethod(jClass, methodDefinition, parameters); + env.AccessFeature.Received(1) + .CallStaticMethod(jClass, methodDefinition, Arg.Is(a => a.SequenceEqual(parameters))); methodDefinition.InvokeReflected(jMethod, jLocal); env.AccessFeature.Received(1).CallMethod(jMethod, jLocal, methodDefinition, false, Arg.Is(a => JMethodDefinitionTests.IsEmptyArgs(a))); methodDefinition.InvokeReflected(jMethod, jLocal, parameters); - env.AccessFeature.Received(1).CallMethod(jMethod, jLocal, methodDefinition, false, parameters); + env.AccessFeature.Received(1).CallMethod(jMethod, jLocal, methodDefinition, false, + Arg.Is(a => a.SequenceEqual(parameters))); methodDefinition.InvokeNonVirtualReflected(jMethod, jLocal); env.AccessFeature.Received(1).CallMethod(jMethod, jLocal, methodDefinition, true, Arg.Is(a => JMethodDefinitionTests.IsEmptyArgs(a))); methodDefinition.InvokeNonVirtualReflected(jMethod, jLocal, parameters); - env.AccessFeature.Received(1).CallMethod(jMethod, jLocal, methodDefinition, true, parameters); + env.AccessFeature.Received(1).CallMethod(jMethod, jLocal, methodDefinition, true, + Arg.Is(a => a.SequenceEqual(parameters))); methodDefinition.InvokeStaticReflected(jMethod); env.AccessFeature.Received(1).CallStaticMethod(jMethod, methodDefinition, Arg.Is(a => JMethodDefinitionTests.IsEmptyArgs(a))); methodDefinition.InvokeStaticReflected(jMethod, parameters); - env.AccessFeature.Received(1).CallStaticMethod(jMethod, methodDefinition, parameters); + env.AccessFeature.Received(1) + .CallStaticMethod(jMethod, methodDefinition, Arg.Is(a => a.SequenceEqual(parameters))); } private static Boolean IsEmptyArgs(IReadOnlyCollection cArgs) - => cArgs.Count == JMethodDefinitionTests.args.Length && cArgs.All(o => o is null); + => (cArgs.Count == JMethodDefinitionTests.args.Length || cArgs.Count == 0) && cArgs.All(o => o is null); private class JFakeMethodDefinition(ReadOnlySpan methodName, params JArgumentMetadata[] metadata) : JMethodDefinition(methodName, metadata) { public new void Invoke(JLocalObject jLocal) => base.Invoke(jLocal); public new void Invoke(JLocalObject jLocal, JClassObject jClass) => base.Invoke(jLocal, jClass); - public new void Invoke(JLocalObject jLocal, IObject?[] args) => base.Invoke(jLocal, args); - public new void Invoke(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + public void Invoke(JLocalObject jLocal, IObject?[] args) => base.Invoke(jLocal, args); + public void Invoke(JLocalObject jLocal, JClassObject jClass, IObject?[] args) => base.Invoke(jLocal, jClass, args); public new void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass) => base.InvokeNonVirtual(jLocal, jClass); - public new void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, IObject?[] args) + public void InvokeNonVirtual(JLocalObject jLocal, JClassObject jClass, IObject?[] args) => base.InvokeNonVirtual(jLocal, jClass, args); public new void StaticInvoke(JClassObject jClass) => base.StaticInvoke(jClass); - public new void StaticInvoke(JClassObject jClass, IObject?[] args) => base.StaticInvoke(jClass, args); + public void StaticInvoke(JClassObject jClass, IObject?[] args) => base.StaticInvoke(jClass, args); public new void InvokeReflected(JMethodObject jMethod, JLocalObject jLocal) => base.InvokeReflected(jMethod, jLocal); - public new void InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + public void InvokeReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) => base.InvokeReflected(jMethod, jLocal, args); public new void InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal) => base.InvokeNonVirtualReflected(jMethod, jLocal); - public new void InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) + public void InvokeNonVirtualReflected(JMethodObject jMethod, JLocalObject jLocal, IObject?[] args) => base.InvokeNonVirtualReflected(jMethod, jLocal, args); public new void InvokeStaticReflected(JMethodObject jMethod) => base.InvokeStaticReflected(jMethod); - public new void InvokeStaticReflected(JMethodObject jMethod, IObject?[] args) + public void InvokeStaticReflected(JMethodObject jMethod, IObject?[] args) => base.InvokeStaticReflected(jMethod, args); } } \ No newline at end of file