From cc378410f29f37c8765fe6de8bde04af921739dc Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 11 Sep 2021 17:19:10 +0200 Subject: [PATCH] Don't rewrite inner class (#58) --- .../TestsRewriter.cs | 151 ++++++++++-------- .../WithNonTestClasses/.meta/config.json | 7 + .../Solutions/WithNonTestClasses/Fake.cs | 4 + .../Solutions/WithNonTestClasses/Fake.csproj | 18 +++ .../Solutions/WithNonTestClasses/FakeTests.cs | 18 +++ .../WithNonTestClasses/expected_results.json | 11 ++ .../TestRunnerTests.cs | 7 + 7 files changed, 147 insertions(+), 69 deletions(-) create mode 100644 test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/.meta/config.json create mode 100644 test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.cs create mode 100644 test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.csproj create mode 100644 test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/FakeTests.cs create mode 100644 test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/expected_results.json diff --git a/src/Exercism.TestRunner.CSharp/TestsRewriter.cs b/src/Exercism.TestRunner.CSharp/TestsRewriter.cs index b056827..5581abc 100644 --- a/src/Exercism.TestRunner.CSharp/TestsRewriter.cs +++ b/src/Exercism.TestRunner.CSharp/TestsRewriter.cs @@ -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")) @@ -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() + .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().Any()) node = node.AddMembers( @@ -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( @@ -226,6 +235,10 @@ public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) SingletonSeparatedList( VariableDeclarator( Identifier("_stringWriter"))))))); + + _visitingTestClass = oldVisitingTestClass; + + return rewrittenClassDeclaration; } } } diff --git a/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/.meta/config.json b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/.meta/config.json new file mode 100644 index 0000000..b6395cc --- /dev/null +++ b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/.meta/config.json @@ -0,0 +1,7 @@ +{ + "files": { + "solution": ["Fake.cs"], + "test": ["FakeTests.cs"], + "example": [".meta/Example.cs"] + } +} \ No newline at end of file diff --git a/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.cs b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.cs new file mode 100644 index 0000000..bfbf44e --- /dev/null +++ b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.cs @@ -0,0 +1,4 @@ +public static class Fake +{ + public static int Add(int x, int y) => x + y; +} \ No newline at end of file diff --git a/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.csproj b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.csproj new file mode 100644 index 0000000..d6a2c1b --- /dev/null +++ b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/Fake.csproj @@ -0,0 +1,18 @@ + + + + net5.0 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/FakeTests.cs b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/FakeTests.cs new file mode 100644 index 0000000..071c2e0 --- /dev/null +++ b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/FakeTests.cs @@ -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); +} \ No newline at end of file diff --git a/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/expected_results.json b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/expected_results.json new file mode 100644 index 0000000..56365e0 --- /dev/null +++ b/test/Exercism.TestRunner.CSharp.IntegrationTests/Solutions/WithNonTestClasses/expected_results.json @@ -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))" + } + ] +} \ No newline at end of file diff --git a/test/Exercism.TestRunner.CSharp.IntegrationTests/TestRunnerTests.cs b/test/Exercism.TestRunner.CSharp.IntegrationTests/TestRunnerTests.cs index 8499428..a9081cc 100644 --- a/test/Exercism.TestRunner.CSharp.IntegrationTests/TestRunnerTests.cs +++ b/test/Exercism.TestRunner.CSharp.IntegrationTests/TestRunnerTests.cs @@ -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() {