Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ protected CreateManifestResourceName() { }
[Microsoft.Build.Framework.OutputAttribute]
public Microsoft.Build.Framework.ITaskItem[] ResourceFilesWithManifestResourceNames { get { throw null; } set { } }
public string RootNamespace { get { throw null; } set { } }
public bool UseDependentUponConvention { get { throw null; } set { } }
protected abstract string CreateManifestName(string fileName, string linkFileName, string rootNamespaceName, string dependentUponFileName, System.IO.Stream binaryStream);
public override bool Execute() { throw null; }
protected abstract bool IsSourceFile(string fileName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ protected CreateManifestResourceName() { }
[Microsoft.Build.Framework.OutputAttribute]
public Microsoft.Build.Framework.ITaskItem[] ResourceFilesWithManifestResourceNames { get { throw null; } set { } }
public string RootNamespace { get { throw null; } set { } }
public bool UseDependentUponConvention { get { throw null; } set { } }
protected abstract string CreateManifestName(string fileName, string linkFileName, string rootNamespaceName, string dependentUponFileName, System.IO.Stream binaryStream);
public override bool Execute() { throw null; }
protected abstract bool IsSourceFile(string fileName);
Expand Down
138 changes: 138 additions & 0 deletions src/Tasks.UnitTests/CreateCSharpManifestResourceName_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@
using Microsoft.Build.Shared;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using Shouldly;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Build.UnitTests
{
sealed public class CreateCSharpManifestResourceName_Tests
{

private readonly ITestOutputHelper _testOutput;

public CreateCSharpManifestResourceName_Tests(ITestOutputHelper output)
{
_testOutput = output;
}
/// <summary>
/// Test the basic functionality.
/// </summary>
Expand Down Expand Up @@ -377,6 +386,135 @@ public void Regress188319()
Assert.Equal(@"CustomToolTest.SR1", resourceNames[0].ItemSpec);
}

/// <summary>
/// Opt into DependentUpon convention and load the expected file properly.
/// </summary>
[Fact]
public void DependentUponConvention_FindsMatch()
{
using (var env = TestEnvironment.Create())
{
var csFile = env.CreateFile("SR1.cs", "namespace MyStuff.Namespace { class Class { } }");
var resXFile = env.CreateFile("SR1.resx", "");

ITaskItem i = new TaskItem(resXFile.Path);
i.SetMetadata("BuildAction", "EmbeddedResource");
// Don't set DependentUpon so it goes by convention

CreateCSharpManifestResourceName t = new CreateCSharpManifestResourceName
{
BuildEngine = new MockEngine(_testOutput),
UseDependentUponConvention = true,
ResourceFiles = new ITaskItem[] { i }
};

t.Execute().ShouldBeTrue("Expected the task to succeed.");

t.ManifestResourceNames.ShouldHaveSingleItem();

t.ManifestResourceNames[0].ItemSpec.ShouldBe("MyStuff.Namespace.Class", "Expecting to find the namespace & class name from SR1.cs");
}
}

/// <summary>
/// Opt into DependentUpon convention without creating the equivalent .cs file for our resource file.
/// </summary>
[Fact]
public void DependentUpon_UseConventionFileDoesNotExist()
{
using (var env = TestEnvironment.Create())
{
// cs file doesn't exist for this case.
var resXFile = env.CreateFile("SR1.resx", "");

ITaskItem i = new TaskItem(Path.GetFileName(resXFile.Path));
i.SetMetadata("BuildAction", "EmbeddedResource");
// Don't set DependentUpon so it goes by convention

// Use relative paths to ensure short manifest name based on the path to the resx.
// See CreateManifestNameImpl
env.SetCurrentDirectory(Path.GetDirectoryName(resXFile.Path));

CreateCSharpManifestResourceName t = new CreateCSharpManifestResourceName
{
BuildEngine = new MockEngine(_testOutput),
UseDependentUponConvention = true,
ResourceFiles = new ITaskItem[] { i }
};

t.Execute().ShouldBeTrue("Expected the task to succeed.");

t.ManifestResourceNames.ShouldHaveSingleItem();

t.ManifestResourceNames[0].ItemSpec.ShouldBe("SR1", "Expected only the file name.");
}
}

/// <summary>
/// Opt into DependentUponConvention, but include DependentUpon metadata with different name.
/// </summary>
[Fact]
public void DependentUpon_SpecifyNewFile()
{
using (var env = TestEnvironment.Create())
{
var conventionCSFile = env.CreateFile("SR1.cs", "namespace MyStuff.Namespace { class Class { } }");
var nonConventionCSFile = env.CreateFile("SR2.cs", "namespace MyStuff2.Namespace { class Class2 { } }");
var resXFile = env.CreateFile("SR1.resx", "");

ITaskItem i = new TaskItem(resXFile.Path);
i.SetMetadata("BuildAction", "EmbeddedResource");
i.SetMetadata("DependentUpon", "SR2.cs");

CreateCSharpManifestResourceName t = new CreateCSharpManifestResourceName
{
BuildEngine = new MockEngine(_testOutput),
UseDependentUponConvention = true,
ResourceFiles = new ITaskItem[] { i }
};

t.Execute().ShouldBeTrue("Expected the task to succeed.");

t.ManifestResourceNames.ShouldHaveSingleItem();

t.ManifestResourceNames[0].ItemSpec.ShouldBe("MyStuff2.Namespace.Class2", "Expected the namespace & class of SR2.");
}
}

/// <summary>
/// When disabling UseDependentUponConvention it will find no .cs file and default to filename.
/// </summary>
[Fact]
public void DependentUponConvention_ConventionDisabledDoesNotReadConventionFile()
{
using (var env = TestEnvironment.Create())
{
var csFile = env.CreateFile("SR1.cs", "namespace MyStuff.Namespace { class Class { } }");
var resXFile = env.CreateFile("SR1.resx", "");

ITaskItem i = new TaskItem(Path.GetFileName(resXFile.Path));
i.SetMetadata("BuildAction", "EmbeddedResource");
// No need to set DependentUpon

// Use relative paths to ensure short manifest name based on the path to the resx.
// See CreateManifestNameImpl
env.SetCurrentDirectory(Path.GetDirectoryName(resXFile.Path));

CreateCSharpManifestResourceName t = new CreateCSharpManifestResourceName
{
BuildEngine = new MockEngine(_testOutput),
UseDependentUponConvention = false,
ResourceFiles = new ITaskItem[] { i }
};

t.Execute().ShouldBeTrue("Expected the task to succeed.");

t.ManifestResourceNames.ShouldHaveSingleItem();

t.ManifestResourceNames[0].ItemSpec.ShouldBe("SR1", "Expected only the file name.");
}
}

/// <summary>
/// helper method for verifying manifest resource names
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Tasks/CreateCSharpManifestResourceName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ namespace Microsoft.Build.Tasks
/// </summary>
public class CreateCSharpManifestResourceName : CreateManifestResourceName
{
internal override string SourceFileExtension => ".cs";

/// <summary>
/// Utility function for creating a C#-style manifest name from
/// a resource name.
Expand Down
15 changes: 15 additions & 0 deletions src/Tasks/CreateManifestResourceName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public abstract class CreateManifestResourceName : TaskExtension
/// </summary>
public bool PrependCultureAsDirectory { get; set; } = true;

public bool UseDependentUponConvention { get; set; }

internal abstract string SourceFileExtension { get; }

/// <summary>
/// The possibly dependent resource files.
/// </summary>
Expand Down Expand Up @@ -142,6 +146,17 @@ CreateFileStream createFileStream
string fileName = resourceFile.ItemSpec;
string dependentUpon = resourceFile.GetMetadata(ItemMetadataNames.dependentUpon);

// If opted into convention and no DependentUpon metadata, reference "<filename>.cs" if it exists.
if (UseDependentUponConvention && string.IsNullOrEmpty(dependentUpon))
{
string conventionDependentUpon = Path.ChangeExtension(fileName, SourceFileExtension);

if (File.Exists(conventionDependentUpon))
{
dependentUpon = conventionDependentUpon;
}
}

// Pre-log some information.
bool isDependentOnSourceFile = !string.IsNullOrEmpty(dependentUpon) && IsSourceFile(dependentUpon);

Expand Down
2 changes: 2 additions & 0 deletions src/Tasks/CreateVisualBasicManifestResourceName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ namespace Microsoft.Build.Tasks
/// </summary>
public class CreateVisualBasicManifestResourceName : CreateManifestResourceName
{
internal override string SourceFileExtension => ".vb";

/// <summary>
/// Utility function for creating a VB-style manifest name from
/// a resource name.
Expand Down
4 changes: 3 additions & 1 deletion src/Tasks/Microsoft.CSharp.CurrentVersion.targets
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<!-- Create manifest names for culture and non-culture Resx files, and for non-culture Non-Resx resources -->
<CreateCSharpManifestResourceName
ResourceFiles="@(EmbeddedResource)"
RootNamespace="$(RootNamespace)"
RootNamespace="$(RootNamespace)"
UseDependentUponConvention="$(EmbeddedResourceUseDependentUponConvention)"
Condition="'%(EmbeddedResource.ManifestResourceName)' == '' and ('%(EmbeddedResource.WithCulture)' == 'false' or '%(EmbeddedResource.Type)' == 'Resx')">

<Output TaskParameter="ResourceFilesWithManifestResourceNames" ItemName="_Temporary" />
Expand All @@ -111,6 +112,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
ResourceFiles="@(EmbeddedResource)"
RootNamespace="$(RootNamespace)"
PrependCultureAsDirectory="false"
UseDependentUponConvention="$(EmbeddedResourceUseDependentUponConvention)"
Condition="'%(EmbeddedResource.ManifestResourceName)' == '' and '%(EmbeddedResource.WithCulture)' == 'true' and '%(EmbeddedResource.Type)' == 'Non-Resx'">

<Output TaskParameter="ResourceFilesWithManifestResourceNames" ItemName="_Temporary" />
Expand Down
4 changes: 3 additions & 1 deletion src/Tasks/Microsoft.VisualBasic.CurrentVersion.targets
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<CreateVisualBasicManifestResourceName
ResourceFiles="@(EmbeddedResource)"
RootNamespace="$(RootNamespace)"
UseDependentUponConvention="$(EmbeddedResourceUseDependentUponConvention)"
Condition="'%(EmbeddedResource.ManifestResourceName)' == '' and ('%(EmbeddedResource.WithCulture)' == 'false' or '%(EmbeddedResource.Type)' == 'Resx')">

<Output TaskParameter="ResourceFilesWithManifestResourceNames" ItemName="_Temporary" />
Expand All @@ -110,7 +111,8 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<CreateVisualBasicManifestResourceName
ResourceFiles="@(EmbeddedResource)"
RootNamespace="$(RootNamespace)"
PrependCultureAsDirectory="false"
PrependCultureAsDirectory="false"
UseDependentUponConvention="$(EmbeddedResourceUseDependentUponConvention)"
Condition="'%(EmbeddedResource.ManifestResourceName)' == '' and '%(EmbeddedResource.WithCulture)' == 'true' and '%(EmbeddedResource.Type)' == 'Non-Resx'">

<Output TaskParameter="ResourceFilesWithManifestResourceNames" ItemName="_Temporary" />
Expand Down