Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a5fb968
Enable NativeAOT library tests on Apple mobile platforms
kotlarmilos Mar 11, 2026
fe0e141
Update dependencies from https://github.com/dotnet/xharness build 202…
dotnet-maestro[bot] Mar 12, 2026
0a9ea0b
Update dependencies from https://github.com/dotnet/xharness build 202…
dotnet-maestro[bot] Mar 12, 2026
1658ca5
Update dependencies from https://github.com/dotnet/xharness build 202…
dotnet-maestro[bot] Mar 16, 2026
9e2a877
Merge branch 'main' into enable-nativeaot-libs-tests-mobile
kotlarmilos Mar 17, 2026
e9c07fe
Update dependencies from https://github.com/dotnet/xharness build 202…
dotnet-maestro[bot] Mar 17, 2026
10f5e12
Update dependencies from https://github.com/dotnet/xharness build 202…
dotnet-maestro[bot] Mar 18, 2026
98a831a
Merge remote-tracking branch 'upstream/darc-main-98c14788-b6c2-47d8-8…
kotlarmilos Mar 18, 2026
aad2539
Merge branch 'main' into enable-nativeaot-libs-tests-mobile
kotlarmilos Mar 19, 2026
033a027
Merge branch 'main' into enable-nativeaot-libs-tests-mobile
kotlarmilos Mar 23, 2026
a50e76c
Enable iOS/tvOS platforms for builds by removing tracking issue comme…
kotlarmilos Mar 23, 2026
1f56b6c
Replace NativeAOT runtime tests with library tests on Apple mobile pl…
kotlarmilos Mar 23, 2026
c9d4929
Add ILC entrypoint for NativeAOT library tests on Apple mobile
kotlarmilos Mar 24, 2026
9c4acbc
Enable console UI template for NativeAOT library tests on Apple mobile
kotlarmilos Mar 25, 2026
7a7383d
Fix AppleTestRunner test discovery for NativeAOT
kotlarmilos Mar 25, 2026
d291786
Root test and xunit assemblies for NativeAOT library tests on Apple m…
kotlarmilos Mar 26, 2026
d767d8b
Root test assemblies and fix xunit-excludes path for NativeAOT on App…
kotlarmilos Mar 26, 2026
56190af
Handle missing xunit-excludes.txt in NativeAOT app bundle
kotlarmilos Mar 26, 2026
e705108
Update XHarness to 11.0.0-prerelease.26173.1 for NativeAOT test runner
kotlarmilos Mar 26, 2026
743e41e
Merge branch 'main' into enable-nativeaot-libs-tests-mobile
kotlarmilos Mar 26, 2026
c564b39
Merge branch 'main' into enable-nativeaot-libs-tests-mobile
kotlarmilos Mar 27, 2026
faefd4c
Merge branch 'main' into enable-nativeaot-libs-tests-mobile
kotlarmilos Mar 27, 2026
b9b429f
Fix NativeAOT test assembly name passed to xunit discovery
kotlarmilos Mar 30, 2026
277d642
Do not exclude .txt files from NativeAOT app bundles
kotlarmilos Mar 30, 2026
7f89e57
Dispatch open virtual delegates through DelegateInvokeMethod
kotlarmilos Mar 31, 2026
f873316
Revert "Dispatch open virtual delegates through DelegateInvokeMethod"
kotlarmilos Mar 31, 2026
b90781a
Add support for default.rd.xml and adjust trimming settings for Nativ…
kotlarmilos Mar 31, 2026
5dd88e7
Bundle per-test rd.xml files for NativeAOT library tests on Apple mobile
kotlarmilos Mar 31, 2026
04921c9
Add pal_console.c to Native sources for Apple platforms
kotlarmilos Apr 1, 2026
4e2156d
Revert changes
kotlarmilos Apr 1, 2026
e62ec0a
Fix SystemNative_IsATty to handle macOS Catalyst, iOS, and tvOS platf…
kotlarmilos Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 2 additions & 40 deletions eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ jobs:
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ]
jobParameters:
testGroup: innerloop
nameSuffix: AllSubsets_NativeAOT_Smoke
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=true /p:DevTeamProvisioning=- /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true
nameSuffix: AllSubsets_NativeAOT
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:DevTeamProvisioning=- /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

