Skip to content

Commit

Permalink
Don't rewrite inner class (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikSchierboom authored Sep 11, 2021
1 parent 7832fd5 commit cc37841
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 69 deletions.
151 changes: 82 additions & 69 deletions src/Exercism.TestRunner.CSharp/TestsRewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,80 +26,76 @@ private static SyntaxNode CaptureConsoleOutput(this SyntaxNode testsRoot) =>

private class UnskipTestsRewriter : CSharpSyntaxRewriter
{
public override SyntaxNode VisitAttribute(AttributeSyntax node)
{
if (node.Name.ToString() == "Fact")
{
return base.VisitAttribute(node.WithArgumentList(null));
}

return base.VisitAttribute(node);
}
public override SyntaxNode VisitAttribute(AttributeSyntax node) =>
base.VisitAttribute(node.Name.ToString() == "Fact" ? node.WithArgumentList(null) : node);
}

private class CaptureConsoleOutputRewriter : CSharpSyntaxRewriter
{
private bool _visitingTestClass;

public override SyntaxNode VisitConstructorDeclaration(ConstructorDeclarationSyntax node) =>
base.VisitConstructorDeclaration(
node.AddParameterListParameters(
Parameter(Identifier("testOutput"))
.WithType(
QualifiedName(
_visitingTestClass ?
base.VisitConstructorDeclaration(
node.AddParameterListParameters(
Parameter(Identifier("testOutput"))
.WithType(
QualifiedName(
IdentifierName("Xunit"),
IdentifierName("Abstractions")),
IdentifierName("ITestOutputHelper"))))
.AddBodyStatements(
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName("_testOutput"),
IdentifierName("testOutput"))),
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName("_stringWriter"),
ObjectCreationExpression(
QualifiedName(
QualifiedName(
IdentifierName("Xunit"),
IdentifierName("Abstractions")),
IdentifierName("ITestOutputHelper"))))
.AddBodyStatements(
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName("_testOutput"),
IdentifierName("testOutput"))),
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName("_stringWriter"),
ObjectCreationExpression(
QualifiedName(
IdentifierName("System"),
IdentifierName("IO")),
IdentifierName("StringWriter")))
.WithArgumentList(
ArgumentList()))),
ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
QualifiedName(
IdentifierName("System"),
IdentifierName("IO")),
IdentifierName("StringWriter")))
.WithArgumentList(
ArgumentList()))),
ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("System"),
IdentifierName("Console")),
IdentifierName("SetOut")))
.WithArgumentList(
ArgumentList(
SingletonSeparatedList(
Argument(
IdentifierName("_stringWriter")))))),
ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("System"),
IdentifierName("Console")),
IdentifierName("SetOut")))
.WithArgumentList(
ArgumentList(
SingletonSeparatedList(
Argument(
IdentifierName("_stringWriter")))))),
ExpressionStatement(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("System"),
IdentifierName("Console")),
IdentifierName("SetError")))
.WithArgumentList(
ArgumentList(
SingletonSeparatedList(
Argument(
IdentifierName("_stringWriter"))))))));
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("System"),
IdentifierName("Console")),
IdentifierName("SetError")))
.WithArgumentList(
ArgumentList(
SingletonSeparatedList(
Argument(
IdentifierName("_stringWriter"))))))))
: base.VisitConstructorDeclaration(node);

public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
if (node.Identifier.Text == "Dispose")
return base.VisitMethodDeclaration(
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) =>
_visitingTestClass && node.Identifier.Text == "Dispose"
? base.VisitMethodDeclaration(
node.AddBodyStatements(LocalDeclarationStatement(
VariableDeclaration(
IdentifierName("var"))
Expand Down Expand Up @@ -171,14 +167,27 @@ public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
Argument(
IdentifierName("output"))))))

));


return base.VisitMethodDeclaration(node);
}
))
: base.VisitMethodDeclaration(node);

public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
{
var oldVisitingTestClass = _visitingTestClass;

_visitingTestClass = node
.DescendantNodes()
.OfType<AttributeSyntax>()
.Any(attribute => attribute.Name.ToString() == "Fact" ||
attribute.Name.ToString() == "Theory" ||
attribute.Name.ToString() == "Diamond");

if (!_visitingTestClass)
{
var visitedClassDeclaration = base.VisitClassDeclaration(node);
_visitingTestClass = oldVisitingTestClass;
return visitedClassDeclaration;
}

// TODO: refactor to method
if (!node.DescendantNodes().OfType<ConstructorDeclarationSyntax>().Any())
node = node.AddMembers(
Expand All @@ -201,8 +210,8 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
PredefinedType(Token(SyntaxKind.VoidKeyword)),
Identifier("Dispose"))
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))));
return base.VisitClassDeclaration(

var rewrittenClassDeclaration = base.VisitClassDeclaration(
node
.AddMembers(
FieldDeclaration(
Expand All @@ -226,6 +235,10 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
SingletonSeparatedList(
VariableDeclarator(
Identifier("_stringWriter")))))));

_visitingTestClass = oldVisitingTestClass;

return rewrittenClassDeclaration;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files": {
"solution": ["Fake.cs"],
"test": ["FakeTests.cs"],
"example": [".meta/Example.cs"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public static class Fake
{
public static int Add(int x, int y) => x + y;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Example.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="Exercism.Tests" Version="0.1.0-alpha" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Xunit;
public class FakeTests
{
private NumberComparer _numberComparer = new();

[Fact]
public void Add_should_add_numbers() => _numberComparer.Compare(2, FakeHelper.AddOne(1));

private class NumberComparer
{
public void Compare(int expected, int actual) => Assert.Equal(expected, actual);
}
}

public static class FakeHelper
{
public static int AddOne(int x) => Fake.Add(x, 1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": 3,
"status": "pass",
"tests": [
{
"name": "Add should add numbers",
"status": "pass",
"test_code": "Assert.Equal(2, Fake.Add(1, 1))"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ public void DownloadedSolution()
Assert.Equal(testRun.Expected, testRun.Actual);
}

[Fact]
public void WithNonTestClasses()
{
var testRun = TestSolutionRunner.Run("WithNonTestClasses");
Assert.Equal(testRun.Expected, testRun.Actual);
}

[Fact]
public void EditorFiles()
{
Expand Down

0 comments on commit cc37841

Please sign in to comment.