[TrimmableTypeMap] Add integration tests for generator-consumed scanner fields
Part of #10789
Context
PR #10827 added integration tests that validate the new JavaPeerScanner (SRM-based) against the legacy Cecil-based scanner. These tests cover the fields that overlap between the two scanners: JavaName, BaseJavaName, ImplementedInterfaces, MarshalMethods, ActivationCtors, and type flags (IsInterface, IsAbstract, IsGenericDefinition, DoNotGenerateAcw).
However, PR #10808 introduced the Generator pipeline (ModelBuilder → TypeMapAssemblyEmitter) which consumes several JavaPeerInfo fields that are new concepts with no legacy equivalent. These fields cannot be validated via legacy-vs-new comparison and need standalone correctness tests.
Fields not covered by integration tests
| Field |
Used by |
Risk if wrong |
IsUnconditional |
ModelBuilder.IsUnconditionalEntry() — determines 2-arg (unconditional) vs 3-arg (trimmable) TypeMap attribute |
Wrong trimming behavior — types could be incorrectly trimmed or unnecessarily preserved |
InvokerTypeName |
ModelBuilder.BuildProxyType() — proxy generation for interfaces/abstract types |
Missing invoker = runtime MissingMethodException when activating interface wrappers |
CompatJniName |
AcwMapWriter — backward-compatible ACW name for acw-map.txt |
Broken debugging, profiling, or tooling that relies on acw-map.txt |
MarshalMethods.ManagedMethodName |
Future UCO wrapper generation |
Low risk now, but incorrect values would cause wrong method dispatch |
Proposed tests
1. IsUnconditional_ComponentTypes
Scan UserTypesFixture.dll:
- Types with
[Activity], [Service], [BroadcastReceiver], [ContentProvider] → IsUnconditional = true
- Plain Java peer types without component attributes →
IsUnconditional = false
- Types referenced by
[Application(BackupAgent=typeof(X))] → forced unconditional via cross-reference
2. IsUnconditional_MonoAndroid
Scan Mono.Android.dll:
- All MCW binding types have
DoNotGenerateAcw=true and should not be marked unconditional
- Sanity check: count of unconditional types = 0
3. InvokerTypeName_InterfacesAndAbstractTypes
Scan Mono.Android.dll:
- Every type with
IsInterface = true should have a non-null InvokerTypeName
- The referenced invoker type should actually exist in the scanned assemblies
- Validate resolution via
[Register] connector (primary) and {TypeName}Invoker convention (fallback)
4. InvokerTypeName_UserTypes
Scan UserTypesFixture.dll:
- Concrete user types →
InvokerTypeName = null
- User-defined interfaces (if present) → invoker resolved correctly
5. CompatJniName_UserTypes
Scan UserTypesFixture.dll:
- Verify
CompatJniName uses lowercased raw namespace format
- E.g.,
MyApp.Namespace.MyType → myapp.namespace/MyType
6. ManagedMethodName_MarshalMethods
Scan Mono.Android.dll:
- Every
MarshalMethodInfo has non-null, non-empty ManagedMethodName
- Spot-check known types (e.g.,
Android.App.Activity has OnCreate method)
Notes
- These tests should live in
tests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/
- Unlike the existing comparison tests, these are standalone correctness tests — they validate the new scanner's output against known expectations, not against the legacy scanner
- The
UserTypesFixture may need additional types (e.g., user-defined interfaces, [Application] with BackupAgent) to exercise all paths
[TrimmableTypeMap] Add integration tests for generator-consumed scanner fields
Part of #10789
Context
PR #10827 added integration tests that validate the new
JavaPeerScanner(SRM-based) against the legacy Cecil-based scanner. These tests cover the fields that overlap between the two scanners:JavaName,BaseJavaName,ImplementedInterfaces,MarshalMethods,ActivationCtors, and type flags (IsInterface,IsAbstract,IsGenericDefinition,DoNotGenerateAcw).However, PR #10808 introduced the Generator pipeline (
ModelBuilder→TypeMapAssemblyEmitter) which consumes severalJavaPeerInfofields that are new concepts with no legacy equivalent. These fields cannot be validated via legacy-vs-new comparison and need standalone correctness tests.Fields not covered by integration tests
IsUnconditionalModelBuilder.IsUnconditionalEntry()— determines 2-arg (unconditional) vs 3-arg (trimmable) TypeMap attributeInvokerTypeNameModelBuilder.BuildProxyType()— proxy generation for interfaces/abstract typesMissingMethodExceptionwhen activating interface wrappersCompatJniNameAcwMapWriter— backward-compatible ACW name foracw-map.txtacw-map.txtMarshalMethods.ManagedMethodNameProposed tests
1.
IsUnconditional_ComponentTypesScan
UserTypesFixture.dll:[Activity],[Service],[BroadcastReceiver],[ContentProvider]→IsUnconditional = trueIsUnconditional = false[Application(BackupAgent=typeof(X))]→ forced unconditional via cross-reference2.
IsUnconditional_MonoAndroidScan
Mono.Android.dll:DoNotGenerateAcw=trueand should not be marked unconditional3.
InvokerTypeName_InterfacesAndAbstractTypesScan
Mono.Android.dll:IsInterface = trueshould have a non-nullInvokerTypeName[Register]connector (primary) and{TypeName}Invokerconvention (fallback)4.
InvokerTypeName_UserTypesScan
UserTypesFixture.dll:InvokerTypeName = null5.
CompatJniName_UserTypesScan
UserTypesFixture.dll:CompatJniNameuses lowercased raw namespace formatMyApp.Namespace.MyType→myapp.namespace/MyType6.
ManagedMethodName_MarshalMethodsScan
Mono.Android.dll:MarshalMethodInfohas non-null, non-emptyManagedMethodNameAndroid.App.ActivityhasOnCreatemethod)Notes
tests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/UserTypesFixturemay need additional types (e.g., user-defined interfaces,[Application]withBackupAgent) to exercise all paths