This switches from an explicit RunSmokeTestsOnly=true (previously) to $(_runSmokeTestsOnlyArg), which evaluates to RunSmokeTestsOnly=false in the runtime-ioslike / runtime-extra-platforms pipelines. That materially increases test scope and may exceed the current timeout or intended coverage for this leg. If the intent is still smoke-only NativeAOT validation, set RunSmokeTestsOnly=true explicitly (or update timeout/nameSuffix to reflect running full innerloop).

Suggested change
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:DevTeamProvisioning=- /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=true /p:DevTeamProvisioning=- /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true

Copilot uses AI. Check for mistakes.
timeoutInMinutes: 180
# extra steps, run tests
postBuildSteps:
Expand All @@ -129,44 +129,6 @@ jobs:
testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true

#
# Build the whole product using NativeAOT for iOS/tvOS and run runtime tests with iOS/tvOS devices
#
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
buildConfig: Release
runtimeFlavor: coreclr
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
isiOSLikeOnlyBuild: ${{ parameters.isiOSLikeOnlyBuild }}
platforms:
- ios_arm64
- tvos_arm64
variables:
- name: timeoutPerTestInMinutes
value: 60
- name: timeoutPerTestCollectionInMinutes
value: 180
jobParameters:
testGroup: innerloop
nameSuffix: AllSubsets_NativeAOT_RuntimeTests
timeoutInMinutes: 240
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs -c $(_BuildConfig)
# extra steps, run tests
extraVariablesTemplates:
- template: /eng/pipelines/common/templates/runtimes/test-variables.yml
parameters:
testGroup: innerloop
useNativeAOTRuntime: true
postBuildSteps:
- template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml
parameters:
creator: dotnet-bot
testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true
testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
buildAllTestsAsStandalone: true

#
# Build the whole product using CoreCLR R2R and run runtime tests
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,49 +90,39 @@ jobs:
extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true

#
# Build the whole product using Native AOT for iOSSimulator/tvOSSimulator and run runtime tests with iOS/tvOS simulators
# iOS/tvOS simulators
# Build the whole product using Native AOT and run libraries tests
#
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
buildConfig: Release
runtimeFlavor: coreclr
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
isiOSLikeOnlyBuild: ${{ parameters.isiOSLikeOnlyBuild }}
isiOSLikeSimulatorOnlyBuild: ${{ parameters.isiOSLikeSimulatorOnlyBuild }}
platforms:
Comment on lines 101 to 104
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

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

isiOSLikeOnlyBuild appears to have been renamed to isiOSLikeSimulatorOnlyBuild for this template, but this file still references parameters.isiOSLikeOnlyBuild in other platform-matrix invocations (e.g., the Mono/CoreCLR runtime-test legs). Since isiOSLikeOnlyBuild is no longer declared in this file's parameters: block, those references will either fail template evaluation or silently pass an empty value. Update the remaining ${{ parameters.isiOSLikeOnlyBuild }} usages to ${{ parameters.isiOSLikeSimulatorOnlyBuild }} (or remove the parameter entirely if it’s unused by the downstream templates).

Copilot uses AI. Check for mistakes.
Comment on lines 101 to 104
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

This job now uses isiOSLikeSimulatorOnlyBuild, but the file still has other jobs that reference parameters.isiOSLikeOnlyBuild (e.g., the Mono/CoreCLR runtime-test simulator jobs). Please update those remaining references (or keep an alias parameter) to avoid pipeline template evaluation failures from an undefined parameter.

