2017-03-02 21:04:03 -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 Microsoft.Build.Construction ;
2016-08-22 12:24:10 -07:00
using Microsoft.DotNet.ProjectJsonMigration ;
2016-10-27 18:46:43 -07:00
using Microsoft.DotNet.Internal.ProjectModel ;
2016-10-24 16:25:57 -07:00
using Microsoft.DotNet.TestFramework ;
2016-08-22 12:24:10 -07:00
using Microsoft.DotNet.Tools.Test.Utilities ;
using NuGet.Frameworks ;
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Threading.Tasks ;
using Xunit ;
using FluentAssertions ;
2016-08-23 13:50:05 -07:00
using Microsoft.DotNet.ProjectJsonMigration.Rules ;
2016-08-22 12:24:10 -07:00
2016-09-14 15:30:11 -07:00
namespace Microsoft.DotNet.ProjectJsonMigration.Tests
2016-08-22 12:24:10 -07:00
{
public class GivenThatIWantToMigrateProjectDependencies : TestBase
{
[Fact]
2016-12-28 14:48:38 -08:00
public void ProjectDependenciesAreMigratedToProjectReference ( )
2016-08-22 12:24:10 -07:00
{
2017-02-15 15:35:03 -08:00
var solutionDirectory = TestAssets . Get ( "TestAppWithLibrary" )
. CreateInstance ( callingMethod : "p" )
. WithSourceFiles ( )
. Root . FullName ;
2016-08-22 12:24:10 -07:00
var appDirectory = Path . Combine ( solutionDirectory , "TestApp" ) ;
2017-03-09 21:17:10 -08:00
var projectContext = ProjectContext . Create ( appDirectory , FrameworkConstants . CommonFrameworks . NetCoreApp11 ) ;
2016-08-22 12:24:10 -07:00
var mockProj = ProjectRootElement . Create ( ) ;
2016-12-07 11:49:15 -10:00
var testSettings = MigrationSettings . CreateMigrationSettingsTestHook ( appDirectory , appDirectory , mockProj , null ) ;
2016-08-22 12:24:10 -07:00
var testInputs = new MigrationRuleInputs ( new [ ] { projectContext } , mockProj , mockProj . AddItemGroup ( ) ,
mockProj . AddPropertyGroup ( ) ) ;
new MigrateProjectDependenciesRule ( ) . Apply ( testSettings , testInputs ) ;
var projectReferences = mockProj . Items . Where ( item = > item . ItemType . Equals ( "ProjectReference" , StringComparison . Ordinal ) ) ;
projectReferences . Count ( ) . Should ( ) . Be ( 1 ) ;
2016-10-21 18:00:17 -07:00
var projectReference = projectReferences . First ( ) ;
projectReference . Include . Should ( ) . Be ( Path . Combine ( ".." , "TestLibrary" , "TestLibrary.csproj" ) ) ;
projectReference . Parent . Condition . Should ( ) . BeEmpty ( ) ;
}
2016-10-24 16:25:57 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void ItDoesNotMigrateADependencyWithTargetPackageThatHasAMatchingProjectAsAProjectReference ( )
2016-10-24 16:25:57 -07:00
{
2017-02-15 15:35:03 -08:00
var solutionDirectory = TestAssets . Get ( "NonRestoredTestProjects" , "AppWithProjectDependencyAsTarget" )
. CreateInstance ( callingMethod : "p" )
. WithSourceFiles ( )
. Root . FullName ;
2016-10-24 16:25:57 -07:00
var appDirectory = Path . Combine ( solutionDirectory , "TestApp" ) ;
2017-03-09 21:17:10 -08:00
var projectContext = ProjectContext . Create ( appDirectory , FrameworkConstants . CommonFrameworks . NetCoreApp11 ) ;
2016-10-24 16:25:57 -07:00
var mockProj = ProjectRootElement . Create ( ) ;
2016-12-07 11:49:15 -10:00
var testSettings = MigrationSettings . CreateMigrationSettingsTestHook ( appDirectory , appDirectory , mockProj , null ) ;
2016-10-24 16:25:57 -07:00
var testInputs = new MigrationRuleInputs ( new [ ] { projectContext } , mockProj , mockProj . AddItemGroup ( ) ,
mockProj . AddPropertyGroup ( ) ) ;
new MigrateProjectDependenciesRule ( ) . Apply ( testSettings , testInputs ) ;
var projectReferences = mockProj . Items . Where (
item = > item . ItemType . Equals ( "ProjectReference" , StringComparison . Ordinal ) ) ;
projectReferences . Should ( ) . BeEmpty ( ) ;
}
2016-10-21 18:00:17 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void TFMSpecificProjectDependenciesAreMigratedToProjectReferenceUnderConditionItemGroup ( )
2016-10-21 18:00:17 -07:00
{
2017-02-15 15:35:03 -08:00
var solutionDirectory = TestAssets . Get ( "TestAppWithLibraryUnderTFM" )
. CreateInstance ( callingMethod : "p" )
. WithSourceFiles ( )
. Root . FullName ;
2016-10-21 18:00:17 -07:00
var appDirectory = Path . Combine ( solutionDirectory , "TestApp" ) ;
2017-03-09 21:17:10 -08:00
var projectContext = ProjectContext . Create ( appDirectory , FrameworkConstants . CommonFrameworks . NetCoreApp11 ) ;
2016-10-21 18:00:17 -07:00
var mockProj = ProjectRootElement . Create ( ) ;
2016-12-07 11:49:15 -10:00
var testSettings = MigrationSettings . CreateMigrationSettingsTestHook ( appDirectory , appDirectory , mockProj , null ) ;
2016-10-21 18:00:17 -07:00
var testInputs = new MigrationRuleInputs ( new [ ] { projectContext } , mockProj , mockProj . AddItemGroup ( ) ,
mockProj . AddPropertyGroup ( ) ) ;
new MigrateProjectDependenciesRule ( ) . Apply ( testSettings , testInputs ) ;
var projectReferences = mockProj . Items . Where ( item = > item . ItemType . Equals ( "ProjectReference" , StringComparison . Ordinal ) ) ;
projectReferences . Count ( ) . Should ( ) . Be ( 1 ) ;
var projectReference = projectReferences . First ( ) ;
projectReference . Include . Should ( ) . Be ( Path . Combine ( ".." , "TestLibrary" , "TestLibrary.csproj" ) ) ;
2017-03-09 21:17:10 -08:00
projectReference . Parent . Condition . Should ( ) . Be ( " '$(TargetFramework)' == 'netcoreapp1.1' " ) ;
2016-08-22 12:24:10 -07:00
}
[Fact]
2016-12-28 14:48:38 -08:00
public void ItThrowsWhenProjectDependencyIsUnresolved ( )
2016-08-22 12:24:10 -07:00
{
// No Lock file => unresolved
2017-02-15 15:35:03 -08:00
var solutionDirectory = TestAssets . Get ( "TestAppWithLibrary" )
. CreateInstance ( )
. WithSourceFiles ( )
. Root . FullName ;
2016-08-22 12:24:10 -07:00
var appDirectory = Path . Combine ( solutionDirectory , "TestApp" ) ;
2016-09-21 21:14:48 -07:00
var libraryDirectory = Path . Combine ( solutionDirectory , "TestLibrary" ) ;
Directory . Delete ( libraryDirectory , true ) ;
2016-08-22 12:24:10 -07:00
2017-03-09 21:17:10 -08:00
var projectContext = ProjectContext . Create ( appDirectory , FrameworkConstants . CommonFrameworks . NetCoreApp11 ) ;
2016-08-22 12:24:10 -07:00
var mockProj = ProjectRootElement . Create ( ) ;
2016-12-07 11:49:15 -10:00
var testSettings = MigrationSettings . CreateMigrationSettingsTestHook ( appDirectory , appDirectory , mockProj ) ;
2016-08-22 12:24:10 -07:00
var testInputs = new MigrationRuleInputs ( new [ ] { projectContext } , mockProj , mockProj . AddItemGroup ( ) , mockProj . AddPropertyGroup ( ) ) ;
Action action = ( ) = > new MigrateProjectDependenciesRule ( ) . Apply ( testSettings , testInputs ) ;
action . ShouldThrow < Exception > ( )
2016-08-23 13:50:05 -07:00
. Where ( e = > e . Message . Contains ( "MIGRATE1014::Unresolved Dependency: Unresolved project dependency (TestLibrary)" ) ) ;
2016-08-22 12:24:10 -07:00
}
2016-09-21 17:27:02 -07:00
[Theory]
[InlineData(@"some/path/to.cSproj", new [] { @"some/path/to.cSproj" } ) ]
[InlineData(@"to.CSPROJ",new [] { @"to.CSPROJ" } ) ]
2016-12-28 14:48:38 -08:00
public void ItMigratesCsprojProjectReferenceInXproj ( string projectReference , string [ ] expectedMigratedReferences )
2016-09-21 17:27:02 -07:00
{
var xproj = ProjectRootElement . Create ( ) ;
xproj . AddItem ( "ProjectReference" , projectReference ) ;
var projectReferenceName = Path . GetFileNameWithoutExtension ( projectReference ) ;
var projectJson = @ "
{
"" dependencies "" : { " +
$"\" { projectReferenceName } \ "" + @ ": {
"" target "" : "" project ""
}
}
}
";
var testDirectory = Temp . CreateDirectory ( ) . Path ;
var migratedProj = TemporaryProjectFileRuleRunner . RunRules ( new IMigrationRule [ ]
{
new MigrateProjectDependenciesRule ( )
} , projectJson , testDirectory , xproj ) ;
var migratedProjectReferenceItems = migratedProj . Items . Where ( i = > i . ItemType = = "ProjectReference" ) ;
migratedProjectReferenceItems . Should ( ) . HaveCount ( expectedMigratedReferences . Length ) ;
migratedProjectReferenceItems . Select ( m = > m . Include ) . Should ( ) . BeEquivalentTo ( expectedMigratedReferences ) ;
}
2016-09-22 12:51:23 -07:00
2016-09-22 14:30:56 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void ItMigratesCsprojProjectReferenceInXprojIncludingConditionOnProjectReference ( )
2016-09-22 12:51:23 -07:00
{
var projectReference = "some/to.csproj" ;
var xproj = ProjectRootElement . Create ( ) ;
var csprojReferenceItem = xproj . AddItem ( "ProjectReference" , projectReference ) ;
csprojReferenceItem . Condition = " '$(Foo)' == 'bar' " ;
var projectReferenceName = Path . GetFileNameWithoutExtension ( projectReference ) ;
var projectJson = @ "
{
"" dependencies "" : { " +
$"\" { projectReferenceName } \ "" + @ ": {
"" target "" : "" project ""
}
}
}
";
var testDirectory = Temp . CreateDirectory ( ) . Path ;
var migratedProj = TemporaryProjectFileRuleRunner . RunRules ( new IMigrationRule [ ]
{
new MigrateProjectDependenciesRule ( )
} , projectJson , testDirectory , xproj ) ;
var migratedProjectReferenceItems = migratedProj . Items . Where ( i = > i . ItemType = = "ProjectReference" ) ;
migratedProjectReferenceItems . Should ( ) . HaveCount ( 1 ) ;
var migratedProjectReferenceItem = migratedProjectReferenceItems . First ( ) ;
migratedProjectReferenceItem . Include . Should ( ) . Be ( projectReference ) ;
migratedProjectReferenceItem . Condition . Should ( ) . Be ( " '$(Foo)' == 'bar' " ) ;
}
2016-09-22 14:30:56 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void ItMigratesCsprojProjectReferenceInXprojIncludingConditionOnProjectReferenceParent ( )
2016-09-22 12:51:23 -07:00
{
var projectReference = "some/to.csproj" ;
var xproj = ProjectRootElement . Create ( ) ;
var csprojReferenceItem = xproj . AddItem ( "ProjectReference" , projectReference ) ;
csprojReferenceItem . Parent . Condition = " '$(Foo)' == 'bar' " ;
var projectReferenceName = Path . GetFileNameWithoutExtension ( projectReference ) ;
var projectJson = @ "
{
"" dependencies "" : { " +
$"\" { projectReferenceName } \ "" + @ ": {
"" target "" : "" project ""
}
}
}
";
var testDirectory = Temp . CreateDirectory ( ) . Path ;
var migratedProj = TemporaryProjectFileRuleRunner . RunRules ( new IMigrationRule [ ]
{
new MigrateProjectDependenciesRule ( )
} , projectJson , testDirectory , xproj ) ;
var migratedProjectReferenceItems = migratedProj . Items . Where ( i = > i . ItemType = = "ProjectReference" ) ;
migratedProjectReferenceItems . Should ( ) . HaveCount ( 1 ) ;
var migratedProjectReferenceItem = migratedProjectReferenceItems . First ( ) ;
migratedProjectReferenceItem . Include . Should ( ) . Be ( projectReference ) ;
migratedProjectReferenceItem . Condition . Should ( ) . Be ( " '$(Foo)' == 'bar' " ) ;
}
2016-09-22 14:30:56 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void ItMigratesCsprojProjectReferenceInXprojIncludingConditionOnProjectReferenceParentAndItem ( )
2016-09-22 12:51:23 -07:00
{
var projectReference = "some/to.csproj" ;
var xproj = ProjectRootElement . Create ( ) ;
var csprojReferenceItem = xproj . AddItem ( "ProjectReference" , projectReference ) ;
csprojReferenceItem . Parent . Condition = " '$(Foo)' == 'bar' " ;
csprojReferenceItem . Condition = " '$(Bar)' == 'foo' " ;
var projectReferenceName = Path . GetFileNameWithoutExtension ( projectReference ) ;
var projectJson = @ "
{
"" dependencies "" : { " +
$"\" { projectReferenceName } \ "" + @ ": {
"" target "" : "" project ""
}
}
}
";
var testDirectory = Temp . CreateDirectory ( ) . Path ;
var migratedProj = TemporaryProjectFileRuleRunner . RunRules ( new IMigrationRule [ ]
{
new MigrateProjectDependenciesRule ( )
} , projectJson , testDirectory , xproj ) ;
var migratedProjectReferenceItems = migratedProj . Items . Where ( i = > i . ItemType = = "ProjectReference" ) ;
migratedProjectReferenceItems . Should ( ) . HaveCount ( 1 ) ;
var migratedProjectReferenceItem = migratedProjectReferenceItems . First ( ) ;
migratedProjectReferenceItem . Include . Should ( ) . Be ( projectReference ) ;
2016-09-22 17:16:37 -07:00
migratedProjectReferenceItem . Condition . Should ( ) . Be ( " '$(Bar)' == 'foo' and '$(Foo)' == 'bar' " ) ;
2016-09-22 12:51:23 -07:00
}
2016-10-27 16:35:35 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void ItDoesNotPromoteP2PReferencesUpInTheDependencyChain ( )
2016-11-01 14:11:11 -07:00
{
var mockProj = MigrateProject ( "TestAppDependencyGraph" , "ProjectA" ) ;
var projectReferences = mockProj . Items . Where (
item = > item . ItemType . Equals ( "ProjectReference" , StringComparison . Ordinal ) ) ;
2016-12-28 14:48:38 -08:00
projectReferences . Count ( ) . Should ( ) . Be ( 2 ) ;
2016-11-01 14:11:11 -07:00
}
2016-11-03 16:54:15 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void ItDoesNotPromoteFrameworkAssembliesFromP2PReferencesUpInTheDependencyChain ( )
2016-11-03 16:54:15 -07:00
{
var solutionDirectory = TestAssets . Get ( TestAssetKinds . DesktopTestProjects , "TestAppWithFrameworkAssemblies" )
. CreateInstance ( )
. WithSourceFiles ( ) . Root ;
var appDirectory = Path . Combine ( solutionDirectory . FullName , "ProjectA" ) ;
var projectContext = ProjectContext . Create ( appDirectory , FrameworkConstants . CommonFrameworks . Net451 ) ;
var mockProj = ProjectRootElement . Create ( ) ;
2016-12-07 11:49:15 -10:00
var testSettings = MigrationSettings . CreateMigrationSettingsTestHook ( appDirectory , appDirectory , mockProj , null ) ;
2016-11-03 16:54:15 -07:00
var testInputs = new MigrationRuleInputs ( new [ ] { projectContext } , mockProj , mockProj . AddItemGroup ( ) ,
mockProj . AddPropertyGroup ( ) ) ;
new MigrateProjectDependenciesRule ( ) . Apply ( testSettings , testInputs ) ;
var frameworkAssemblyReferences = mockProj . Items . Where (
item = > item . ItemType = = "Reference" & &
item . Include = = "System.ComponentModel.DataAnnotations" & &
item . Parent . Condition = = " '$(TargetFramework)' == 'net451' " ) ;
2016-12-28 14:48:38 -08:00
frameworkAssemblyReferences . Count ( ) . Should ( ) . Be ( 0 ) ;
2016-11-03 16:54:15 -07:00
}
2016-11-03 10:27:51 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void NoP2PReferenceIsMarkedWithAFromP2PAttribute ( )
2016-11-03 10:27:51 -07:00
{
var expectedNonHoistedProjectReferences = new [ ] {
Path . Combine ( ".." , "ProjectB" , "ProjectB.csproj" ) ,
Path . Combine ( ".." , "ProjectC" , "ProjectC.csproj" )
} ;
var mockProj = MigrateProject ( "TestAppDependencyGraph" , "ProjectA" ) ;
var projectReferences = mockProj . Items
. Where ( item = >
2016-12-28 14:48:38 -08:00
item . ItemType = = "ProjectReference" ) ;
projectReferences . Should ( ) . HaveCount ( c = > c = = 2 )
. And . OnlyContain ( item = > item . GetMetadataWithName ( "FromP2P" ) = = null ) ;
2016-11-03 10:27:51 -07:00
2016-12-28 14:48:38 -08:00
projectReferences . Select ( i = > i . Include ) . Should ( ) . BeEquivalentTo ( expectedNonHoistedProjectReferences ) ;
2016-11-03 10:27:51 -07:00
}
2016-11-01 14:11:11 -07:00
[Fact]
2016-12-28 14:48:38 -08:00
public void ItMigratesUnqualifiedDependenciesAsProjectReferenceWhenAMatchingProjectIsFound ( )
2016-11-01 14:11:11 -07:00
{
var mockProj = MigrateProject ( "TestAppWithUnqualifiedDependencies" , "ProjectA" ) ;
2017-03-02 21:04:03 -08:00
var projectReferenceInclude = Path . Combine ( ".." , "ProjectB" , "ProjectB.csproj" ) ;
2016-11-01 14:11:11 -07:00
var projectReferences = mockProj . Items . Should ( ) . ContainSingle (
2016-11-01 14:58:11 -07:00
item = > item . ItemType = = "ProjectReference" & & item . Include = = projectReferenceInclude ) ;
2016-11-01 14:11:11 -07:00
}
2017-01-31 15:27:22 -08:00
[Fact]
public void ItDoesNotReferenceTheProjectUnderBackupWhenMigratingAPartiallyMigratedStructure ( )
{
2017-02-15 15:35:03 -08:00
var solutionDirectory = TestAssets . Get ( "NonRestoredTestProjects" , "PJHalfMigrated" )
. CreateInstance ( )
. WithSourceFiles ( )
. Root . FullName ;
2017-01-31 15:27:22 -08:00
var appDirectory = Path . Combine ( solutionDirectory , "ProjectB" ) ;
2017-03-09 21:17:10 -08:00
var projectContext = ProjectContext . Create ( appDirectory , FrameworkConstants . CommonFrameworks . NetCoreApp11 ) ;
2017-01-31 15:27:22 -08:00
var mockProj = ProjectRootElement . Create ( ) ;
var testSettings = MigrationSettings . CreateMigrationSettingsTestHook ( appDirectory , appDirectory , mockProj , null ) ;
var testInputs = new MigrationRuleInputs ( new [ ] { projectContext } , mockProj , mockProj . AddItemGroup ( ) ,
mockProj . AddPropertyGroup ( ) ) ;
new MigrateProjectDependenciesRule ( ) . Apply ( testSettings , testInputs ) ;
var projectReferences = mockProj . Items . Where (
item = > item . ItemType . Equals ( "ProjectReference" , StringComparison . Ordinal ) ) ;
projectReferences . Should ( ) . ContainSingle ( ) ;
2017-01-31 18:53:18 -08:00
projectReferences . Single ( ) . Include . Should ( ) . Be ( Path . Combine ( ".." , "src" , "ProjectA" , "ProjectA.csproj" ) ) ;
2017-01-31 15:27:22 -08:00
}
2016-11-01 14:11:11 -07:00
private ProjectRootElement MigrateProject ( string solution , string project )
2016-11-03 16:54:15 -07:00
{
2017-03-09 21:17:10 -08:00
return MigrateProject ( solution , project , FrameworkConstants . CommonFrameworks . NetCoreApp11 ) ;
2016-11-03 16:54:15 -07:00
}
private ProjectRootElement MigrateProject (
string solution ,
string project ,
NuGetFramework targetFramework )
2016-10-27 16:35:35 -07:00
{
2017-02-15 15:35:03 -08:00
var solutionDirectory = TestAssets . Get ( solution )
. CreateInstance ( callingMethod : "p" )
. WithSourceFiles ( )
. Root . FullName ;
2016-10-27 16:35:35 -07:00
2016-11-01 14:11:11 -07:00
var appDirectory = Path . Combine ( solutionDirectory , project ) ;
2016-10-27 16:35:35 -07:00
2016-11-03 16:54:15 -07:00
var projectContext = ProjectContext . Create ( appDirectory , targetFramework ) ;
2016-10-27 16:35:35 -07:00
var mockProj = ProjectRootElement . Create ( ) ;
2016-12-07 11:49:15 -10:00
var testSettings = MigrationSettings . CreateMigrationSettingsTestHook ( appDirectory , appDirectory , mockProj , null ) ;
2016-10-27 16:35:35 -07:00
var testInputs = new MigrationRuleInputs ( new [ ] { projectContext } , mockProj , mockProj . AddItemGroup ( ) ,
mockProj . AddPropertyGroup ( ) ) ;
new MigrateProjectDependenciesRule ( ) . Apply ( testSettings , testInputs ) ;
2016-11-01 14:11:11 -07:00
var s = mockProj . Items . Select ( p = > $"ItemType = {p.ItemType}, Include = {p.Include}" ) ;
Console . WriteLine ( string . Join ( Environment . NewLine , s ) ) ;
return mockProj ;
2016-10-27 16:35:35 -07:00
}
2016-08-22 12:24:10 -07:00
}
}