2016-02-03 18:57:25 +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.
2016-04-15 21:45:51 +00:00
using System ;
2016-02-03 18:57:25 +00:00
using System.IO ;
using System.Linq ;
2016-02-23 17:03:04 +00:00
using System.Runtime.InteropServices ;
2016-02-03 18:57:25 +00:00
using FluentAssertions ;
2016-04-28 23:30:32 +00:00
using Microsoft.DotNet.InternalAbstractions ;
2016-02-03 18:57:25 +00:00
using Microsoft.DotNet.ProjectModel ;
using Microsoft.DotNet.Tools.Test.Utilities ;
2016-04-15 21:45:51 +00:00
using Newtonsoft.Json.Linq ;
2016-02-23 14:53:51 +00:00
using NuGet.Frameworks ;
2016-02-03 18:57:25 +00:00
using Xunit ;
namespace Microsoft.DotNet.Tools.Builder.Tests
{
public class BuildOutputTests : TestBase
{
2016-02-11 22:17:20 +00:00
private string _testProjectsRoot ;
private string _runtime ;
private DirectoryInfo _rootDirInfo ;
private DirectoryInfo _testAppDirDirInfo ;
private DirectoryInfo _testLibDirInfo ;
2016-02-03 18:57:25 +00:00
private readonly string [ ] _runtimeFiles =
{
"TestApp" + FileNameSuffixes . DotNet . DynamicLib ,
"TestApp" + FileNameSuffixes . DotNet . ProgramDatabase ,
"TestApp" + FileNameSuffixes . CurrentPlatform . Exe ,
2016-03-09 00:46:50 +00:00
"TestApp" + FileNameSuffixes . DepsJson ,
2016-04-11 18:01:41 +00:00
"TestApp" + FileNameSuffixes . RuntimeConfigJson ,
2016-02-03 18:57:25 +00:00
"TestLibrary" + FileNameSuffixes . DotNet . DynamicLib ,
"TestLibrary" + FileNameSuffixes . DotNet . ProgramDatabase
} ;
2016-04-11 18:01:41 +00:00
private readonly string [ ] _runtimeExcludeFiles =
{
"TestLibrary" + FileNameSuffixes . RuntimeConfigJson ,
"TestLibrary" + FileNameSuffixes . RuntimeConfigDevJson
} ;
2016-02-03 18:57:25 +00:00
private readonly string [ ] _appCompileFiles =
{
"TestApp" + FileNameSuffixes . DotNet . DynamicLib ,
"TestApp" + FileNameSuffixes . DotNet . ProgramDatabase
} ;
2016-04-11 18:01:41 +00:00
2016-02-03 18:57:25 +00:00
private readonly string [ ] _libCompileFiles =
{
"TestLibrary" + FileNameSuffixes . DotNet . DynamicLib ,
2016-03-09 19:36:16 +00:00
"TestLibrary" + FileNameSuffixes . DotNet . ProgramDatabase
2016-02-03 18:57:25 +00:00
} ;
2016-04-11 18:01:41 +00:00
private readonly string [ ] _libCompileExcludeFiles =
{
"TestLibrary" + FileNameSuffixes . RuntimeConfigJson ,
"TestLibrary" + FileNameSuffixes . RuntimeConfigDevJson
} ;
2016-02-11 22:17:20 +00:00
private void GetProjectInfo ( string testRoot )
2016-02-03 18:57:25 +00:00
{
2016-02-11 22:17:20 +00:00
_testProjectsRoot = testRoot ;
_rootDirInfo = new DirectoryInfo ( _testProjectsRoot ) ;
_testAppDirDirInfo = new DirectoryInfo ( Path . Combine ( _testProjectsRoot , "TestApp" ) ) ;
_testLibDirInfo = new DirectoryInfo ( Path . Combine ( _testProjectsRoot , "TestLibrary" ) ) ;
2016-02-03 18:57:25 +00:00
var contexts = ProjectContext . CreateContextForEachFramework (
2016-02-11 22:17:20 +00:00
_testAppDirDirInfo . FullName ,
2016-02-03 18:57:25 +00:00
null ,
2016-04-28 23:30:32 +00:00
RuntimeEnvironmentRidExtensions . GetAllCandidateRuntimeIdentifiers ( ) ) ;
2016-02-11 22:17:20 +00:00
_runtime = contexts . FirstOrDefault ( c = > ! string . IsNullOrEmpty ( c . RuntimeIdentifier ) ) ? . RuntimeIdentifier ;
2016-02-03 18:57:25 +00:00
}
private string FormatPath ( string input , string framework , string runtime )
{
return input . Replace ( "{fw}" , framework ) . Replace ( "{rid}" , runtime ) ;
}
[Theory]
// global.json exists
2016-02-11 23:55:37 +00:00
[InlineData("1", true, null, null, "TestLibrary/bin/Debug/{fw}", "TestApp/bin/Debug/{fw}", "TestApp/bin/Debug/{fw}/{rid}")]
[InlineData("2", true, "out", null, "TestLibrary/bin/Debug/{fw}", "TestApp/bin/Debug/{fw}", "out")]
[InlineData("3", true, null, "build", "build/TestLibrary/bin/Debug/{fw}", "build/TestApp/bin/Debug/{fw}", "build/TestApp/bin/Debug/{fw}/{rid}")]
[InlineData("4", true, "out", "build", "build/TestLibrary/bin/Debug/{fw}", "build/TestApp/bin/Debug/{fw}", "out")]
2016-02-03 18:57:25 +00:00
//no global.json
2016-02-11 22:17:20 +00:00
//[InlineData(false, null, null, "TestLibrary/bin/debug/{fw}", "TestApp/bin/debug/{fw}", "TestApp/bin/debug/{fw}/{rid}")]
//[InlineData(false, "out", null, "TestLibrary/bin/debug/{fw}", "TestApp/bin/debug/{fw}", "out")]
2016-02-03 18:57:25 +00:00
//[InlineData(false, null, "build", "build/TestLibrary/bin/debug/{fw}", "build/TestApp/bin/debug/{fw}", "build/TestApp/bin/debug/{fw}/{rid}")]
//[InlineData(false, "out", "build", "build/TestLibrary/bin/debug/{fw}", "build/TestApp/bin/debug/{fw}", "out")]
2016-04-11 18:01:41 +00:00
public void AppDefaultPaths ( string testIdentifer , bool global , string outputValue , string baseValue , string expectedLibCompile , string expectedAppCompile , string expectedAppRuntime )
2016-02-03 18:57:25 +00:00
{
2016-02-11 23:55:37 +00:00
var testInstance = TestAssetsManager . CreateTestInstance ( "TestAppWithLibrary" , identifier : testIdentifer )
2016-02-11 22:17:20 +00:00
. WithLockFiles ( ) ;
GetProjectInfo ( testInstance . TestRoot ) ;
2016-02-03 18:57:25 +00:00
2016-02-11 22:17:20 +00:00
new BuildCommand ( GetProjectPath ( _testAppDirDirInfo ) ,
output : outputValue ! = null ? Path . Combine ( _testProjectsRoot , outputValue ) : string . Empty ,
2016-04-11 18:01:41 +00:00
buildBasePath : baseValue ! = null ? Path . Combine ( _testProjectsRoot , baseValue ) : string . Empty ,
2016-02-03 18:57:25 +00:00
framework : DefaultFramework )
. ExecuteWithCapturedOutput ( ) . Should ( ) . Pass ( ) ;
2016-04-13 00:29:07 +00:00
var libdebug = _rootDirInfo . Sub ( FormatPath ( expectedLibCompile , DefaultLibraryFramework , _runtime ) ) ;
2016-02-11 22:17:20 +00:00
var appdebug = _rootDirInfo . Sub ( FormatPath ( expectedAppCompile , DefaultFramework , _runtime ) ) ;
var appruntime = _rootDirInfo . Sub ( FormatPath ( expectedAppRuntime , DefaultFramework , _runtime ) ) ;
2016-02-03 18:57:25 +00:00
2016-04-11 18:01:41 +00:00
libdebug . Should ( ) . Exist ( )
. And . HaveFiles ( _libCompileFiles )
. And . NotHaveFiles ( _libCompileExcludeFiles ) ;
2016-02-03 18:57:25 +00:00
appdebug . Should ( ) . Exist ( ) . And . HaveFiles ( _appCompileFiles ) ;
2016-04-11 18:01:41 +00:00
appruntime . Should ( ) . Exist ( )
. And . HaveFiles ( _runtimeFiles )
. And . NotHaveFiles ( _runtimeExcludeFiles ) ;
}
[Theory]
[InlineData("1", true, null, null, "TestLibrary/bin/Debug/{fw}", "TestLibrary/bin/Debug/{fw}/{rid}")]
[InlineData("2", true, "out", null, "TestLibrary/bin/Debug/{fw}", "out")]
[InlineData("3", true, null, "build", "build/TestLibrary/bin/Debug/{fw}", "build/TestLibrary/bin/Debug/{fw}/{rid}")]
[InlineData("4", true, "out", "build", "build/TestLibrary/bin/Debug/{fw}", "out")]
public void LibDefaultPaths ( string testIdentifer , bool global , string outputValue , string baseValue , string expectedLibCompile , string expectedLibOutput )
{
var testInstance = TestAssetsManager . CreateTestInstance ( "TestAppWithLibrary" , identifier : testIdentifer )
. WithLockFiles ( ) ;
GetProjectInfo ( testInstance . TestRoot ) ;
new BuildCommand ( GetProjectPath ( _testLibDirInfo ) ,
output : outputValue ! = null ? Path . Combine ( _testProjectsRoot , outputValue ) : string . Empty ,
buildBasePath : baseValue ! = null ? Path . Combine ( _testProjectsRoot , baseValue ) : string . Empty ,
2016-04-13 00:29:07 +00:00
framework : DefaultLibraryFramework )
2016-04-11 18:01:41 +00:00
. ExecuteWithCapturedOutput ( ) . Should ( ) . Pass ( ) ;
2016-04-13 00:29:07 +00:00
var libdebug = _rootDirInfo . Sub ( FormatPath ( expectedLibCompile , DefaultLibraryFramework , _runtime ) ) ;
2016-04-11 18:01:41 +00:00
libdebug . Should ( ) . Exist ( )
. And . HaveFiles ( _libCompileFiles )
. And . NotHaveFiles ( _libCompileExcludeFiles ) ;
2016-02-03 18:57:25 +00:00
}
2016-02-18 09:09:23 +00:00
[Fact]
2016-02-18 09:12:24 +00:00
public void SettingVersionInEnvironment_ShouldStampAssemblyInfoInOutputAssembly ( )
2016-02-18 09:09:23 +00:00
{
var testInstance = TestAssetsManager . CreateTestInstance ( "TestLibraryWithConfiguration" )
. WithLockFiles ( ) ;
2016-04-13 00:29:07 +00:00
var cmd = new BuildCommand ( Path . Combine ( testInstance . TestRoot , Project . FileName ) , framework : DefaultLibraryFramework ) ;
2016-02-18 09:09:23 +00:00
cmd . Environment [ "DOTNET_BUILD_VERSION" ] = "85" ;
cmd . Environment [ "DOTNET_ASSEMBLY_FILE_VERSION" ] = "345" ;
cmd . ExecuteWithCapturedOutput ( ) . Should ( ) . Pass ( ) ;
2016-04-13 00:29:07 +00:00
var output = Path . Combine ( testInstance . TestRoot , "bin" , "Debug" , DefaultLibraryFramework , "TestLibraryWithConfiguration.dll" ) ;
2016-02-18 09:09:23 +00:00
var informationalVersion = PeReaderUtils . GetAssemblyAttributeValue ( output , "AssemblyInformationalVersionAttribute" ) ;
var fileVersion = PeReaderUtils . GetAssemblyAttributeValue ( output , "AssemblyFileVersionAttribute" ) ;
informationalVersion . Should ( ) . NotBeNull ( ) ;
informationalVersion . Should ( ) . BeEquivalentTo ( "1.0.0-85" ) ;
fileVersion . Should ( ) . NotBeNull ( ) ;
fileVersion . Should ( ) . BeEquivalentTo ( "1.0.0.345" ) ;
}
2016-03-09 19:36:16 +00:00
2016-02-18 09:09:23 +00:00
[Fact]
2016-02-18 09:12:24 +00:00
public void SettingVersionSuffixFlag_ShouldStampAssemblyInfoInOutputAssembly ( )
2016-02-18 09:09:23 +00:00
{
var testInstance = TestAssetsManager . CreateTestInstance ( "TestLibraryWithConfiguration" )
. WithLockFiles ( ) ;
2016-04-13 00:29:07 +00:00
var cmd = new BuildCommand ( Path . Combine ( testInstance . TestRoot , Project . FileName ) , framework : DefaultLibraryFramework , versionSuffix : "85" ) ;
2016-02-18 09:09:23 +00:00
cmd . ExecuteWithCapturedOutput ( ) . Should ( ) . Pass ( ) ;
2016-04-13 00:29:07 +00:00
var output = Path . Combine ( testInstance . TestRoot , "bin" , "Debug" , DefaultLibraryFramework , "TestLibraryWithConfiguration.dll" ) ;
2016-02-18 09:09:23 +00:00
var informationalVersion = PeReaderUtils . GetAssemblyAttributeValue ( output , "AssemblyInformationalVersionAttribute" ) ;
informationalVersion . Should ( ) . NotBeNull ( ) ;
informationalVersion . Should ( ) . BeEquivalentTo ( "1.0.0-85" ) ;
}
2016-02-23 14:53:51 +00:00
[Theory]
2016-04-28 23:30:32 +00:00
// [InlineData("net20", false, true)]
// [InlineData("net40", true, true)]
// [InlineData("net461", true, true)]
2016-04-13 00:29:07 +00:00
[InlineData("netstandard1.5", true, false)]
2016-02-23 17:03:04 +00:00
public void MultipleFrameworks_ShouldHaveValidTargetFrameworkAttribute ( string frameworkName , bool shouldHaveTargetFrameworkAttribute , bool windowsOnly )
2016-02-23 14:53:51 +00:00
{
var framework = NuGetFramework . Parse ( frameworkName ) ;
var testInstance = TestAssetsManager . CreateTestInstance ( "TestLibraryWithMultipleFrameworks" )
. WithLockFiles ( ) ;
var cmd = new BuildCommand ( Path . Combine ( testInstance . TestRoot , Project . FileName ) , framework : framework . GetShortFolderName ( ) ) ;
2016-02-24 13:19:21 +00:00
if ( windowsOnly & & ! RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
2016-02-23 14:53:51 +00:00
{
2016-02-24 13:19:21 +00:00
// on non-windows platforms, desktop frameworks will not build
cmd . ExecuteWithCapturedOutput ( ) . Should ( ) . Fail ( ) ;
2016-02-23 14:53:51 +00:00
}
else
{
2016-02-24 13:19:21 +00:00
cmd . ExecuteWithCapturedOutput ( ) . Should ( ) . Pass ( ) ;
var output = Path . Combine ( testInstance . TestRoot , "bin" , "Debug" , framework . GetShortFolderName ( ) , "TestLibraryWithMultipleFrameworks.dll" ) ;
var targetFramework = PeReaderUtils . GetAssemblyAttributeValue ( output , "TargetFrameworkAttribute" ) ;
if ( shouldHaveTargetFrameworkAttribute )
{
targetFramework . Should ( ) . NotBeNull ( ) ;
targetFramework . Should ( ) . BeEquivalentTo ( framework . DotNetFrameworkName ) ;
}
else
{
targetFramework . Should ( ) . BeNull ( ) ;
}
2016-02-23 14:53:51 +00:00
}
}
2016-04-28 17:02:05 +00:00
[Fact]
public void UnresolvedReferenceCausesBuildToFailAndNotProduceOutput ( )
{
var testAssetsManager = GetTestGroupTestAssetsManager ( "NonRestoredTestProjects" ) ;
var testInstance = testAssetsManager . CreateTestInstance ( "TestProjectWithUnresolvedDependency" )
. WithLockFiles ( ) ;
var restoreResult = new RestoreCommand ( ) { WorkingDirectory = testInstance . TestRoot } . Execute ( ) ;
restoreResult . Should ( ) . Fail ( ) ;
new DirectoryInfo ( testInstance . TestRoot ) . Should ( ) . HaveFile ( "project.lock.json" ) ;
var buildCmd = new BuildCommand ( testInstance . TestRoot ) ;
var buildResult = buildCmd . ExecuteWithCapturedOutput ( ) ;
buildResult . Should ( ) . Fail ( ) ;
buildResult . StdErr . Should ( ) . Contain ( "The dependency ThisIsNotARealDependencyAndIfSomeoneGoesAndAddsAProjectWithThisNameIWillFindThemAndPunishThem could not be resolved." ) ;
var outputDir = new DirectoryInfo ( Path . Combine ( testInstance . TestRoot , "bin" , "Debug" , "netcoreapp1.0" ) ) ;
outputDir . GetFiles ( ) . Length . Should ( ) . Be ( 0 ) ;
}
2016-04-15 21:45:51 +00:00
[Fact]
public void PackageReferenceWithResourcesTest ( )
{
var testInstance = TestAssetsManager . CreateTestInstance ( "ResourcesTests" )
. WithLockFiles ( ) ;
var projectRoot = Path . Combine ( testInstance . TestRoot , "TestApp" ) ;
var cmd = new BuildCommand ( projectRoot ) ;
var result = cmd . Execute ( ) ;
result . Should ( ) . Pass ( ) ;
var outputDir = new DirectoryInfo ( Path . Combine ( projectRoot , "bin" , "Debug" , "netcoreapp1.0" ) ) ;
outputDir . Should ( ) . HaveFile ( "TestLibraryWithResources.dll" ) ;
outputDir . Sub ( "fr" ) . Should ( ) . HaveFile ( "TestLibraryWithResources.resources.dll" ) ;
var depsJson = JObject . Parse ( File . ReadAllText ( Path . Combine ( outputDir . FullName , $"{Path.GetFileNameWithoutExtension(cmd.GetOutputExecutableName())}.deps.json" ) ) ) ;
foreach ( var library in new [ ] { Tuple . Create ( "Microsoft.Data.OData" , "5.6.4" ) , Tuple . Create ( "TestLibraryWithResources" , "1.0.0" ) } )
{
var resources = depsJson [ "targets" ] [ ".NETCoreApp,Version=v1.0" ] [ library . Item1 + "/" + library . Item2 ] [ "resources" ] ;
resources . Should ( ) . NotBeNull ( ) ;
foreach ( var item in resources . Children < JProperty > ( ) )
{
var locale = item . Value [ "locale" ] ;
locale . Should ( ) . NotBeNull ( ) ;
item . Name . Should ( ) . EndWith ( $"{locale}/{library.Item1}.resources.dll" ) ;
}
}
}
2016-02-03 18:57:25 +00:00
[Fact]
public void ResourceTest ( )
{
2016-02-11 23:55:37 +00:00
var testInstance = TestAssetsManager . CreateTestInstance ( "TestAppWithLibrary" )
. WithLockFiles ( ) ;
GetProjectInfo ( testInstance . TestRoot ) ;
2016-02-03 18:57:25 +00:00
var names = new [ ]
{
"uk-UA" ,
"en" ,
"en-US"
} ;
2016-02-11 22:17:20 +00:00
foreach ( var folder in new [ ] { _testAppDirDirInfo , _testLibDirInfo } )
2016-02-03 18:57:25 +00:00
{
foreach ( var name in names )
{
2016-02-11 22:17:20 +00:00
var resourceFile = Path . Combine ( folder . FullName , $"Resource.{name}.resx" ) ;
File . WriteAllText ( resourceFile , "<root></root>" ) ;
2016-02-03 18:57:25 +00:00
}
}
2016-02-11 22:17:20 +00:00
new BuildCommand ( GetProjectPath ( _testAppDirDirInfo ) , framework : DefaultFramework )
2016-02-03 18:57:25 +00:00
. ExecuteWithCapturedOutput ( ) . Should ( ) . Pass ( ) ;
2016-04-13 00:29:07 +00:00
var libdebug = _testLibDirInfo . Sub ( "bin/Debug" ) . Sub ( DefaultLibraryFramework ) ;
2016-02-11 22:17:20 +00:00
var appdebug = _testAppDirDirInfo . Sub ( "bin/Debug" ) . Sub ( DefaultFramework ) ;
var appruntime = appdebug . Sub ( _runtime ) ;
2016-02-03 18:57:25 +00:00
foreach ( var name in names )
{
libdebug . Sub ( name ) . Should ( ) . Exist ( ) . And . HaveFile ( "TestLibrary.resources.dll" ) ;
appdebug . Sub ( name ) . Should ( ) . Exist ( ) . And . HaveFile ( "TestApp.resources.dll" ) ;
2016-02-11 22:17:20 +00:00
appruntime . Sub ( name ) . Should ( ) . Exist ( ) . And . HaveFiles ( new [ ] { "TestLibrary.resources.dll" , "TestApp.resources.dll" } ) ;
2016-02-03 18:57:25 +00:00
}
}
2016-04-29 22:54:47 +00:00
[Fact]
2016-05-03 18:33:13 +00:00
private void StandaloneApp_WithoutCoreClrDll_Fails ( )
2016-04-29 22:54:47 +00:00
{
// Convert a Portable App to Standalone to simulate the customer scenario
var testInstance = TestAssetsManager . CreateTestInstance ( "DependencyChangeTest" )
. WithLockFiles ( ) ;
// Convert the portable test project to standalone by removing "type": "platform" and adding rids
var originalTestProject = Path . Combine ( testInstance . TestRoot , "PortableApp_Standalone" , "project.json" ) ;
var modifiedTestProject = Path . Combine ( testInstance . TestRoot , "PortableApp_Standalone" , "project.json.modified" ) ;
// Simulate a user editting the project.json
File . Delete ( originalTestProject ) ;
File . Copy ( modifiedTestProject , originalTestProject ) ;
var buildResult = new BuildCommand ( originalTestProject , framework : DefaultFramework )
. ExecuteWithCapturedOutput ( ) ;
buildResult . Should ( ) . Fail ( ) ;
2016-05-03 18:33:13 +00:00
buildResult . StdErr . Should ( ) . Contain ( "Expected coreclr library not found in package graph. Please try running dotnet restore again." ) ;
2016-04-29 22:54:47 +00:00
}
2016-02-03 18:57:25 +00:00
private void CopyProjectToTempDir ( string projectDir , TempDirectory tempDir )
{
// copy all the files to temp dir
foreach ( var file in Directory . EnumerateFiles ( projectDir ) )
{
tempDir . CopyFile ( file ) ;
}
}
2016-02-11 22:17:20 +00:00
private string GetProjectPath ( DirectoryInfo projectDir )
2016-02-03 18:57:25 +00:00
{
2016-02-11 22:17:20 +00:00
return Path . Combine ( projectDir . FullName , "project.json" ) ;
2016-02-03 18:57:25 +00:00
}
}
}