Skip to content

Handle empty Assembly.Location on Android CoreCLR#7772

Merged
Evangelink merged 2 commits intomainfrom
fix/7769-empty-assembly-location
Apr 23, 2026
Merged

Handle empty Assembly.Location on Android CoreCLR#7772
Evangelink merged 2 commits intomainfrom
fix/7769-empty-assembly-location

Conversation

@nohwnd
Copy link
Copy Markdown
Member

@nohwnd nohwnd commented Apr 22, 2026

Assembly.Location is empty on Android CoreCLR (assemblies are memory-mapped), which makes AreValidSources throw NotSupportedException because empty string is neither .dll nor .exe.

Fall back to <AssemblyName>.dll when Location is empty. Works on .NET Core because FileOperations.DoesFileExist always returns true there, and FileOperations.LoadAssembly loads by name, not by path — so the already-loaded assembly is found.

Added tests for empty / null Location, null name, a real dynamic in-memory assembly, and a file-backed one.

Fixes #7769

Copilot AI review requested due to automatic review settings April 22, 2026 08:51
Copy link
Copy Markdown
Contributor

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 addresses a runtime-specific issue in the VSTest bridge where Assembly.Location can be an empty string (notably on Android CoreCLR with memory-mapped assemblies), which previously caused MSTest discovery/execution to fail due to source extension validation.

Changes:

  • Updated VSTest bridge assembly source collection to use a helper that tolerates empty Assembly.Location.
  • Added GetAssemblyPath(Assembly) fallback logic to synthesize a “.dll” path from the assembly name when Location is empty.
  • Added unit tests covering non-empty, empty, null Location, missing assembly name, dynamic in-memory assemblies, and real file-backed assemblies.

Reviewed changes

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

File Description
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs Uses GetAssemblyPath instead of Assembly.Location directly, and introduces the fallback helper.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/SynchronizedSingleSessionVSTestBridgedTestFrameworkTests.cs Adds coverage for the new GetAssemblyPath behavior across key scenarios.

@nohwnd nohwnd force-pushed the fix/7769-empty-assembly-location branch from 91a6af0 to 82b4b0b Compare April 22, 2026 09:30
When Assembly.Location returns empty string (e.g. on Android CoreCLR where
assemblies are memory-mapped), fall back to using the assembly name with a
.dll extension as a synthetic path. This allows AreValidSources validation
to pass and downstream Assembly.Load by name to find the already-loaded
assembly.

Fixes #7769

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nohwnd nohwnd force-pushed the fix/7769-empty-assembly-location branch from 82b4b0b to a831875 Compare April 22, 2026 09:31
Copilot AI review requested due to automatic review settings April 22, 2026 09:31
Copy link
Copy Markdown
Contributor

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

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

Copy link
Copy Markdown
Member

@simonrozsival simonrozsival left a comment

Choose a reason for hiding this comment

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

This change will unblock us in dotnet/android

Copy link
Copy Markdown
Member

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

Looks good! The fix correctly solves the reported issue with minimal risk. The synthetic path approach works because on .NET Core, FileOperations.DoesFileExist always returns true and FileOperations.LoadAssembly resolves by assembly name (not file path), so the synthetic name.dll path is just a token to pass AreValidSources validation.

A few minor suggestions below — none are blocking.

Summary of suggestions:

  1. Remove the now-redundant #pragma warning disable IL3000 at the call site — the pragma has moved into GetAssemblyPath, so the outer pragma is no longer needed.
  2. Use method group Select(GetAssemblyPath) instead of Select(x => GetAssemblyPath(x)).
  3. Narrow the pragma scope inside GetAssemblyPath to just the assembly.Location line.
  4. The hardcoded .dll extension is fine for the Android CoreCLR scenario (test assemblies are always DLLs there), but a brief comment documenting this assumption would be helpful for future readers.

Co-authored-by: Amaury Levé <amauryleve@microsoft.com>
Copilot AI review requested due to automatic review settings April 23, 2026 10:30
Copy link
Copy Markdown
Contributor

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.

Copilot's findings

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Extensions.VSTestBridge/SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.cs:192

  • GetAssemblyPath currently has nested IL3000 suppressions (one wrapping the whole method and another around assembly.Location). This is redundant and broadens the suppression scope more than needed. Consider keeping a single suppression scoped as narrowly as possible (e.g., only around the assembly.Location access).
#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
    internal static string GetAssemblyPath(Assembly assembly)
    {
#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file
        string location = assembly.Location;
#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file
  • Files reviewed: 2/2 changed files
  • Comments generated: 2

@Evangelink Evangelink merged commit 930b6bd into main Apr 23, 2026
14 checks passed
@Evangelink Evangelink deleted the fix/7769-empty-assembly-location branch April 23, 2026 11:34
Evangelink pushed a commit that referenced this pull request Apr 24, 2026
Continuation of #7772.

On .NET for Android, `Assembly.Location` returns a relative path
like `"AndroidTest1.dll"` (MonoVM) or an empty string (CoreCLR).
`Path.GetDirectoryName` returns `""` for these inputs, and then
`Directory.CreateDirectory("")` throws `ArgumentException`.

This would fail in Release mode on Android, or if the "fast
deployment" feature is disabled.

Guard against empty/relative paths by checking the result of
`Path.GetDirectoryName` and falling back to the standard
`RootDeploymentDirectory/Out` path.

Full stack trace from AZDO build
(https://dev.azure.com/dnceng-public/public/_build/results?buildId=1392743):

    INSTRUMENTATION_RESULT: error=System.ArgumentException: The value cannot be an empty string. (Parameter 'path')
     at System.ArgumentException.ThrowNullOrEmptyException(String argument, String paramName)
     at System.ArgumentException.ThrowIfNullOrEmpty(String argument, String paramName)
     at System.IO.Directory.CreateDirectory(String path)
     at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities.FileUtility.CreateDirectoryIfNotExists(String directory)
     at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Utilities.DeploymentUtilityBase.CreateDeploymentDirectories(IRunContext runContext, String firstTestSource)
     at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.TestDeployment.Deploy(IEnumerable`1 testCases, IRunContext runContext, IFrameworkHandle frameworkHandle, ITestSourceHandler testSourceHandler, TestRunCancellationToken cancellationToken)
     at Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.MSTestExecutor.RunTestsAsync(...)
     at Microsoft.VisualStudio.TestTools.UnitTesting.MSTestBridgedTestFramework.SynchronizedRunTestsAsync(...)
     at Microsoft.Testing.Extensions.VSTestBridge.SynchronizedSingleSessionVSTestBridgedTestFramework.ExecuteRequestAsync(...)
     at Microsoft.Testing.Platform.Builder.TestApplication.RunAsync()
     at DotNetNewAndroidTestMonoVM.TestInstrumentation.<OnStart>b__2_0()
    INSTRUMENTATION_CODE: 0

Related: dotnet/android#11195, #7769

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MSTest throws NotSupportedException when Assembly.Location returns empty string (Android CoreCLR)

4 participants