Add tests

This commit is contained in:
ds5678
2025-04-08 11:16:14 -07:00
parent db45fc70a2
commit fb180b0010
4 changed files with 127 additions and 15 deletions
@@ -131,6 +131,7 @@
<Compile Include="Helpers\TestsAssemblyOutput.cs" />
<Compile Include="Output\InsertParenthesesVisitorTests.cs" />
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
<Compile Include="ProjectDecompiler\WholeProjectDecompilerTests.cs" />
<Compile Include="TestAssemblyResolver.cs" />
<Compile Include="TestCases\ILPretty\Issue3421.cs" />
<Compile Include="TestCases\ILPretty\Issue3442.cs" />
@@ -23,7 +23,7 @@ using ICSharpCode.Decompiler.Metadata;
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests
namespace ICSharpCode.Decompiler.Tests.ProjectDecompiler
{
[TestFixture]
public sealed class TargetFrameworkTests
@@ -0,0 +1,101 @@
// Copyright (c) 2025 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.Metadata;
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests.ProjectDecompiler;
[TestFixture]
public sealed class WholeProjectDecompilerTests
{
[Test]
public void UseNestedDirectoriesForNamespacesTrueWorks()
{
string targetDirectory = Path.Combine(Environment.CurrentDirectory, Path.GetRandomFileName());
TestFriendlyProjectDecompiler decompiler = new(new UniversalAssemblyResolver(null, false, null));
decompiler.Settings.UseNestedDirectoriesForNamespaces = true;
decompiler.DecompileProject(new PEFile("ICSharpCode.Decompiler.dll"), targetDirectory);
AssertDirectoryDoesntExist(targetDirectory);
string projectDecompilerDirectory = Path.Combine(targetDirectory, "ICSharpCode", "Decompiler", "CSharp", "ProjectDecompiler");
string projectDecompilerFile = Path.Combine(projectDecompilerDirectory, $"{nameof(WholeProjectDecompiler)}.cs");
using (Assert.EnterMultipleScope())
{
Assert.That(decompiler.Files.ContainsKey(projectDecompilerFile), Is.True);
Assert.That(decompiler.Directories.Contains(projectDecompilerDirectory), Is.True);
}
}
[Test]
public void UseNestedDirectoriesForNamespacesFalseWorks()
{
string targetDirectory = Path.Combine(Environment.CurrentDirectory, Path.GetRandomFileName());
TestFriendlyProjectDecompiler decompiler = new(new UniversalAssemblyResolver(null, false, null));
decompiler.Settings.UseNestedDirectoriesForNamespaces = false;
decompiler.DecompileProject(new PEFile("ICSharpCode.Decompiler.dll"), targetDirectory);
AssertDirectoryDoesntExist(targetDirectory);
string projectDecompilerDirectory = Path.Combine(targetDirectory, "ICSharpCode.Decompiler.CSharp.ProjectDecompiler");
string projectDecompilerFile = Path.Combine(projectDecompilerDirectory, $"{nameof(WholeProjectDecompiler)}.cs");
using (Assert.EnterMultipleScope())
{
Assert.That(decompiler.Files.ContainsKey(projectDecompilerFile), Is.True);
Assert.That(decompiler.Directories.Contains(projectDecompilerDirectory), Is.True);
}
}
static void AssertDirectoryDoesntExist(string directory)
{
if (Directory.Exists(directory))
{
Directory.Delete(directory, recursive: true);
Assert.Fail("Directory should not have been created.");
}
}
sealed class TestFriendlyProjectDecompiler(IAssemblyResolver assemblyResolver) : WholeProjectDecompiler(assemblyResolver)
{
public Dictionary<string, StringWriter> Files { get; } = [];
public HashSet<string> Directories { get; } = [];
protected override TextWriter CreateFile(string path)
{
StringWriter writer = new();
Files[path] = writer;
return writer;
}
protected override void CreateDirectory(string path)
{
Directories.Add(path);
}
protected override IEnumerable<ProjectItemInfo> WriteMiscellaneousFilesInProject(PEFile module) => [];
protected override IEnumerable<ProjectItemInfo> WriteResourceFilesInProject(MetadataFile module) => [];
}
}
@@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
public void DecompileProject(MetadataFile file, string targetDirectory, CancellationToken cancellationToken = default(CancellationToken))
{
string projectFileName = Path.Combine(targetDirectory, CleanUpFileName(file.Name, ".csproj"));
using (var writer = new StreamWriter(projectFileName))
using (var writer = CreateFile(projectFileName))
{
DecompileProject(file, targetDirectory, writer, cancellationToken);
}
@@ -186,6 +186,24 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
return true;
}
protected virtual TextWriter CreateFile(string path)
{
return new StreamWriter(path);
}
protected virtual void CreateDirectory(string path)
{
try
{
Directory.CreateDirectory(path);
}
catch (IOException)
{
File.Delete(path);
Directory.CreateDirectory(path);
}
}
CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts)
{
var decompiler = new CSharpDecompiler(ts, Settings);
@@ -204,9 +222,9 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
const string prop = "Properties";
if (directories.Add(prop))
Directory.CreateDirectory(Path.Combine(TargetDirectory, prop));
CreateDirectory(Path.Combine(TargetDirectory, prop));
string assemblyInfo = Path.Combine(prop, "AssemblyInfo.cs");
using (StreamWriter w = new StreamWriter(Path.Combine(TargetDirectory, assemblyInfo)))
using (var w = CreateFile(Path.Combine(TargetDirectory, assemblyInfo)))
{
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, Settings.CSharpFormattingOptions));
}
@@ -251,15 +269,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
if (directories.Add(dir))
{
var path = Path.Combine(TargetDirectory, dir);
try
{
Directory.CreateDirectory(path);
}
catch (IOException)
{
File.Delete(path);
Directory.CreateDirectory(path);
}
CreateDirectory(path);
}
return Path.Combine(dir, file);
}
@@ -277,7 +287,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
delegate (IGrouping<string, TypeDefinitionHandle> file) {
try
{
using StreamWriter w = new StreamWriter(Path.Combine(TargetDirectory, file.Key));
using var w = CreateFile(Path.Combine(TargetDirectory, file.Key));
CSharpDecompiler decompiler = CreateDecompiler(ts);
foreach (var partialType in partialTypes)
@@ -344,7 +354,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
string dirName = Path.GetDirectoryName(fileName);
if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName))
{
Directory.CreateDirectory(Path.Combine(TargetDirectory, dirName));
CreateDirectory(Path.Combine(TargetDirectory, dirName));
}
Stream entryStream = (Stream)value;
entryStream.Position = 0;