Copilot uses AI. Check for mistakes.
- iossimulator_x64
- iossimulator_arm64
- tvossimulator_arm64
variables:
- ${{ if and(eq(variables['System.TeamProject'], 'public'), eq(variables['Build.Reason'], 'PullRequest')) }}:
- name: _HelixSource
value: pr/dotnet/runtime/$(Build.SourceBranch)
- ${{ if and(eq(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}:
- name: _HelixSource
value: ci/dotnet/runtime/$(Build.SourceBranch)
- name: timeoutPerTestInMinutes
value: 60
- name: timeoutPerTestCollectionInMinutes
value: 180
# map dependencies variables to local variables
- name: librariesContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
- name: coreclrContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ]
jobParameters:
testGroup: innerloop
nameSuffix: AllSubsets_NativeAOT_RuntimeTests
nameSuffix: AllSubsets_NativeAOT
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true
timeoutInMinutes: 180
Comment on lines 115 to 118
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

$(_runSmokeTestsOnlyArg) expands to /p:RunSmokeTestsOnly=$(isRunSmokeTestsOnly). For the dedicated runtime-ioslikesimulator / runtime-extra-platforms pipelines, isRunSmokeTestsOnly is false (per eng/pipelines/common/variables.yml), so this will run non-smoke library tests. If the intent is to keep this leg smoke-only (as the previous NativeAOT runtime leg effectively was), set RunSmokeTestsOnly=true explicitly or adjust timeouts/naming accordingly.

Copilot uses AI. Check for mistakes.
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs -c $(_BuildConfig)
# extra steps, run tests
extraVariablesTemplates:
- template: /eng/pipelines/common/templates/runtimes/test-variables.yml
parameters:
testGroup: innerloop
useNativeAOTRuntime: true
postBuildSteps:
- template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml
- template: /eng/pipelines/libraries/helix.yml
parameters:
creator: dotnet-bot
testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true
testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
buildAllTestsAsStandalone: true
extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true

#
# Build the whole product using CoreCLR R2R and run runtime tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,13 @@ jobs:
testRunNamePrefixSuffix: Mono_$(_BuildConfig)

#
# Build the whole product using Native AOT and run runtime tests
# MacCatalyst
# Build the whole product using Native AOT and run libraries tests
#
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
buildConfig: Release
runtimeFlavor: coreclr
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
Expand All @@ -144,34 +145,30 @@ jobs:
# map dependencies variables to local variables
- name: librariesContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
- name: monoContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_mono_excluding_wasm.containsChange'] ]
- name: coreclrContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ]
jobParameters:
testGroup: innerloop
nameSuffix: AllSubsets_NativeAOT_RuntimeTests
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs -c $(_BuildConfig)
nameSuffix: AllSubsets_NativeAOT
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:DevTeamProvisioning=adhoc /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

$(_runSmokeTestsOnlyArg) expands to /p:RunSmokeTestsOnly=$(isRunSmokeTestsOnly). In the dedicated runtime-maccatalyst / runtime-extra-platforms pipelines, isRunSmokeTestsOnly is false, so this leg will run non-smoke library tests (potentially much larger than the previous NativeAOT runtime smoke leg). If the intent is smoke-only coverage, set RunSmokeTestsOnly=true explicitly (and similarly for the AppSandbox variant) or adjust timeout/expectations.

Suggested change
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:DevTeamProvisioning=adhoc /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=true /p:DevTeamProvisioning=adhoc /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true

Copilot uses AI. Check for mistakes.
timeoutInMinutes: 180
# extra steps, run tests
extraVariablesTemplates:
- template: /eng/pipelines/common/templates/runtimes/test-variables.yml
parameters:
testGroup: innerloop
useNativeAOTRuntime: true
postBuildSteps:
- template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml
- template: /eng/pipelines/libraries/helix.yml
parameters:
creator: dotnet-bot
buildAllTestsAsStandalone: true
testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true
testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true

#
# Build the whole product using Native AOT with the App Sandbox entitlement and run runtime tests
# MacCatalyst
# Build the whole product using Native AOT and run libraries tests
# The test app is built with the App Sandbox entitlement
#
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
buildConfig: Release
runtimeFlavor: coreclr
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
Expand All @@ -183,26 +180,20 @@ jobs:
# map dependencies variables to local variables
- name: librariesContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
- name: monoContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_mono_excluding_wasm.containsChange'] ]
- name: coreclrContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ]
jobParameters:
testGroup: innerloop
nameSuffix: AllSubsets_NativeAOT_RuntimeTests_AppSandbox
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs -c $(_BuildConfig)
nameSuffix: AllSubsets_NativeAOT_AppSandbox
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:DevTeamProvisioning=adhoc /p:BuildTestsOnHelix=true /p:UseNativeAOTRuntime=true /p:RunAOTCompilation=false /p:ContinuousIntegrationBuild=true /p:EnableAppSandbox=true
timeoutInMinutes: 180
# extra steps, run tests
extraVariablesTemplates:
- template: /eng/pipelines/common/templates/runtimes/test-variables.yml
parameters:
testGroup: innerloop
useNativeAOTRuntime: true
postBuildSteps:
- template: /eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml
- template: /eng/pipelines/libraries/helix.yml
parameters:
creator: dotnet-bot
buildAllTestsAsStandalone: true
testBuildArgs: tree nativeaot/MobileSmokeTest /p:BuildNativeAOTRuntimePack=true /p:DevTeamProvisioning=adhoc /p:EnableAppSandbox=true
testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
extraHelixArguments: /p:NeedsToBuildAppsOnHelix=true

