Skip to content

Commit

Permalink
Convert to scriban (#2357)
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikSchierboom authored Feb 2, 2025
1 parent f2c700c commit d3bd5a3
Show file tree
Hide file tree
Showing 30 changed files with 264 additions and 297 deletions.
6 changes: 2 additions & 4 deletions docs/GENERATORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ To generate a practice exercise's tests, the test generator:

### Step 1: read `canonical-data.json` file

The test generator parses the test cases from the exercise's `canonical-data.json` using the [JSON.net library](https://www.newtonsoft.com/json).
The test generator parses the test cases from the exercise's `canonical-data.json` using the [System.Text.Json namespace](https://learn.microsoft.com/en-us/dotnet/api/system.text.json).

Since some canonical data uses nesting, the parsed test case includes an additional `path` field that contains the `description` properties of any parent elements, as well as the test case's own `description` property.

Note: the JSON is parsed to an `ExpandoObject` instance, which makes dealing with dynamic data easier.

### Step 2: omit excluded tests from `tests.toml` file

Each exercise has a `tests.toml` file, in which individual tests can be excluded/disabled.
Expand All @@ -44,7 +42,7 @@ Finally, the output of the rendered template is written to the exercise's test f

## Templates

The templates are rendered using the [Handlebars.Net library](https://github.com/Handlebars-Net/Handlebars.Net), which supports [handlebars syntax](https://handlebarsjs.com/).
The templates are rendered using the [Scriban library](https://github.com/scriban/scriban/).

## Command-line interface

Expand Down
10 changes: 5 additions & 5 deletions exercises/practice/acronym/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class AcronymTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.Equal({{lit expected}}, Acronym.Abbreviate({{lit input.phrase}}));
Assert.Equal({{testCase.expected | string.literal}}, Acronym.Abbreviate({{testCase.input.phrase | string.literal}}));
}
{{/test_cases}}
{{end}}
}
28 changes: 8 additions & 20 deletions exercises/practice/affine-cipher/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,15 @@ using Xunit;

public class AffineCipherTests
{
{{#test_cases_by_property.encode}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{short_test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.shortTestMethodName}}()
{
{{#if expected.error}}
Assert.Throws<ArgumentException>(() => AffineCipher.Encode({{lit input.phrase}}, {{input.key.a}}, {{input.key.b}}));
{{if testCase.expected.error}}
Assert.Throws<ArgumentException>(() => AffineCipher.{{testCase.property | string.capitalize}}({{testCase.input.phrase | string.literal}}, {{testCase.input.key.a}}, {{testCase.input.key.b}}));
{{else}}
Assert.Equal({{lit expected}}, AffineCipher.Encode({{lit input.phrase}}, {{input.key.a}}, {{input.key.b}}));
{{/if}}
Assert.Equal({{testCase.expected | string.literal}}, AffineCipher.{{testCase.property | string.capitalize}}({{testCase.input.phrase | string.literal}}, {{testCase.input.key.a}}, {{testCase.input.key.b}}));
{{end}}
}
{{/test_cases_by_property.encode}}

{{#test_cases_by_property.decode}}
[Fact(Skip = "Remove this Skip property to run this test")]
public void {{short_test_method_name}}()
{
{{#if expected.error}}
Assert.Throws<ArgumentException>(() => AffineCipher.Decode({{lit input.phrase}}, {{input.key.a}}, {{input.key.b}}));
{{else}}
Assert.Equal({{lit expected}}, AffineCipher.Decode({{lit input.phrase}}, {{input.key.a}}, {{input.key.b}}));
{{/if}}
}
{{/test_cases_by_property.decode}}
{{end}}
}
30 changes: 17 additions & 13 deletions exercises/practice/allergies/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,30 @@ using Xunit;

public class AllergiesTests
{
{{#test_cases_by_property.allergicTo}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCasesByProperty.allergicTo}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
var sut = new Allergies({{input.score}});
Assert.{{expected}}(sut.IsAllergicTo(Allergen.{{Capitalize input.item}}));
var sut = new Allergies({{testCase.input.score}});
Assert.{{testCase.expected ? "True" : "False"}}(sut.IsAllergicTo({{testCase.input.item | enum "Allergen"}}));
}
{{/test_cases_by_property.allergicTo}}
{{end}}

{{#test_cases_by_property.list}}
{{for testCase in testCasesByProperty.list}}
[Fact(Skip = "Remove this Skip property to run this test")]
public void {{test_method_name}}()
public void {{testCase.testMethodName}}()
{
var sut = new Allergies({{input.score}});
{{#isempty expected}}
var sut = new Allergies({{testCase.input.score}});
{{if testCase.expected.empty?}}
Assert.Empty(sut.List());
{{else}}
Allergen[] expected = [{{#each ../expected}}Allergen.{{Capitalize .}}{{#unless @last}},{{/unless}}{{/each}}];
Allergen[] expected = [
{{for expected in testCase.expected}}
{{expected | enum "Allergen"}}{{if !for.last}},{{end}}
{{end}}
];
Assert.Equal(expected, sut.List());
{{/isempty}}
{{end}}
}
{{/test_cases_by_property.list}}
{{end}}
}
10 changes: 5 additions & 5 deletions exercises/practice/darts/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class DartsTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.Equal({{expected}}, Darts.Score({{input.x}}, {{input.y}}));
Assert.Equal({{testCase.expected}}, Darts.Score({{testCase.input.x}}, {{testCase.input.y}}));
}
{{/test_cases}}
{{end}}
}
2 changes: 1 addition & 1 deletion exercises/practice/darts/DartsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void Just_outside_the_middle_circle()
[Fact(Skip = "Remove this Skip property to run this test")]
public void Just_within_the_outer_circle()
{
Assert.Equal(1, Darts.Score(-7, 7));
Assert.Equal(1, Darts.Score(-7.0, 7.0));
}

[Fact(Skip = "Remove this Skip property to run this test")]
Expand Down
26 changes: 5 additions & 21 deletions exercises/practice/difference-of-squares/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,11 @@ using Xunit;

public class DifferenceOfSquaresTests
{
{{#test_cases_by_property.squareOfSum}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{short_test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.shortTestMethodName}}()
{
Assert.Equal({{expected}}, DifferenceOfSquares.CalculateSquareOfSum({{input.number}}));
Assert.Equal({{testCase.expected}}, DifferenceOfSquares.Calculate{{testCase.property | string.capitalize}}({{testCase.input.number}}));
}
{{/test_cases_by_property.squareOfSum}}

{{#test_cases_by_property.sumOfSquares}}
[Fact(Skip = "Remove this Skip property to run this test")]
public void {{short_test_method_name}}()
{
Assert.Equal({{expected}}, DifferenceOfSquares.CalculateSumOfSquares({{input.number}}));
}
{{/test_cases_by_property.sumOfSquares}}

{{#test_cases_by_property.differenceOfSquares}}
[Fact(Skip = "Remove this Skip property to run this test")]
public void {{short_test_method_name}}()
{
Assert.Equal({{expected}}, DifferenceOfSquares.CalculateDifferenceOfSquares({{input.number}}));
}
{{/test_cases_by_property.differenceOfSquares}}
{{end}}
}
10 changes: 5 additions & 5 deletions exercises/practice/eliuds-eggs/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class EliudsEggsTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.Equal({{expected}}, EliudsEggs.EggCount({{input.number}}));
Assert.Equal({{testCase.expected}}, EliudsEggs.EggCount({{testCase.input.number}}));
}
{{/test_cases}}
{{end}}
}
16 changes: 8 additions & 8 deletions exercises/practice/hamming/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ using Xunit;

public class HammingTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
{{#if expected.error}}
Assert.Throws<ArgumentException>(() => Hamming.Distance({{lit input.strand1}}, {{lit input.strand2}}));
{{if testCase.expected.error}}
Assert.Throws<ArgumentException>(() => Hamming.Distance({{testCase.input.strand1 | string.literal}}, {{testCase.input.strand2 | string.literal}}));
{{else}}
Assert.Equal({{expected}}, Hamming.Distance({{lit input.strand1}}, {{lit input.strand2}}));
{{/if}}
Assert.Equal({{testCase.expected}}, Hamming.Distance({{testCase.input.strand1 | string.literal}}, {{testCase.input.strand2 | string.literal}}));
{{end}}
}
{{/test_cases}}
{{end}}
}
10 changes: 5 additions & 5 deletions exercises/practice/isogram/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class IsogramTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.{{expected}}(Isogram.IsIsogram({{lit input.phrase}}));
Assert.{{testCase.expected ? "True" : "False"}}(Isogram.IsIsogram({{testCase.input.phrase | string.literal}}));
}
{{/test_cases}}
{{end}}
}
10 changes: 5 additions & 5 deletions exercises/practice/leap/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class LeapTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.{{expected}}(Leap.IsLeapYear({{input.year}}));
Assert.{{testCase.expected ? "True" : "False"}}(Leap.IsLeapYear({{testCase.input.year}}));
}
{{/test_cases}}
{{end}}
}
10 changes: 5 additions & 5 deletions exercises/practice/pangram/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class PangramTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.{{lit expected}}(Pangram.IsPangram({{lit input.sentence}}));
Assert.{{testCase.expected ? "True" : "False"}}(Pangram.IsPangram({{testCase.input.sentence | string.literal}}));
}
{{/test_cases}}
{{end}}
}
16 changes: 8 additions & 8 deletions exercises/practice/perfect-numbers/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ using Xunit;

public class PerfectNumbersTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{short_test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.shortTestMethodName}}()
{
{{#if expected.error}}
Assert.Throws<ArgumentOutOfRangeException>(() => PerfectNumbers.Classify({{input.number}}));
{{if testCase.expected.error}}
Assert.Throws<ArgumentOutOfRangeException>(() => PerfectNumbers.Classify({{testCase.input.number}}));
{{else}}
Assert.Equal(Classification.{{Capitalize expected}}, PerfectNumbers.Classify({{input.number}}));
{{/if}}
Assert.Equal({{testCase.expected | enum "Classification"}}, PerfectNumbers.Classify({{testCase.input.number}}));
{{end}}
}
{{/test_cases}}
{{end}}
}
10 changes: 5 additions & 5 deletions exercises/practice/rotational-cipher/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class RotationalCipherTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.Equal({{lit expected}}, RotationalCipher.Rotate({{lit input.text}}, {{input.shiftKey}}));
Assert.Equal({{testCase.expected | string.literal}}, RotationalCipher.Rotate({{testCase.input.text | string.literal}}, {{testCase.input.shiftKey}}));
}
{{/test_cases}}
{{end}}
}
12 changes: 6 additions & 6 deletions exercises/practice/sieve/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ using Xunit;

public class SieveTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
int[] expected = [{{expected}}];
Assert.Equal(expected, Sieve.Primes({{input.limit}}));
int[] expected = {{testCase.expected}};
Assert.Equal(expected, Sieve.Primes({{testCase.input.limit}}));
}
{{/test_cases}}
{{end}}
}
12 changes: 6 additions & 6 deletions exercises/practice/space-age/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ using Xunit;

public class SpaceAgeTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
var sut = new SpaceAge({{input.seconds}});
Assert.Equal({{lit expected}}, sut.On{{input.planet}}(), precision: 2);
var sut = new SpaceAge({{testCase.input.seconds}});
Assert.Equal({{testCase.expected}}, sut.On{{testCase.input.planet}}(), precision: 2);
}
{{/test_cases}}
{{end}}
}
10 changes: 5 additions & 5 deletions exercises/practice/square-root/.meta/Generator.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ using Xunit;

public class SquareRootTests
{
{{#test_cases}}
[Fact{{#unless @first}}(Skip = "Remove this Skip property to run this test"){{/unless}}]
public void {{test_method_name}}()
{{for testCase in testCases}}
[Fact{{if !for.first}}(Skip = "Remove this Skip property to run this test"){{end}}]
public void {{testCase.testMethodName}}()
{
Assert.Equal({{expected}}, SquareRoot.Root({{input.radicand}}));
Assert.Equal({{testCase.expected}}, SquareRoot.Root({{testCase.input.radicand}}));
}
{{/test_cases}}
{{end}}
}
Loading

0 comments on commit d3bd5a3

Please sign in to comment.