Skip to content

[TrimmableTypeMap] Scanner unit tests#10813

Open
simonrozsival wants to merge 4 commits intodotnet:mainfrom
simonrozsival:dev/simonrozsival/ttm-slice-core-unit
Open

[TrimmableTypeMap] Scanner unit tests#10813
simonrozsival wants to merge 4 commits intodotnet:mainfrom
simonrozsival:dev/simonrozsival/ttm-slice-core-unit

Conversation

@simonrozsival
Copy link
Member

@simonrozsival simonrozsival commented Feb 13, 2026

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.

Review guide

Three commits — review in order:

  1. Test fixtures + foundational — start here for the test type catalog
  2. Behavior + contracts — the main test surface
  3. Edge cases — regression coverage

@simonrozsival simonrozsival changed the title [TrimmableTypeMap][Slice] Scanner core + unit tests [TrimmableTypeMap] Scanner core and unit tests Feb 14, 2026
@simonrozsival simonrozsival changed the base branch from main to dev/simonrozsival/ttm-core-c-scanner-only February 14, 2026 00:20
@simonrozsival simonrozsival changed the title [TrimmableTypeMap] Scanner core and unit tests [TrimmableTypeMap] Scanner unit tests Feb 14, 2026
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from e2affc3 to 3c806bb Compare February 14, 2026 00:22
@simonrozsival simonrozsival changed the base branch from dev/simonrozsival/ttm-core-c-scanner-only to dev/simonrozsival/ttm-core-c-scanner February 14, 2026 00:23
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from ec29e03 to 5dc8a66 Compare February 14, 2026 00:30
@simonrozsival simonrozsival changed the title [TrimmableTypeMap] Scanner unit tests [TrimmableTypeMap] Scanner unit tests: foundational coverage Feb 14, 2026
@simonrozsival simonrozsival added copilot `copilot-cli` or other AIs were used to author this trimmable-type-map Area: CoreCLR Issues that only occur when using CoreCLR. Area: NativeAOT Issues that only occur when using NativeAOT. labels Feb 14, 2026
@simonrozsival simonrozsival changed the base branch from dev/simonrozsival/ttm-core-c-scanner to dev/simonrozsival/java-peer-scanner-core February 16, 2026 15:25
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from 5dc8a66 to 85634c7 Compare February 16, 2026 15:26
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/java-peer-scanner-core branch from b6895af to cf78bbe Compare February 16, 2026 15:31
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch 2 times, most recently from f25894f to 55aa377 Compare February 16, 2026 15:33
@simonrozsival simonrozsival changed the title [TrimmableTypeMap] Scanner unit tests: foundational coverage [TrimmableTypeMap] Scanner unit tests Feb 16, 2026
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from 55aa377 to 40043e8 Compare February 16, 2026 15:44
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/java-peer-scanner-core branch from cf78bbe to 8cd798b Compare February 16, 2026 16:57
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch 5 times, most recently from fd452b2 to 1ba6f56 Compare February 16, 2026 20:05
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/java-peer-scanner-core branch from 8cd798b to 4dc7fc6 Compare February 16, 2026 20:50
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from 1ba6f56 to 54d4d99 Compare February 16, 2026 20:50
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/java-peer-scanner-core branch from 4dc7fc6 to 1520328 Compare February 16, 2026 20:53
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from 54d4d99 to c3aa816 Compare February 16, 2026 20:53
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/java-peer-scanner-core branch from 1520328 to 265b874 Compare February 16, 2026 20:54
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from c3aa816 to b52694c Compare February 16, 2026 20:54
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/java-peer-scanner-core branch from 265b874 to e709c94 Compare February 16, 2026 21:04
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from b52694c to 3b6b95f Compare February 16, 2026 21:04
jonathanpeppers pushed a commit that referenced this pull request Feb 18, 2026
Sliced from #10805. Adds the core scanner pipeline for the TrimmableTypeMap feature — the component that reads .NET assemblies and discovers all Java peer types using `System.Reflection.Metadata`.

## What this PR adds

New `Microsoft.Android.Sdk.TrimmableTypeMap` project (`netstandard2.0`, ~1500 lines) with three logical layers:

### 1. Data model and metadata type providers
> `Scanner/JavaPeerInfo.cs`, `Scanner/SignatureTypeProvider.cs`, `Scanner/CustomAttributeTypeProvider.cs`

- **`JavaPeerInfo`** record — represents a discovered Java peer with its JNI name, marshal methods, activation constructor info, and component attributes
- **`SignatureTypeProvider`** — decodes method signatures to extract parameter types (needed for marshal method and activation constructor matching)
- **`CustomAttributeTypeProvider`** — decodes `[Register]`, `[Export]`, `[Activity]` etc. attribute blobs; includes a lazy enum type cache and correct nested type resolution

### 2. AssemblyIndex — per-assembly metadata indexer
> `Scanner/AssemblyIndex.cs`

First phase of the pipeline. Reads a single assembly and builds an index of:
- `[Register]`/`[Export]` attributes on types and methods → `RegisterInfo`/`ExportInfo` records
- Component attributes (`[Activity]`, `[Service]`, `[BroadcastReceiver]`, `[ContentProvider]`) with their JNI name properties
- Type definition → Java peer registration mapping

