From c3284544e810b1c6abea52a84633b0e8b4f5e51e Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Wed, 19 Aug 2020 00:40:16 -0700 Subject: [PATCH 1/5] Return host's path when using GetCommandLineArgs from within a single-file app --- src/coreclr/src/vm/corhost.cpp | 3 +- .../EnvironmentGetCommandLineArgs.csproj | 10 ++++ .../EnvironmentGetCommandLineArgs/Program.cs | 15 +++++ .../BundleEnvironmentGetCommandLineArgs.cs | 55 +++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/EnvironmentGetCommandLineArgs.csproj create mode 100644 src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs create mode 100644 src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs diff --git a/src/coreclr/src/vm/corhost.cpp b/src/coreclr/src/vm/corhost.cpp index a50e1515604657..f82aeeed0181bd 100644 --- a/src/coreclr/src/vm/corhost.cpp +++ b/src/coreclr/src/vm/corhost.cpp @@ -27,6 +27,7 @@ #include "comdelegate.h" #include "dllimportcallback.h" #include "eventtrace.h" +#include "bundle.h" #include "win32threadpool.h" #include "eventtrace.h" @@ -272,7 +273,7 @@ void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) GCPROTECT_BEGIN(gc); gc.cmdLineArgs = (PTRARRAYREF)AllocateObjectArray(argc + 1 /* arg[0] should be the exe name*/, g_pStringClass); - OBJECTREF orAssemblyPath = StringObject::NewString(pwzAssemblyPath); + OBJECTREF orAssemblyPath = StringObject::NewString(Bundle::AppIsBundle() ? Bundle::AppBundle->Path() : pwzAssemblyPath); gc.cmdLineArgs->SetAt(0, orAssemblyPath); for (int i = 0; i < argc; ++i) diff --git a/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/EnvironmentGetCommandLineArgs.csproj b/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/EnvironmentGetCommandLineArgs.csproj new file mode 100644 index 00000000000000..9052b4e7ce36f7 --- /dev/null +++ b/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/EnvironmentGetCommandLineArgs.csproj @@ -0,0 +1,10 @@ + + + + $(NetCoreAppCurrent) + Exe + $(TestTargetRid) + $(MNAVersion) + + + \ No newline at end of file diff --git a/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs b/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs new file mode 100644 index 00000000000000..c10cb9c974c9de --- /dev/null +++ b/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs @@ -0,0 +1,15 @@ +using System; + +namespace EnvironmentGetCommandLineArgs +{ + public class Program + { + public static void Main(string[] args) + { + foreach (var arg in Environment.GetCommandLineArgs()) + { + Console.WriteLine(arg); + } + } + } +} diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs new file mode 100644 index 00000000000000..4f131967ecb91a --- /dev/null +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs @@ -0,0 +1,55 @@ +using System; +using BundleTests.Helpers; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.DotNet.CoreSetup.Test; +using Xunit; + +namespace AppHost.Bundle.Tests +{ + public class BundleEnvironmentGetCommandLineArgs : IClassFixture + { + private SharedTestState sharedTestState; + + public BundleEnvironmentGetCommandLineArgs(SharedTestState fixture) + { + sharedTestState = fixture; + } + + [Fact] + public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() + { + var fixture = sharedTestState.TestFixture.Copy(); + var singleFile = BundleHelper.BundleApp(fixture); + var executablePath = BundleHelper.GetHostPath(fixture); + + Command.Create(singleFile) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining(executablePath); + } + + public class SharedTestState : IDisposable + { + public TestProjectFixture TestFixture { get; set; } + public RepoDirectoriesProvider RepoDirectories { get; set; } + + public SharedTestState() + { + RepoDirectories = new RepoDirectoriesProvider(); + TestFixture = new TestProjectFixture("EnvironmentGetCommandLineArgs", RepoDirectories); + TestFixture + .EnsureRestoredForRid(TestFixture.CurrentRid, RepoDirectories.CorehostPackages) + .PublishProject(runtime: TestFixture.CurrentRid, outputDirectory: BundleHelper.GetPublishPath(TestFixture)); + } + + public void Dispose() + { + TestFixture.Dispose(); + } + } + } +} From 9cfde56fe0a2edf928875fa74a65b2caa5ca7dd1 Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Wed, 19 Aug 2020 01:02:59 -0700 Subject: [PATCH 2/5] Look for the called exe --- .../BundleEnvironmentGetCommandLineArgs.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs index 4f131967ecb91a..67784dfc3a0a1f 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs @@ -20,7 +20,6 @@ public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() { var fixture = sharedTestState.TestFixture.Copy(); var singleFile = BundleHelper.BundleApp(fixture); - var executablePath = BundleHelper.GetHostPath(fixture); Command.Create(singleFile) .CaptureStdErr() @@ -29,7 +28,7 @@ public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() .Should() .Pass() .And - .HaveStdOutContaining(executablePath); + .HaveStdOutContaining(singleFile); } public class SharedTestState : IDisposable From b53f87eb02a70fb0b041d1166a7020f304a9ced6 Mon Sep 17 00:00:00 2001 From: mateoatr Date: Wed, 19 Aug 2020 19:41:08 +0000 Subject: [PATCH 3/5] Remove bundle header --- src/coreclr/src/vm/corhost.cpp | 3 +-- .../BundleEnvironmentGetCommandLineArgs.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/coreclr/src/vm/corhost.cpp b/src/coreclr/src/vm/corhost.cpp index f82aeeed0181bd..33aa48cf5c104b 100644 --- a/src/coreclr/src/vm/corhost.cpp +++ b/src/coreclr/src/vm/corhost.cpp @@ -27,7 +27,6 @@ #include "comdelegate.h" #include "dllimportcallback.h" #include "eventtrace.h" -#include "bundle.h" #include "win32threadpool.h" #include "eventtrace.h" @@ -273,7 +272,7 @@ void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) GCPROTECT_BEGIN(gc); gc.cmdLineArgs = (PTRARRAYREF)AllocateObjectArray(argc + 1 /* arg[0] should be the exe name*/, g_pStringClass); - OBJECTREF orAssemblyPath = StringObject::NewString(Bundle::AppIsBundle() ? Bundle::AppBundle->Path() : pwzAssemblyPath); + OBJECTREF orAssemblyPath = StringObject::NewString(Bundle::AppIsBundle() ? static_cast(Bundle::AppBundle->Path()) : pwzAssemblyPath); gc.cmdLineArgs->SetAt(0, orAssemblyPath); for (int i = 0; i < argc; ++i) diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs index 67784dfc3a0a1f..e3e16e17aeb600 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs @@ -21,6 +21,8 @@ public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() var fixture = sharedTestState.TestFixture.Copy(); var singleFile = BundleHelper.BundleApp(fixture); + // For single-file, Environment.GetCommandLineArgs[0] + // should return the file path of the host. Command.Create(singleFile) .CaptureStdErr() .CaptureStdOut() @@ -29,6 +31,20 @@ public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() .Pass() .And .HaveStdOutContaining(singleFile); + + // For non single-file apps, Environment.GetCommandLineArgs[0] + // should return the file path of the managed entrypoint. + var dotnet = fixture.BuiltDotnet; + var appPath = BundleHelper.GetAppPath(fixture); + + dotnet.Exec(appPath) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining(appPath); } public class SharedTestState : IDisposable From 2fbb63c8ae75f182cf3e2c7d842e470f4bccc915 Mon Sep 17 00:00:00 2001 From: mateoatr Date: Wed, 19 Aug 2020 21:36:53 +0000 Subject: [PATCH 4/5] Split test --- .../BundleEnvironmentGetCommandLineArgs.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs index e3e16e17aeb600..1126272fc8a73b 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs @@ -31,12 +31,17 @@ public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() .Pass() .And .HaveStdOutContaining(singleFile); + } - // For non single-file apps, Environment.GetCommandLineArgs[0] - // should return the file path of the managed entrypoint. + [Fact] + public void GetEnvironmentArgs_0_Non_Bundled_App() + { + var fixture = sharedTestState.TestFixture.Copy(); var dotnet = fixture.BuiltDotnet; var appPath = BundleHelper.GetAppPath(fixture); + // For non single-file apps, Environment.GetCommandLineArgs[0] + // should return the file path of the managed entrypoint. dotnet.Exec(appPath) .CaptureStdErr() .CaptureStdOut() From b17d68361c1966458027ff1ddbcd7e5f5ee4dc8a Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Tue, 25 Aug 2020 15:51:06 -0700 Subject: [PATCH 5/5] Throw from CodeBase if assembly is in the bundle (#40974) Also adds test for Module.FullyQualifiedName (cherry picked from commit 0546bd55c24618846d487d1315cf1d8f47dad4de) --- .../src/System/Reflection/RuntimeAssembly.cs | 28 +++++++++--- src/coreclr/src/vm/assembly.hpp | 2 +- src/coreclr/src/vm/assemblynative.cpp | 9 ++-- src/coreclr/src/vm/assemblynative.hpp | 2 +- src/coreclr/src/vm/pefile.cpp | 23 +++++++--- src/coreclr/src/vm/pefile.h | 4 +- .../EnvironmentGetCommandLineArgs/Program.cs | 15 ------- .../SingleFileApiTests/Program.cs | 39 ++++++++++++++++ .../SingleFileApiTests.csproj} | 0 ...mmandLineArgs.cs => SingleFileApiTests.cs} | 44 ++++++++++++++++--- .../src/Resources/Strings.resx | 3 ++ .../System.Reflection/tests/AssemblyTests.cs | 11 +++++ 12 files changed, 138 insertions(+), 42 deletions(-) delete mode 100644 src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs create mode 100644 src/installer/tests/Assets/TestProjects/SingleFileApiTests/Program.cs rename src/installer/tests/Assets/TestProjects/{EnvironmentGetCommandLineArgs/EnvironmentGetCommandLineArgs.csproj => SingleFileApiTests/SingleFileApiTests.csproj} (100%) rename src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/{BundleEnvironmentGetCommandLineArgs.cs => SingleFileApiTests.cs} (61%) diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index 0f273a87e33ce2..20a72464b3ac78 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -69,19 +69,33 @@ public override event ModuleResolveEventHandler? ModuleResolve } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] - private static extern void GetCodeBase(QCallAssembly assembly, - bool copiedName, + private static extern bool GetCodeBase(QCallAssembly assembly, StringHandleOnStack retString); - internal string? GetCodeBase(bool copiedName) + internal string? GetCodeBase() { string? codeBase = null; RuntimeAssembly runtimeAssembly = this; - GetCodeBase(new QCallAssembly(ref runtimeAssembly), copiedName, new StringHandleOnStack(ref codeBase)); - return codeBase; + if (GetCodeBase(new QCallAssembly(ref runtimeAssembly), new StringHandleOnStack(ref codeBase))) + { + return codeBase; + } + return null; } - public override string? CodeBase => GetCodeBase(false); + public override string? CodeBase + { + get + { + var codeBase = GetCodeBase(); + if (codeBase is null) + { + // Not supported if the assembly was loaded from memory + throw new NotSupportedException(SR.NotSupported_CodeBase); + } + return codeBase; + } + } internal RuntimeAssembly GetNativeHandle() => this; @@ -90,7 +104,7 @@ private static extern void GetCodeBase(QCallAssembly assembly, // is returned. public override AssemblyName GetName(bool copiedName) { - string? codeBase = GetCodeBase(copiedName); + string? codeBase = GetCodeBase(); var an = new AssemblyName(GetSimpleName(), GetPublicKey(), diff --git a/src/coreclr/src/vm/assembly.hpp b/src/coreclr/src/vm/assembly.hpp index 26291d2c0f65e6..4b594c46dc3744 100644 --- a/src/coreclr/src/vm/assembly.hpp +++ b/src/coreclr/src/vm/assembly.hpp @@ -337,7 +337,7 @@ class Assembly } #endif // DACCESS_COMPILE - void GetCodeBase(SString &result) + BOOL GetCodeBase(SString &result) { WRAPPER_NO_CONTRACT; diff --git a/src/coreclr/src/vm/assemblynative.cpp b/src/coreclr/src/vm/assemblynative.cpp index 8f5bb7820ec8a7..432f16785b3fcc 100644 --- a/src/coreclr/src/vm/assemblynative.cpp +++ b/src/coreclr/src/vm/assemblynative.cpp @@ -562,21 +562,24 @@ void QCALLTYPE AssemblyNative::GetLocale(QCall::AssemblyHandle pAssembly, QCall: END_QCALL; } -void QCALLTYPE AssemblyNative::GetCodeBase(QCall::AssemblyHandle pAssembly, BOOL fCopiedName, QCall::StringHandleOnStack retString) +BOOL QCALLTYPE AssemblyNative::GetCodeBase(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString) { QCALL_CONTRACT; + BOOL ret = TRUE; + BEGIN_QCALL; StackSString codebase; { - pAssembly->GetFile()->GetCodeBase(codebase); + ret = pAssembly->GetFile()->GetCodeBase(codebase); } retString.Set(codebase); - END_QCALL; + + return ret; } INT32 QCALLTYPE AssemblyNative::GetHashAlgorithm(QCall::AssemblyHandle pAssembly) diff --git a/src/coreclr/src/vm/assemblynative.hpp b/src/coreclr/src/vm/assemblynative.hpp index db80d9a8a28250..4ba91275b72ec0 100644 --- a/src/coreclr/src/vm/assemblynative.hpp +++ b/src/coreclr/src/vm/assemblynative.hpp @@ -60,7 +60,7 @@ class AssemblyNative void QCALLTYPE GetLocation(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString); static - void QCALLTYPE GetCodeBase(QCall::AssemblyHandle pAssembly, BOOL fCopiedName, QCall::StringHandleOnStack retString); + BOOL QCALLTYPE GetCodeBase(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString); static BYTE * QCALLTYPE GetResource(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, DWORD * length); diff --git a/src/coreclr/src/vm/pefile.cpp b/src/coreclr/src/vm/pefile.cpp index 25d379524977cb..9966c4c1d2e5f9 100644 --- a/src/coreclr/src/vm/pefile.cpp +++ b/src/coreclr/src/vm/pefile.cpp @@ -2128,9 +2128,8 @@ const SString &PEAssembly::GetEffectivePath() // Codebase is the fusion codebase or path for the assembly. It is in URL format. // Note this may be obtained from the parent PEFile if we don't have a path or fusion // assembly. -// -// fCopiedName means to get the "shadow copied" path rather than the original path, if applicable -void PEAssembly::GetCodeBase(SString &result, BOOL fCopiedName/*=FALSE*/) +// Returns false if the assembly was loaded from a bundle, true otherwise +BOOL PEAssembly::GetCodeBase(SString &result) { CONTRACTL { @@ -2142,10 +2141,20 @@ void PEAssembly::GetCodeBase(SString &result, BOOL fCopiedName/*=FALSE*/) } CONTRACTL_END; - // All other cases use the file path. - result.Set(GetEffectivePath()); - if (!result.IsEmpty()) - PathToUrl(result); + auto ilImage = GetILimage(); + if (ilImage == nullptr || !ilImage->IsInBundle()) + { + // All other cases use the file path. + result.Set(GetEffectivePath()); + if (!result.IsEmpty()) + PathToUrl(result); + return TRUE; + } + else + { + result.Set(SString::Empty()); + return FALSE; + } } /* static */ diff --git a/src/coreclr/src/vm/pefile.h b/src/coreclr/src/vm/pefile.h index 383fb53de0534c..32eb4f48334447 100644 --- a/src/coreclr/src/vm/pefile.h +++ b/src/coreclr/src/vm/pefile.h @@ -663,9 +663,7 @@ class PEAssembly : public PEFile // Codebase is the fusion codebase or path for the assembly. It is in URL format. // Note this may be obtained from the parent PEFile if we don't have a path or fusion // assembly. - // - // fCopiedName means to get the "shadow copied" path rather than the original path, if applicable - void GetCodeBase(SString &result, BOOL fCopiedName = FALSE); + BOOL GetCodeBase(SString &result); // Display name is the fusion binding name for an assembly void GetDisplayName(SString &result, DWORD flags = 0); diff --git a/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs b/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs deleted file mode 100644 index c10cb9c974c9de..00000000000000 --- a/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/Program.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace EnvironmentGetCommandLineArgs -{ - public class Program - { - public static void Main(string[] args) - { - foreach (var arg in Environment.GetCommandLineArgs()) - { - Console.WriteLine(arg); - } - } - } -} diff --git a/src/installer/tests/Assets/TestProjects/SingleFileApiTests/Program.cs b/src/installer/tests/Assets/TestProjects/SingleFileApiTests/Program.cs new file mode 100644 index 00000000000000..7b4ed44b4a3b40 --- /dev/null +++ b/src/installer/tests/Assets/TestProjects/SingleFileApiTests/Program.cs @@ -0,0 +1,39 @@ +using System; + +namespace SingleFileApiTests +{ + public class Program + { + public static void Main(string[] args) + { + switch (args[0]) + { + case "fullyqualifiedname": + var module = typeof(object).Assembly.GetModules()[0]; + Console.WriteLine("FullyQualifiedName: " + module.FullyQualifiedName); + Console.WriteLine("Name: " + module.Name); + return; + + case "cmdlineargs": + Console.WriteLine(Environment.GetCommandLineArgs()[0]); + return; + + case "codebase": + try + { + #pragma warning disable SYSLIB0012 + _ = typeof(Program).Assembly.CodeBase; + #pragma warning restore SYSLIB0012 + } + catch (NotSupportedException) + { + Console.WriteLine("CodeBase NotSupported"); + return; + } + break; + } + + Console.WriteLine("test failure"); + } + } +} diff --git a/src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/EnvironmentGetCommandLineArgs.csproj b/src/installer/tests/Assets/TestProjects/SingleFileApiTests/SingleFileApiTests.csproj similarity index 100% rename from src/installer/tests/Assets/TestProjects/EnvironmentGetCommandLineArgs/EnvironmentGetCommandLineArgs.csproj rename to src/installer/tests/Assets/TestProjects/SingleFileApiTests/SingleFileApiTests.csproj diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/SingleFileApiTests.cs similarity index 61% rename from src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs rename to src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/SingleFileApiTests.cs index 1126272fc8a73b..ece250d2e8cad7 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleEnvironmentGetCommandLineArgs.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/SingleFileApiTests.cs @@ -6,15 +6,49 @@ namespace AppHost.Bundle.Tests { - public class BundleEnvironmentGetCommandLineArgs : IClassFixture + public class SingleFileApiTests : IClassFixture { private SharedTestState sharedTestState; - public BundleEnvironmentGetCommandLineArgs(SharedTestState fixture) + public SingleFileApiTests(SharedTestState fixture) { sharedTestState = fixture; } + [Fact] + public void FullyQualifiedName() + { + var fixture = sharedTestState.TestFixture.Copy(); + var singleFile = BundleHelper.BundleApp(fixture); + + Command.Create(singleFile, "fullyqualifiedname") + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("FullyQualifiedName: " + + Environment.NewLine + + "Name: "); + } + + [Fact] + public void CodeBaseThrows() + { + var fixture = sharedTestState.TestFixture.Copy(); + var singleFile = BundleHelper.BundleApp(fixture); + + Command.Create(singleFile, "codebase") + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("CodeBase NotSupported"); + } + [Fact] public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() { @@ -23,7 +57,7 @@ public void GetEnvironmentArgs_0_Returns_Bundled_Executable_Path() // For single-file, Environment.GetCommandLineArgs[0] // should return the file path of the host. - Command.Create(singleFile) + Command.Create(singleFile, "cmdlineargs") .CaptureStdErr() .CaptureStdOut() .Execute() @@ -42,7 +76,7 @@ public void GetEnvironmentArgs_0_Non_Bundled_App() // For non single-file apps, Environment.GetCommandLineArgs[0] // should return the file path of the managed entrypoint. - dotnet.Exec(appPath) + dotnet.Exec(appPath, "cmdlineargs") .CaptureStdErr() .CaptureStdOut() .Execute() @@ -60,7 +94,7 @@ public class SharedTestState : IDisposable public SharedTestState() { RepoDirectories = new RepoDirectoriesProvider(); - TestFixture = new TestProjectFixture("EnvironmentGetCommandLineArgs", RepoDirectories); + TestFixture = new TestProjectFixture("SingleFileApiTests", RepoDirectories); TestFixture .EnsureRestoredForRid(TestFixture.CurrentRid, RepoDirectories.CorehostPackages) .PublishProject(runtime: TestFixture.CurrentRid, outputDirectory: BundleHelper.GetPublishPath(TestFixture)); diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 57ed5264638c60..c2d6cea19e41ac 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -3775,4 +3775,7 @@ BinaryFormatter serialization and deserialization are disabled within this application. See https://aka.ms/binaryformatter for more information. + + CodeBase is not supported on assemblies loaded from a single-file bundle. + diff --git a/src/libraries/System.Reflection/tests/AssemblyTests.cs b/src/libraries/System.Reflection/tests/AssemblyTests.cs index bc9642718499d4..66d8d41a5675b3 100644 --- a/src/libraries/System.Reflection/tests/AssemblyTests.cs +++ b/src/libraries/System.Reflection/tests/AssemblyTests.cs @@ -185,6 +185,17 @@ public void GetFile_InMemory() Assert.Throws(() => asm.GetFiles(getResourceModules: false)); } + [Fact] + public void CodeBaseInMemory() + { + var inMemBlob = File.ReadAllBytes(SourceTestAssemblyPath); + var asm = Assembly.Load(inMemBlob); + // Should not throw + #pragma warning disable SYSLIB0012 + _ = asm.CodeBase; + #pragma warning restore SYSLIB0012 + } + [Fact] public void GetFiles() {