Skip to content

Instantly share code, notes, and snippets.

@egil
Last active May 4, 2021 15:07
Show Gist options
  • Save egil/ddb05663c500c015515ec2cb1df090f7 to your computer and use it in GitHub Desktop.
Save egil/ddb05663c500c015515ec2cb1df090f7 to your computer and use it in GitHub Desktop.
C# source code comparison / assertion helper (depends on the packages Microsoft.CodeAnalysis.CSharp and DiffPlex).
using System;
using System.Text;
using DiffPlex.DiffBuilder;
using DiffPlex.DiffBuilder.Model;
using FluentAssertions.Execution;
using FluentAssertions.Primitives;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace FluentAssertions
{
public static class StringAssertionExtensions
{
public static AndConstraint<StringAssertions> HaveEquivalentSyntaxTreeTo(this StringAssertions assertions, string expectedCode)
{
var subject = CSharpSyntaxTree.ParseText(assertions.Subject);
var expected = CSharpSyntaxTree.ParseText(expectedCode);
Execute.Assertion
.ForCondition(subject.IsEquivalentTo(expected, topLevel: false))
.FailWith(() =>
{
var formattedSubject = subject.GetRoot().NormalizeWhitespace(eol: Environment.NewLine).GetText().ToString();
var formattedExpected = expected.GetRoot().NormalizeWhitespace(eol: Environment.NewLine).GetText().ToString();
var msgBuilder = new StringBuilder();
msgBuilder.AppendLine("Expected the syntax tree for: ");
msgBuilder.AppendLine();
msgBuilder.Append(" ");
msgBuilder.AppendLine(formattedSubject.Replace(Environment.NewLine, $"{Environment.NewLine} ", StringComparison.Ordinal));
msgBuilder.AppendLine();
msgBuilder.AppendLine("To be equivalent to the syntax tree for: ");
msgBuilder.AppendLine();
msgBuilder.Append(" ");
msgBuilder.AppendLine(formattedExpected.Replace(Environment.NewLine, $"{Environment.NewLine} ", StringComparison.Ordinal));
msgBuilder.AppendLine();
msgBuilder.AppendLine("The diff between the two is:");
msgBuilder.AppendLine();
var diff = InlineDiffBuilder.Diff(formattedExpected, formattedSubject, ignoreWhiteSpace: true);
foreach (var line in diff.Lines)
{
switch (line.Type)
{
case ChangeType.Inserted:
msgBuilder.Append("+ ");
break;
case ChangeType.Deleted:
msgBuilder.Append("- ");
break;
default:
msgBuilder.Append(" ");
break;
}
msgBuilder.AppendLine(line.Text);
}
var msg = msgBuilder.Replace("{", "{{").Replace("}", "}}").ToString();
return new FailReason(msg);
});
return new AndConstraint<StringAssertions>(assertions);
}
}
}
@egil
Copy link
Author

egil commented May 4, 2021

This allows you to do:

var actualCode = "... some c# code";
var expectedCode=  "... some c# code";

actualCode.Should().HaveEquivalentSyntaxTreeTo(expectedCode);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment