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
87 changes: 80 additions & 7 deletions src/Tasks.UnitTests/WriteCodeFragment_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,51 @@ public void CombineFileDirectory()
string file = Path.Combine(Path.GetTempPath(), "CombineFileDirectory.tmp");
Assert.Equal(file, task.OutputFile.ItemSpec);
Assert.True(File.Exists(file));

File.Delete(task.OutputFile.ItemSpec);
}

/// <summary>
/// Combine file and directory where the directory does not already exist
/// </summary>
[Fact]
public void CombineFileDirectoryAndDirectoryDoesNotExist()
{
using TestEnvironment env = TestEnvironment.Create();

TaskItem folder = new TaskItem(env.CreateFolder(folderPath: null, createFolder: false).Path);

TaskItem file = new TaskItem("CombineFileDirectory.tmp");

string expectedFile = Path.Combine(folder.ItemSpec, file.ItemSpec);
WriteCodeFragment task = CreateTask("c#", folder, file, new TaskItem[] { new TaskItem("aa") });
MockEngine engine = new MockEngine(true);
task.BuildEngine = engine;
bool result = task.Execute();

Assert.True(result);
Assert.Equal(expectedFile, task.OutputFile.ItemSpec);
Assert.True(File.Exists(expectedFile));
}

/// <summary>
/// Combine file and directory where the directory does not already exist
/// </summary>
[Fact]
public void FileWithPathAndDirectoryDoesNotExist()
{
using TestEnvironment env = TestEnvironment.Create();

TaskItem file = new TaskItem(Path.Combine(env.CreateFolder(folderPath: null, createFolder: false).Path, "File.tmp"));

WriteCodeFragment task = CreateTask("c#", null, file, new TaskItem[] { new TaskItem("aa") });
MockEngine engine = new MockEngine(true);
task.BuildEngine = engine;
bool result = task.Execute();

Assert.True(result);
Assert.Equal(file.ItemSpec, task.OutputFile.ItemSpec);
Assert.True(File.Exists(task.OutputFile.ItemSpec));
}

/// <summary>
Expand Down Expand Up @@ -176,7 +221,7 @@ public void NoAttributesShouldEmitNoFile2()
/// <summary>
/// Bad file path
/// </summary>
[Fact]
[WindowsOnlyFact(additionalMessage: "No invalid characters on Unix.")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this test work on Unix before?

Copy link
Contributor Author

@jrdodds jrdodds Mar 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It worked before because the path didn't exist. Now that we ensure that the path is created, the test fails because there is not an MSB3713 error as the test expects. 😀

Copy link
Contributor

@Forgind Forgind Mar 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, looks like 3713 is a very generic error for any failure after our initial validation. Makes sense, thanks!

public void InvalidFilePath()
{
WriteCodeFragment task = new WriteCodeFragment();
Expand Down Expand Up @@ -317,6 +362,27 @@ public void ToDirectory()
File.Delete(task.OutputFile.ItemSpec);
}

/// <summary>
/// Specify directory where the directory does not already exist
/// </summary>
[Fact]
public void ToDirectoryAndDirectoryDoesNotExist()
{
using TestEnvironment env = TestEnvironment.Create();

TaskItem folder = new TaskItem(env.CreateFolder(folderPath: null, createFolder: false).Path);

WriteCodeFragment task = CreateTask("c#", folder, null, new TaskItem[] { new TaskItem("System.AssemblyTrademarkAttribute") });
MockEngine engine = new MockEngine(true);
task.BuildEngine = engine;
bool result = task.Execute();

Assert.True(result);
Assert.True(File.Exists(task.OutputFile.ItemSpec));
Assert.Equal(folder.ItemSpec, task.OutputFile.ItemSpec.Substring(0, folder.ItemSpec.Length));
Assert.Equal(".cs", task.OutputFile.ItemSpec.Substring(task.OutputFile.ItemSpec.Length - 3));
}

/// <summary>
/// Regular case
/// </summary>
Expand Down Expand Up @@ -874,7 +940,7 @@ public void InferredTypeForNamedParameter()
}

/// <summary>
/// For backward-compatibility, if multiple constructors are found with the same number
/// For backward-compatibility, if multiple constructors are found with the same number
/// of position arguments that was specified in the metadata, then the constructor that
/// has strings for every parameter should be used.
/// </summary>
Expand Down Expand Up @@ -985,11 +1051,18 @@ public void UsingInferredDeclaredTypesAndLiteralsInSameAttribute()

private WriteCodeFragment CreateTask(string language, params TaskItem[] attributes)
{
WriteCodeFragment task = new();
task.Language = language;
task.OutputDirectory = new TaskItem(Path.GetTempPath());
task.AssemblyAttributes = attributes;
return task;
return CreateTask(language, new TaskItem(Path.GetTempPath()), null, attributes);
}

private WriteCodeFragment CreateTask(string language, TaskItem outputDirectory, TaskItem outputFile, params TaskItem[] attributes)
{
return new WriteCodeFragment()
{
Language = language,
OutputDirectory = outputDirectory,
OutputFile = outputFile,
AssemblyAttributes = attributes
};
}

private void ExecuteAndVerifySuccess(WriteCodeFragment task, params string[] expectedAttributes)
Expand Down
8 changes: 5 additions & 3 deletions src/Tasks/WriteCodeFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class WriteCodeFragment : TaskExtension
/// The path to the file that was generated.
/// If this is set, and a file name, the destination folder will be prepended.
/// If this is set, and is rooted, the destination folder will be ignored.
/// If this is not set, the destination folder will be used, an arbitrary file name will be used, and
/// If this is not set, the destination folder will be used, an arbitrary file name will be used, and
/// the default extension for the language selected.
/// </summary>
[Output]
Expand Down Expand Up @@ -113,6 +113,8 @@ public override bool Execute()

OutputFile ??= new TaskItem(FileUtilities.GetTemporaryFile(OutputDirectory.ItemSpec, null, extension));

FileUtilities.EnsureDirectoryExists(Path.GetDirectoryName(OutputFile.ItemSpec));

File.WriteAllText(OutputFile.ItemSpec, code); // Overwrites file if it already exists (and can be overwritten)
}
catch (Exception ex) when (ExceptionHandling.IsIoRelatedException(ex))
Expand Down Expand Up @@ -481,7 +483,7 @@ private Type[] FindPositionalParameterTypes(Type attributeType, IReadOnlyList<At
Log.LogMessageFromResources("WriteCodeFragment.MultipleConstructorsFound");

// Before parameter types could be specified, all parameter values were
// treated as strings. To be backward-compatible, we need to prefer
// treated as strings. To be backward-compatible, we need to prefer
// the constructor that has all string parameters, if it exists.
var allStringParameters = candidates.FirstOrDefault(c => c.All(t => t == typeof(string)));

Expand Down Expand Up @@ -551,7 +553,7 @@ private bool TryConvertParameterValue(string typeName, string rawValue, out Code
/// </summary>
private CodeExpression ConvertParameterValueToInferredType(Type inferredType, string rawValue, string parameterName)
{
// If we don't know what type the parameter should be, then we
// If we don't know what type the parameter should be, then we
// can't convert the type. We'll just treat is as a string.
if (inferredType is null)
{
Expand Down