2016-01-14 19:52:54 +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.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
2016-02-05 23:29:34 +00:00
|
|
|
|
using FluentAssertions;
|
2016-01-14 19:52:54 +00:00
|
|
|
|
using Microsoft.DotNet.Cli.Utils;
|
2016-01-26 22:53:56 +00:00
|
|
|
|
using Microsoft.DotNet.Tools.Test.Utilities;
|
2016-01-14 19:52:54 +00:00
|
|
|
|
using Xunit;
|
2016-02-11 22:17:20 +00:00
|
|
|
|
using System.Runtime.InteropServices;
|
2016-01-14 19:52:54 +00:00
|
|
|
|
|
|
|
|
|
namespace Microsoft.DotNet.Tools.Builder.Tests
|
|
|
|
|
{
|
|
|
|
|
public class ProjectToProjectDependenciesIncrementalTest : IncrementalTestBase
|
|
|
|
|
{
|
2016-02-05 23:29:34 +00:00
|
|
|
|
private readonly string[] _projects = new[] { "L0", "L11", "L12", "L21", "L22" };
|
2016-04-13 00:29:07 +00:00
|
|
|
|
private readonly string _appProject = "L0";
|
2016-01-14 19:52:54 +00:00
|
|
|
|
|
2016-04-13 00:29:07 +00:00
|
|
|
|
|
2016-02-11 22:17:20 +00:00
|
|
|
|
private string MainProjectExe
|
2016-01-14 19:52:54 +00:00
|
|
|
|
{
|
2016-02-11 22:17:20 +00:00
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return MainProject + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ProjectToProjectDependenciesIncrementalTest()
|
|
|
|
|
{
|
|
|
|
|
MainProject = "L0";
|
|
|
|
|
ExpectedOutput = "L0 L11 L12 L22 L21 L12 L22 " + Environment.NewLine;
|
|
|
|
|
|
2016-01-14 19:52:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-13 00:29:07 +00:00
|
|
|
|
[Theory]
|
|
|
|
|
[InlineData("1", "L0", new[] { "L0" })]
|
|
|
|
|
[InlineData("2", "L11", new[] { "L0", "L11" })]
|
|
|
|
|
[InlineData("3", "L12", new[] { "L0", "L11", "L12" })]
|
|
|
|
|
[InlineData("4", "L22", new[] { "L0", "L11", "L12", "L22" })]
|
|
|
|
|
[InlineData("5", "L21", new[] { "L0", "L11", "L21" })]
|
2016-02-11 22:17:20 +00:00
|
|
|
|
public void TestIncrementalBuildOfDependencyGraph(string testIdentifer, string projectToTouch, string[] expectedRebuiltProjects)
|
2016-01-14 19:52:54 +00:00
|
|
|
|
{
|
2016-02-11 22:17:20 +00:00
|
|
|
|
var testInstance = TestAssetsManager.CreateTestInstance("TestProjectToProjectDependencies", identifier: testIdentifer)
|
|
|
|
|
.WithLockFiles()
|
|
|
|
|
.WithBuildArtifacts();
|
2016-01-14 19:52:54 +00:00
|
|
|
|
|
2016-02-11 22:17:20 +00:00
|
|
|
|
TestProjectRoot = testInstance.TestRoot;
|
2016-01-14 19:52:54 +00:00
|
|
|
|
|
|
|
|
|
// second build; nothing changed; no project required compilation
|
|
|
|
|
var result2 = BuildProject();
|
|
|
|
|
AssertRebuilt(result2, Array.Empty<string>());
|
|
|
|
|
|
|
|
|
|
//modify the source code of a project
|
|
|
|
|
TouchSourcesOfProject(projectToTouch);
|
|
|
|
|
|
|
|
|
|
// third build; all projects on the paths from touched project to root project need to be rebuilt
|
|
|
|
|
var result3 = BuildProject();
|
|
|
|
|
AssertRebuilt(result3, expectedRebuiltProjects);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-05 23:29:34 +00:00
|
|
|
|
[Fact]
|
|
|
|
|
public void TestNoDependencyFlag()
|
|
|
|
|
{
|
2016-02-16 19:26:40 +00:00
|
|
|
|
var testInstance = TestAssetsManager.CreateTestInstance("TestProjectToProjectDependencies")
|
|
|
|
|
.WithLockFiles()
|
|
|
|
|
.WithBuildArtifacts();
|
|
|
|
|
|
|
|
|
|
TestProjectRoot = testInstance.TestRoot;
|
2016-02-05 23:29:34 +00:00
|
|
|
|
|
2016-02-16 19:26:40 +00:00
|
|
|
|
var dependencies = new[] { "L11", "L12", "L21", "L22" };
|
2016-02-05 23:29:34 +00:00
|
|
|
|
|
|
|
|
|
// modify the source code of a leaf dependency
|
|
|
|
|
TouchSourcesOfProject("L22");
|
|
|
|
|
|
|
|
|
|
// second build with no dependencies and no incremental; only the root rebuilds
|
|
|
|
|
var result2 = BuildProject(noDependencies: true, noIncremental: true);
|
2016-03-02 01:42:44 +00:00
|
|
|
|
result2.Should().HaveStdOutMatching("Compiling.*L0.*");
|
2016-02-05 23:29:34 +00:00
|
|
|
|
|
|
|
|
|
AssertResultDoesNotContainStrings(result2, dependencies);
|
|
|
|
|
|
|
|
|
|
// third build with no dependencies but incremental; nothing rebuilds
|
|
|
|
|
var result3 = BuildProject(noDependencies: true);
|
2016-04-13 00:29:07 +00:00
|
|
|
|
result3.Should().HaveSkippedProjectCompilation("L0", _appFrameworkFullName);
|
2016-02-05 23:29:34 +00:00
|
|
|
|
AssertResultDoesNotContainStrings(result3, dependencies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void AssertResultDoesNotContainStrings(CommandResult commandResult, string[] strings)
|
|
|
|
|
{
|
|
|
|
|
foreach (var s in strings)
|
|
|
|
|
{
|
|
|
|
|
commandResult.StdOut.Should().NotContain(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-14 19:52:54 +00:00
|
|
|
|
// compute A - B
|
|
|
|
|
private T[] SetDifference<T>(T[] A, T[] B)
|
|
|
|
|
{
|
|
|
|
|
var setA = new HashSet<T>(A);
|
|
|
|
|
setA.ExceptWith(B);
|
|
|
|
|
return setA.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AssertRebuilt(CommandResult buildResult, string[] expectedRebuilt)
|
|
|
|
|
{
|
|
|
|
|
foreach (var rebuiltProject in expectedRebuilt)
|
|
|
|
|
{
|
2016-04-13 00:29:07 +00:00
|
|
|
|
string frameworkFullName = null;
|
|
|
|
|
|
|
|
|
|
if (TestProjectIsApp(rebuiltProject))
|
|
|
|
|
{
|
|
|
|
|
buildResult
|
|
|
|
|
.Should()
|
|
|
|
|
.HaveCompiledProject(rebuiltProject, frameworkFullName: _appFrameworkFullName);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
buildResult
|
|
|
|
|
.Should()
|
|
|
|
|
.HaveCompiledProject(rebuiltProject, _libraryFrameworkFullName);
|
|
|
|
|
}
|
2016-01-14 19:52:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var skippedProject in SetDifference(_projects, expectedRebuilt))
|
|
|
|
|
{
|
2016-04-13 00:29:07 +00:00
|
|
|
|
if (TestProjectIsApp(skippedProject))
|
|
|
|
|
{
|
|
|
|
|
buildResult.Should().HaveSkippedProjectCompilation(skippedProject, _appFrameworkFullName);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
buildResult.Should().HaveSkippedProjectCompilation(skippedProject, _libraryFrameworkFullName);
|
|
|
|
|
}
|
2016-01-14 19:52:54 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-13 00:29:07 +00:00
|
|
|
|
private bool TestProjectIsApp(string testproject)
|
|
|
|
|
{
|
|
|
|
|
return testproject.Equals(_appProject, StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-14 19:52:54 +00:00
|
|
|
|
protected override string GetProjectDirectory(string projectName)
|
|
|
|
|
{
|
2016-02-11 22:17:20 +00:00
|
|
|
|
return Path.Combine(TestProjectRoot, "src", projectName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override string GetOutputDir()
|
|
|
|
|
{
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override string GetOutputExePath()
|
|
|
|
|
{
|
|
|
|
|
var outputExe = Directory.GetFiles(TestProjectRoot, MainProjectExe, SearchOption.AllDirectories)
|
|
|
|
|
.FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(outputExe))
|
|
|
|
|
{
|
|
|
|
|
throw new FileNotFoundException($"Unable to find {outputExe} in {TestProjectRoot} or its subdirectories");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Path.GetDirectoryName(outputExe);
|
2016-01-14 19:52:54 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|