1+ using System . Text . Json ;
2+ using System . Text . Json . Nodes ;
3+
4+ using Scriban ;
5+
6+ namespace Generators ;
7+
8+ internal static class TemplateGenerator
9+ {
10+ internal static void Generate ( Exercise exercise )
11+ {
12+ Console . WriteLine ( $ "{ exercise . Slug } : generating template...") ;
13+
14+ var canonicalData = CanonicalDataParser . Parse ( exercise ) ;
15+ var filteredCanonicalData = TestCasesConfiguration . RemoveExcludedTestCases ( canonicalData ) ;
16+
17+ var template = RenderTemplate ( filteredCanonicalData ) ;
18+ File . WriteAllText ( Paths . TemplateFile ( exercise ) , template ) ;
19+ }
20+
21+ private static string RenderTemplate ( CanonicalData canonicalData )
22+ {
23+ var error = canonicalData . TestCases . Where ( ExpectsError ) . Any ( ) ;
24+ var testCase = canonicalData . TestCases . First ( testCase => ! ExpectsError ( testCase ) ) ;
25+ var model = new { error , assert = Assertion ( testCase ) , throws = AssertThrows ( testCase ) } ;
26+
27+ var template = Template . Parse ( GeneratorTemplate ) ;
28+ return template . Render ( model ) . Trim ( ) + Environment . NewLine ;
29+ }
30+
31+ private static string Value ( string field , JsonNode ? testCase ) =>
32+ testCase is not null && testCase . GetValueKind ( ) == JsonValueKind . String
33+ ? $ "{{{{{field} | string.literal}}}}"
34+ : $ "{{{{{field}}}}}";
35+
36+ private static string Expected ( JsonNode testCase ) => Value ( "test.expected" , testCase [ "expected" ] ) ;
37+
38+ private static string Assertion ( JsonNode testCase ) =>
39+ testCase [ "expected" ] ! . GetValueKind ( ) switch
40+ {
41+ JsonValueKind . False or JsonValueKind . True => AssertBool ( testCase ) ,
42+ _ => AssertEqual ( testCase )
43+ } ;
44+
45+ private static string TestedMethodArguments ( JsonNode testCase ) =>
46+ string . Join ( ", " , testCase [ "input" ] ! . AsObject ( ) . Select ( kv => Value ( $ "test.input.{ kv . Key } ", kv . Value ! ) ) ) ;
47+
48+ private static string TestedMethodCall ( JsonNode testCase ) =>
49+ $ "{{{{testedClass}}}}.{{{{test.testedMethod}}}}({ TestedMethodArguments ( testCase ) } )";
50+
51+ private static string AssertBool ( JsonNode testCase ) =>
52+ $ "Assert.{{{{test.expected ? \" True\" : \" False\" }}}}({ TestedMethodCall ( testCase ) } );";
53+
54+ private static string AssertEqual ( JsonNode testCase ) =>
55+ $ "Assert.Equal({ Expected ( testCase ) } , { TestedMethodCall ( testCase ) } );";
56+
57+ private static string AssertThrows ( JsonNode testCase ) =>
58+ $ "Assert.Throws<ArgumentException>(() => { TestedMethodCall ( testCase ) } );";
59+
60+ private static bool ExpectsError ( this JsonNode testCase ) =>
61+ testCase [ "expected" ] is JsonObject jsonObject && jsonObject . ContainsKey ( "error" ) ;
62+
63+ private const string GeneratorTemplate = @"
64+ {{if error}}using System;{{end}}
65+ using Xunit;
66+
67+ public class {%{{{testClass}}}%}
68+ {
69+ {%{{{for test in tests}}}%}
70+ [Fact{%{{{if !for.first}}}%}(Skip = ""Remove this Skip property to run this test""){%{{{end}}}%}]
71+ public void {%{{{test.testMethod}}}%}()
72+ {
73+ {{-if error}}
74+ {%{{{if test.expected.error}}}%}
75+ {{throws}}
76+ {%{{{else}}}%}
77+ {{assert}}
78+ {%{{{end}}}%}
79+ {{-else}}
80+ {{assert}}
81+ {{-end}}
82+ }
83+ {%{{{end}}}%}
84+ }" ;
85+ }
0 commit comments