2017-11-27 18:45:43 +00:00
|
|
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Diagnostics;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Runtime.InteropServices;
|
2018-01-18 22:54:10 +00:00
|
|
|
using System.Xml.Linq;
|
2017-11-27 18:45:43 +00:00
|
|
|
using FluentAssertions;
|
|
|
|
using Microsoft.DotNet.Cli.Utils;
|
|
|
|
using Microsoft.DotNet.TestFramework;
|
|
|
|
using Microsoft.DotNet.Tools.Test.Utilities;
|
|
|
|
using Xunit;
|
2018-01-18 22:54:10 +00:00
|
|
|
using Xunit.Abstractions;
|
2017-11-27 18:45:43 +00:00
|
|
|
|
2017-12-04 22:13:24 +00:00
|
|
|
namespace Microsoft.DotNet.ShellShim.Tests
|
2017-11-27 18:45:43 +00:00
|
|
|
{
|
|
|
|
public class ShellShimMakerTests : TestBase
|
|
|
|
{
|
2018-01-18 22:54:10 +00:00
|
|
|
private readonly ITestOutputHelper _output;
|
2017-11-27 18:45:43 +00:00
|
|
|
|
2018-01-18 22:54:10 +00:00
|
|
|
public ShellShimMakerTests(ITestOutputHelper output)
|
2017-11-27 18:45:43 +00:00
|
|
|
{
|
2018-01-18 22:54:10 +00:00
|
|
|
_output = output;
|
|
|
|
}
|
|
|
|
|
|
|
|
[Theory]
|
|
|
|
[InlineData("my_native_app.exe", null)]
|
|
|
|
[InlineData("./my_native_app.js", "nodejs")]
|
|
|
|
[InlineData(@"C:\tools\my_native_app.dll", "dotnet")]
|
|
|
|
public void GivenAnRunnerOrEntryPointItCanCreateConfig(string entryPoint, string runner)
|
|
|
|
{
|
|
|
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
|
|
return;
|
|
|
|
|
|
|
|
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
|
|
|
|
|
|
|
|
var tmpFile = Path.Combine(TempRoot.Root, Path.GetRandomFileName());
|
|
|
|
|
|
|
|
shellShimMaker.CreateConfigFile(tmpFile, entryPoint, runner);
|
|
|
|
|
|
|
|
new FileInfo(tmpFile).Should().Exist();
|
|
|
|
|
|
|
|
var generated = XDocument.Load(tmpFile);
|
|
|
|
|
|
|
|
generated.Descendants("appSettings")
|
|
|
|
.Descendants("add")
|
|
|
|
.Should()
|
|
|
|
.Contain(e => e.Attribute("key").Value == "runner" && e.Attribute("value").Value == (runner ?? string.Empty))
|
|
|
|
.And
|
|
|
|
.Contain(e => e.Attribute("key").Value == "entryPoint" && e.Attribute("value").Value == entryPoint);
|
2017-11-27 18:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void GivenAnExecutablePathItCanGenerateShimFile()
|
|
|
|
{
|
|
|
|
var outputDll = MakeHelloWorldExecutableDll();
|
|
|
|
|
2018-01-18 22:54:10 +00:00
|
|
|
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
|
2017-11-27 18:45:43 +00:00
|
|
|
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
|
|
|
|
|
|
|
|
shellShimMaker.CreateShim(
|
|
|
|
outputDll.FullName,
|
|
|
|
shellCommandName);
|
|
|
|
var stdOut = ExecuteInShell(shellCommandName);
|
|
|
|
|
|
|
|
stdOut.Should().Contain("Hello World");
|
|
|
|
}
|
|
|
|
|
2018-01-18 22:54:10 +00:00
|
|
|
[Theory]
|
|
|
|
[InlineData("arg1 arg2", new[] { "arg1", "arg2" })]
|
|
|
|
[InlineData(" \"arg1 with space\" arg2", new[] { "arg1 with space", "arg2" })]
|
|
|
|
[InlineData(" \"arg with ' quote\" ", new[] { "arg with ' quote" })]
|
|
|
|
public void GivenAShimItPassesThroughArguments(string arguments, string[] expectedPassThru)
|
|
|
|
{
|
|
|
|
var outputDll = MakeHelloWorldExecutableDll();
|
|
|
|
|
|
|
|
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
|
|
|
|
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
|
|
|
|
|
|
|
|
shellShimMaker.CreateShim(
|
|
|
|
outputDll.FullName,
|
|
|
|
shellCommandName);
|
|
|
|
|
|
|
|
var stdOut = ExecuteInShell(shellCommandName, arguments);
|
|
|
|
|
|
|
|
for (int i = 0; i < expectedPassThru.Length; i++)
|
|
|
|
{
|
|
|
|
stdOut.Should().Contain($"{i} = {expectedPassThru[i]}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-27 18:45:43 +00:00
|
|
|
[Fact]
|
|
|
|
public void GivenAnExecutablePathWithExistingSameNameShimItThrows()
|
|
|
|
{
|
|
|
|
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
|
|
|
|
|
2018-01-18 22:54:10 +00:00
|
|
|
MakeNameConflictingCommand(TempRoot.Root, shellCommandName);
|
2017-11-27 18:45:43 +00:00
|
|
|
|
2018-01-18 22:54:10 +00:00
|
|
|
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
|
2017-11-27 18:45:43 +00:00
|
|
|
|
|
|
|
Action a = () => shellShimMaker.EnsureCommandNameUniqueness(shellCommandName);
|
|
|
|
a.ShouldThrow<GracefulException>()
|
|
|
|
.And.Message
|
|
|
|
.Should().Contain(
|
|
|
|
$"Failed to install tool {shellCommandName}. A command with the same name already exists.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
public void GivenAnExecutablePathWithoutExistingSameNameShimItShouldNotThrow()
|
|
|
|
{
|
|
|
|
var shellCommandName = nameof(ShellShimMakerTests) + Path.GetRandomFileName();
|
|
|
|
|
2018-01-18 22:54:10 +00:00
|
|
|
var shellShimMaker = new ShellShimMaker(TempRoot.Root);
|
2017-11-27 18:45:43 +00:00
|
|
|
|
|
|
|
Action a = () => shellShimMaker.EnsureCommandNameUniqueness(shellCommandName);
|
|
|
|
a.ShouldNotThrow();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void MakeNameConflictingCommand(string pathToPlaceShim, string shellCommandName)
|
|
|
|
{
|
|
|
|
File.WriteAllText(Path.Combine(pathToPlaceShim, shellCommandName), string.Empty);
|
|
|
|
}
|
|
|
|
|
2018-01-18 22:54:10 +00:00
|
|
|
private string ExecuteInShell(string shellCommandName, string arguments = "")
|
2017-11-27 18:45:43 +00:00
|
|
|
{
|
|
|
|
ProcessStartInfo processStartInfo;
|
|
|
|
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
|
|
{
|
2018-01-18 22:54:10 +00:00
|
|
|
var file = Path.Combine(TempRoot.Root, shellCommandName + ".exe");
|
2017-11-27 18:45:43 +00:00
|
|
|
processStartInfo = new ProcessStartInfo
|
|
|
|
{
|
2018-01-18 22:54:10 +00:00
|
|
|
FileName = file,
|
|
|
|
UseShellExecute = false,
|
|
|
|
Arguments = arguments,
|
2017-11-27 18:45:43 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
processStartInfo = new ProcessStartInfo
|
|
|
|
{
|
|
|
|
FileName = "sh",
|
2018-01-18 22:54:10 +00:00
|
|
|
Arguments = shellCommandName + " " + arguments,
|
2017-11-27 18:45:43 +00:00
|
|
|
UseShellExecute = false
|
|
|
|
};
|
|
|
|
}
|
2018-01-18 22:54:10 +00:00
|
|
|
|
|
|
|
_output.WriteLine($"Launching '{processStartInfo.FileName} {processStartInfo.Arguments}'");
|
|
|
|
processStartInfo.WorkingDirectory = TempRoot.Root;
|
2017-11-27 18:45:43 +00:00
|
|
|
processStartInfo.EnvironmentVariables["PATH"] = Path.GetDirectoryName(new Muxer().MuxerPath);
|
|
|
|
|
|
|
|
processStartInfo.ExecuteAndCaptureOutput(out var stdOut, out var stdErr);
|
|
|
|
|
|
|
|
stdErr.Should().BeEmpty();
|
|
|
|
|
|
|
|
return stdOut ?? "";
|
|
|
|
}
|
|
|
|
|
|
|
|
private static FileInfo MakeHelloWorldExecutableDll()
|
|
|
|
{
|
|
|
|
const string testAppName = "TestAppSimple";
|
|
|
|
const string emptySpaceToTestSpaceInPath = " ";
|
|
|
|
TestAssetInstance testInstance = TestAssets.Get(testAppName)
|
|
|
|
.CreateInstance(testAppName + emptySpaceToTestSpaceInPath)
|
|
|
|
.UseCurrentRuntimeFrameworkVersion()
|
|
|
|
.WithRestoreFiles()
|
|
|
|
.WithBuildFiles();
|
|
|
|
|
|
|
|
var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? "Debug";
|
|
|
|
|
|
|
|
FileInfo outputDll = testInstance.Root.GetDirectory("bin", configuration)
|
|
|
|
.GetDirectories().Single()
|
|
|
|
.GetFile($"{testAppName}.dll");
|
|
|
|
|
|
|
|
return outputDll;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|