diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln
index bd7e28c5a..be6d49846 100644
--- a/Microsoft.DotNet.Cli.sln
+++ b/Microsoft.DotNet.Cli.sln
@@ -65,6 +65,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Cli.Utils.
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Compiler.Common.Tests", "test\Microsoft.DotNet.Compiler.Common.Tests\Microsoft.DotNet.Compiler.Common.Tests.xproj", "{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.TestFramework", "src\Microsoft.DotNet.TestFramework\Microsoft.DotNet.TestFramework.xproj", "{0724ED7C-56E3-4604-9970-25E600611383}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -461,6 +463,22 @@ Global
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Debug|x64.Build.0 = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.MinSizeRel|x64.Build.0 = Debug|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Release|x64.ActiveCfg = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.Release|x64.Build.0 = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
+ {0724ED7C-56E3-4604-9970-25E600611383}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -490,5 +508,6 @@ Global
{D521DD9F-0614-4929-93B4-D8FA5682C174} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
{09C52F96-EFDD-4448-95EC-6D362DD60BAA} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
+ {0724ED7C-56E3-4604-9970-25E600611383} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
EndGlobalSection
EndGlobal
diff --git a/TestAssets/TestProjects/TestApp/Program.cs b/TestAssets/TestProjects/TestAppCompilationContext/TestApp/Program.cs
similarity index 100%
rename from TestAssets/TestProjects/TestApp/Program.cs
rename to TestAssets/TestProjects/TestAppCompilationContext/TestApp/Program.cs
diff --git a/TestAssets/TestProjects/TestAppCompilationContext/project.json b/TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json
similarity index 100%
rename from TestAssets/TestProjects/TestAppCompilationContext/project.json
rename to TestAssets/TestProjects/TestAppCompilationContext/TestApp/project.json
diff --git a/TestAssets/TestProjects/TestLibrary/Helper.cs b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/Helper.cs
similarity index 100%
rename from TestAssets/TestProjects/TestLibrary/Helper.cs
rename to TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/Helper.cs
diff --git a/TestAssets/TestProjects/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj
similarity index 100%
rename from TestAssets/TestProjects/TestLibrary/TestLibrary.xproj
rename to TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/TestLibrary.xproj
diff --git a/TestAssets/TestProjects/TestLibrary/project.json b/TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json
similarity index 100%
rename from TestAssets/TestProjects/TestLibrary/project.json
rename to TestAssets/TestProjects/TestAppCompilationContext/TestLibrary/project.json
diff --git a/TestAssets/TestProjects/TestAppCompilationContext/global.json b/TestAssets/TestProjects/TestAppCompilationContext/global.json
new file mode 100644
index 000000000..3a4684c26
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppCompilationContext/global.json
@@ -0,0 +1,3 @@
+{
+ "projects": [ "."]
+}
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppCompilationContext/Program.cs b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/Program.cs
similarity index 100%
rename from TestAssets/TestProjects/TestAppCompilationContext/Program.cs
rename to TestAssets/TestProjects/TestAppWithLibrary/TestApp/Program.cs
diff --git a/TestAssets/TestProjects/TestApp/TestApp.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj
similarity index 100%
rename from TestAssets/TestProjects/TestApp/TestApp.xproj
rename to TestAssets/TestProjects/TestAppWithLibrary/TestApp/TestApp.xproj
diff --git a/TestAssets/TestProjects/TestApp/project.json b/TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json
similarity index 100%
rename from TestAssets/TestProjects/TestApp/project.json
rename to TestAssets/TestProjects/TestAppWithLibrary/TestApp/project.json
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/Helper.cs b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/Helper.cs
new file mode 100644
index 000000000..8c643796b
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/Helper.cs
@@ -0,0 +1,24 @@
+// 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;
+
+namespace TestLibrary
+{
+ public static class Helper
+ {
+ ///
+ /// Gets the message from the helper. This comment is here to help test XML documentation file generation, please do not remove it.
+ ///
+ /// A message
+ public static string GetMessage()
+ {
+ return "This string came from the test library!";
+ }
+
+ public static void SayHi()
+ {
+ Console.WriteLine("Hello there!");
+ }
+ }
+}
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj
new file mode 100644
index 000000000..eb9f8bc2d
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/TestLibrary.xproj
@@ -0,0 +1,19 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ 947dd232-8d9b-4b78-9c6a-94f807d2dd58
+ TestLibrary
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json
new file mode 100644
index 000000000..6aaf77a3d
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithLibrary/TestLibrary/project.json
@@ -0,0 +1,15 @@
+{
+ "version": "1.0.0-*",
+ "compilationOptions": {
+ "nowarn": [ "CS1591" ],
+ "xmlDoc": true,
+ "additionalArguments": [ "-highentropyva+" ]
+ },
+ "dependencies": {
+ "NETStandard.Library": "1.0.0-rc2-23808"
+ },
+
+ "frameworks": {
+ "dnxcore50": { }
+ }
+}
diff --git a/TestAssets/TestProjects/TestAppWithLibrary/global.json b/TestAssets/TestProjects/TestAppWithLibrary/global.json
new file mode 100644
index 000000000..3a4684c26
--- /dev/null
+++ b/TestAssets/TestProjects/TestAppWithLibrary/global.json
@@ -0,0 +1,3 @@
+{
+ "projects": [ "."]
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestInstance.cs b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestInstance.cs
new file mode 100644
index 000000000..be635515e
--- /dev/null
+++ b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestInstance.cs
@@ -0,0 +1,116 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+
+namespace Microsoft.DotNet.TestFramework
+{
+ public class TestInstance
+ {
+ private string _testDestination;
+ private TestScenario _testScenario;
+
+ internal TestInstance(TestScenario testScenario, string testDestination)
+ {
+ if (testScenario == null)
+ {
+ throw new ArgumentNullException("testScenario");
+ }
+
+ if (string.IsNullOrEmpty(testDestination))
+ {
+ throw new ArgumentException("testDestination");
+ }
+
+ _testScenario = testScenario;
+ _testDestination = testDestination;
+
+ if (Directory.Exists(testDestination))
+ {
+ Directory.Delete(testDestination, true);
+ }
+
+ Directory.CreateDirectory(testDestination);
+ CopySource();
+ }
+
+ private void CopySource()
+ {
+ var sourceDirs = Directory.GetDirectories(_testScenario.SourceRoot, "*", SearchOption.AllDirectories)
+ .Where(dir =>
+ {
+ dir = dir.ToLower();
+ return !dir.EndsWith("\\bin") && !dir.Contains("\\bin\\")
+ && !dir.EndsWith("\\obj") && !dir.Contains("\\obj\\");
+ });
+
+ foreach (string sourceDir in sourceDirs)
+ {
+ Directory.CreateDirectory(sourceDir.Replace(_testScenario.SourceRoot, _testDestination));
+ }
+
+ var sourceFiles = Directory.GetFiles(_testScenario.SourceRoot, "*.*", SearchOption.AllDirectories)
+ .Where(file =>
+ {
+ file = file.ToLower();
+ return !file.EndsWith("project.lock.json")
+ && !file.Contains("\\bin\\") && !file.Contains("\\obj\\");
+ });
+
+ foreach (string srcFile in sourceFiles)
+ {
+ File.Copy(srcFile, srcFile.Replace(_testScenario.SourceRoot, _testDestination), true);
+ }
+ }
+
+ public TestInstance WithLockFiles()
+ {
+ foreach (string lockFile in Directory.GetFiles(_testScenario.SourceRoot, "project.lock.json", SearchOption.AllDirectories))
+ {
+ string destinationLockFile = lockFile.Replace(_testScenario.SourceRoot, _testDestination);
+ File.Copy(lockFile, destinationLockFile, true);
+ }
+
+ return this;
+ }
+
+ public TestInstance WithBinaries()
+ {
+ var binDirs = Directory.GetDirectories(_testScenario.SourceRoot, "*", SearchOption.AllDirectories)
+ .Where(dir =>
+ {
+ dir = dir.ToLower();
+ return dir.EndsWith("\\bin") || dir.Contains("\\bin\\")
+ || dir.EndsWith("\\obj") || dir.Contains("\\obj\\");
+ });
+
+ foreach (string dirPath in binDirs)
+ {
+ Directory.CreateDirectory(dirPath.Replace(_testScenario.SourceRoot, _testDestination));
+ }
+
+ var binFiles = Directory.GetFiles(_testScenario.SourceRoot, "*.*", SearchOption.AllDirectories)
+ .Where(file =>
+ {
+ file = file.ToLower();
+ return file.Contains("\\bin\\") || file.Contains("\\obj\\");
+ });
+
+ foreach (string binFile in binFiles)
+ {
+ File.Copy(binFile, binFile.Replace(_testScenario.SourceRoot, _testDestination), true);
+ }
+
+ return this;
+ }
+
+ public string TestRoot
+ {
+ get { return _testDestination; }
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestScenario.cs b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestScenario.cs
new file mode 100644
index 000000000..91ddfd42a
--- /dev/null
+++ b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.TestScenario.cs
@@ -0,0 +1,115 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Microsoft.DotNet.Cli.Utils;
+
+namespace Microsoft.DotNet.TestFramework
+{
+ public class TestScenario
+ {
+ private static IDictionary _scenarioCache = new Dictionary();
+
+ private TestScenario(string testSourceRoot, bool skipRestore, bool skipBuild)
+ {
+ SourceRoot = testSourceRoot;
+ Projects = GetAllProjects(SourceRoot);
+
+ if (!skipRestore)
+ {
+ Restore();
+ }
+
+ if (!skipBuild)
+ {
+ Build();
+ }
+ }
+
+ private IEnumerable Projects
+ {
+ get; set;
+ }
+
+ public string SourceRoot
+ {
+ get;
+ private set;
+ }
+
+ public static TestScenario Create(string testSourceRoot, bool skipRestore = false, bool skipBuild = false)
+ {
+ TestScenario testScenario;
+ lock (_scenarioCache)
+ {
+ if (!_scenarioCache.TryGetValue(testSourceRoot, out testScenario))
+ {
+ testScenario = new TestScenario(testSourceRoot, skipRestore, skipBuild);
+ _scenarioCache.Add(testSourceRoot, testScenario);
+ }
+ }
+
+ return testScenario;
+ }
+
+ public TestInstance CreateTestInstance([CallerMemberName] string callingMethod = "", string identifier = "")
+ {
+ string projectName = new DirectoryInfo(SourceRoot).Name;
+ string testDestination = Path.Combine(AppContext.BaseDirectory, callingMethod + identifier, projectName);
+ var testInstance = new TestInstance(this, testDestination);
+ return testInstance;
+ }
+
+ internal void Build()
+ {
+ foreach (var project in Projects)
+ {
+ string[] buildArgs = new string[] { "build", project };
+ var commandResult = Command.Create("dotnet", buildArgs)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute();
+
+ Console.WriteLine(commandResult.StdOut);
+ Console.WriteLine(commandResult.StdErr);
+ int exitCode = commandResult.ExitCode;
+
+ if (exitCode != 0)
+ {
+
+ string message = string.Format("Command Failed - 'dotnet {0}' with exit code - {1}", string.Join(" ", buildArgs), exitCode);
+ throw new Exception(message);
+ }
+ }
+ }
+
+ private static IEnumerable GetAllProjects(string sourceRoot)
+ {
+ return Directory.GetFiles(sourceRoot, "project.json", SearchOption.AllDirectories);
+ }
+
+ internal void Restore()
+ {
+ string[] restoreArgs = new string[] { "restore", SourceRoot };
+ var commandResult = Command.Create("dotnet", restoreArgs)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute();
+
+ Console.WriteLine(commandResult.StdOut);
+ Console.WriteLine(commandResult.StdErr);
+ int exitCode = commandResult.ExitCode;
+
+ if (exitCode != 0)
+ {
+ string message = string.Format("Command Failed - 'dotnet {0}' with exit code - {1}", string.Join(" ", restoreArgs), exitCode);
+ throw new Exception(message);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj
new file mode 100644
index 000000000..3cf0c3871
--- /dev/null
+++ b/src/Microsoft.DotNet.TestFramework/Microsoft.DotNet.TestFramework.xproj
@@ -0,0 +1,20 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ 0724ed7c-56e3-4604-9970-25e600611383
+ Microsoft.DotNet.TestFramework
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+
+ 2.0
+
+
+
diff --git a/src/Microsoft.DotNet.TestFramework/project.json b/src/Microsoft.DotNet.TestFramework/project.json
new file mode 100644
index 000000000..f9eca94d2
--- /dev/null
+++ b/src/Microsoft.DotNet.TestFramework/project.json
@@ -0,0 +1,19 @@
+{
+ "version": "1.0.0-*",
+ "description": "Microsoft.DotNet.TestFramework Class Library",
+ "authors": [ "sridhper" ],
+ "tags": [ "" ],
+ "projectUrl": "",
+ "licenseUrl": "",
+
+ "dependencies": {
+ "Microsoft.DotNet.Cli.Utils": "1.0.0-*",
+ "NETStandard.Library": "1.0.0-rc2-23728"
+ },
+
+ "frameworks": {
+ "dnxcore50": {
+ "imports": "portable-net45+win8"
+ }
+ }
+}
diff --git a/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs b/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs
index a9d465ee5..b3c7dc45f 100644
--- a/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs
+++ b/test/dotnet-publish.Tests/Microsoft.DotNet.Tools.Publish.Tests.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
+using Microsoft.DotNet.TestFramework;
using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.Extensions.PlatformAbstractions;
using Xunit;
@@ -14,10 +15,37 @@ namespace Microsoft.DotNet.Tools.Publish.Tests
public class PublishTests : TestBase
{
private readonly string _testProjectsRoot;
+ private string _repoRoot;
+
+ private string RepoRoot
+ {
+ get
+ {
+ if (!string.IsNullOrEmpty(_repoRoot))
+ {
+ return _repoRoot;
+ }
+
+ string directory = AppContext.BaseDirectory;
+
+ while (!Directory.Exists(Path.Combine(directory, ".git")) && directory != null)
+ {
+ directory = Directory.GetParent(directory).FullName;
+ }
+
+ if (directory == null)
+ {
+ throw new Exception("Cannot find the git repository root");
+ }
+
+ _repoRoot = directory;
+ return _repoRoot;
+ }
+ }
public PublishTests()
{
- _testProjectsRoot = Path.Combine(AppContext.BaseDirectory, "TestAssets", "TestProjects");
+ _testProjectsRoot = Path.Combine(RepoRoot, "TestAssets", "TestProjects");
}
public static IEnumerable