Designed for per-assembly parallelism — each assembly gets its own index.

### 3. JavaPeerScanner — execution logic
> `Scanner/JavaPeerScanner.cs`

Second phase. Consumes all `AssemblyIndex` results and produces the final `JavaPeerInfo` list:
- Resolves inheritance chains across assemblies to find the nearest registered Java ancestor
- Detects activation constructors (`IntPtr` + `JniHandleOwnership`)
- Collects marshal methods and exported methods with JNI signatures
- Merges component attribute metadata and resolves JNI names
- Flags types for unconditional preservation when component attributes specify non-default JNI names

Pure function: assemblies in → peer info out, no side effects.

## Review guide

Three commits, one per layer — review in order:
1. **Data model and metadata type providers** — start here for the type system
2. **AssemblyIndex** — the per-assembly indexing phase
3. **JavaPeerScanner** — the cross-assembly resolution phase

Scanner unit tests follow in #10813.
simonrozsival and others added 4 commits February 18, 2026 16:56
Add test infrastructure for the Java peer scanner:

- TestFixtures project with stub Mono.Android attributes ([Register],
  [Activity], [Service], etc.) and test types covering MCW bindings,
  user types, generics, nested types, interfaces, and component types
- JavaPeerScannerTests with test helpers (ScanFixtures, FindByJavaName)
  and foundational assertions: type discovery, DoNotGenerateAcw flags,
  component unconditional marking, interface/abstract/generic metadata

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Test marshal method collection, JNI signature decoding, activation
constructor resolution, base type chain walking, interface resolution,
compat JNI names, and component attribute metadata merging.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover generic base/interface type specification resolution, component-
only base detection, unregistered nested type naming, deep nesting,
empty namespace types, plain subclass CRC64 naming, and unregistered
types with interfaces or [Export] methods.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add TrimmableTypeMap, TrimmableTypeMap.Tests, and TestFixtures projects
to Xamarin.Android.sln. Add CI step to run scanner unit tests and
publish results on the Windows build pipeline.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/ttm-slice-core-unit branch from 3b6b95f to f1a2847 Compare February 18, 2026 15:56
@simonrozsival simonrozsival changed the base branch from dev/simonrozsival/java-peer-scanner-core to main February 18, 2026 15:56
@simonrozsival simonrozsival marked this pull request as ready for review February 18, 2026 16:04
Copilot AI review requested due to automatic review settings February 18, 2026 16:04
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive unit test coverage for the Java peer scanner component of the TrimmableTypeMap feature, which was introduced in #10823. The tests validate the scanner's ability to discover and analyze Java peer types from .NET assemblies using System.Reflection.Metadata.

Changes:

  • Added new xUnit-based test project with ~300 lines of test code across three test files
  • Created standalone TestFixtures project with stub Android attributes and ~340 lines of representative test types
  • Integrated tests into Windows CI pipeline with proper test result publishing

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj New test project using xUnit, references TrimmableTypeMap project and TestFixtures DLL
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/TestFixtures.csproj Standalone fixture assembly targeting DotNetStableTargetFramework with stub attributes and test types
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/StubAttributes.cs Stub implementations of Android attributes (Register, Activity, Service, Export, etc.) for test isolation
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/TestTypes.cs Comprehensive catalog of test types: MCW bindings, user types with components, generics, nested types, interfaces, edge cases
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/JavaPeerScannerTests.cs Foundational tests: peer discovery, DoNotGenerateAcw flags, component unconditional marking, type metadata
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/JavaPeerScannerTests.Behavior.cs Behavior tests: marshal methods, JNI signatures, activation constructors, inheritance, interface resolution, compat names
tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/JavaPeerScannerTests.EdgeCases.cs Edge case tests: generic TypeSpecification resolution, component-only bases, unregistered nested types, deep nesting, empty namespaces
src/Microsoft.Android.Sdk.TrimmableTypeMap/Microsoft.Android.Sdk.TrimmableTypeMap.csproj Added InternalsVisibleTo for test assembly access
build-tools/automation/yaml-templates/build-windows-steps.yaml Added test execution and result publishing steps for new test project
Xamarin.Android.sln Added three new projects to solution: TrimmableTypeMap, TrimmableTypeMap.Tests, TestFixtures

@simonrozsival
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Member

@jonathanpeppers jonathanpeppers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a test failure in the new test project:

  Failed Microsoft.Android.Sdk.TrimmableTypeMap.Tests.JavaPeerScannerTests.Scan_CustomJniNameProviderAttribute_UsesNameFromAttribute [4 ms]
  Error Message:
   Assert.Equal() Failure: Strings differ
            ↓ (pos 1)
Expected: "com/example/CustomWidget"
Actual:   "crc64eb3df85c64aa1af6/CustomWidget"
            ↑ (pos 1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: CoreCLR Issues that only occur when using CoreCLR. Area: NativeAOT Issues that only occur when using NativeAOT. copilot `copilot-cli` or other AIs were used to author this trimmable-type-map

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments