55using Microsoft . CodeAnalysis ;
66using Microsoft . CodeAnalysis . CSharp ;
77using Microsoft . CodeAnalysis . CSharp . Syntax ;
8+ using Microsoft . Win32 . SafeHandles ;
89
9- namespace Exercism . TestRunner . CSharp
10+ namespace Exercism . TestRunner . CSharp ;
11+
12+ internal static class TestResultParser
1013{
11- internal static class TestResultParser
14+ internal static TestResult [ ] FromFile ( string logFilePath , SyntaxTree testsSyntaxTree )
1215 {
13- internal static TestResult [ ] FromFile ( string logFilePath , SyntaxTree testsSyntaxTree )
14- {
15- using var fileStream = File . OpenRead ( logFilePath ) ;
16- var result = ( XmlTestRun ) new XmlSerializer ( typeof ( XmlTestRun ) ) . Deserialize ( fileStream ) ;
17-
18- if ( result . Results == null )
19- return Array . Empty < TestResult > ( ) ;
20-
21- return result . ToTestResults ( testsSyntaxTree ) ;
22- }
16+ using var fileStream = File . OpenRead ( logFilePath ) ;
17+ var result = new XmlSerializer ( typeof ( XmlTestRun ) ) . Deserialize ( fileStream ) as XmlTestRun ;
2318
24- private static TestResult [ ] ToTestResults ( this XmlTestRun result , SyntaxTree testsSyntaxTree )
25- {
26- var methodDeclarations =
27- testsSyntaxTree
28- . GetRoot ( )
29- . DescendantNodes ( )
30- . OfType < MethodDeclarationSyntax > ( )
31- . ToArray ( ) ;
32-
33- var testResults =
34- from unitTestResult in result . Results . UnitTestResult
35- let testMethodDeclaration = unitTestResult . TestMethod ( methodDeclarations )
36- orderby testMethodDeclaration . GetLocation ( ) . GetLineSpan ( ) . StartLinePosition . Line
37- select ToTestResult ( unitTestResult , testMethodDeclaration ) ;
38-
39- return testResults . ToArray ( ) ;
40- }
41-
42- private static TestResult ToTestResult ( XmlUnitTestResult xmlUnitTestResult , MethodDeclarationSyntax testMethodDeclaration ) =>
43- new ( )
44- {
45- Name = xmlUnitTestResult . Name ( ) ,
46- Status = xmlUnitTestResult . Status ( ) ,
47- Message = xmlUnitTestResult . Message ( ) ,
48- Output = xmlUnitTestResult . Output ( ) ,
49- TaskId = testMethodDeclaration . TaskId ( ) ,
50- TestCode = testMethodDeclaration . TestCode ( )
51- } ;
52-
53- private static MethodDeclarationSyntax TestMethod ( this XmlUnitTestResult xmlUnitTestResult , IEnumerable < MethodDeclarationSyntax > methodDeclarations )
54- {
55- var classAndMethodName = xmlUnitTestResult . TestName . Split ( "." ) ;
56- var className = classAndMethodName [ 0 ] ;
57- var methodName = classAndMethodName [ 1 ] . Split ( '(' ) [ 0 ] ;
58-
59- return methodDeclarations . Single ( method =>
60- method . Identifier . Text == methodName &&
61- method . Parent is ClassDeclarationSyntax classDeclaration &&
62- classDeclaration . Identifier . Text == className ) ;
63- }
64-
65- private static string Name ( this XmlUnitTestResult xmlUnitTestResult ) =>
66- xmlUnitTestResult . TestName
67- . Substring ( xmlUnitTestResult . TestName . LastIndexOf ( "." , StringComparison . Ordinal ) + 1 )
68- . Humanize ( ) ;
69-
70- private static TestStatus Status ( this XmlUnitTestResult xmlUnitTestResult ) =>
71- xmlUnitTestResult . Outcome switch
72- {
73- "Passed" => TestStatus . Pass ,
74- "Failed" => TestStatus . Fail ,
75- _ => TestStatus . Error
76- } ;
77-
78- private static string Message ( this XmlUnitTestResult xmlUnitTestResult ) =>
79- xmlUnitTestResult . Output ? . ErrorInfo ? . Message ? . UseUnixNewlines ( ) ? . Trim ( ) ;
80-
81- private static string Output ( this XmlUnitTestResult xmlUnitTestResult ) =>
82- xmlUnitTestResult . Output ? . StdOut ? . UseUnixNewlines ( ) ? . Trim ( ) ;
83-
84- private static string TestCode ( this MethodDeclarationSyntax testMethod )
85- {
86- if ( testMethod . Body != null )
87- return SyntaxFactory . List ( testMethod . Body . Statements . Select ( statement => statement . WithoutLeadingTrivia ( ) ) ) . ToString ( ) ;
88-
89- return testMethod . ExpressionBody !
90- . Expression
91- . WithoutLeadingTrivia ( )
92- . ToString ( ) ;
93- }
94-
95- private static int ? TaskId ( this MethodDeclarationSyntax testMethod ) =>
96- testMethod . AttributeLists
97- . SelectMany ( attributeList => attributeList . Attributes )
98- . Where ( attribute =>
99- attribute . Name . ToString ( ) == "Task" &&
100- attribute . ArgumentList != null &&
101- attribute . ArgumentList . Arguments . Count == 1 &&
102- attribute . ArgumentList . Arguments [ 0 ] . Expression . IsKind ( SyntaxKind . NumericLiteralExpression ) )
103- . Select ( attribute => ( LiteralExpressionSyntax ) attribute . ArgumentList . Arguments [ 0 ] . Expression )
104- . Select ( taskNumberExpression => ( int ? ) taskNumberExpression . Token . Value ! )
105- . FirstOrDefault ( ) ;
19+ return result ? . Results is null ? [ ] : result . ToTestResults ( testsSyntaxTree ) ;
10620 }
10721
108- [ XmlRoot ( ElementName = "Output" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
109- public class XmlOutput
22+ private static TestResult [ ] ToTestResults ( this XmlTestRun result , SyntaxTree testsSyntaxTree )
11023 {
111- [ XmlElement ( ElementName = "StdOut" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
112- public string StdOut { get ; set ; }
24+ var methodDeclarations =
25+ testsSyntaxTree
26+ . GetRoot ( )
27+ . DescendantNodes ( )
28+ . OfType < MethodDeclarationSyntax > ( )
29+ . ToArray ( ) ;
30+
31+ var testResults =
32+ from unitTestResult in result . Results . UnitTestResult
33+ let testMethodDeclaration = unitTestResult . TestMethod ( methodDeclarations )
34+ orderby testMethodDeclaration . GetLocation ( ) . GetLineSpan ( ) . StartLinePosition . Line
35+ select ToTestResult ( unitTestResult , testMethodDeclaration ) ;
11336
114- [ XmlElement ( ElementName = "ErrorInfo" ,
115- Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
116- public XmlErrorInfo ErrorInfo { get ; set ; }
37+ return testResults . ToArray ( ) ;
11738 }
11839
119- [ XmlRoot ( ElementName = "UnitTestResult" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
120- public class XmlUnitTestResult
40+ private static TestResult ToTestResult ( XmlUnitTestResult xmlUnitTestResult , MethodDeclarationSyntax testMethodDeclaration ) =>
41+ new ( )
42+ {
43+ Name = xmlUnitTestResult . Name ( ) ,
44+ Status = xmlUnitTestResult . Status ( ) ,
45+ Message = xmlUnitTestResult . Message ( ) ,
46+ Output = xmlUnitTestResult . Output ( ) ,
47+ TaskId = testMethodDeclaration . TaskId ( ) ,
48+ TestCode = testMethodDeclaration . TestCode ( )
49+ } ;
50+
51+ private static MethodDeclarationSyntax TestMethod ( this XmlUnitTestResult xmlUnitTestResult , IEnumerable < MethodDeclarationSyntax > methodDeclarations )
12152 {
122- [ XmlElement ( ElementName = "Output" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
123- public XmlOutput Output { get ; set ; }
53+ var classAndMethodName = xmlUnitTestResult . TestName . Split ( "." ) ;
54+ var className = classAndMethodName [ 0 ] ;
55+ var methodName = classAndMethodName [ 1 ] . Split ( '(' ) [ 0 ] ;
56+
57+ return methodDeclarations . Single ( method =>
58+ method . Identifier . Text == methodName &&
59+ method . Parent is ClassDeclarationSyntax classDeclaration &&
60+ classDeclaration . Identifier . Text == className ) ;
61+ }
12462
125- [ XmlAttribute ( AttributeName = "testName" ) ]
126- public string TestName { get ; set ; }
63+ private static string Name ( this XmlUnitTestResult xmlUnitTestResult ) =>
64+ xmlUnitTestResult . TestName
65+ . Substring ( xmlUnitTestResult . TestName . LastIndexOf ( "." , StringComparison . Ordinal ) + 1 )
66+ . Humanize ( ) ;
12767
128- [ XmlAttribute ( AttributeName = "outcome" ) ]
129- public string Outcome { get ; set ; }
130- }
68+ private static TestStatus Status ( this XmlUnitTestResult xmlUnitTestResult ) =>
69+ xmlUnitTestResult . Outcome switch
70+ {
71+ "Passed" => TestStatus . Pass ,
72+ "Failed" => TestStatus . Fail ,
73+ _ => TestStatus . Error
74+ } ;
13175
132- [ XmlRoot ( ElementName = "ErrorInfo" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
133- public class XmlErrorInfo
134- {
135- [ XmlElement ( ElementName = "Message" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
136- public string Message { get ; set ; }
137- }
76+ private static string ? Message ( this XmlUnitTestResult xmlUnitTestResult ) =>
77+ xmlUnitTestResult . Output ? . ErrorInfo ? . Message ? . UseUnixNewlines ( ) ? . Trim ( ) ;
13878
139- [ XmlRoot ( ElementName = "Results" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
140- public class XmlResults
141- {
142- [ XmlElement ( ElementName = "UnitTestResult" ,
143- Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
144- public List < XmlUnitTestResult > UnitTestResult { get ; set ; }
145- }
79+ private static string ? Output ( this XmlUnitTestResult xmlUnitTestResult ) =>
80+ xmlUnitTestResult . Output ? . StdOut ? . UseUnixNewlines ( ) ? . Trim ( ) ;
14681
147- [ XmlRoot ( ElementName = "TestRun" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
148- public class XmlTestRun
82+ private static string TestCode ( this MethodDeclarationSyntax testMethod )
14983 {
150- [ XmlElement ( ElementName = "Results" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
151- public XmlResults Results { get ; set ; }
84+ if ( testMethod . Body is not null )
85+ return SyntaxFactory . List ( testMethod . Body . Statements . Select ( statement => statement . WithoutLeadingTrivia ( ) ) ) . ToString ( ) ;
86+
87+ return testMethod . ExpressionBody !
88+ . Expression
89+ . WithoutLeadingTrivia ( )
90+ . ToString ( ) ;
15291 }
92+
93+ private static int ? TaskId ( this MethodDeclarationSyntax testMethod ) =>
94+ testMethod . AttributeLists
95+ . SelectMany ( attributeList => attributeList . Attributes )
96+ . Where ( attribute =>
97+ attribute . Name . ToString ( ) == "Task" &&
98+ attribute . ArgumentList != null &&
99+ attribute . ArgumentList . Arguments . Count == 1 &&
100+ attribute . ArgumentList . Arguments [ 0 ] . Expression . IsKind ( SyntaxKind . NumericLiteralExpression ) )
101+ . Select ( attribute => ( LiteralExpressionSyntax ) attribute . ArgumentList ! . Arguments [ 0 ] . Expression )
102+ . Select ( taskNumberExpression => ( int ? ) taskNumberExpression . Token . Value ! )
103+ . FirstOrDefault ( ) ;
104+ }
105+
106+ [ XmlRoot ( ElementName = "Output" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
107+ public sealed class XmlOutput
108+ {
109+ [ XmlElement ( ElementName = "StdOut" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
110+ public string ? StdOut { get ; set ; }
111+
112+ [ XmlElement ( ElementName = "ErrorInfo" ,
113+ Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
114+ public XmlErrorInfo ? ErrorInfo { get ; set ; }
115+ }
116+
117+ [ XmlRoot ( ElementName = "UnitTestResult" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
118+ public sealed class XmlUnitTestResult
119+ {
120+ [ XmlElement ( ElementName = "Output" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
121+ public XmlOutput ? Output { get ; set ; }
122+
123+ [ XmlAttribute ( AttributeName = "testName" ) ]
124+ public required string TestName { get ; set ; }
125+
126+ [ XmlAttribute ( AttributeName = "outcome" ) ]
127+ public required string Outcome { get ; set ; }
128+ }
129+
130+ [ XmlRoot ( ElementName = "ErrorInfo" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
131+ public sealed class XmlErrorInfo
132+ {
133+ [ XmlElement ( ElementName = "Message" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
134+ public string ? Message { get ; set ; }
135+ }
136+
137+ [ XmlRoot ( ElementName = "Results" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
138+ public sealed class XmlResults
139+ {
140+ [ XmlElement ( ElementName = "UnitTestResult" ,
141+ Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
142+ public List < XmlUnitTestResult > ? UnitTestResult { get ; set ; }
143+ }
144+
145+ [ XmlRoot ( ElementName = "TestRun" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
146+ public sealed class XmlTestRun
147+ {
148+ [ XmlElement ( ElementName = "Results" , Namespace = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010" ) ]
149+ public required XmlResults Results { get ; set ; }
153150}
0 commit comments