#
# Build the whole product using CoreCLR R2R and run runtime tests
Expand Down
11 changes: 11 additions & 0 deletions eng/testing/tests.ioslike.targets
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@
<Copy SourceFiles="@(BundleFiles)" DestinationFolder="$(BundleDir)%(TargetDir)" />
<Copy SourceFiles="@(ExtraFiles)" DestinationFolder="$(BundleDir)\%(TargetDir)" />

<!-- For NativeAOT library tests, bundle both the shared rd.xml (xunit generic
instantiations) and any per-test rd.xml files declared in the test csproj.
The shared file is renamed to common.rd.xml to avoid overwriting a per-test
default.rd.xml; ProxyProjectForAOTOnHelix.proj globs *.rd.xml to pick up both. -->
<Copy Condition="'$(UseNativeAOTRuntime)' == 'true'"
SourceFiles="$(MSBuildThisFileDirectory)default.rd.xml"
DestinationFiles="$(BundleDir)publish/common.rd.xml" />
<Copy Condition="'$(UseNativeAOTRuntime)' == 'true' and '@(RdXmlFile)' != ''"
SourceFiles="@(RdXmlFile)"
DestinationFolder="$(BundleDir)publish" />

<!-- Only publish artifacts minus runtime pack assets (move to dotnet build later as opposed to publish)-->
<ItemGroup Condition="'$(UsePortableRuntimePack)' == 'true'">
<_PublishBundleFiles Include="@(BundleFiles->'$(AppBundlePath)/%(FileName)%(Extension)')" />
Expand Down
60 changes: 54 additions & 6 deletions src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class SimpleTestRunner : iOSApplicationEntryPoint, IDevice
public extern static void mono_ios_set_summary (string value);

private static List<string> s_testLibs = new List<string>();
private static List<Assembly>? s_testAssemblies;
private static string? s_MainTestName;

public static async Task<int> Main(string[] args)
Expand All @@ -45,13 +46,41 @@ public static async Task<int> Main(string[] args)

if (s_testLibs.Count < 1)
{
// Look for *.Tests.dll files if target test suites are not set via "testlib:" arguments
s_testLibs = Directory.GetFiles(Environment.CurrentDirectory, "*.Tests.dll").ToList();
if (!RuntimeFeature.IsDynamicCodeSupported)
{
// NativeAOT: test assemblies are statically linked into the native binary,
// so there are no DLL files on disk. Discover them from loaded assemblies.
Console.WriteLine("NativeAOT mode: discovering test assemblies from loaded assemblies.");
Assembly[] allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
Console.WriteLine($"Loaded assemblies ({allAssemblies.Length}):");
foreach (Assembly a in allAssemblies)
{
Console.WriteLine($" {a.GetName().Name}");
}
Comment on lines +55 to +59
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

The runner prints the full list of loaded assemblies unconditionally in the new NativeAOT path. This can create very large logs in CI/device runs and make failures harder to triage. Consider gating this behind --verbose (or a dedicated flag) and keep the default output to a short summary.

Suggested change
Console.WriteLine($"Loaded assemblies ({allAssemblies.Length}):");
foreach (Assembly a in allAssemblies)
{
Console.WriteLine($" {a.GetName().Name}");
}
if (verbose)
{
Console.WriteLine($"Loaded assemblies ({allAssemblies.Length}):");
foreach (Assembly a in allAssemblies)
{
Console.WriteLine($" {a.GetName().Name}");
}
}
else
{
Console.WriteLine($"Discovered {allAssemblies.Length} loaded assemblies.");
}

Copilot uses AI. Check for mistakes.

s_testAssemblies = allAssemblies
.Where(a => a.GetName().Name?.EndsWith(".Tests") == true)
.ToList();
s_testLibs = s_testAssemblies.Select(a => a.GetName().Name!).ToList();
}
Comment on lines +49 to +65
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

Using RuntimeFeature.IsDynamicCodeSupported to detect NativeAOT is unreliable on Apple platforms (it can be false for non-NativeAOT AOT/interpreter scenarios too). This can cause the runner to skip the on-disk *.Tests.dll discovery and then fail to find/load tests. Consider detecting NativeAOT by first checking for any *.Tests.dll files on disk and only falling back to assembly-based loading when none exist (or attempt Assembly.Load for discovered/arg-specified assemblies).

Copilot uses AI. Check for mistakes.
else
{
// Look for *.Tests.dll files if target test suites are not set via "testlib:" arguments
s_testLibs = Directory.GetFiles(Environment.CurrentDirectory, "*.Tests.dll").ToList();
}
Comment on lines +49 to +70
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

RuntimeFeature.IsDynamicCodeSupported is not a reliable way to detect “NativeAOT mode” here (it will also be false for other AOT configurations). In those cases this branch skips the on-disk *.Tests.dll discovery and may fail to find any tests because the assemblies are not yet loaded. Consider attempting file-based discovery first (as before) and only falling back to reflection-based discovery when no *.Tests.dll files are present; for the fallback, prefer loading candidate assemblies (e.g., from referenced assemblies) rather than relying on AppDomain.CurrentDomain.GetAssemblies() alone.

Copilot uses AI. Check for mistakes.
}

