Skip to content

Commit 6fdfc6e

Browse files
[TrimmableTypeMap] Scanner unit tests (#10813)
Stacked on #10823. Adds comprehensive unit test coverage for the Java peer scanner. Part of #10798 ## What this PR adds New `Microsoft.Android.Sdk.TrimmableTypeMap.Tests` project with xUnit tests: ### 1. Test fixtures > `TestFixtures/StubAttributes.cs`, `TestFixtures/TestTypes.cs` Stub Mono.Android attributes and a representative set of test types covering MCW bindings, user types with component attributes, generics, nested types, interfaces with invokers, and edge-case types (unregistered, empty namespace, deep nesting). ### 2. Foundational tests > `Scanner/JavaPeerScannerTests.cs` Core discovery assertions: all peers found, DoNotGenerateAcw flags, component types marked unconditional, interface/abstract/generic metadata, assembly name populated. ### 3. Behavior and contract tests > `Scanner/JavaPeerScannerTests.Behavior.cs` Marshal method collection, JNI signature decoding for all primitive types and arrays, activation constructor inheritance, base type chain resolution, compat JNI names, custom JNI name provider attributes, nested type discovery. ### 4. Edge-case regression tests > `Scanner/JavaPeerScannerTests.EdgeCases.cs` Generic TypeSpecification resolution, component-only base detection, unregistered nested type naming, 3-level deep nesting, empty namespace handling, plain subclass CRC64 naming, unregistered types with interfaces/exports.
1 parent 265a63b commit 6fdfc6e

File tree

11 files changed

+895
-0
lines changed

11 files changed

+895
-0
lines changed

Xamarin.Android.sln

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.ProjectTools", "src
5959
EndProject
6060
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Build.Tests", "src\Xamarin.Android.Build.Tasks\Tests\Xamarin.Android.Build.Tests\Xamarin.Android.Build.Tests.csproj", "{53E4ABF0-1085-45F9-B964-DCAE4B819998}"
6161
EndProject
62+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Android.Sdk.TrimmableTypeMap", "src\Microsoft.Android.Sdk.TrimmableTypeMap\Microsoft.Android.Sdk.TrimmableTypeMap.csproj", "{507759AE-93DF-411B-8645-31F680319F5C}"
63+
EndProject
64+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Android.Sdk.TrimmableTypeMap.Tests", "tests\Microsoft.Android.Sdk.TrimmableTypeMap.Tests\Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj", "{F9CD012E-67AC-4A4E-B2A7-252387F91256}"
65+
EndProject
66+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFixtures", "tests\Microsoft.Android.Sdk.TrimmableTypeMap.Tests\TestFixtures\TestFixtures.csproj", "{C5A44686-3469-45A7-B6AB-2798BA0625BC}"
67+
EndProject
6268
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "class-parse", "external\Java.Interop\tools\class-parse\class-parse.csproj", "{38C762AB-8FD1-44DE-9855-26AAE7129DC3}"
6369
EndProject
6470
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logcat-parse", "external\Java.Interop\tools\logcat-parse\logcat-parse.csproj", "{7387E151-48E3-4885-B2CA-A74434A34045}"
@@ -231,6 +237,18 @@ Global
231237
{53E4ABF0-1085-45F9-B964-DCAE4B819998}.Debug|AnyCPU.Build.0 = Debug|Any CPU
232238
{53E4ABF0-1085-45F9-B964-DCAE4B819998}.Release|AnyCPU.ActiveCfg = Release|Any CPU
233239
{53E4ABF0-1085-45F9-B964-DCAE4B819998}.Release|AnyCPU.Build.0 = Release|Any CPU
240+
{507759AE-93DF-411B-8645-31F680319F5C}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
241+
{507759AE-93DF-411B-8645-31F680319F5C}.Debug|AnyCPU.Build.0 = Debug|Any CPU
242+
{507759AE-93DF-411B-8645-31F680319F5C}.Release|AnyCPU.ActiveCfg = Release|Any CPU
243+
{507759AE-93DF-411B-8645-31F680319F5C}.Release|AnyCPU.Build.0 = Release|Any CPU
244+
{F9CD012E-67AC-4A4E-B2A7-252387F91256}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
245+
{F9CD012E-67AC-4A4E-B2A7-252387F91256}.Debug|AnyCPU.Build.0 = Debug|Any CPU
246+
{F9CD012E-67AC-4A4E-B2A7-252387F91256}.Release|AnyCPU.ActiveCfg = Release|Any CPU
247+
{F9CD012E-67AC-4A4E-B2A7-252387F91256}.Release|AnyCPU.Build.0 = Release|Any CPU
248+
{C5A44686-3469-45A7-B6AB-2798BA0625BC}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
249+
{C5A44686-3469-45A7-B6AB-2798BA0625BC}.Debug|AnyCPU.Build.0 = Debug|Any CPU
250+
{C5A44686-3469-45A7-B6AB-2798BA0625BC}.Release|AnyCPU.ActiveCfg = Release|Any CPU
251+
{C5A44686-3469-45A7-B6AB-2798BA0625BC}.Release|AnyCPU.Build.0 = Release|Any CPU
234252
{38C762AB-8FD1-44DE-9855-26AAE7129DC3}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
235253
{38C762AB-8FD1-44DE-9855-26AAE7129DC3}.Debug|AnyCPU.Build.0 = Debug|Any CPU
236254
{38C762AB-8FD1-44DE-9855-26AAE7129DC3}.Release|AnyCPU.ActiveCfg = Release|Any CPU
@@ -398,6 +416,8 @@ Global
398416
{645E1718-C8C4-4C23-8A49-5A37E4ECF7ED} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
399417
{2DD1EE75-6D8D-4653-A800-0A24367F7F38} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
400418
{53E4ABF0-1085-45F9-B964-DCAE4B819998} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
419+
{F9CD012E-67AC-4A4E-B2A7-252387F91256} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
420+
{C5A44686-3469-45A7-B6AB-2798BA0625BC} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
401421
{38C762AB-8FD1-44DE-9855-26AAE7129DC3} = {864062D3-A415-4A6F-9324-5820237BA058}
402422
{7387E151-48E3-4885-B2CA-A74434A34045} = {864062D3-A415-4A6F-9324-5820237BA058}
403423
{8A6CB07C-E493-4A4F-AB94-038645A27118} = {E351F97D-EA4F-4E7F-AAA0-8EBB1F2A4A62}

build-tools/automation/yaml-templates/build-windows-steps.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,21 @@ steps:
7777
testRunTitle: Microsoft.Android.Sdk.Analysis.Tests
7878
continueOnError: true
7979

80+
- template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml@self
81+
parameters:
82+
command: test
83+
project: tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj
84+
arguments: -c $(XA.Build.Configuration) --logger trx --results-directory $(Agent.TempDirectory)/trimmable-typemap-tests
85+
displayName: Test Microsoft.Android.Sdk.TrimmableTypeMap.Tests $(XA.Build.Configuration)
86+
87+
- task: PublishTestResults@2
88+
displayName: publish Microsoft.Android.Sdk.TrimmableTypeMap.Tests results
89+
condition: always()
90+
inputs:
91+
testResultsFormat: VSTest
92+
testResultsFiles: "$(Agent.TempDirectory)/trimmable-typemap-tests/*.trx"
93+
testRunTitle: Microsoft.Android.Sdk.TrimmableTypeMap.Tests
94+
8095
- task: BatchScript@1
8196
displayName: Test dotnet-local.cmd - create template
8297
inputs:

src/Microsoft.Android.Sdk.TrimmableTypeMap/Microsoft.Android.Sdk.TrimmableTypeMap.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<ItemGroup>
1212
<PackageReference Include="System.IO.Hashing" Version="$(SystemIOHashingPackageVersion)" />
1313
<PackageReference Include="System.Reflection.Metadata" Version="$(SystemReflectionMetadataPackageVersion)" />
14+
<InternalsVisibleTo Include="Microsoft.Android.Sdk.TrimmableTypeMap.Tests" />
1415
</ItemGroup>
1516

1617
<ItemGroup>

src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/AssemblyIndex.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ void Build ()
105105
applicationAttributeInfo.BackupAgent = TryGetTypeProperty (ca, "BackupAgent");
106106
applicationAttributeInfo.ManageSpaceActivity = TryGetTypeProperty (ca, "ManageSpaceActivity");
107107
}
108+
} else if (attrInfo is null && ImplementsJniNameProviderAttribute (ca)) {
109+
// Custom attribute implementing IJniNameProviderAttribute (e.g., user-defined [CustomJniName])
110+
var name = TryGetNameProperty (ca);
111+
if (name is not null) {
112+
attrInfo = new TypeAttributeInfo (attrName);
113+
attrInfo.JniName = name.Replace ('.', '/');
114+
}
108115
}
109116
}
110117

