Skip to content

Commit

Permalink
fix most of teh tests and share solution creation boiler plate betwee…
Browse files Browse the repository at this point in the history
…n tests
  • Loading branch information
dicko2 committed Dec 14, 2024
1 parent 6ba7497 commit 44250f5
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.8.3" />
<PackageReference Include="Microsoft.Build" Version="17.8.3" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.8.3" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.8.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
Expand Down
38 changes: 23 additions & 15 deletions src/Agoda.CodeCompass.MSBuild.Tests/SarifConversionTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Text.Json;
using Agoda.CodeCompass.MSBuild.Sarif;
using Agoda.CodeCompass.MSBuild.Sarif;
using Microsoft.Build.Framework;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Newtonsoft.Json.Serialization;
Expand All @@ -18,30 +17,36 @@ public class SarifConversionTests
private readonly string _writeSarifPath = "TestData/write.sarif";
private readonly string _sampleSarifPath = "TestData/sample.sarif";
private readonly IBuildEngine _buildEngine = Substitute.For<IBuildEngine>();
private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
private JsonSerializerSettings _jsonSettings = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Error = HandleDeserializationError,
Formatting = Formatting.Indented,
};

public SarifConversionTests()
{
_tempSolutionDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(_tempSolutionDir);
}
private string _tempSolutionDir;