if (s_testLibs.Count < 1)
{
Console.WriteLine($"Test libs were not found (*.Tests.dll was not found in {Environment.CurrentDirectory})");
if (!RuntimeFeature.IsDynamicCodeSupported)
{
Console.WriteLine("No assemblies ending with '.Tests' were found among loaded assemblies.");
}
else
{
Console.WriteLine($"Test libs were not found (*.Tests.dll was not found in {Environment.CurrentDirectory})");
}

return -1;
}

Expand Down Expand Up @@ -110,9 +139,19 @@ public SimpleTestRunner(bool verbose)

protected override IEnumerable<TestAssemblyInfo> GetTestAssemblies()
{
foreach (string file in s_testLibs)
if (s_testAssemblies is not null)
{
foreach (Assembly assembly in s_testAssemblies)
{
yield return new TestAssemblyInfo(assembly, assembly.GetName().Name! + ".dll");
}
}
else
{
yield return new TestAssemblyInfo(Assembly.LoadFrom(file), file);
foreach (string file in s_testLibs)
{
yield return new TestAssemblyInfo(Assembly.LoadFrom(file), file);
}
Comment on lines +151 to +154
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

In NativeAOT runs (RuntimeFeature.IsDynamicCodeSupported == false), s_testLibs values coming from testlib: args will still be processed via Assembly.LoadFrom(file), but NativeAOT test assemblies are not present as .dll files on disk. This will throw and prevents running a selected subset of tests.

Consider handling the NativeAOT case here by resolving each s_testLibs entry to an already-loaded Assembly (by simple-name match) or by calling Assembly.Load(new AssemblyName(simpleName)) and yielding TestAssemblyInfo from that, instead of LoadFrom.

Suggested change
foreach (string file in s_testLibs)
{
yield return new TestAssemblyInfo(Assembly.LoadFrom(file), file);
}
if (!RuntimeFeature.IsDynamicCodeSupported)
{
foreach (string file in s_testLibs)
{
string simpleName = Path.GetFileNameWithoutExtension(file);
Assembly? assembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => string.Equals(a.GetName().Name, simpleName, StringComparison.OrdinalIgnoreCase));
if (assembly is null)
{
try
{
assembly = Assembly.Load(new AssemblyName(simpleName));
}
catch (Exception ex)
{
throw new InvalidOperationException($"Could not load test assembly '{simpleName}' in a NativeAOT environment.", ex);
}
}
yield return new TestAssemblyInfo(assembly, file);
}
}
else
{
foreach (string file in s_testLibs)
{
yield return new TestAssemblyInfo(Assembly.LoadFrom(file), file);
}
}

Copilot uses AI. Check for mistakes.
}
}

Expand All @@ -129,7 +168,16 @@ protected override void TerminateWithSuccess()

protected override string? IgnoreFilesDirectory => null;

protected override string IgnoredTraitsFilePath => "xunit-excludes.txt";
// NativeAOT excludes .txt files from the app bundle (Xcode.cs predefinedExcludes),
// so xunit-excludes.txt may not be present. Return empty string to skip trait filtering.
Comment on lines +171 to +172
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This comment says NativeAOT excludes .txt files via Xcode.cs predefinedExcludes, but that exclusion was removed in this PR. The code’s behavior (skip trait filtering if the file isn’t present) still makes sense, but the comment should be updated to reflect the current reason (e.g., the file may be absent depending on how the app bundle is produced), without referencing a .txt exclusion that no longer exists.