@@ -129,6 +136,36 @@ static TypeAttributeInfo CreateTypeAttributeInfo (string attrName)
129136

130137
static bool IsKnownComponentAttribute (string attrName) => KnownComponentAttributes.Contains (attrName);
131138

139+
/// <summary>
140+
/// Checks whether a custom attribute's type implements <c>Java.Interop.IJniNameProviderAttribute</c>.
141+
/// Only works for attributes defined in the assembly being scanned (MethodDefinition constructors).
142+
/// </summary>
143+
bool ImplementsJniNameProviderAttribute (CustomAttribute ca)
144+
{
145+
if (ca.Constructor.Kind != HandleKind.MethodDefinition) {
146+
return false;
147+
}
148+
var methodDef = Reader.GetMethodDefinition ((MethodDefinitionHandle)ca.Constructor);
149+
var typeDef = Reader.GetTypeDefinition (methodDef.GetDeclaringType ());
150+
foreach (var implHandle in typeDef.GetInterfaceImplementations ()) {
151+
var impl = Reader.GetInterfaceImplementation (implHandle);
152+
if (impl.Interface.Kind == HandleKind.TypeReference) {
153+
var typeRef = Reader.GetTypeReference ((TypeReferenceHandle)impl.Interface);
154+
if (Reader.GetString (typeRef.Name) == "IJniNameProviderAttribute" &&
155+
Reader.GetString (typeRef.Namespace) == "Java.Interop") {
156+
return true;
157+
}
158+
} else if (impl.Interface.Kind == HandleKind.TypeDefinition) {
159+
var ifaceDef = Reader.GetTypeDefinition ((TypeDefinitionHandle)impl.Interface);
160+
if (Reader.GetString (ifaceDef.Name) == "IJniNameProviderAttribute" &&
161+
Reader.GetString (ifaceDef.Namespace) == "Java.Interop") {
162+
return true;
163+
}
164+
}
165+
}
166+
return false;
167+
}
168+
132169
internal static string? GetCustomAttributeName (CustomAttribute ca, MetadataReader reader)
133170
{
134171
if (ca.Constructor.Kind == HandleKind.MemberReference) {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(DotNetStableTargetFramework)</TargetFramework>
5+
<LangVersion>latest</LangVersion>
6+
<Nullable>enable</Nullable>
7+
<IsPackable>false</IsPackable>
8+
<RootNamespace>Microsoft.Android.Sdk.TrimmableTypeMap.Tests</RootNamespace>
9+
</PropertyGroup>
10+
11+
<!-- Exclude TestFixtures subdirectory — it's a separate project compiled independently -->
12+
<ItemGroup>
13+
<Compile Remove="TestFixtures\**" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<PackageReference Include="xunit" Version="2.9.3" />
18+
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2" />
19+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
20+
</ItemGroup>
21+
22+
<ItemGroup>
23+
<ProjectReference Include="..\..\src\Microsoft.Android.Sdk.TrimmableTypeMap\Microsoft.Android.Sdk.TrimmableTypeMap.csproj" />
24+
<ProjectReference Include="TestFixtures\TestFixtures.csproj">
25+
<!-- Don't add as a compile-time reference — we only need the built DLL as scanner test input -->
26+
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
27+
</ProjectReference>
28+
</ItemGroup>
29+
30+
<!-- Copy TestFixtures output to our output directory so tests can find it -->
31+
<Target Name="_CopyTestFixturesOutput" AfterTargets="Build">
32+
<ItemGroup>
33+
<_TestFixtureFiles Include="TestFixtures\bin\$(Configuration)\$(DotNetStableTargetFramework)\TestFixtures.dll" />
34+
</ItemGroup>
35+
<Copy SourceFiles="@(_TestFixtureFiles)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
36+
</Target>
37+
38+
</Project>
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using System.Linq;
2+
using Xunit;
3+
4+
namespace Microsoft.Android.Sdk.TrimmableTypeMap.Tests;
5+
6+
public partial class JavaPeerScannerTests
7+
{
8+
[Theory]
9+
[InlineData ("android/app/Activity", "OnCreate", "onCreate", "(Landroid/os/Bundle;)V")]
10+
[InlineData ("android/app/Activity", "OnStart", "onStart", "()V")]
11+
[InlineData ("my/app/MainActivity", "OnCreate", "onCreate", "(Landroid/os/Bundle;)V")]
12+
[InlineData ("my/app/AbstractBase", "DoWork", "doWork", "()V")]
13+
[InlineData ("java/lang/Throwable", "Message", "getMessage", "()Ljava/lang/String;")]
14+
[InlineData ("my/app/TouchHandler", "OnTouch", "onTouch", "(Landroid/view/View;I)Z")]
15+
[InlineData ("my/app/TouchHandler", "OnFocusChange", "onFocusChange", "(Landroid/view/View;Z)V")]
16+
[InlineData ("my/app/TouchHandler", "OnScroll", "onScroll", "(IFJD)V")]
17+
[InlineData ("my/app/TouchHandler", "SetItems", "setItems", "([Ljava/lang/String;)V")]
18+
public void Scan_MarshalMethod_HasCorrectSignature (string javaName, string managedName, string jniName, string jniSig)
19+
{
20+
var peers = ScanFixtures ();
21+
var method = FindByJavaName (peers, javaName)
22+
.MarshalMethods.FirstOrDefault (m => m.ManagedMethodName == managedName || m.JniName == jniName);
23+
Assert.NotNull (method);
24+
Assert.Equal (jniName, method.JniName);
25+
Assert.Equal (jniSig, method.JniSignature);
26+
}
27+
28+
[Fact]
29+
public void Scan_MarshalMethod_ConstructorsAndSpecialCases ()
30+
{
31+
var peers = ScanFixtures ();
32+
33+
var ctors = FindByJavaName (peers, "my/app/CustomView")
34+
.MarshalMethods.Where (m => m.IsConstructor).ToList ();
35+
Assert.Equal (2, ctors.Count);
36+
Assert.Equal ("()V", ctors [0].JniSignature);
37+
Assert.Equal ("(Landroid/content/Context;)V", ctors [1].JniSignature);
38+
39+
Assert.DoesNotContain (FindByJavaName (peers, "my/app/MyHelper").MarshalMethods, m => m.IsConstructor);
40+
41+
var exportMethod = FindByJavaName (peers, "my/app/ExportExample").MarshalMethods.Single ();
42+
Assert.Equal ("myExportedMethod", exportMethod.JniName);
43+
Assert.Null (exportMethod.Connector);
44+
45+
var onStart = FindByJavaName (peers, "android/app/Activity")
46+
.MarshalMethods.FirstOrDefault (m => m.JniName == "onStart");
47+
Assert.NotNull (onStart);
48+
Assert.Equal ("", onStart.Connector);
49+
50+
var onClick = FindByManagedName (peers, "Android.Views.IOnClickListener")
51+
.MarshalMethods.FirstOrDefault (m => m.JniName == "onClick");
52+
Assert.NotNull (onClick);
53+
Assert.Equal ("(Landroid/view/View;)V", onClick.JniSignature);
54+
55+
Assert.Equal ("Android.Views.IOnClickListenerInvoker",
56+
FindByManagedName (peers, "Android.Views.IOnClickListener").InvokerTypeName);
57+
}
58+
59+
[Theory]
60+
[InlineData ("android/app/Activity", "Android.App.Activity")]
61+
[InlineData ("my/app/SimpleActivity", "Android.App.Activity")]
62+
[InlineData ("my/app/MyButton", "MyApp.MyButton")]
63+
public void Scan_ActivationCtor_InheritsFromNearestBase (string javaName, string expectedDeclaringType)
64+
{
65+
var peers = ScanFixtures ();
66+
var peer = FindByJavaName (peers, javaName);
67+
Assert.NotNull (peer.ActivationCtor);
68+
Assert.Equal (expectedDeclaringType, peer.ActivationCtor.DeclaringTypeName);
69+
}
70+
71+
[Theory]
72+
[InlineData ("java/lang/Object", null)]
73+
[InlineData ("android/app/Activity", "java/lang/Object")]
74+
[InlineData ("my/app/MainActivity", "android/app/Activity")]
75+
[InlineData ("java/lang/Throwable", "java/lang/Object")]
76+
[InlineData ("java/lang/Exception", "java/lang/Throwable")]
77+
[InlineData ("my/app/MyButton", "android/widget/Button")]
78+
public void Scan_BaseJavaName_ResolvesCorrectly (string javaName, string? expectedBase)
79+
{
80+
var peers = ScanFixtures ();
81+
Assert.Equal (expectedBase, FindByJavaName (peers, javaName).BaseJavaName);
82+
}
83+
84+
[Fact]
85+
public void Scan_MultipleInterfaces_AllResolved ()
86+
{
87+
var peers = ScanFixtures ();
88+
89+
var multi = FindByJavaName (peers, "my/app/MultiInterfaceView");
90+
Assert.Contains ("android/view/View$OnClickListener", multi.ImplementedInterfaceJavaNames);
91+
Assert.Contains ("android/view/View$OnLongClickListener", multi.ImplementedInterfaceJavaNames);
92+
Assert.Equal (2, multi.ImplementedInterfaceJavaNames.Count);
93+
94+
Assert.Contains ("android/view/View$OnClickListener",
95+
FindByJavaName (peers, "my/app/ClickableView").ImplementedInterfaceJavaNames);
96+
Assert.Empty (FindByJavaName (peers, "my/app/MyHelper").ImplementedInterfaceJavaNames);
97+
}
98+
99+
[Theory]
100+
[InlineData ("android/app/Activity", "android/app/Activity")]
101+
[InlineData ("my/app/MainActivity", "my/app/MainActivity")]
102+
public void Scan_CompatJniName (string javaName, string expectedCompat)
103+
{
104+
var peers = ScanFixtures ();
105+
Assert.Equal (expectedCompat, FindByJavaName (peers, javaName).CompatJniName);
106+
}
107+
108+
[Fact]
109+
public void Scan_CompatJniName_UnregisteredType_UsesRawNamespace ()
110+
{
111+
var peers = ScanFixtures ();
112+
var unregistered = FindByManagedName (peers, "MyApp.UnregisteredHelper");
113+
Assert.StartsWith ("crc64", unregistered.JavaName);
114+
Assert.Equal ("myapp/UnregisteredHelper", unregistered.CompatJniName);
115+
}
116+
117+
[Fact]
118+
public void Scan_CustomJniNameProviderAttribute_UsesNameFromAttribute ()
119+
{
120+
var peers = ScanFixtures ();
121+
Assert.Equal ("com/example/CustomWidget",
122+
FindByManagedName (peers, "MyApp.CustomWidget").JavaName);
123+
}
124+
125+
[Theory]
126+
[InlineData ("my/app/Outer$Inner", "MyApp.Outer+Inner")]
127+
[InlineData ("my/app/ICallback$Result", "MyApp.ICallback+Result")]
128+
public void Scan_NestedType_IsDiscovered (string javaName, string managedName)
129+
{
130+
var peers = ScanFixtures ();
131+
Assert.Equal (managedName, FindByJavaName (peers, javaName).ManagedTypeName);
132+
}
133+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Linq;
2+
using Xunit;
3+
4+
namespace Microsoft.Android.Sdk.TrimmableTypeMap.Tests;
5+
6+
public partial class JavaPeerScannerTests
7+
{
8+
[Fact]
9+
public void Scan_GenericTypes_ResolveViaTypeSpecification ()
10+
{
11+
var peers = ScanFixtures ();
12+
Assert.Equal ("my/app/GenericBase",
13+
FindByJavaName (peers, "my/app/ConcreteFromGeneric").BaseJavaName);
14+
Assert.Contains ("my/app/IGenericCallback",
15+
FindByJavaName (peers, "my/app/GenericCallbackImpl").ImplementedInterfaceJavaNames);
16+
}
17+
18+
[Fact]
19+
public void Scan_ComponentOnlyBase_BothBaseAndDerivedDiscovered ()
20+
{
21+
var peers = ScanFixtures ();
22+
23+
var baseType = FindByJavaName (peers, "my/app/BaseActivityNoRegister");
24+
Assert.True (baseType.IsUnconditional);
25+
Assert.Equal ("android/app/Activity", baseType.BaseJavaName);
26+
27+
var derived = FindByManagedName (peers, "MyApp.DerivedFromComponentBase");
28+
Assert.StartsWith ("crc64", derived.JavaName);
29+
}
30+
31+
[Theory]
32+
[InlineData ("MyApp.RegisteredParent+UnregisteredChild", "my/app/RegisteredParent_UnregisteredChild")]
33+
[InlineData ("MyApp.DeepOuter+Middle+DeepInner", "my/app/DeepOuter_Middle_DeepInner")]
34+
public void Scan_UnregisteredNestedType_UsesParentJniPrefix (string managedName, string expectedJavaName)
35+
{
36+
var peers = ScanFixtures ();
37+
Assert.Equal (expectedJavaName, FindByManagedName (peers, managedName).JavaName);
38+
}
39+
40+
[Fact]
41+
public void Scan_EmptyNamespace_Handled ()
42+
{
43+
var peers = ScanFixtures ();
44+
Assert.Equal ("GlobalType", FindByJavaName (peers, "my/app/GlobalType").ManagedTypeName);
45+
Assert.Equal ("GlobalUnregisteredType",
46+
FindByManagedName (peers, "GlobalUnregisteredType").CompatJniName);
47+
}
48+
49+
[Theory]
50+
[InlineData ("MyApp.PlainActivitySubclass")]
51+
[InlineData ("MyApp.UnnamedActivity")]
52+
[InlineData ("MyApp.UnregisteredClickListener")]
53+
[InlineData ("MyApp.UnregisteredExporter")]
54+
public void Scan_UnregisteredType_DiscoveredWithCrc64Name (string managedName)
55+
{
56+
var peers = ScanFixtures ();
57+
Assert.StartsWith ("crc64", FindByManagedName (peers, managedName).JavaName);
58+
}
59+
60+
[Fact]
61+
public void Scan_ExportOnUnregisteredType_MethodDiscovered ()
62+
{
63+
var peers = ScanFixtures ();
64+
var exportMethod = FindByManagedName (peers, "MyApp.UnregisteredExporter")
65+
.MarshalMethods.FirstOrDefault (m => m.JniName == "doExportedWork");
66+
Assert.NotNull (exportMethod);
67+
Assert.Null (exportMethod.Connector);
68+
}
69+
}

0 commit comments

Comments
 (0)