[Test]
public async Task ConvertSarif_WithValidInput_ShouldAddTechDebtProperties()
{
SetupTests.SetupSolutionAndProject(_tempSolutionDir);
var outfile = "TestData/" + Guid.NewGuid();
// Arrange
var task = new TechDebtSarifTask
{
InputPath = _sampleSarifPath,
OutputPath = outfile,
BuildEngine = _buildEngine
BuildEngine = _buildEngine,
SolutionPath = _tempSolutionDir
};

// Act
var result = task.Execute();

// Assert
result.ShouldBeTrue();
task.Execute().ShouldBeTrue();

var jsonSettings = new JsonSerializerSettings
{
Expand All @@ -67,17 +72,17 @@ public async Task ConvertSarif_WithValidInput_ShouldAddTechDebtProperties()
[Test]
public async Task ConvertSarif_WithV1FromTestData_ShouldHave1Violation()
{
SetupTests.SetupSolutionAndProject(_tempSolutionDir);
var outfile = "TestData/" + Guid.NewGuid();
var task = new TechDebtSarifTask
{
InputPath = "TestData/v1.sarif",
OutputPath = outfile,
BuildEngine = _buildEngine
BuildEngine = _buildEngine,
SolutionPath = _tempSolutionDir
};

var result = task.Execute();

result.ShouldBeTrue();
task.Execute().ShouldBeTrue();

var outputJson = await File.ReadAllTextAsync(outfile);
var output = JsonConvert.DeserializeObject<SarifV1Report>(outputJson, _jsonSettings);
Expand All @@ -100,6 +105,7 @@ private static void HandleDeserializationError(object sender, ErrorEventArgs err
[Test]
public async Task ConvertSarif_WithMultipleRules_ShouldPreserveRuleMetadata()
{
SetupTests.SetupSolutionAndProject(_tempSolutionDir);
// Arrange
var sarif = new SarifReport
{
Expand All @@ -116,18 +122,20 @@ public async Task ConvertSarif_WithMultipleRules_ShouldPreserveRuleMetadata()
}
};

var outfile = "TestData/" + Guid.NewGuid();
await File.WriteAllTextAsync(_writeSarifPath,
JsonConvert.SerializeObject(sarif, _jsonSettings));
var outfile = "TestData/" + Guid.NewGuid();

var task = new TechDebtSarifTask
{
InputPath = _writeSarifPath,
OutputPath = outfile,
BuildEngine = _buildEngine
BuildEngine = _buildEngine,
SolutionPath = _tempSolutionDir
};

// Act
task.Execute();
task.Execute().ShouldBeTrue();

// Assert
var outputJson = await File.ReadAllTextAsync(outfile);
Expand Down
80 changes: 80 additions & 0 deletions src/Agoda.CodeCompass.MSBuild.Tests/Setup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Agoda.CodeCompass.MSBuild.Tests;

public static class SetupTests
{
public static void SetupSolutionAndProject(string tempSolutionDir)
{
// Create a minimal solution structure
var projectDir = Path.Combine(tempSolutionDir, "TestProject");
Directory.CreateDirectory(projectDir);

// Create project file with explicit SDK reference
var projectPath = Path.Combine(projectDir, "TestProject.csproj");
File.WriteAllText(projectPath, @"
<Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>library</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=""Agoda.Analyzers"" Version=""1.1.94-preview"">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include=""Microsoft.Build"" Version=""17.8.3"" ExcludeAssets=""runtime"" />
<PackageReference Include=""Microsoft.Build.Framework"" Version=""17.8.3"" ExcludeAssets=""runtime"" />
<PackageReference Include=""Microsoft.CodeAnalysis.Workspaces.MSBuild"" Version=""4.8.0"" />
<PackageReference Include=""Microsoft.CodeAnalysis.CSharp.Workspaces"" Version=""4.8.0"" />
</ItemGroup>
</Project>");

// Create a test file with a diagnostic that should be reported
var sourcePath = Path.Combine(projectDir, "Test.cs");
File.WriteAllText(sourcePath, @"
using System;
public class Test
{
// CS0649: Field is never assigned to
private readonly string _unused;
public void Method()
{
// CS0219: Variable is assigned but its value is never used
int unused = 1;
}
}");
// Create solution file that references the project
var projectGuid = Guid.NewGuid().ToString("B").ToUpper();
var solutionPath = Path.Combine(tempSolutionDir, "test.sln");
File.WriteAllText(solutionPath, $@"
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project(""{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}"") = ""TestProject"", ""TestProject\TestProject.csproj"", ""{projectGuid}""
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{projectGuid}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{projectGuid}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal");
}
}
171 changes: 171 additions & 0 deletions src/Agoda.CodeCompass.MSBuild.Tests/TechDebtSarifTaskTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
using Agoda.CodeCompass.Data;
using Agoda.CodeCompass.MSBuild;
using Microsoft.Build.Framework;
using Microsoft.CodeAnalysis.MSBuild;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
using System.Reflection;
using System.Text.Json;
using Agoda.CodeCompass.MSBuild.Sarif;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
using JsonSerializer = Newtonsoft.Json.JsonSerializer;

namespace Agoda.CodeCompass.MSBuild.Tests;

[TestFixture]
public class TechDebtSarifTaskTests
{
private string _tempInputPath;
private string _tempOutputPath;
private string _tempSolutionDir;
private IBuildEngine _buildEngine;
private MSBuildWorkspace _workspace;
private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Error = HandleDeserializationError,
Formatting = Formatting.Indented,
};

private static void HandleDeserializationError(object? sender, ErrorEventArgs e)
{
Console.WriteLine(e.ErrorContext.Error.ToString());
}

static TechDebtSarifTaskTests()
{
// Register assembly resolution handler for Microsoft.Build assemblies
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var requestedAssembly = new AssemblyName(args.Name);

// If it's looking for an older version of Microsoft.Build.Framework, redirect to the new one
if (requestedAssembly.Name == "Microsoft.Build.Framework" && requestedAssembly.Version.Major == 15)
{
return Assembly.Load("Microsoft.Build.Framework, Version=17.8.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
}

// If it's looking for an older version of Microsoft.Build, redirect to the new one
if (requestedAssembly.Name == "Microsoft.Build" && requestedAssembly.Version.Major == 15)
{
return Assembly.Load("Microsoft.Build, Version=17.8.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
}

return null;
};
}
[SetUp]
public void Setup()
{
// Create temporary directories and files
_tempSolutionDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(_tempSolutionDir);

// Set up temporary paths for input/output
_tempInputPath = Path.Combine(_tempSolutionDir, "input.sarif");
_tempOutputPath = Path.Combine(_tempSolutionDir, "output.sarif");

// Set up substitute build engine
_buildEngine = Substitute.For<IBuildEngine>();

// Set environment variable
Environment.SetEnvironmentVariable("SolutionDir", _tempSolutionDir);

// Configure MSBuildWorkspace
var properties = new Dictionary<string, string>
{
{ "Configuration", "Debug" },
{ "Platform", "AnyCPU" }
};

_workspace = MSBuildWorkspace.Create(properties);

// Subscribe to workspace failed events for debugging
_workspace.WorkspaceFailed += (sender, args) =>
{
Console.WriteLine($"Workspace failure: {args.Diagnostic.Message}");
};
}

[TearDown]
public void TearDown()
{
_workspace?.Dispose();

if (Directory.Exists(_tempSolutionDir))
{
Directory.Delete(_tempSolutionDir, true);
}

Environment.SetEnvironmentVariable("SolutionDir", null);
}

[Test]
public void Execute_ShouldUpdateTechDebtMetadata()
{
// Arrange
SetupTests.SetupSolutionAndProject(_tempSolutionDir);

var minimalSarifContent = @"{
""$schema"": ""https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"",
""version"": ""2.1.0"",
""runs"": [
{
""tool"": {
""driver"": {
""name"": ""Test Tool"",
""rules"": [
{
""id"": ""CS0649"",
""properties"": {
""techDebtMinutes"": ""30"",
""category"": ""TestCategory"",
""priority"": ""High""
}
}
]
}
},
""results"": [
{
""ruleId"": ""CS0649"",
""ruleId"": ""AG0005""
}
]
}
]
}";

File.WriteAllText(_tempInputPath, minimalSarifContent);

var task = new TechDebtSarifTask
{
BuildEngine = _buildEngine,
InputPath = _tempInputPath,
OutputPath = _tempOutputPath,
SolutionPath = _tempSolutionDir
};

task.Execute().ShouldBeTrue();

File.Exists(_tempOutputPath).ShouldBeTrue();
_buildEngine.DidNotReceive().LogErrorEvent(Arg.Any<BuildErrorEventArgs>());

var outputContent = File.ReadAllText(_tempOutputPath);
var outputDoc = JsonConvert.DeserializeObject<SarifReport>(outputContent, _jsonSettings);

// Verify the tech debt info was updated
var techDebtInfo = outputDoc.Runs[0].Results[0].Properties.TechDebt;
techDebtInfo.ShouldNotBeNull();
techDebtInfo.Minutes.ShouldBe(10);
techDebtInfo.Category.ShouldBe("Compiler");
techDebtInfo.Priority.ShouldBe("Low");
// Verify the tech debt info was updated
techDebtInfo = outputDoc.Runs[0].Tool.Driver.Rules.FirstOrDefault(x => x.Id == "AG0005").Properties.TechDebt;
techDebtInfo.ShouldNotBeNull();
techDebtInfo.Minutes.ShouldBe(10);
}
}
Loading

0 comments on commit 44250f5

Please sign in to comment.