diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..73a669f
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "0.1.0",
+ "command": "dotnet",
+ "isShellCommand": true,
+ "args": [],
+ "tasks": [
+ {
+ "taskName": "build",
+ "args": [ "test/dotnet-new.Tests/dotnet-new.Tests.csproj" ],
+ "isBuildCommand": true,
+ "showOutput": "silent",
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/FSharp.NET.Sdk/FSharp.NET.Sdk.proj b/src/FSharp.NET.Sdk/FSharp.NET.Sdk.proj
index 5a2f40a..8a5fe6c 100644
--- a/src/FSharp.NET.Sdk/FSharp.NET.Sdk.proj
+++ b/src/FSharp.NET.Sdk/FSharp.NET.Sdk.proj
@@ -38,7 +38,7 @@
-
+
diff --git a/test/dotnet-new.Tests/MSBuildHostTypeAttribute.cs b/test/dotnet-new.Tests/MSBuildHostTypeAttribute.cs
new file mode 100644
index 0000000..2cac9be
--- /dev/null
+++ b/test/dotnet-new.Tests/MSBuildHostTypeAttribute.cs
@@ -0,0 +1,44 @@
+using System;
+using Xunit;
+using static System.Environment;
+
+namespace NetcoreCliFsc.Tests
+{
+ [Flags]
+ public enum MSBuildHostTypesOnly
+ {
+ Core = 1,
+ MSBuild = 2,
+ Mono = 4,
+ }
+
+ public class MSBuildHostTypeOnlyFactAttribute : FactAttribute
+ {
+ public string Reason { get; set; }
+
+ public MSBuildHostTypeOnlyFactAttribute(MSBuildHostTypesOnly msbuildHostType)
+ {
+ if (!TestSuite.MSBuildHostTypesOnly.HasFlag(msbuildHostType))
+ {
+ var hostName = Enum.GetName(typeof(MSBuildHostTypesOnly), msbuildHostType);
+ this.Skip = $"This test requires msbuild host type {hostName} to run"
+ + (string.IsNullOrEmpty(Reason)? "" : $". Why? {Reason}");
+ }
+ }
+ }
+
+ public class MSBuildHostTypeOnlyTheoryAttribute : TheoryAttribute
+ {
+ public string Reason { get; set; }
+
+ public MSBuildHostTypeOnlyTheoryAttribute(MSBuildHostTypesOnly msbuildHostType)
+ {
+ if (!TestSuite.MSBuildHostTypesOnly.HasFlag(msbuildHostType))
+ {
+ var hostName = Enum.GetName(typeof(MSBuildHostTypesOnly), msbuildHostType);
+ this.Skip = $"This test requires msbuild host type {hostName} to run"
+ + (string.IsNullOrEmpty(Reason)? "" : $". Why? {Reason}");
+ }
+ }
+ }
+}
diff --git a/test/dotnet-new.Tests/MsbuildCommonScenarioTests.cs b/test/dotnet-new.Tests/MsbuildCommonScenarioTests.cs
new file mode 100644
index 0000000..944b223
--- /dev/null
+++ b/test/dotnet-new.Tests/MsbuildCommonScenarioTests.cs
@@ -0,0 +1,398 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+using Microsoft.DotNet.Tools.Test.Utilities;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Xunit;
+using FluentAssertions;
+using static System.Environment;
+using static NetcoreCliFsc.Tests.MsbuildTestSuite;
+
+namespace NetcoreCliFsc.Tests
+{
+ public class MsbuildCommonScenario : TestBase
+ {
+ private static string RestoreProps()
+ {
+ var props = new Dictionary()
+ {
+ { "FSharpNETSdkVersion", GetEnvironmentVariable("TEST_SUITE_FSHARP_NET_SDK_PKG_VERSION")},
+ { "FSharpCorePkgVersion", GetEnvironmentVariable("TEST_SUITE_FSHARP_CORE_PKG_VERSION")},
+ };
+
+ return string.Join(" ", props.Where(kv => kv.Value != null).Select(kv => $"/p:{kv.Key}={kv.Value}") );
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestAppWithArgs()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("netcoreapp1.0/TestConsoleAppTemplate", rootPath);
+ TestAssets.CopyDirTo("TestAppWithArgs", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs}")
+ .Should().Pass();
+
+ test("dotnet")
+ .Execute($"run {LogArgs}")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestAppWithArgs451()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("net451/TestConsoleAppTemplate", rootPath);
+ TestAssets.CopyDirTo("TestAppWithArgs", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ string rid = GetCurrentRID();
+
+ test("msbuild")
+ .Execute($"/t:Restore /p:RuntimeIdentifier={rid} {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build /p:RuntimeIdentifier={rid} {LogArgs}")
+ .Should().Pass();
+
+ test(Path.Combine(rootPath, "bin", "Debug", "net451", rid, "ConsoleApp.exe"))
+ .Execute($"arg1 arg2")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.Mono)]
+ public void MonoCheck()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("mono")
+ .Execute($"--version")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestLibrary()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("TestLibrary", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs}")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestXmlDoc()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("TestLibrary", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ Assert.Equal(false, File.Exists(Path.Combine(rootPath, "doc.xml")));
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs} /p:DocumentationFile=doc.xml")
+ .Should().Pass();
+
+ Assert.Equal(true, File.Exists(Path.Combine(rootPath, "doc.xml")));
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestImplicitFrameworkDefines()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("netcoreapp1.0/TestConsoleAppTemplate", rootPath);
+ TestAssets.CopyDirTo("TestAppDefines", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs}")
+ .Should().Pass();
+
+ var result = test("dotnet").ExecuteWithCapturedOutput($"run {LogArgs}");
+
+ result.Should().Pass();
+
+ Assert.NotNull(result.StdOut);
+ Assert.Contains($"TFM: 'NETCOREAPP1_0'", result.StdOut.Trim());
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestImplicitConfigurationDefines()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("netcoreapp1.0/TestConsoleAppTemplate", rootPath);
+ TestAssets.CopyDirTo("TestAppDefines", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ var configurations = new Dictionary {
+ { "release", "RELEASE" },
+ { "debug", "DEBUG" },
+ };
+
+ foreach (var kv in configurations)
+ {
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs} /p:Configuration={kv.Key}")
+ .Should().Pass();
+
+ var result = test("dotnet").ExecuteWithCapturedOutput($"run -c {kv.Key} {LogArgs}");
+
+ result.Should().Pass();
+
+ Assert.NotNull(result.StdOut);
+ Assert.Contains($"CONF: '{kv.Value}'", result.StdOut.Trim());
+ }
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestMultipleLibraryInSameDir()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("TestLibrary", rootPath);
+ TestAssets.CopyDirTo("TestMultipleLibraryInSameDir", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore TestLibrary.fsproj {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Restore TestLibrary2.fsproj {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build TestLibrary.fsproj {LogArgs}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build TestLibrary2.fsproj {LogArgs}")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestLibraryCross()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("TestLibraryCross", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Pack {LogArgs}")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestApp()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ foreach (var a in new[] { "TestLibrary", "TestApp" })
+ {
+ var projDir = Path.Combine(rootPath, a);
+ TestAssets.CopyDirTo(a, projDir);
+ TestAssets.CopyDirTo("TestSuiteProps", projDir);
+ }
+
+ var appDir = Path.Combine(rootPath, "TestApp");
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = appDir };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs}")
+ .Should().Pass();
+
+ test("dotnet")
+ .Execute($"run {LogArgs}")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestPathWithBlank()
+ {
+ var rootPath = Path.Combine(Temp.CreateDirectory().Path, "path with blank");
+
+ TestAssets.CopyDirTo("TestLibrary", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs}")
+ .Should().Pass();
+ }
+
+ private string GetCurrentRID()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ Func test = n => new TestCommand(n) { WorkingDirectory = rootPath };
+
+ var result = test("dotnet").ExecuteWithCapturedOutput($"--info");
+
+ result.Should().Pass();
+
+ var dotnetInfo = result.StdOut;
+
+ string rid =
+ dotnetInfo
+ .Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(s => s.Trim())
+ .Where(s => s.StartsWith("RID:"))
+ .Select(s => s.Replace("RID:", "").Trim())
+ .FirstOrDefault();
+
+ return rid;
+ }
+
+ private void CreateNoopExe(string intoDir, string name, bool fail = false)
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("Noop", rootPath);
+
+ Func test = n => new TestCommand(n) { WorkingDirectory = rootPath };
+
+ string rid = GetCurrentRID();
+ string msbuildArgs = $"/p:AssemblyName={name} " + (fail? "/p:Fail=true" : "");
+
+ test("dotnet")
+ .Execute($"restore -r {rid} {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()} {msbuildArgs}")
+ .Should().Pass();
+
+ test("dotnet")
+ .Execute($"publish -r {rid} -o \"{intoDir}\" {msbuildArgs}")
+ .Should().Pass();
+ }
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestAppWithRes()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("netcoreapp1.0/TestConsoleAppTemplate", rootPath);
+ TestAssets.CopyDirTo("TestAppWithRes", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ test("msbuild")
+ .Execute($"/t:Restore {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build {LogArgs}")
+ .Should().Pass();
+
+ var result = test("dotnet").ExecuteWithCapturedOutput($"run {LogArgs}");
+
+ result.Should().Pass();
+
+ Assert.NotNull(result.StdOut);
+ Assert.Equal("Hi!", result.StdOut.Trim());
+ }
+
+
+ [MSBuildHostTypeOnlyFact(MSBuildHostTypesOnly.MSBuild)]
+ public void TestAppWithResNet451()
+ {
+ var rootPath = Temp.CreateDirectory().Path;
+
+ TestAssets.CopyDirTo("net451/TestConsoleAppTemplate", rootPath);
+ TestAssets.CopyDirTo("TestAppWithRes", rootPath);
+ TestAssets.CopyDirTo("TestSuiteProps", rootPath);
+
+ Func test = name => new TestCommand(name) { WorkingDirectory = rootPath };
+
+ string rid = GetCurrentRID();
+
+ test("msbuild")
+ .Execute($"/t:Restore /p:RuntimeIdentifier={rid} {RestoreDefaultArgs} {RestoreSourcesArgs(NugetConfigSources)} {RestoreProps()}")
+ .Should().Pass();
+
+ test("msbuild")
+ .Execute($"/t:Build /p:RuntimeIdentifier={rid} {LogArgs}")
+ .Should().Pass();
+
+
+ var result =
+ test(Path.Combine(rootPath, "bin", "Debug", "net451", rid, "ConsoleApp.exe"))
+ .ExecuteWithCapturedOutput("");
+
+ result.Should().Pass();
+
+ Assert.NotNull(result.StdOut);
+ Assert.Equal("Hi!", result.StdOut.Trim());
+ }
+
+ }
+}
diff --git a/test/dotnet-new.Tests/MsbuildTestSuite.cs b/test/dotnet-new.Tests/MsbuildTestSuite.cs
new file mode 100644
index 0000000..e210142
--- /dev/null
+++ b/test/dotnet-new.Tests/MsbuildTestSuite.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+using Microsoft.DotNet.Tools.Test.Utilities;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Xunit;
+using FluentAssertions;
+using static System.Environment;
+
+namespace NetcoreCliFsc.Tests
+{
+ public static class MsbuildTestSuite
+ {
+ public static string RestoreSourcesArgs(IEnumerable sources)
+ {
+ return "\"/p:RestoreSources=" + string.Join(MsbuildPropertySeparator, sources) + "\"";
+ }
+
+ private static string MsbuildPropertySeparator = "%3B";
+
+ public static IEnumerable NugetConfigSources => TestSuite.NugetConfigSources;
+
+ public static string RestoreDefaultArgs => $"/p:RestoreNoCache=true {LogArgs} \"/p:RestorePackagesPath={TestSuite.NugetPackagesDir}\"";
+
+ public static string LogArgs => "/v:n";
+ }
+}
diff --git a/test/dotnet-new.Tests/TestSuite.cs b/test/dotnet-new.Tests/TestSuite.cs
index f8f1d0b..728ab9b 100644
--- a/test/dotnet-new.Tests/TestSuite.cs
+++ b/test/dotnet-new.Tests/TestSuite.cs
@@ -43,7 +43,7 @@ namespace NetcoreCliFsc.Tests
}
}
- private static string NugetPackagesDir => Path.Combine(TestBase.RepoRoot, "test", "packages");
+ public static string NugetPackagesDir => Path.Combine(TestBase.RepoRoot, "test", "packages");
public static string RestoreSourcesArgs(IEnumerable sources)
{
@@ -53,5 +53,23 @@ namespace NetcoreCliFsc.Tests
public static string RestoreDefaultArgs => $"--no-cache {LogArgs} --packages \"{NugetPackagesDir}\"";
public static string LogArgs => "-v n";
+
+ public static MSBuildHostTypesOnly MSBuildHostTypesOnly
+ {
+ get
+ {
+ var msbuildHost =
+ (GetEnvironmentVariable("TEST_SUITE_MSBUILD_HOST_ONLY") ?? "")
+ .ToUpper()
+ .Split(';');
+
+ var result = MSBuildHostTypesOnly.Core;
+ if (msbuildHost.Contains("MSBUILD"))
+ result = result | MSBuildHostTypesOnly.MSBuild;
+ if (msbuildHost.Contains("MONO"))
+ result = result | MSBuildHostTypesOnly.Mono;
+ return result;
+ }
+ }
}
}