2016-01-14 11:52:54 -08: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 15:29:34 -08:00
using FluentAssertions ;
2016-01-14 11:52:54 -08:00
using Microsoft.DotNet.Cli.Utils ;
2016-01-26 14:53:56 -08:00
using Microsoft.DotNet.Tools.Test.Utilities ;
2016-01-14 11:52:54 -08:00
using Xunit ;
2016-02-11 14:17:20 -08:00
using System.Runtime.InteropServices ;
2016-01-14 11:52:54 -08:00
namespace Microsoft.DotNet.Tools.Builder.Tests
{
public class ProjectToProjectDependenciesIncrementalTest : IncrementalTestBase
{
2016-02-05 15:29:34 -08:00
private readonly string [ ] _projects = new [ ] { "L0" , "L11" , "L12" , "L21" , "L22" } ;
2016-01-14 11:52:54 -08:00
2016-02-11 14:17:20 -08:00
private string MainProjectExe
2016-01-14 11:52:54 -08:00
{
2016-02-11 14:17:20 -08: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 11:52:54 -08:00
}
[ Theory ,
2016-02-11 14:17:20 -08:00
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-01-14 11:52:54 -08:00
]
2016-02-11 14:17:20 -08:00
public void TestIncrementalBuildOfDependencyGraph ( string testIdentifer , string projectToTouch , string [ ] expectedRebuiltProjects )
2016-01-14 11:52:54 -08:00
{
2016-02-11 14:17:20 -08:00
var testInstance = TestAssetsManager . CreateTestInstance ( "TestProjectToProjectDependencies" , identifier : testIdentifer )
. WithLockFiles ( )
. WithBuildArtifacts ( ) ;
2016-01-14 11:52:54 -08:00
2016-02-11 14:17:20 -08:00
TestProjectRoot = testInstance . TestRoot ;
2016-01-14 11:52:54 -08: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 15:29:34 -08:00
[Fact]
public void TestNoDependencyFlag ( )
{
2016-02-16 11:26:40 -08:00
var testInstance = TestAssetsManager . CreateTestInstance ( "TestProjectToProjectDependencies" )
. WithLockFiles ( )
. WithBuildArtifacts ( ) ;
TestProjectRoot = testInstance . TestRoot ;
2016-02-05 15:29:34 -08:00
2016-02-16 11:26:40 -08:00
var dependencies = new [ ] { "L11" , "L12" , "L21" , "L22" } ;
2016-02-05 15:29:34 -08: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 ) ;
result2 . Should ( ) . StdOutMatchPattern ( "Compiling.*L0.*" ) ;
AssertResultDoesNotContainStrings ( result2 , dependencies ) ;
// third build with no dependencies but incremental; nothing rebuilds
var result3 = BuildProject ( noDependencies : true ) ;
result3 . Should ( ) . HaveSkippedProjectCompilation ( "L0" ) ;
AssertResultDoesNotContainStrings ( result3 , dependencies ) ;
}
private static void AssertResultDoesNotContainStrings ( CommandResult commandResult , string [ ] strings )
{
foreach ( var s in strings )
{
commandResult . StdOut . Should ( ) . NotContain ( s ) ;
}
}
2016-01-14 11:52:54 -08: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-01-26 14:53:56 -08:00
buildResult . Should ( ) . HaveCompiledProject ( rebuiltProject ) ;
2016-01-14 11:52:54 -08:00
}
foreach ( var skippedProject in SetDifference ( _projects , expectedRebuilt ) )
{
2016-01-26 14:53:56 -08:00
buildResult . Should ( ) . HaveSkippedProjectCompilation ( skippedProject ) ;
2016-01-14 11:52:54 -08:00
}
}
protected override string GetProjectDirectory ( string projectName )
{
2016-02-11 14:17:20 -08: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 11:52:54 -08:00
}
}
}