Suggested change
// NativeAOT excludes .txt files from the app bundle (Xcode.cs predefinedExcludes),
// so xunit-excludes.txt may not be present. Return empty string to skip trait filtering.
// The xunit-excludes.txt file may not be present in the app bundle, depending on how the
// application is built and packaged. Return an empty string when it's missing to skip trait filtering.

Copilot uses AI. Check for mistakes.
protected override string IgnoredTraitsFilePath
{
get
{
string path = Path.Combine(AppContext.BaseDirectory, "xunit-excludes.txt");
return File.Exists(path) ? path : string.Empty;
Comment on lines +171 to +178
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

Returning string.Empty here effectively disables xUnit trait exclusion when xunit-excludes.txt is missing. Given the file is intentionally generated during test bundling, skipping exclusions may cause known-bad traits/tests to run under NativeAOT. Consider addressing this by ensuring xunit-excludes.txt is included in the NativeAOT app bundle (or passing the excludes via args/env) rather than bypassing trait filtering.

Suggested change
// NativeAOT excludes .txt files from the app bundle (Xcode.cs predefinedExcludes),
// so xunit-excludes.txt may not be present. Return empty string to skip trait filtering.
protected override string IgnoredTraitsFilePath
{
get
{
string path = Path.Combine(AppContext.BaseDirectory, "xunit-excludes.txt");
return File.Exists(path) ? path : string.Empty;
// NativeAOT may exclude .txt files from the app bundle (Xcode.cs predefinedExcludes),
// which can cause xunit-excludes.txt to be missing. Use an environment variable override
// if provided, otherwise fall back to the bundle path. If no excludes file is found,
// return the expected bundle path and log a warning so trait filtering is not silently
// disabled and bundling/configuration issues are visible.
protected override string IgnoredTraitsFilePath
{
get
{
const string excludesFileName = "xunit-excludes.txt";
const string excludesEnvVarName = "XUNIT_EXCLUDES_FILE";
string? envPath = Environment.GetEnvironmentVariable(excludesEnvVarName);
if (envPath is not null && envPath.Length > 0 && File.Exists(envPath))
{
return envPath;
}
string bundlePath = Path.Combine(AppContext.BaseDirectory, excludesFileName);
if (File.Exists(bundlePath))
{
return bundlePath;
}
Console.Error.WriteLine($"[AppleTestRunner] Warning: xUnit excludes file '{bundlePath}' was not found. " +
$"Set the '{excludesEnvVarName}' environment variable to a valid file path or " +
"ensure the file is included in the app bundle to enable trait filtering.");
return bundlePath;

Copilot uses AI. Check for mistakes.
}
}

public string BundleIdentifier => "net.dot." + s_MainTestName;

Expand Down
1 change: 1 addition & 0 deletions src/libraries/tests.proj
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@

<ItemGroup>
<SmokeTestProject Condition="'$(UseNativeAOTRuntime)' != 'true'" Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Runtime.Tests\System.Runtime.Tests.csproj" />
<SmokeTestProject Condition="'$(TargetsAppleMobile)' == 'true' and '$(UseNativeAOTRuntime)' == 'true'" Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Runtime.Tests\System.Runtime.Tests.csproj" />
</ItemGroup>

<!-- browser smoke tests Mono -->
Expand Down
1 change: 1 addition & 0 deletions src/mono/msbuild/apple/build/AppleBuild.targets
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
<_AppleRuntimeConfigFilePath Condition="'$(_AppleRuntimeConfigFilePath)' == ''">$([MSBuild]::NormalizePath($(AppleBuildDir), '$(AssemblyName).runtimeconfig.json'))</_AppleRuntimeConfigFilePath>
<_ParsedRuntimeConfigFilePath Condition="'$(_ParsedRuntimeConfigFilePath)' == ''">$([MSBuild]::NormalizePath($(AppleBuildDir), 'runtimeconfig.bin'))</_ParsedRuntimeConfigFilePath>
<UseConsoleUITemplate Condition="'$(UseConsoleUITemplate)' == '' and '$(UseNativeAOTRuntime)' != 'true'">true</UseConsoleUITemplate>
<UseConsoleUITemplate Condition="'$(UseConsoleUITemplate)' == '' and '$(UseNativeAOTRuntime)' == 'true' and '$(IncludesTestRunner)' == 'true'">true</UseConsoleUITemplate>
</PropertyGroup>

<RemoveDir Directories="$(AppleBundleDir)" />
Expand Down
Loading
Loading