Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluate OutputFileName and OutputDirectory Item Metadata #197

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
33 changes: 33 additions & 0 deletions .devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
{
"name": "t4 DevEnv",
// Use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"build": {
"dockerfile": "Dockerfile"
},

// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "sudo pwsh -Command \"Install-Module -Name PSScriptAnalyzer -Force -Scope AllUsers\"",

// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"streetsidesoftware.code-spell-checker",
"DavidAnson.vscode-markdownlint",
"ms-dotnettools.csdevkit",
"EditorConfig.EditorConfig"
]
}
}

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# syntax=docker/dockerfile:1

ARG DOTNET_VERSION=7.0
ARG DEBIAN_VERSION=bookworm

FROM mcr.microsoft.com/devcontainers/dotnet:1-${DOTNET_VERSION}-${DEBIAN_VERSION}

RUN <<EOT
set -eu

DEBIAN_FRONTEND=noninteractive

apt-get update
apt-get install -y \
dos2unix

apt-get autoremove -y
apt-get clean
rm -rf /var/lib/apt/lists/*
EOT

ENTRYPOINT ["/bin/bash"]
204 changes: 173 additions & 31 deletions Mono.TextTemplating.Build.Tests/MSBuildExecutionTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Linq;
using Xunit;

Expand All @@ -10,108 +11,249 @@ namespace Mono.TextTemplating.Tests
[CollectionDefinition (nameof (MSBuildExecutionTests), DisableParallelization = true)]
public class MSBuildExecutionTests : IClassFixture<MSBuildFixture>
{
[Fact]
public void TransformExplicitWithArguments ()
[Theory]
[InlineData ("TransformTemplates", "foo.txt", "Hello 2019!")]
[InlineData ("TransformTemplateFromRelativePath", "Nested/Template/Folder/foo.txt", "Hello 2024!")]
[InlineData ("TransformTemplateWithExtension", "foo.html", "<h1>Hello 2024!</h1>")]
public void TransformExplicitWithArguments (string projectName, string expectedFilePath, string expectedText)
{
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("TransformTemplates");
var project = ctx.LoadTestProject (projectName);

var instance = project.Build ("TransformTemplates");

var generated = project.DirectoryPath["foo.txt"].AssertTextStartsWith ("Hello 2019!");
var generated = project.DirectoryPath[expectedFilePath].AssertTextStartsWith (expectedText);

instance.AssertSingleItem ("GeneratedTemplates", withFullPath: generated);
instance.AssertNoItems ("PreprocessedTemplates");
}

[Fact]
public void TransformOnBuild ()
[Theory]
[InlineData ("TransformTemplates", "foo.txt", "Hello 2019!")]
[InlineData ("TransformTemplateFromRelativePath", "Nested/Template/Folder/foo.txt", "Hello 2024!")]
[InlineData ("TransformTemplateWithExtension", "foo.html", "<h1>Hello 2024!</h1>")]
public void TransformOnBuild (string projectName, string expectedFilePath, string expectedText)
{
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("TransformTemplates")
var project = ctx.LoadTestProject (projectName)
.WithProperty ("TransformOnBuild", "true");

project.Restore ();

var instance = project.Build ("Build");

var generatedFilePath = project.DirectoryPath["foo.txt"].AssertTextStartsWith("Hello 2019!");
var generatedFilePath = project.DirectoryPath[expectedFilePath].AssertTextStartsWith (expectedText);

instance.AssertSingleItem ("GeneratedTemplates", withFullPath: generatedFilePath);
instance.AssertNoItems ("PreprocessedTemplates");
}

[Fact]
public void TransformOnBuildDisabled ()
[Theory]
[InlineData ("TransformTemplates", "foo.txt")]
[InlineData ("TransformTemplateFromRelativePath", "Nested/Template/Folder/foo.txt")]
[InlineData ("TransformTemplateWithExtension", "foo.html")]
public void TransformOnBuildDisabled (string projectName, string expectedFilePath)
{
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("TransformTemplates");
var project = ctx.LoadTestProject (projectName);

project.Restore ();

var instance = project.Build ("Build");

project.DirectoryPath["foo.txt"].AssertFileExists (false);
project.DirectoryPath[expectedFilePath].AssertFileExists (false);

instance.AssertNoItems ("GeneratedTemplates", "PreprocessedTemplates");
}

[Fact]
public void PreprocessLegacy ()
public void TransformMetadata ()
{
// Arrange
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("TransformTemplateMetadata");

var outputDirectory = project.DirectoryPath["Demo/Output/OutputDirectory.txt"];
var outputFilePath = project.DirectoryPath["Demo/LegacyOutput/OutputFilePath.txt"];
var outputFileName = project.DirectoryPath["Demo/OutputFileNameTest"];
var outputDirectoryAndOutputFileName = project.DirectoryPath["Demo/Output/OutputDirectoryAndFileNameTest.log"];

// Act
var instance = project.Build ("TransformTemplates");

// Assert
Assert.Multiple (() => {
outputDirectory.AssertTextStartsWith ("Hello Metadata OutputDirectory 2024!");
outputFilePath.AssertTextStartsWith ("Hello Metadata OutputFilePath 2024!");
outputFileName.AssertTextStartsWith ("Hello Metadata OutputFileName 2024!");
outputDirectoryAndOutputFileName.AssertTextStartsWith ("Hello Metadata OutputDirectory and OutputFileName 2024!");
});

instance.AssertNoItems ("PreprocessedTemplates");
}

[Theory]
[InlineData (
"PreprocessTemplate",
"foo.cs",
new string[] {
"namespace PreprocessTemplate {",
"public partial class foo : fooBase {"
}
)]
[InlineData (
"PreprocessTemplateFromRelativePath",
"Nested/Template/Folder/foo.cs",
new string[] {
"namespace PreprocessTemplateFromRelativePath.Nested.Template.Folder {",
"public partial class foo : fooBase {"
}
)]
[InlineData (
"PreprocessTemplateWithExtension",
"foo.g.cs",
new string[] {
"namespace PreprocessTemplateWithExtension {",
"public partial class foo : fooBase {"
}
)]
public void PreprocessLegacy (string projectName, string expectedFilePath, string[] expectedContents)
{
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("PreprocessTemplate")
var project = ctx.LoadTestProject (projectName)
.WithProperty ("UseLegacyT4Preprocessing", "true");

var instance = project.Build ("TransformTemplates");

var generatedFilePath = project.DirectoryPath["foo.cs"].AssertTextStartsWith ("//--------");
var generatedFilePath = project.DirectoryPath[expectedFilePath]
.AssertContainsText
(
StringComparison.Ordinal,
expectedContents
);

instance.AssertSingleItem ("PreprocessedTemplates", generatedFilePath);
instance.AssertNoItems ("GeneratedTemplates");
}

[Fact]
public void PreprocessOnBuild ()
[Theory]
[InlineData (
"PreprocessTemplate",
"TextTransform/foo.cs",
"PreprocessTemplate.foo"
)]
[InlineData (
"PreprocessTemplateFromRelativePath",
"TextTransform/Nested/Template/Folder/foo.cs",
"PreprocessTemplateFromRelativePath.Nested.Template.Folder.foo"
)]
[InlineData (
"PreprocessTemplateWithExtension",
"TextTransform/foo.g.cs",
"PreprocessTemplateWithExtension.foo"
)]
public void PreprocessOnBuild (string projectName, string expectedFilePath, string expectedType)
{
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("PreprocessTemplate");
var project = ctx.LoadTestProject (projectName);

project.Restore ();

var instance = project.Build ("Build");
var objDir = project.DirectoryPath["obj", "Debug", "netstandard2.0"];

var generatedFilePath = instance.GetIntermediateDirFile ("TextTransform", "foo.cs")
var generatedFilePath = instance.GetIntermediateDirFile (expectedFilePath)
.AssertTextStartsWith ("//--------");

instance.AssertSingleItem ("PreprocessedTemplates", generatedFilePath);
instance.AssertNoItems ("GeneratedTemplates");

instance.GetTargetPath ()
.AssertFileName ("PreprocessTemplate.dll")
.AssertAssemblyContainsType ("PreprocessTemplate.foo");
.AssertFileName ($"{projectName}.dll")
.AssertAssemblyContainsType (expectedType);
}

[Fact]
public void PreprocessOnDesignTimeBuild ()
[Theory]
[InlineData (
"PreprocessTemplate",
"TextTransform/foo.cs"
)]
[InlineData (
"PreprocessTemplateFromRelativePath",
"TextTransform/Nested/Template/Folder/foo.cs"
)]
[InlineData (
"PreprocessTemplateWithExtension",
"TextTransform/foo.g.cs"
)]
public void PreprocessOnDesignTimeBuild (string projectName, string expectedFilePath)
{
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("PreprocessTemplate")
var project = ctx.LoadTestProject (projectName)
.WithProperty ("DesignTimeBuild", "true")
.WithProperty ("SkipCompilerExecution", "true");

project.Restore ();

var instance = project.Build ("CoreCompile");

var generatedFilePath = instance.GetIntermediateDirFile ("TextTransform", "foo.cs")
var generatedFilePath = instance.GetIntermediateDirFile (expectedFilePath)
.AssertTextStartsWith ("//--------");

instance.AssertSingleItem ("PreprocessedTemplates", generatedFilePath);
instance.AssertNoItems ("GeneratedTemplates");
}

[Fact]
public void PreprocessLegacyMetadata ()
{
// Arrange
using var ctx = new MSBuildTestContext ();
var project = ctx.LoadTestProject ("PreprocessTemplateMetadata")
.WithProperty ("UseLegacyT4Preprocessing", "true");

var outputDirectory = project.DirectoryPath["Demo/Output/OutputDirectory.cs"];
var outputFilePath = project.DirectoryPath["Demo/LegacyOutput/OutputFilePath.cs"];
var outputFileName = project.DirectoryPath["Demo/OutputFileNameTest.cs"];
var outputFileNameAndOutputDirectory = project.DirectoryPath["Demo/Output/OutputDirectoryAndFileNameTest.g.cs"];

// Act
var instance = project.Build ("TransformTemplates");

// Assert
Assert.Multiple (() => {
outputDirectory.AssertContainsText
(
StringComparison.Ordinal,
"namespace PreprocessTemplateMetadata.Demo.Output {",
"partial class OutputDirectory"
);

outputFilePath.AssertContainsText
(
StringComparison.Ordinal,
"namespace PreprocessTemplateMetadata.Demo.LegacyOutput {",
"partial class OutputFilePath"
);

outputFileName.AssertContainsText
(
StringComparison.Ordinal,
"namespace PreprocessTemplateMetadata.Demo {",
"partial class OutputFileNameTest"
);

outputFileNameAndOutputDirectory.AssertContainsText
(
StringComparison.Ordinal,
"namespace PreprocessTemplateMetadata.Demo.Output {",
"partial class OutputDirectoryAndFileNameTest"
);
});

instance.AssertNoItems ("GeneratedTemplates");
}

[Fact]
public void IncrementalTransform ()
{
Expand All @@ -120,13 +262,13 @@ public void IncrementalTransform ()

project.Restore ();

var fooGenerated = project.DirectoryPath ["foo.txt"];
var fooTemplate = project.DirectoryPath ["foo.tt"];
var barGenerated = project.DirectoryPath ["bar.txt"];
var barTemplate = project.DirectoryPath ["bar.tt"];
var includeFile = project.DirectoryPath ["helper.ttinclude"];
var fooGenerated = project.DirectoryPath["foo.txt"];
var fooTemplate = project.DirectoryPath["foo.tt"];
var barGenerated = project.DirectoryPath["bar.txt"];
var barTemplate = project.DirectoryPath["bar.tt"];
var includeFile = project.DirectoryPath["helper.ttinclude"];

void ExecuteAndValidate()
void ExecuteAndValidate ()
{
var instance = project.Build ("TransformTemplates");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<#@ template language="C#" #>
Hello World
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(TemplatingTargetsPath)\T4.BuildTools.props" />

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<T4Preprocess Include="./Nested/Template/Folder/foo.tt" />
<PackageReference Include="System.CodeDom" Version="5.0.0" />
</ItemGroup>

<Import Project="$(TemplatingTargetsPath)\T4.BuildTools.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<#@ template language="C#" #>
Hello Item Metadata OutputDirectory
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<#@ template language="C#" #>
Hello Item Metadata OutputDirectory And OutputDFileName
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<#@ template language="C#" #>
<#@ output extension=".generated.cs" #>
Hello Item Metadata OutputDFileName
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<#@ template language="C#" #>
Hello Item Metadata OutputFilePath
Loading