diff --git a/.gitignore b/.gitignore index dea37c33e2..cf03e5e831 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ packages/ obj/ bin/ *.userprefs -.dotnet/ +*.DotSettings.user .dotnet/ .vs/ diff --git a/config/maintainers.json b/config/maintainers.json index ca61dd1c8c..1c2c90c0ec 100644 --- a/config/maintainers.json +++ b/config/maintainers.json @@ -8,8 +8,8 @@ "name": "Erik Schierboom", "link_text": "My blog", "link_url": "http://www.erikschierboom.com/", - "avatar_url": null, - "bio": null + "avatar_url": "https://nl.gravatar.com/userimage/27030165/64dc5009cee6a1177883121d464d7743.jpg", + "bio": "I am a developer with a passion for learning new languages. C# is a well-designed and expressive language that I love programming in." }, { "github_username": "burtlo", diff --git a/docs/GENERATORS.md b/docs/GENERATORS.md index c8809145c7..f37eb750f6 100644 --- a/docs/GENERATORS.md +++ b/docs/GENERATORS.md @@ -1,12 +1,13 @@ -# Test Generators +# Test generators Test generators allow tracks to generate tests automatically without having to write them ourselves. Each test generator reads from the exercise's `canonical data`, which defines the name of the test, its inputs, and outputs. You can read more about exercism's approach to test suites [here](https://github.com/exercism/docs/blob/master/language-tracks/exercises/anatomy/test-suites.md). -Generating tests automatically removes any sort of user error when creating tests. We want the tests to be accurate with respect to its canonical data. Test generation also makes it much easier to keep tests up to date. As the canonical data changes, the tests will be automatically updated when the generator for that test is run. +Generating tests automatically removes any sort of user error when creating tests. Furthermore, we want the tests to be accurate with respect to its canonical data. Test generation also makes it much easier to keep tests up to date. As the canonical data changes, the tests will be automatically updated when the generator for that test is run. An example of a canonical data file can be found [here](https://github.com/exercism/problem-specifications/blob/master/exercises/bob/canonical-data.json) -## Common Terms +## Common terms + When looking through the canonical data and the generator code base, we use a lot of common terminology. This list hopefully clarifies what they represent. - Canonical Data - Represents the entire test suite. @@ -16,13 +17,14 @@ When looking through the canonical data and the generator code base, we use a lo - Input - The input for the test case. - Expected - The expected value when running the test case. -## Adding A Simple Generator -Adding a test generator file is straightforward. Simply add a new file to the generators folder with the name of the exercise (in PascalCase), and extend the `GeneratorExercise` abstract class. +## Adding a simple generator + +Adding a test generator is straightforward. Simply add a new file to the `Exercises/Generators` folder with the name of the exercise (in PascalCase), and create a class that extends the `GeneratorExercise` class. -An example of a simple generator would be the Bob exercise. The source is below, but you can freely view it in the repository [here](https://github.com/exercism/csharp/blob/master/generators/Exercises/Bob.cs). +An example of a simple generator would be the Bob exercise. The source is displayed below, but you can freely view it in the repository [here](https://github.com/exercism/csharp/blob/master/generators/Exercises/Bob.cs). ```csharp -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class Bob : GeneratorExercise { @@ -30,73 +32,217 @@ namespace Generators.Exercises } ``` -This is a fully working generator, no other code needs to be written. However, it's simplicity stems from the fact that the test suite and the program itself are relatively trivial. +This is a fully working generator, no other code needs to be written! However, it's simplicity stems from the fact that the test suite and the program itself are relatively trivial. + +## Adding a complex generator -## Adding A Complex Generator +When the generator's default output is not sufficient, you can override the `GeneratorExercise` class' virtual methods to override the default behavior. -A more *complex* generator would be the ComplexNumbers generator found [here](https://github.com/exercism/csharp/blob/master/generators/Exercises/ComplexNumbers.cs). +### Method 1: UpdateTestMethod(TestMethod testMethod) -The `GeneratorExercise` abstract class currently exposes five methods that are used for overriding the default behavior when generating an exercise. +Update the test method that described the test method being generated. When you are required to customize a test generator, overriding this method is virtually always what you want to do. -### void UpdateCanonicalData(CanonicalData canonicalData) -Update the canonical data for a given test. +There are many things that can be customized, of which we'll list the more common usages. -The most common use for this override is to iterate over each of the canonical data cases. +#### Customize test data -As an example, if you wanted to change the default behavior so that when the `Input` value of a test is a negative number, an exception should be thrown, the code would look like this. +It is not uncommon that a generator has to transform its input data or expected value to a different value/representation. + +An example of this is the [bracket-push](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/BracketPush.cs) generator, which has a `"value"` input value, which is of type `string`. However, this `string` value contains a backslash, which needs to escaped in order for it to be rendered correctly: ```csharp -protected override void UpdateCanonicalData(CanonicalData canonicalData) +protected override void UpdateTestMethod(TestMethod testMethod) { - foreach (var canonicalDataCase in canonicalData.Cases) - { - var caseInputLessThanZero = (long)canonicalDataCase.Input["number"] < 0; - canonicalDataCase.ExceptionThrown = caseInputLessThanZero ? typeof(ArgumentException) : null; - } + testMethod.Input["value"] = testMethod.Input["value"].Replace("\\", "\\\\"); + // [...] } ``` -### HashSet\ AddAdditionalNamespaces() -Allows more namespaces to be added to the test suite. +Another common use case is to handle empty arrays. If an array is empty, its type will default to `JArray`, which doesn't have any type information. To allow the generator to output a correctly typed array, we have to convert the `JArray` to an array first. -The tests use `Xunit` so all tests will automatically include the `Xunit` namespace. However, more advanced tests may require additional namespaces. +An example of this is the [proverb](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/Proverb.cs) generator, which converts the `JArray` to an empty `string` array: ```csharp -protected override HashSet AddAdditionalNamespaces() +protected override void UpdateTestMethod(TestMethod testMethod) { - return new HashSet() - { - typeof(Dictionary).Namespace - }; + // [...] + + if (testMethod.Input["strings"] is JArray) + testMethod.Input["strings"] = Array.Empty(); + + if (testMethod.Expected is JArray) + testMethod.Expected = Array.Empty(); +} +``` + +#### Output test data as variables + +Sometimes, it might make sense to not define a test method's data inline, but as variables. + +An example of this is the [crypto-square](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/CryptoSquare.cs) generator, which indicates that both the test method input as well as the expected value, should be stored in variables: + +```csharp +protected override void UpdateTestMethod(TestMethod testMethod) +{ + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; +} +``` + +#### Custom tested method type + +By default, the generator will test a static method. However, you can also test for instance methods, extension methods, properties and constructors. + +An example of this is the [roman-numerals](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/RomanNumerals.cs) generator, which indicates that it tests an extensions method: + +```csharp +protected override void UpdateTestMethod(TestMethod testMethod) +{ + testMethod.TestedMethodType = TestedMethodType.ExtensionMethod; + testMethod.TestedMethod = "ToRoman"; } ``` -This snippet would add the namespace that the `Dictionary` collection lives in (`System.Collections.Generic`). +#### Change names used + +As we saw in the previous example, you can also customize the name of the tested method. You are also allowed to customize the tested class' name and the test method name. -### string RenderTestMethodBody[Arrange/Act/Assert] -Override the default behavior when rendering a test methods arrange, act, and/or assert sections. +An example of this is the [triangle](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/Triangle.cs) generator, which by default generates duplicate test method names (which will be a compile-time error), but instead uses the `TestMethodNameWithPath` to use the full path as the test method name (effectively making the test method name unique): + +```csharp +protected override void UpdateTestMethod(TestMethod testMethod) +{ + // [...] + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + // [...] +} +``` -More advanced tests may need to leverage a `template`. A template allows you to add additional code to a test and assert more complex statements. +#### Test for an exception being thrown -An example of this is the [RunLengthEncoding](https://github.com/exercism/csharp/blob/master/generators/Exercises/RunLengthEncoding.cs) test. +Some test methods want to verify that an exception is being thrown. -Here the **Assert** is being overridden. The assert needs to call additional functions, but only if the property is `consistency`. Otherwise, render the assert as usual. +An example of this is the [rna-transcription](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/RnaTranscription.cs) generator, which defines that some of its test methods should throw an `ArgumentException`: -### string[] RenderAdditionalMethods() -Allow additional methods to be added to the test suite. +```csharp +protected override void UpdateTestMethod(TestMethod testMethod) +{ + if (testMethod.Expected is null) + testMethod.ExceptionThrown = typeof(ArgumentException); +} +``` -There may exist cases where a suite of unit tests will need to reuse the same logic in each of the tests. Rather than duplicating code, this method allows you to provide helper methods for the tests. +Note that `ArgumentException` type's namespace will be automatically added to the list of namespaces used in the test class. -An example of this is the [Tournament](https://github.com/exercism/csharp/blob/master/generators/Exercises/Tournament.cs#L45) generator. +#### Custom input/constructor parameters -Additional methods added using this override will be added to the bottom of the test suite. +In some cases, you might want to override the parameters that are used as input parameters. + +An example of this is the [two-fer](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/TwoFer.cs) generator, which does not use any input parameters when the `"name"` input parameter is set to `null`: + +```csharp +protected override void UpdateTestMethod(TestMethod testMethod) +{ + // [...] + + if (testMethod.Input["name"] is null) + testMethod.InputParameters = Array.Empty(); +} +``` + +If a test method tests an instance method, you can also specify which parameters to use as constructor parameters (the others will be input parameters, unless specified otherwise). + +An example of this is the [matrix](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/Matrix.cs) generator, which specifies that the `"string"` parameter should be passed as a constructor parameter: + +```csharp +protected override void UpdateTestMethod(TestMethod testMethod) +{ + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.ConstructorInputParameters = new[] { "string" }; +} +``` + +#### Custom arrange/act/assert code + +Although this should be used as a last resort, some generators might want to skip the default generation completely and control which arrange, act or assert code the test method should contain. + +An example of this is the [run-length-encoding](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/RunLengthEncoding.cs) generator, which uses a custom assertion for one specific property: + +```csharp +protected override void UpdateTestMethod(TestMethod testMethod) +{ + // [...] + + if (testMethod.Property == "consistency") + testMethod.Assert = RenderConsistencyToAssert(testMethod); +} + +private string RenderConsistencyToAssert(TestMethod testMethod) +{ + var expected = Render.Object(testMethod.Expected); + var actual = $"{testMethod.TestedClass}.Decode({testMethod.TestedClass}.Encode({expected}))"; + return Render.AssertEqual(expected, actual); +} +``` + +Note that the `Render` instance is used to render the assertion and the expected value. + +### Method 2: UpdateNamespaces(ISet namespaces) + +Allows additional namespaces to be added to the test suite. + +All tests use the `Xunit` framework, so each test class will automatically include the `Xunit` namespace. However, some test classes may require additional namespaces. + +An example of this is the [gigasecond](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/Gigasecond.cs) generator, which uses the `DateTime` class in its test methods, and thus adds its namespace to the list of namespaces: + +```csharp +protected override void UpdateNamespaces(ISet namespaces) +{ + namespaces.Add(typeof(DateTime).Namespace); +} +``` + +Note that as mentioned before, the namespace of any thrown exception types are automatically added to the list of namespaces. + +### Method 3: UpdateTestClass(TestClass testClass) + +This method allows you to customize the output of the test class. Only in rare cases would you want to override this method. The most common use case to override this method, is to add additional (helper) methods to the test suite. + +An example of this is the [tournament](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/Tournament.cs) generator, which adds a helper method to the test suite: + +```csharp +protected override void UpdateTestClass(TestClass testClass) +{ + AddRunTallyMethod(testClass); +} + +private static void AddRunTallyMethod(TestClass testClass) +{ + testClass.AdditionalMethods.Add(@" +private string RunTally(string input) +{ + var encoding = new UTF8Encoding(); + + using (var inStream = new MemoryStream(encoding.GetBytes(input))) + using (var outStream = new MemoryStream()) + { + Tournament.Tally(inStream, outStream); + return encoding.GetString(outStream.ToArray()); + } +}"); +} +``` + +Additional methods will be added to the bottom of the test suite. ## Updating Existing Files + It is possible that an existing exercise does not match the canonical data. It is OK to update the exercise stub and/or the exercise example to follow the canonical data! An example might be that an exercise is named SumOfMultiples, but the SumOfMultiples.cs and Example.cs files both use `Multiples` as the name of the class. Also, if you find an issue with one of the existing generators or test suites simply open up the generator that you would like to update, make your changes, and then run the generators. ## Running The Generators + This repository is coded against [.NET Core](https://www.microsoft.com/net/core). To run the generators all you need to do is run the following command in the generators directory: `dotnet run` @@ -112,4 +258,5 @@ Once the generator has been run, you can view the output of your generation by n `exercises/bob/BobTest.cs` ## Submitting A Generator + If you are satisfied with the output of your generator, we would love for you to submit a pull request! Please include your generator, updated test suite, and any other corresponding files that you may have changed. diff --git a/exercises/all-your-base/AllYourBaseTest.cs b/exercises/all-your-base/AllYourBaseTest.cs index abfaf4e897..9ce28a7e49 100644 --- a/exercises/all-your-base/AllYourBaseTest.cs +++ b/exercises/all-your-base/AllYourBaseTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 2.3.0 of the canonical data. -using Xunit; using System; +using Xunit; public class AllYourBaseTest { @@ -89,7 +89,7 @@ public void Number_15_bit_integer() public void Empty_list() { var inputBase = 2; - var digits = new int[0]; + var digits = Array.Empty(); var outputBase = 10; var expected = new[] { 0 }; Assert.Equal(expected, AllYourBase.Rebase(inputBase, digits, outputBase)); @@ -138,7 +138,7 @@ public void Input_base_is_one() public void Input_base_is_zero() { var inputBase = 0; - var digits = new int[0]; + var digits = Array.Empty(); var outputBase = 10; Assert.Throws(() => AllYourBase.Rebase(inputBase, digits, outputBase)); } diff --git a/exercises/alphametics/AlphameticsTest.cs b/exercises/alphametics/AlphameticsTest.cs index 3ce16c20ce..ce325e38b8 100644 --- a/exercises/alphametics/AlphameticsTest.cs +++ b/exercises/alphametics/AlphameticsTest.cs @@ -1,8 +1,8 @@ // This file was auto-generated based on version 1.2.0 of the canonical data. -using Xunit; using System; using System.Collections.Generic; +using Xunit; public class AlphameticsTest { diff --git a/exercises/binary-search-tree/BinarySearchTreeTest.cs b/exercises/binary-search-tree/BinarySearchTreeTest.cs index 970c4b81c7..39acafc3e0 100644 --- a/exercises/binary-search-tree/BinarySearchTreeTest.cs +++ b/exercises/binary-search-tree/BinarySearchTreeTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.0.0 of the canonical data. -using Xunit; using System.Linq; +using Xunit; public class BinarySearchTreeTest { @@ -12,19 +12,6 @@ public void Data_is_retained() Assert.Equal(4, tree.Value); } - [Fact(Skip = "Remove to run test")] - public void Can_create_complex_tree() - { - var tree = new BinarySearchTree(new[] { 4, 2, 6, 1, 3, 5, 7 }); - Assert.Equal(4, tree.Value); - Assert.Equal(2, tree.Left.Value); - Assert.Equal(1, tree.Left.Left.Value); - Assert.Equal(3, tree.Left.Right.Value); - Assert.Equal(6, tree.Right.Value); - Assert.Equal(5, tree.Right.Left.Value); - Assert.Equal(7, tree.Right.Right.Value); - } - [Fact(Skip = "Remove to run test")] public void Smaller_number_at_left_node() { @@ -49,6 +36,19 @@ public void Greater_number_at_right_node() Assert.Equal(5, tree.Right.Value); } + [Fact(Skip = "Remove to run test")] + public void Can_create_complex_tree() + { + var tree = new BinarySearchTree(new[] { 4, 2, 6, 1, 3, 5, 7 }); + Assert.Equal(4, tree.Value); + Assert.Equal(2, tree.Left.Value); + Assert.Equal(1, tree.Left.Left.Value); + Assert.Equal(3, tree.Left.Right.Value); + Assert.Equal(6, tree.Right.Value); + Assert.Equal(5, tree.Right.Left.Value); + Assert.Equal(7, tree.Right.Right.Value); + } + [Fact(Skip = "Remove to run test")] public void Can_sort_single_number() { diff --git a/exercises/binary-search/BinarySearchTest.cs b/exercises/binary-search/BinarySearchTest.cs index 0a8c69597e..cf4c027b81 100644 --- a/exercises/binary-search/BinarySearchTest.cs +++ b/exercises/binary-search/BinarySearchTest.cs @@ -1,5 +1,6 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. +using System; using Xunit; public class BinarySearchTest @@ -79,7 +80,7 @@ public void A_value_larger_than_the_arrays_largest_value_is_not_included() [Fact(Skip = "Remove to run test")] public void Nothing_is_included_in_an_empty_array() { - var array = new int[0]; + var array = Array.Empty(); var sut = new BinarySearch(array); Assert.Equal(-1, sut.Find(1)); } diff --git a/exercises/book-store/BookStoreTest.cs b/exercises/book-store/BookStoreTest.cs index c6332e5edd..204505245f 100644 --- a/exercises/book-store/BookStoreTest.cs +++ b/exercises/book-store/BookStoreTest.cs @@ -1,5 +1,6 @@ // This file was auto-generated based on version 1.3.0 of the canonical data. +using System; using Xunit; public class BookStoreTest @@ -21,7 +22,7 @@ public void Two_of_the_same_book() [Fact(Skip = "Remove to run test")] public void Empty_basket() { - var basket = new int[0]; + var basket = Array.Empty(); Assert.Equal(0, BookStore.Total(basket)); } diff --git a/exercises/bowling/BowlingTest.cs b/exercises/bowling/BowlingTest.cs index e936ffd8e4..1d251b714a 100644 --- a/exercises/bowling/BowlingTest.cs +++ b/exercises/bowling/BowlingTest.cs @@ -1,8 +1,8 @@ // This file was auto-generated based on version 1.2.0 of the canonical data. -using Xunit; using System; using System.Collections.Generic; +using Xunit; public class BowlingTest { @@ -10,7 +10,7 @@ public class BowlingTest public void Should_be_able_to_score_a_game_with_all_zeros() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(0, actual); @@ -20,7 +20,7 @@ public void Should_be_able_to_score_a_game_with_all_zeros() public void Should_be_able_to_score_a_game_with_no_strikes_or_spares() { var sut = new BowlingGame(); - var previousRolls = new [] { 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6 }; + var previousRolls = new[] { 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(90, actual); @@ -30,7 +30,7 @@ public void Should_be_able_to_score_a_game_with_no_strikes_or_spares() public void A_spare_followed_by_zeros_is_worth_ten_points() { var sut = new BowlingGame(); - var previousRolls = new [] { 6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(10, actual); @@ -40,7 +40,7 @@ public void A_spare_followed_by_zeros_is_worth_ten_points() public void Points_scored_in_the_roll_after_a_spare_are_counted_twice() { var sut = new BowlingGame(); - var previousRolls = new [] { 6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(16, actual); @@ -50,7 +50,7 @@ public void Points_scored_in_the_roll_after_a_spare_are_counted_twice() public void Consecutive_spares_each_get_a_one_roll_bonus() { var sut = new BowlingGame(); - var previousRolls = new [] { 5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(31, actual); @@ -60,7 +60,7 @@ public void Consecutive_spares_each_get_a_one_roll_bonus() public void A_spare_in_the_last_frame_gets_a_one_roll_bonus_that_is_counted_once() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(17, actual); @@ -70,7 +70,7 @@ public void A_spare_in_the_last_frame_gets_a_one_roll_bonus_that_is_counted_once public void A_strike_earns_ten_points_in_a_frame_with_a_single_roll() { var sut = new BowlingGame(); - var previousRolls = new [] { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(10, actual); @@ -80,7 +80,7 @@ public void A_strike_earns_ten_points_in_a_frame_with_a_single_roll() public void Points_scored_in_the_two_rolls_after_a_strike_are_counted_twice_as_a_bonus() { var sut = new BowlingGame(); - var previousRolls = new [] { 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(26, actual); @@ -90,7 +90,7 @@ public void Points_scored_in_the_two_rolls_after_a_strike_are_counted_twice_as_a public void Consecutive_strikes_each_get_the_two_roll_bonus() { var sut = new BowlingGame(); - var previousRolls = new [] { 10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(81, actual); @@ -100,7 +100,7 @@ public void Consecutive_strikes_each_get_the_two_roll_bonus() public void A_strike_in_the_last_frame_gets_a_two_roll_bonus_that_is_counted_once() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(18, actual); @@ -110,7 +110,7 @@ public void A_strike_in_the_last_frame_gets_a_two_roll_bonus_that_is_counted_onc public void Rolling_a_spare_with_the_two_roll_bonus_does_not_get_a_bonus_roll() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(20, actual); @@ -120,7 +120,7 @@ public void Rolling_a_spare_with_the_two_roll_bonus_does_not_get_a_bonus_roll() public void Strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(30, actual); @@ -130,7 +130,7 @@ public void Strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls() public void A_strike_with_the_one_roll_bonus_after_a_spare_in_the_last_frame_does_not_get_a_bonus() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(20, actual); @@ -140,7 +140,7 @@ public void A_strike_with_the_one_roll_bonus_after_a_spare_in_the_last_frame_doe public void All_strikes_is_a_perfect_game() { var sut = new BowlingGame(); - var previousRolls = new [] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; + var previousRolls = new[] { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(300, actual); @@ -150,7 +150,7 @@ public void All_strikes_is_a_perfect_game() public void Rolls_cannot_score_negative_points() { var sut = new BowlingGame(); - var previousRolls = new int[0]; + var previousRolls = Array.Empty(); DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(-1)); } @@ -159,7 +159,7 @@ public void Rolls_cannot_score_negative_points() public void A_roll_cannot_score_more_than_10_points() { var sut = new BowlingGame(); - var previousRolls = new int[0]; + var previousRolls = Array.Empty(); DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(11)); } @@ -168,7 +168,7 @@ public void A_roll_cannot_score_more_than_10_points() public void Two_rolls_in_a_frame_cannot_score_more_than_10_points() { var sut = new BowlingGame(); - var previousRolls = new [] { 5 }; + var previousRolls = new[] { 5 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(6)); } @@ -177,7 +177,7 @@ public void Two_rolls_in_a_frame_cannot_score_more_than_10_points() public void Bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(11)); } @@ -186,7 +186,7 @@ public void Bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more_than_1 public void Two_bonus_rolls_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(6)); } @@ -195,7 +195,7 @@ public void Two_bonus_rolls_after_a_strike_in_the_last_frame_cannot_score_more_t public void Two_bonus_rolls_after_a_strike_in_the_last_frame_can_score_more_than_10_points_if_one_is_a_strike() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6 }; DoRoll(previousRolls, sut); var actual = sut.Score(); Assert.Equal(26, actual); @@ -205,7 +205,7 @@ public void Two_bonus_rolls_after_a_strike_in_the_last_frame_can_score_more_than public void The_second_bonus_rolls_after_a_strike_in_the_last_frame_cannot_be_a_strike_if_the_first_one_is_not_a_strike() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(10)); } @@ -214,7 +214,7 @@ public void The_second_bonus_rolls_after_a_strike_in_the_last_frame_cannot_be_a_ public void Second_bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(11)); } @@ -223,7 +223,7 @@ public void Second_bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more public void An_unstarted_game_cannot_be_scored() { var sut = new BowlingGame(); - var previousRolls = new int[0]; + var previousRolls = Array.Empty(); DoRoll(previousRolls, sut); Assert.Throws(() => sut.Score()); } @@ -232,7 +232,7 @@ public void An_unstarted_game_cannot_be_scored() public void An_incomplete_game_cannot_be_scored() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0 }; + var previousRolls = new[] { 0, 0 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Score()); } @@ -241,7 +241,7 @@ public void An_incomplete_game_cannot_be_scored() public void Cannot_roll_if_game_already_has_ten_frames() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(0)); } @@ -250,7 +250,7 @@ public void Cannot_roll_if_game_already_has_ten_frames() public void Bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Score()); } @@ -259,7 +259,7 @@ public void Bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_sco public void Both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Score()); } @@ -268,7 +268,7 @@ public void Both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_befor public void Bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_can_be_calculated() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Score()); } @@ -277,7 +277,7 @@ public void Bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score public void Cannot_roll_after_bonus_roll_for_spare() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 2 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 2 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(2)); } @@ -286,12 +286,12 @@ public void Cannot_roll_after_bonus_roll_for_spare() public void Cannot_roll_after_bonus_rolls_for_strike() { var sut = new BowlingGame(); - var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 3, 2 }; + var previousRolls = new[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 3, 2 }; DoRoll(previousRolls, sut); Assert.Throws(() => sut.Roll(2)); } - public void DoRoll(ICollection rolls, BowlingGame sut) + public void DoRoll(IEnumerable rolls, BowlingGame sut) { foreach (var roll in rolls) { diff --git a/exercises/change/ChangeTest.cs b/exercises/change/ChangeTest.cs index 1c7f79169e..9663ad5867 100644 --- a/exercises/change/ChangeTest.cs +++ b/exercises/change/ChangeTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.2.0 of the canonical data. -using Xunit; using System; +using Xunit; public class ChangeTest { diff --git a/exercises/circular-buffer/CircularBufferTest.cs b/exercises/circular-buffer/CircularBufferTest.cs index e0ae774635..f5be48eedd 100644 --- a/exercises/circular-buffer/CircularBufferTest.cs +++ b/exercises/circular-buffer/CircularBufferTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class CircularBufferTest { diff --git a/exercises/clock/ClockTest.cs b/exercises/clock/ClockTest.cs index 94fd421c72..8bd8768f08 100644 --- a/exercises/clock/ClockTest.cs +++ b/exercises/clock/ClockTest.cs @@ -253,7 +253,7 @@ public void Subtract_more_than_two_days() public void Clocks_with_same_time() { var sut = new Clock(15, 37); - Assert.Equal(new Clock(15, 37), sut); + Assert.Equal(new Clock(15, 37), sut); } [Fact(Skip = "Remove to run test")] @@ -274,83 +274,83 @@ public void Clocks_an_hour_apart() public void Clocks_with_hour_overflow() { var sut = new Clock(34, 37); - Assert.Equal(new Clock(10, 37), sut); + Assert.Equal(new Clock(10, 37), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_hour_overflow_by_several_days() { var sut = new Clock(99, 11); - Assert.Equal(new Clock(3, 11), sut); + Assert.Equal(new Clock(3, 11), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_hour() { var sut = new Clock(-2, 40); - Assert.Equal(new Clock(22, 40), sut); + Assert.Equal(new Clock(22, 40), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_hour_that_wraps() { var sut = new Clock(-31, 3); - Assert.Equal(new Clock(17, 3), sut); + Assert.Equal(new Clock(17, 3), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_hour_that_wraps_multiple_times() { var sut = new Clock(-83, 49); - Assert.Equal(new Clock(13, 49), sut); + Assert.Equal(new Clock(13, 49), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_minute_overflow() { var sut = new Clock(0, 1441); - Assert.Equal(new Clock(0, 1), sut); + Assert.Equal(new Clock(0, 1), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_minute_overflow_by_several_days() { var sut = new Clock(2, 4322); - Assert.Equal(new Clock(2, 2), sut); + Assert.Equal(new Clock(2, 2), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_minute() { var sut = new Clock(3, -20); - Assert.Equal(new Clock(2, 40), sut); + Assert.Equal(new Clock(2, 40), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_minute_that_wraps() { var sut = new Clock(5, -1490); - Assert.Equal(new Clock(4, 10), sut); + Assert.Equal(new Clock(4, 10), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_minute_that_wraps_multiple_times() { var sut = new Clock(6, -4305); - Assert.Equal(new Clock(6, 15), sut); + Assert.Equal(new Clock(6, 15), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_hours_and_minutes() { var sut = new Clock(-12, -268); - Assert.Equal(new Clock(7, 32), sut); + Assert.Equal(new Clock(7, 32), sut); } [Fact(Skip = "Remove to run test")] public void Clocks_with_negative_hours_and_minutes_that_wrap() { var sut = new Clock(-54, -11513); - Assert.Equal(new Clock(18, 7), sut); + Assert.Equal(new Clock(18, 7), sut); } } \ No newline at end of file diff --git a/exercises/collatz-conjecture/CollatzConjectureTest.cs b/exercises/collatz-conjecture/CollatzConjectureTest.cs index 32b512d359..e5748ef4f8 100644 --- a/exercises/collatz-conjecture/CollatzConjectureTest.cs +++ b/exercises/collatz-conjecture/CollatzConjectureTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.2.0 of the canonical data. -using Xunit; using System; +using Xunit; public class CollatzConjectureTest { diff --git a/exercises/complex-numbers/ComplexNumbersTest.cs b/exercises/complex-numbers/ComplexNumbersTest.cs index 8835b7d521..4774dc6204 100644 --- a/exercises/complex-numbers/ComplexNumbersTest.cs +++ b/exercises/complex-numbers/ComplexNumbersTest.cs @@ -1,20 +1,11 @@ // This file was auto-generated based on version 1.3.0 of the canonical data. -using Xunit; using System; +using Xunit; public class ComplexNumbersTest { [Fact] - public void Imaginary_unit() - { - var sut = new ComplexNumber(0, 1); - var expected = new ComplexNumber(-1, 0); - Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(0, 1)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(0, 1)).Imaginary(), precision: 15); - } - - [Fact(Skip = "Remove to run test")] public void Real_part_of_a_purely_real_number() { var sut = new ComplexNumber(1, 0); @@ -56,13 +47,22 @@ public void Imaginary_part_of_a_number_with_real_and_imaginary_part() Assert.Equal(2, sut.Imaginary()); } + [Fact(Skip = "Remove to run test")] + public void Imaginary_unit() + { + var sut = new ComplexNumber(0, 1); + var expected = new ComplexNumber(-1, 0); + Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(0, 1)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(0, 1)).Imaginary(), precision: 7); + } + [Fact(Skip = "Remove to run test")] public void Add_purely_real_numbers() { var sut = new ComplexNumber(1, 0); var expected = new ComplexNumber(3, 0); - Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(2, 0)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(2, 0)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(2, 0)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(2, 0)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -70,8 +70,8 @@ public void Add_purely_imaginary_numbers() { var sut = new ComplexNumber(0, 1); var expected = new ComplexNumber(0, 3); - Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(0, 2)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(0, 2)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(0, 2)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(0, 2)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -79,8 +79,8 @@ public void Add_numbers_with_real_and_imaginary_part() { var sut = new ComplexNumber(1, 2); var expected = new ComplexNumber(4, 6); - Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(3, 4)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(3, 4)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Add(new ComplexNumber(3, 4)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Add(new ComplexNumber(3, 4)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -88,8 +88,8 @@ public void Subtract_purely_real_numbers() { var sut = new ComplexNumber(1, 0); var expected = new ComplexNumber(-1, 0); - Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(2, 0)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(2, 0)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(2, 0)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(2, 0)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -97,8 +97,8 @@ public void Subtract_purely_imaginary_numbers() { var sut = new ComplexNumber(0, 1); var expected = new ComplexNumber(0, -1); - Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(0, 2)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(0, 2)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(0, 2)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(0, 2)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -106,8 +106,8 @@ public void Subtract_numbers_with_real_and_imaginary_part() { var sut = new ComplexNumber(1, 2); var expected = new ComplexNumber(-2, -2); - Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(3, 4)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(3, 4)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Sub(new ComplexNumber(3, 4)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Sub(new ComplexNumber(3, 4)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -115,8 +115,8 @@ public void Multiply_purely_real_numbers() { var sut = new ComplexNumber(1, 0); var expected = new ComplexNumber(2, 0); - Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(2, 0)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(2, 0)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(2, 0)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(2, 0)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -124,8 +124,8 @@ public void Multiply_purely_imaginary_numbers() { var sut = new ComplexNumber(0, 1); var expected = new ComplexNumber(-2, 0); - Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(0, 2)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(0, 2)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(0, 2)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(0, 2)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -133,8 +133,8 @@ public void Multiply_numbers_with_real_and_imaginary_part() { var sut = new ComplexNumber(1, 2); var expected = new ComplexNumber(-5, 10); - Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(3, 4)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(3, 4)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Mul(new ComplexNumber(3, 4)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Mul(new ComplexNumber(3, 4)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -142,8 +142,8 @@ public void Divide_purely_real_numbers() { var sut = new ComplexNumber(1, 0); var expected = new ComplexNumber(0.5, 0); - Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(2, 0)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(2, 0)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(2, 0)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(2, 0)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -151,8 +151,8 @@ public void Divide_purely_imaginary_numbers() { var sut = new ComplexNumber(0, 1); var expected = new ComplexNumber(0.5, 0); - Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(0, 2)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(0, 2)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(0, 2)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(0, 2)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -160,8 +160,8 @@ public void Divide_numbers_with_real_and_imaginary_part() { var sut = new ComplexNumber(1, 2); var expected = new ComplexNumber(0.44, 0.08); - Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(3, 4)).Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(3, 4)).Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Div(new ComplexNumber(3, 4)).Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Div(new ComplexNumber(3, 4)).Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -204,8 +204,8 @@ public void Conjugate_a_purely_real_number() { var sut = new ComplexNumber(5, 0); var expected = new ComplexNumber(5, 0); - Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -213,8 +213,8 @@ public void Conjugate_a_purely_imaginary_number() { var sut = new ComplexNumber(0, 5); var expected = new ComplexNumber(0, -5); - Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -222,8 +222,8 @@ public void Conjugate_a_number_with_real_and_imaginary_part() { var sut = new ComplexNumber(1, 1); var expected = new ComplexNumber(1, -1); - Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Conjugate().Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Conjugate().Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -231,8 +231,8 @@ public void Eulers_identity_formula() { var sut = new ComplexNumber(0, Math.PI); var expected = new ComplexNumber(-1, 0); - Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -240,8 +240,8 @@ public void Exponential_of_0() { var sut = new ComplexNumber(0, 0); var expected = new ComplexNumber(1, 0); - Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -249,8 +249,8 @@ public void Exponential_of_a_purely_real_number() { var sut = new ComplexNumber(1, 0); var expected = new ComplexNumber(Math.E, 0); - Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7); } [Fact(Skip = "Remove to run test")] @@ -258,7 +258,7 @@ public void Exponential_of_a_number_with_real_and_imaginary_part() { var sut = new ComplexNumber(Math.Log(2.0), Math.PI); var expected = new ComplexNumber(-2, 0); - Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 15); - Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 15); + Assert.Equal(expected.Real(), sut.Exp().Real(), precision: 7); + Assert.Equal(expected.Imaginary(), sut.Exp().Imaginary(), precision: 7); } } \ No newline at end of file diff --git a/exercises/connect/ConnectTest.cs b/exercises/connect/ConnectTest.cs index 2417d52d6d..6e0da7f075 100644 --- a/exercises/connect/ConnectTest.cs +++ b/exercises/connect/ConnectTest.cs @@ -7,14 +7,13 @@ public class ConnectTest [Fact] public void An_empty_board_has_no_winner() { - var board = new [] - { + var board = new[] + { ". . . . .", " . . . . .", " . . . . .", " . . . . .", " . . . . ." - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.None, sut.Result()); @@ -23,9 +22,9 @@ public void An_empty_board_has_no_winner() [Fact(Skip = "Remove to run test")] public void X_can_win_on_a_1x1_board() { - var board = new [] - { - "X" + var board = new[] + { + "X" }; var sut = new Connect(board); Assert.Equal(ConnectWinner.Black, sut.Result()); @@ -34,9 +33,9 @@ public void X_can_win_on_a_1x1_board() [Fact(Skip = "Remove to run test")] public void O_can_win_on_a_1x1_board() { - var board = new [] - { - "O" + var board = new[] + { + "O" }; var sut = new Connect(board); Assert.Equal(ConnectWinner.White, sut.Result()); @@ -45,13 +44,12 @@ public void O_can_win_on_a_1x1_board() [Fact(Skip = "Remove to run test")] public void Only_edges_does_not_make_a_winner() { - var board = new [] - { + var board = new[] + { "O O O X", " X . . X", " X . . X", " X O O O" - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.None, sut.Result()); @@ -60,14 +58,13 @@ public void Only_edges_does_not_make_a_winner() [Fact(Skip = "Remove to run test")] public void Illegal_diagonal_does_not_make_a_winner() { - var board = new [] - { + var board = new[] + { "X O . .", " O X X X", " O X O .", " . O X .", " X X O O" - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.None, sut.Result()); @@ -76,14 +73,13 @@ public void Illegal_diagonal_does_not_make_a_winner() [Fact(Skip = "Remove to run test")] public void Nobody_wins_crossing_adjacent_angles() { - var board = new [] - { + var board = new[] + { "X . . .", " . X O .", " O . X O", " . O . X", " . . O ." - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.None, sut.Result()); @@ -92,14 +88,13 @@ public void Nobody_wins_crossing_adjacent_angles() [Fact(Skip = "Remove to run test")] public void X_wins_crossing_from_left_to_right() { - var board = new [] - { + var board = new[] + { ". O . .", " O X X X", " O X O .", " X X O X", " . O X ." - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.Black, sut.Result()); @@ -108,14 +103,13 @@ public void X_wins_crossing_from_left_to_right() [Fact(Skip = "Remove to run test")] public void O_wins_crossing_from_top_to_bottom() { - var board = new [] - { + var board = new[] + { ". O . .", " O X X X", " O O O .", " X X O X", " . O X ." - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.White, sut.Result()); @@ -124,14 +118,13 @@ public void O_wins_crossing_from_top_to_bottom() [Fact(Skip = "Remove to run test")] public void X_wins_using_a_convoluted_path() { - var board = new [] - { + var board = new[] + { ". X X . .", " X . X . X", " . X . X .", " . X X . .", " O O O O O" - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.Black, sut.Result()); @@ -140,8 +133,8 @@ public void X_wins_using_a_convoluted_path() [Fact(Skip = "Remove to run test")] public void X_wins_using_a_spiral_path() { - var board = new [] - { + var board = new[] + { "O X X X X X X X X", " O X O O O O O O O", " O X O X X X X X O", @@ -151,7 +144,6 @@ public void X_wins_using_a_spiral_path() " O X X X X X O X O", " O O O O O O O X O", " X X X X X X X X O" - }; var sut = new Connect(board); Assert.Equal(ConnectWinner.Black, sut.Result()); diff --git a/exercises/dominoes/Dominoes.cs b/exercises/dominoes/Dominoes.cs index 134f76eea3..df8c56dcfc 100644 --- a/exercises/dominoes/Dominoes.cs +++ b/exercises/dominoes/Dominoes.cs @@ -3,7 +3,7 @@ public static class Dominoes { - public static bool CanChain(IEnumerable> dominoes) + public static bool CanChain(IEnumerable<(int, int)> dominoes) { throw new NotImplementedException("You need to implement this function."); } diff --git a/exercises/dominoes/DominoesTest.cs b/exercises/dominoes/DominoesTest.cs index 97fa3bc7dd..5f28466d8b 100644 --- a/exercises/dominoes/DominoesTest.cs +++ b/exercises/dominoes/DominoesTest.cs @@ -1,91 +1,91 @@ // This file was auto-generated based on version 2.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class DominoesTest { [Fact] public void Empty_input_empty_output() { - var dominoes = new Tuple[] { }; + var dominoes = Array.Empty<(int, int)>(); Assert.True(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Singleton_input_singleton_output() { - var dominoes = new Tuple[] { Tuple.Create(1, 1) }; + var dominoes = new[] { (1, 1) }; Assert.True(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Singleton_that_cant_be_chained() { - var dominoes = new Tuple[] { Tuple.Create(1, 2) }; + var dominoes = new[] { (1, 2) }; Assert.False(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Three_elements() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(3, 1), Tuple.Create(2, 3) }; + var dominoes = new[] { (1, 2), (3, 1), (2, 3) }; Assert.True(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Can_reverse_dominoes() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(1, 3), Tuple.Create(2, 3) }; + var dominoes = new[] { (1, 2), (1, 3), (2, 3) }; Assert.True(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Cant_be_chained() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(4, 1), Tuple.Create(2, 3) }; + var dominoes = new[] { (1, 2), (4, 1), (2, 3) }; Assert.False(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Disconnected_simple() { - var dominoes = new Tuple[] { Tuple.Create(1, 1), Tuple.Create(2, 2) }; + var dominoes = new[] { (1, 1), (2, 2) }; Assert.False(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Disconnected_double_loop() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(2, 1), Tuple.Create(3, 4), Tuple.Create(4, 3) }; + var dominoes = new[] { (1, 2), (2, 1), (3, 4), (4, 3) }; Assert.False(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Disconnected_single_isolated() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(2, 3), Tuple.Create(3, 1), Tuple.Create(4, 4) }; + var dominoes = new[] { (1, 2), (2, 3), (3, 1), (4, 4) }; Assert.False(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Need_backtrack() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(2, 3), Tuple.Create(3, 1), Tuple.Create(2, 4), Tuple.Create(2, 4) }; + var dominoes = new[] { (1, 2), (2, 3), (3, 1), (2, 4), (2, 4) }; Assert.True(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Separate_loops() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(2, 3), Tuple.Create(3, 1), Tuple.Create(1, 1), Tuple.Create(2, 2), Tuple.Create(3, 3) }; + var dominoes = new[] { (1, 2), (2, 3), (3, 1), (1, 1), (2, 2), (3, 3) }; Assert.True(Dominoes.CanChain(dominoes)); } [Fact(Skip = "Remove to run test")] public void Nine_elements() { - var dominoes = new Tuple[] { Tuple.Create(1, 2), Tuple.Create(5, 3), Tuple.Create(3, 1), Tuple.Create(1, 2), Tuple.Create(2, 4), Tuple.Create(1, 6), Tuple.Create(2, 3), Tuple.Create(3, 4), Tuple.Create(5, 6) }; + var dominoes = new[] { (1, 2), (5, 3), (3, 1), (1, 2), (2, 4), (1, 6), (2, 3), (3, 4), (5, 6) }; Assert.True(Dominoes.CanChain(dominoes)); } } \ No newline at end of file diff --git a/exercises/dominoes/Example.cs b/exercises/dominoes/Example.cs index d11a0ba022..e530ca8706 100644 --- a/exercises/dominoes/Example.cs +++ b/exercises/dominoes/Example.cs @@ -4,7 +4,7 @@ public static class Dominoes { - public static bool CanChain(IEnumerable> dominoes) + public static bool CanChain(IEnumerable<(int, int)> dominoes) { if (!dominoes.Any()) { @@ -21,17 +21,17 @@ public static bool CanChain(IEnumerable> dominoes) return dominoes.Skip(1).Rotate().Any(sublist => PossibleChains(domino, sublist).Any(CanChain)); } - public static IEnumerable[]> PossibleChains(Tuple domino, IEnumerable> remainder) + public static IEnumerable<(int, int)[]> PossibleChains((int, int) domino, IEnumerable<(int, int)> remainder) { var head = remainder.First(); if (domino.Item2 == head.Item1) { - yield return new[] { Tuple.Create(domino.Item1, head.Item2) }.Concat(remainder.Skip(1)).ToArray(); + yield return new[] { (domino.Item1, head.Item2) }.Concat(remainder.Skip(1)).ToArray(); } else if (domino.Item2 == head.Item2) { - yield return new[] { Tuple.Create(domino.Item1, head.Item1) }.Concat(remainder.Skip(1)).ToArray(); + yield return new[] { (domino.Item1, head.Item1) }.Concat(remainder.Skip(1)).ToArray(); } } diff --git a/exercises/etl/EtlTest.cs b/exercises/etl/EtlTest.cs index 5207bd5c74..2ecc5f7212 100644 --- a/exercises/etl/EtlTest.cs +++ b/exercises/etl/EtlTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.0.0 of the canonical data. -using Xunit; using System.Collections.Generic; +using Xunit; public class EtlTest { diff --git a/exercises/flatten-array/FlattenArrayTest.cs b/exercises/flatten-array/FlattenArrayTest.cs index 9d66683805..bfc348b279 100644 --- a/exercises/flatten-array/FlattenArrayTest.cs +++ b/exercises/flatten-array/FlattenArrayTest.cs @@ -7,7 +7,12 @@ public class FlattenArrayTest [Fact] public void No_nesting() { - var array = new[] { 0, 1, 2 }; + var array = new object[] + { + 0, + 1, + 2 + }; var expected = new[] { 0, 1, 2 }; Assert.Equal(expected, FlattenArray.Flatten(array)); } @@ -15,17 +20,11 @@ public void No_nesting() [Fact(Skip = "Remove to run test")] public void Flattens_array_with_just_integers_present() { - var array = new object[] { - 1, - new object[] { - 2, - 3, - 4, - 5, - 6, - 7 - }, - 8 + var array = new object[] + { + 1, + new object[] { 2, 3, 4, 5, 6, 7 }, + 8 }; var expected = new[] { 1, 2, 3, 4, 5, 6, 7, 8 }; Assert.Equal(expected, FlattenArray.Flatten(array)); @@ -34,26 +33,12 @@ public void Flattens_array_with_just_integers_present() [Fact(Skip = "Remove to run test")] public void Number_5_level_nesting() { - var array = new object[] { - 0, - 2, - new object[] { - new object[] { - 2, - 3 - }, - 8, - 100, - 4, - new object[] { - new object[] { - new object[] { - 50 - } - } - } - }, - -2 + var array = new object[] + { + 0, + 2, + new object[] { new object[] { 2, 3 }, 8, 100, 4, new object[] { new object[] { new object[] { 50 } } } }, + -2 }; var expected = new[] { 0, 2, 2, 3, 8, 100, 4, 50, -2 }; Assert.Equal(expected, FlattenArray.Flatten(array)); @@ -62,27 +47,11 @@ public void Number_5_level_nesting() [Fact(Skip = "Remove to run test")] public void Number_6_level_nesting() { - var array = new object[] { - 1, - new object[] { - 2, - new object[] { - new object[] { - 3 - } - }, - new object[] { - 4, - new object[] { - new object[] { - 5 - } - } - }, - 6, - 7 - }, - 8 + var array = new object[] + { + 1, + new object[] { 2, new object[] { new object[] { 3 } }, new object[] { 4, new object[] { new object[] { 5 } } }, 6, 7 }, + 8 }; var expected = new[] { 1, 2, 3, 4, 5, 6, 7, 8 }; Assert.Equal(expected, FlattenArray.Flatten(array)); @@ -91,28 +60,12 @@ public void Number_6_level_nesting() [Fact(Skip = "Remove to run test")] public void Number_6_level_nest_list_with_null_values() { - var array = new object[] { - 0, - 2, - new object[] { - new object[] { - 2, - 3 - }, - 8, - new object[] { - new object[] { - 100 - } - }, - null, - new object[] { - new object[] { - null - } - } - }, - -2 + var array = new object[] + { + 0, + 2, + new object[] { new object[] { 2, 3 }, 8, new object[] { new object[] { 100 } }, null, new object[] { new object[] { null } } }, + -2 }; var expected = new[] { 0, 2, 2, 3, 8, 100, -2 }; Assert.Equal(expected, FlattenArray.Flatten(array)); @@ -121,25 +74,14 @@ public void Number_6_level_nest_list_with_null_values() [Fact(Skip = "Remove to run test")] public void All_values_in_nested_list_are_null() { - var array = new object[] { - null, - new object[] { - new object[] { - new object[] { - null - } - } - }, - null, - null, - new object[] { - new object[] { - null, - null - }, + var array = new object[] + { + null, + new object[] { new object[] { new object[] { null } } }, + null, + null, + new object[] { new object[] { null, null }, null }, null - }, - null }; Assert.Empty(FlattenArray.Flatten(array)); } diff --git a/exercises/forth/ForthTest.cs b/exercises/forth/ForthTest.cs index bba6dda3b2..1ee9c54287 100644 --- a/exercises/forth/ForthTest.cs +++ b/exercises/forth/ForthTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.6.0 of the canonical data. -using Xunit; using System; +using Xunit; public class ForthTest { diff --git a/exercises/gigasecond/GigasecondTest.cs b/exercises/gigasecond/GigasecondTest.cs index 2c56fe3f73..ba2e004924 100644 --- a/exercises/gigasecond/GigasecondTest.cs +++ b/exercises/gigasecond/GigasecondTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class GigasecondTest { diff --git a/exercises/go-counting/Example.cs b/exercises/go-counting/Example.cs index da48e0bbbf..07c1538479 100644 --- a/exercises/go-counting/Example.cs +++ b/exercises/go-counting/Example.cs @@ -37,45 +37,45 @@ private static Owner[][] ParseBoard(string input) private int Cols => board[0].Length; private int Rows => board.Length; - private bool IsValidCoordinate(ValueTuple coordinate) => + private bool IsValidCoordinate((int, int) coordinate) => coordinate.Item2 >= 0 && coordinate.Item2 < Rows && coordinate.Item1 >= 0 && coordinate.Item1 < Cols; - private Owner GetPlayer(ValueTuple coordinate) => board[coordinate.Item2][coordinate.Item1]; + private Owner GetPlayer((int, int) coordinate) => board[coordinate.Item2][coordinate.Item1]; - private bool IsEmpty(ValueTuple coordinate) => GetPlayer(coordinate) == Owner.None; - private bool IsTaken(ValueTuple coordinate) => !IsEmpty(coordinate); + private bool IsEmpty((int, int) coordinate) => GetPlayer(coordinate) == Owner.None; + private bool IsTaken((int, int) coordinate) => !IsEmpty(coordinate); - private IEnumerable> EmptyCoordinates() + private IEnumerable<(int, int)> EmptyCoordinates() { return Enumerable.Range(0, Cols).SelectMany(col => - Enumerable.Range(0, Rows).Select(row => new ValueTuple(col, row))) + Enumerable.Range(0, Rows).Select(row => (col, row))) .Where(IsEmpty); } - private IEnumerable> NeighborCoordinates(ValueTuple coordinate) + private IEnumerable<(int, int)> NeighborCoordinates((int, int) coordinate) { var row = coordinate.Item2; var col = coordinate.Item1; var coords = new[] { - new ValueTuple(col, row - 1), - new ValueTuple(col-1, row), - new ValueTuple(col+1, row), - new ValueTuple(col, row+1) + (col, row - 1), + (col - 1, row), + (col + 1, row), + (col, row + 1) }; return coords.Where(IsValidCoordinate); } - private IEnumerable> TakenNeighborCoordinates(ValueTuple coordinate) => + private IEnumerable<(int, int)> TakenNeighborCoordinates((int, int) coordinate) => NeighborCoordinates(coordinate).Where(IsTaken); - private IEnumerable> EmptyNeighborCoordinates(ValueTuple coordinate) => + private IEnumerable<(int, int)> EmptyNeighborCoordinates((int, int) coordinate) => NeighborCoordinates(coordinate).Where(IsEmpty); - private Owner TerritoryOwner(IEnumerable> coords) + private Owner TerritoryOwner(IEnumerable<(int, int)> coords) { var neighborColors = coords.SelectMany(TakenNeighborCoordinates).Select(GetPlayer); var uniqueNeighborColors = ToSet(neighborColors); @@ -86,12 +86,12 @@ private Owner TerritoryOwner(IEnumerable> coords) return Owner.None; } - private HashSet> TerritoryHelper(HashSet> remainder, HashSet> acc) + private HashSet<(int, int)> TerritoryHelper(HashSet<(int, int)> remainder, HashSet<(int, int)> acc) { if (!remainder.Any()) return acc; - var emptyNeighbors = new HashSet>(remainder.SelectMany(EmptyNeighborCoordinates)); + var emptyNeighbors = new HashSet<(int, int)>(remainder.SelectMany(EmptyNeighborCoordinates)); emptyNeighbors.ExceptWith(acc); var newAcc = ToSet(acc); @@ -99,12 +99,12 @@ private HashSet> TerritoryHelper(HashSet> TerritoryHelper(ValueTuple coordinate) => + private HashSet<(int, int)> TerritoryHelper((int, int) coordinate) => IsValidCoordinate(coordinate) && IsEmpty(coordinate) ? TerritoryHelper(ToSingletonSet(coordinate), ToSingletonSet(coordinate)) - : new HashSet>(); + : new HashSet<(int, int)>(); - public ValueTuple>> Territory(ValueTuple coord) + public ValueTuple> Territory((int, int) coord) { if (coord.Item1 < 0 || coord.Item1 >= Rows || coord.Item2 < 0 || coord.Item2 >= Cols) { @@ -113,13 +113,13 @@ public ValueTuple>> Territory(ValueTuple var coords = TerritoryHelper(coord); if (!coords.Any()) - return (Owner.None, Enumerable.Empty>()); + return (Owner.None, Enumerable.Empty<(int, int)>()); var owner = TerritoryOwner(coords); return (owner, coords.OrderBy(x => x.Item1).ThenBy(x => x.Item2).ToArray()); } - private Dictionary[]> TerritoriesHelper(HashSet> remainder, Dictionary[]> acc) + private Dictionary TerritoriesHelper(HashSet<(int, int)> remainder, Dictionary acc) { if (!remainder.Any()) return acc; @@ -135,15 +135,15 @@ private Dictionary[]> TerritoriesHelper(HashSet[]> Territories() + public Dictionary Territories() { var emptyCoords = EmptyCoordinates(); - var territories = new Dictionary[]> + var territories = new Dictionary { - [Owner.Black] = new ValueTuple[0], - [Owner.White] = new ValueTuple[0], - [Owner.None] = new ValueTuple[0] + [Owner.Black] = Array.Empty<(int, int)>(), + [Owner.White] = Array.Empty<(int, int)>(), + [Owner.None] = Array.Empty<(int, int)>() }; return TerritoriesHelper(ToSet(emptyCoords), territories); diff --git a/exercises/go-counting/GoCounting.cs b/exercises/go-counting/GoCounting.cs index 7bccd2ace0..7637951aad 100644 --- a/exercises/go-counting/GoCounting.cs +++ b/exercises/go-counting/GoCounting.cs @@ -15,12 +15,12 @@ public GoCounting(string input) throw new NotImplementedException("You need to implement this function."); } - public Tuple>> TerritoryFor(ValueTuple coord) + public Tuple> TerritoryFor((int, int) coord) { throw new NotImplementedException("You need to implement this function."); } - public Dictionary>> Territories() + public Dictionary> Territories() { throw new NotImplementedException("You need to implement this function."); } diff --git a/exercises/go-counting/GoCountingTest.cs b/exercises/go-counting/GoCountingTest.cs index 083efe7ac1..c4459cff26 100644 --- a/exercises/go-counting/GoCountingTest.cs +++ b/exercises/go-counting/GoCountingTest.cs @@ -1,8 +1,8 @@ // This file was auto-generated based on version 1.0.0 of the canonical data. -using Xunit; using System; using System.Collections.Generic; +using Xunit; public class GoCountingTest { @@ -69,7 +69,7 @@ public void A_stone_and_not_a_territory_on_5x5_board() " W "; var sut = new GoCounting(board); var actual = sut.Territory(coordinate); - var expected = (Owner.None, new ValueTuple[0]); + var expected = (Owner.None, Array.Empty<(int, int)>()); Assert.Equal(expected.Item1, actual.Item1); Assert.Equal(expected.Item2, actual.Item2); } @@ -136,10 +136,10 @@ public void One_territory_is_the_whole_board() var board = " "; var sut = new GoCounting(board); var actual = sut.Territories(); - var expected = new Dictionary[]> + var expected = new Dictionary { - [Owner.Black] = new ValueTuple[0], - [Owner.White] = new ValueTuple[0], + [Owner.Black] = Array.Empty<(int, int)>(), + [Owner.White] = Array.Empty<(int, int)>(), [Owner.None] = new[] { (0, 0) } }; Assert.Equal(expected.Keys, actual.Keys); @@ -156,11 +156,11 @@ public void Two_territory_rectangular_board() " BW "; var sut = new GoCounting(board); var actual = sut.Territories(); - var expected = new Dictionary[]> + var expected = new Dictionary { [Owner.Black] = new[] { (0, 0), (0, 1) }, [Owner.White] = new[] { (3, 0), (3, 1) }, - [Owner.None] = new ValueTuple[0] + [Owner.None] = Array.Empty<(int, int)>() }; Assert.Equal(expected.Keys, actual.Keys); Assert.Equal(expected[Owner.Black], actual[Owner.Black]); @@ -174,11 +174,11 @@ public void Two_region_rectangular_board() var board = " B "; var sut = new GoCounting(board); var actual = sut.Territories(); - var expected = new Dictionary[]> + var expected = new Dictionary { [Owner.Black] = new[] { (0, 0), (2, 0) }, - [Owner.White] = new ValueTuple[0], - [Owner.None] = new ValueTuple[0] + [Owner.White] = Array.Empty<(int, int)>(), + [Owner.None] = Array.Empty<(int, int)>() }; Assert.Equal(expected.Keys, actual.Keys); Assert.Equal(expected[Owner.Black], actual[Owner.Black]); diff --git a/exercises/grains/GrainsTest.cs b/exercises/grains/GrainsTest.cs index 895efb6775..5326cb8992 100644 --- a/exercises/grains/GrainsTest.cs +++ b/exercises/grains/GrainsTest.cs @@ -1,17 +1,11 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class GrainsTest { [Fact] - public void Returns_the_total_number_of_grains_on_the_board() - { - Assert.Equal(18446744073709551615UL, Grains.Total()); - } - - [Fact(Skip = "Remove to run test")] public void Number_1() { Assert.Equal(1UL, Grains.Square(1)); @@ -70,4 +64,10 @@ public void Square_greater_than_64_raises_an_exception() { Assert.Throws(() => Grains.Square(65)); } + + [Fact(Skip = "Remove to run test")] + public void Returns_the_total_number_of_grains_on_the_board() + { + Assert.Equal(18446744073709551615UL, Grains.Total()); + } } \ No newline at end of file diff --git a/exercises/grep/Example.cs b/exercises/grep/Example.cs index e4760781da..0806200374 100644 --- a/exercises/grep/Example.cs +++ b/exercises/grep/Example.cs @@ -71,7 +71,7 @@ private static IEnumerable FindMatchingLines(string pattern, Flags flags, private static Line CreateLine(string file, int index, string text) => new Line { File = file, Number = index + 1, Text = text }; - private static string FormatMatchingFile(string file) => $"{file}\n"; + private static string FormatMatchingFile(string file) => $"{file}"; private static string FormatMatchingFiles(string pattern, Flags flags, string[] files) { @@ -79,7 +79,7 @@ private static string FormatMatchingFiles(string pattern, Flags flags, string[] .Where(file => FindMatchingLines(pattern, flags, file).Any()) .Select(FormatMatchingFile); - return string.Concat(matchingFiles); + return string.Join("\n", matchingFiles); } private static string FormatMatchingLine(Flags flags, string[] files, Line line) @@ -89,18 +89,18 @@ private static string FormatMatchingLine(Flags flags, string[] files, Line line) if (printLineNumbers && printFileName) { - return $"{line.File}:{line.Number}:{line.Text}\n"; + return $"{line.File}:{line.Number}:{line.Text}"; } if (printLineNumbers && !printFileName) { - return $"{line.Number}:{line.Text}\n"; + return $"{line.Number}:{line.Text}"; } if (!printLineNumbers && printFileName) { - return $"{line.File}:{line.Text}\n"; + return $"{line.File}:{line.Text}"; } - return $"{line.Text}\n"; + return $"{line.Text}"; } private static string FormatMatchingLines(string pattern, Flags flags, string[] files) @@ -109,6 +109,6 @@ private static string FormatMatchingLines(string pattern, Flags flags, string[] .SelectMany(file => FindMatchingLines(pattern, flags, file)) .Select(line => FormatMatchingLine(flags, files, line)); - return string.Concat(matchingFiles); + return string.Join("\n", matchingFiles); } } \ No newline at end of file diff --git a/exercises/grep/GrepTest.cs b/exercises/grep/GrepTest.cs index 8c61ab9976..2c6f0c1e77 100644 --- a/exercises/grep/GrepTest.cs +++ b/exercises/grep/GrepTest.cs @@ -1,8 +1,8 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; using System.IO; +using Xunit; public class GrepTest : IDisposable { @@ -11,12 +11,8 @@ public void One_file_one_match_no_flags() { var pattern = "Agamemnon"; var flags = ""; - var files = new[] - { - "iliad.txt" - }; - var expected = - "Of Atreus, Agamemnon, King of men.\n"; + var files = new[] { "iliad.txt" }; + var expected = "Of Atreus, Agamemnon, King of men."; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -25,12 +21,8 @@ public void One_file_one_match_print_line_numbers_flag() { var pattern = "Forbidden"; var flags = "-n"; - var files = new[] - { - "paradise-lost.txt" - }; - var expected = - "2:Of that Forbidden Tree, whose mortal tast\n"; + var files = new[] { "paradise-lost.txt" }; + var expected = "2:Of that Forbidden Tree, whose mortal tast"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -39,12 +31,8 @@ public void One_file_one_match_case_insensitive_flag() { var pattern = "FORBIDDEN"; var flags = "-i"; - var files = new[] - { - "paradise-lost.txt" - }; - var expected = - "Of that Forbidden Tree, whose mortal tast\n"; + var files = new[] { "paradise-lost.txt" }; + var expected = "Of that Forbidden Tree, whose mortal tast"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -53,12 +41,8 @@ public void One_file_one_match_print_file_names_flag() { var pattern = "Forbidden"; var flags = "-l"; - var files = new[] - { - "paradise-lost.txt" - }; - var expected = - "paradise-lost.txt\n"; + var files = new[] { "paradise-lost.txt" }; + var expected = "paradise-lost.txt"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -67,12 +51,8 @@ public void One_file_one_match_match_entire_lines_flag() { var pattern = "With loss of Eden, till one greater Man"; var flags = "-x"; - var files = new[] - { - "paradise-lost.txt" - }; - var expected = - "With loss of Eden, till one greater Man\n"; + var files = new[] { "paradise-lost.txt" }; + var expected = "With loss of Eden, till one greater Man"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -81,12 +61,8 @@ public void One_file_one_match_multiple_flags() { var pattern = "OF ATREUS, Agamemnon, KIng of MEN."; var flags = "-n -i -x"; - var files = new[] - { - "iliad.txt" - }; - var expected = - "9:Of Atreus, Agamemnon, King of men.\n"; + var files = new[] { "iliad.txt" }; + var expected = "9:Of Atreus, Agamemnon, King of men."; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -95,14 +71,11 @@ public void One_file_several_matches_no_flags() { var pattern = "may"; var flags = ""; - var files = new[] - { - "midsummer-night.txt" - }; + var files = new[] { "midsummer-night.txt" }; var expected = "Nor how it may concern my modesty,\n" + "But I beseech your grace that I may know\n" + - "The worst that may befall me in this case,\n"; + "The worst that may befall me in this case,"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -111,14 +84,11 @@ public void One_file_several_matches_print_line_numbers_flag() { var pattern = "may"; var flags = "-n"; - var files = new[] - { - "midsummer-night.txt" - }; + var files = new[] { "midsummer-night.txt" }; var expected = "3:Nor how it may concern my modesty,\n" + "5:But I beseech your grace that I may know\n" + - "6:The worst that may befall me in this case,\n"; + "6:The worst that may befall me in this case,"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -127,10 +97,7 @@ public void One_file_several_matches_match_entire_lines_flag() { var pattern = "may"; var flags = "-x"; - var files = new[] - { - "midsummer-night.txt" - }; + var files = new[] { "midsummer-night.txt" }; var expected = ""; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -140,13 +107,10 @@ public void One_file_several_matches_case_insensitive_flag() { var pattern = "ACHILLES"; var flags = "-i"; - var files = new[] - { - "iliad.txt" - }; + var files = new[] { "iliad.txt" }; var expected = "Achilles sing, O Goddess! Peleus' son;\n" + - "The noble Chief Achilles from the son\n"; + "The noble Chief Achilles from the son"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -155,16 +119,13 @@ public void One_file_several_matches_inverted_flag() { var pattern = "Of"; var flags = "-v"; - var files = new[] - { - "paradise-lost.txt" - }; + var files = new[] { "paradise-lost.txt" }; var expected = "Brought Death into the World, and all our woe,\n" + "With loss of Eden, till one greater Man\n" + "Restore us, and regain the blissful Seat,\n" + "Sing Heav'nly Muse, that on the secret top\n" + - "That Shepherd, who first taught the chosen Seed\n"; + "That Shepherd, who first taught the chosen Seed"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -173,10 +134,7 @@ public void One_file_no_matches_various_flags() { var pattern = "Gandalf"; var flags = "-n -l -x -i"; - var files = new[] - { - "iliad.txt" - }; + var files = new[] { "iliad.txt" }; var expected = ""; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -186,14 +144,8 @@ public void Multiple_files_one_match_no_flags() { var pattern = "Agamemnon"; var flags = ""; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; - var expected = - "iliad.txt:Of Atreus, Agamemnon, King of men.\n"; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; + var expected = "iliad.txt:Of Atreus, Agamemnon, King of men."; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -202,16 +154,11 @@ public void Multiple_files_several_matches_no_flags() { var pattern = "may"; var flags = ""; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; var expected = "midsummer-night.txt:Nor how it may concern my modesty,\n" + "midsummer-night.txt:But I beseech your grace that I may know\n" + - "midsummer-night.txt:The worst that may befall me in this case,\n"; + "midsummer-night.txt:The worst that may befall me in this case,"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -220,17 +167,12 @@ public void Multiple_files_several_matches_print_line_numbers_flag() { var pattern = "that"; var flags = "-n"; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; var expected = "midsummer-night.txt:5:But I beseech your grace that I may know\n" + "midsummer-night.txt:6:The worst that may befall me in this case,\n" + "paradise-lost.txt:2:Of that Forbidden Tree, whose mortal tast\n" + - "paradise-lost.txt:6:Sing Heav'nly Muse, that on the secret top\n"; + "paradise-lost.txt:6:Sing Heav'nly Muse, that on the secret top"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -239,15 +181,10 @@ public void Multiple_files_one_match_print_file_names_flag() { var pattern = "who"; var flags = "-l"; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; var expected = "iliad.txt\n" + - "paradise-lost.txt\n"; + "paradise-lost.txt"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -256,12 +193,7 @@ public void Multiple_files_several_matches_case_insensitive_flag() { var pattern = "TO"; var flags = "-i"; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; var expected = "iliad.txt:Caused to Achaia's host, sent many a soul\n" + "iliad.txt:Illustrious into Ades premature,\n" + @@ -272,7 +204,7 @@ public void Multiple_files_several_matches_case_insensitive_flag() "midsummer-night.txt:If I refuse to wed Demetrius.\n" + "paradise-lost.txt:Brought Death into the World, and all our woe,\n" + "paradise-lost.txt:Restore us, and regain the blissful Seat,\n" + - "paradise-lost.txt:Sing Heav'nly Muse, that on the secret top\n"; + "paradise-lost.txt:Sing Heav'nly Muse, that on the secret top"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -281,16 +213,11 @@ public void Multiple_files_several_matches_inverted_flag() { var pattern = "a"; var flags = "-v"; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; var expected = "iliad.txt:Achilles sing, O Goddess! Peleus' son;\n" + "iliad.txt:The noble Chief Achilles from the son\n" + - "midsummer-night.txt:If I refuse to wed Demetrius.\n"; + "midsummer-night.txt:If I refuse to wed Demetrius."; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -299,14 +226,8 @@ public void Multiple_files_one_match_match_entire_lines_flag() { var pattern = "But I beseech your grace that I may know"; var flags = "-x"; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; - var expected = - "midsummer-night.txt:But I beseech your grace that I may know\n"; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; + var expected = "midsummer-night.txt:But I beseech your grace that I may know"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -315,14 +236,8 @@ public void Multiple_files_one_match_multiple_flags() { var pattern = "WITH LOSS OF EDEN, TILL ONE GREATER MAN"; var flags = "-n -i -x"; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; - var expected = - "paradise-lost.txt:4:With loss of Eden, till one greater Man\n"; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; + var expected = "paradise-lost.txt:4:With loss of Eden, till one greater Man"; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } @@ -331,12 +246,7 @@ public void Multiple_files_no_matches_various_flags() { var pattern = "Frodo"; var flags = "-n -l -x -i"; - var files = new[] - { - "iliad.txt", - "midsummer-night.txt", - "paradise-lost.txt" - }; + var files = new[] { "iliad.txt", "midsummer-night.txt", "paradise-lost.txt" }; var expected = ""; Assert.Equal(expected, Grep.Match(pattern, flags, files)); } diff --git a/exercises/hamming/HammingTest.cs b/exercises/hamming/HammingTest.cs index 67d3b71159..d38c185207 100644 --- a/exercises/hamming/HammingTest.cs +++ b/exercises/hamming/HammingTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 2.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class HammingTest { diff --git a/exercises/isbn-verifier/IsbnVerifierTest.cs b/exercises/isbn-verifier/IsbnVerifierTest.cs index 2d5999111c..5a2ae46dd2 100644 --- a/exercises/isbn-verifier/IsbnVerifierTest.cs +++ b/exercises/isbn-verifier/IsbnVerifierTest.cs @@ -1,4 +1,4 @@ -// This file was auto-generated based on version 2.4.0 of the canonical data. +// This file was auto-generated based on version 2.7.0 of the canonical data. using Xunit; @@ -65,15 +65,15 @@ public void Too_long_isbn_and_no_dashes() } [Fact(Skip = "Remove to run test")] - public void Isbn_without_check_digit() + public void Too_short_isbn() { - Assert.False(IsbnVerifier.IsValid("3-598-21507")); + Assert.False(IsbnVerifier.IsValid("00")); } [Fact(Skip = "Remove to run test")] - public void Too_long_isbn() + public void Isbn_without_check_digit() { - Assert.False(IsbnVerifier.IsValid("3-598-21507-XX")); + Assert.False(IsbnVerifier.IsValid("3-598-21507")); } [Fact(Skip = "Remove to run test")] @@ -93,4 +93,16 @@ public void Input_is_9_characters() { Assert.False(IsbnVerifier.IsValid("134456729")); } + + [Fact(Skip = "Remove to run test")] + public void Invalid_characters_are_not_ignored() + { + Assert.False(IsbnVerifier.IsValid("3132P34035")); + } + + [Fact(Skip = "Remove to run test")] + public void Input_is_too_long_but_contains_a_valid_isbn() + { + Assert.False(IsbnVerifier.IsValid("98245726788")); + } } \ No newline at end of file diff --git a/exercises/largest-series-product/LargestSeriesProductTest.cs b/exercises/largest-series-product/LargestSeriesProductTest.cs index c41f8613c4..e17ff30af9 100644 --- a/exercises/largest-series-product/LargestSeriesProductTest.cs +++ b/exercises/largest-series-product/LargestSeriesProductTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class LargestSeriesProductTest { diff --git a/exercises/list-ops/ListOpsTest.cs b/exercises/list-ops/ListOpsTest.cs index ea57b19b74..38cbc1cf28 100644 --- a/exercises/list-ops/ListOpsTest.cs +++ b/exercises/list-ops/ListOpsTest.cs @@ -1,8 +1,8 @@ // This file was auto-generated based on version 2.3.0 of the canonical data. -using Xunit; using System; using System.Collections.Generic; +using Xunit; public class ListOpsTest { diff --git a/exercises/luhn/LuhnTest.cs b/exercises/luhn/LuhnTest.cs index cd5a0215c8..49035f01b7 100644 --- a/exercises/luhn/LuhnTest.cs +++ b/exercises/luhn/LuhnTest.cs @@ -1,4 +1,4 @@ -// This file was auto-generated based on version 1.1.0 of the canonical data. +// This file was auto-generated based on version 1.2.0 of the canonical data. using Xunit; @@ -81,4 +81,10 @@ public void Input_digit_9_is_correctly_converted_to_output_digit_9() { Assert.True(Luhn.IsValid("091")); } + + [Fact(Skip = "Remove to run test")] + public void Strings_with_non_digits_is_invalid() + { + Assert.False(Luhn.IsValid(":9")); + } } \ No newline at end of file diff --git a/exercises/meetup/MeetupTest.cs b/exercises/meetup/MeetupTest.cs index a4fe493710..b0ceaf76e9 100644 --- a/exercises/meetup/MeetupTest.cs +++ b/exercises/meetup/MeetupTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class MeetupTest { @@ -9,759 +9,759 @@ public class MeetupTest public void Monteenth_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Monteenth_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Monteenth_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Tuesteenth_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Tuesteenth_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Tuesteenth_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Wednesteenth_of_january_2013() { var sut = new Meetup(1, 2013); - var expected = "2013-01-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 1, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Wednesteenth_of_february_2013() { var sut = new Meetup(2, 2013); - var expected = "2013-02-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 2, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Wednesteenth_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Thursteenth_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Thursteenth_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Thursteenth_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Friteenth_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Friteenth_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Friteenth_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Saturteenth_of_february_2013() { var sut = new Meetup(2, 2013); - var expected = "2013-02-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 2, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Saturteenth_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Saturteenth_of_october_2013() { var sut = new Meetup(10, 2013); - var expected = "2013-10-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 10, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Sunteenth_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Sunteenth_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void Sunteenth_of_october_2013() { var sut = new Meetup(10, 2013); - var expected = "2013-10-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Teenth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 10, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Teenth)); } [Fact(Skip = "Remove to run test")] public void First_monday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-04"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 4); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_monday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-01"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 1); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_tuesday_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-07"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 7); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_tuesday_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-04"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 4); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_wednesday_of_july_2013() { var sut = new Meetup(7, 2013); - var expected = "2013-07-03"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 7, 3); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_wednesday_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-07"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 7); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_thursday_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-05"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 5); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_thursday_of_october_2013() { var sut = new Meetup(10, 2013); - var expected = "2013-10-03"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 10, 3); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_friday_of_november_2013() { var sut = new Meetup(11, 2013); - var expected = "2013-11-01"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 11, 1); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_friday_of_december_2013() { var sut = new Meetup(12, 2013); - var expected = "2013-12-06"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 12, 6); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_saturday_of_january_2013() { var sut = new Meetup(1, 2013); - var expected = "2013-01-05"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 1, 5); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_saturday_of_february_2013() { var sut = new Meetup(2, 2013); - var expected = "2013-02-02"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 2, 2); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_sunday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-03"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 3); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void First_sunday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-07"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 7); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.First)); } [Fact(Skip = "Remove to run test")] public void Second_monday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-11"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 11); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_monday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-08"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 8); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_tuesday_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-14"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 14); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_tuesday_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-11"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 11); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_wednesday_of_july_2013() { var sut = new Meetup(7, 2013); - var expected = "2013-07-10"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 7, 10); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_wednesday_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-14"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 14); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_thursday_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-12"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 12); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_thursday_of_october_2013() { var sut = new Meetup(10, 2013); - var expected = "2013-10-10"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 10, 10); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_friday_of_november_2013() { var sut = new Meetup(11, 2013); - var expected = "2013-11-08"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 11, 8); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_friday_of_december_2013() { var sut = new Meetup(12, 2013); - var expected = "2013-12-13"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 12, 13); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_saturday_of_january_2013() { var sut = new Meetup(1, 2013); - var expected = "2013-01-12"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 1, 12); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_saturday_of_february_2013() { var sut = new Meetup(2, 2013); - var expected = "2013-02-09"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 2, 9); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_sunday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-10"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 10); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Second_sunday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-14"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Second).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 14); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Second)); } [Fact(Skip = "Remove to run test")] public void Third_monday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-18"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 18); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_monday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-15"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 15); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_tuesday_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-21"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 21); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_tuesday_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-18"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 18); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_wednesday_of_july_2013() { var sut = new Meetup(7, 2013); - var expected = "2013-07-17"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 7, 17); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_wednesday_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-21"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 21); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_thursday_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_thursday_of_october_2013() { var sut = new Meetup(10, 2013); - var expected = "2013-10-17"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 10, 17); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_friday_of_november_2013() { var sut = new Meetup(11, 2013); - var expected = "2013-11-15"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 11, 15); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_friday_of_december_2013() { var sut = new Meetup(12, 2013); - var expected = "2013-12-20"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 12, 20); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_saturday_of_january_2013() { var sut = new Meetup(1, 2013); - var expected = "2013-01-19"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 1, 19); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_saturday_of_february_2013() { var sut = new Meetup(2, 2013); - var expected = "2013-02-16"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 2, 16); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_sunday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-17"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 17); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Third_sunday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-21"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Third).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 21); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Third)); } [Fact(Skip = "Remove to run test")] public void Fourth_monday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-25"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 25); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_monday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-22"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 22); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_tuesday_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-28"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 28); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_tuesday_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-25"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 25); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_wednesday_of_july_2013() { var sut = new Meetup(7, 2013); - var expected = "2013-07-24"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 7, 24); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_wednesday_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-28"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 28); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_thursday_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-26"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 26); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_thursday_of_october_2013() { var sut = new Meetup(10, 2013); - var expected = "2013-10-24"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 10, 24); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_friday_of_november_2013() { var sut = new Meetup(11, 2013); - var expected = "2013-11-22"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 11, 22); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_friday_of_december_2013() { var sut = new Meetup(12, 2013); - var expected = "2013-12-27"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 12, 27); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_saturday_of_january_2013() { var sut = new Meetup(1, 2013); - var expected = "2013-01-26"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 1, 26); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_saturday_of_february_2013() { var sut = new Meetup(2, 2013); - var expected = "2013-02-23"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 2, 23); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_sunday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-24"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 24); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Fourth_sunday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-28"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Fourth).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 28); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Fourth)); } [Fact(Skip = "Remove to run test")] public void Last_monday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-25"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 25); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_monday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-29"; - Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 29); + Assert.Equal(expected, sut.Day(DayOfWeek.Monday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_tuesday_of_may_2013() { var sut = new Meetup(5, 2013); - var expected = "2013-05-28"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 5, 28); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_tuesday_of_june_2013() { var sut = new Meetup(6, 2013); - var expected = "2013-06-25"; - Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 6, 25); + Assert.Equal(expected, sut.Day(DayOfWeek.Tuesday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_wednesday_of_july_2013() { var sut = new Meetup(7, 2013); - var expected = "2013-07-31"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 7, 31); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_wednesday_of_august_2013() { var sut = new Meetup(8, 2013); - var expected = "2013-08-28"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 8, 28); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_thursday_of_september_2013() { var sut = new Meetup(9, 2013); - var expected = "2013-09-26"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 9, 26); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_thursday_of_october_2013() { var sut = new Meetup(10, 2013); - var expected = "2013-10-31"; - Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 10, 31); + Assert.Equal(expected, sut.Day(DayOfWeek.Thursday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_friday_of_november_2013() { var sut = new Meetup(11, 2013); - var expected = "2013-11-29"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 11, 29); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_friday_of_december_2013() { var sut = new Meetup(12, 2013); - var expected = "2013-12-27"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 12, 27); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_saturday_of_january_2013() { var sut = new Meetup(1, 2013); - var expected = "2013-01-26"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 1, 26); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_saturday_of_february_2013() { var sut = new Meetup(2, 2013); - var expected = "2013-02-23"; - Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 2, 23); + Assert.Equal(expected, sut.Day(DayOfWeek.Saturday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_sunday_of_march_2013() { var sut = new Meetup(3, 2013); - var expected = "2013-03-31"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 3, 31); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_sunday_of_april_2013() { var sut = new Meetup(4, 2013); - var expected = "2013-04-28"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2013, 4, 28); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_wednesday_of_february_2012() { var sut = new Meetup(2, 2012); - var expected = "2012-02-29"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2012, 2, 29); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_wednesday_of_december_2014() { var sut = new Meetup(12, 2014); - var expected = "2014-12-31"; - Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2014, 12, 31); + Assert.Equal(expected, sut.Day(DayOfWeek.Wednesday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void Last_sunday_of_february_2015() { var sut = new Meetup(2, 2015); - var expected = "2015-02-22"; - Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Last).ToString("yyyy-MM-dd")); + var expected = new DateTime(2015, 2, 22); + Assert.Equal(expected, sut.Day(DayOfWeek.Sunday, Schedule.Last)); } [Fact(Skip = "Remove to run test")] public void First_friday_of_december_2012() { var sut = new Meetup(12, 2012); - var expected = "2012-12-07"; - Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.First).ToString("yyyy-MM-dd")); + var expected = new DateTime(2012, 12, 7); + Assert.Equal(expected, sut.Day(DayOfWeek.Friday, Schedule.First)); } } \ No newline at end of file diff --git a/exercises/minesweeper/MinesweeperTest.cs b/exercises/minesweeper/MinesweeperTest.cs index f44f6dad1c..d8776e2703 100644 --- a/exercises/minesweeper/MinesweeperTest.cs +++ b/exercises/minesweeper/MinesweeperTest.cs @@ -1,28 +1,28 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class MinesweeperTest { [Fact] public void No_rows() { - var minefield = new string[0]; - var expected = new string[0]; + var minefield = Array.Empty(); + var expected = Array.Empty(); Assert.Equal(expected, Minesweeper.Annotate(minefield)); } [Fact(Skip = "Remove to run test")] public void No_columns() { - var minefield = new string[] - { - "" + var minefield = new[] + { + "" }; - var expected = new string[] - { - "" + var expected = new[] + { + "" }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -30,19 +30,17 @@ public void No_columns() [Fact(Skip = "Remove to run test")] public void No_mines() { - var minefield = new string[] - { + var minefield = new[] + { " ", " ", " " - }; - var expected = new string[] - { + var expected = new[] + { " ", " ", " " - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -50,19 +48,17 @@ public void No_mines() [Fact(Skip = "Remove to run test")] public void Minefield_with_only_mines() { - var minefield = new string[] - { + var minefield = new[] + { "***", "***", "***" - }; - var expected = new string[] - { + var expected = new[] + { "***", "***", "***" - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -70,19 +66,17 @@ public void Minefield_with_only_mines() [Fact(Skip = "Remove to run test")] public void Mine_surrounded_by_spaces() { - var minefield = new string[] - { + var minefield = new[] + { " ", " * ", " " - }; - var expected = new string[] - { + var expected = new[] + { "111", "1*1", "111" - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -90,19 +84,17 @@ public void Mine_surrounded_by_spaces() [Fact(Skip = "Remove to run test")] public void Space_surrounded_by_mines() { - var minefield = new string[] - { + var minefield = new[] + { "***", "* *", "***" - }; - var expected = new string[] - { + var expected = new[] + { "***", "*8*", "***" - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -110,13 +102,13 @@ public void Space_surrounded_by_mines() [Fact(Skip = "Remove to run test")] public void Horizontal_line() { - var minefield = new string[] - { - " * * " + var minefield = new[] + { + " * * " }; - var expected = new string[] - { - "1*2*1" + var expected = new[] + { + "1*2*1" }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -124,13 +116,13 @@ public void Horizontal_line() [Fact(Skip = "Remove to run test")] public void Horizontal_line_mines_at_edges() { - var minefield = new string[] - { - "* *" + var minefield = new[] + { + "* *" }; - var expected = new string[] - { - "*1 1*" + var expected = new[] + { + "*1 1*" }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -138,23 +130,21 @@ public void Horizontal_line_mines_at_edges() [Fact(Skip = "Remove to run test")] public void Vertical_line() { - var minefield = new string[] - { + var minefield = new[] + { " ", "*", " ", "*", " " - }; - var expected = new string[] - { + var expected = new[] + { "1", "*", "2", "*", "1" - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -162,23 +152,21 @@ public void Vertical_line() [Fact(Skip = "Remove to run test")] public void Vertical_line_mines_at_edges() { - var minefield = new string[] - { + var minefield = new[] + { "*", " ", " ", " ", "*" - }; - var expected = new string[] - { + var expected = new[] + { "*", "1", " ", "1", "*" - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -186,23 +174,21 @@ public void Vertical_line_mines_at_edges() [Fact(Skip = "Remove to run test")] public void Cross() { - var minefield = new string[] - { + var minefield = new[] + { " * ", " * ", "*****", " * ", " * " - }; - var expected = new string[] - { + var expected = new[] + { " 2*2 ", "25*52", "*****", "25*52", " 2*2 " - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } @@ -210,25 +196,23 @@ public void Cross() [Fact(Skip = "Remove to run test")] public void Large_minefield() { - var minefield = new string[] - { + var minefield = new[] + { " * * ", " * ", " * ", " * *", " * * ", " " - }; - var expected = new string[] - { + var expected = new[] + { "1*22*1", "12*322", " 123*2", "112*4*", "1*22*2", "111111" - }; Assert.Equal(expected, Minesweeper.Annotate(minefield)); } diff --git a/exercises/nth-prime/NthPrimeTest.cs b/exercises/nth-prime/NthPrimeTest.cs index 8c9aec4c89..4a2ca7fb4d 100644 --- a/exercises/nth-prime/NthPrimeTest.cs +++ b/exercises/nth-prime/NthPrimeTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 2.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class NthPrimeTest { diff --git a/exercises/nucleotide-count/Example.cs b/exercises/nucleotide-count/Example.cs index 6fb509a90d..b25845a936 100644 --- a/exercises/nucleotide-count/Example.cs +++ b/exercises/nucleotide-count/Example.cs @@ -20,9 +20,7 @@ private void InitializeNucleotideCounts(string sequence) } catch (KeyNotFoundException) { - throw new InvalidNucleotideException(); + throw new ArgumentException(); } } } - -public class InvalidNucleotideException : Exception { } diff --git a/exercises/nucleotide-count/NucleotideCount.cs b/exercises/nucleotide-count/NucleotideCount.cs index 4f71c41d2e..310a058299 100644 --- a/exercises/nucleotide-count/NucleotideCount.cs +++ b/exercises/nucleotide-count/NucleotideCount.cs @@ -14,6 +14,4 @@ public IDictionary NucleotideCounts throw new NotImplementedException("You need to implement this function."); } } -} - -public class InvalidNucleotideException : Exception { } +} \ No newline at end of file diff --git a/exercises/nucleotide-count/NucleotideCountTest.cs b/exercises/nucleotide-count/NucleotideCountTest.cs index 9b4174757c..44a5d9edbd 100644 --- a/exercises/nucleotide-count/NucleotideCountTest.cs +++ b/exercises/nucleotide-count/NucleotideCountTest.cs @@ -1,7 +1,8 @@ // This file was auto-generated based on version 1.3.0 of the canonical data. -using Xunit; +using System; using System.Collections.Generic; +using Xunit; public class NucleotideCountTest { @@ -64,6 +65,6 @@ public void Strand_with_multiple_nucleotides() [Fact(Skip = "Remove to run test")] public void Strand_with_invalid_nucleotides() { - Assert.Throws(() => new NucleotideCount("AGXXACT")); + Assert.Throws(() => new NucleotideCount("AGXXACT")); } } \ No newline at end of file diff --git a/exercises/ocr-numbers/OcrNumbersTest.cs b/exercises/ocr-numbers/OcrNumbersTest.cs index b189cdc75d..cb55c05e08 100644 --- a/exercises/ocr-numbers/OcrNumbersTest.cs +++ b/exercises/ocr-numbers/OcrNumbersTest.cs @@ -1,17 +1,18 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class OcrNumbersTest { [Fact] public void Recognizes_0() { - var rows = " _ " + "\n" + - "| |" + "\n" + - "|_|" + "\n" + - " "; + var rows = + " _ \n" + + "| |\n" + + "|_|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("0", actual); } @@ -19,10 +20,11 @@ public void Recognizes_0() [Fact(Skip = "Remove to run test")] public void Recognizes_1() { - var rows = " " + "\n" + - " |" + "\n" + - " |" + "\n" + - " "; + var rows = + " \n" + + " |\n" + + " |\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("1", actual); } @@ -30,10 +32,11 @@ public void Recognizes_1() [Fact(Skip = "Remove to run test")] public void Unreadable_but_correctly_sized_inputs_return_() { - var rows = " " + "\n" + - " _" + "\n" + - " |" + "\n" + - " "; + var rows = + " \n" + + " _\n" + + " |\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("?", actual); } @@ -41,29 +44,32 @@ public void Unreadable_but_correctly_sized_inputs_return_() [Fact(Skip = "Remove to run test")] public void Input_with_a_number_of_lines_that_is_not_a_multiple_of_four_raises_an_error() { - var rows = " _ " + "\n" + - "| |" + "\n" + - " "; + var rows = + " _ \n" + + "| |\n" + + " "; Assert.Throws(() => OcrNumbers.Convert(rows)); } [Fact(Skip = "Remove to run test")] public void Input_with_a_number_of_columns_that_is_not_a_multiple_of_three_raises_an_error() { - var rows = " " + "\n" + - " |" + "\n" + - " |" + "\n" + - " "; + var rows = + " \n" + + " |\n" + + " |\n" + + " "; Assert.Throws(() => OcrNumbers.Convert(rows)); } [Fact(Skip = "Remove to run test")] public void Recognizes_110101100() { - var rows = " _ _ _ _ " + "\n" + - " | || | || | | || || |" + "\n" + - " | ||_| ||_| | ||_||_|" + "\n" + - " "; + var rows = + " _ _ _ _ \n" + + " | || | || | | || || |\n" + + " | ||_| ||_| | ||_||_|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("110101100", actual); } @@ -71,10 +77,11 @@ public void Recognizes_110101100() [Fact(Skip = "Remove to run test")] public void Garbled_numbers_in_a_string_are_replaced_with_() { - var rows = " _ _ _ " + "\n" + - " | || | || | || || |" + "\n" + - " | | _| ||_| | ||_||_|" + "\n" + - " "; + var rows = + " _ _ _ \n" + + " | || | || | || || |\n" + + " | | _| ||_| | ||_||_|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("11?10?1?0", actual); } @@ -82,10 +89,11 @@ public void Garbled_numbers_in_a_string_are_replaced_with_() [Fact(Skip = "Remove to run test")] public void Recognizes_2() { - var rows = " _ " + "\n" + - " _|" + "\n" + - "|_ " + "\n" + - " "; + var rows = + " _ \n" + + " _|\n" + + "|_ \n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("2", actual); } @@ -93,10 +101,11 @@ public void Recognizes_2() [Fact(Skip = "Remove to run test")] public void Recognizes_3() { - var rows = " _ " + "\n" + - " _|" + "\n" + - " _|" + "\n" + - " "; + var rows = + " _ \n" + + " _|\n" + + " _|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("3", actual); } @@ -104,10 +113,11 @@ public void Recognizes_3() [Fact(Skip = "Remove to run test")] public void Recognizes_4() { - var rows = " " + "\n" + - "|_|" + "\n" + - " |" + "\n" + - " "; + var rows = + " \n" + + "|_|\n" + + " |\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("4", actual); } @@ -115,10 +125,11 @@ public void Recognizes_4() [Fact(Skip = "Remove to run test")] public void Recognizes_5() { - var rows = " _ " + "\n" + - "|_ " + "\n" + - " _|" + "\n" + - " "; + var rows = + " _ \n" + + "|_ \n" + + " _|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("5", actual); } @@ -126,10 +137,11 @@ public void Recognizes_5() [Fact(Skip = "Remove to run test")] public void Recognizes_6() { - var rows = " _ " + "\n" + - "|_ " + "\n" + - "|_|" + "\n" + - " "; + var rows = + " _ \n" + + "|_ \n" + + "|_|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("6", actual); } @@ -137,10 +149,11 @@ public void Recognizes_6() [Fact(Skip = "Remove to run test")] public void Recognizes_7() { - var rows = " _ " + "\n" + - " |" + "\n" + - " |" + "\n" + - " "; + var rows = + " _ \n" + + " |\n" + + " |\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("7", actual); } @@ -148,10 +161,11 @@ public void Recognizes_7() [Fact(Skip = "Remove to run test")] public void Recognizes_8() { - var rows = " _ " + "\n" + - "|_|" + "\n" + - "|_|" + "\n" + - " "; + var rows = + " _ \n" + + "|_|\n" + + "|_|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("8", actual); } @@ -159,10 +173,11 @@ public void Recognizes_8() [Fact(Skip = "Remove to run test")] public void Recognizes_9() { - var rows = " _ " + "\n" + - "|_|" + "\n" + - " _|" + "\n" + - " "; + var rows = + " _ \n" + + "|_|\n" + + " _|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("9", actual); } @@ -170,10 +185,11 @@ public void Recognizes_9() [Fact(Skip = "Remove to run test")] public void Recognizes_string_of_decimal_numbers() { - var rows = " _ _ _ _ _ _ _ _ " + "\n" + - " | _| _||_||_ |_ ||_||_|| |" + "\n" + - " ||_ _| | _||_| ||_| _||_|" + "\n" + - " "; + var rows = + " _ _ _ _ _ _ _ _ \n" + + " | _| _||_||_ |_ ||_||_|| |\n" + + " ||_ _| | _||_| ||_| _||_|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("1234567890", actual); } @@ -181,18 +197,19 @@ public void Recognizes_string_of_decimal_numbers() [Fact(Skip = "Remove to run test")] public void Numbers_separated_by_empty_lines_are_recognized_lines_are_joined_by_commas_() { - var rows = " _ _ " + "\n" + - " | _| _|" + "\n" + - " ||_ _|" + "\n" + - " " + "\n" + - " _ _ " + "\n" + - "|_||_ |_ " + "\n" + - " | _||_|" + "\n" + - " " + "\n" + - " _ _ _ " + "\n" + - " ||_||_|" + "\n" + - " ||_| _|" + "\n" + - " "; + var rows = + " _ _ \n" + + " | _| _|\n" + + " ||_ _|\n" + + " \n" + + " _ _ \n" + + "|_||_ |_ \n" + + " | _||_|\n" + + " \n" + + " _ _ _ \n" + + " ||_||_|\n" + + " ||_| _|\n" + + " "; var actual = OcrNumbers.Convert(rows); Assert.Equal("123,456,789", actual); } diff --git a/exercises/palindrome-products/PalindromeProductsTest.cs b/exercises/palindrome-products/PalindromeProductsTest.cs index 89e57b6510..de2548c600 100644 --- a/exercises/palindrome-products/PalindromeProductsTest.cs +++ b/exercises/palindrome-products/PalindromeProductsTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class PalindromeProductsTest { diff --git a/exercises/pascals-triangle/PascalsTriangleTest.cs b/exercises/pascals-triangle/PascalsTriangleTest.cs index b5d1fad9ef..2034d549fe 100644 --- a/exercises/pascals-triangle/PascalsTriangleTest.cs +++ b/exercises/pascals-triangle/PascalsTriangleTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.3.0 of the canonical data. -using Xunit; using System; +using Xunit; public class PascalsTriangleTest { @@ -14,49 +14,94 @@ public void Zero_rows() [Fact(Skip = "Remove to run test")] public void Single_row() { - var expected = new[] { new[] { 1 } }; + var expected = new[] + { + new[] { 1 } + }; Assert.Equal(expected, PascalsTriangle.Calculate(1)); } [Fact(Skip = "Remove to run test")] public void Two_rows() { - var expected = new[] { new[] { 1 }, new[] { 1, 1 } }; + var expected = new[] + { + new[] { 1 }, + new[] { 1, 1 } + }; Assert.Equal(expected, PascalsTriangle.Calculate(2)); } [Fact(Skip = "Remove to run test")] public void Three_rows() { - var expected = new[] { new[] { 1 }, new[] { 1, 1 }, new[] { 1, 2, 1 } }; + var expected = new[] + { + new[] { 1 }, + new[] { 1, 1 }, + new[] { 1, 2, 1 } + }; Assert.Equal(expected, PascalsTriangle.Calculate(3)); } [Fact(Skip = "Remove to run test")] public void Four_rows() { - var expected = new[] { new[] { 1 }, new[] { 1, 1 }, new[] { 1, 2, 1 }, new[] { 1, 3, 3, 1 } }; + var expected = new[] + { + new[] { 1 }, + new[] { 1, 1 }, + new[] { 1, 2, 1 }, + new[] { 1, 3, 3, 1 } + }; Assert.Equal(expected, PascalsTriangle.Calculate(4)); } [Fact(Skip = "Remove to run test")] public void Five_rows() { - var expected = new[] { new[] { 1 }, new[] { 1, 1 }, new[] { 1, 2, 1 }, new[] { 1, 3, 3, 1 }, new[] { 1, 4, 6, 4, 1 } }; + var expected = new[] + { + new[] { 1 }, + new[] { 1, 1 }, + new[] { 1, 2, 1 }, + new[] { 1, 3, 3, 1 }, + new[] { 1, 4, 6, 4, 1 } + }; Assert.Equal(expected, PascalsTriangle.Calculate(5)); } [Fact(Skip = "Remove to run test")] public void Six_rows() { - var expected = new[] { new[] { 1 }, new[] { 1, 1 }, new[] { 1, 2, 1 }, new[] { 1, 3, 3, 1 }, new[] { 1, 4, 6, 4, 1 }, new[] { 1, 5, 10, 10, 5, 1 } }; + var expected = new[] + { + new[] { 1 }, + new[] { 1, 1 }, + new[] { 1, 2, 1 }, + new[] { 1, 3, 3, 1 }, + new[] { 1, 4, 6, 4, 1 }, + new[] { 1, 5, 10, 10, 5, 1 } + }; Assert.Equal(expected, PascalsTriangle.Calculate(6)); } [Fact(Skip = "Remove to run test")] public void Ten_rows() { - var expected = new[] { new[] { 1 }, new[] { 1, 1 }, new[] { 1, 2, 1 }, new[] { 1, 3, 3, 1 }, new[] { 1, 4, 6, 4, 1 }, new[] { 1, 5, 10, 10, 5, 1 }, new[] { 1, 6, 15, 20, 15, 6, 1 }, new[] { 1, 7, 21, 35, 35, 21, 7, 1 }, new[] { 1, 8, 28, 56, 70, 56, 28, 8, 1 }, new[] { 1, 9, 36, 84, 126, 126, 84, 36, 9, 1 } }; + var expected = new[] + { + new[] { 1 }, + new[] { 1, 1 }, + new[] { 1, 2, 1 }, + new[] { 1, 3, 3, 1 }, + new[] { 1, 4, 6, 4, 1 }, + new[] { 1, 5, 10, 10, 5, 1 }, + new[] { 1, 6, 15, 20, 15, 6, 1 }, + new[] { 1, 7, 21, 35, 35, 21, 7, 1 }, + new[] { 1, 8, 28, 56, 70, 56, 28, 8, 1 }, + new[] { 1, 9, 36, 84, 126, 126, 84, 36, 9, 1 } + }; Assert.Equal(expected, PascalsTriangle.Calculate(10)); } diff --git a/exercises/perfect-numbers/PerfectNumbersTest.cs b/exercises/perfect-numbers/PerfectNumbersTest.cs index 7fc8dd88fc..35487c1bc5 100644 --- a/exercises/perfect-numbers/PerfectNumbersTest.cs +++ b/exercises/perfect-numbers/PerfectNumbersTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class PerfectNumbersTest { diff --git a/exercises/phone-number/PhoneNumberTest.cs b/exercises/phone-number/PhoneNumberTest.cs index 7ffaa32460..d388cfb707 100644 --- a/exercises/phone-number/PhoneNumberTest.cs +++ b/exercises/phone-number/PhoneNumberTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.4.0 of the canonical data. -using Xunit; using System; +using Xunit; public class PhoneNumberTest { diff --git a/exercises/poker/PokerTest.cs b/exercises/poker/PokerTest.cs index 3f4001855c..6c49dbab90 100644 --- a/exercises/poker/PokerTest.cs +++ b/exercises/poker/PokerTest.cs @@ -7,7 +7,8 @@ public class PokerTest [Fact] public void Single_hand_always_wins() { - var actual = Poker.BestHands(new[] { "4S 5S 7H 8D JC" }); + var hands = new[] { "4S 5S 7H 8D JC" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4S 5S 7H 8D JC" }; Assert.Equal(expected, actual); } @@ -15,7 +16,8 @@ public void Single_hand_always_wins() [Fact(Skip = "Remove to run test")] public void Highest_card_out_of_all_hands_wins() { - var actual = Poker.BestHands(new[] { "4D 5S 6S 8D 3C", "2S 4C 7S 9H 10H", "3S 4S 5D 6H JH" }); + var hands = new[] { "4D 5S 6S 8D 3C", "2S 4C 7S 9H 10H", "3S 4S 5D 6H JH" }; + var actual = Poker.BestHands(hands); var expected = new[] { "3S 4S 5D 6H JH" }; Assert.Equal(expected, actual); } @@ -23,7 +25,8 @@ public void Highest_card_out_of_all_hands_wins() [Fact(Skip = "Remove to run test")] public void A_tie_has_multiple_winners() { - var actual = Poker.BestHands(new[] { "4D 5S 6S 8D 3C", "2S 4C 7S 9H 10H", "3S 4S 5D 6H JH", "3H 4H 5C 6C JD" }); + var hands = new[] { "4D 5S 6S 8D 3C", "2S 4C 7S 9H 10H", "3S 4S 5D 6H JH", "3H 4H 5C 6C JD" }; + var actual = Poker.BestHands(hands); var expected = new[] { "3S 4S 5D 6H JH", "3H 4H 5C 6C JD" }; Assert.Equal(expected, actual); } @@ -31,7 +34,8 @@ public void A_tie_has_multiple_winners() [Fact(Skip = "Remove to run test")] public void Multiple_hands_with_the_same_high_cards_tie_compares_next_highest_ranked_down_to_last_card() { - var actual = Poker.BestHands(new[] { "3S 5H 6S 8D 7H", "2S 5D 6D 8C 7S" }); + var hands = new[] { "3S 5H 6S 8D 7H", "2S 5D 6D 8C 7S" }; + var actual = Poker.BestHands(hands); var expected = new[] { "3S 5H 6S 8D 7H" }; Assert.Equal(expected, actual); } @@ -39,7 +43,8 @@ public void Multiple_hands_with_the_same_high_cards_tie_compares_next_highest_ra [Fact(Skip = "Remove to run test")] public void One_pair_beats_high_card() { - var actual = Poker.BestHands(new[] { "4S 5H 6C 8D KH", "2S 4H 6S 4D JH" }); + var hands = new[] { "4S 5H 6C 8D KH", "2S 4H 6S 4D JH" }; + var actual = Poker.BestHands(hands); var expected = new[] { "2S 4H 6S 4D JH" }; Assert.Equal(expected, actual); } @@ -47,7 +52,8 @@ public void One_pair_beats_high_card() [Fact(Skip = "Remove to run test")] public void Highest_pair_wins() { - var actual = Poker.BestHands(new[] { "4S 2H 6S 2D JH", "2S 4H 6C 4D JD" }); + var hands = new[] { "4S 2H 6S 2D JH", "2S 4H 6C 4D JD" }; + var actual = Poker.BestHands(hands); var expected = new[] { "2S 4H 6C 4D JD" }; Assert.Equal(expected, actual); } @@ -55,7 +61,8 @@ public void Highest_pair_wins() [Fact(Skip = "Remove to run test")] public void Two_pairs_beats_one_pair() { - var actual = Poker.BestHands(new[] { "2S 8H 6S 8D JH", "4S 5H 4C 8C 5C" }); + var hands = new[] { "2S 8H 6S 8D JH", "4S 5H 4C 8C 5C" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4S 5H 4C 8C 5C" }; Assert.Equal(expected, actual); } @@ -63,7 +70,8 @@ public void Two_pairs_beats_one_pair() [Fact(Skip = "Remove to run test")] public void Both_hands_have_two_pairs_highest_ranked_pair_wins() { - var actual = Poker.BestHands(new[] { "2S 8H 2D 8D 3H", "4S 5H 4C 8S 5D" }); + var hands = new[] { "2S 8H 2D 8D 3H", "4S 5H 4C 8S 5D" }; + var actual = Poker.BestHands(hands); var expected = new[] { "2S 8H 2D 8D 3H" }; Assert.Equal(expected, actual); } @@ -71,7 +79,8 @@ public void Both_hands_have_two_pairs_highest_ranked_pair_wins() [Fact(Skip = "Remove to run test")] public void Both_hands_have_two_pairs_with_the_same_highest_ranked_pair_tie_goes_to_low_pair() { - var actual = Poker.BestHands(new[] { "2S QS 2C QD JH", "JD QH JS 8D QC" }); + var hands = new[] { "2S QS 2C QD JH", "JD QH JS 8D QC" }; + var actual = Poker.BestHands(hands); var expected = new[] { "JD QH JS 8D QC" }; Assert.Equal(expected, actual); } @@ -79,7 +88,8 @@ public void Both_hands_have_two_pairs_with_the_same_highest_ranked_pair_tie_goes [Fact(Skip = "Remove to run test")] public void Both_hands_have_two_identically_ranked_pairs_tie_goes_to_remaining_card_kicker_() { - var actual = Poker.BestHands(new[] { "JD QH JS 8D QC", "JS QS JC 2D QD" }); + var hands = new[] { "JD QH JS 8D QC", "JS QS JC 2D QD" }; + var actual = Poker.BestHands(hands); var expected = new[] { "JD QH JS 8D QC" }; Assert.Equal(expected, actual); } @@ -87,7 +97,8 @@ public void Both_hands_have_two_identically_ranked_pairs_tie_goes_to_remaining_c [Fact(Skip = "Remove to run test")] public void Three_of_a_kind_beats_two_pair() { - var actual = Poker.BestHands(new[] { "2S 8H 2H 8D JH", "4S 5H 4C 8S 4H" }); + var hands = new[] { "2S 8H 2H 8D JH", "4S 5H 4C 8S 4H" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4S 5H 4C 8S 4H" }; Assert.Equal(expected, actual); } @@ -95,7 +106,8 @@ public void Three_of_a_kind_beats_two_pair() [Fact(Skip = "Remove to run test")] public void Both_hands_have_three_of_a_kind_tie_goes_to_highest_ranked_triplet() { - var actual = Poker.BestHands(new[] { "2S 2H 2C 8D JH", "4S AH AS 8C AD" }); + var hands = new[] { "2S 2H 2C 8D JH", "4S AH AS 8C AD" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4S AH AS 8C AD" }; Assert.Equal(expected, actual); } @@ -103,7 +115,8 @@ public void Both_hands_have_three_of_a_kind_tie_goes_to_highest_ranked_triplet() [Fact(Skip = "Remove to run test")] public void With_multiple_decks_two_players_can_have_same_three_of_a_kind_ties_go_to_highest_remaining_cards() { - var actual = Poker.BestHands(new[] { "4S AH AS 7C AD", "4S AH AS 8C AD" }); + var hands = new[] { "4S AH AS 7C AD", "4S AH AS 8C AD" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4S AH AS 8C AD" }; Assert.Equal(expected, actual); } @@ -111,7 +124,8 @@ public void With_multiple_decks_two_players_can_have_same_three_of_a_kind_ties_g [Fact(Skip = "Remove to run test")] public void A_straight_beats_three_of_a_kind() { - var actual = Poker.BestHands(new[] { "4S 5H 4C 8D 4H", "3S 4D 2S 6D 5C" }); + var hands = new[] { "4S 5H 4C 8D 4H", "3S 4D 2S 6D 5C" }; + var actual = Poker.BestHands(hands); var expected = new[] { "3S 4D 2S 6D 5C" }; Assert.Equal(expected, actual); } @@ -119,7 +133,8 @@ public void A_straight_beats_three_of_a_kind() [Fact(Skip = "Remove to run test")] public void Aces_can_end_a_straight_10_j_q_k_a_() { - var actual = Poker.BestHands(new[] { "4S 5H 4C 8D 4H", "10D JH QS KD AC" }); + var hands = new[] { "4S 5H 4C 8D 4H", "10D JH QS KD AC" }; + var actual = Poker.BestHands(hands); var expected = new[] { "10D JH QS KD AC" }; Assert.Equal(expected, actual); } @@ -127,7 +142,8 @@ public void Aces_can_end_a_straight_10_j_q_k_a_() [Fact(Skip = "Remove to run test")] public void Aces_can_start_a_straight_a_2_3_4_5_() { - var actual = Poker.BestHands(new[] { "4S 5H 4C 8D 4H", "4D AH 3S 2D 5C" }); + var hands = new[] { "4S 5H 4C 8D 4H", "4D AH 3S 2D 5C" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4D AH 3S 2D 5C" }; Assert.Equal(expected, actual); } @@ -135,7 +151,8 @@ public void Aces_can_start_a_straight_a_2_3_4_5_() [Fact(Skip = "Remove to run test")] public void Both_hands_with_a_straight_tie_goes_to_highest_ranked_card() { - var actual = Poker.BestHands(new[] { "4S 6C 7S 8D 5H", "5S 7H 8S 9D 6H" }); + var hands = new[] { "4S 6C 7S 8D 5H", "5S 7H 8S 9D 6H" }; + var actual = Poker.BestHands(hands); var expected = new[] { "5S 7H 8S 9D 6H" }; Assert.Equal(expected, actual); } @@ -143,7 +160,8 @@ public void Both_hands_with_a_straight_tie_goes_to_highest_ranked_card() [Fact(Skip = "Remove to run test")] public void Even_though_an_ace_is_usually_high_a_5_high_straight_is_the_lowest_scoring_straight() { - var actual = Poker.BestHands(new[] { "2H 3C 4D 5D 6H", "4S AH 3S 2D 5H" }); + var hands = new[] { "2H 3C 4D 5D 6H", "4S AH 3S 2D 5H" }; + var actual = Poker.BestHands(hands); var expected = new[] { "2H 3C 4D 5D 6H" }; Assert.Equal(expected, actual); } @@ -151,7 +169,8 @@ public void Even_though_an_ace_is_usually_high_a_5_high_straight_is_the_lowest_s [Fact(Skip = "Remove to run test")] public void Flush_beats_a_straight() { - var actual = Poker.BestHands(new[] { "4C 6H 7D 8D 5H", "2S 4S 5S 6S 7S" }); + var hands = new[] { "4C 6H 7D 8D 5H", "2S 4S 5S 6S 7S" }; + var actual = Poker.BestHands(hands); var expected = new[] { "2S 4S 5S 6S 7S" }; Assert.Equal(expected, actual); } @@ -159,7 +178,8 @@ public void Flush_beats_a_straight() [Fact(Skip = "Remove to run test")] public void Both_hands_have_a_flush_tie_goes_to_high_card_down_to_the_last_one_if_necessary() { - var actual = Poker.BestHands(new[] { "4H 7H 8H 9H 6H", "2S 4S 5S 6S 7S" }); + var hands = new[] { "4H 7H 8H 9H 6H", "2S 4S 5S 6S 7S" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4H 7H 8H 9H 6H" }; Assert.Equal(expected, actual); } @@ -167,7 +187,8 @@ public void Both_hands_have_a_flush_tie_goes_to_high_card_down_to_the_last_one_i [Fact(Skip = "Remove to run test")] public void Full_house_beats_a_flush() { - var actual = Poker.BestHands(new[] { "3H 6H 7H 8H 5H", "4S 5H 4C 5D 4H" }); + var hands = new[] { "3H 6H 7H 8H 5H", "4S 5H 4C 5D 4H" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4S 5H 4C 5D 4H" }; Assert.Equal(expected, actual); } @@ -175,7 +196,8 @@ public void Full_house_beats_a_flush() [Fact(Skip = "Remove to run test")] public void Both_hands_have_a_full_house_tie_goes_to_highest_ranked_triplet() { - var actual = Poker.BestHands(new[] { "4H 4S 4D 9S 9D", "5H 5S 5D 8S 8D" }); + var hands = new[] { "4H 4S 4D 9S 9D", "5H 5S 5D 8S 8D" }; + var actual = Poker.BestHands(hands); var expected = new[] { "5H 5S 5D 8S 8D" }; Assert.Equal(expected, actual); } @@ -183,7 +205,8 @@ public void Both_hands_have_a_full_house_tie_goes_to_highest_ranked_triplet() [Fact(Skip = "Remove to run test")] public void With_multiple_decks_both_hands_have_a_full_house_with_the_same_triplet_tie_goes_to_the_pair() { - var actual = Poker.BestHands(new[] { "5H 5S 5D 9S 9D", "5H 5S 5D 8S 8D" }); + var hands = new[] { "5H 5S 5D 9S 9D", "5H 5S 5D 8S 8D" }; + var actual = Poker.BestHands(hands); var expected = new[] { "5H 5S 5D 9S 9D" }; Assert.Equal(expected, actual); } @@ -191,7 +214,8 @@ public void With_multiple_decks_both_hands_have_a_full_house_with_the_same_tripl [Fact(Skip = "Remove to run test")] public void Four_of_a_kind_beats_a_full_house() { - var actual = Poker.BestHands(new[] { "4S 5H 4D 5D 4H", "3S 3H 2S 3D 3C" }); + var hands = new[] { "4S 5H 4D 5D 4H", "3S 3H 2S 3D 3C" }; + var actual = Poker.BestHands(hands); var expected = new[] { "3S 3H 2S 3D 3C" }; Assert.Equal(expected, actual); } @@ -199,7 +223,8 @@ public void Four_of_a_kind_beats_a_full_house() [Fact(Skip = "Remove to run test")] public void Both_hands_have_four_of_a_kind_tie_goes_to_high_quad() { - var actual = Poker.BestHands(new[] { "2S 2H 2C 8D 2D", "4S 5H 5S 5D 5C" }); + var hands = new[] { "2S 2H 2C 8D 2D", "4S 5H 5S 5D 5C" }; + var actual = Poker.BestHands(hands); var expected = new[] { "4S 5H 5S 5D 5C" }; Assert.Equal(expected, actual); } @@ -207,7 +232,8 @@ public void Both_hands_have_four_of_a_kind_tie_goes_to_high_quad() [Fact(Skip = "Remove to run test")] public void With_multiple_decks_both_hands_with_identical_four_of_a_kind_tie_determined_by_kicker() { - var actual = Poker.BestHands(new[] { "3S 3H 2S 3D 3C", "3S 3H 4S 3D 3C" }); + var hands = new[] { "3S 3H 2S 3D 3C", "3S 3H 4S 3D 3C" }; + var actual = Poker.BestHands(hands); var expected = new[] { "3S 3H 4S 3D 3C" }; Assert.Equal(expected, actual); } @@ -215,7 +241,8 @@ public void With_multiple_decks_both_hands_with_identical_four_of_a_kind_tie_det [Fact(Skip = "Remove to run test")] public void Straight_flush_beats_four_of_a_kind() { - var actual = Poker.BestHands(new[] { "4S 5H 5S 5D 5C", "7S 8S 9S 6S 10S" }); + var hands = new[] { "4S 5H 5S 5D 5C", "7S 8S 9S 6S 10S" }; + var actual = Poker.BestHands(hands); var expected = new[] { "7S 8S 9S 6S 10S" }; Assert.Equal(expected, actual); } @@ -223,7 +250,8 @@ public void Straight_flush_beats_four_of_a_kind() [Fact(Skip = "Remove to run test")] public void Both_hands_have_straight_flush_tie_goes_to_highest_ranked_card() { - var actual = Poker.BestHands(new[] { "4H 6H 7H 8H 5H", "5S 7S 8S 9S 6S" }); + var hands = new[] { "4H 6H 7H 8H 5H", "5S 7S 8S 9S 6S" }; + var actual = Poker.BestHands(hands); var expected = new[] { "5S 7S 8S 9S 6S" }; Assert.Equal(expected, actual); } diff --git a/exercises/pov/PovTest.cs b/exercises/pov/PovTest.cs index cdc07dd868..58dab05582 100644 --- a/exercises/pov/PovTest.cs +++ b/exercises/pov/PovTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.3.0 of the canonical data. -using Xunit; using System; +using Xunit; public class PovTest { @@ -81,11 +81,7 @@ public void Can_find_path_to_parent() var from = "x"; var to = "parent"; var tree = new Tree("parent", new Tree("x"), new Tree("sibling")); - var expected = new[] - { - "x", - "parent" - }; + var expected = new[] { "x", "parent" }; Assert.Equal(expected, Pov.PathTo(from, to, tree)); } @@ -95,12 +91,7 @@ public void Can_find_path_to_sibling() var from = "x"; var to = "b"; var tree = new Tree("parent", new Tree("a"), new Tree("x"), new Tree("b"), new Tree("c")); - var expected = new[] - { - "x", - "parent", - "b" - }; + var expected = new[] { "x", "parent", "b" }; Assert.Equal(expected, Pov.PathTo(from, to, tree)); } @@ -110,14 +101,7 @@ public void Can_find_path_to_cousin() var from = "x"; var to = "cousin-1"; var tree = new Tree("grandparent", new Tree("parent", new Tree("x", new Tree("kid-0"), new Tree("kid-1")), new Tree("sibling-0"), new Tree("sibling-1")), new Tree("uncle", new Tree("cousin-0"), new Tree("cousin-1"))); - var expected = new[] - { - "x", - "parent", - "grandparent", - "uncle", - "cousin-1" - }; + var expected = new[] { "x", "parent", "grandparent", "uncle", "cousin-1" }; Assert.Equal(expected, Pov.PathTo(from, to, tree)); } @@ -127,12 +111,7 @@ public void Can_find_path_not_involving_root() var from = "x"; var to = "sibling-1"; var tree = new Tree("grandparent", new Tree("parent", new Tree("x"), new Tree("sibling-0"), new Tree("sibling-1"))); - var expected = new[] - { - "x", - "parent", - "sibling-1" - }; + var expected = new[] { "x", "parent", "sibling-1" }; Assert.Equal(expected, Pov.PathTo(from, to, tree)); } @@ -142,12 +121,7 @@ public void Can_find_path_from_nodes_other_than_x() var from = "a"; var to = "c"; var tree = new Tree("parent", new Tree("a"), new Tree("x"), new Tree("b"), new Tree("c")); - var expected = new[] - { - "a", - "parent", - "c" - }; + var expected = new[] { "a", "parent", "c" }; Assert.Equal(expected, Pov.PathTo(from, to, tree)); } diff --git a/exercises/proverb/ProverbTest.cs b/exercises/proverb/ProverbTest.cs index 3cbe8a2d80..392225e960 100644 --- a/exercises/proverb/ProverbTest.cs +++ b/exercises/proverb/ProverbTest.cs @@ -1,5 +1,6 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. +using System; using Xunit; public class ProverbTest @@ -7,45 +8,72 @@ public class ProverbTest [Fact] public void Zero_pieces() { - Assert.Empty(Proverb.Recite(new string[0])); + var strings = Array.Empty(); + var expected = Array.Empty(); + Assert.Equal(expected, Proverb.Recite(strings)); } [Fact(Skip = "Remove to run test")] public void One_piece() { + var strings = new[] + { + "nail" + }; var expected = new[] { "And all for the want of a nail." }; - Assert.Equal(expected, Proverb.Recite(new[] { "nail" })); + Assert.Equal(expected, Proverb.Recite(strings)); } [Fact(Skip = "Remove to run test")] public void Two_pieces() { + var strings = new[] + { + "nail", + "shoe" + }; var expected = new[] { "For want of a nail the shoe was lost.", "And all for the want of a nail." }; - Assert.Equal(expected, Proverb.Recite(new[] { "nail", "shoe" })); + Assert.Equal(expected, Proverb.Recite(strings)); } [Fact(Skip = "Remove to run test")] public void Three_pieces() { + var strings = new[] + { + "nail", + "shoe", + "horse" + }; var expected = new[] { "For want of a nail the shoe was lost.", "For want of a shoe the horse was lost.", "And all for the want of a nail." }; - Assert.Equal(expected, Proverb.Recite(new[] { "nail", "shoe", "horse" })); + Assert.Equal(expected, Proverb.Recite(strings)); } [Fact(Skip = "Remove to run test")] public void Full_proverb() { + var strings = new[] + { + "nail", + "shoe", + "horse", + "rider", + "message", + "battle", + "kingdom" + }; var expected = new[] { "For want of a nail the shoe was lost.", @@ -56,12 +84,19 @@ public void Full_proverb() "For want of a battle the kingdom was lost.", "And all for the want of a nail." }; - Assert.Equal(expected, Proverb.Recite(new[] { "nail", "shoe", "horse", "rider", "message", "battle", "kingdom" })); + Assert.Equal(expected, Proverb.Recite(strings)); } [Fact(Skip = "Remove to run test")] public void Four_pieces_modernized() { + var strings = new[] + { + "pin", + "gun", + "soldier", + "battle" + }; var expected = new[] { "For want of a pin the gun was lost.", @@ -69,6 +104,6 @@ public void Four_pieces_modernized() "For want of a soldier the battle was lost.", "And all for the want of a pin." }; - Assert.Equal(expected, Proverb.Recite(new[] { "pin", "gun", "soldier", "battle" })); + Assert.Equal(expected, Proverb.Recite(strings)); } } \ No newline at end of file diff --git a/exercises/queen-attack/QueenAttackTest.cs b/exercises/queen-attack/QueenAttackTest.cs index 5b85d6459e..288b173516 100644 --- a/exercises/queen-attack/QueenAttackTest.cs +++ b/exercises/queen-attack/QueenAttackTest.cs @@ -1,12 +1,12 @@ // This file was auto-generated based on version 2.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class QueenAttackTest { [Fact] - public void Queen_with_a_valid_position_does_not_throw_exception() + public void Queen_with_a_valid_position() { var actual = QueenAttack.Create(2, 2); } diff --git a/exercises/rational-numbers/RationalNumbersTest.cs b/exercises/rational-numbers/RationalNumbersTest.cs index ef44b49e70..6f7ea79e63 100644 --- a/exercises/rational-numbers/RationalNumbersTest.cs +++ b/exercises/rational-numbers/RationalNumbersTest.cs @@ -7,216 +7,216 @@ public class RationalNumbersTest [Fact] public void Add_two_positive_rational_numbers() { - Assert.Equal(new RationalNumber (7, 6), new RationalNumber(1, 2) + (new RationalNumber(2, 3))); + Assert.Equal(new RationalNumber(7, 6), new RationalNumber(1, 2) + (new RationalNumber(2, 3))); } [Fact(Skip = "Remove to run test")] public void Add_a_positive_rational_number_and_a_negative_rational_number() { - Assert.Equal(new RationalNumber (-1, 6), new RationalNumber(1, 2) + (new RationalNumber(-2, 3))); + Assert.Equal(new RationalNumber(-1, 6), new RationalNumber(1, 2) + (new RationalNumber(-2, 3))); } [Fact(Skip = "Remove to run test")] public void Add_two_negative_rational_numbers() { - Assert.Equal(new RationalNumber (-7, 6), new RationalNumber(-1, 2) + (new RationalNumber(-2, 3))); + Assert.Equal(new RationalNumber(-7, 6), new RationalNumber(-1, 2) + (new RationalNumber(-2, 3))); } [Fact(Skip = "Remove to run test")] public void Add_a_rational_number_to_its_additive_inverse() { - Assert.Equal(new RationalNumber (0, 1), new RationalNumber(1, 2) + (new RationalNumber(-1, 2))); + Assert.Equal(new RationalNumber(0, 1), new RationalNumber(1, 2) + (new RationalNumber(-1, 2))); } [Fact(Skip = "Remove to run test")] public void Subtract_two_positive_rational_numbers() { - Assert.Equal(new RationalNumber (-1, 6), new RationalNumber(1, 2) - (new RationalNumber(2, 3))); + Assert.Equal(new RationalNumber(-1, 6), new RationalNumber(1, 2) - (new RationalNumber(2, 3))); } [Fact(Skip = "Remove to run test")] public void Subtract_a_positive_rational_number_and_a_negative_rational_number() { - Assert.Equal(new RationalNumber (7, 6), new RationalNumber(1, 2) - (new RationalNumber(-2, 3))); + Assert.Equal(new RationalNumber(7, 6), new RationalNumber(1, 2) - (new RationalNumber(-2, 3))); } [Fact(Skip = "Remove to run test")] public void Subtract_two_negative_rational_numbers() { - Assert.Equal(new RationalNumber (1, 6), new RationalNumber(-1, 2) - (new RationalNumber(-2, 3))); + Assert.Equal(new RationalNumber(1, 6), new RationalNumber(-1, 2) - (new RationalNumber(-2, 3))); } [Fact(Skip = "Remove to run test")] public void Subtract_a_rational_number_from_itself() { - Assert.Equal(new RationalNumber (0, 1), new RationalNumber(1, 2) - (new RationalNumber(1, 2))); + Assert.Equal(new RationalNumber(0, 1), new RationalNumber(1, 2) - (new RationalNumber(1, 2))); } [Fact(Skip = "Remove to run test")] public void Multiply_two_positive_rational_numbers() { - Assert.Equal(new RationalNumber (1, 3), new RationalNumber(1, 2) * (new RationalNumber(2, 3))); + Assert.Equal(new RationalNumber(1, 3), new RationalNumber(1, 2) * (new RationalNumber(2, 3))); } [Fact(Skip = "Remove to run test")] public void Multiply_a_negative_rational_number_by_a_positive_rational_number() { - Assert.Equal(new RationalNumber (-1, 3), new RationalNumber(-1, 2) * (new RationalNumber(2, 3))); + Assert.Equal(new RationalNumber(-1, 3), new RationalNumber(-1, 2) * (new RationalNumber(2, 3))); } [Fact(Skip = "Remove to run test")] public void Multiply_two_negative_rational_numbers() { - Assert.Equal(new RationalNumber (1, 3), new RationalNumber(-1, 2) * (new RationalNumber(-2, 3))); + Assert.Equal(new RationalNumber(1, 3), new RationalNumber(-1, 2) * (new RationalNumber(-2, 3))); } [Fact(Skip = "Remove to run test")] public void Multiply_a_rational_number_by_its_reciprocal() { - Assert.Equal(new RationalNumber (1, 1), new RationalNumber(1, 2) * (new RationalNumber(2, 1))); + Assert.Equal(new RationalNumber(1, 1), new RationalNumber(1, 2) * (new RationalNumber(2, 1))); } [Fact(Skip = "Remove to run test")] public void Multiply_a_rational_number_by_1() { - Assert.Equal(new RationalNumber (1, 2), new RationalNumber(1, 2) * (new RationalNumber(1, 1))); + Assert.Equal(new RationalNumber(1, 2), new RationalNumber(1, 2) * (new RationalNumber(1, 1))); } [Fact(Skip = "Remove to run test")] public void Multiply_a_rational_number_by_0() { - Assert.Equal(new RationalNumber (0, 1), new RationalNumber(1, 2) * (new RationalNumber(0, 1))); + Assert.Equal(new RationalNumber(0, 1), new RationalNumber(1, 2) * (new RationalNumber(0, 1))); } [Fact(Skip = "Remove to run test")] public void Divide_two_positive_rational_numbers() { - Assert.Equal(new RationalNumber (3, 4), new RationalNumber(1, 2) / (new RationalNumber(2, 3))); + Assert.Equal(new RationalNumber(3, 4), new RationalNumber(1, 2) / (new RationalNumber(2, 3))); } [Fact(Skip = "Remove to run test")] public void Divide_a_positive_rational_number_by_a_negative_rational_number() { - Assert.Equal(new RationalNumber (-3, 4), new RationalNumber(1, 2) / (new RationalNumber(-2, 3))); + Assert.Equal(new RationalNumber(-3, 4), new RationalNumber(1, 2) / (new RationalNumber(-2, 3))); } [Fact(Skip = "Remove to run test")] public void Divide_two_negative_rational_numbers() { - Assert.Equal(new RationalNumber (3, 4), new RationalNumber(-1, 2) / (new RationalNumber(-2, 3))); + Assert.Equal(new RationalNumber(3, 4), new RationalNumber(-1, 2) / (new RationalNumber(-2, 3))); } [Fact(Skip = "Remove to run test")] public void Divide_a_rational_number_by_1() { - Assert.Equal(new RationalNumber (1, 2), new RationalNumber(1, 2) / (new RationalNumber(1, 1))); + Assert.Equal(new RationalNumber(1, 2), new RationalNumber(1, 2) / (new RationalNumber(1, 1))); } [Fact(Skip = "Remove to run test")] public void Absolute_value_of_a_positive_rational_number() { - Assert.Equal(new RationalNumber (1, 2), new RationalNumber(1, 2).Abs()); + Assert.Equal(new RationalNumber(1, 2), new RationalNumber(1, 2).Abs()); } [Fact(Skip = "Remove to run test")] public void Absolute_value_of_a_negative_rational_number() { - Assert.Equal(new RationalNumber (1, 2), new RationalNumber(-1, 2).Abs()); + Assert.Equal(new RationalNumber(1, 2), new RationalNumber(-1, 2).Abs()); } [Fact(Skip = "Remove to run test")] public void Absolute_value_of_zero() { - Assert.Equal(new RationalNumber (0, 1), new RationalNumber(0, 1).Abs()); + Assert.Equal(new RationalNumber(0, 1), new RationalNumber(0, 1).Abs()); } [Fact(Skip = "Remove to run test")] public void Raise_a_positive_rational_number_to_a_positive_integer_power() { - Assert.Equal(new RationalNumber (1, 8), new RationalNumber(1, 2).Exprational(3)); + Assert.Equal(new RationalNumber(1, 8), new RationalNumber(1, 2).Exprational(3)); } [Fact(Skip = "Remove to run test")] public void Raise_a_negative_rational_number_to_a_positive_integer_power() { - Assert.Equal(new RationalNumber (-1, 8), new RationalNumber(-1, 2).Exprational(3)); + Assert.Equal(new RationalNumber(-1, 8), new RationalNumber(-1, 2).Exprational(3)); } [Fact(Skip = "Remove to run test")] public void Raise_zero_to_an_integer_power() { - Assert.Equal(new RationalNumber (0, 1), new RationalNumber(0, 1).Exprational(5)); + Assert.Equal(new RationalNumber(0, 1), new RationalNumber(0, 1).Exprational(5)); } [Fact(Skip = "Remove to run test")] public void Raise_one_to_an_integer_power() { - Assert.Equal(new RationalNumber (1, 1), new RationalNumber(1, 1).Exprational(4)); + Assert.Equal(new RationalNumber(1, 1), new RationalNumber(1, 1).Exprational(4)); } [Fact(Skip = "Remove to run test")] public void Raise_a_positive_rational_number_to_the_power_of_zero() { - Assert.Equal(new RationalNumber (1, 1), new RationalNumber(1, 2).Exprational(0)); + Assert.Equal(new RationalNumber(1, 1), new RationalNumber(1, 2).Exprational(0)); } [Fact(Skip = "Remove to run test")] public void Raise_a_negative_rational_number_to_the_power_of_zero() { - Assert.Equal(new RationalNumber (1, 1), new RationalNumber(-1, 2).Exprational(0)); + Assert.Equal(new RationalNumber(1, 1), new RationalNumber(-1, 2).Exprational(0)); } [Fact(Skip = "Remove to run test")] public void Raise_a_real_number_to_a_positive_rational_number() { - Assert.Equal(16, 8.Expreal(new RationalNumber(4, 3)),0); + Assert.Equal(16, 8.Expreal(new RationalNumber(4, 3)), precision: 0); } [Fact(Skip = "Remove to run test")] public void Raise_a_real_number_to_a_negative_rational_number() { - Assert.Equal(0.333333333333333, 9.Expreal(new RationalNumber(-1, 2)),15); + Assert.Equal(0.3333333, 9.Expreal(new RationalNumber(-1, 2)), precision: 7); } [Fact(Skip = "Remove to run test")] public void Raise_a_real_number_to_a_zero_rational_number() { - Assert.Equal(1, 2.Expreal(new RationalNumber(0, 1)),0); + Assert.Equal(1, 2.Expreal(new RationalNumber(0, 1)), precision: 0); } [Fact(Skip = "Remove to run test")] public void Reduce_a_positive_rational_number_to_lowest_terms() { - Assert.Equal(new RationalNumber (1, 2), new RationalNumber(2, 4).Reduce()); + Assert.Equal(new RationalNumber(1, 2), new RationalNumber(2, 4).Reduce()); } [Fact(Skip = "Remove to run test")] public void Reduce_a_negative_rational_number_to_lowest_terms() { - Assert.Equal(new RationalNumber (-2, 3), new RationalNumber(-4, 6).Reduce()); + Assert.Equal(new RationalNumber(-2, 3), new RationalNumber(-4, 6).Reduce()); } [Fact(Skip = "Remove to run test")] public void Reduce_a_rational_number_with_a_negative_denominator_to_lowest_terms() { - Assert.Equal(new RationalNumber (-1, 3), new RationalNumber(3, -9).Reduce()); + Assert.Equal(new RationalNumber(-1, 3), new RationalNumber(3, -9).Reduce()); } [Fact(Skip = "Remove to run test")] public void Reduce_zero_to_lowest_terms() { - Assert.Equal(new RationalNumber (0, 1), new RationalNumber(0, 6).Reduce()); + Assert.Equal(new RationalNumber(0, 1), new RationalNumber(0, 6).Reduce()); } [Fact(Skip = "Remove to run test")] public void Reduce_an_integer_to_lowest_terms() { - Assert.Equal(new RationalNumber (-2, 1), new RationalNumber(-14, 7).Reduce()); + Assert.Equal(new RationalNumber(-2, 1), new RationalNumber(-14, 7).Reduce()); } [Fact(Skip = "Remove to run test")] public void Reduce_one_to_lowest_terms() { - Assert.Equal(new RationalNumber (1, 1), new RationalNumber(13, 13).Reduce()); + Assert.Equal(new RationalNumber(1, 1), new RationalNumber(13, 13).Reduce()); } } \ No newline at end of file diff --git a/exercises/react/ReactTest.cs b/exercises/react/ReactTest.cs index df01056e82..12a4bbf1e8 100644 --- a/exercises/react/ReactTest.cs +++ b/exercises/react/ReactTest.cs @@ -1,8 +1,8 @@ // This file was auto-generated based on version 2.0.0 of the canonical data. -using Xunit; -using System; using FakeItEasy; +using System; +using Xunit; public class ReactTest { diff --git a/exercises/rectangles/RectanglesTest.cs b/exercises/rectangles/RectanglesTest.cs index 94838833c3..d94f27fb90 100644 --- a/exercises/rectangles/RectanglesTest.cs +++ b/exercises/rectangles/RectanglesTest.cs @@ -1,5 +1,6 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. +using System; using Xunit; public class RectanglesTest @@ -7,7 +8,7 @@ public class RectanglesTest [Fact] public void No_rows() { - var strings = new string[0]; + var strings = Array.Empty(); Assert.Equal(0, Rectangles.Count(strings)); } diff --git a/exercises/run-length-encoding/RunLengthEncodingTest.cs b/exercises/run-length-encoding/RunLengthEncodingTest.cs index f840783774..ee21c7421e 100644 --- a/exercises/run-length-encoding/RunLengthEncodingTest.cs +++ b/exercises/run-length-encoding/RunLengthEncodingTest.cs @@ -5,79 +5,79 @@ public class RunLengthEncodingTest { [Fact] - public void Encode_empty_string() + public void Run_length_encode_a_string_empty_string() { Assert.Equal("", RunLengthEncoding.Encode("")); } [Fact(Skip = "Remove to run test")] - public void Encode_single_characters_only_are_encoded_without_count() + public void Run_length_encode_a_string_single_characters_only_are_encoded_without_count() { Assert.Equal("XYZ", RunLengthEncoding.Encode("XYZ")); } [Fact(Skip = "Remove to run test")] - public void Encode_string_with_no_single_characters() + public void Run_length_encode_a_string_string_with_no_single_characters() { Assert.Equal("2A3B4C", RunLengthEncoding.Encode("AABBBCCCC")); } [Fact(Skip = "Remove to run test")] - public void Encode_single_characters_mixed_with_repeated_characters() + public void Run_length_encode_a_string_single_characters_mixed_with_repeated_characters() { Assert.Equal("12WB12W3B24WB", RunLengthEncoding.Encode("WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB")); } [Fact(Skip = "Remove to run test")] - public void Encode_multiple_whitespace_mixed_in_string() + public void Run_length_encode_a_string_multiple_whitespace_mixed_in_string() { Assert.Equal("2 hs2q q2w2 ", RunLengthEncoding.Encode(" hsqq qww ")); } [Fact(Skip = "Remove to run test")] - public void Encode_lowercase_characters() + public void Run_length_encode_a_string_lowercase_characters() { Assert.Equal("2a3b4c", RunLengthEncoding.Encode("aabbbcccc")); } [Fact(Skip = "Remove to run test")] - public void Decode_empty_string() + public void Run_length_decode_a_string_empty_string() { Assert.Equal("", RunLengthEncoding.Decode("")); } [Fact(Skip = "Remove to run test")] - public void Decode_single_characters_only() + public void Run_length_decode_a_string_single_characters_only() { Assert.Equal("XYZ", RunLengthEncoding.Decode("XYZ")); } [Fact(Skip = "Remove to run test")] - public void Decode_string_with_no_single_characters() + public void Run_length_decode_a_string_string_with_no_single_characters() { Assert.Equal("AABBBCCCC", RunLengthEncoding.Decode("2A3B4C")); } [Fact(Skip = "Remove to run test")] - public void Decode_single_characters_with_repeated_characters() + public void Run_length_decode_a_string_single_characters_with_repeated_characters() { Assert.Equal("WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB", RunLengthEncoding.Decode("12WB12W3B24WB")); } [Fact(Skip = "Remove to run test")] - public void Decode_multiple_whitespace_mixed_in_string() + public void Run_length_decode_a_string_multiple_whitespace_mixed_in_string() { Assert.Equal(" hsqq qww ", RunLengthEncoding.Decode("2 hs2q q2w2 ")); } [Fact(Skip = "Remove to run test")] - public void Decode_lower_case_string() + public void Run_length_decode_a_string_lower_case_string() { Assert.Equal("aabbbcccc", RunLengthEncoding.Decode("2a3b4c")); } [Fact(Skip = "Remove to run test")] - public void Consistency_encode_followed_by_decode_gives_original_string() + public void Encode_and_then_decode_encode_followed_by_decode_gives_original_string() { Assert.Equal("zzz ZZ zZ", RunLengthEncoding.Decode(RunLengthEncoding.Encode("zzz ZZ zZ"))); } diff --git a/exercises/saddle-points/Example.cs b/exercises/saddle-points/Example.cs index 4decb02f87..4b17b1b7f1 100644 --- a/exercises/saddle-points/Example.cs +++ b/exercises/saddle-points/Example.cs @@ -15,20 +15,20 @@ public SaddlePoints(int[,] values) this.minCols = Columns().Select(r => r.Min()).ToArray(); } - public IEnumerable> Calculate() + public IEnumerable<(int, int)> Calculate() { return Coordinates().Where(IsSaddlePoint); } - private bool IsSaddlePoint(Tuple coordinate) + private bool IsSaddlePoint((int, int) coordinate) { return maxRows[coordinate.Item1] == values[coordinate.Item1, coordinate.Item2] && minCols[coordinate.Item2] == values[coordinate.Item1, coordinate.Item2]; } - private IEnumerable> Coordinates() + private IEnumerable<(int, int)> Coordinates() { - return Enumerable.Range(0, RowCount).SelectMany(x => Enumerable.Range(0, ColumnCount).Select(y => Tuple.Create(x, y))); + return Enumerable.Range(0, RowCount).SelectMany(x => Enumerable.Range(0, ColumnCount).Select(y => (x, y))); } private IEnumerable> Rows() diff --git a/exercises/saddle-points/SaddlePoints.cs b/exercises/saddle-points/SaddlePoints.cs index 7d19831ddc..a472688c7f 100644 --- a/exercises/saddle-points/SaddlePoints.cs +++ b/exercises/saddle-points/SaddlePoints.cs @@ -8,7 +8,7 @@ public SaddlePoints(int[,] values) { } - public IEnumerable> Calculate() + public IEnumerable<(int, int)> Calculate() { throw new NotImplementedException("You need to implement this function."); } diff --git a/exercises/saddle-points/SaddlePointsTest.cs b/exercises/saddle-points/SaddlePointsTest.cs index db0c869a53..2419bfa828 100644 --- a/exercises/saddle-points/SaddlePointsTest.cs +++ b/exercises/saddle-points/SaddlePointsTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class SaddlePointsTest { @@ -10,13 +10,13 @@ public void Can_identify_single_saddle_point() { var matrix = new[,] { - { 9, 8, 7 }, - { 5, 3, 2 }, - { 6, 6, 7 } + { 9, 8, 7 }, + { 5, 3, 2 }, + { 6, 6, 7 } }; var sut = new SaddlePoints(matrix); var actual = sut.Calculate(); - var expected = new[] { Tuple.Create(1, 0) }; + var expected = new[] { (1, 0) }; Assert.Equal(expected, actual); } @@ -34,9 +34,9 @@ public void Can_identify_lack_of_saddle_points_when_there_are_none() { var matrix = new[,] { - { 1, 2, 3 }, - { 3, 1, 2 }, - { 2, 3, 1 } + { 1, 2, 3 }, + { 3, 1, 2 }, + { 2, 3, 1 } }; var sut = new SaddlePoints(matrix); var actual = sut.Calculate(); @@ -48,13 +48,13 @@ public void Can_identify_multiple_saddle_points() { var matrix = new[,] { - { 4, 5, 4 }, - { 3, 5, 5 }, - { 1, 5, 4 } + { 4, 5, 4 }, + { 3, 5, 5 }, + { 1, 5, 4 } }; var sut = new SaddlePoints(matrix); var actual = sut.Calculate(); - var expected = new[] { Tuple.Create(0, 1), Tuple.Create(1, 1), Tuple.Create(2, 1) }; + var expected = new[] { (0, 1), (1, 1), (2, 1) }; Assert.Equal(expected, actual); } @@ -63,13 +63,13 @@ public void Can_identify_saddle_point_in_bottom_right_corner() { var matrix = new[,] { - { 8, 7, 9 }, - { 6, 7, 6 }, - { 3, 2, 5 } + { 8, 7, 9 }, + { 6, 7, 6 }, + { 3, 2, 5 } }; var sut = new SaddlePoints(matrix); var actual = sut.Calculate(); - var expected = new[] { Tuple.Create(2, 2) }; + var expected = new[] { (2, 2) }; Assert.Equal(expected, actual); } } \ No newline at end of file diff --git a/exercises/say/SayTest.cs b/exercises/say/SayTest.cs index 4b831f8de2..8f5d7a0915 100644 --- a/exercises/say/SayTest.cs +++ b/exercises/say/SayTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class SayTest { diff --git a/exercises/sieve/SieveTest.cs b/exercises/sieve/SieveTest.cs index b30083c964..f7e934c0f5 100644 --- a/exercises/sieve/SieveTest.cs +++ b/exercises/sieve/SieveTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class SieveTest { diff --git a/exercises/simple-cipher/SimpleCipherTest.cs b/exercises/simple-cipher/SimpleCipherTest.cs index f2c89995b4..f37284d626 100644 --- a/exercises/simple-cipher/SimpleCipherTest.cs +++ b/exercises/simple-cipher/SimpleCipherTest.cs @@ -1,7 +1,7 @@ -// This file was auto-generated based on version 1.0.0 of the canonical data. +// This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class SimpleCipherTest { diff --git a/exercises/spiral-matrix/SpiralMatrixTest.cs b/exercises/spiral-matrix/SpiralMatrixTest.cs index f4622b5b39..97b827632d 100644 --- a/exercises/spiral-matrix/SpiralMatrixTest.cs +++ b/exercises/spiral-matrix/SpiralMatrixTest.cs @@ -15,7 +15,7 @@ public void Trivial_spiral() { var expected = new[,] { - { 1 } + { 1 } }; Assert.Equal(expected, SpiralMatrix.GetMatrix(1)); } @@ -25,8 +25,8 @@ public void Spiral_of_size_2() { var expected = new[,] { - { 1, 2 }, - { 4, 3 } + { 1, 2 }, + { 4, 3 } }; Assert.Equal(expected, SpiralMatrix.GetMatrix(2)); } @@ -36,9 +36,9 @@ public void Spiral_of_size_3() { var expected = new[,] { - { 1, 2, 3 }, - { 8, 9, 4 }, - { 7, 6, 5 } + { 1, 2, 3 }, + { 8, 9, 4 }, + { 7, 6, 5 } }; Assert.Equal(expected, SpiralMatrix.GetMatrix(3)); } @@ -48,10 +48,10 @@ public void Spiral_of_size_4() { var expected = new[,] { - { 1, 2, 3, 4 }, - { 12, 13, 14, 5 }, - { 11, 16, 15, 6 }, - { 10, 9, 8, 7 } + { 1, 2, 3, 4 }, + { 12, 13, 14, 5 }, + { 11, 16, 15, 6 }, + { 10, 9, 8, 7 } }; Assert.Equal(expected, SpiralMatrix.GetMatrix(4)); } @@ -61,11 +61,11 @@ public void Spiral_of_size_5() { var expected = new[,] { - { 1, 2, 3, 4, 5 }, - { 16, 17, 18, 19, 6 }, - { 15, 24, 25, 20, 7 }, - { 14, 23, 22, 21, 8 }, - { 13, 12, 11, 10, 9 } + { 1, 2, 3, 4, 5 }, + { 16, 17, 18, 19, 6 }, + { 15, 24, 25, 20, 7 }, + { 14, 23, 22, 21, 8 }, + { 13, 12, 11, 10, 9 } }; Assert.Equal(expected, SpiralMatrix.GetMatrix(5)); } diff --git a/exercises/sublist/SublistTest.cs b/exercises/sublist/SublistTest.cs index 18b3d89683..b40e94a316 100644 --- a/exercises/sublist/SublistTest.cs +++ b/exercises/sublist/SublistTest.cs @@ -1,109 +1,109 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System.Collections.Generic; +using Xunit; public class SublistTest { [Fact] public void Empty_lists() { - Assert.Equal(SublistType.Equal, Sublist.Classify(new List() { }, new List() { })); + Assert.Equal(SublistType.Equal, Sublist.Classify(new List(), new List())); } [Fact(Skip = "Remove to run test")] public void Empty_list_within_non_empty_list() { - Assert.Equal(SublistType.Sublist, Sublist.Classify(new List() { }, new List() { 1, 2, 3 })); + Assert.Equal(SublistType.Sublist, Sublist.Classify(new List(), new List { 1, 2, 3 })); } [Fact(Skip = "Remove to run test")] public void Non_empty_list_contains_empty_list() { - Assert.Equal(SublistType.Superlist, Sublist.Classify(new List() { 1, 2, 3 }, new List() { })); + Assert.Equal(SublistType.Superlist, Sublist.Classify(new List { 1, 2, 3 }, new List())); } [Fact(Skip = "Remove to run test")] public void List_equals_itself() { - Assert.Equal(SublistType.Equal, Sublist.Classify(new List() { 1, 2, 3 }, new List() { 1, 2, 3 })); + Assert.Equal(SublistType.Equal, Sublist.Classify(new List { 1, 2, 3 }, new List { 1, 2, 3 })); } [Fact(Skip = "Remove to run test")] public void Different_lists() { - Assert.Equal(SublistType.Unequal, Sublist.Classify(new List() { 1, 2, 3 }, new List() { 2, 3, 4 })); + Assert.Equal(SublistType.Unequal, Sublist.Classify(new List { 1, 2, 3 }, new List { 2, 3, 4 })); } [Fact(Skip = "Remove to run test")] public void False_start() { - Assert.Equal(SublistType.Sublist, Sublist.Classify(new List() { 1, 2, 5 }, new List() { 0, 1, 2, 3, 1, 2, 5, 6 })); + Assert.Equal(SublistType.Sublist, Sublist.Classify(new List { 1, 2, 5 }, new List { 0, 1, 2, 3, 1, 2, 5, 6 })); } [Fact(Skip = "Remove to run test")] public void Consecutive() { - Assert.Equal(SublistType.Sublist, Sublist.Classify(new List() { 1, 1, 2 }, new List() { 0, 1, 1, 1, 2, 1, 2 })); + Assert.Equal(SublistType.Sublist, Sublist.Classify(new List { 1, 1, 2 }, new List { 0, 1, 1, 1, 2, 1, 2 })); } [Fact(Skip = "Remove to run test")] public void Sublist_at_start() { - Assert.Equal(SublistType.Sublist, Sublist.Classify(new List() { 0, 1, 2 }, new List() { 0, 1, 2, 3, 4, 5 })); + Assert.Equal(SublistType.Sublist, Sublist.Classify(new List { 0, 1, 2 }, new List { 0, 1, 2, 3, 4, 5 })); } [Fact(Skip = "Remove to run test")] public void Sublist_in_middle() { - Assert.Equal(SublistType.Sublist, Sublist.Classify(new List() { 2, 3, 4 }, new List() { 0, 1, 2, 3, 4, 5 })); + Assert.Equal(SublistType.Sublist, Sublist.Classify(new List { 2, 3, 4 }, new List { 0, 1, 2, 3, 4, 5 })); } [Fact(Skip = "Remove to run test")] public void Sublist_at_end() { - Assert.Equal(SublistType.Sublist, Sublist.Classify(new List() { 3, 4, 5 }, new List() { 0, 1, 2, 3, 4, 5 })); + Assert.Equal(SublistType.Sublist, Sublist.Classify(new List { 3, 4, 5 }, new List { 0, 1, 2, 3, 4, 5 })); } [Fact(Skip = "Remove to run test")] public void At_start_of_superlist() { - Assert.Equal(SublistType.Superlist, Sublist.Classify(new List() { 0, 1, 2, 3, 4, 5 }, new List() { 0, 1, 2 })); + Assert.Equal(SublistType.Superlist, Sublist.Classify(new List { 0, 1, 2, 3, 4, 5 }, new List { 0, 1, 2 })); } [Fact(Skip = "Remove to run test")] public void In_middle_of_superlist() { - Assert.Equal(SublistType.Superlist, Sublist.Classify(new List() { 0, 1, 2, 3, 4, 5 }, new List() { 2, 3 })); + Assert.Equal(SublistType.Superlist, Sublist.Classify(new List { 0, 1, 2, 3, 4, 5 }, new List { 2, 3 })); } [Fact(Skip = "Remove to run test")] public void At_end_of_superlist() { - Assert.Equal(SublistType.Superlist, Sublist.Classify(new List() { 0, 1, 2, 3, 4, 5 }, new List() { 3, 4, 5 })); + Assert.Equal(SublistType.Superlist, Sublist.Classify(new List { 0, 1, 2, 3, 4, 5 }, new List { 3, 4, 5 })); } [Fact(Skip = "Remove to run test")] public void First_list_missing_element_from_second_list() { - Assert.Equal(SublistType.Unequal, Sublist.Classify(new List() { 1, 3 }, new List() { 1, 2, 3 })); + Assert.Equal(SublistType.Unequal, Sublist.Classify(new List { 1, 3 }, new List { 1, 2, 3 })); } [Fact(Skip = "Remove to run test")] public void Second_list_missing_element_from_first_list() { - Assert.Equal(SublistType.Unequal, Sublist.Classify(new List() { 1, 2, 3 }, new List() { 1, 3 })); + Assert.Equal(SublistType.Unequal, Sublist.Classify(new List { 1, 2, 3 }, new List { 1, 3 })); } [Fact(Skip = "Remove to run test")] public void Order_matters_to_a_list() { - Assert.Equal(SublistType.Unequal, Sublist.Classify(new List() { 1, 2, 3 }, new List() { 3, 2, 1 })); + Assert.Equal(SublistType.Unequal, Sublist.Classify(new List { 1, 2, 3 }, new List { 3, 2, 1 })); } [Fact(Skip = "Remove to run test")] public void Same_digits_but_different_numbers() { - Assert.Equal(SublistType.Unequal, Sublist.Classify(new List() { 1, 0, 1 }, new List() { 10, 1 })); + Assert.Equal(SublistType.Unequal, Sublist.Classify(new List { 1, 0, 1 }, new List { 10, 1 })); } } \ No newline at end of file diff --git a/exercises/sum-of-multiples/SumOfMultiplesTest.cs b/exercises/sum-of-multiples/SumOfMultiplesTest.cs index 46268814f4..d2e97016a7 100644 --- a/exercises/sum-of-multiples/SumOfMultiplesTest.cs +++ b/exercises/sum-of-multiples/SumOfMultiplesTest.cs @@ -1,5 +1,6 @@ // This file was auto-generated based on version 1.2.0 of the canonical data. +using System; using Xunit; public class SumOfMultiplesTest @@ -79,6 +80,6 @@ public void Multiples_of_1_up_to_100() [Fact(Skip = "Remove to run test")] public void Multiples_of_an_empty_list_up_to_10000() { - Assert.Equal(0, SumOfMultiples.Sum(new int[0], 10000)); + Assert.Equal(0, SumOfMultiples.Sum(Array.Empty(), 10000)); } } \ No newline at end of file diff --git a/exercises/tournament/TournamentTest.cs b/exercises/tournament/TournamentTest.cs index 881efaad14..98f4880f7d 100644 --- a/exercises/tournament/TournamentTest.cs +++ b/exercises/tournament/TournamentTest.cs @@ -1,9 +1,9 @@ // This file was auto-generated based on version 1.4.0 of the canonical data. -using Xunit; using System; using System.IO; using System.Text; +using Xunit; public class TournamentTest { diff --git a/exercises/two-bucket/TwoBucketTest.cs b/exercises/two-bucket/TwoBucketTest.cs index bc37231661..5b0035a860 100644 --- a/exercises/two-bucket/TwoBucketTest.cs +++ b/exercises/two-bucket/TwoBucketTest.cs @@ -8,59 +8,59 @@ public class TwoBucketTest public void Measure_using_bucket_one_of_size_3_and_bucket_two_of_size_5_start_with_bucket_one() { var sut = new TwoBucket(3, 5, Bucket.One); - var result = sut.Measure(1); - Assert.Equal(4, result.Moves); - Assert.Equal(5, result.OtherBucket); - Assert.Equal(Bucket.One, result.GoalBucket); + var actual = sut.Measure(1); + Assert.Equal(4, actual.Moves); + Assert.Equal(5, actual.OtherBucket); + Assert.Equal(Bucket.One, actual.GoalBucket); } [Fact(Skip = "Remove to run test")] public void Measure_using_bucket_one_of_size_3_and_bucket_two_of_size_5_start_with_bucket_two() { var sut = new TwoBucket(3, 5, Bucket.Two); - var result = sut.Measure(1); - Assert.Equal(8, result.Moves); - Assert.Equal(3, result.OtherBucket); - Assert.Equal(Bucket.Two, result.GoalBucket); + var actual = sut.Measure(1); + Assert.Equal(8, actual.Moves); + Assert.Equal(3, actual.OtherBucket); + Assert.Equal(Bucket.Two, actual.GoalBucket); } [Fact(Skip = "Remove to run test")] public void Measure_using_bucket_one_of_size_7_and_bucket_two_of_size_11_start_with_bucket_one() { var sut = new TwoBucket(7, 11, Bucket.One); - var result = sut.Measure(2); - Assert.Equal(14, result.Moves); - Assert.Equal(11, result.OtherBucket); - Assert.Equal(Bucket.One, result.GoalBucket); + var actual = sut.Measure(2); + Assert.Equal(14, actual.Moves); + Assert.Equal(11, actual.OtherBucket); + Assert.Equal(Bucket.One, actual.GoalBucket); } [Fact(Skip = "Remove to run test")] public void Measure_using_bucket_one_of_size_7_and_bucket_two_of_size_11_start_with_bucket_two() { var sut = new TwoBucket(7, 11, Bucket.Two); - var result = sut.Measure(2); - Assert.Equal(18, result.Moves); - Assert.Equal(7, result.OtherBucket); - Assert.Equal(Bucket.Two, result.GoalBucket); + var actual = sut.Measure(2); + Assert.Equal(18, actual.Moves); + Assert.Equal(7, actual.OtherBucket); + Assert.Equal(Bucket.Two, actual.GoalBucket); } [Fact(Skip = "Remove to run test")] public void Measure_one_step_using_bucket_one_of_size_1_and_bucket_two_of_size_3_start_with_bucket_two() { var sut = new TwoBucket(1, 3, Bucket.Two); - var result = sut.Measure(3); - Assert.Equal(1, result.Moves); - Assert.Equal(0, result.OtherBucket); - Assert.Equal(Bucket.Two, result.GoalBucket); + var actual = sut.Measure(3); + Assert.Equal(1, actual.Moves); + Assert.Equal(0, actual.OtherBucket); + Assert.Equal(Bucket.Two, actual.GoalBucket); } [Fact(Skip = "Remove to run test")] public void Measure_using_bucket_one_of_size_2_and_bucket_two_of_size_3_start_with_bucket_one_and_end_with_bucket_two() { var sut = new TwoBucket(2, 3, Bucket.One); - var result = sut.Measure(3); - Assert.Equal(2, result.Moves); - Assert.Equal(2, result.OtherBucket); - Assert.Equal(Bucket.Two, result.GoalBucket); + var actual = sut.Measure(3); + Assert.Equal(2, actual.Moves); + Assert.Equal(2, actual.OtherBucket); + Assert.Equal(Bucket.Two, actual.GoalBucket); } } \ No newline at end of file diff --git a/exercises/variable-length-quantity/VariableLengthQuantityTest.cs b/exercises/variable-length-quantity/VariableLengthQuantityTest.cs index b71cca1166..891314b416 100644 --- a/exercises/variable-length-quantity/VariableLengthQuantityTest.cs +++ b/exercises/variable-length-quantity/VariableLengthQuantityTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class VariableLengthQuantityTest { diff --git a/exercises/word-count/WordCountTest.cs b/exercises/word-count/WordCountTest.cs index 8e592381d5..309e3049b3 100644 --- a/exercises/word-count/WordCountTest.cs +++ b/exercises/word-count/WordCountTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.2.0 of the canonical data. -using Xunit; using System.Collections.Generic; +using Xunit; public class WordCountTest { diff --git a/exercises/word-search/Example.cs b/exercises/word-search/Example.cs index 2b561ce86d..f5410125cd 100644 --- a/exercises/word-search/Example.cs +++ b/exercises/word-search/Example.cs @@ -9,7 +9,7 @@ public class WordSearch private readonly int height; private (int, int)[] positions; - private static readonly ValueTuple[] Directions = + private static readonly (int, int)[] Directions = { ( 1, 0), ( 0, 1), @@ -29,12 +29,12 @@ public WordSearch(string puzzle) positions = Positions(); } - public Dictionary, ValueTuple>?> Search(IEnumerable words) + public Dictionary Search(IEnumerable words) { return words.ToDictionary(word => word, Search); } - private ValueTuple, ValueTuple>? Search(string word) + private ((int, int), (int, int))? Search(string word) { return Positions() @@ -42,7 +42,7 @@ public WordSearch(string puzzle) .FirstOrDefault(); } - private IEnumerable, ValueTuple>> Find(string word, ValueTuple position, ValueTuple direction) + private IEnumerable<((int, int), (int, int))> Find(string word, (int, int) position, (int, int) direction) { var current = position; @@ -56,10 +56,10 @@ private IEnumerable, ValueTuple>> Find current = (current.Item1 + direction.Item1, current.Item2 + direction.Item2); } - yield return ValueTuple.Create(position, (current.Item1 - direction.Item1, current.Item2 - direction.Item2)); + yield return (position, (current.Item1 - direction.Item1, current.Item2 - direction.Item2)); } - private char? FindChar(ValueTuple coordinate) + private char? FindChar((int, int) coordinate) { if (coordinate.Item1 > 0 && coordinate.Item1 <= width && coordinate.Item2 > 0 && coordinate.Item2 <= height) { @@ -69,7 +69,7 @@ private IEnumerable, ValueTuple>> Find return null; } - private ValueTuple[] Positions() + private (int, int)[] Positions() { return Enumerable.Range(1, width).SelectMany(x => Enumerable.Range(1, height).Select(y => (x, y))) diff --git a/exercises/word-search/WordSearchTest.cs b/exercises/word-search/WordSearchTest.cs index c032ae9cad..be9f85e29d 100644 --- a/exercises/word-search/WordSearchTest.cs +++ b/exercises/word-search/WordSearchTest.cs @@ -1,18 +1,15 @@ -// This file was auto-generated based on version 1.2.0 of the canonical data. +// This file was auto-generated based on version 1.2.1 of the canonical data. -using Xunit; using System; using System.Collections.Generic; +using Xunit; public class WordSearchTest { [Fact] public void Should_accept_an_initial_game_grid_and_a_target_search_word() { - var wordsToSearchFor = new[] - { - "clojure" - }; + var wordsToSearchFor = new[] { "clojure" }; var grid = "jefblpepre"; var sut = new WordSearch(grid); var actual = sut.Search(wordsToSearchFor); @@ -26,10 +23,7 @@ public void Should_accept_an_initial_game_grid_and_a_target_search_word() [Fact(Skip = "Remove to run test")] public void Should_locate_one_word_written_left_to_right() { - var wordsToSearchFor = new[] - { - "clojure" - }; + var wordsToSearchFor = new[] { "clojure" }; var grid = "clojurermt"; var sut = new WordSearch(grid); var actual = sut.Search(wordsToSearchFor); @@ -43,10 +37,7 @@ public void Should_locate_one_word_written_left_to_right() [Fact(Skip = "Remove to run test")] public void Should_locate_the_same_word_written_left_to_right_in_a_different_position() { - var wordsToSearchFor = new[] - { - "clojure" - }; + var wordsToSearchFor = new[] { "clojure" }; var grid = "mtclojurer"; var sut = new WordSearch(grid); var actual = sut.Search(wordsToSearchFor); @@ -60,10 +51,7 @@ public void Should_locate_the_same_word_written_left_to_right_in_a_different_pos [Fact(Skip = "Remove to run test")] public void Should_locate_a_different_left_to_right_word() { - var wordsToSearchFor = new[] - { - "coffee" - }; + var wordsToSearchFor = new[] { "coffee" }; var grid = "coffeelplx"; var sut = new WordSearch(grid); var actual = sut.Search(wordsToSearchFor); @@ -77,10 +65,7 @@ public void Should_locate_a_different_left_to_right_word() [Fact(Skip = "Remove to run test")] public void Should_locate_that_different_left_to_right_word_in_a_different_position() { - var wordsToSearchFor = new[] - { - "coffee" - }; + var wordsToSearchFor = new[] { "coffee" }; var grid = "xcoffeezlp"; var sut = new WordSearch(grid); var actual = sut.Search(wordsToSearchFor); @@ -94,10 +79,7 @@ public void Should_locate_that_different_left_to_right_word_in_a_different_posit [Fact(Skip = "Remove to run test")] public void Should_locate_a_left_to_right_word_in_two_line_grid() { - var wordsToSearchFor = new[] - { - "clojure" - }; + var wordsToSearchFor = new[] { "clojure" }; var grid = "jefblpepre\n" + "tclojurerm"; @@ -113,10 +95,7 @@ public void Should_locate_a_left_to_right_word_in_two_line_grid() [Fact(Skip = "Remove to run test")] public void Should_locate_a_left_to_right_word_in_three_line_grid() { - var wordsToSearchFor = new[] - { - "clojure" - }; + var wordsToSearchFor = new[] { "clojure" }; var grid = "camdcimgtc\n" + "jefblpepre\n" + @@ -133,10 +112,7 @@ public void Should_locate_a_left_to_right_word_in_three_line_grid() [Fact(Skip = "Remove to run test")] public void Should_locate_a_left_to_right_word_in_ten_line_grid() { - var wordsToSearchFor = new[] - { - "clojure" - }; + var wordsToSearchFor = new[] { "clojure" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -160,10 +136,7 @@ public void Should_locate_a_left_to_right_word_in_ten_line_grid() [Fact(Skip = "Remove to run test")] public void Should_locate_that_left_to_right_word_in_a_different_position_in_a_ten_line_grid() { - var wordsToSearchFor = new[] - { - "clojure" - }; + var wordsToSearchFor = new[] { "clojure" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -187,10 +160,7 @@ public void Should_locate_that_left_to_right_word_in_a_different_position_in_a_t [Fact(Skip = "Remove to run test")] public void Should_locate_a_different_left_to_right_word_in_a_ten_line_grid() { - var wordsToSearchFor = new[] - { - "fortran" - }; + var wordsToSearchFor = new[] { "fortran" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -214,11 +184,7 @@ public void Should_locate_a_different_left_to_right_word_in_a_ten_line_grid() [Fact(Skip = "Remove to run test")] public void Should_locate_multiple_words() { - var wordsToSearchFor = new[] - { - "fortran", - "clojure" - }; + var wordsToSearchFor = new[] { "fortran", "clojure" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -244,10 +210,7 @@ public void Should_locate_multiple_words() [Fact(Skip = "Remove to run test")] public void Should_locate_a_single_word_written_right_to_left() { - var wordsToSearchFor = new[] - { - "elixir" - }; + var wordsToSearchFor = new[] { "elixir" }; var grid = "rixilelhrs"; var sut = new WordSearch(grid); var actual = sut.Search(wordsToSearchFor); @@ -261,11 +224,7 @@ public void Should_locate_a_single_word_written_right_to_left() [Fact(Skip = "Remove to run test")] public void Should_locate_multiple_words_written_in_different_horizontal_directions() { - var wordsToSearchFor = new[] - { - "elixir", - "clojure" - }; + var wordsToSearchFor = new[] { "elixir", "clojure" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -291,12 +250,7 @@ public void Should_locate_multiple_words_written_in_different_horizontal_directi [Fact(Skip = "Remove to run test")] public void Should_locate_words_written_top_to_bottom() { - var wordsToSearchFor = new[] - { - "clojure", - "elixir", - "ecmascript" - }; + var wordsToSearchFor = new[] { "clojure", "elixir", "ecmascript" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -324,13 +278,7 @@ public void Should_locate_words_written_top_to_bottom() [Fact(Skip = "Remove to run test")] public void Should_locate_words_written_bottom_to_top() { - var wordsToSearchFor = new[] - { - "clojure", - "elixir", - "ecmascript", - "rust" - }; + var wordsToSearchFor = new[] { "clojure", "elixir", "ecmascript", "rust" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -360,14 +308,7 @@ public void Should_locate_words_written_bottom_to_top() [Fact(Skip = "Remove to run test")] public void Should_locate_words_written_top_left_to_bottom_right() { - var wordsToSearchFor = new[] - { - "clojure", - "elixir", - "ecmascript", - "rust", - "java" - }; + var wordsToSearchFor = new[] { "clojure", "elixir", "ecmascript", "rust", "java" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -399,15 +340,7 @@ public void Should_locate_words_written_top_left_to_bottom_right() [Fact(Skip = "Remove to run test")] public void Should_locate_words_written_bottom_right_to_top_left() { - var wordsToSearchFor = new[] - { - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua" - }; + var wordsToSearchFor = new[] { "clojure", "elixir", "ecmascript", "rust", "java", "lua" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -441,16 +374,7 @@ public void Should_locate_words_written_bottom_right_to_top_left() [Fact(Skip = "Remove to run test")] public void Should_locate_words_written_bottom_left_to_top_right() { - var wordsToSearchFor = new[] - { - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua", - "lisp" - }; + var wordsToSearchFor = new[] { "clojure", "elixir", "ecmascript", "rust", "java", "lua", "lisp" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -486,17 +410,7 @@ public void Should_locate_words_written_bottom_left_to_top_right() [Fact(Skip = "Remove to run test")] public void Should_locate_words_written_top_right_to_bottom_left() { - var wordsToSearchFor = new[] - { - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua", - "lisp", - "ruby" - }; + var wordsToSearchFor = new[] { "clojure", "elixir", "ecmascript", "rust", "java", "lua", "lisp", "ruby" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + @@ -534,18 +448,7 @@ public void Should_locate_words_written_top_right_to_bottom_left() [Fact(Skip = "Remove to run test")] public void Should_fail_to_locate_a_word_that_is_not_in_the_puzzle() { - var wordsToSearchFor = new[] - { - "clojure", - "elixir", - "ecmascript", - "rust", - "java", - "lua", - "lisp", - "ruby", - "haskell" - }; + var wordsToSearchFor = new[] { "clojure", "elixir", "ecmascript", "rust", "java", "lua", "lisp", "ruby", "haskell" }; var grid = "jefblpepre\n" + "camdcimgtc\n" + diff --git a/exercises/wordy/WordyTest.cs b/exercises/wordy/WordyTest.cs index 92adbc262d..aa2ff5436a 100644 --- a/exercises/wordy/WordyTest.cs +++ b/exercises/wordy/WordyTest.cs @@ -1,7 +1,7 @@ // This file was auto-generated based on version 1.1.0 of the canonical data. -using Xunit; using System; +using Xunit; public class WordyTest { diff --git a/generators/Exercises/AllYourBase.cs b/generators/Exercises/AllYourBase.cs deleted file mode 100644 index a75393c626..0000000000 --- a/generators/Exercises/AllYourBase.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; - -namespace Generators.Exercises -{ - public class AllYourBase : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Input["digits"] = ConvertHelper.ToArray(canonicalDataCase.Input["digits"]); - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is Dictionary ? typeof(ArgumentException) : null; - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Allergies.cs b/generators/Exercises/Allergies.cs deleted file mode 100644 index a34ef1ad01..0000000000 --- a/generators/Exercises/Allergies.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class Allergies : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - if (canonicalDataCase.Property == "allergicTo") - canonicalDataCase.Property = "IsAllergicTo"; - else if (canonicalDataCase.Property == "list") - canonicalDataCase.UseVariableForExpected = true; - - canonicalDataCase.SetConstructorInputParameters("score"); - } - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.CanonicalDataCase.Property == "IsAllergicTo") - return RenderIsAllergicToAssert(testMethodBody); - - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - private static string RenderIsAllergicToAssert(TestMethodBody testMethodBody) - { - const string template = - @"{%- for allergy in Allergies -%} -Assert.{% if allergy.result %}True{% else %}False{% endif %}(sut.IsAllergicTo(""{{ allergy.substance }}"")); -{%- endfor -%}"; - - var templateParameters = new { Allergies = testMethodBody.CanonicalDataCase.Expected }; - return TemplateRenderer.RenderInline(template, templateParameters); - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Alphametics.cs b/generators/Exercises/Alphametics.cs deleted file mode 100644 index 0b4eaf5d9f..0000000000 --- a/generators/Exercises/Alphametics.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Alphametics : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.UseVariableForTested = true; - - if (canonicalDataCase.Expected == null) - canonicalDataCase.ExceptionThrown = typeof(ArgumentException); - else - canonicalDataCase.Expected = ConvertExpected(canonicalDataCase); - } - } - - private static dynamic ConvertExpected(CanonicalDataCase canonicalDataCase) - { - Dictionary expected = canonicalDataCase.Expected; - return expected.ToDictionary(kv => kv.Key[0], kv => int.Parse(kv.Value.ToString())); - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(Dictionary).Namespace }; - } -} \ No newline at end of file diff --git a/generators/Exercises/Anagram.cs b/generators/Exercises/Anagram.cs deleted file mode 100644 index c59d867808..0000000000 --- a/generators/Exercises/Anagram.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class Anagram : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.SetConstructorInputParameters("subject"); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/BeerSong.cs b/generators/Exercises/BeerSong.cs deleted file mode 100644 index 8432c65936..0000000000 --- a/generators/Exercises/BeerSong.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class BeerSong : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Expected = ConvertHelper.ToMultiLineString(canonicalDataCase.Expected); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/BinarySearch.cs b/generators/Exercises/BinarySearch.cs deleted file mode 100644 index 6ab3860f86..0000000000 --- a/generators/Exercises/BinarySearch.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class BinarySearch : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Input["array"] = ConvertHelper.ToArray(canonicalDataCase.Input["array"]); - canonicalDataCase.UseVariablesForConstructorParameters = true; - canonicalDataCase.SetConstructorInputParameters("array"); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/BinarySearchTree.cs b/generators/Exercises/BinarySearchTree.cs deleted file mode 100644 index dc668caed8..0000000000 --- a/generators/Exercises/BinarySearchTree.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Generators.Output; - -namespace Generators.Exercises -{ - public class ExpectedDataBinaryTree - { - public ExpectedDataBinaryTree(System.Collections.Generic.Dictionary treeNode) - { - Value = treeNode["data"] as string; - if (treeNode["left"] != null) this.Left = new ExpectedDataBinaryTree(treeNode["left"] as System.Collections.Generic.Dictionary); - if (treeNode["right"] != null) this.Right = new ExpectedDataBinaryTree(treeNode["right"] as System.Collections.Generic.Dictionary); - } - - public int Level { get; } - public string Value { get; } - public ExpectedDataBinaryTree Left { get; private set; } - public ExpectedDataBinaryTree Right { get; private set; } - - public IEnumerable TestAsserts(string traverse = "") - { - yield return $"Assert.Equal({this.Value}, tree{traverse}.Value);"; - if (this.Left != null) foreach (var assert in this.Left.TestAsserts(traverse + ".Left")) yield return assert; - if (this.Right != null) foreach (var assert in this.Right.TestAsserts(traverse + ".Right")) yield return assert; - } - } - - public class BinarySearchTree : GeneratorExercise - { - protected override HashSet AddAdditionalNamespaces() => new HashSet() { typeof(System.Linq.IQueryable).Namespace }; - - private StringBuilder testFactCodeLines; - void addCodeLine(string line) => testFactCodeLines.Append(line + "\r\n"); - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - testFactCodeLines = new StringBuilder(); - var canonicalDataCase = testMethodBody.CanonicalDataCase; - var input = canonicalDataCase.Properties["input"] as System.Collections.Generic.Dictionary; - var constructorData = input["treeData"] as string[]; - - if (constructorData.Length == 1) addCodeLine($"var tree = new BinarySearchTree({constructorData[0]});"); - else - { - string constructorDataString = string.Join(", ", constructorData); - addCodeLine($"var tree = new BinarySearchTree(new[] {{ {constructorDataString} }});"); - } - - var expected = canonicalDataCase.Properties["expected"] as System.Collections.Generic.Dictionary; - if (expected != null) - { - var tree = new ExpectedDataBinaryTree(expected as System.Collections.Generic.Dictionary); - foreach (var assert in tree.TestAsserts()) addCodeLine(assert); - } - else - { - string expectedArrayString = string.Join(", ", canonicalDataCase.Properties["expected"] as string[]); - addCodeLine($"Assert.Equal(new[] {{ {expectedArrayString} }}, tree.AsEnumerable());"); - } - - return TemplateRenderer.RenderInline(testFactCodeLines.ToString(), testMethodBody.AssertTemplateParameters); - } - - } -} - - diff --git a/generators/Exercises/BookStore.cs b/generators/Exercises/BookStore.cs deleted file mode 100644 index de874c5aa5..0000000000 --- a/generators/Exercises/BookStore.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class BookStore : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Expected = canonicalDataCase.Expected / 100.0f; - canonicalDataCase.Input["basket"] = ConvertHelper.ToArray(canonicalDataCase.Input["basket"]); - canonicalDataCase.SetInputParameters("basket"); - canonicalDataCase.UseVariablesForInput = true; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Bowling.cs b/generators/Exercises/Bowling.cs deleted file mode 100644 index 2f561f75c7..0000000000 --- a/generators/Exercises/Bowling.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Text; -using Generators.Input; -using Generators.Output; -using System.Collections.Generic; - -namespace Generators.Exercises -{ - public class Bowling : GeneratorExercise - { - private const string PreviousRolls = "previousRolls"; - - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - if (!(canonicalDataCase.Expected is int)) - { - canonicalDataCase.ExceptionThrown = typeof(ArgumentException); - } - else - { - canonicalDataCase.UseVariableForTested = true; - - } - canonicalDataCase.SetInputParameters(); - } - } - - protected override string RenderTestMethodBodyArrange(TestMethodBody testMethodBody) - { - var builder = new StringBuilder(); - builder.AppendLine("var sut = new BowlingGame();"); - - if (testMethodBody.CanonicalDataCase.Input.ContainsKey(PreviousRolls)) - { - var array = testMethodBody.CanonicalDataCase.Input[PreviousRolls] as int[]; - if (array == null) - { - builder.Append("var previousRolls = new int[0];"); - } - else - { - builder.Append("var previousRolls = new [] { "); - builder.AppendJoin(", ", array); - builder.AppendLine(" };"); - } - } - - return builder.ToString(); - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - var template = string.Empty; - if (testMethodBody.CanonicalDataCase.ExceptionThrown != null && testMethodBody.CanonicalDataCase.Input.ContainsKey("roll")) - { - template = "Assert.Throws(() => sut.Roll({{RollVal}}));"; - var templateParams = new - { - RollVal = testMethodBody.CanonicalDataCase.Input["roll"] - }; - return TemplateRenderer.RenderInline(template, templateParams); - } - else if (testMethodBody.CanonicalDataCase.ExceptionThrown != null && testMethodBody.CanonicalDataCase.Property == "score") - { - template = "Assert.Throws(() => sut.Score());"; - return template; - } - - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - protected override string RenderTestMethodBodyAct(TestMethodBody testMethodBody) - { - var template = -@"DoRoll(previousRolls, sut); -"; - - if (testMethodBody.CanonicalDataCase.ExceptionThrown != null) - { - return template; - } - - if (testMethodBody.CanonicalDataCase.Input.ContainsKey("roll")) - { - template += -@"sut.Roll({{RolVal}}); -var actual = sut.Score(); -"; - var templateParameters = new - { - RolVal = testMethodBody.CanonicalDataCase.Input["roll"] - }; - return TemplateRenderer.RenderInline(template, templateParameters); - } - - template += "var actual = sut.Score();"; - return template; - } - - protected override string[] RenderAdditionalMethods() - { - return new string[] { -@" -public void DoRoll(ICollection rolls, BowlingGame sut) -{ - foreach (var roll in rolls) - { - sut.Roll(roll); - } -}" }; - } - - protected override HashSet AddAdditionalNamespaces() - { - return new HashSet { typeof(ICollection<>).Namespace }; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/BracketPush.cs b/generators/Exercises/BracketPush.cs deleted file mode 100644 index 086b3c2afa..0000000000 --- a/generators/Exercises/BracketPush.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class BracketPush : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Input["value"] = canonicalDataCase.Input["value"].Replace("\\", "\\\\"); - canonicalDataCase.UseVariablesForInput = true; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Change.cs b/generators/Exercises/Change.cs deleted file mode 100644 index 374ce0c4d1..0000000000 --- a/generators/Exercises/Change.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Change : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - - if (canonicalDataCase.Expected is int) - canonicalDataCase.ExceptionThrown = typeof(ArgumentException); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/CircularBuffer.cs b/generators/Exercises/CircularBuffer.cs deleted file mode 100644 index 4049e49a7f..0000000000 --- a/generators/Exercises/CircularBuffer.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class CircularBuffer : GeneratorExercise - { - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - var lines = new StringBuilder(); - lines.AppendLine(RenderSut(testMethodBody.CanonicalDataCase)); - - foreach (var operation in testMethodBody.CanonicalDataCase.Input["operations"]) - lines.AppendLine(RenderOperation(operation)); - - return lines.ToString(); - } - - private static string RenderSut(CanonicalDataCase canonicalDataCase) - { - var capacity = canonicalDataCase.Input["capacity"]; - return $"var buffer = new CircularBuffer(capacity: {capacity});"; - } - - private static string RenderOperation(dynamic operation) - { - switch (operation["operation"]) - { - case "read": - return RenderReadOperation(operation); - case "write": - return RenderWriteOperation(operation); - case "overwrite": - return RenderOverwriteOperation(operation); - case "clear": - return RenderClearOperation(operation); - default: - throw new ArgumentOutOfRangeException($"Unknown operation type: {operation["operation"]}"); - } - } - - private static string RenderReadOperation(dynamic operation) - { - if (operation["should_succeed"]) - { - return $"Assert.Equal({operation["expected"]}, buffer.Read());"; - } - - return "Assert.Throws(() => buffer.Read());"; - } - - private static string RenderWriteOperation(dynamic operation) - { - if (operation["should_succeed"]) - { - return $"buffer.Write({operation["item"]});"; - } - - return $"Assert.Throws(() => buffer.Write({operation["item"]}));"; - } - - private static string RenderOverwriteOperation(dynamic operation) - => $"buffer.Overwrite({operation["item"]});"; - - private static string RenderClearOperation(dynamic operation) - => "buffer.Clear();"; - - protected override HashSet AddAdditionalNamespaces() - => new HashSet { typeof(InvalidOperationException).Namespace }; - } -} \ No newline at end of file diff --git a/generators/Exercises/Clock.cs b/generators/Exercises/Clock.cs deleted file mode 100644 index e4f5caa3d4..0000000000 --- a/generators/Exercises/Clock.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class Clock : GeneratorExercise - { - private const string ParamClock1 = "clock1"; - private const string ParamClock2 = "clock2"; - private const string ParamHour = "hour"; - private const string ParamMinute = "minute"; - - private const string PropertyCreate = "create"; - private const string PropertyEqual = "equal"; - private const string PropertyEquals = "equals"; - private const string PropertyToString = "to_string"; - - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - if (canonicalDataCase.Property != PropertyEqual) - { - canonicalDataCase.SetConstructorInputParameters(ParamHour, ParamMinute); - } - else - { - canonicalDataCase.SetConstructorInputParameters(ParamClock2); - - var result = (Dictionary)canonicalDataCase.Input[ParamClock1]; - canonicalDataCase.Input[ParamClock1] = new UnescapedValue($"new Clock({result[ParamHour]}, {result[ParamMinute]})"); - } - - if (canonicalDataCase.Property == PropertyCreate) - { - canonicalDataCase.Property = PropertyToString; - } - else if (canonicalDataCase.Property == PropertyEqual) - { - canonicalDataCase.Property = PropertyEquals; - } - } - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.CanonicalDataCase.Property == PropertyEquals) - { - return RenderEqualToAssert(testMethodBody); - } - else if (testMethodBody.CanonicalDataCase.Property != PropertyToString) - { - return RenderConsistencyToAssert(testMethodBody); - } - else - { - return base.RenderTestMethodBodyAssert(testMethodBody); - } - } - - private static string RenderConsistencyToAssert(TestMethodBody testMethodBody) - { - var template = $"Assert.Equal({{{{ ExpectedParameter }}}}, {{{{ TestedValue }}}}.ToString());"; - - return TemplateRenderer.RenderInline(template, testMethodBody.AssertTemplateParameters); - } - - private static string RenderEqualToAssert(TestMethodBody testMethodBody) - { - var expectedParameter = testMethodBody.CanonicalDataCase.Input[ParamClock1]; - var testedValue = "sut"; - var expectedEqual = testMethodBody.CanonicalDataCase.Expected; - - testMethodBody.AssertTemplateParameters = new { expectedParameter, testedValue }; - - var template = expectedEqual - ? $"Assert.Equal({{{{ ExpectedParameter }}}}, {{{{ TestedValue }}}}); " - : $"Assert.NotEqual({{{{ ExpectedParameter }}}}, {{{{ TestedValue }}}});"; - - return TemplateRenderer.RenderInline(template, testMethodBody.AssertTemplateParameters); - } - } -} \ No newline at end of file diff --git a/generators/Exercises/CollatzConjecture.cs b/generators/Exercises/CollatzConjecture.cs deleted file mode 100644 index 88bc717c01..0000000000 --- a/generators/Exercises/CollatzConjecture.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Generators.Input; -using System; - -namespace Generators.Exercises -{ - public class CollatzConjecture : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - canonicalDataCase.ExceptionThrown = canonicalDataCase.Input["number"] <= 0 ? typeof(ArgumentException) : null; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/ComplexNumbers.cs b/generators/Exercises/ComplexNumbers.cs deleted file mode 100644 index 1be6cbe87a..0000000000 --- a/generators/Exercises/ComplexNumbers.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class ComplexNumbers : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - canonicalData.Exercise = "complex-number"; - - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = IsComplexNumber(canonicalDataCase.Expected); - canonicalDataCase.Expected = ConvertToType(canonicalDataCase.Expected); - - var constructorParamName = canonicalDataCase.Input.ContainsKey("z") ? "z" : "z1"; - canonicalDataCase.Input["real"] = ConvertMathDouble(canonicalDataCase.Input[constructorParamName][0]); - canonicalDataCase.Input["imaginary"] = ConvertMathDouble(canonicalDataCase.Input[constructorParamName][1]); - - canonicalDataCase.SetInputParameters(GetInputParameters(canonicalDataCase, constructorParamName)); - canonicalDataCase.SetConstructorInputParameters("real", "imaginary"); - - var keys = canonicalDataCase.Input.Keys.ToArray(); - - foreach (var key in keys) - canonicalDataCase.Input[key] = ConvertToType(canonicalDataCase.Input[key]); - } - } - - private static string[] GetInputParameters(CanonicalDataCase canonicalDataCase, string constructorParamName) - => canonicalDataCase.Input.Keys.Where(x => x != constructorParamName).ToArray(); - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.UseVariableForExpected) - return RenderComplexNumberAssert(testMethodBody); - - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - private static string RenderComplexNumberAssert(TestMethodBody testMethodBody) - { - const string template = "Assert.Equal({{ ExpectedParameter }}.Real(), {{ TestedValue }}.Real(), precision: 15);\r\nAssert.Equal({{ ExpectedParameter }}.Imaginary(), {{ TestedValue }}.Imaginary(), precision: 15);"; - - return TemplateRenderer.RenderInline(template, testMethodBody.AssertTemplateParameters); - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet - { - typeof(Math).Namespace - }; - - private static object ConvertToType(dynamic rawValue) - { - if (IsComplexNumber(rawValue)) - return new UnescapedValue($"new ComplexNumber({ValueFormatter.Format(ConvertMathDouble(rawValue[0]))}, {ValueFormatter.Format(ConvertMathDouble(rawValue[1]))})"); - - return rawValue; - } - - private static bool IsComplexNumber(object rawValue) => rawValue is int[] || rawValue is double[] || rawValue is float[] || rawValue is JArray; - - private static object ConvertMathDouble(dynamic value) - { - switch (value.ToString()) - { - case "e": - return new UnescapedValue("Math.E"); - case "pi": - return new UnescapedValue("Math.PI"); - case "ln(2)": - return new UnescapedValue("Math.Log(2.0)"); - default: - return double.Parse(value.ToString()); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Connect.cs b/generators/Exercises/Connect.cs deleted file mode 100644 index 4176151aa0..0000000000 --- a/generators/Exercises/Connect.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class Connect : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForConstructorParameters = true; - canonicalDataCase.SetConstructorInputParameters("board"); - canonicalDataCase.Property = "result"; - canonicalDataCase.Input["board"] = ToMultiLineString(canonicalDataCase.Input["board"]); - - //convert to enum - switch (canonicalDataCase.Expected) - { - case "X": - canonicalDataCase.Expected = new UnescapedValue("ConnectWinner.Black"); - break; - case "O": - canonicalDataCase.Expected = new UnescapedValue("ConnectWinner.White"); - break; - case "": - canonicalDataCase.Expected = new UnescapedValue("ConnectWinner.None"); - break; - } - } - } - - private UnescapedValue ToMultiLineString(string[] input) - { - const string template = -@"new [] -{ - {% if input.size == 0 %}string.Empty{% else %}{% for item in {{input}} %}{% if forloop.length == 1 %}""{{item}}""{% break %}{% endif %}""{{item}}""{% if forloop.last == false %},{% else %}{{string.Empty}}{% endif %} - {% endfor %}{% endif %} -}"; - - return new UnescapedValue(TemplateRenderer.RenderInline(template, new { input })); - } - } -} diff --git a/generators/Exercises/CryptoSquare.cs b/generators/Exercises/CryptoSquare.cs deleted file mode 100644 index 5ddb54e76f..0000000000 --- a/generators/Exercises/CryptoSquare.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class CryptoSquare : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - } - } - } -} \ No newline at end of file diff --git a/generators/CustomExercise.cs b/generators/Exercises/CustomExercise.cs similarity index 65% rename from generators/CustomExercise.cs rename to generators/Exercises/CustomExercise.cs index 3eae5f16ce..e7ce08c115 100644 --- a/generators/CustomExercise.cs +++ b/generators/Exercises/CustomExercise.cs @@ -1,6 +1,6 @@ -using Generators.Output; +using Exercism.CSharp.Helpers; -namespace Generators +namespace Exercism.CSharp.Exercises { public abstract class CustomExercise : Exercise { diff --git a/generators/Exercises/CustomSet.cs b/generators/Exercises/CustomSet.cs deleted file mode 100644 index a3e3b4f89d..0000000000 --- a/generators/Exercises/CustomSet.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class CustomSet : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - - if (canonicalDataCase.Input.ContainsKey("set")) - { - if (!(canonicalDataCase.Input["set"] is int[])) - { - canonicalDataCase.Input["set"] = new UnescapedValue(""); - } - - canonicalDataCase.SetConstructorInputParameters("set"); - } - else - { - if (!(canonicalDataCase.Input["set1"] is int[])) - { - canonicalDataCase.Input["set1"] = new UnescapedValue(""); - } - - canonicalDataCase.SetConstructorInputParameters("set1"); - canonicalDataCase.Input["set2"] = ConvertCustomSet(canonicalDataCase.Input["set2"]); - - if (canonicalDataCase.Property == "equal") - { - canonicalDataCase.Property = "Equals"; - } - } - - canonicalDataCase.Expected = ConvertCustomSet(canonicalDataCase.Expected); - } - } - - private static dynamic ConvertCustomSet(dynamic value) - { - if (value is bool) - return value; - - if (value is int[] values && values.Length > 0) - { - return new UnescapedValue($"new CustomSet({ValueFormatter.Format(values)})"); - } - - return new UnescapedValue($"new CustomSet()"); - } - } -} \ No newline at end of file diff --git a/generators/DeprecatedExercise.cs b/generators/Exercises/DeprecatedExercise.cs similarity index 59% rename from generators/DeprecatedExercise.cs rename to generators/Exercises/DeprecatedExercise.cs index 680dfde465..2535769eca 100644 --- a/generators/DeprecatedExercise.cs +++ b/generators/Exercises/DeprecatedExercise.cs @@ -1,6 +1,6 @@ -namespace Generators +namespace Exercism.CSharp.Exercises { - public sealed class DeprecatedExercise : Exercise + public class DeprecatedExercise : Exercise { public DeprecatedExercise(string name) => Name = name; diff --git a/generators/Exercises/DifferenceOfSquares.cs b/generators/Exercises/DifferenceOfSquares.cs deleted file mode 100644 index 857247b6bb..0000000000 --- a/generators/Exercises/DifferenceOfSquares.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class DifferenceOfSquares : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - switch(canonicalDataCase.Property) - { - case "squareOfSum": - canonicalDataCase.Property = "CalculateSquareOfSum"; - break; - case "sumOfSquares": - canonicalDataCase.Property = "CalculateSumOfSquares"; - break; - case "differenceOfSquares": - canonicalDataCase.Property = "CalculateDifferenceOfSquares"; - break; - } - } - } -} diff --git a/generators/Exercises/Dominoes.cs b/generators/Exercises/Dominoes.cs deleted file mode 100644 index 2bc4625b67..0000000000 --- a/generators/Exercises/Dominoes.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class Dominoes : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.Input["dominoes"] = ConvertInput(canonicalDataCase.Input["dominoes"]); - } - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet() { typeof(Tuple).Namespace }; - - private UnescapedValue ConvertInput(dynamic input) - { - var dominoes = (input as JArray).Children(); - - // Manually format array of ints to array of tuples since the ValueFormatter doesn't handle Tuple[] - // Project each jtoken element to an int array, then format to a string that will create a tuple from the 2-element array (via UnescapedValues) - var tuplesStringLiteral = dominoes.Select(s => s.ToObject()).Select(s => $"Tuple.Create({s[0]}, {s[1]})"); - return new UnescapedValue($"new Tuple[] {{ {string.Join(", ", tuplesStringLiteral)} }}"); - } - } -} diff --git a/generators/Exercises/Etl.cs b/generators/Exercises/Etl.cs deleted file mode 100644 index 5e81377877..0000000000 --- a/generators/Exercises/Etl.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Generators.Input; -using Generators.Output; -using System.Collections.Generic; -using System.Linq; - -namespace Generators.Exercises -{ - public class Etl : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Input = ConvertInput(canonicalDataCase.Input); - canonicalDataCase.Expected = ConvertExpected(canonicalDataCase.Expected); - canonicalDataCase.SetInputParameters("input"); - } - } - - private static dynamic ConvertExpected(dynamic expected) - => ((Dictionary)expected).ToDictionary(kv => kv.Key, kv => int.Parse($"{kv.Value}")); - - private static IDictionary ConvertInput(IDictionary input) - => new Dictionary - { - ["input"] = input.ToDictionary(kv => int.Parse(kv.Key), kv => (string[])kv.Value) - }; - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(Dictionary).Namespace }; - } -} diff --git a/generators/Exercise.cs b/generators/Exercises/Exercise.cs similarity index 70% rename from generators/Exercise.cs rename to generators/Exercises/Exercise.cs index 1bae8f399c..5dfb2c72d6 100644 --- a/generators/Exercise.cs +++ b/generators/Exercises/Exercise.cs @@ -1,4 +1,4 @@ -namespace Generators +namespace Exercism.CSharp.Exercises { public abstract class Exercise { diff --git a/generators/ExerciseCollection.cs b/generators/Exercises/ExerciseCollection.cs similarity index 77% rename from generators/ExerciseCollection.cs rename to generators/Exercises/ExerciseCollection.cs index f464a67a9a..bfd20c2c8a 100644 --- a/generators/ExerciseCollection.cs +++ b/generators/Exercises/ExerciseCollection.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using Generators.Input; -using Generators.Output; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Input; -namespace Generators +namespace Exercism.CSharp.Exercises { public class ExerciseCollection : IEnumerable { @@ -14,14 +14,15 @@ public class ExerciseCollection : IEnumerable private readonly Dictionary _exerciseTypesByName; public ExerciseCollection(CanonicalDataFile canonicalDataFile) - { - _canonicalDataFile = canonicalDataFile; + => (_canonicalDataFile, _exerciseTypesByName) = (canonicalDataFile, GetExerciseTypesByName()); - _exerciseTypesByName = Assembly.GetEntryAssembly() + private static Dictionary GetExerciseTypesByName() + => Assembly.GetEntryAssembly() .GetTypes() .Where(IsConcreteGenerator) .ToDictionary(type => type.ToExerciseName(), StringComparer.OrdinalIgnoreCase); - } + + private static bool IsConcreteGenerator(Type type) => typeof(Exercise).IsAssignableFrom(type); public IEnumerator GetEnumerator() => GetExercises().GetEnumerator(); @@ -29,9 +30,9 @@ public ExerciseCollection(CanonicalDataFile canonicalDataFile) private IEnumerable GetExercises() { - foreach (var exercise in ConfigFile.GetExercises()) + foreach (var exercise in TrackConfigFile.GetExercises()) { - var exerciseName = exercise.Name; + var exerciseName = exercise.Slug.ToExerciseName(); if (exercise.Deprecated) yield return new DeprecatedExercise(exerciseName); else if (HasNoCanonicalData(exerciseName)) @@ -47,9 +48,7 @@ private IEnumerable GetExercises() private bool IsNotImplemented(string exerciseName) => !_exerciseTypesByName.ContainsKey(exerciseName.ToExerciseName()); - private Exercise CreateExercise(string exerciseName) + private Exercise CreateExercise(string exerciseName) => (Exercise)Activator.CreateInstance(_exerciseTypesByName[exerciseName.ToExerciseName()]); - - private static bool IsConcreteGenerator(Type type) => typeof(Exercise).IsAssignableFrom(type); } } \ No newline at end of file diff --git a/generators/Exercises/FlattenArray.cs b/generators/Exercises/FlattenArray.cs deleted file mode 100644 index 724d5677d0..0000000000 --- a/generators/Exercises/FlattenArray.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class FlattenArray : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - - var stringInput = canonicalDataCase.Input["array"].ToString(); - - // We skip reformatting of pure int arrays. - if (stringInput.Contains("System.Int32")) - continue; - - canonicalDataCase.Input["array"] = new UnescapedValue(ToProperObjArray(stringInput)); - } - } - - private string ToProperObjArray(string input) - => input - .Replace("System.Int32", "") - .Replace("]", "}") - .Replace("[", "new object[] {"); - } -} \ No newline at end of file diff --git a/generators/Exercises/FoodChain.cs b/generators/Exercises/FoodChain.cs deleted file mode 100644 index dd8bd01c4d..0000000000 --- a/generators/Exercises/FoodChain.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class FoodChain : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Expected = ConvertHelper.ToMultiLineString(canonicalDataCase.Expected); - canonicalDataCase.UseVariableForExpected = true; - - if (canonicalDataCase.Input["startVerse"] == canonicalDataCase.Input["endVerse"]) - { - canonicalDataCase.SetInputParameters("startVerse"); - } - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Forth.cs b/generators/Exercises/Forth.cs deleted file mode 100644 index 1f4d3ee64f..0000000000 --- a/generators/Exercises/Forth.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Forth : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseFullDescriptionPath = true; - - if (canonicalDataCase.Expected == null) - { - canonicalDataCase.ExceptionThrown = typeof(InvalidOperationException); - } - else - { - canonicalDataCase.Expected = string.Join(" ", canonicalDataCase.Expected); - } - } - } - } -} diff --git a/generators/Exercises/GeneratorExercise.cs b/generators/Exercises/GeneratorExercise.cs new file mode 100644 index 0000000000..79a4b1389c --- /dev/null +++ b/generators/Exercises/GeneratorExercise.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Input; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises +{ + public abstract class GeneratorExercise : Exercise + { + public override string Name => GetType().ToExerciseName(); + + protected Render Render { get; } = new Render(); + + public void Regenerate(CanonicalData canonicalData) + { + var testClass = CreateTestClass(canonicalData); + var testClassOutput = new TestClassOutput(testClass); + testClassOutput.WriteToFile(); + } + + private TestClass CreateTestClass(CanonicalData canonicalData) + { + var testMethods = CreateTestMethods(canonicalData); + var testClass = new TestClass( + exercise: canonicalData.Exercise, + version: canonicalData.Version, + className: canonicalData.Exercise.ToTestClassName(), + testMethods: testMethods + ); + UpdateTestClass(testClass); + UpdateNamespaces(testClass.Namespaces); + + return testClass; + } + + protected virtual void UpdateTestClass(TestClass testClass) + { + } + + protected virtual void UpdateNamespaces(ISet namespaces) + { + } + + private TestMethod[] CreateTestMethods(CanonicalData canonicalData) => + canonicalData.Cases + .Select(canonicalDataCase => CreateTestMethod(canonicalData, canonicalDataCase)) + .ToArray(); + + private TestMethod CreateTestMethod(CanonicalData canonicalData, CanonicalDataCase canonicalDataCase) + { + var testMethod = new TestMethod(canonicalData, canonicalDataCase); + UpdateTestMethod(testMethod); + + return testMethod; + } + + protected virtual void UpdateTestMethod(TestMethod testMethod) + { + } + } +} diff --git a/generators/Exercises/Acronym.cs b/generators/Exercises/Generators/Acronym.cs similarity index 54% rename from generators/Exercises/Acronym.cs rename to generators/Exercises/Generators/Acronym.cs index 1846d6196c..c499d3b646 100644 --- a/generators/Exercises/Acronym.cs +++ b/generators/Exercises/Generators/Acronym.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class Acronym : GeneratorExercise { diff --git a/generators/Exercises/Generators/AllYourBase.cs b/generators/Exercises/Generators/AllYourBase.cs new file mode 100644 index 0000000000..181dba13b9 --- /dev/null +++ b/generators/Exercises/Generators/AllYourBase.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class AllYourBase : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Input["digits"] is JArray) + testMethod.Input["digits"] = Array.Empty(); + + if (testMethod.Expected is Dictionary) + testMethod.ExceptionThrown = typeof(ArgumentException); + + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Allergies.cs b/generators/Exercises/Generators/Allergies.cs new file mode 100644 index 0000000000..c410f72523 --- /dev/null +++ b/generators/Exercises/Generators/Allergies.cs @@ -0,0 +1,29 @@ +using System.Text; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Allergies : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.ConstructorInputParameters = new[] { "score" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + + if (testMethod.Property == "allergicTo") + testMethod.Assert = RenderIsAllergicToAssert(testMethod); + else if (testMethod.Property == "list") + testMethod.UseVariableForExpected = true; + } + + private string RenderIsAllergicToAssert(TestMethod testMethod) + { + var assert = new StringBuilder(); + + foreach (var allergy in testMethod.Expected) + assert.AppendLine(Render.AssertBoolean(allergy["result"], $"sut.IsAllergicTo({Render.Object(allergy["substance"])})")); + + return assert.ToString(); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Alphametics.cs b/generators/Exercises/Generators/Alphametics.cs new file mode 100644 index 0000000000..431853309a --- /dev/null +++ b/generators/Exercises/Generators/Alphametics.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Alphametics : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + testMethod.UseVariableForTested = true; + + if (testMethod.Expected == null) + testMethod.ExceptionThrown = typeof(ArgumentException); + else + testMethod.Expected = ConvertExpected(testMethod); + } + + private static dynamic ConvertExpected(TestMethod testMethod) + { + Dictionary expected = testMethod.Expected; + return expected.ToDictionary(kv => kv.Key[0], kv => Convert.ToInt32(kv.Value)); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Dictionary).Namespace); + } +} +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Anagram.cs b/generators/Exercises/Generators/Anagram.cs new file mode 100644 index 0000000000..f440f935c1 --- /dev/null +++ b/generators/Exercises/Generators/Anagram.cs @@ -0,0 +1,15 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Anagram : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + testMethod.ConstructorInputParameters = new[] { "subject" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/ArmstrongNumbers.cs b/generators/Exercises/Generators/ArmstrongNumbers.cs similarity index 57% rename from generators/Exercises/ArmstrongNumbers.cs rename to generators/Exercises/Generators/ArmstrongNumbers.cs index e3235cb727..b6528565a8 100644 --- a/generators/Exercises/ArmstrongNumbers.cs +++ b/generators/Exercises/Generators/ArmstrongNumbers.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class ArmstrongNumbers : GeneratorExercise { diff --git a/generators/Exercises/AtbashCipher.cs b/generators/Exercises/Generators/AtbashCipher.cs similarity index 56% rename from generators/Exercises/AtbashCipher.cs rename to generators/Exercises/Generators/AtbashCipher.cs index a863a35ac9..6d50d69339 100644 --- a/generators/Exercises/AtbashCipher.cs +++ b/generators/Exercises/Generators/AtbashCipher.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class AtbashCipher : GeneratorExercise { diff --git a/generators/Exercises/Generators/BeerSong.cs b/generators/Exercises/Generators/BeerSong.cs new file mode 100644 index 0000000000..475e661605 --- /dev/null +++ b/generators/Exercises/Generators/BeerSong.cs @@ -0,0 +1,14 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class BeerSong : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + testMethod.Expected = new MultiLineString(testMethod.Expected); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/BinarySearch.cs b/generators/Exercises/Generators/BinarySearch.cs new file mode 100644 index 0000000000..6bc64c29e5 --- /dev/null +++ b/generators/Exercises/Generators/BinarySearch.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class BinarySearch : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Input["array"] is JArray) + testMethod.Input["array"] = Array.Empty(); + + testMethod.ConstructorInputParameters = new[] { "array" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.UseVariablesForConstructorParameters = true; + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/BinarySearchTree.cs b/generators/Exercises/Generators/BinarySearchTree.cs new file mode 100644 index 0000000000..3593a79fef --- /dev/null +++ b/generators/Exercises/Generators/BinarySearchTree.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class BinarySearchTree : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Assert = RenderAssert(testMethod); + } + + private string RenderAssert(TestMethod testMethod) + { + var assert = new StringBuilder(); + + var treeData = ConvertToIntegers(testMethod.Input["treeData"]); + var constructorParameters = Render.Object(treeData.Length == 1 ? treeData[0] : treeData); + assert.AppendLine(Render.Variable("tree", $"new BinarySearchTree({constructorParameters})")); + + if (testMethod.Expected is Dictionary) + { + foreach (var testAssert in TestAsserts(testMethod.Expected)) + assert.AppendLine(testAssert); + } + else + { + var renderedExpected = Render.Object(ConvertToIntegers(testMethod.Expected)); + assert.AppendLine(Render.AssertEqual(renderedExpected, "tree.AsEnumerable()")); + } + + return assert.ToString(); + } + + private static int[] ConvertToIntegers(dynamic data) => ((string[]) data).Select(int.Parse).ToArray(); + + private IEnumerable TestAsserts(dynamic tree, string traverse = "") + { + yield return Render.AssertEqual(tree["data"], $"tree{traverse}.Value"); + if (tree["left"] != null) foreach (var assert in TestAsserts(tree["left"], $"{traverse}.Left")) yield return assert; + if (tree["right"] != null) foreach (var assert in TestAsserts(tree["right"], $"{traverse}.Right")) yield return assert; + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(IQueryable).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Bob.cs b/generators/Exercises/Generators/Bob.cs similarity index 52% rename from generators/Exercises/Bob.cs rename to generators/Exercises/Generators/Bob.cs index b8377340d4..5d7b21b71d 100644 --- a/generators/Exercises/Bob.cs +++ b/generators/Exercises/Generators/Bob.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class Bob : GeneratorExercise { diff --git a/generators/Exercises/Generators/BookStore.cs b/generators/Exercises/Generators/BookStore.cs new file mode 100644 index 0000000000..46e65ac027 --- /dev/null +++ b/generators/Exercises/Generators/BookStore.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class BookStore : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Input["basket"] is JArray) + testMethod.Input["basket"] = Array.Empty(); + + testMethod.Expected = testMethod.Expected / 100.0f; + testMethod.InputParameters = new[] { "basket" }; + testMethod.UseVariablesForInput = true; + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Bowling.cs b/generators/Exercises/Generators/Bowling.cs new file mode 100644 index 0000000000..0df2cdc931 --- /dev/null +++ b/generators/Exercises/Generators/Bowling.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Bowling : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected is int) + testMethod.UseVariableForTested = true; + else + testMethod.ExceptionThrown = typeof(ArgumentException); + + testMethod.InputParameters = Array.Empty(); + + testMethod.Arrange = RenderArrange(testMethod); + testMethod.Act = RenderAct(testMethod); + testMethod.Assert = RenderAssert(testMethod); + } + + private string RenderArrange(TestMethod testMethod) + { + var builder = new StringBuilder(); + builder.AppendLine(Render.Variable("sut", "new BowlingGame()")); + + if (!testMethod.Input.ContainsKey("previousRolls")) + return builder.ToString(); + + var previousRolls = testMethod.Input["previousRolls"] as int[] ?? Array.Empty(); + builder.Append(Render.Variable("previousRolls", Render.ObjectMultiLine(previousRolls))); + + return builder.ToString(); + } + + private string RenderAssert(TestMethod testMethod) + { + if (testMethod.ExceptionThrown != null && testMethod.Input.ContainsKey("roll")) + { + var actual = Render.Object(testMethod.Input["roll"]); + return Render.AssertThrows(testMethod.ExceptionThrown, $"sut.Roll({actual})"); + } + + if (testMethod.ExceptionThrown == null || testMethod.Property != "score") + return testMethod.Assert; + + return Render.AssertThrows(testMethod.ExceptionThrown, "sut.Score()"); + } + + private string RenderAct(TestMethod testMethod) + { + var act = new StringBuilder(); + act.AppendLine("DoRoll(previousRolls, sut);"); + + if (testMethod.ExceptionThrown != null) + { + return act.ToString(); + } + + if (testMethod.Input.ContainsKey("roll")) + { + act.AppendLine($"sut.Roll({testMethod.Input["roll"]});"); + act.AppendLine(Render.Variable("actual", "sut.Score()")); + return act.ToString(); + } + + act.AppendLine(Render.Variable("actual", "sut.Score()")); + return act.ToString(); + } + + protected override void UpdateTestClass(TestClass testClass) + { + AddDoRollMethod(testClass); + } + + private static void AddDoRollMethod(TestClass testClass) + { + testClass.AdditionalMethods.Add(@" +public void DoRoll(IEnumerable rolls, BowlingGame sut) +{ + foreach (var roll in rolls) + { + sut.Roll(roll); + } +}"); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + namespaces.Add(typeof(ICollection<>).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/BracketPush.cs b/generators/Exercises/Generators/BracketPush.cs new file mode 100644 index 0000000000..894a9c0198 --- /dev/null +++ b/generators/Exercises/Generators/BracketPush.cs @@ -0,0 +1,13 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class BracketPush : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Input["value"] = testMethod.Input["value"].Replace("\\", "\\\\"); + testMethod.UseVariablesForInput = true; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Change.cs b/generators/Exercises/Generators/Change.cs new file mode 100644 index 0000000000..044db6a51f --- /dev/null +++ b/generators/Exercises/Generators/Change.cs @@ -0,0 +1,17 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Change : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + + if (testMethod.Expected is int) + testMethod.ExceptionThrown = typeof(ArgumentException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/CircularBuffer.cs b/generators/Exercises/Generators/CircularBuffer.cs new file mode 100644 index 0000000000..483db0d534 --- /dev/null +++ b/generators/Exercises/Generators/CircularBuffer.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class CircularBuffer : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Assert = RenderAssert(testMethod); + } + + private string RenderAssert(TestMethod testMethod) + { + var assert = new StringBuilder(); + assert.AppendLine(RenderSut(testMethod)); + + foreach (var operation in testMethod.Input["operations"]) + assert.AppendLine(RenderOperation(operation)); + + return assert.ToString(); + } + + private string RenderSut(TestMethod testMethod) + => Render.Variable("buffer", $"new CircularBuffer(capacity: {testMethod.Input["capacity"]})"); + + private string RenderOperation(dynamic operation) + { + switch (operation["operation"]) + { + case "read": + return RenderReadOperation(operation); + case "write": + return RenderWriteOperation(operation); + case "overwrite": + return RenderOverwriteOperation(operation); + case "clear": + return RenderClearOperation(); + default: + throw new ArgumentOutOfRangeException($"Unknown operation type: {operation["operation"]}"); + } + } + + private string RenderReadOperation(dynamic operation) + => operation["should_succeed"] + ? Render.AssertEqual(operation["expected"].ToString(), "buffer.Read()") + : Render.AssertThrows("buffer.Read()"); + + private string RenderWriteOperation(dynamic operation) + => operation["should_succeed"] + ? $"buffer.Write({operation["item"]});" + : Render.AssertThrows($"buffer.Write({operation["item"]})"); + + private static string RenderOverwriteOperation(dynamic operation) + => $"buffer.Overwrite({operation["item"]});"; + + private static string RenderClearOperation() + => "buffer.Clear();"; + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(InvalidOperationException).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Clock.cs b/generators/Exercises/Generators/Clock.cs new file mode 100644 index 0000000000..0b9d57bfe8 --- /dev/null +++ b/generators/Exercises/Generators/Clock.cs @@ -0,0 +1,55 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Clock : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.ConstructorInputParameters = new[] { "hour", "minute" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + + if (testMethod.Property == "create") + UpdateTestMethodForCreateProperty(testMethod); + else if (testMethod.Property == "equal") + UpdateTestMethodForEqualProperty(testMethod); + else + UpdateTestMethodForConsistencyProperty(testMethod); + } + + private static void UpdateTestMethodForCreateProperty(TestMethod testMethod) + { + testMethod.TestedMethod = "ToString"; + } + + private void UpdateTestMethodForEqualProperty(TestMethod testMethod) + { + var clock1 = testMethod.Input["clock1"]; + testMethod.Input["clock1"] = new UnescapedValue($"new Clock({clock1["hour"]}, {clock1["minute"]})"); + + var clock2 = testMethod.Input["clock2"]; + testMethod.Input["hour"] = clock2["hour"]; + testMethod.Input["minute"] = clock2["minute"]; + + testMethod.Assert = RenderEqualToAssert(testMethod); + } + + private string RenderEqualToAssert(TestMethod testMethod) + { + var expected = Render.Object(testMethod.Input["clock1"]); + + return testMethod.Expected + ? Render.AssertEqual(expected, "sut") + : Render.AssertNotEqual(expected, "sut"); + } + + private void UpdateTestMethodForConsistencyProperty(TestMethod testMethod) + { + testMethod.Assert = RenderConsistencyToAssert(testMethod); + } + + private string RenderConsistencyToAssert(TestMethod testMethod) + => Render.AssertEqual(Render.Object(testMethod.Expected), $"sut.{testMethod.TestedMethod}({testMethod.Input["value"]}).ToString()"); + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/CollatzConjecture.cs b/generators/Exercises/Generators/CollatzConjecture.cs new file mode 100644 index 0000000000..f2c4e21b3f --- /dev/null +++ b/generators/Exercises/Generators/CollatzConjecture.cs @@ -0,0 +1,14 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class CollatzConjecture : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Input["number"] <= 0) + testMethod.ExceptionThrown = typeof(ArgumentException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/ComplexNumbers.cs b/generators/Exercises/Generators/ComplexNumbers.cs new file mode 100644 index 0000000000..c839e1deed --- /dev/null +++ b/generators/Exercises/Generators/ComplexNumbers.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class ComplexNumbers : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedClass = "ComplexNumber"; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + + testMethod.UseVariableForExpected = IsComplexNumber(testMethod.Expected); + testMethod.Expected = ConvertToType(testMethod.Expected); + + var constructorParamName = testMethod.Input.ContainsKey("z") ? "z" : "z1"; + testMethod.Input["real"] = ConvertToDouble(testMethod.Input[constructorParamName][0]); + testMethod.Input["imaginary"] = ConvertToDouble(testMethod.Input[constructorParamName][1]); + + testMethod.InputParameters = GetInputParameters(testMethod, constructorParamName); + testMethod.ConstructorInputParameters = new[] {"real", "imaginary"}; + + var keys = testMethod.Input.Keys.ToArray(); + + foreach (var key in keys) + testMethod.Input[key] = ConvertToType(testMethod.Input[key]); + + testMethod.Assert = RenderAssert(testMethod); + } + + private static string[] GetInputParameters(TestMethod testMethod, string constructorParamName) + => testMethod.Input.Keys.Where(x => x != constructorParamName).ToArray(); + + private string RenderAssert(TestMethod testMethod) + => testMethod.UseVariableForExpected + ? RenderComplexNumberAssert(testMethod) + : testMethod.Assert; + + private string RenderComplexNumberAssert(TestMethod testMethod) + { + var inputParameters = testMethod.Input.ContainsKey("z") ? "" : Render.Object(testMethod.Input["z2"]); + var actual = $"sut.{testMethod.TestedMethod}({inputParameters})"; + + var assert = new StringBuilder(); + assert.AppendLine(Render.AssertEqualWithin("expected.Real()", $"{actual}.Real()", 7)); + assert.AppendLine(Render.AssertEqualWithin("expected.Imaginary()", $"{actual}.Imaginary()", 7)); + + return assert.ToString(); + } + + private object ConvertToType(dynamic rawValue) + => IsComplexNumber(rawValue) + ? RenderComplexNumber(rawValue) + : rawValue; + + private UnescapedValue RenderComplexNumber(dynamic rawValue) + => new UnescapedValue($"new ComplexNumber({Render.Object(ConvertToDouble(rawValue[0]))}, {Render.Object(ConvertToDouble(rawValue[1]))})"); + + private static bool IsComplexNumber(object rawValue) => rawValue is int[] || rawValue is double[] || rawValue is float[] || rawValue is JArray; + + private static object ConvertToDouble(dynamic value) + { + switch (value.ToString()) + { + case "e": + return new UnescapedValue("Math.E"); + case "pi": + return new UnescapedValue("Math.PI"); + case "ln(2)": + return new UnescapedValue("Math.Log(2.0)"); + default: + return double.Parse(value.ToString()); + } + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Math).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Connect.cs b/generators/Exercises/Generators/Connect.cs new file mode 100644 index 0000000000..4c353ed8c6 --- /dev/null +++ b/generators/Exercises/Generators/Connect.cs @@ -0,0 +1,35 @@ +using DotLiquid.Exceptions; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Connect : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForConstructorParameters = true; + testMethod.ConstructorInputParameters = new[] { "board" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.TestedMethod = "Result"; + + testMethod.Input["board"] = new UnescapedValue(Render.ArrayMultiLine(testMethod.Input["board"])); + testMethod.Expected = ConvertExpected(testMethod); + } + + private UnescapedValue ConvertExpected(TestMethod testMethod) + { + switch (testMethod.Expected) + { + case "X": + return Render.Enum("ConnectWinner", "Black"); + case "O": + return Render.Enum("ConnectWinner", "White"); + case "": + return Render.Enum("ConnectWinner", "None"); + default: + throw new ArgumentException("Unsupported expected value"); + } + } + } +} diff --git a/generators/Exercises/Generators/CryptoSquare.cs b/generators/Exercises/Generators/CryptoSquare.cs new file mode 100644 index 0000000000..f6ccc3fcea --- /dev/null +++ b/generators/Exercises/Generators/CryptoSquare.cs @@ -0,0 +1,13 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class CryptoSquare : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/CustomSet.cs b/generators/Exercises/Generators/CustomSet.cs new file mode 100644 index 0000000000..38140173b6 --- /dev/null +++ b/generators/Exercises/Generators/CustomSet.cs @@ -0,0 +1,60 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class CustomSet : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.Expected = ConvertToCustomSet(testMethod.Expected); + + if (testMethod.Input.ContainsKey("set")) + UpdateTestMethodForSingleSetProperty(testMethod); + else + UpdateTestMethodForMultipleSetsProperty(testMethod); + } + + private static void UpdateTestMethodForSingleSetProperty(TestMethod testMethod) + { + if (testMethod.Input["set"] is JArray) + { + testMethod.Input["set"] = new UnescapedValue(""); + } + + testMethod.ConstructorInputParameters = new[] {"set"}; + } + + private void UpdateTestMethodForMultipleSetsProperty(TestMethod testMethod) + { + if (testMethod.Input["set1"] is JArray) + { + testMethod.Input["set1"] = new UnescapedValue(""); + } + + testMethod.ConstructorInputParameters = new[] {"set1"}; + testMethod.Input["set2"] = ConvertToCustomSet(testMethod.Input["set2"]); + + if (testMethod.Property == "equal") + { + testMethod.TestedMethod = "Equals"; + } + } + + private dynamic ConvertToCustomSet(dynamic value) + { + switch (value) + { + case bool _: + return value; + case int[] values when values.Length > 0: + return new UnescapedValue($"new CustomSet({Render.Object(values)})"); + default: + return new UnescapedValue("new CustomSet()"); + } + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Diamond.cs b/generators/Exercises/Generators/Diamond.cs similarity index 82% rename from generators/Exercises/Diamond.cs rename to generators/Exercises/Generators/Diamond.cs index 9bb2fea8e5..787196d117 100644 --- a/generators/Exercises/Diamond.cs +++ b/generators/Exercises/Generators/Diamond.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { // This class derives from CustomExercise instead of GeneratorExercise // as it has custom (property-based) tests that cannot be generated from diff --git a/generators/Exercises/Generators/DifferenceOfSquares.cs b/generators/Exercises/Generators/DifferenceOfSquares.cs new file mode 100644 index 0000000000..329a79f65f --- /dev/null +++ b/generators/Exercises/Generators/DifferenceOfSquares.cs @@ -0,0 +1,12 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class DifferenceOfSquares : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = $"Calculate{testMethod.TestedMethod}"; + } + } +} diff --git a/generators/Exercises/Generators/Dominoes.cs b/generators/Exercises/Generators/Dominoes.cs new file mode 100644 index 0000000000..3ec57b950e --- /dev/null +++ b/generators/Exercises/Generators/Dominoes.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Dominoes : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.Input["dominoes"] = ConvertDominoes(testMethod.Input["dominoes"]); + } + + private static ValueTuple[] ConvertDominoes(JToken input) + => input.ToObject().Select(x => (x[0], x[1])).ToArray(); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(ValueTuple).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/Etl.cs b/generators/Exercises/Generators/Etl.cs new file mode 100644 index 0000000000..a47abab7a0 --- /dev/null +++ b/generators/Exercises/Generators/Etl.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Etl : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + + var input = ConvertInput(testMethod.Input); + testMethod.Input.Clear(); + testMethod.Input["input"] = input; + testMethod.Expected = ConvertExpected(testMethod.Expected); + testMethod.InputParameters = new[] { "input" }; + } + + private static dynamic ConvertExpected(dynamic expected) + => ((Dictionary)expected).ToDictionary(kv => kv.Key, kv => Convert.ToInt32(kv.Value)); + + private static IDictionary ConvertInput(IDictionary input) + => input.ToDictionary(kv => Convert.ToInt32(kv.Key), kv => (string[]) kv.Value); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Dictionary).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/FlattenArray.cs b/generators/Exercises/Generators/FlattenArray.cs new file mode 100644 index 0000000000..3a9cf04f25 --- /dev/null +++ b/generators/Exercises/Generators/FlattenArray.cs @@ -0,0 +1,33 @@ +using System.Linq; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class FlattenArray : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + + var renderedArray = Render.ArrayMultiLine(ConvertToObjectArray(testMethod.Input["array"])); + testMethod.Input["array"] = new UnescapedValue(renderedArray.Replace("new[]", "new object[]")); + } + + private static dynamic ConvertToObjectArray(dynamic input) + { + if (input is int[] ints) + return ints; + + if (input is JArray jArray) + return jArray.Cast().Select(ConvertToObjectArray).ToArray(); + + if (input is JToken jToken && jToken.Type == JTokenType.Null) + return null; + + return input; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/FoodChain.cs b/generators/Exercises/Generators/FoodChain.cs new file mode 100644 index 0000000000..511e74136a --- /dev/null +++ b/generators/Exercises/Generators/FoodChain.cs @@ -0,0 +1,19 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class FoodChain : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Expected = new MultiLineString(testMethod.Expected); + testMethod.UseVariableForExpected = true; + + if (testMethod.Input["startVerse"] == testMethod.Input["endVerse"]) + { + testMethod.InputParameters = new[] { "startVerse" }; + } + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Forth.cs b/generators/Exercises/Generators/Forth.cs new file mode 100644 index 0000000000..d1994c0b39 --- /dev/null +++ b/generators/Exercises/Generators/Forth.cs @@ -0,0 +1,22 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Forth : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + + if (testMethod.Expected == null) + { + testMethod.ExceptionThrown = typeof(InvalidOperationException); + } + else + { + testMethod.Expected = string.Join(" ", testMethod.Expected); + } + } + } +} diff --git a/generators/Exercises/Generators/Gigasecond.cs b/generators/Exercises/Generators/Gigasecond.cs new file mode 100644 index 0000000000..89b931197b --- /dev/null +++ b/generators/Exercises/Generators/Gigasecond.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Gigasecond : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Input["birthdate"] = DateTime.Parse(testMethod.Input["birthdate"].ToString()); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(DateTime).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/GoCounting.cs b/generators/Exercises/Generators/GoCounting.cs new file mode 100644 index 0000000000..b02796de35 --- /dev/null +++ b/generators/Exercises/Generators/GoCounting.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class GoCounting : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + testMethod.UseVariablesForConstructorParameters = true; + testMethod.UseVariableForTested = true; + + testMethod.Input["board"] = new MultiLineString(testMethod.Input["board"]); + testMethod.ConstructorInputParameters = new[] { "board" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + + if (testMethod.Property == "territory") + UpdateTestMethodForTerritoryProperty(testMethod); + else + UpdateTestMethodForTerritoriesProperty(testMethod); + } + + private void UpdateTestMethodForTerritoryProperty(TestMethod testMethod) + { + testMethod.Input["coordinate"] = (testMethod.Input["x"], testMethod.Input["y"]); + testMethod.InputParameters = new[] {"coordinate"}; + + if (testMethod.Expected.ContainsKey("error")) + { + testMethod.ExceptionThrown = typeof(ArgumentException); + } + else + { + var owner = RenderOwner(testMethod.Expected["owner"]); + var territory = RenderTerritory(testMethod.Expected["territory"]); + testMethod.Expected = (owner, territory); + testMethod.Assert = RenderTerritoryAssert(); + } + } + + private void UpdateTestMethodForTerritoriesProperty(TestMethod testMethod) + { + var expected = new[] + { + "new Dictionary", + "{", + $" [Owner.Black] = {RenderTerritory(testMethod.Expected["territoryBlack"])},", + $" [Owner.White] = {RenderTerritory(testMethod.Expected["territoryWhite"])},", + $" [Owner.None] = {RenderTerritory(testMethod.Expected["territoryNone"])}", + "}" + }; + + testMethod.Expected = new UnescapedValue(string.Join(Environment.NewLine, expected)); + testMethod.Assert = RenderTerritoriesAssert(); + } + + private string RenderTerritoryAssert() + { + var assert = new StringBuilder(); + assert.AppendLine(Render.AssertEqual("expected.Item1", "actual.Item1")); + assert.AppendLine(Render.AssertEqual("expected.Item2", "actual.Item2")); + return assert.ToString(); + } + + private string RenderTerritoriesAssert() + { + var territoriesAssert = new StringBuilder(); + territoriesAssert.AppendLine(Render.AssertEqual("expected.Keys", "actual.Keys")); + territoriesAssert.AppendLine(Render.AssertEqual("expected[Owner.Black]", "actual[Owner.Black]")); + territoriesAssert.AppendLine(Render.AssertEqual("expected[Owner.White]", "actual[Owner.White]")); + territoriesAssert.AppendLine(Render.AssertEqual("expected[Owner.None]", "actual[Owner.None]")); + return territoriesAssert.ToString(); + } + + private UnescapedValue RenderOwner(dynamic owner) => Render.Enum("Owner", owner); + + private string RenderTerritory(dynamic territory) + => Render.Object(((JArray)territory).Select(coordinate => (coordinate[0].ToObject(), coordinate[1].ToObject())).ToArray()); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Dictionary).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Grains.cs b/generators/Exercises/Generators/Grains.cs new file mode 100644 index 0000000000..4477a12d8b --- /dev/null +++ b/generators/Exercises/Generators/Grains.cs @@ -0,0 +1,16 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Grains : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected is int i && i == -1) + testMethod.ExceptionThrown = typeof(ArgumentOutOfRangeException); + else + testMethod.Expected = (ulong)testMethod.Expected; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Grep.cs b/generators/Exercises/Generators/Grep.cs new file mode 100644 index 0000000000..e443aa06a3 --- /dev/null +++ b/generators/Exercises/Generators/Grep.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Grep : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "Match"; + testMethod.Input["flags"] = ConvertFlags(testMethod); + testMethod.Expected = ConvertExpected(testMethod.Expected); + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + } + + private static dynamic ConvertFlags(TestMethod testMethod) + => string.Join(" ", testMethod.Input["flags"]); + + private static MultiLineString ConvertExpected(dynamic expected) + => new MultiLineString(expected as string[] ?? Array.Empty()); + + protected override void UpdateTestClass(TestClass testClass) + { + testClass.IsDisposable = true; + + AddAdditionalMethods(testClass); + } + + private static void AddAdditionalMethods(TestClass testClass) + { + AddIliadData(testClass); + AddMidsummerNightData(testClass); + AddParadiseLostData(testClass); + AddConstructor(testClass); + AddDisposeMethod(testClass); + } + + private static void AddIliadData(TestClass testClass) + { + testClass.AdditionalMethods.Add(@" +private const string IliadFileName = ""iliad.txt""; +private const string IliadContents = + ""Achilles sing, O Goddess! Peleus' son;\n"" + + ""His wrath pernicious, who ten thousand woes\n"" + + ""Caused to Achaia's host, sent many a soul\n"" + + ""Illustrious into Ades premature,\n"" + + ""And Heroes gave (so stood the will of Jove)\n"" + + ""To dogs and to all ravening fowls a prey,\n"" + + ""When fierce dispute had separated once\n"" + + ""The noble Chief Achilles from the son\n"" + + ""Of Atreus, Agamemnon, King of men.\n"";"); + } + + private static void AddMidsummerNightData(TestClass testClass) + { + testClass.AdditionalMethods.Add(@" +private const string MidsummerNightFileName = ""midsummer-night.txt""; +private const string MidsummerNightContents = + ""I do entreat your grace to pardon me.\n"" + + ""I know not by what power I am made bold,\n"" + + ""Nor how it may concern my modesty,\n"" + + ""In such a presence here to plead my thoughts;\n"" + + ""But I beseech your grace that I may know\n"" + + ""The worst that may befall me in this case,\n"" + + ""If I refuse to wed Demetrius.\n"";"); + } + + private static void AddParadiseLostData(TestClass testClass) + { + testClass.AdditionalMethods.Add(@" +private const string ParadiseLostFileName = ""paradise-lost.txt""; +private const string ParadiseLostContents = + ""Of Mans First Disobedience, and the Fruit\n"" + + ""Of that Forbidden Tree, whose mortal tast\n"" + + ""Brought Death into the World, and all our woe,\n"" + + ""With loss of Eden, till one greater Man\n"" + + ""Restore us, and regain the blissful Seat,\n"" + + ""Sing Heav'nly Muse, that on the secret top\n"" + + ""Of Oreb, or of Sinai, didst inspire\n"" + + ""That Shepherd, who first taught the chosen Seed\n"";"); + } + + private static void AddConstructor(TestClass testClass) + { + testClass.AdditionalMethods.Add(@" +public GrepTest() +{ + Directory.SetCurrentDirectory(Path.GetTempPath()); + File.WriteAllText(IliadFileName, IliadContents); + File.WriteAllText(MidsummerNightFileName, MidsummerNightContents); + File.WriteAllText(ParadiseLostFileName, ParadiseLostContents); +}"); + } + + private static void AddDisposeMethod(TestClass testClass) + { + testClass.AdditionalMethods.Add(@" +public void Dispose() +{ + Directory.SetCurrentDirectory(Path.GetTempPath()); + File.Delete(IliadFileName); + File.Delete(MidsummerNightFileName); + File.Delete(ParadiseLostFileName); +}"); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(IDisposable).Namespace); + namespaces.Add(typeof(File).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/Hamming.cs b/generators/Exercises/Generators/Hamming.cs new file mode 100644 index 0000000000..8bae530c29 --- /dev/null +++ b/generators/Exercises/Generators/Hamming.cs @@ -0,0 +1,14 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Hamming : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (!(testMethod.Expected is int)) + testMethod.ExceptionThrown = typeof(ArgumentException); + } + } +} diff --git a/generators/Exercises/HelloWorld.cs b/generators/Exercises/Generators/HelloWorld.cs similarity index 57% rename from generators/Exercises/HelloWorld.cs rename to generators/Exercises/Generators/HelloWorld.cs index c9d2389994..1ff6c0962e 100644 --- a/generators/Exercises/HelloWorld.cs +++ b/generators/Exercises/Generators/HelloWorld.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class HelloWorld : GeneratorExercise { diff --git a/generators/Exercises/Generators/House.cs b/generators/Exercises/Generators/House.cs new file mode 100644 index 0000000000..f3421a932b --- /dev/null +++ b/generators/Exercises/Generators/House.cs @@ -0,0 +1,19 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class House : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + testMethod.Expected = new MultiLineString(testMethod.Expected); + + if (testMethod.Input["startVerse"] == testMethod.Input["endVerse"]) + { + testMethod.InputParameters = new[] { "startVerse" }; + } + } + } +} \ No newline at end of file diff --git a/generators/Exercises/IsbnVerifier.cs b/generators/Exercises/Generators/IsbnVerifier.cs similarity index 56% rename from generators/Exercises/IsbnVerifier.cs rename to generators/Exercises/Generators/IsbnVerifier.cs index 64449be9a4..28574ad5fa 100644 --- a/generators/Exercises/IsbnVerifier.cs +++ b/generators/Exercises/Generators/IsbnVerifier.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class IsbnVerifier : GeneratorExercise { diff --git a/generators/Exercises/Isogram.cs b/generators/Exercises/Generators/Isogram.cs similarity index 56% rename from generators/Exercises/Isogram.cs rename to generators/Exercises/Generators/Isogram.cs index c775f93cf5..451708229c 100644 --- a/generators/Exercises/Isogram.cs +++ b/generators/Exercises/Generators/Isogram.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class Isogram : GeneratorExercise { diff --git a/generators/Exercises/Generators/KindergartenGarden.cs b/generators/Exercises/Generators/KindergartenGarden.cs new file mode 100644 index 0000000000..0207ac9ce6 --- /dev/null +++ b/generators/Exercises/Generators/KindergartenGarden.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class KindergartenGarden : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + + if (testMethod.Input.ContainsKey("students")) + testMethod.ConstructorInputParameters = new[] { "diagram", "students" }; + else + testMethod.ConstructorInputParameters = new[] { "diagram" }; + + testMethod.Expected = ConvertExpected(testMethod.Expected); + } + + private UnescapedValue[] ConvertExpected(IEnumerable plants) + => plants + .Select(plant => Render.Enum("Plant", plant)) + .ToArray(); + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/LargestSeriesProduct.cs b/generators/Exercises/Generators/LargestSeriesProduct.cs new file mode 100644 index 0000000000..3334f0bcf6 --- /dev/null +++ b/generators/Exercises/Generators/LargestSeriesProduct.cs @@ -0,0 +1,16 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class LargestSeriesProduct : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "GetLargestProduct"; + + if (testMethod.Expected == -1) + testMethod.ExceptionThrown = typeof(ArgumentException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Leap.cs b/generators/Exercises/Generators/Leap.cs new file mode 100644 index 0000000000..bd54a614c2 --- /dev/null +++ b/generators/Exercises/Generators/Leap.cs @@ -0,0 +1,12 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Leap : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "IsLeapYear"; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/ListOps.cs b/generators/Exercises/Generators/ListOps.cs new file mode 100644 index 0000000000..569034e17b --- /dev/null +++ b/generators/Exercises/Generators/ListOps.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class ListOps : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = !(testMethod.Expected is int); + + if (testMethod.Input.TryGetValue("list", out var list)) + testMethod.Input["list"] = ConvertToList(list); + + if (testMethod.Input.TryGetValue("list1", out var list1)) + testMethod.Input["list1"] = ConvertToList(list1); + + if (testMethod.Input.TryGetValue("list2", out var list2)) + testMethod.Input["list2"] = ConvertToList(list2); + + if (testMethod.Input.TryGetValue("lists", out var lists)) + testMethod.Input["lists"] = ConvertToNestedList(lists); + + if (testMethod.Input.TryGetValue("function", out var function)) + testMethod.Input["function"] = ConvertToFunction(testMethod.Property, function); + + if (testMethod.Expected is IEnumerable) + { + testMethod.Expected = ConvertToList(testMethod.Expected); + } + } + + private static UnescapedValue ConvertToFunction(string property, dynamic function) + { + var signature = + property == "filter" ? "" : + property == "map" ? "" : + ""; + + var body = function + .Replace("modulo", "%") + .Replace("->", "=>"); + + return new UnescapedValue($"new Func{signature}({body})"); + } + + private static dynamic ConvertToList(dynamic value) + { + if (IsArrayOfIntegers(value)) + return new List(value); + + if (IsListOfIntegers(value)) + return value.ToObject>(); + + if (IsListOfListOfIntegers(value)) + return value.ToObject>>(); + + if (IsListOfListOfListOfIntegers(value)) + return value.ToObject>>>(); + + throw new ArgumentException("Unsupported list type"); + } + + private static dynamic ConvertToNestedList(dynamic value) + => IsEmptyList(value) + ? new List>() + : ConvertToList(value); + + private static bool IsArrayOfIntegers(dynamic value) + => value is int []; + + private static bool IsListOfIntegers(dynamic value) + => value is JArray jArray && jArray.All(child => child.Type == JTokenType.Integer); + + private static bool IsListOfListOfIntegers(dynamic value) + => value is JArray jArray && jArray.All(IsListOfIntegers); + + private static bool IsListOfListOfListOfIntegers(dynamic value) + => value is JArray jArray && jArray.All(IsListOfListOfIntegers); + + private static bool IsEmptyList(dynamic value) + => value is JArray jArray && jArray.Count == 0; + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Func).Namespace); + namespaces.Add(typeof(List).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Luhn.cs b/generators/Exercises/Generators/Luhn.cs new file mode 100644 index 0000000000..4f2d19e1d9 --- /dev/null +++ b/generators/Exercises/Generators/Luhn.cs @@ -0,0 +1,12 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Luhn : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "IsValid"; + } + } +} diff --git a/generators/Exercises/Generators/Markdown.cs b/generators/Exercises/Generators/Markdown.cs new file mode 100644 index 0000000000..2ccda69322 --- /dev/null +++ b/generators/Exercises/Generators/Markdown.cs @@ -0,0 +1,16 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Markdown : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + testMethod.Input["markdown"] = new MultiLineString(testMethod.Input["markdown"]); + testMethod.Skip = false; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Matrix.cs b/generators/Exercises/Generators/Matrix.cs new file mode 100644 index 0000000000..9f18faba59 --- /dev/null +++ b/generators/Exercises/Generators/Matrix.cs @@ -0,0 +1,13 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Matrix : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.ConstructorInputParameters = new[] { "string" }; + } + } +} diff --git a/generators/Exercises/Generators/Meetup.cs b/generators/Exercises/Generators/Meetup.cs new file mode 100644 index 0000000000..d8f7fff918 --- /dev/null +++ b/generators/Exercises/Generators/Meetup.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Meetup : GeneratorExercise + { + private const string ParamYear = "year"; + private const string ParamMonth = "month"; + private const string ParamWeek = "week"; + private const string ParamDayOfWeek = "dayofweek"; + + private const string PropertyDay = "Day"; + + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = PropertyDay; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.UseVariableForExpected = true; + testMethod.ConstructorInputParameters = new[] { ParamMonth, ParamYear }; + testMethod.InputParameters = new[] { ParamDayOfWeek, ParamWeek }; + + testMethod.Input[ParamYear] = testMethod.Input[ParamYear]; + testMethod.Input[ParamMonth] = testMethod.Input[ParamMonth]; + testMethod.Input[ParamWeek] = Render.Enum("Schedule", testMethod.Input[ParamWeek]); + testMethod.Input[ParamDayOfWeek] = Render.Enum("DayOfWeek", testMethod.Input[ParamDayOfWeek]); + + testMethod.Expected = DateTime.Parse(testMethod.Expected); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(DayOfWeek).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/Minesweeper.cs b/generators/Exercises/Generators/Minesweeper.cs new file mode 100644 index 0000000000..d02f96c17d --- /dev/null +++ b/generators/Exercises/Generators/Minesweeper.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Minesweeper : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + + testMethod.Input["minefield"] = RenderAsMultilineArray(testMethod.Input["minefield"]); + testMethod.Expected = RenderAsMultilineArray(testMethod.Expected); + } + + private UnescapedValue RenderAsMultilineArray(dynamic value) + => new UnescapedValue(Render.ArrayMultiLine(value as string[] ?? Array.Empty())); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/NthPrime.cs b/generators/Exercises/Generators/NthPrime.cs new file mode 100644 index 0000000000..e3c68d17ed --- /dev/null +++ b/generators/Exercises/Generators/NthPrime.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class NthPrime : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected is Dictionary) + testMethod.ExceptionThrown = typeof(ArgumentOutOfRangeException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/NucleotideCount.cs b/generators/Exercises/Generators/NucleotideCount.cs new file mode 100644 index 0000000000..d7966717ea --- /dev/null +++ b/generators/Exercises/Generators/NucleotideCount.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class NucleotideCount : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected.ContainsKey("error")) + { + testMethod.ExceptionThrown = typeof(ArgumentException); + testMethod.TestedMethodType = TestedMethodType.Constructor; + } + else + { + testMethod.Expected = ConvertExpected(testMethod.Expected); + testMethod.TestedMethodType = TestedMethodType.Property; + } + + testMethod.UseVariableForExpected = true; + testMethod.ConstructorInputParameters = new[] { "strand" }; + } + + private static dynamic ConvertExpected(dynamic expected) + => ((Dictionary)expected).ToDictionary(kv => kv.Key[0], kv => Convert.ToInt32(kv.Value)); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(ArgumentException).Namespace); + namespaces.Add(typeof(Dictionary).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/OcrNumbers.cs b/generators/Exercises/Generators/OcrNumbers.cs new file mode 100644 index 0000000000..05f6940a37 --- /dev/null +++ b/generators/Exercises/Generators/OcrNumbers.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class OcrNumbers : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected is int i && i <= 0) + testMethod.ExceptionThrown = typeof(ArgumentException); + + testMethod.Input["rows"] = new MultiLineString(testMethod.Input["rows"]); + testMethod.Expected = testMethod.Expected.ToString(); + testMethod.UseVariableForTested = true; + testMethod.UseVariablesForInput = true; + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/PalindromeProducts.cs b/generators/Exercises/Generators/PalindromeProducts.cs new file mode 100644 index 0000000000..93bfbc810c --- /dev/null +++ b/generators/Exercises/Generators/PalindromeProducts.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Text; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class PalindromeProducts : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected.ContainsKey("error")) + { + testMethod.ExceptionThrown = typeof(ArgumentException); + } + else + { + testMethod.UseVariableForTested = true; + testMethod.UseVariableForExpected = true; + testMethod.Expected = (testMethod.Expected["value"], RenderCoordinates(testMethod.Expected["factors"])); + testMethod.Assert = RenderAssert(); + } + } + + private string RenderAssert() + { + var assert = new StringBuilder(); + assert.AppendLine(Render.AssertEqual("expected.Item1", "actual.Item1")); + assert.AppendLine(Render.AssertEqual("expected.Item2", "actual.Item2")); + return assert.ToString(); + } + + private string RenderCoordinates(JArray coordinates) + => Render.Object(coordinates + .Select(RenderCoordinate) + .ToArray()); + + private static (int, int) RenderCoordinate(JToken coordinate) + => (coordinate[0].ToObject(), coordinate[1].ToObject()); + } +} \ No newline at end of file diff --git a/generators/Exercises/Pangram.cs b/generators/Exercises/Generators/Pangram.cs similarity index 54% rename from generators/Exercises/Pangram.cs rename to generators/Exercises/Generators/Pangram.cs index 032e8c741e..72811a1ea6 100644 --- a/generators/Exercises/Pangram.cs +++ b/generators/Exercises/Generators/Pangram.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class Pangram : GeneratorExercise { diff --git a/generators/Exercises/Generators/PascalsTriangle.cs b/generators/Exercises/Generators/PascalsTriangle.cs new file mode 100644 index 0000000000..b178a509a3 --- /dev/null +++ b/generators/Exercises/Generators/PascalsTriangle.cs @@ -0,0 +1,20 @@ +using System; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class PascalsTriangle : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + testMethod.TestedMethod = "Calculate"; + + if (testMethod.Expected is JArray jArray) + testMethod.Expected = jArray.ToObject(); + else + testMethod.ExceptionThrown = typeof(ArgumentOutOfRangeException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/PerfectNumbers.cs b/generators/Exercises/Generators/PerfectNumbers.cs new file mode 100644 index 0000000000..69faa4d08d --- /dev/null +++ b/generators/Exercises/Generators/PerfectNumbers.cs @@ -0,0 +1,16 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class PerfectNumbers : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected is string) + testMethod.Expected = Render.Enum("Classification", testMethod.Expected); + else + testMethod.ExceptionThrown = typeof(ArgumentOutOfRangeException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/PhoneNumber.cs b/generators/Exercises/Generators/PhoneNumber.cs new file mode 100644 index 0000000000..2db4a12112 --- /dev/null +++ b/generators/Exercises/Generators/PhoneNumber.cs @@ -0,0 +1,16 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class PhoneNumber : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + + if (testMethod.Expected is null) + testMethod.ExceptionThrown = typeof(ArgumentException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/PigLatin.cs b/generators/Exercises/Generators/PigLatin.cs similarity index 54% rename from generators/Exercises/PigLatin.cs rename to generators/Exercises/Generators/PigLatin.cs index 1dcfacb4fc..7bb47b3043 100644 --- a/generators/Exercises/PigLatin.cs +++ b/generators/Exercises/Generators/PigLatin.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class PigLatin : GeneratorExercise { diff --git a/generators/Exercises/Generators/Poker.cs b/generators/Exercises/Generators/Poker.cs new file mode 100644 index 0000000000..e37889f90d --- /dev/null +++ b/generators/Exercises/Generators/Poker.cs @@ -0,0 +1,14 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Poker : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + testMethod.UseVariableForTested = true; + } + } +} diff --git a/generators/Exercises/Generators/Pov.cs b/generators/Exercises/Generators/Pov.cs new file mode 100644 index 0000000000..8c4660202d --- /dev/null +++ b/generators/Exercises/Generators/Pov.cs @@ -0,0 +1,44 @@ +using System; +using System.Linq; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Pov : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + + if (testMethod.Expected is null) + testMethod.ExceptionThrown = typeof(ArgumentException); + + testMethod.Input["tree"] = RenderTree(testMethod.Input["tree"]); + + if (testMethod.Property == "fromPov") + { + testMethod.Expected = RenderTree(testMethod.Expected); + } + } + + private UnescapedValue RenderTree(dynamic tree) + { + if (tree == null) + { + return null; + } + + var label = Render.Object(tree["label"]); + + if (tree.ContainsKey("children")) + { + var children = string.Join(", ", ((object[])tree["children"]).Select(RenderTree)); + return new UnescapedValue($"new Tree({label}, {children})"); + } + + return new UnescapedValue($"new Tree({label})"); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/PrimeFactors.cs b/generators/Exercises/Generators/PrimeFactors.cs similarity index 56% rename from generators/Exercises/PrimeFactors.cs rename to generators/Exercises/Generators/PrimeFactors.cs index d16a8e744a..9bf490d197 100644 --- a/generators/Exercises/PrimeFactors.cs +++ b/generators/Exercises/Generators/PrimeFactors.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class PrimeFactors : GeneratorExercise { diff --git a/generators/Exercises/ProteinTranslation.cs b/generators/Exercises/Generators/ProteinTranslation.cs similarity index 54% rename from generators/Exercises/ProteinTranslation.cs rename to generators/Exercises/Generators/ProteinTranslation.cs index 987d12bc81..05bbe01925 100644 --- a/generators/Exercises/ProteinTranslation.cs +++ b/generators/Exercises/Generators/ProteinTranslation.cs @@ -1,6 +1,4 @@ -using Generators.Input; - -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class ProteinTranslation : GeneratorExercise { diff --git a/generators/Exercises/Generators/Proverb.cs b/generators/Exercises/Generators/Proverb.cs new file mode 100644 index 0000000000..c4b6fd337e --- /dev/null +++ b/generators/Exercises/Generators/Proverb.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Proverb : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + + testMethod.Input["strings"] = RenderAsMultilineArray(testMethod.Input["strings"]); + testMethod.Expected = RenderAsMultilineArray(testMethod.Expected); + } + + private UnescapedValue RenderAsMultilineArray(dynamic value) + => new UnescapedValue(Render.ArrayMultiLine(value as string[] ?? Array.Empty())); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/QueenAttack.cs b/generators/Exercises/Generators/QueenAttack.cs new file mode 100644 index 0000000000..0be80fe7fd --- /dev/null +++ b/generators/Exercises/Generators/QueenAttack.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class QueenAttack : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Property == "create") + UpdateTestMethodForCreateProperty(testMethod); + else if (testMethod.Property == "canAttack") + UpdateTestMethodForCanAttackProperty(testMethod); + } + + private static void UpdateTestMethodForCreateProperty(TestMethod testMethod) + { + if (testMethod.Expected < 0) + { + testMethod.ExceptionThrown = typeof(ArgumentOutOfRangeException); + } + else + { + testMethod.UseVariableForTested = true; + testMethod.Assert = string.Empty; + } + + var coordinates = GetCoordinatesFromPosition(testMethod.Input["queen"]); + testMethod.Input["X"] = coordinates.Item1; + testMethod.Input["Y"] = coordinates.Item2; + + testMethod.InputParameters = new[] {"X", "Y"}; + } + + private static void UpdateTestMethodForCanAttackProperty(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.Input["white_queen"] = RenderQueen(testMethod.Input["white_queen"]); + testMethod.Input["black_queen"] = RenderQueen(testMethod.Input["black_queen"]); + } + + private static UnescapedValue RenderQueen(dynamic input) + { + var (x, y) = GetCoordinatesFromPosition((IDictionary)input); + return new UnescapedValue($"QueenAttack.Create({x},{y})"); + } + + private static (int, int) GetCoordinatesFromPosition(IDictionary expected) + { + var coordinates = expected["position"]; + var positionX = (int)coordinates["row"]; + var positionY = (int)coordinates["column"]; + + return (positionX, positionY); + } + } +} diff --git a/generators/Exercises/Generators/RailFenceCipher.cs b/generators/Exercises/Generators/RailFenceCipher.cs new file mode 100644 index 0000000000..f875148e7b --- /dev/null +++ b/generators/Exercises/Generators/RailFenceCipher.cs @@ -0,0 +1,15 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class RailFenceCipher : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + testMethod.ConstructorInputParameters = new[] { "rails" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Raindrops.cs b/generators/Exercises/Generators/Raindrops.cs similarity index 55% rename from generators/Exercises/Raindrops.cs rename to generators/Exercises/Generators/Raindrops.cs index f2eb064e5d..21d7f356b7 100644 --- a/generators/Exercises/Raindrops.cs +++ b/generators/Exercises/Generators/Raindrops.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class Raindrops : GeneratorExercise { diff --git a/generators/Exercises/Generators/RationalNumbers.cs b/generators/Exercises/Generators/RationalNumbers.cs new file mode 100644 index 0000000000..f775e8f78f --- /dev/null +++ b/generators/Exercises/Generators/RationalNumbers.cs @@ -0,0 +1,44 @@ +using System; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class RationalNumbers : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Assert = RenderAssert(testMethod); + } + + private string RenderAssert(TestMethod testMethod) + { + switch (testMethod.Property) + { + case "add": + case "sub": + case "mul": + case "div": + const string operationsWithOverloading = "add|+|sub|-|mul|*|div|/"; + var operationCode = operationsWithOverloading.Substring(operationsWithOverloading.IndexOf(testMethod.Property, StringComparison.OrdinalIgnoreCase) + 4, 1); + return Render.AssertEqual(RenderRationalNumber(testMethod.Expected), $"{RenderRationalNumber(testMethod.Input["r1"])} {operationCode} ({RenderRationalNumber(testMethod.Input["r2"])})"); + case "abs": + case "reduce": + return Render.AssertEqual(RenderRationalNumber(testMethod.Expected), $"{RenderRationalNumber(testMethod.Input["r"])}.{testMethod.TestedMethod}()"); + case "exprational": + return Render.AssertEqual(RenderRationalNumber(testMethod.Expected), $"{RenderRationalNumber(testMethod.Input["r"])}.{testMethod.TestedMethod}({testMethod.Input["n"]})"); + case "expreal": + return Render.AssertEqualWithin(Render.Object(testMethod.Expected), $"{testMethod.Input["x"]}.{testMethod.TestedMethod}({RenderRationalNumber(testMethod.Input["r"])})", Precision(testMethod.Expected)); + default: + throw new ArgumentOutOfRangeException(); + } + } + + private static string RenderRationalNumber(dynamic input) => $"new RationalNumber({input[0]}, {input[1]})"; + + private static int Precision(object rawValue) + => rawValue.ToString().Split(new[] { '.' }).Length <= 1 + ? 0 + : rawValue.ToString().Split(new[] { '.' })[1].Length; + } +} \ No newline at end of file diff --git a/generators/Exercises/React.cs b/generators/Exercises/Generators/React.cs similarity index 64% rename from generators/Exercises/React.cs rename to generators/Exercises/Generators/React.cs index 1260653eb8..8a1c368531 100644 --- a/generators/Exercises/React.cs +++ b/generators/Exercises/Generators/React.cs @@ -3,40 +3,36 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; -using Generators.Output; -using Humanizer; -using Newtonsoft.Json.Linq; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Output; -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class React : GeneratorExercise { - protected override string RenderTestMethodBodyArrange(TestMethodBody testMethodBody) + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Arrange = RenderArrange(testMethod); + testMethod.Assert = RenderAssert(); + } + + private string RenderArrange(TestMethod testMethod) { var arrange = new StringBuilder(); - arrange.AppendLine("var sut = new Reactor();"); + arrange.AppendLine(Render.Variable("sut", "new Reactor()")); - var cells = RenderCells(testMethodBody.CanonicalDataCase.Input["cells"]); + var cells = RenderCells(testMethod.Input["cells"]); arrange.AppendLine(cells); - var operations = RenderOperations(testMethodBody.CanonicalDataCase.Input["operations"]); + var operations = RenderOperations(testMethod.Input["operations"]); arrange.AppendLine(operations); return arrange.ToString(); } - private static string RenderCells(dynamic cells) - { - if (cells.Length == 0) - { - return ""; - } - - var renderedCells = ((object[])cells).Select(RenderCell); - return string.Join("\n", renderedCells); - } + private string RenderCells(object[] cells) => string.Join(Environment.NewLine, cells.Select(RenderCell)); - private static string RenderCell(dynamic cell) + private string RenderCell(dynamic cell) { var cellType = (string)cell["type"]; var cellName = ToVariableName(cell["name"]); @@ -44,11 +40,11 @@ private static string RenderCell(dynamic cell) switch (cellType) { case "input": - return $"var {cellName} = sut.CreateInputCell({cell["initial_value"]});"; + return Render.Variable(cellName, $"sut.CreateInputCell({cell["initial_value"]})"); case "compute": var inputs = string.Join(", ", ((string[])cell["inputs"]).Select(ToVariableName)); var computeFunction = RenderComputeFunction(cell["compute_function"]); - return $"var {cellName} = sut.CreateComputeCell(new[] {{ {inputs} }}, inputs => {computeFunction});"; + return Render.Variable(cellName, $"sut.CreateComputeCell(new[] {{ {inputs} }}, inputs => {computeFunction})"); default: throw new InvalidOperationException($"Unknown cell type: {cellType}"); } @@ -58,26 +54,15 @@ private static string RenderComputeFunction(dynamic computeFunction) { var match = Regex.Match((string)computeFunction, "if (.+) then (.+) else (.+)"); - if (match.Success) - { - return $"{match.Groups[1]} ? {match.Groups[2]} : {match.Groups[3]}"; - } - - return computeFunction; + return match.Success + ? $"{match.Groups[1]} ? {match.Groups[2]} : {match.Groups[3]}" + : (string)computeFunction; } - private static string RenderOperations(dynamic operations) - { - if (operations.Length == 0) - { - return ""; - } - - var renderedOperations = ((object[])operations).Select(RenderOperation); - return string.Join("\n", renderedOperations); - } + private string RenderOperations(object[] operations) + => string.Join(Environment.NewLine, operations.Select(RenderOperation)); - private static string RenderOperation(dynamic operation) + private string RenderOperation(dynamic operation) { var operationType = (string)operation["type"]; @@ -113,24 +98,24 @@ private static string RenderOperation(dynamic operation) return $"Assert.Equal({operation["value"]}, {ToVariableName(operation["cell"])}.Value);"; case "add_callback": var addCallbackName = ToVariableName(operation["name"]); - return $"var {addCallbackName} = A.Fake>();\n" + + return Render.Variable(addCallbackName, "A.Fake>()") + Environment.NewLine + $"{ToVariableName(operation["cell"])}.Changed += {addCallbackName};"; case "remove_callback": var removeCallbackName = ToVariableName(operation["name"]); return $"{ToVariableName(operation["cell"])}.Changed -= {removeCallbackName};"; default: - return $"qweqwe"; + throw new ArgumentOutOfRangeException(); } } - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) => ""; + private static string RenderAssert() => string.Empty; - protected override HashSet AddAdditionalNamespaces() => new HashSet + protected override void UpdateNamespaces(ISet namespaces) { - typeof(EventHandler).Namespace, - "FakeItEasy" - }; + namespaces.Add(typeof(EventHandler).Namespace); + namespaces.Add("FakeItEasy"); + } - private static string ToVariableName(dynamic value) => ((string)value).Camelize(); + private static string ToVariableName(dynamic value) => ((string)value).ToVariableName(); } } \ No newline at end of file diff --git a/generators/Exercises/Generators/Rectangles.cs b/generators/Exercises/Generators/Rectangles.cs new file mode 100644 index 0000000000..79ab0c80df --- /dev/null +++ b/generators/Exercises/Generators/Rectangles.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Rectangles : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.TestedMethod = "Count"; + + if (testMethod.Input["strings"] is JArray) + testMethod.Input["strings"] = Array.Empty(); + + testMethod.Input["strings"] = new UnescapedValue(Render.ArrayMultiLine(testMethod.Input["strings"])); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/ReverseString.cs b/generators/Exercises/Generators/ReverseString.cs similarity index 57% rename from generators/Exercises/ReverseString.cs rename to generators/Exercises/Generators/ReverseString.cs index 59132fd5ab..76bb7e04f7 100644 --- a/generators/Exercises/ReverseString.cs +++ b/generators/Exercises/Generators/ReverseString.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class ReverseString : GeneratorExercise { diff --git a/generators/Exercises/Generators/RnaTranscription.cs b/generators/Exercises/Generators/RnaTranscription.cs new file mode 100644 index 0000000000..0ebf602ff9 --- /dev/null +++ b/generators/Exercises/Generators/RnaTranscription.cs @@ -0,0 +1,14 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class RnaTranscription : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected is null) + testMethod.ExceptionThrown = typeof(ArgumentException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/RobotSimulator.cs b/generators/Exercises/Generators/RobotSimulator.cs new file mode 100644 index 0000000000..8b132f883d --- /dev/null +++ b/generators/Exercises/Generators/RobotSimulator.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Text; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class RobotSimulator : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Input["direction"] = RenderDirection(testMethod.Input["direction"]); + testMethod.Input["coordinate"] = RenderCreateCoordinate(testMethod.Input["position"]); + + testMethod.ConstructorInputParameters = new[] { "direction", "coordinate" }; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + + testMethod.Act = RenderAct(testMethod); + testMethod.Assert = RenderAssert(testMethod); + } + + private string RenderAct(TestMethod testMethod) + { + switch (testMethod.Property) + { + case "create": return null; + case "instructions": return RenderInstructionsAct(testMethod); + default: return RenderDefaultAct(testMethod); + } + } + + private static string RenderDefaultAct(TestMethod testMethod) => $"sut.{testMethod.TestedMethod}();"; + + private string RenderInstructionsAct(TestMethod testMethod) + { + var actual = Render.Object(testMethod.Input["instructions"]); + return $"sut.Simulate({actual});"; + } + + private string RenderAssert(TestMethod testMethod) + { + var expected = (Dictionary)testMethod.Expected; + expected.TryGetValue("position", out var position); + expected.TryGetValue("direction", out var direction); + + var assert = new StringBuilder(); + + if (direction != null) + { + var expectedDirection = RenderDirection(direction); + assert.AppendLine(Render.AssertEqual(Render.Object(expectedDirection), "sut.Direction")); + } + + if (position == null) + return assert.ToString(); + + var x = Render.Object(position["x"]); + var y = Render.Object(position["y"]); + + assert.AppendLine(Render.AssertEqual(x, "sut.Coordinate.X")); + assert.AppendLine(Render.AssertEqual(y, "sut.Coordinate.Y")); + + return assert.ToString(); + } + + private UnescapedValue RenderDirection(string direction) + => Render.Enum("Direction", direction); + + private static UnescapedValue RenderCreateCoordinate(dynamic coordinates) + => new UnescapedValue($"new Coordinate({coordinates["x"]}, {coordinates["y"]})"); + } +} diff --git a/generators/Exercises/Generators/RomanNumerals.cs b/generators/Exercises/Generators/RomanNumerals.cs new file mode 100644 index 0000000000..a19155138f --- /dev/null +++ b/generators/Exercises/Generators/RomanNumerals.cs @@ -0,0 +1,13 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class RomanNumerals : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethodType = TestedMethodType.ExtensionMethod; + testMethod.TestedMethod = "ToRoman"; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/RotationalCipher.cs b/generators/Exercises/Generators/RotationalCipher.cs similarity index 59% rename from generators/Exercises/RotationalCipher.cs rename to generators/Exercises/Generators/RotationalCipher.cs index e8fcccbbf4..b491972cb3 100644 --- a/generators/Exercises/RotationalCipher.cs +++ b/generators/Exercises/Generators/RotationalCipher.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class RotationalCipher : GeneratorExercise { diff --git a/generators/Exercises/Generators/RunLengthEncoding.cs b/generators/Exercises/Generators/RunLengthEncoding.cs new file mode 100644 index 0000000000..b4b5830120 --- /dev/null +++ b/generators/Exercises/Generators/RunLengthEncoding.cs @@ -0,0 +1,22 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class RunLengthEncoding : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + + if (testMethod.Property == "consistency") + testMethod.Assert = RenderConsistencyToAssert(testMethod); + } + + private string RenderConsistencyToAssert(TestMethod testMethod) + { + var expected = Render.Object(testMethod.Expected); + var actual = $"{testMethod.TestedClass}.Decode({testMethod.TestedClass}.Encode({expected}))"; + return Render.AssertEqual(expected, actual); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/SaddlePoints.cs b/generators/Exercises/Generators/SaddlePoints.cs new file mode 100644 index 0000000000..afc1ca6493 --- /dev/null +++ b/generators/Exercises/Generators/SaddlePoints.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class SaddlePoints : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.TestedMethod = "Calculate"; + testMethod.ConstructorInputParameters = new[] { "matrix" }; + + testMethod.UseVariablesForConstructorParameters = true; + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForTested = true; + testMethod.UseVariableForExpected = true; + + testMethod.Input["matrix"] = ToMultiDimensionalArray(testMethod.Input["matrix"]); + + if (testMethod.Expected is Array array) + { + testMethod.Expected = ToTupleCollection(array); + } + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(string).Namespace); + } + + private static dynamic ToMultiDimensionalArray(JToken jArray) => jArray.ToObject(); + + private static (string, object)[] ToTupleCollection(Array array) + { + var tuples = new List<(string, object)>(); + + for (var x = 0; x < array.GetLength(0); x++) + { + var current = (Dictionary)array.GetValue(x); + tuples.Add((current["row"].ToString(), current["column"].ToString())); + } + + return tuples.ToArray(); + } + } +} diff --git a/generators/Exercises/Generators/Say.cs b/generators/Exercises/Generators/Say.cs new file mode 100644 index 0000000000..003c29bc00 --- /dev/null +++ b/generators/Exercises/Generators/Say.cs @@ -0,0 +1,16 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Say : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "InEnglish"; + + if (testMethod.Expected is int) + testMethod.ExceptionThrown = typeof(ArgumentOutOfRangeException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/ScaleGenerator.cs b/generators/Exercises/Generators/ScaleGenerator.cs new file mode 100644 index 0000000000..74528f1ad9 --- /dev/null +++ b/generators/Exercises/Generators/ScaleGenerator.cs @@ -0,0 +1,12 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class ScaleGenerator : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/ScrabbleScore.cs b/generators/Exercises/Generators/ScrabbleScore.cs similarity index 56% rename from generators/Exercises/ScrabbleScore.cs rename to generators/Exercises/Generators/ScrabbleScore.cs index bf156d878d..cb8435c1c8 100644 --- a/generators/Exercises/ScrabbleScore.cs +++ b/generators/Exercises/Generators/ScrabbleScore.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class ScrabbleScore : GeneratorExercise { diff --git a/generators/Exercises/SecretHandshake.cs b/generators/Exercises/Generators/SecretHandshake.cs similarity index 57% rename from generators/Exercises/SecretHandshake.cs rename to generators/Exercises/Generators/SecretHandshake.cs index 32d93e1195..830da3066f 100644 --- a/generators/Exercises/SecretHandshake.cs +++ b/generators/Exercises/Generators/SecretHandshake.cs @@ -1,4 +1,4 @@ -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class SecretHandshake : GeneratorExercise { diff --git a/generators/Exercises/Generators/Sieve.cs b/generators/Exercises/Generators/Sieve.cs new file mode 100644 index 0000000000..3c743a8adc --- /dev/null +++ b/generators/Exercises/Generators/Sieve.cs @@ -0,0 +1,22 @@ +using System; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Sieve : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + + if (testMethod.Input["limit"] < 2) + testMethod.ExceptionThrown = typeof(ArgumentOutOfRangeException); + else + testMethod.Expected = RenderAsSingleLineArray(testMethod.Expected); + } + + private UnescapedValue RenderAsSingleLineArray(dynamic value) + => new UnescapedValue(Render.Array(value as int[] ?? Array.Empty())); + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/SimpleCipher.cs b/generators/Exercises/Generators/SimpleCipher.cs new file mode 100644 index 0000000000..2c2b82922b --- /dev/null +++ b/generators/Exercises/Generators/SimpleCipher.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class SimpleCipher : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + + if (testMethod.Input.ContainsKey("key")) + testMethod.ConstructorInputParameters = new[] { "key" }; + + if (testMethod.Property == "new") + UpdateTestMethodForNewProperty(testMethod); + else if (testMethod.Property == "key") + UpdateTestMethodForKeyProperty(testMethod); + else + UpdateTestMethodForEncodeOrDecodeProperty(testMethod); + } + + private static void UpdateTestMethodForNewProperty(TestMethod testMethod) + { + testMethod.TestedMethodType = TestedMethodType.Constructor; + testMethod.ExceptionThrown = typeof(ArgumentException); + } + + private static void UpdateTestMethodForKeyProperty(TestMethod testMethod) + { + testMethod.Expected = new Regex(testMethod.Expected["match"]); + testMethod.TestedMethodType = TestedMethodType.Property; + } + + private void UpdateTestMethodForEncodeOrDecodeProperty(TestMethod testMethod) + { + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + + if (testMethod.Input.TryGetValue("ciphertext", out var cipherText)) + { + if (cipherText.StartsWith("cipher.key.substring")) + { + testMethod.Input["ciphertext"] = new UnescapedValue($"sut.Key.Substring(0, {testMethod.Expected.Length})"); + } + else if (cipherText == "cipher.encode") + { + var plaintext = Render.Object(testMethod.Input["plaintext"]); + testMethod.Input["ciphertext"] = new UnescapedValue($"sut.Encode({plaintext})"); + testMethod.InputParameters = new[] {"ciphertext"}; + } + } + + if (testMethod.Expected is string s && s.StartsWith("cipher.key.substring")) + { + testMethod.Expected = new UnescapedValue($"sut.Key.Substring(0, {testMethod.Input["plaintext"].Length})"); + } + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(ArgumentException).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/SpaceAge.cs b/generators/Exercises/Generators/SpaceAge.cs new file mode 100644 index 0000000000..7d01d039a8 --- /dev/null +++ b/generators/Exercises/Generators/SpaceAge.cs @@ -0,0 +1,17 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class SpaceAge : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = $"On{testMethod.Input["planet"]}"; + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + + testMethod.InputParameters = Array.Empty(); + testMethod.ConstructorInputParameters = new[] {"seconds"}; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/SpiralMatrix.cs b/generators/Exercises/Generators/SpiralMatrix.cs new file mode 100644 index 0000000000..f85212eaf6 --- /dev/null +++ b/generators/Exercises/Generators/SpiralMatrix.cs @@ -0,0 +1,17 @@ +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class SpiralMatrix : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "GetMatrix"; + testMethod.UseVariableForExpected = true; + testMethod.Expected = ConvertExpected(testMethod.Expected); + } + + private static int[,] ConvertExpected(JToken jArray) => jArray.ToObject(); + } +} diff --git a/generators/Exercises/Generators/Sublist.cs b/generators/Exercises/Generators/Sublist.cs new file mode 100644 index 0000000000..f0864649a9 --- /dev/null +++ b/generators/Exercises/Generators/Sublist.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Sublist : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Input["listOne"] = ConvertToList(testMethod.Input["listOne"]); + testMethod.Input["listTwo"] = ConvertToList(testMethod.Input["listTwo"]); + + testMethod.TestedMethod = "Classify"; + testMethod.Expected = Render.Enum("SublistType", testMethod.Expected); + } + + private static List ConvertToList(dynamic value) => new List(value as int[] ?? Array.Empty()); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(IList).Namespace); + } + } +} + diff --git a/generators/Exercises/Generators/SumOfMultiples.cs b/generators/Exercises/Generators/SumOfMultiples.cs new file mode 100644 index 0000000000..f3c7e6465c --- /dev/null +++ b/generators/Exercises/Generators/SumOfMultiples.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using Exercism.CSharp.Output; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class SumOfMultiples : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Input["factors"] is JArray) + testMethod.Input["factors"] = Array.Empty(); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Tournament.cs b/generators/Exercises/Generators/Tournament.cs new file mode 100644 index 0000000000..3dd1a34b7d --- /dev/null +++ b/generators/Exercises/Generators/Tournament.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Tournament : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "RunTally"; + testMethod.TestedMethodType = TestedMethodType.StaticMethod; + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + testMethod.Input["rows"] = new MultiLineString(testMethod.Input["rows"]); + testMethod.Expected = new MultiLineString(testMethod.Expected); + + testMethod.Assert = RenderAssert(); + } + + private string RenderAssert() => Render.AssertEqual("expected", "RunTally(rows)"); + + protected override void UpdateTestClass(TestClass testClass) + { + AddRunTallyMethod(testClass); + } + + private static void AddRunTallyMethod(TestClass testClass) + { + testClass.AdditionalMethods.Add(@" +private string RunTally(string input) +{ + var encoding = new UTF8Encoding(); + + using (var inStream = new MemoryStream(encoding.GetBytes(input))) + using (var outStream = new MemoryStream()) + { + Tournament.Tally(inStream, outStream); + return encoding.GetString(outStream.ToArray()); + } +}"); + } + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + namespaces.Add(typeof(Stream).Namespace); + namespaces.Add(typeof(UTF8Encoding).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/Transpose.cs b/generators/Exercises/Generators/Transpose.cs new file mode 100644 index 0000000000..240385f79a --- /dev/null +++ b/generators/Exercises/Generators/Transpose.cs @@ -0,0 +1,18 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Transpose : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "String"; + testMethod.Input["lines"] = new MultiLineString(testMethod.Input["lines"]); + testMethod.Expected = new MultiLineString(testMethod.Expected); + + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForExpected = true; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Triangle.cs b/generators/Exercises/Generators/Triangle.cs new file mode 100644 index 0000000000..b184d66ce5 --- /dev/null +++ b/generators/Exercises/Generators/Triangle.cs @@ -0,0 +1,20 @@ +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Triangle : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = $"Is{testMethod.TestedMethod}".ToTestedMethodName(); + testMethod.TestMethodName = testMethod.TestMethodNameWithPath; + + testMethod.Input["x"] = testMethod.Input["sides"][0]; + testMethod.Input["y"] = testMethod.Input["sides"][1]; + testMethod.Input["z"] = testMethod.Input["sides"][2]; + testMethod.Input.Remove("sides"); + testMethod.InputParameters = new[] { "x", "y", "z" }; + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/TwelveDays.cs b/generators/Exercises/Generators/TwelveDays.cs new file mode 100644 index 0000000000..2eba8c0745 --- /dev/null +++ b/generators/Exercises/Generators/TwelveDays.cs @@ -0,0 +1,19 @@ +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class TwelveDays : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + testMethod.Expected = new MultiLineString(testMethod.Expected); + + if (testMethod.Input["startVerse"] == testMethod.Input["endVerse"]) + { + testMethod.InputParameters = new[] { "startVerse" }; + } + } + } +} diff --git a/generators/Exercises/Generators/TwoBucket.cs b/generators/Exercises/Generators/TwoBucket.cs new file mode 100644 index 0000000000..051ce53870 --- /dev/null +++ b/generators/Exercises/Generators/TwoBucket.cs @@ -0,0 +1,31 @@ +using System.Text; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class TwoBucket : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForTested = true; + + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.ConstructorInputParameters = new[] { "bucketOne", "bucketTwo", "startBucket" }; + testMethod.Input["startBucket"] = Render.Enum("Bucket", testMethod.Input["startBucket"]); + + testMethod.Assert = RenderAssert(testMethod); + } + + private string RenderAssert(TestMethod testMethod) + { + var assert = new StringBuilder(); + assert.AppendLine(Render.AssertEqual(testMethod.Expected["moves"].ToString(), "actual.Moves")); + assert.AppendLine(Render.AssertEqual(testMethod.Expected["otherBucket"].ToString(), "actual.OtherBucket")); + + var expected = Render.Enum("Bucket", testMethod.Expected["goalBucket"]); + assert.AppendLine(Render.AssertEqual(expected.ToString(), "actual.GoalBucket")); + + return assert.ToString(); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/TwoFer.cs b/generators/Exercises/Generators/TwoFer.cs new file mode 100644 index 0000000000..1e7be05598 --- /dev/null +++ b/generators/Exercises/Generators/TwoFer.cs @@ -0,0 +1,16 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class TwoFer : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedMethod = "Name"; + + if (testMethod.Input["name"] is null) + testMethod.InputParameters = Array.Empty(); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/VariableLengthQuantity.cs b/generators/Exercises/Generators/VariableLengthQuantity.cs new file mode 100644 index 0000000000..3fb539310f --- /dev/null +++ b/generators/Exercises/Generators/VariableLengthQuantity.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class VariableLengthQuantity : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + testMethod.UseVariablesForInput = true; + testMethod.Input["integers"] = ConvertToUInt32Array(testMethod.Input["integers"]); + + if (testMethod.Expected == null) + testMethod.ExceptionThrown = typeof(InvalidOperationException); + else + testMethod.Expected = ConvertToUInt32Array(testMethod.Expected); + } + + private static uint[] ConvertToUInt32Array(IEnumerable input) + => input.Cast().Select(number => Convert.ToUInt32(number.ToString())).ToArray(); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Array).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/WordCount.cs b/generators/Exercises/Generators/WordCount.cs new file mode 100644 index 0000000000..0ee4d1c8e7 --- /dev/null +++ b/generators/Exercises/Generators/WordCount.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class WordCount : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariableForExpected = true; + testMethod.UseVariableForTested = true; + testMethod.Expected = ConvertExpected(testMethod.Expected); + } + + private static dynamic ConvertExpected(dynamic expected) + => ((Dictionary)expected).ToDictionary(kv => kv.Key, kv => Convert.ToInt32(kv.Value)); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(Dictionary).Namespace); + } + } +} diff --git a/generators/Exercises/Generators/WordSearch.cs b/generators/Exercises/Generators/WordSearch.cs new file mode 100644 index 0000000000..b3bcf2ed72 --- /dev/null +++ b/generators/Exercises/Generators/WordSearch.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Exercism.CSharp.Output; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class WordSearch : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.UseVariablesForInput = true; + testMethod.UseVariableForTested = true; + testMethod.UseVariableForExpected = true; + testMethod.UseVariablesForConstructorParameters = true; + + testMethod.TestedMethodType = TestedMethodType.InstanceMethod; + testMethod.ConstructorInputParameters = new[] { "grid" }; + + testMethod.Input["grid"] = new MultiLineString(testMethod.Input["grid"]); + testMethod.Expected = ConvertExpected(testMethod); + + testMethod.Assert = RenderAssert(testMethod); + } + + private static Dictionary ConvertExpected(TestMethod testMethod) + => ((IDictionary)testMethod.Expected).ToDictionary(kv => kv.Key, kv => (((int, int), (int, int))?)ConvertToPosition(kv.Value)); + + private string RenderAssert(TestMethod testMethod) + { + var assert = new StringBuilder(); + + foreach (var kv in testMethod.Expected) + assert.AppendLine(RenderAssertForSearchWord(kv.Key, kv.Value)); + + return assert.ToString(); + } + + private string RenderAssertForSearchWord(string word, dynamic expected) + => expected is null + ? Render.AssertNull($"expected[\"{word}\"]") + : Render.AssertEqual($"expected[\"{word}\"]", $"actual[\"{word}\"]"); + + private static ((int, int), (int, int))? ConvertToPosition(dynamic position) + { + if (position == null) + return null; + + return (ConvertToCoordinate(position["start"]), ConvertToCoordinate(position["end"])); + } + + private static (int, int) ConvertToCoordinate(dynamic coordinate) + => (Convert.ToInt32(coordinate["column"]), Convert.ToInt32(coordinate["row"])); + + protected override void UpdateNamespaces(ISet namespaces) + { + namespaces.Add(typeof(ValueTuple).Namespace); + namespaces.Add(typeof(Dictionary>).Namespace); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Wordy.cs b/generators/Exercises/Generators/Wordy.cs new file mode 100644 index 0000000000..ef27256bc3 --- /dev/null +++ b/generators/Exercises/Generators/Wordy.cs @@ -0,0 +1,14 @@ +using System; +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Wordy : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + if (testMethod.Expected is bool) + testMethod.ExceptionThrown = typeof(ArgumentException); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Generators/Yacht.cs b/generators/Exercises/Generators/Yacht.cs new file mode 100644 index 0000000000..78c8037527 --- /dev/null +++ b/generators/Exercises/Generators/Yacht.cs @@ -0,0 +1,13 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class Yacht : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.TestedClass = "YachtGame"; + testMethod.Input["category"] = Render.Enum("YachtCategory", testMethod.Input["category"]); + } + } +} diff --git a/generators/Exercises/Generators/ZebraPuzzle.cs b/generators/Exercises/Generators/ZebraPuzzle.cs new file mode 100644 index 0000000000..34b5fe4144 --- /dev/null +++ b/generators/Exercises/Generators/ZebraPuzzle.cs @@ -0,0 +1,12 @@ +using Exercism.CSharp.Output; + +namespace Exercism.CSharp.Exercises.Generators +{ + public class ZebraPuzzle : GeneratorExercise + { + protected override void UpdateTestMethod(TestMethod testMethod) + { + testMethod.Expected = Render.Enum("Nationality", testMethod.Expected); + } + } +} \ No newline at end of file diff --git a/generators/Exercises/Zipper.cs b/generators/Exercises/Generators/Zipper.cs similarity index 51% rename from generators/Exercises/Zipper.cs rename to generators/Exercises/Generators/Zipper.cs index b105e7ea48..048030c223 100644 --- a/generators/Exercises/Zipper.cs +++ b/generators/Exercises/Generators/Zipper.cs @@ -1,66 +1,57 @@ using System; using System.Linq; using System.Text; -using Generators.Output; -using Humanizer; -using Newtonsoft.Json.Linq; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Output; -namespace Generators.Exercises +namespace Exercism.CSharp.Exercises.Generators { public class Zipper : GeneratorExercise { - protected override string RenderTestMethodBodyArrange(TestMethodBody testMethodBody) + protected override void UpdateTestMethod(TestMethod testMethod) { - var arrange = new StringBuilder(); - - var tree = RenderTree(testMethodBody.CanonicalDataCase.Input["initialTree"]); - arrange.AppendLine($"var tree = {tree};"); - arrange.AppendLine("var sut = Zipper.FromTree(tree);"); + testMethod.Arrange = RenderArrange(testMethod); + testMethod.Assert = RenderAssert(testMethod); + } - var operations = RenderOperations(testMethodBody.CanonicalDataCase.Input["operations"]); - arrange.AppendLine($"var actual = sut{operations};"); + private string RenderArrange(TestMethod testMethod) + { + var arrange = new StringBuilder(); + var tree = RenderTree(testMethod.Input["initialTree"]); + arrange.AppendLine(Render.Variable("tree", tree)); + arrange.AppendLine(Render.Variable("sut", "Zipper.FromTree(tree)")); + var operations = RenderOperations(testMethod.Input["operations"]); + arrange.AppendLine(Render.Variable("actual", $"sut{operations}")); return arrange.ToString(); } - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) + private string RenderAssert(TestMethod testMethod) { - var assert = new StringBuilder(); - - var expected = RenderExpected(testMethodBody.CanonicalDataCase.Expected); + var expected = RenderExpected(testMethod.Expected); if (expected == null) { - assert.AppendLine("Assert.Null(actual);"); - } - else - { - assert.AppendLine($"var expected = {expected};"); - assert.AppendLine("Assert.Equal(expected, actual);"); + return Render.AssertNull("actual"); } + var assert = new StringBuilder(); + assert.AppendLine(Render.Variable("expected", expected)); + assert.AppendLine(Render.AssertEqual("expected", "actual")); return assert.ToString(); } private static string RenderTree(dynamic tree) { if (tree == null) - { return "null"; - } - var value = tree["value"]; - var left = tree["left"] == null ? "null" : RenderTree(tree["left"]); - var right = tree["right"] == null ? "null" : RenderTree(tree["right"]); - - return $"new BinTree({value}, {left}, {right})"; + return $"new BinTree({tree["value"]}, {RenderTree(tree["left"])}, {RenderTree(tree["right"])})"; } private static string RenderOperations(dynamic operations) { if (operations.Length == 0) - { return ""; - } return "." + string.Join(".", ((object[])operations).Select(RenderOperation)); } @@ -68,26 +59,26 @@ private static string RenderOperations(dynamic operations) private static string RenderOperation(dynamic operation) { var operationType = (string)operation["operation"]; + var operationMethod = operationType.ToMethodName(); switch (operationType) { case "set_value": - return $"SetValue({operation["item"]})"; + return $"{operationMethod}({operation["item"]})"; case "set_left": - return $"SetLeft({RenderTree(operation["item"])})"; case "set_right": - return $"SetRight({RenderTree(operation["item"])})"; + return $"{operationMethod}({RenderTree(operation["item"])})"; default: - return $"{operationType.Pascalize()}()"; + return $"{operationMethod}()"; } } - private static string RenderExpected(dynamic expected) + private string RenderExpected(dynamic expected) { switch (expected["type"]) { case "int": - return expected["value"].ToString(); + return Render.Object(expected["value"]); case "zipper": if (expected.TryGetValue("value", out dynamic value) && value == null) { diff --git a/generators/Exercises/Gigasecond.cs b/generators/Exercises/Gigasecond.cs deleted file mode 100644 index ca61e5d75b..0000000000 --- a/generators/Exercises/Gigasecond.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class Gigasecond : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - var input = DateTime.Parse(canonicalDataCase.Input["birthdate"].ToString()); - canonicalDataCase.Input["birthdate"] = new UnescapedValue(FormatDateTime(input)); - - canonicalDataCase.Expected = new UnescapedValue(FormatDateTime((DateTime)canonicalDataCase.Expected)); - } - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(DateTime).Namespace }; - - private static string FormatDateTime(DateTime dateTime) - { - return dateTime.Hour == 0 && dateTime.Minute == 0 && dateTime.Second == 0 - ? $"new DateTime({dateTime.Year}, {dateTime.Month}, {dateTime.Day})" - : $"new DateTime({dateTime.Year}, {dateTime.Month}, {dateTime.Day}, {dateTime.Hour}, {dateTime.Minute}, {dateTime.Second})"; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/GoCounting.cs b/generators/Exercises/GoCounting.cs deleted file mode 100644 index f797faf073..0000000000 --- a/generators/Exercises/GoCounting.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Humanizer; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class GoCounting : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.UseVariablesForConstructorParameters = true; - canonicalDataCase.UseVariableForTested = true; - - canonicalDataCase.Input["board"] = ConvertHelper.ToMultiLineString(canonicalDataCase.Input["board"]); - canonicalDataCase.SetConstructorInputParameters("board"); - - if (canonicalDataCase.Property == "territory") - { - canonicalDataCase.Input["coordinate"] = (canonicalDataCase.Input["x"], canonicalDataCase.Input["y"]); - canonicalDataCase.SetInputParameters("coordinate"); - - if (canonicalDataCase.Expected.ContainsKey("error")) - { - canonicalDataCase.ExceptionThrown = typeof(ArgumentException); - } - else - { - var owner = FormatOwner(canonicalDataCase.Expected["owner"]); - var territory = FormatTerritory(canonicalDataCase.Expected["territory"]); - canonicalDataCase.Expected = (new UnescapedValue(owner), territory); - } - } - else - { - var expected = new[] - { - "new Dictionary[]>", - "{", - $" [Owner.Black] = {FormatTerritory(canonicalDataCase.Expected["territoryBlack"])},", - $" [Owner.White] = {FormatTerritory(canonicalDataCase.Expected["territoryWhite"])},", - $" [Owner.None] = {FormatTerritory(canonicalDataCase.Expected["territoryNone"])}", - "}" - }; - - canonicalDataCase.Expected = new UnescapedValue(string.Join("\n", expected)); - } - } - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.CanonicalDataCase.ExceptionThrown != null) - { - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - if (testMethodBody.CanonicalDataCase.Property == "territories") - { - return string.Join("\n", new[] - { - "Assert.Equal(expected.Keys, actual.Keys);", - "Assert.Equal(expected[Owner.Black], actual[Owner.Black]);", - "Assert.Equal(expected[Owner.White], actual[Owner.White]);", - "Assert.Equal(expected[Owner.None], actual[Owner.None]);" - }); - } - - return string.Join("\n", new[] - { - "Assert.Equal(expected.Item1, actual.Item1);", - "Assert.Equal(expected.Item2, actual.Item2);" - }); - } - - private string FormatOwner(dynamic owner) - => $"Owner.{(owner as string).ToLowerInvariant().Humanize()}"; - - private string FormatTerritory(dynamic territory) - => ValueFormatter.Format((territory as JArray).Select(coordinate => (coordinate[0].ToObject(), coordinate[1].ToObject())).ToArray()); - - protected override HashSet AddAdditionalNamespaces() => new HashSet - { - typeof(ArgumentException).Namespace, - typeof(Dictionary).Namespace - }; - } -} \ No newline at end of file diff --git a/generators/Exercises/Grains.cs b/generators/Exercises/Grains.cs deleted file mode 100644 index b3a4364ce6..0000000000 --- a/generators/Exercises/Grains.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Grains : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - if (ShouldThrowException(canonicalDataCase.Expected)) - canonicalDataCase.ExceptionThrown = typeof(ArgumentOutOfRangeException); - else - canonicalDataCase.Expected = (ulong)canonicalDataCase.Expected; - } - } - - private static bool ShouldThrowException(dynamic value) => value is int i && i == -1; - } -} \ No newline at end of file diff --git a/generators/Exercises/Grep.cs b/generators/Exercises/Grep.cs deleted file mode 100644 index 6c7b814779..0000000000 --- a/generators/Exercises/Grep.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class Grep : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "Match"; - canonicalDataCase.Input["flags"] = string.Join(" ", canonicalDataCase.Input["flags"]); - canonicalDataCase.Expected = ConvertExpected(canonicalDataCase.Expected); - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - } - } - private static dynamic ConvertExpected(dynamic expected) - { - var arr = expected as object[]; - - if (arr == null || arr.Length == 0) - return ""; - - return new UnescapedValue("\n" + string.Join("\n", arr.Select(((x, i) => $" \"{x}\\n\"{(i < arr.Length - 1 ? " +" : "")}")))); - } - - protected override TestClass CreateTestClass() - { - var testClass = base.CreateTestClass(); - testClass.TemplateName = "TestClassDisposable"; - - return testClass; - } - - protected override HashSet AddAdditionalNamespaces() - { - return new HashSet - { - typeof(IDisposable).Namespace, - typeof(System.IO.File).Namespace - }; - } - - protected override string[] RenderAdditionalMethods() - { - return new[] - { - @" -private const string IliadFileName = ""iliad.txt""; -private const string IliadContents = - ""Achilles sing, O Goddess! Peleus' son;\n"" + - ""His wrath pernicious, who ten thousand woes\n"" + - ""Caused to Achaia's host, sent many a soul\n"" + - ""Illustrious into Ades premature,\n"" + - ""And Heroes gave (so stood the will of Jove)\n"" + - ""To dogs and to all ravening fowls a prey,\n"" + - ""When fierce dispute had separated once\n"" + - ""The noble Chief Achilles from the son\n"" + - ""Of Atreus, Agamemnon, King of men.\n"";", - @" -private const string MidsummerNightFileName = ""midsummer-night.txt""; -private const string MidsummerNightContents = - ""I do entreat your grace to pardon me.\n"" + - ""I know not by what power I am made bold,\n"" + - ""Nor how it may concern my modesty,\n"" + - ""In such a presence here to plead my thoughts;\n"" + - ""But I beseech your grace that I may know\n"" + - ""The worst that may befall me in this case,\n"" + - ""If I refuse to wed Demetrius.\n"";", - @" -private const string ParadiseLostFileName = ""paradise-lost.txt""; -private const string ParadiseLostContents = - ""Of Mans First Disobedience, and the Fruit\n"" + - ""Of that Forbidden Tree, whose mortal tast\n"" + - ""Brought Death into the World, and all our woe,\n"" + - ""With loss of Eden, till one greater Man\n"" + - ""Restore us, and regain the blissful Seat,\n"" + - ""Sing Heav'nly Muse, that on the secret top\n"" + - ""Of Oreb, or of Sinai, didst inspire\n"" + - ""That Shepherd, who first taught the chosen Seed\n"";", - @" -public GrepTest() -{ - Directory.SetCurrentDirectory(Path.GetTempPath()); - File.WriteAllText(IliadFileName, IliadContents); - File.WriteAllText(MidsummerNightFileName, MidsummerNightContents); - File.WriteAllText(ParadiseLostFileName, ParadiseLostContents); -}", - @" -public void Dispose() -{ - Directory.SetCurrentDirectory(Path.GetTempPath()); - File.Delete(IliadFileName); - File.Delete(MidsummerNightFileName); - File.Delete(ParadiseLostFileName); -}" - }; - } - } -} diff --git a/generators/Exercises/Hamming.cs b/generators/Exercises/Hamming.cs deleted file mode 100644 index 2d6c7ed1e2..0000000000 --- a/generators/Exercises/Hamming.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Hamming : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is int ? null : typeof(ArgumentException); - } - } -} diff --git a/generators/Exercises/House.cs b/generators/Exercises/House.cs deleted file mode 100644 index 01ab6c12be..0000000000 --- a/generators/Exercises/House.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class House : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Expected = ConvertHelper.ToMultiLineString(canonicalDataCase.Expected); - - if (canonicalDataCase.Input["startVerse"] == canonicalDataCase.Input["endVerse"]) - { - canonicalDataCase.SetInputParameters("startVerse"); - } - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/KindergartenGarden.cs b/generators/Exercises/KindergartenGarden.cs deleted file mode 100644 index c00a6507b1..0000000000 --- a/generators/Exercises/KindergartenGarden.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Humanizer; - -namespace Generators.Exercises -{ - public class KindergartenGarden : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.TestedMethodType = TestedMethodType.Instance; - canonicalDataCase.UseFullDescriptionPath = true; - - if (canonicalDataCase.Input.ContainsKey("students")) - canonicalDataCase.SetConstructorInputParameters("diagram", "students"); - else - canonicalDataCase.SetConstructorInputParameters("diagram"); - - var plants = (IEnumerable)canonicalDataCase.Expected; - canonicalDataCase.Expected = plants - .Select(x => new UnescapedValue($"Plant.{x.Humanize()}")) - .ToArray(); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/LargestSeriesProduct.cs b/generators/Exercises/LargestSeriesProduct.cs deleted file mode 100644 index 48fb03b289..0000000000 --- a/generators/Exercises/LargestSeriesProduct.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class LargestSeriesProduct : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "GetLargestProduct"; - - var caseInputLessThanZero = (long)canonicalDataCase.Expected == -1; - canonicalDataCase.ExceptionThrown = caseInputLessThanZero ? typeof(System.ArgumentException) : null; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Leap.cs b/generators/Exercises/Leap.cs deleted file mode 100644 index 78567f7d4c..0000000000 --- a/generators/Exercises/Leap.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class Leap : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - canonicalDataCase.Property = "IsLeapYear"; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/ListOps.cs b/generators/Exercises/ListOps.cs deleted file mode 100644 index 123cccfce6..0000000000 --- a/generators/Exercises/ListOps.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class ListOps : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseFullDescriptionPath = true; - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = !(canonicalDataCase.Expected is int); - - if (canonicalDataCase.Input.TryGetValue("list", out var list)) - canonicalDataCase.Input["list"] = ConvertToList(list); - - if (canonicalDataCase.Input.TryGetValue("list1", out var list1)) - canonicalDataCase.Input["list1"] = ConvertToList(list1); - - if (canonicalDataCase.Input.TryGetValue("list2", out var list2)) - canonicalDataCase.Input["list2"] = ConvertToList(list2); - - if (canonicalDataCase.Input.TryGetValue("lists", out var lists)) - canonicalDataCase.Input["lists"] = ConvertToNestedList(lists, true); - - if (canonicalDataCase.Input.TryGetValue("function", out var function)) - canonicalDataCase.Input["function"] = ConvertToFunction(canonicalDataCase.Property, function); - - if (canonicalDataCase.Expected is IEnumerable) - { - if (canonicalDataCase.Input.ContainsKey("lists")) - canonicalDataCase.Expected = ConvertToNestedList(canonicalDataCase.Expected, false); - else - canonicalDataCase.Expected = ConvertToList(canonicalDataCase.Expected); - } - } - } - - private static UnescapedValue ConvertToFunction(string property, dynamic function) - { - var signature = - property == "filter" ? "" : - property == "map" ? "" : - ""; - - var body = function - .Replace("modulo", "%") - .Replace("->", "=>"); - - return new UnescapedValue($"new Func{signature}({body})"); - } - - private static dynamic ConvertToList(dynamic value) - { - if (value is JArray jArray) - { - if (jArray.Count == 0) - return new List(); - - if (jArray.Any(jToken => jToken.Type == JTokenType.Array)) - return jArray.Select(ConvertToList).ToList(); - - return jArray.ToObject().ToList(); - } - - if (value is IEnumerable ints) - { - return ints.ToList(); - } - - return value; - } - - private static dynamic ConvertToNestedList(dynamic value, bool unescapeEmpty) - { - if (value is JArray jArray) - { - if (jArray.Count == 0) - { - if (unescapeEmpty) - { - return new UnescapedValue("new List>()"); - } - - return new List(); - } - - var nestedList = jArray - .Children() - .Select(ConvertToList) - .Select(ValueFormatter.Format) - .Select(formattedValue => new UnescapedValue(formattedValue)) - .ToList(); - - return new UnescapedValue(ValueFormatter.Format(nestedList) - .Replace("", "") - .Replace("new List { new List", "new List> { new List") - .Replace("new[] { new List>", "new List>> { new List>") - .Replace("new[] { new List", "new List> { new List")); - } - - if (value is IEnumerable ints) - { - return new UnescapedValue(ValueFormatter.Format(ints.ToList())); - } - - return value; - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet - { - typeof(Func).Namespace, - typeof(List).Namespace - }; - } -} \ No newline at end of file diff --git a/generators/Exercises/Luhn.cs b/generators/Exercises/Luhn.cs deleted file mode 100644 index d6f6295d73..0000000000 --- a/generators/Exercises/Luhn.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class Luhn : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - canonicalDataCase.Property = "IsValid"; - } - } -} diff --git a/generators/Exercises/Markdown.cs b/generators/Exercises/Markdown.cs deleted file mode 100644 index f672275712..0000000000 --- a/generators/Exercises/Markdown.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class Markdown : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - } - } - - protected override TestMethod CreateTestMethod(CanonicalDataCase canonicalDataCase, int index) - { - var testMethod = base.CreateTestMethod(canonicalDataCase, index); - testMethod.Skip = false; - - return testMethod; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Matrix.cs b/generators/Exercises/Matrix.cs deleted file mode 100644 index 41b50ceb19..0000000000 --- a/generators/Exercises/Matrix.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class Matrix : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Properties["string"] = canonicalDataCase.Properties["input"]["string"]; - canonicalDataCase.SetConstructorInputParameters("string"); - canonicalDataCase.Properties["index"] = canonicalDataCase.Properties["input"]["index"]; - canonicalDataCase.SetInputParameters("index"); - } - } - } -} diff --git a/generators/Exercises/Meetup.cs b/generators/Exercises/Meetup.cs deleted file mode 100644 index 76b063a5f5..0000000000 --- a/generators/Exercises/Meetup.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; -using Humanizer; - -namespace Generators.Exercises -{ - public class Meetup : GeneratorExercise - { - private const string ParamYear = "year"; - private const string ParamMonth = "month"; - private const string ParamWeek = "week"; - private const string ParamDayOfWeek = "dayofweek"; - - private const string PropertyDay = "Day"; - - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = PropertyDay; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.SetConstructorInputParameters(ParamMonth, ParamYear); - canonicalDataCase.SetInputParameters(ParamDayOfWeek, ParamWeek); - - canonicalDataCase.Input[ParamYear] = canonicalDataCase.Input[ParamYear]; - canonicalDataCase.Input[ParamMonth] = canonicalDataCase.Input[ParamMonth]; - canonicalDataCase.Input[ParamWeek] = - new UnescapedValue($"Schedule.{((string)canonicalDataCase.Input[ParamWeek]).Transform(To.SentenceCase)}"); - canonicalDataCase.Input[ParamDayOfWeek] = - new UnescapedValue($"DayOfWeek.{((string)canonicalDataCase.Input[ParamDayOfWeek]).Transform(To.SentenceCase)}"); - } - } - - protected override String RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - string template = $"Assert.Equal({{{{ ExpectedParameter }}}}, {{{{ TestedValue }}}}.ToString(\"yyyy-MM-dd\"));"; - - return TemplateRenderer.RenderInline(template, testMethodBody.AssertTemplateParameters); - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(DayOfWeek).Namespace }; - } -} diff --git a/generators/Exercises/Minesweeper.cs b/generators/Exercises/Minesweeper.cs deleted file mode 100644 index 64ee61e5ce..0000000000 --- a/generators/Exercises/Minesweeper.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class Minesweeper : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - - canonicalDataCase.Input["minefield"] = ToMultiLineString(canonicalDataCase.Input["minefield"]); - canonicalDataCase.Expected = ToMultiLineString(canonicalDataCase.Expected); - } - } - - private UnescapedValue ToMultiLineString(JArray input) - { - return new UnescapedValue("new string[0]"); - } - - private UnescapedValue ToMultiLineString(IEnumerable input) - { - const string template = -@"new string[] -{ - {% if input.size > 0 %}{% for item in {{input}} %}{% if forloop.length == 1 %}""{{item}}""{% break %}{% endif %}""{{item}}""{% if forloop.last == false %},{% else %}{{string.Empty}}{% endif %} - {% endfor %}{% endif %} -}"; - - return new UnescapedValue(TemplateRenderer.RenderInline(template, new { input })); - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(Array).Namespace }; - } -} diff --git a/generators/MissingDataExercise.cs b/generators/Exercises/MissingDataExercise.cs similarity index 58% rename from generators/MissingDataExercise.cs rename to generators/Exercises/MissingDataExercise.cs index 8e8e8675d4..c5951349ec 100644 --- a/generators/MissingDataExercise.cs +++ b/generators/Exercises/MissingDataExercise.cs @@ -1,6 +1,6 @@ -namespace Generators +namespace Exercism.CSharp.Exercises { - public sealed class MissingDataExercise : Exercise + public class MissingDataExercise : Exercise { public MissingDataExercise(string name) => Name = name; diff --git a/generators/Exercises/NthPrime.cs b/generators/Exercises/NthPrime.cs deleted file mode 100644 index bcd476ce6f..0000000000 --- a/generators/Exercises/NthPrime.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; - -namespace Generators.Exercises -{ - public class NthPrime : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is Dictionary ? typeof(ArgumentOutOfRangeException) : null; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/NucleotideCount.cs b/generators/Exercises/NucleotideCount.cs deleted file mode 100644 index 398f9b4562..0000000000 --- a/generators/Exercises/NucleotideCount.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Generators.Input; -using Generators.Output; -using System.Collections.Generic; -using System.Linq; - -namespace Generators.Exercises -{ - public class NucleotideCount : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - if (!((Dictionary)canonicalDataCase.Expected).ContainsKey("error")) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.SetConstructorInputParameters("strand"); - canonicalDataCase.Expected = ConvertExpected(canonicalDataCase.Expected); - } - } - } - - private static dynamic ConvertExpected(dynamic expected) - => ((Dictionary)expected).ToDictionary(kv => kv.Key[0], kv => int.Parse($"{kv.Value}")); - - protected override HashSet AddAdditionalNamespaces() => new HashSet() { typeof(Dictionary).Namespace }; - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.UseVariableForExpected) - { - return RenderEqualBodyAssert(testMethodBody); - } - return RenderThrowsBodyAssert(testMethodBody); - } - - private string RenderEqualBodyAssert(TestMethodBody testMethodBody) - { - const string template = @"Assert.Equal(expected, sut.{{ TestedMethodName }});"; - - var templateParameters = new - { - TestedMethodName = testMethodBody.CanonicalDataCase.Property.ToTestedMethodName() - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - - private string RenderThrowsBodyAssert(TestMethodBody testMethodBody) - { - const string template = @"Assert.Throws(() => new NucleotideCount(""{{ Input }}""));"; - - var templateParameters = new - { - Input = testMethodBody.CanonicalDataCase.Input["strand"] - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - } -} diff --git a/generators/Exercises/OcrNumbers.cs b/generators/Exercises/OcrNumbers.cs deleted file mode 100644 index 2f6d36ee8f..0000000000 --- a/generators/Exercises/OcrNumbers.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class OcrNumbers : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.ExceptionThrown = (canonicalDataCase.Expected is int && canonicalDataCase.Expected <= 0) ? typeof(ArgumentException) : null; - canonicalDataCase.Input["rows"] = ToDigitStringRepresentation(canonicalDataCase.Input["rows"]); - canonicalDataCase.Expected = canonicalDataCase.Expected.ToString(); - canonicalDataCase.UseVariableForTested = true; - canonicalDataCase.UseVariablesForInput = true; - } - } - - private UnescapedValue ToMultiLineString(JArray input) - { - return new UnescapedValue("Array.Empty()"); - } - - private UnescapedValue ToDigitStringRepresentation(string[] input) - { - const string template = @" {% for item in {{input}} %}{% if forloop.first == true %}""{{item}}"" + ""\n"" +{% continue %}{% endif %} - ""{{item}}""{% if forloop.last == false %} + ""\n"" +{% endif %}{% endfor %}"; - - return new UnescapedValue(TemplateRenderer.RenderInline(template, new { input })); - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(Array).Namespace }; - } -} diff --git a/generators/Exercises/PalindromeProducts.cs b/generators/Exercises/PalindromeProducts.cs deleted file mode 100644 index 24144cbce2..0000000000 --- a/generators/Exercises/PalindromeProducts.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Humanizer; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class PalindromeProducts : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - if (canonicalDataCase.Expected.ContainsKey("error")) - { - canonicalDataCase.ExceptionThrown = typeof(ArgumentException); - } - else - { - canonicalDataCase.UseVariableForTested = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Expected = (canonicalDataCase.Expected["value"], FormatCoordinates(canonicalDataCase.Expected["factors"])); - } - } - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.CanonicalDataCase.ExceptionThrown != null) - { - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - return string.Join("\n", new[] - { - "Assert.Equal(expected.Item1, actual.Item1);", - "Assert.Equal(expected.Item2, actual.Item2);" - }); - } - - private string FormatCoordinates(dynamic coordinates) - => ValueFormatter.Format((coordinates as JArray).Select(coordinate => (coordinate[0].ToObject(), coordinate[1].ToObject())).ToArray()); - } -} \ No newline at end of file diff --git a/generators/Exercises/PascalsTriangle.cs b/generators/Exercises/PascalsTriangle.cs deleted file mode 100644 index 3b573694cf..0000000000 --- a/generators/Exercises/PascalsTriangle.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Linq; -using Generators.Input; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class PascalsTriangle : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Property = "calculate"; - if (!(canonicalDataCase.Expected is JArray)) - canonicalDataCase.ExceptionThrown = typeof(ArgumentOutOfRangeException); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/PerfectNumbers.cs b/generators/Exercises/PerfectNumbers.cs deleted file mode 100644 index 8d0a93865d..0000000000 --- a/generators/Exercises/PerfectNumbers.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Generators.Input; -using Generators.Output; -using Humanizer; - -namespace Generators.Exercises -{ - public class PerfectNumbers : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - if (canonicalDataCase.Expected is string classificationType) - canonicalDataCase.Expected = new UnescapedValue($"Classification.{classificationType.Transform(To.SentenceCase)}"); - else - canonicalDataCase.ExceptionThrown = typeof(ArgumentOutOfRangeException); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/PhoneNumber.cs b/generators/Exercises/PhoneNumber.cs deleted file mode 100644 index 33a22dd6c9..0000000000 --- a/generators/Exercises/PhoneNumber.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class PhoneNumber : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is null ? typeof(ArgumentException) : null; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Poker.cs b/generators/Exercises/Poker.cs deleted file mode 100644 index 668e5dd3f2..0000000000 --- a/generators/Exercises/Poker.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class Poker : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.UseVariableForTested = true; - } - } - } -} diff --git a/generators/Exercises/Pov.cs b/generators/Exercises/Pov.cs deleted file mode 100644 index dd3e6ecaf1..0000000000 --- a/generators/Exercises/Pov.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using Generators.Input; -using Generators.Output; -using Humanizer; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class Pov : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is null ? typeof(ArgumentException) : null; - - canonicalDataCase.Input["tree"] = RenderTree(canonicalDataCase.Input["tree"]); - - if (canonicalDataCase.Property == "fromPov") - { - canonicalDataCase.Expected = RenderTree(canonicalDataCase.Expected); - } - } - } - - private static UnescapedValue RenderTree(dynamic tree) - { - if (tree == null) - { - return null; - } - - var sb = new StringBuilder(); - - var label = ValueFormatter.Format(tree["label"]); - - if (tree.ContainsKey("children")) - { - var children = string.Join(", ", ((object[])tree["children"]).Select(RenderTree)); - sb.Append($"new Tree({label}, {children})"); - } - else - { - sb.Append($"new Tree({label})"); - } - - return new UnescapedValue(sb.ToString()); - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Proverb.cs b/generators/Exercises/Proverb.cs deleted file mode 100644 index 72a28e1a59..0000000000 --- a/generators/Exercises/Proverb.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class Proverb : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Input["strings"] = ConvertHelper.ToArray(canonicalDataCase.Input["strings"]); - canonicalDataCase.Expected = ConvertHelper.ToArray(canonicalDataCase.Expected); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/QueenAttack.cs b/generators/Exercises/QueenAttack.cs deleted file mode 100644 index 0e4b288669..0000000000 --- a/generators/Exercises/QueenAttack.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Generators.Input; -using Generators.Output; -using System; -using System.Linq; - -namespace Generators.Exercises -{ - public class QueenAttack : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases.Where(canonicalDataCase => canonicalDataCase.Property == "create")) - SetCreatePropertyData(canonicalDataCase); - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.CanonicalDataCase.Property == "canAttack") - return RenderCanAttackAssert(testMethodBody); - - if (testMethodBody.UseVariableForTested) - return string.Empty; - - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - private static string RenderCanAttackAssert(TestMethodBody testMethodBody) - { - const string template = -@"var whiteQueen = QueenAttack.Create({{whiteQueenX}},{{whiteQueenY}}); -var blackQueen = QueenAttack.Create({{blackQueenX}},{{blackQueenY}}); -Assert.{% if Expected %}True{% else %}False{% endif %}(QueenAttack.CanAttack(whiteQueen, blackQueen));"; - - var whiteQueenPositions = GetCoordinatesFromPosition(testMethodBody.CanonicalDataCase.Input["white_queen"]); - var blackQueenPositions = GetCoordinatesFromPosition(testMethodBody.CanonicalDataCase.Input["black_queen"]); - - var templateParameters = new - { - whiteQueenX = whiteQueenPositions.Item1, - whiteQueenY = whiteQueenPositions.Item2, - blackQueenX = blackQueenPositions.Item1, - blackQueenY = blackQueenPositions.Item2, - Expected = testMethodBody.CanonicalDataCase.Expected - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - - private static Tuple GetCoordinatesFromPosition(dynamic expected) - { - var coordinates = expected["position"]; - - var positionX = (int)coordinates["row"]; - var positionY = (int)coordinates["column"]; - - return Tuple.Create(positionX, positionY); - } - - private static void SetCreatePropertyData(CanonicalDataCase canonicalDataCase) - { - var validExpected = canonicalDataCase.Expected >= 0; - - canonicalDataCase.UseVariableForTested = validExpected; - canonicalDataCase.ExceptionThrown = validExpected ? null : typeof(ArgumentOutOfRangeException); - canonicalDataCase.Description = validExpected ? canonicalDataCase.Description + " does not throw exception" : canonicalDataCase.Description; - - var coordinates = GetCoordinatesFromPosition(canonicalDataCase.Input["queen"]); - canonicalDataCase.Input["X"] = coordinates.Item1; - canonicalDataCase.Input["Y"] = coordinates.Item2; - - canonicalDataCase.SetInputParameters("X", "Y"); - } - } -} diff --git a/generators/Exercises/RailFenceCipher.cs b/generators/Exercises/RailFenceCipher.cs deleted file mode 100644 index d9b1a3de20..0000000000 --- a/generators/Exercises/RailFenceCipher.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class RailFenceCipher : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.SetConstructorInputParameters("rails"); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/RationalNumbers.cs b/generators/Exercises/RationalNumbers.cs deleted file mode 100644 index d26d16823a..0000000000 --- a/generators/Exercises/RationalNumbers.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Generators.Output; - -namespace Generators.Exercises -{ - public struct RationalNumber - { - public RationalNumber(int[] n) - { - this.Numerator = n[0]; - this.Denominator = n[1]; - } - - public int Numerator { get; } - public int Denominator { get; } - } - - public class RationalNumbers : GeneratorExercise - { - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - var input = testMethodBody.CanonicalDataCase.Properties["input"] as System.Collections.Generic.Dictionary; - var operation = testMethodBody.CanonicalDataCase.Properties["property"].ToString(); - var expected = testMethodBody.CanonicalDataCase.Properties["expected"]; - var operationName = char.ToUpper(operation[0]) + operation.Substring(1); - string assertCodeLine = ""; - string operationsWithOverloading = "add|+|sub|-|mul|*|div|/"; - string operationCode = operationsWithOverloading.Substring(operationsWithOverloading.IndexOf(operation.ToLower()) + 4, 1); - - switch (operation.ToLower()) - { - case "add": - case "sub": - case "mul": - case "div": - { - var r1 = new RationalNumber((int[])input["r1"]); - var r2 = new RationalNumber((int[])input["r2"]); - var e = new RationalNumber((int[])expected); - assertCodeLine = "Assert.Equal(" + $"new RationalNumber ({e.Numerator}, {e.Denominator}), new RationalNumber({r1.Numerator}, {r1.Denominator}) {operationCode} (new RationalNumber({r2.Numerator}, {r2.Denominator})));"; - } - break; - case "abs": - case "reduce": - { - var r = new RationalNumber((int[])input["r"]); - var e = new RationalNumber((int[])expected); - assertCodeLine = "Assert.Equal(" + $"new RationalNumber ({e.Numerator}, {e.Denominator}), new RationalNumber({r.Numerator}, {r.Denominator}).{operationName}());"; - } - break; - case "exprational": - { - var r = new RationalNumber((int[])input["r"]); - var n = input["n"]; - var e = new RationalNumber((int[])expected); - assertCodeLine = "Assert.Equal(" + $"new RationalNumber ({e.Numerator}, {e.Denominator}), new RationalNumber({r.Numerator}, {r.Denominator}).{operationName}({n}));"; - } - break; - case "expreal": - { - var x = input["x"].ToString(); - var r = new RationalNumber((int[])input["r"]); - var e = expected; - var p = precision(e); - assertCodeLine = "Assert.Equal(" + $"{e}, {x}.{operationName}(new RationalNumber({r.Numerator}, {r.Denominator})),{p});"; - } - break; - } - return TemplateRenderer.RenderInline(assertCodeLine, testMethodBody.AssertTemplateParameters); - } - - private static int precision(object rawValue) => rawValue.ToString().Split(new char[] { '.' }).Length <= 1 ? 0 : rawValue.ToString().Split(new char[] { '.' })[1].Length; - } -} \ No newline at end of file diff --git a/generators/Exercises/Rectangles.cs b/generators/Exercises/Rectangles.cs deleted file mode 100644 index 10b48a81df..0000000000 --- a/generators/Exercises/Rectangles.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class Rectangles : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "count"; - canonicalDataCase.Input["strings"] = canonicalDataCase.Input["strings"] as string[] ?? new string[0]; - canonicalDataCase.UseVariablesForInput = true; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/RnaTranscription.cs b/generators/Exercises/RnaTranscription.cs deleted file mode 100644 index cc738d4022..0000000000 --- a/generators/Exercises/RnaTranscription.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class RnaTranscription : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is null ? typeof(ArgumentException) : null; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/RobotSimulator.cs b/generators/Exercises/RobotSimulator.cs deleted file mode 100644 index ea226e9175..0000000000 --- a/generators/Exercises/RobotSimulator.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class RobotSimulator : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - const string direction = "direction"; - const string position = "position"; - const string coordinate = "coordinate"; - - foreach (var canonicalDataCase in canonicalData.Cases) - { - var positionVal = new UnescapedValue(GetCoordinateInstance(canonicalDataCase.Input[position])); - var directionVal = new UnescapedValue(GetDirectionEnum(canonicalDataCase.Input[direction])); - - canonicalDataCase.Input[direction] = directionVal; - canonicalDataCase.Input[coordinate] = positionVal; - - canonicalDataCase.SetConstructorInputParameters(direction, coordinate); - - canonicalDataCase.UseFullDescriptionPath = true; - canonicalDataCase.UseVariableForTested = true; - } - } - - protected override string RenderTestMethodBodyArrange(TestMethodBody testMethodBody) - { - ((testMethodBody.ArrangeTemplateParameters as dynamic).Variables as List).RemoveAt(1); - - return base.RenderTestMethodBodyArrange(testMethodBody); - } - - protected override string RenderTestMethodBodyAct(TestMethodBody testMethodBody) - { - switch (testMethodBody.CanonicalDataCase.Property) - { - case "create": return string.Empty; - case "instructions": return RenderInstructionsMethodBodyAct(testMethodBody); - default: return RenderDefaultMethodBodyAct(testMethodBody); - } - } - - private string RenderDefaultMethodBodyAct(TestMethodBody testMethodBody) - { - string template = @"sut.{{MethodInvocation}}();"; - - var templateParameters = new - { - MethodInvocation = testMethodBody.CanonicalDataCase.Property.ToTestedMethodName() - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - - private string RenderInstructionsMethodBodyAct(TestMethodBody testMethodBody) - { - string template = @"sut.{{MethodInvocation}}(""{{Instructions}}"");"; - - var templateParameters = new - { - MethodInvocation = "Simulate", - Instructions = testMethodBody.CanonicalDataCase.Input["instructions"] - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - var expected = testMethodBody.CanonicalDataCase.Expected as Dictionary; - expected.TryGetValue("position", out dynamic position); - expected.TryGetValue("direction", out dynamic direction); - - StringBuilder template = new StringBuilder(); - - if (direction != null) - template.AppendLine("Assert.Equal({{Direction}}, sut.Direction);"); - - if (position != null) - { - template.AppendLine("Assert.Equal({{X}}, sut.Coordinate.X);"); - template.AppendLine("Assert.Equal({{Y}}, sut.Coordinate.Y);"); - } - - var templateParameters = new - { - Direction = !string.IsNullOrEmpty(direction) ? GetDirectionEnum(direction) : null, - X = position?["x"], - Y = position?["y"] - }; - - return TemplateRenderer.RenderInline(template.ToString(), templateParameters); - } - - private string GetDirectionEnum(string direction) - { - switch (direction) - { - case "north": return "Direction.North"; - case "east": return "Direction.East"; - case "south": return "Direction.South"; - case "west": return "Direction.West"; - - default: throw new ArgumentException("Unrecognized 'Direction' enum value"); - } - } - - private string GetCoordinateInstance(dynamic coordinates) => $"new Coordinate({coordinates["x"]}, {coordinates["y"]})"; - } -} diff --git a/generators/Exercises/RomanNumerals.cs b/generators/Exercises/RomanNumerals.cs deleted file mode 100644 index e3f687044a..0000000000 --- a/generators/Exercises/RomanNumerals.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class RomanNumerals : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.TestedMethodType = TestedMethodType.Extension; - canonicalDataCase.Property = "ToRoman"; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/RunLengthEncoding.cs b/generators/Exercises/RunLengthEncoding.cs deleted file mode 100644 index 9616b3792b..0000000000 --- a/generators/Exercises/RunLengthEncoding.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class RunLengthEncoding : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - // Prefix the test name with encode/decode because both functions are tested with the same cases - canonicalDataCase.Description = $"{canonicalDataCase.Property} {canonicalDataCase.Description}"; - } - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.CanonicalDataCase.Property == "consistency") - { - return RenderConsistencyToAssert(testMethodBody); - } - - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - private static string RenderConsistencyToAssert(TestMethodBody testMethodBody) - { - const string template = @"Assert.Equal(""{{ExpectedOutput}}"", {{ExerciseName}}.Decode({{ExerciseName}}.Encode(""{{ExpectedOutput}}"")));"; - - var templateParameters = new - { - ExpectedOutput = testMethodBody.CanonicalDataCase.Expected, - ExerciseName = testMethodBody.CanonicalData.Exercise.ToTestedClassName() - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - } -} \ No newline at end of file diff --git a/generators/Exercises/SaddlePoints.cs b/generators/Exercises/SaddlePoints.cs deleted file mode 100644 index 3c76d335a4..0000000000 --- a/generators/Exercises/SaddlePoints.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class SaddlePoints : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.TestedMethodType = TestedMethodType.Instance; - canonicalDataCase.Property = "Calculate"; - canonicalDataCase.SetConstructorInputParameters("matrix"); - canonicalDataCase.UseVariablesForConstructorParameters = true; - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForTested = true; - canonicalDataCase.UseVariableForExpected = true; - - canonicalDataCase.Input["matrix"] = (canonicalDataCase.Input["matrix"] as JArray).ToObject(); - - var array = canonicalDataCase.Expected as Array; - - if (array != null) - { - canonicalDataCase.Expected = ToTupleCollection(array); - } - } - } - - protected override HashSet AddAdditionalNamespaces() - { - return new HashSet - { - typeof(System.String).Namespace - }; - } - - private IEnumerable> ToTupleCollection(Array array) - { - for (int x = 0; x < array.GetLength(0); x++) - { - var current = ((Array)array).GetValue(x) as Dictionary; - yield return new Tuple(current["row"].ToString(), current["column"].ToString()); - } - } - } -} diff --git a/generators/Exercises/Say.cs b/generators/Exercises/Say.cs deleted file mode 100644 index 568bc0ca1a..0000000000 --- a/generators/Exercises/Say.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Say : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "InEnglish"; - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is int ? typeof(ArgumentOutOfRangeException) : null; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/ScaleGenerator.cs b/generators/Exercises/ScaleGenerator.cs deleted file mode 100644 index 9fce86fc5b..0000000000 --- a/generators/Exercises/ScaleGenerator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class ScaleGenerator : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Sieve.cs b/generators/Exercises/Sieve.cs deleted file mode 100644 index e7fabd1b81..0000000000 --- a/generators/Exercises/Sieve.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Sieve : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.ExceptionThrown = canonicalDataCase.Input["limit"] < 2 ? typeof(ArgumentOutOfRangeException) : null; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/SimpleCipher.cs b/generators/Exercises/SimpleCipher.cs deleted file mode 100644 index 1f453d0c56..0000000000 --- a/generators/Exercises/SimpleCipher.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class SimpleCipher : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseFullDescriptionPath = true; - - if (canonicalDataCase.Property == "new") - { - continue; - } - - canonicalDataCase.TestedMethodType = TestedMethodType.Instance; - - if (canonicalDataCase.Input.ContainsKey("key")) - { - canonicalDataCase.SetConstructorInputParameters("key"); - } - - if (canonicalDataCase.Input.TryGetValue("ciphertext", out var cipherText)) - { - if (cipherText == "cipher.key") - { - canonicalDataCase.Input["ciphertext"] = new UnescapedValue("sut.Key.Substring(0, 10)"); - } - else if (cipherText == "cipher.encode") - { - var plaintext = ValueFormatter.Format(canonicalDataCase.Input["plaintext"]); - canonicalDataCase.Input["ciphertext"] = new UnescapedValue($"sut.Encode({plaintext})"); - canonicalDataCase.SetInputParameters("ciphertext"); - } - } - - if (canonicalDataCase.Expected is string s && s == "cipher.key") - { - canonicalDataCase.Expected = new UnescapedValue("sut.Key.Substring(0, 10)"); - } - } - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - if (testMethodBody.CanonicalDataCase.Property == "new") - { - var key = ValueFormatter.Format(testMethodBody.CanonicalDataCase.Input["key"]); - return $"Assert.Throws(() => new SimpleCipher({key}));"; - } - else if (testMethodBody.CanonicalDataCase.Property == "key") - { - var pattern = ValueFormatter.Format(testMethodBody.CanonicalDataCase.Expected["match"]); - return $"Assert.Matches({pattern}, sut.Key);"; - } - - return base.RenderTestMethodBodyAssert(testMethodBody); - } - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(ArgumentException).Namespace }; - } -} \ No newline at end of file diff --git a/generators/Exercises/SpaceAge.cs b/generators/Exercises/SpaceAge.cs deleted file mode 100644 index fea1592e18..0000000000 --- a/generators/Exercises/SpaceAge.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class SpaceAge : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = $"On_{canonicalDataCase.Input["planet"]}"; - canonicalDataCase.SetInputParameters(); - canonicalDataCase.SetConstructorInputParameters("seconds"); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/SpiralMatrix.cs b/generators/Exercises/SpiralMatrix.cs deleted file mode 100644 index 15ab185a81..0000000000 --- a/generators/Exercises/SpiralMatrix.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class SpiralMatrix : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "GetMatrix"; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Expected = ConvertExpected(canonicalDataCase.Expected); - } - } - - private dynamic ConvertExpected(dynamic expected) - { - var jArray = (JArray)expected; - - if (jArray.Count == 0) - return new int[0, 0]; - - var rows = jArray.Count; - var cols = jArray[0].Count(); - - var matrix = new int[rows, cols]; - - for (var y = 0; y < rows; y++) - { - for (var x = 0; x < cols; x++) - { - matrix[y, x] = jArray[y][x].ToObject(); - } - } - - return matrix; - } - } -} diff --git a/generators/Exercises/Sublist.cs b/generators/Exercises/Sublist.cs deleted file mode 100644 index 39683c6714..0000000000 --- a/generators/Exercises/Sublist.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; -using Humanizer; - -namespace Generators.Exercises -{ - public class Sublist : GeneratorExercise - { - protected override HashSet AddAdditionalNamespaces() => new HashSet() { typeof(IList).Namespace }; - - private UnescapedValue InputValues(int[] list) - { - var template = (list != null) ? string.Join(", ", Array.ConvertAll(list, (x) => { return $"{x}"; })) : ""; - return new UnescapedValue($"new List() {{ {template} }}".Replace(" ", " ")); - } - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Input["listOne"] = InputValues(canonicalDataCase.Input["listOne"] as int[]); - canonicalDataCase.Input["listTwo"] = InputValues(canonicalDataCase.Input["listTwo"] as int[]); - - canonicalDataCase.Property = "classify"; - canonicalDataCase.Expected = new UnescapedValue($"SublistType.{(canonicalDataCase.Expected as string).Dehumanize()}"); - } - } - } -} - diff --git a/generators/Exercises/SumOfMultiples.cs b/generators/Exercises/SumOfMultiples.cs deleted file mode 100644 index 1d4f4ef797..0000000000 --- a/generators/Exercises/SumOfMultiples.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class SumOfMultiples : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Input["factors"] = ConvertHelper.ToArray(canonicalDataCase.Input["factors"]); - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/TestedMethodType.cs b/generators/Exercises/TestedMethodType.cs new file mode 100644 index 0000000000..d1a0768d39 --- /dev/null +++ b/generators/Exercises/TestedMethodType.cs @@ -0,0 +1,11 @@ +namespace Exercism.CSharp.Exercises +{ + public enum TestedMethodType + { + StaticMethod, + InstanceMethod, + ExtensionMethod, + Property, + Constructor + } +} \ No newline at end of file diff --git a/generators/Exercises/Tournament.cs b/generators/Exercises/Tournament.cs deleted file mode 100644 index a6f49a7e1d..0000000000 --- a/generators/Exercises/Tournament.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using Generators.Input; -using Generators.Output; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class Tournament : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "RunTally"; - canonicalDataCase.TestedMethodType = TestedMethodType.Static; - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Input["rows"] = ConvertHelper.ToMultiLineString(canonicalDataCase.Input["rows"], ""); - canonicalDataCase.Expected = ConvertHelper.ToMultiLineString(canonicalDataCase.Expected); - } - } - - protected override HashSet AddAdditionalNamespaces() - { - return new HashSet - { - typeof(Array).Namespace, - typeof(System.String).Namespace, - typeof(System.IO.Stream).Namespace, - typeof(System.Text.UTF8Encoding).Namespace - }; - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - string template = @"Assert.Equal(expected, RunTally(rows));"; - return TemplateRenderer.RenderInline(template, new { }); - } - - protected override string[] RenderAdditionalMethods() - { - var methods = @" -private string RunTally(string input) -{ - var encoding = new UTF8Encoding(); - - using (var inStream = new MemoryStream(encoding.GetBytes(input))) - using (var outStream = new MemoryStream()) - { - Tournament.Tally(inStream, outStream); - return encoding.GetString(outStream.ToArray()); - } -}"; - return methods.Split("", System.StringSplitOptions.None); - } - } -} diff --git a/generators/Exercises/Transpose.cs b/generators/Exercises/Transpose.cs deleted file mode 100644 index 166d326659..0000000000 --- a/generators/Exercises/Transpose.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class Transpose : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "String"; - canonicalDataCase.Input["lines"] = ConvertHelper.ToMultiLineString(canonicalDataCase.Input["lines"], ""); - canonicalDataCase.Expected = ConvertHelper.ToMultiLineString(canonicalDataCase.Expected, ""); - - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForExpected = true; - } - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Triangle.cs b/generators/Exercises/Triangle.cs deleted file mode 100644 index 24c2d34ef8..0000000000 --- a/generators/Exercises/Triangle.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections; -using Generators.Input; -using Generators.Output; -namespace Generators.Exercises -{ - public class Triangle : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var data in canonicalData.Cases) - { - if (data.Property == "equilateral") - data.Property = "IsEquilateral"; - else if (data.Property == "isosceles") - data.Property = "IsIsosceles"; - else if (data.Property == "scalene") - data.Property = "IsScalene"; - - data.Input["sides"] = SplitArrayToValues(data.Input["sides"]); - data.SetInputParameters("sides"); - data.UseFullDescriptionPath = true; - - } - } - - private UnescapedValue SplitArrayToValues(IEnumerable input) - { - const string template = "{% for item in {{input}} %}{{item}}{% if forloop.last == false %}, {% endif %}{% endfor %}"; - - return new UnescapedValue(TemplateRenderer.RenderInline(template, new { input })); - } - } -} \ No newline at end of file diff --git a/generators/Exercises/TwelveDays.cs b/generators/Exercises/TwelveDays.cs deleted file mode 100644 index fd2bcc3cbc..0000000000 --- a/generators/Exercises/TwelveDays.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Generators.Input; -using Generators.Output; -using System.Linq; -using Humanizer; - -namespace Generators.Exercises -{ - public class TwelveDays : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.Expected = ConvertHelper.ToMultiLineString(canonicalDataCase.Expected); - - if (canonicalDataCase.Input["startVerse"] == canonicalDataCase.Input["endVerse"]) - { - canonicalDataCase.SetInputParameters("startVerse"); - } - } - } - } -} diff --git a/generators/Exercises/TwoBucket.cs b/generators/Exercises/TwoBucket.cs deleted file mode 100644 index ef3cc54341..0000000000 --- a/generators/Exercises/TwoBucket.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class TwoBucket : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.TestedMethodType = TestedMethodType.Instance; - canonicalDataCase.SetConstructorInputParameters("bucketOne", "bucketTwo", "startBucket"); - - var startBucket = canonicalDataCase.Input["startBucket"]; - canonicalDataCase.Input["startBucket"] = new UnescapedValue(startBucket == "two" ? "Bucket.Two" : "Bucket.One"); - } - } - - protected override string RenderTestMethodBodyAct(TestMethodBody testMethodBody) - { - const string template = @"var result = {{MethodInvocation}};"; - - var templateParameters = new - { - MethodInvocation = testMethodBody.Data.TestedMethodInvocation - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - const string template = -@"Assert.Equal({{MovesExpected}}, result.Moves); -Assert.Equal({{OtherBucketExpected}}, result.OtherBucket); -Assert.Equal({% if GoalBucketExpected == 'two' %}Bucket.Two{% else %}Bucket.One{% endif %}, result.GoalBucket);"; - - var templateParameters = new - { - MovesExpected = testMethodBody.CanonicalDataCase.Expected["moves"], - OtherBucketExpected = testMethodBody.CanonicalDataCase.Expected["otherBucket"], - GoalBucketExpected = testMethodBody.CanonicalDataCase.Expected["goalBucket"], - }; - - return TemplateRenderer.RenderInline(template, templateParameters); - } - } -} \ No newline at end of file diff --git a/generators/Exercises/TwoFer.cs b/generators/Exercises/TwoFer.cs deleted file mode 100644 index 35c7a86954..0000000000 --- a/generators/Exercises/TwoFer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Generators.Input; - -namespace Generators.Exercises -{ - public class TwoFer : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.Property = "Name"; - } - } - } -} \ No newline at end of file diff --git a/generators/UnimplementedExercise.cs b/generators/Exercises/UnimplementedExercise.cs similarity index 58% rename from generators/UnimplementedExercise.cs rename to generators/Exercises/UnimplementedExercise.cs index 1809140b79..a1a88088fb 100644 --- a/generators/UnimplementedExercise.cs +++ b/generators/Exercises/UnimplementedExercise.cs @@ -1,6 +1,6 @@ -namespace Generators +namespace Exercism.CSharp.Exercises { - public sealed class UnimplementedExercise : Exercise + public class UnimplementedExercise : Exercise { public UnimplementedExercise(string name) => Name = name; diff --git a/generators/Exercises/VariableLengthQuantity.cs b/generators/Exercises/VariableLengthQuantity.cs deleted file mode 100644 index 34e22a89ca..0000000000 --- a/generators/Exercises/VariableLengthQuantity.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; - -namespace Generators.Exercises -{ - public class VariableLengthQuantity : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.Input["integers"] = FormatUInt32Array(canonicalDataCase.Input["integers"]); - - if (canonicalDataCase.Expected == null) - canonicalDataCase.ExceptionThrown = typeof(InvalidOperationException); - else - canonicalDataCase.Expected = FormatUInt32Array(canonicalDataCase.Expected); - } - } - - private dynamic FormatUInt32Array(dynamic input) - { - var numbers = ToUInt32Array(input as IEnumerable); - if (!numbers.Any()) - { - return new UnescapedValue("new uint[0]"); - } - - return numbers.Select(number => new UnescapedValue(string.Format("0x{0:X}u", number))).ToArray(); - } - - private IEnumerable ToUInt32Array(IEnumerable input) - { - foreach (var number in input) - yield return Convert.ToUInt32(number.ToString()); - } - } -} \ No newline at end of file diff --git a/generators/Exercises/WordCount.cs b/generators/Exercises/WordCount.cs deleted file mode 100644 index 9a992819c0..0000000000 --- a/generators/Exercises/WordCount.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Generators.Input; -using System.Collections.Generic; -using System.Linq; - -namespace Generators.Exercises -{ - public class WordCount : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.UseVariableForTested = true; - canonicalDataCase.Expected = ConvertExpected(canonicalDataCase.Expected); - } - } - - private static dynamic ConvertExpected(dynamic expected) - => ((Dictionary)expected).ToDictionary(kv => kv.Key, kv => int.Parse(kv.Value.ToString())); - - protected override HashSet AddAdditionalNamespaces() => new HashSet { typeof(Dictionary).Namespace }; - } -} diff --git a/generators/Exercises/WordSearch.cs b/generators/Exercises/WordSearch.cs deleted file mode 100644 index 65f5ce1f93..0000000000 --- a/generators/Exercises/WordSearch.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; -using Humanizer; -using Newtonsoft.Json.Linq; - -namespace Generators.Exercises -{ - public class WordSearch : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - canonicalDataCase.UseVariablesForInput = true; - canonicalDataCase.UseVariableForTested = true; - canonicalDataCase.UseVariableForExpected = true; - canonicalDataCase.UseVariablesForConstructorParameters = true; - - canonicalDataCase.SetConstructorInputParameters("grid"); - - canonicalDataCase.Input["grid"] = ConvertHelper.ToMultiLineString(canonicalDataCase.Input["grid"]); - - var expectedDictionary = canonicalDataCase.Expected as IDictionary; - - var expected = new List - { - "new Dictionary", - "{" - }; - - expected.AddRange(expectedDictionary.Select(((kv, i) => $" [\"{kv.Key}\"] = {FormatPosition(kv.Value)}{(i < expectedDictionary.Count - 1 ? "," : "")}"))); - expected.Add("}"); - - canonicalDataCase.Expected = new UnescapedValue(string.Join("\n", expected)); - } - } - - protected override string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - { - var expectedDictionary = testMethodBody.CanonicalDataCase.Properties["expected"] as IDictionary; - - var assert = new List(); - - foreach (var kv in expectedDictionary) - { - assert.Add(RenderTestMethodBodyAssertForSearchWord(kv.Key, kv.Value)); - } - - return string.Join("\n", assert); - } - - private string RenderTestMethodBodyAssertForSearchWord(string word, dynamic expected) - { - if (expected == null) - { - return $"Assert.Null(expected[\"{word}\"]);"; - } - - return $"Assert.Equal(expected[\"{word}\"], actual[\"{word}\"]);"; - } - - private string FormatPosition(dynamic position) - { - if (position == null) - { - return "null"; - } - - return ValueFormatter.Format((FormatCoordinate(position["start"]), FormatCoordinate(position["end"]))); - } - - private string FormatCoordinate(dynamic coordinate) - => ValueFormatter.Format((coordinate["column"], coordinate["row"])); - - protected override HashSet AddAdditionalNamespaces() => new HashSet - { - typeof(ValueTuple).Namespace, - typeof(Dictionary>).Namespace - }; - } -} \ No newline at end of file diff --git a/generators/Exercises/Wordy.cs b/generators/Exercises/Wordy.cs deleted file mode 100644 index db683dc31b..0000000000 --- a/generators/Exercises/Wordy.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Exercises -{ - public class Wordy : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - canonicalDataCase.ExceptionThrown = canonicalDataCase.Expected is bool ? typeof(ArgumentException) : null; - } - } -} \ No newline at end of file diff --git a/generators/Exercises/Yacht.cs b/generators/Exercises/Yacht.cs deleted file mode 100644 index f79a37c95a..0000000000 --- a/generators/Exercises/Yacht.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Generators.Input; -using Generators.Output; -using Humanizer; - -namespace Generators.Exercises -{ - public class Yacht : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - canonicalData.Exercise = "yacht-game"; - foreach (var canonicalDataCase in canonicalData.Cases) - { - var category = canonicalDataCase.Input["category"].ToString(); - var formattedCategory = StringDehumanizeExtensions.Dehumanize(category); - canonicalDataCase.Input["category"] = new UnescapedValue($"YachtCategory.{formattedCategory}"); - } - } - } -} diff --git a/generators/Exercises/ZebraPuzzle.cs b/generators/Exercises/ZebraPuzzle.cs deleted file mode 100644 index f0833ea052..0000000000 --- a/generators/Exercises/ZebraPuzzle.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using Generators.Input; -using Generators.Output; -using Humanizer; - -namespace Generators.Exercises -{ - public class ZebraPuzzle : GeneratorExercise - { - protected override void UpdateCanonicalData(CanonicalData canonicalData) - { - foreach (var canonicalDataCase in canonicalData.Cases) - { - var nationality = canonicalDataCase.Expected as string; - canonicalDataCase.Expected = new UnescapedValue($"Nationality.{nationality.Humanize()}"); - } - } - } -} \ No newline at end of file diff --git a/generators/GeneratorExercise.cs b/generators/GeneratorExercise.cs deleted file mode 100644 index 53f17c86d7..0000000000 --- a/generators/GeneratorExercise.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Generators.Input; -using Generators.Output; - -namespace Generators -{ - public abstract class GeneratorExercise : Exercise - { - private static readonly ExerciseWriter ExerciseWriter = new ExerciseWriter(); - private CanonicalData _canonicalData; - - public override string Name => GetType().ToExerciseName(); - - public void Regenerate(CanonicalData canonicalData) - { - _canonicalData = canonicalData; - UpdateCanonicalData(canonicalData); - - ExerciseWriter.WriteToFile(this); - } - - public string Render() => CreateTestClass().Render(); - - protected virtual void UpdateCanonicalData(CanonicalData canonicalData) - { - } - - protected virtual HashSet AddAdditionalNamespaces() - { - return new HashSet(); - } - - protected virtual string RenderTestMethodBodyArrange(TestMethodBody testMethodBody) - => TemplateRenderer.RenderPartial(testMethodBody.ArrangeTemplateName, testMethodBody.ArrangeTemplateParameters); - - protected virtual string RenderTestMethodBodyAct(TestMethodBody testMethodBody) - => TemplateRenderer.RenderPartial(testMethodBody.ActTemplateName, testMethodBody.ActTemplateParameters); - - protected virtual string RenderTestMethodBodyAssert(TestMethodBody testMethodBody) - => TemplateRenderer.RenderPartial(testMethodBody.AssertTemplateName, testMethodBody.AssertTemplateParameters); - - protected virtual string[] RenderAdditionalMethods() - { - return new string[] { }; - } - - private HashSet GetUsingNamespaces() - { - var usingNamespaces = new HashSet { "Xunit" }; - - foreach (var canonicalDataCase in _canonicalData.Cases.Where(canonicalDataCase => canonicalDataCase.ExceptionThrown != null)) - usingNamespaces.Add(canonicalDataCase.ExceptionThrown.Namespace); - - usingNamespaces.UnionWith(AddAdditionalNamespaces()); - - return usingNamespaces; - } - - private string[] RenderTestMethods() => _canonicalData.Cases.Select(RenderTestMethod).Concat(RenderAdditionalMethods()).ToArray(); - - protected virtual TestClass CreateTestClass() => new TestClass - { - ClassName = Name.ToTestClassName(), - Methods = RenderTestMethods(), - CanonicalDataVersion = _canonicalData.Version, - UsingNamespaces = GetUsingNamespaces() - }; - - private string RenderTestMethod(CanonicalDataCase canonicalDataCase, int index) => CreateTestMethod(canonicalDataCase, index).Render(); - - protected virtual TestMethod CreateTestMethod(CanonicalDataCase canonicalDataCase, int index) => new TestMethod - { - Skip = index > 0, - Name = ToTestMethodName(canonicalDataCase), - Body = RenderTestMethodBody(canonicalDataCase) - }; - - private static string ToTestMethodName(CanonicalDataCase canonicalDataCase) - => canonicalDataCase.UseFullDescriptionPath - ? string.Join(" - ", canonicalDataCase.DescriptionPath).ToTestMethodName() - : canonicalDataCase.Description.ToTestMethodName(); - - private string RenderTestMethodBody(CanonicalDataCase canonicalDataCase) - { - var testMethodBody = CreateTestMethodBody(canonicalDataCase); - testMethodBody.Arrange = RenderTestMethodBodyArrange(testMethodBody); - testMethodBody.Act = RenderTestMethodBodyAct(testMethodBody); - testMethodBody.Assert = RenderTestMethodBodyAssert(testMethodBody); - - return testMethodBody.Render(); - } - - protected virtual TestMethodBody CreateTestMethodBody(CanonicalDataCase canonicalDataCase) - { - if (canonicalDataCase.ExceptionThrown != null) - { - return new TestMethodBodyWithExceptionCheck(canonicalDataCase, _canonicalData); - } - - if (canonicalDataCase.Expected is bool) - { - return new TestMethodBodyWithBooleanCheck(canonicalDataCase, _canonicalData); - } - - if (canonicalDataCase.Expected is null) - { - return new TestMethodBodyWithNullCheck(canonicalDataCase, _canonicalData); - } - - return new TestMethodBodyWithEqualityCheck(canonicalDataCase, _canonicalData); - } - } -} diff --git a/generators/GeneratorStatus.cs b/generators/GeneratorStatus.cs index adf127e104..72c849a741 100644 --- a/generators/GeneratorStatus.cs +++ b/generators/GeneratorStatus.cs @@ -1,4 +1,4 @@ -namespace Generators +namespace Exercism.CSharp { public enum GeneratorStatus { diff --git a/generators/Generators.csproj b/generators/Generators.csproj index 30898a188f..a56c06b6bb 100644 --- a/generators/Generators.csproj +++ b/generators/Generators.csproj @@ -2,17 +2,18 @@ Exe netcoreapp2.0 + Exercism.CSharp - - - + + + - - + + - + \ No newline at end of file diff --git a/generators/Helpers/ArrayExtensions.cs b/generators/Helpers/ArrayExtensions.cs new file mode 100644 index 0000000000..e9a9397c88 --- /dev/null +++ b/generators/Helpers/ArrayExtensions.cs @@ -0,0 +1,16 @@ +using System.Linq; + +namespace Exercism.CSharp.Helpers +{ + public static class ArrayExtensions + { + public static T[][] Rows(this T[,] array) + { + return Enumerable.Range(0, array.GetLength(0)) + .Select(Row) + .ToArray(); + + T[] Row(int row) => Enumerable.Range(0, array.GetLength(1)).Select(col => array[row, col]).ToArray(); + } + } +} \ No newline at end of file diff --git a/generators/Helpers/EmbeddedResource.cs b/generators/Helpers/EmbeddedResource.cs new file mode 100644 index 0000000000..8e1e9639ee --- /dev/null +++ b/generators/Helpers/EmbeddedResource.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace Exercism.CSharp.Helpers +{ + public static class EmbeddedResource + { + public static string Read(string name) + { + using (var stream = typeof(EmbeddedResource).Assembly.GetManifestResourceStream(name)) + using (var streamReader = new StreamReader(stream)) + { + return streamReader.ReadToEnd(); + } + } + } +} diff --git a/generators/Helpers/EnumerableExtensions.cs b/generators/Helpers/EnumerableExtensions.cs new file mode 100644 index 0000000000..1e033c3e6c --- /dev/null +++ b/generators/Helpers/EnumerableExtensions.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Exercism.CSharp.Helpers +{ + public static class EnumerableExtensions + { + public static SortedSet ToSortedSet(this IEnumerable source) + => new SortedSet(source); + } +} \ No newline at end of file diff --git a/generators/Helpers/NameExtensions.cs b/generators/Helpers/NameExtensions.cs new file mode 100644 index 0000000000..d91690a6ec --- /dev/null +++ b/generators/Helpers/NameExtensions.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Humanizer; + +namespace Exercism.CSharp.Helpers +{ + public static class NameExtensions + { + private static readonly HashSet ValueTupleTypes = new HashSet(new[] + { + typeof(ValueTuple<>), + typeof(ValueTuple<,>), + typeof(ValueTuple<,,>), + typeof(ValueTuple<,,,>), + typeof(ValueTuple<,,,,>), + typeof(ValueTuple<,,,,,>), + typeof(ValueTuple<,,,,,,>), + typeof(ValueTuple<,,,,,,,>) + }); + + public static string ToExerciseName(this Type exerciseType) => exerciseType.Name.ToExerciseName(); + + public static string ToExerciseName(this string input) => input.Kebaberize(); + + public static string ToTestClassName(this string input) => $"{input.Dehumanize()}Test"; + + public static string ToTestedClassName(this string input) => input.Dehumanize(); + + public static string ToTestMethodName(this string input) + { + var methodName = input + .Replace(":", " is") + .Replace("'", ""); + + methodName = Regex.Replace(methodName, @"[^\w]+", "_", RegexOptions.Compiled) + .Transform(To.TitleCase); + + if (char.IsDigit(methodName[0])) + return "Number_" + methodName; + + return !char.IsLetter(methodName[0]) ? "Test_" : methodName; + } + + public static string ToTestedMethodName(this string input) => input.ToMethodName(); + + public static string ToMethodName(this string input) => input.Dehumanize(); + + public static string ToVariableName(this string input) => input.Camelize(); + + public static string ToFriendlyName(this Type type) + { + if (type == typeof(int)) + return "int"; + if (type == typeof(short)) + return "short"; + if (type == typeof(byte)) + return "byte"; + if (type == typeof(bool)) + return "bool"; + if (type == typeof(long)) + return "long"; + if (type == typeof(float)) + return "float"; + if (type == typeof(double)) + return "double"; + if (type == typeof(decimal)) + return "decimal"; + if (type == typeof(string)) + return "string"; + if (type == typeof(char)) + return "char"; + if (type == typeof(object)) + return "object"; + if (type.IsGenericType && ValueTupleTypes.Contains(type.GetGenericTypeDefinition())) + return $"({string.Join(", ", type.GetGenericArguments().Select(ToFriendlyName))})"; + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + return $"{type.GetGenericArguments()[0].ToFriendlyName()}?"; + if (type.IsGenericType) + return $"{type.Name.Split('`')[0]}<{string.Join(", ", type.GetGenericArguments().Select(ToFriendlyName))}>"; + if (type.IsArray) + return $"{type.GetElementType().ToFriendlyName()}[]"; + return type.Name; + } + } +} \ No newline at end of file diff --git a/generators/Input/CanonicalData.cs b/generators/Input/CanonicalData.cs index 1359c97859..f2b6133ab4 100644 --- a/generators/Input/CanonicalData.cs +++ b/generators/Input/CanonicalData.cs @@ -1,14 +1,14 @@ -namespace Generators.Input +using System.Collections.Generic; + +namespace Exercism.CSharp.Input { public class CanonicalData { - public CanonicalData(string exercise, string version, CanonicalDataCase[] cases) + public CanonicalData(string exercise, string version, IReadOnlyCollection cases) => (Exercise, Version, Cases) = (exercise, version, cases); - public string Exercise { get; set; } - + public string Exercise { get; } public string Version { get; } - - public CanonicalDataCase[] Cases { get; } + public IReadOnlyCollection Cases { get; } } } \ No newline at end of file diff --git a/generators/Input/CanonicalDataCase.cs b/generators/Input/CanonicalDataCase.cs index 1c1b4e243f..c832eb378a 100644 --- a/generators/Input/CanonicalDataCase.cs +++ b/generators/Input/CanonicalDataCase.cs @@ -1,48 +1,19 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; +using System.Collections.Generic; -namespace Generators.Input +namespace Exercism.CSharp.Input { public class CanonicalDataCase { - public IDictionary Properties { get; set; } - public IDictionary Input { get; set; } - public dynamic Expected { get; set; } - - public string Property { get; set; } - public string Description { get; set; } - public string[] DescriptionPath { get; set; } - - public bool UseVariablesForInput { get; set; } - public bool UseVariableForExpected { get; set; } - public bool UseVariablesForConstructorParameters { get; set; } - public bool UseVariableForTested { get; set; } - public bool UseFullDescriptionPath { get; set; } - - public TestedMethodType TestedMethodType { get; set; } - public Type ExceptionThrown { get; set; } - - public HashSet InputParameters { get; } = new HashSet(); - public HashSet ConstructorInputParameters { get; } = new HashSet(); - - public void SetInputParameters(params string[] properties) - { - InputParameters.Clear(); - InputParameters.UnionWith(properties); - - ConstructorInputParameters.ExceptWith(properties); - } - - public void SetConstructorInputParameters(params string[] properties) - { - ConstructorInputParameters.Clear(); - ConstructorInputParameters.UnionWith(properties); - - InputParameters.ExceptWith(properties); - - TestedMethodType = TestedMethodType.Instance; - } + public CanonicalDataCase(int index, string property, IReadOnlyDictionary input, + dynamic expected, string description, IReadOnlyCollection descriptionPath) + => (Index, Property, Input, Expected, Description, DescriptionPath) = + (index, property, input, expected, description, descriptionPath); + + public int Index { get; } + public IReadOnlyDictionary Input { get; } + public dynamic Expected { get; } + public string Property { get; } + public string Description { get; } + public IReadOnlyCollection DescriptionPath { get; } } } \ No newline at end of file diff --git a/generators/Input/CanonicalDataCaseParser.cs b/generators/Input/CanonicalDataCaseParser.cs index 9452347c82..89883ea90e 100644 --- a/generators/Input/CanonicalDataCaseParser.cs +++ b/generators/Input/CanonicalDataCaseParser.cs @@ -1,170 +1,46 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; -namespace Generators.Input +namespace Exercism.CSharp.Input { public static class CanonicalDataCaseParser { - private const string TokensPath = "$..*[?(@.property)]"; - - public static CanonicalDataCase[] Parse(JArray canonicalDataCasesJArray) - => canonicalDataCasesJArray - .SelectTokens(TokensPath) - .Select(Parse) + public static IReadOnlyCollection Parse(JToken canonicalDataCaseJToken) + => GetCanonicalDataCaseTokens(canonicalDataCaseJToken) + .Select(ParseWithIndex) .ToArray(); - private static CanonicalDataCase Parse(JToken canonicalDataCaseJToken) + private static IEnumerable GetCanonicalDataCaseTokens(JToken currentJToken) { - var canonicalDataCase = new CanonicalDataCase + switch (currentJToken) { - Property = canonicalDataCaseJToken.Value("property"), - Properties = ToDictionary(canonicalDataCaseJToken), - Input = ToDictionary(canonicalDataCaseJToken["input"]), - Expected = ConvertJToken(canonicalDataCaseJToken["expected"]), - Description = canonicalDataCaseJToken.Value("description"), - DescriptionPath = GetDescriptionPath(canonicalDataCaseJToken) - }; - canonicalDataCase.SetInputParameters(canonicalDataCase.Input.Keys.ToArray()); - - return canonicalDataCase; - } - - private static string[] GetDescriptionPath(JToken canonicalDataCaseToken) - { - var descriptionPath = new Stack(); - var currentToken = canonicalDataCaseToken; - - while (currentToken != null) - { - if (currentToken.Type == JTokenType.Object) - { - var description = currentToken.SelectToken("description"); - if (description == null) - break; - - descriptionPath.Push(description.ToObject()); - } - - currentToken = currentToken.Parent; - } - - return descriptionPath.Where(x => !string.IsNullOrEmpty(x)).ToArray(); - } - - private static IDictionary ToDictionary(JToken jToken) => ConvertJToken(jToken); - - private static dynamic ConvertJToken(JToken jToken) - { - switch (jToken?.Type) - { - case JTokenType.Object: - return ConvertJObject((JObject)jToken); - case JTokenType.Array: - return ConvertJArray((JArray)jToken); - case JTokenType.Property: - return jToken.ToObject>(); - case JTokenType.Integer: - return ConvertIntegerJToken(jToken); - case JTokenType.Float: - return jToken.ToObject(); - case JTokenType.String: - return jToken.ToObject(); - case JTokenType.Boolean: - return jToken.ToObject(); - case JTokenType.Date: - return jToken.ToObject(); - case JTokenType.Raw: - return jToken.ToObject(); - case JTokenType.Bytes: - return jToken.ToObject(); - case JTokenType.Guid: - return jToken.ToObject(); - case JTokenType.Uri: - return jToken.ToObject(); - case JTokenType.TimeSpan: - return jToken.ToObject(); + case JArray jArray: + return jArray.SelectMany(GetCanonicalDataCaseTokens); + case JObject jObject when jObject.TryGetValue("cases", out var casesJToken) && casesJToken is JArray childJArray: + return childJArray.SelectMany(GetCanonicalDataCaseTokens); + case JObject jObject when jObject.ContainsKey("property"): + return new[] { jObject }; default: - return null; + return Enumerable.Empty(); } } - private static dynamic ConvertJObject(JObject jObject) - { - var properties = jObject.ToObject>(); - - for (var i = 0; i < properties.Count; i++) - { - var key = properties.Keys.ElementAt(i); - var value = properties[key]; - properties[key] = value is JToken jToken ? ConvertJToken(jToken) : value; - } - - return properties; - } - - private static dynamic ConvertJArray(JArray jArray) - { - // We can't determine the type of the array if the array is empty - if (!jArray.Any()) - return jArray; - - // We can only convert when all values have the same type - if (jArray.Select(x => x.Type).Distinct().Count() != 1) - return jArray; - - switch (jArray[0].Type) - { - case JTokenType.Object: - return jArray.Select(ConvertJToken).ToArray(); - case JTokenType.Integer: - var strings = jArray.ToObject(); - if (strings.All(str => int.TryParse(str, out var _))) - return jArray.ToObject(); - - if (strings.All(str => long.TryParse(str, out var _))) - return jArray.ToObject(); - - if (strings.All(str => ulong.TryParse(str, out var _))) - return jArray.ToObject(); - - return strings; - case JTokenType.Float: - return jArray.ToObject(); - case JTokenType.String: - return jArray.ToObject(); - case JTokenType.Boolean: - return jArray.ToObject(); - case JTokenType.Date: - return jArray.ToObject(); - case JTokenType.Bytes: - return jArray.ToObject(); - case JTokenType.Guid: - return jArray.ToObject(); - case JTokenType.Uri: - return jArray.ToObject(); - case JTokenType.TimeSpan: - return jArray.ToObject(); - default: - return jArray; - } - } - - private static dynamic ConvertIntegerJToken(JToken jToken) - { - var str = jToken.ToObject(); - - if (int.TryParse(str, out var i)) - return i; - - if (long.TryParse(str, out var l)) - return l; - - if (ulong.TryParse(str, out var ul)) - return ul; - - return str; - } + private static CanonicalDataCase ParseWithIndex(JToken canonicalDataCaseJToken, int index) + => new CanonicalDataCase( + index: index, + property: canonicalDataCaseJToken.Value("property"), + input: JTokenHelper.ConvertJToken(canonicalDataCaseJToken["input"]), + expected: JTokenHelper.ConvertJToken(canonicalDataCaseJToken["expected"]), + description: canonicalDataCaseJToken.Value("description"), + descriptionPath: GetDescriptionPath(canonicalDataCaseJToken)); + + private static string[] GetDescriptionPath(JToken canonicalDataCaseJToken) + => canonicalDataCaseJToken.ParentsAndSelf() + .Where(token => token.Type == JTokenType.Object) + .Select(token => token.Value("description")) + .Where(description => description != null) + .Reverse() + .ToArray(); } } diff --git a/generators/Input/CanonicalDataFile.cs b/generators/Input/CanonicalDataFile.cs index 8c91b89cec..135642e129 100644 --- a/generators/Input/CanonicalDataFile.cs +++ b/generators/Input/CanonicalDataFile.cs @@ -3,7 +3,7 @@ using LibGit2Sharp; using Serilog; -namespace Generators.Input +namespace Exercism.CSharp.Input { public class CanonicalDataFile { @@ -14,16 +14,13 @@ public class CanonicalDataFile private readonly Options _options; - public CanonicalDataFile(Options options) - { - _options = options; - } + public CanonicalDataFile(Options options) => _options = options; public bool Exists(string exercise) => File.Exists(GetExerciseCanonicalDataPath(exercise)); public string Contents(string exercise) => File.ReadAllText(GetExerciseCanonicalDataPath(exercise)); - private string GetExerciseCanonicalDataPath(string exercise) + private string GetExerciseCanonicalDataPath(string exercise) => Path.Combine(_options.CanonicalDataDirectory, "exercises", exercise, "canonical-data.json"); public void DownloadData() @@ -55,10 +52,10 @@ private void UpdateToLatestVersion() using (var repository = new Repository(_options.CanonicalDataDirectory)) { Commands.Fetch(repository, ProblemSpecificationsRemote, Enumerable.Empty(), new FetchOptions(), null); - + var remoteBranch = repository.Branches[ProblemSpecificationsRemoteBranch]; repository.Reset(ResetMode.Hard, remoteBranch.Tip); - } + } Log.Information("Updated repository to latest version."); } diff --git a/generators/Input/CanonicalDataParser.cs b/generators/Input/CanonicalDataParser.cs index 4229b7471e..f72ba65fb3 100644 --- a/generators/Input/CanonicalDataParser.cs +++ b/generators/Input/CanonicalDataParser.cs @@ -1,6 +1,7 @@ -using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; -namespace Generators.Input +namespace Exercism.CSharp.Input { public class CanonicalDataParser { @@ -13,17 +14,18 @@ public CanonicalData Parse(string exercise) var canonicalDataJsonContents = _canonicalDataFile.Contents(exercise); var canonicalDataJson = JObject.Parse(canonicalDataJsonContents); - var name = ParseName(canonicalDataJson); + var exerciseName = ParseExerciseName(canonicalDataJson); var version = ParseVersion(canonicalDataJson); var canonicalDataCases = ParseCanonicalDataCases(canonicalDataJson); - return new CanonicalData(name, version, canonicalDataCases); + return new CanonicalData(exerciseName, version, canonicalDataCases); } - private static string ParseName(JToken canonicalDataJObject) => canonicalDataJObject.Value("exercise"); + private static string ParseExerciseName(JToken canonicalDataJObject) => canonicalDataJObject.Value("exercise"); private static string ParseVersion(JToken canonicalDataJObject) => canonicalDataJObject.Value("version"); - private static CanonicalDataCase[] ParseCanonicalDataCases(JObject canonicalDataJObject) => CanonicalDataCaseParser.Parse((JArray)canonicalDataJObject["cases"]); + private static IReadOnlyCollection ParseCanonicalDataCases(JObject canonicalDataJObject) + => CanonicalDataCaseParser.Parse((JArray)canonicalDataJObject["cases"]); } } \ No newline at end of file diff --git a/generators/Input/ConvertHelper.cs b/generators/Input/ConvertHelper.cs deleted file mode 100644 index 81b0c66216..0000000000 --- a/generators/Input/ConvertHelper.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Generators.Input -{ - public static class ConvertHelper - { - public static string ToMultiLineString(this object obj) => string.Join("\n", obj as object[]); - - public static string ToMultiLineString(this object obj, string empty) - { - var arr = obj as object[]; - - if (arr == null || arr.Length == 0) - return empty; - - return string.Join("\n", obj as object[]); - } - - public static T[] ToArray(this object obj) - { - var arr = obj as T[]; - - if (arr == null || arr.Length == 0) - return new T[0]; - - return arr; - } - } -} \ No newline at end of file diff --git a/generators/Input/JTokenHelper.cs b/generators/Input/JTokenHelper.cs new file mode 100644 index 0000000000..02a15c6763 --- /dev/null +++ b/generators/Input/JTokenHelper.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Input +{ + public static class JTokenHelper + { + public static IEnumerable ParentsAndSelf(this JToken jToken) + { + while (jToken != null) + { + yield return jToken; + jToken = jToken.Parent; + } + } + + public static dynamic ConvertJToken(JToken jToken) + { + switch (jToken) + { + case JObject jObject: + return ConvertJObject(jObject); + case JArray jArray: + return ConvertJArray(jArray); + } + + switch (jToken.Type) + { + case JTokenType.Integer: + return ConvertJTokenToInteger(jToken); + case JTokenType.Float: + return jToken.ToObject(); + case JTokenType.String: + return jToken.ToObject(); + case JTokenType.Boolean: + return jToken.ToObject(); + case JTokenType.Date: + return jToken.ToObject(); + default: + return null; + } + } + + private static dynamic ConvertJObject(JObject jObject) + { + var properties = jObject.ToObject>(); + + for (var i = 0; i < properties.Count; i++) + { + var key = properties.Keys.ElementAt(i); + var value = properties[key]; + properties[key] = value is JToken jToken ? ConvertJToken(jToken) : value; + } + + return new Dictionary(properties, StringComparer.OrdinalIgnoreCase); + } + + private static dynamic ConvertJArray(JArray jArray) + { + // We can't determine the type of the array if the array is empty + if (!jArray.Any()) + return jArray; + + // We can only convert when all values have the same type + if (jArray.Select(x => x.Type).Distinct().Count() != 1) + return jArray; + + switch (jArray[0].Type) + { + case JTokenType.Object: + return jArray.Select(ConvertJToken).ToArray(); + case JTokenType.Integer: + var strings = jArray.ToObject(); + if (strings.All(str => int.TryParse(str, out _))) + return jArray.ToObject(); + + if (strings.All(str => long.TryParse(str, out _))) + return jArray.ToObject(); + + if (strings.All(str => ulong.TryParse(str, out _))) + return jArray.ToObject(); + + return strings; + case JTokenType.Float: + return jArray.ToObject(); + case JTokenType.String: + return jArray.ToObject(); + case JTokenType.Boolean: + return jArray.ToObject(); + case JTokenType.Date: + return jArray.ToObject(); + default: + return jArray; + } + } + + private static dynamic ConvertJTokenToInteger(JToken jToken) + { + var str = jToken.ToObject(); + + if (int.TryParse(str, out var i)) + return i; + + if (long.TryParse(str, out var l)) + return l; + + if (ulong.TryParse(str, out var ul)) + return ul; + + return str; + } + } +} \ No newline at end of file diff --git a/generators/Input/ConfigFile.cs b/generators/Input/TrackConfigFile.cs similarity index 65% rename from generators/Input/ConfigFile.cs rename to generators/Input/TrackConfigFile.cs index 55fc22fc0d..996c510afc 100644 --- a/generators/Input/ConfigFile.cs +++ b/generators/Input/TrackConfigFile.cs @@ -1,30 +1,29 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Exercism.CSharp.Helpers; using Newtonsoft.Json; -using Generators.Output; -namespace Generators.Input +namespace Exercism.CSharp.Input { - public static class ConfigFile + public static class TrackConfigFile { - private const string ConfigFilePath = "../config.json"; + private static readonly string ConfigFilePath = Path.Combine("..", "config.json"); public static IEnumerable GetExercises() { var jsonContents = File.ReadAllText(ConfigFilePath); var config = JsonConvert.DeserializeObject(jsonContents); - return config.Exercises.OrderBy(x => x.Name).ToArray(); + return config.Exercises.OrderBy(x => x.Slug).ToArray(); } - private class Config + private sealed class Config { public ConfigExercise[] Exercises { get; set; } } public class ConfigExercise { - public string Name => Slug.ToExerciseName(); public string Slug { get; set; } public bool Deprecated { get; set; } } diff --git a/generators/Options.cs b/generators/Options.cs index 5817b3ab0f..dfb4fdea0e 100644 --- a/generators/Options.cs +++ b/generators/Options.cs @@ -2,14 +2,14 @@ using System.IO; using CommandLine; -namespace Generators +namespace Exercism.CSharp { public class Options { private static string DefaultCanonicalDataDirectory => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "exercism", "problem-specifications"); - [Option('e', "exercise", Required = false, + [Option('e', "exercise", Required = false, HelpText = "Exercise to generate (defaults to all exercises).")] public string Exercise { get; set; } diff --git a/generators/Output/ExerciseWriter.cs b/generators/Output/ExerciseWriter.cs deleted file mode 100644 index 728096c1cf..0000000000 --- a/generators/Output/ExerciseWriter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.IO; - -namespace Generators.Output -{ - public class ExerciseWriter - { - public virtual void WriteToFile(GeneratorExercise generatorExercise) - { - var testClassFilePath = TestClassFilePath(generatorExercise); - var testClassContents = generatorExercise.Render(); - - Directory.CreateDirectory(Path.GetDirectoryName(testClassFilePath)); - File.WriteAllText(testClassFilePath, testClassContents); - } - - private static string TestClassFilePath(GeneratorExercise generatorExercise) => Path.Combine("..", "exercises", generatorExercise.Name, TestClassFileName(generatorExercise)); - - private static string TestClassFileName(GeneratorExercise generatorExercise) => $"{generatorExercise.Name.ToTestClassName()}.cs"; - } -} \ No newline at end of file diff --git a/generators/Output/FormattingExtensions.cs b/generators/Output/FormattingExtensions.cs deleted file mode 100644 index 0f5c48381e..0000000000 --- a/generators/Output/FormattingExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Generators.Output -{ - public static class FormattingExtensions - { - public static string Indent(this string str, int level = 1) => $"{new string(' ', 4 * level)}{str}"; - - public static string EscapeSpecialCharacters(this string s) - => s.Replace("\n", "\\n") - .Replace("\t", "\\t") - .Replace("\r", "\\r") - .Replace("\"", "\\\""); - - public static string Quote(this string s) => $"\"{s}\""; - - public static IEnumerable AddTrailingSemicolon(this IEnumerable enumerable) - { - var array = enumerable.ToArray(); - array[array.Length - 1] += ";"; - return array; - } - } -} diff --git a/generators/Output/NameExtensions.cs b/generators/Output/NameExtensions.cs deleted file mode 100644 index e3c7121b23..0000000000 --- a/generators/Output/NameExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Text.RegularExpressions; -using Humanizer; - -namespace Generators.Output -{ - public static class NameExtensions - { - public static string ToExerciseName(this Type exerciseType) => exerciseType.Name.ToExerciseName(); - - public static string ToExerciseName(this string input) => input.Kebaberize(); - - public static string ToTestClassName(this string input) => $"{input.Dehumanize()}Test"; - - public static string ToTestedClassName(this string input) => input.Dehumanize(); - - public static string ToTestMethodName(this string input) - { - var methodName = input - .Replace(":", " is") - .Replace("'", ""); - - methodName = Regex.Replace(methodName, @"[^\w]+", "_", RegexOptions.Compiled) - .Transform(To.TitleCase); - - if (char.IsDigit(methodName[0])) - return "Number_" + methodName; - - if (!char.IsLetter(methodName[0])) - return "Test_"; - - return methodName; - } - - public static string ToTestedMethodName(this string input) => input.Dehumanize(); - - public static string ToVariableName(this string input) => input.Camelize(); - } -} \ No newline at end of file diff --git a/generators/Output/IndentFilter.cs b/generators/Output/Rendering/IndentFilter.cs similarity index 65% rename from generators/Output/IndentFilter.cs rename to generators/Output/Rendering/IndentFilter.cs index fc3a6d6f44..812006b020 100644 --- a/generators/Output/IndentFilter.cs +++ b/generators/Output/Rendering/IndentFilter.cs @@ -1,11 +1,11 @@ using System; using System.Linq; -namespace Generators.Output +namespace Exercism.CSharp.Output.Rendering { - public class IndentFilter + public static class IndentFilter { - public static string Indent(string input) + public static string Indent(string input) => string.Join(Environment.NewLine, input .Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Indent())); diff --git a/generators/Output/Rendering/MultiLineString.cs b/generators/Output/Rendering/MultiLineString.cs new file mode 100644 index 0000000000..1e13fe76f5 --- /dev/null +++ b/generators/Output/Rendering/MultiLineString.cs @@ -0,0 +1,28 @@ +using System; +using Newtonsoft.Json.Linq; + +namespace Exercism.CSharp.Output.Rendering +{ + public class MultiLineString + { + public MultiLineString(object obj) + { + switch (obj) + { + case string[] lines: + Lines = lines; + break; + case string line: + Lines = line.Split("\n"); + break; + case JArray _: + Lines = Array.Empty(); + break; + default: + throw new ArgumentException("Unsupported multi-line string type", nameof(obj)); + } + } + + public string[] Lines { get; } + } +} diff --git a/generators/Output/Rendering/Render.cs b/generators/Output/Rendering/Render.cs new file mode 100644 index 0000000000..85249f2a51 --- /dev/null +++ b/generators/Output/Rendering/Render.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string Object(object val) + { + if (val == null) + return "null"; + + switch (val) + { + case string str: return String(str); + case double dbl: return Double(dbl); + case int i: return Int(i); + case uint ui: return Uint(ui); + case float flt: return Float(flt); + case ulong ulng: return Ulong(ulng); + case char c: return Char(c); + case DateTime dateTime: return DateTime(dateTime); + case Regex regex: return Regex(regex); + default: + if (IsList(val)) + return List((dynamic)val); + + if (IsArray(val)) + return Array((dynamic)val); + + if (IsDictionary(val)) + return Dictionary((dynamic)val); + + return val.ToString(); + } + } + + public string ObjectMultiLine(object val) + { + if (val == null) + return "null"; + + switch (val) + { + case MultiLineString multiLineValue: + return StringMultiLine(multiLineValue); + default: + if (IsDictionary(val)) + return DictionaryMultiLine((dynamic) val); + + if (IsArray(val)) + return RenderArrayAsMultiline((dynamic) val) + ? ArrayMultiLine((dynamic) val) + : Array((dynamic) val); + + return Object(val); + } + } + + private static bool IsList(object obj) + => obj.GetType().IsGenericType && obj.GetType().GetGenericTypeDefinition() == typeof(List<>); + + private static bool IsArray(object obj) + => obj.GetType().IsArray; + + private static bool IsDictionary(object obj) + => obj.GetType().IsGenericType && obj.GetType().GetGenericTypeDefinition() == typeof(Dictionary<,>); + + private static bool RenderArrayAsMultiline(T[,] _) => true; + + private static bool RenderArrayAsMultiline(T[] elements) + => IsNestedArray(elements) && elements.Length > 0; + + private static bool IsNestedArray(T[] elements) + => elements.GetType().GetElementType().IsArray; + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderArray.cs b/generators/Output/Rendering/RenderArray.cs new file mode 100644 index 0000000000..1b0ccc77c7 --- /dev/null +++ b/generators/Output/Rendering/RenderArray.cs @@ -0,0 +1,27 @@ +using Exercism.CSharp.Helpers; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string Array(T[] elements) => + elements.Length == 0 + ? $"Array.Empty<{typeof(T).ToFriendlyName()}>()" + : $"new[]{CollectionInitializer(elements)}"; + + public string ArrayMultiLine(T[] elements) + => elements.Length == 0 + ? $"Array.Empty<{typeof(T).ToFriendlyName()}>()" + : $"new[]{MultiLineCollectionInitializer(elements)}"; + + public string Array(T[,] elements) + => elements.Length == 0 + ? $"new {typeof(T).ToFriendlyName()}[,] {{ }}" + : $"new[,]{CollectionInitializer(elements.Rows())}"; + + public string ArrayMultiLine(T[,] elements) + => elements.Length == 0 + ? $"new {typeof(T).ToFriendlyName()}[,] {{ }}" + : $"new[,]{MultiLineCollectionInitializer(elements.Rows(), CollectionInitializer)}"; + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderAssert.cs b/generators/Output/Rendering/RenderAssert.cs new file mode 100644 index 0000000000..4f857fd52b --- /dev/null +++ b/generators/Output/Rendering/RenderAssert.cs @@ -0,0 +1,37 @@ +using System; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string AssertNull(string actual) + => RenderTemplate("AssertNull", new { actual }); + + public string AssertEmpty(string expected, string actual) + => RenderTemplate("AssertEmpty", new { expected, actual }); + + public string AssertEqual(string expected, string actual) + => RenderTemplate("AssertEqual", new { expected, actual }); + + public string AssertEqualWithin(string expected, string actual, int precision) + => RenderTemplate("AssertEqualWithin", new { expected, actual, precision }); + + public string AssertNotEqual(string expected, string actual) + => RenderTemplate("AssertNotEqual", new { expected, actual }); + + public string AssertBoolean(bool expected, string actual) + => RenderTemplate("AssertBoolean", new { expected = expected.ToString(), actual }); + + public string AssertMatches(string expected, string actual) + => RenderTemplate("AssertMatches", new { expected, actual }); + + public string AssertThrows(Type expectedException, string actual) + => RenderTemplate("AssertThrows", new { expected = expectedException.Name, actual }); + + public string AssertThrows(string actual) + => AssertThrows(typeof(T), actual); + + private static string RenderTemplate(string template, object parameters) + => Template.Render(template, parameters); + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderCollection.cs b/generators/Output/Rendering/RenderCollection.cs new file mode 100644 index 0000000000..a014bdd4d6 --- /dev/null +++ b/generators/Output/Rendering/RenderCollection.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string CollectionInitializer(IEnumerable elements) + => CollectionInitializer(elements, line => Object(line), " "); + + public string CollectionInitializer(IEnumerable elements, Func render) + => CollectionInitializer(elements, render, " "); + + public string MultiLineCollectionInitializer(IEnumerable elements) + => CollectionInitializer(elements, line => Object(line).Indent(), Environment.NewLine); + + public string MultiLineCollectionInitializer(IEnumerable elements, Func render) + => CollectionInitializer(elements, line => render(line).Indent(), Environment.NewLine); + + private static string CollectionInitializer(IEnumerable elements, Func render, string separator) + => $"{separator}{{{separator}{string.Join($",{separator}", elements.Select(render))}{separator}}}"; + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderDateTime.cs b/generators/Output/Rendering/RenderDateTime.cs new file mode 100644 index 0000000000..ebd570a67a --- /dev/null +++ b/generators/Output/Rendering/RenderDateTime.cs @@ -0,0 +1,14 @@ +using System; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string DateTime(DateTime dateTime) + { + return dateTime.Hour == 0 && dateTime.Minute == 0 && dateTime.Second == 0 + ? $"new DateTime({dateTime.Year}, {dateTime.Month}, {dateTime.Day})" + : $"new DateTime({dateTime.Year}, {dateTime.Month}, {dateTime.Day}, {dateTime.Hour}, {dateTime.Minute}, {dateTime.Second})"; + } + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderDictionary.cs b/generators/Output/Rendering/RenderDictionary.cs new file mode 100644 index 0000000000..81a315214a --- /dev/null +++ b/generators/Output/Rendering/RenderDictionary.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Exercism.CSharp.Helpers; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string Dictionary(IDictionary dict) => + dict.Count == 0 + ? $"new Dictionary<{typeof(TKey).ToFriendlyName()}, {typeof(TValue).ToFriendlyName()}>()" + : $"new Dictionary<{typeof(TKey).ToFriendlyName()}, {typeof(TValue).ToFriendlyName()}>{CollectionInitializer(dict, KeyValueAssignment)}"; + + public string DictionaryMultiLine(IDictionary dict) => + dict.Count == 0 + ? $"new Dictionary<{typeof(TKey).ToFriendlyName()}, {typeof(TValue).ToFriendlyName()}>()" + : $"new Dictionary<{typeof(TKey).ToFriendlyName()}, {typeof(TValue).ToFriendlyName()}>{MultiLineCollectionInitializer(dict, KeyValueAssignment)}"; + + private string KeyValueAssignment(KeyValuePair kv) => $"[{Object(kv.Key)}] = {Object(kv.Value)}"; + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderExtensions.cs b/generators/Output/Rendering/RenderExtensions.cs new file mode 100644 index 0000000000..dd001363d9 --- /dev/null +++ b/generators/Output/Rendering/RenderExtensions.cs @@ -0,0 +1,19 @@ +namespace Exercism.CSharp.Output.Rendering +{ + public static class RenderExtensions + { + private const int IndentSize = 4; + + public static string Indent(this string str) => $"{new string(' ', IndentSize)}{str}"; + + public static string EscapeSpecialCharacters(this string str) + => str.Replace("\n", "\\n") + .Replace("\t", "\\t") + .Replace("\r", "\\r") + .Replace("\"", "\\\""); + + public static string Quote(this string str) => $"\"{str}\""; + + public static string Quote(this char c) => $"'{c}'"; + } +} diff --git a/generators/Output/Rendering/RenderList.cs b/generators/Output/Rendering/RenderList.cs new file mode 100644 index 0000000000..2243eb5ec3 --- /dev/null +++ b/generators/Output/Rendering/RenderList.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Helpers; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string List(List elements) => + elements.Any() + ? $"new List<{typeof(T).ToFriendlyName()}>{CollectionInitializer(elements)}" + : $"new List<{typeof(T).ToFriendlyName()}>()"; + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderNumber.cs b/generators/Output/Rendering/RenderNumber.cs new file mode 100644 index 0000000000..e6a17eab31 --- /dev/null +++ b/generators/Output/Rendering/RenderNumber.cs @@ -0,0 +1,17 @@ +using System.Globalization; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public string Double(double dbl) => dbl.ToString(CultureInfo.InvariantCulture); + + public string Float(float flt) => flt.ToString(CultureInfo.InvariantCulture); + + public string Int(int i) => i.ToString(CultureInfo.InvariantCulture); + + public string Ulong(ulong ulng) => $"{ulng}UL"; + + public string Uint(uint ui) => string.Format("0x{0:X}u", ui); + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderString.cs b/generators/Output/Rendering/RenderString.cs new file mode 100644 index 0000000000..35a3eace25 --- /dev/null +++ b/generators/Output/Rendering/RenderString.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Humanizer; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public UnescapedValue Enum(string enumType, string enumCase) + => new UnescapedValue($"{enumType}.{enumCase.ToLower().Dehumanize()}"); + + public string Char(char c) => c.Quote(); + + public string String(string s) => s.EscapeSpecialCharacters().Quote(); + + public string StringMultiLine(MultiLineString multiLineString) + { + switch (multiLineString.Lines.Length) + { + case 0: + return String(string.Empty); + case 1: + return String(multiLineString.Lines[0]); + default: + return $"{Environment.NewLine}{string.Join(Environment.NewLine, RenderLines())}"; + } + + IEnumerable RenderLines() => + multiLineString.Lines.Select((t, i) => i < multiLineString.Lines.Length - 1 + ? $"{String($"{t}\n").Indent()} +" + : $"{String(t).Indent()}"); + } + + public string Regex(Regex regex) => String(regex.ToString()); + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/RenderVariable.cs b/generators/Output/Rendering/RenderVariable.cs new file mode 100644 index 0000000000..fc6e9d0b4c --- /dev/null +++ b/generators/Output/Rendering/RenderVariable.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Helpers; + +namespace Exercism.CSharp.Output.Rendering +{ + public partial class Render + { + public IEnumerable Variables(IDictionary variables) + => variables.Select(Variable).ToArray(); + + private string Variable(KeyValuePair variable) + => Variable(variable.Key.ToVariableName(), ObjectMultiLine(variable.Value)); + + public string Variable(string name, string value) => $"var {name} = {value};"; + } +} \ No newline at end of file diff --git a/generators/Output/Rendering/Template.cs b/generators/Output/Rendering/Template.cs new file mode 100644 index 0000000000..b034381b5d --- /dev/null +++ b/generators/Output/Rendering/Template.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using DotLiquid; +using DotLiquid.FileSystems; + +namespace Exercism.CSharp.Output.Rendering +{ + public static class Template + { + private static readonly string EmbeddedTemplatesNamespace = $"{typeof(Template).Namespace}.Templates"; + + static Template() + { + DotLiquid.Template.RegisterFilter(typeof(IndentFilter)); + DotLiquid.Template.FileSystem = new EmbeddedFileSystem(Assembly.GetEntryAssembly(), EmbeddedTemplatesNamespace); + } + + public static string Render(string template, object parameters) + => DotLiquid.Template.Parse($"{{% include \"{template}\" %}}").Render(Hash.FromAnonymousObject(parameters)); + } +} \ No newline at end of file diff --git a/generators/Output/Templates/_Act.liquid b/generators/Output/Rendering/Templates/_Act.liquid similarity index 100% rename from generators/Output/Templates/_Act.liquid rename to generators/Output/Rendering/Templates/_Act.liquid diff --git a/generators/Output/Templates/_Arrange.liquid b/generators/Output/Rendering/Templates/_Arrange.liquid similarity index 100% rename from generators/Output/Templates/_Arrange.liquid rename to generators/Output/Rendering/Templates/_Arrange.liquid diff --git a/generators/Output/Rendering/Templates/_AssertBoolean.liquid b/generators/Output/Rendering/Templates/_AssertBoolean.liquid new file mode 100644 index 0000000000..09377ab8b1 --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertBoolean.liquid @@ -0,0 +1 @@ +Assert.{{ expected }}({{ actual }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_AssertEmpty.liquid b/generators/Output/Rendering/Templates/_AssertEmpty.liquid new file mode 100644 index 0000000000..e9c3bd6d5d --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertEmpty.liquid @@ -0,0 +1 @@ +Assert.Empty({{ actual }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_AssertEqual.liquid b/generators/Output/Rendering/Templates/_AssertEqual.liquid new file mode 100644 index 0000000000..2333a5bfea --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertEqual.liquid @@ -0,0 +1 @@ +Assert.Equal({{ expected }}, {{ actual }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_AssertEqualWithin.liquid b/generators/Output/Rendering/Templates/_AssertEqualWithin.liquid new file mode 100644 index 0000000000..3bb7756cf2 --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertEqualWithin.liquid @@ -0,0 +1 @@ +Assert.Equal({{ expected }}, {{ actual }}, precision: {{ precision }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_AssertMatches.liquid b/generators/Output/Rendering/Templates/_AssertMatches.liquid new file mode 100644 index 0000000000..d84f82b6e2 --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertMatches.liquid @@ -0,0 +1 @@ +Assert.Matches({{ expected }}, {{ actual }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_AssertNotEqual.liquid b/generators/Output/Rendering/Templates/_AssertNotEqual.liquid new file mode 100644 index 0000000000..b3af0ab819 --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertNotEqual.liquid @@ -0,0 +1 @@ +Assert.NotEqual({{ expected }}, {{ actual }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_AssertNull.liquid b/generators/Output/Rendering/Templates/_AssertNull.liquid new file mode 100644 index 0000000000..3b88555e7b --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertNull.liquid @@ -0,0 +1 @@ +Assert.Null({{ actual }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_AssertThrows.liquid b/generators/Output/Rendering/Templates/_AssertThrows.liquid new file mode 100644 index 0000000000..5c700c93e6 --- /dev/null +++ b/generators/Output/Rendering/Templates/_AssertThrows.liquid @@ -0,0 +1 @@ +Assert.Throws<{{ expected }}>(() => {{ actual }}); \ No newline at end of file diff --git a/generators/Output/Rendering/Templates/_TestClass.liquid b/generators/Output/Rendering/Templates/_TestClass.liquid new file mode 100644 index 0000000000..e320d155e9 --- /dev/null +++ b/generators/Output/Rendering/Templates/_TestClass.liquid @@ -0,0 +1,14 @@ +// This file was auto-generated based on version {{Version}} of the canonical data. + +{%- for namespace in Namespaces -%} +using {{ namespace }}; +{%- endfor -%} + +public class {{ClassName}}{% if IsDisposable %} : IDisposable{% endif %} +{ +{%- for method in Methods -%} +{{ method | indent }} +{%- if forloop.last == false %} +{% endif -%} +{%- endfor -%} +} \ No newline at end of file diff --git a/generators/Output/Templates/_TestMethod.liquid b/generators/Output/Rendering/Templates/_TestMethod.liquid similarity index 57% rename from generators/Output/Templates/_TestMethod.liquid rename to generators/Output/Rendering/Templates/_TestMethod.liquid index f4960c1a34..8182578a8b 100644 --- a/generators/Output/Templates/_TestMethod.liquid +++ b/generators/Output/Rendering/Templates/_TestMethod.liquid @@ -1,5 +1,7 @@ [Fact{% if Skip %}(Skip = "Remove to run test"){% endif %}] public void {{ Name }}() { -{{ Body | indent }} +{{ Arrange | indent }} +{{ Act | indent }} +{{ Assert | indent }} } \ No newline at end of file diff --git a/generators/Output/UnescapedValue.cs b/generators/Output/Rendering/UnescapedValue.cs similarity index 87% rename from generators/Output/UnescapedValue.cs rename to generators/Output/Rendering/UnescapedValue.cs index cb97bdfac9..864c491752 100644 --- a/generators/Output/UnescapedValue.cs +++ b/generators/Output/Rendering/UnescapedValue.cs @@ -1,6 +1,6 @@ using DotLiquid; -namespace Generators.Output +namespace Exercism.CSharp.Output.Rendering { public class UnescapedValue : ILiquidizable { diff --git a/generators/Output/TemplateRenderer.cs b/generators/Output/TemplateRenderer.cs deleted file mode 100644 index 573b40af9d..0000000000 --- a/generators/Output/TemplateRenderer.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Reflection; -using DotLiquid; -using DotLiquid.FileSystems; - -namespace Generators.Output -{ - public static class TemplateRenderer - { - private static readonly string EmbeddedTemplatesNamespace = $"{typeof(TemplateRenderer).Namespace}.Templates"; - - static TemplateRenderer() - { - Template.RegisterFilter(typeof(IndentFilter)); - Template.FileSystem = new EmbeddedFileSystem(Assembly.GetEntryAssembly(), EmbeddedTemplatesNamespace); - } - - public static string RenderInline(string template, object parameters) - => Template.Parse(template).Render(Hash.FromAnonymousObject(parameters)); - - public static string RenderPartial(string template, object parameters) - => Template.Parse($"{{% include \"{template}\" %}}").Render(Hash.FromAnonymousObject(parameters)); - } -} \ No newline at end of file diff --git a/generators/Output/Templates/_AssertBoolean.liquid b/generators/Output/Templates/_AssertBoolean.liquid deleted file mode 100644 index 1b1e21bf36..0000000000 --- a/generators/Output/Templates/_AssertBoolean.liquid +++ /dev/null @@ -1 +0,0 @@ -Assert.{{ BooleanAssertMethod}}({{ TestedValue }}); \ No newline at end of file diff --git a/generators/Output/Templates/_AssertEqual.liquid b/generators/Output/Templates/_AssertEqual.liquid deleted file mode 100644 index 1103752cdb..0000000000 --- a/generators/Output/Templates/_AssertEqual.liquid +++ /dev/null @@ -1 +0,0 @@ -Assert.Equal({{ ExpectedParameter }}, {{ TestedValue }}); \ No newline at end of file diff --git a/generators/Output/Templates/_AssertEqual_Empty.liquid b/generators/Output/Templates/_AssertEqual_Empty.liquid deleted file mode 100644 index 609e5c97fa..0000000000 --- a/generators/Output/Templates/_AssertEqual_Empty.liquid +++ /dev/null @@ -1 +0,0 @@ -Assert.Empty({{ TestedValue }}); \ No newline at end of file diff --git a/generators/Output/Templates/_AssertNull.liquid b/generators/Output/Templates/_AssertNull.liquid deleted file mode 100644 index 93d9af2a94..0000000000 --- a/generators/Output/Templates/_AssertNull.liquid +++ /dev/null @@ -1 +0,0 @@ -Assert.Null({{ TestedValue }}); \ No newline at end of file diff --git a/generators/Output/Templates/_AssertThrowsException.liquid b/generators/Output/Templates/_AssertThrowsException.liquid deleted file mode 100644 index 04efd3ca5a..0000000000 --- a/generators/Output/Templates/_AssertThrowsException.liquid +++ /dev/null @@ -1 +0,0 @@ -Assert.Throws<{{ ExceptionType }}>(() => {{ TestedValue }}); \ No newline at end of file diff --git a/generators/Output/Templates/_TestClass.liquid b/generators/Output/Templates/_TestClass.liquid deleted file mode 100644 index 6fd4a50e16..0000000000 --- a/generators/Output/Templates/_TestClass.liquid +++ /dev/null @@ -1,14 +0,0 @@ -// This file was auto-generated based on version {{CanonicalDataVersion}} of the canonical data. - -{%- for namespace in UsingNamespaces -%} -using {{ namespace }}; -{%- endfor -%} - -public class {{ClassName}} -{ -{%- for method in Methods -%} -{{ method | indent }} -{%- if forloop.last == false %} -{% endif -%} -{%- endfor -%} -} \ No newline at end of file diff --git a/generators/Output/Templates/_TestClassDisposable.liquid b/generators/Output/Templates/_TestClassDisposable.liquid deleted file mode 100644 index f46dcdec94..0000000000 --- a/generators/Output/Templates/_TestClassDisposable.liquid +++ /dev/null @@ -1,14 +0,0 @@ -// This file was auto-generated based on version {{CanonicalDataVersion}} of the canonical data. - -{%- for namespace in UsingNamespaces -%} -using {{ namespace }}; -{%- endfor -%} - -public class {{ClassName}} : IDisposable -{ -{%- for method in Methods -%} -{{ method | indent }} -{%- if forloop.last == false %} -{% endif -%} -{%- endfor -%} -} \ No newline at end of file diff --git a/generators/Output/Templates/_TestMethodBody.liquid b/generators/Output/Templates/_TestMethodBody.liquid deleted file mode 100644 index 9cf0a0f729..0000000000 --- a/generators/Output/Templates/_TestMethodBody.liquid +++ /dev/null @@ -1,3 +0,0 @@ -{{ Arrange }} -{{ Act }} -{{ Assert }} \ No newline at end of file diff --git a/generators/Output/TestClass.cs b/generators/Output/TestClass.cs index f02403b7a8..e5f7383bd5 100644 --- a/generators/Output/TestClass.cs +++ b/generators/Output/TestClass.cs @@ -1,15 +1,18 @@ using System.Collections.Generic; -namespace Generators.Output +namespace Exercism.CSharp.Output { public class TestClass { - public string ClassName { get; set; } - public string CanonicalDataVersion { get; set; } - public IList Methods { get; set; } - public ISet UsingNamespaces { get; set; } - public string TemplateName { get; set; } = "TestClass"; + public TestClass(string exercise, string version, string className, IReadOnlyCollection testMethods) + => (Exercise, Version, ClassName, TestMethods) = (exercise, version, className, testMethods); - public string Render() => TemplateRenderer.RenderPartial(TemplateName, new { ClassName, CanonicalDataVersion, Methods, UsingNamespaces }); - } + public string Exercise { get; } + public string ClassName { get; } + public string Version { get; } + public IReadOnlyCollection TestMethods { get; } + public ICollection AdditionalMethods { get; } = new List(); + public ISet Namespaces { get; } = new SortedSet(); + public bool IsDisposable { get; set; } + } } \ No newline at end of file diff --git a/generators/Output/TestClassOutput.cs b/generators/Output/TestClassOutput.cs new file mode 100644 index 0000000000..fde80bc75e --- /dev/null +++ b/generators/Output/TestClassOutput.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Output +{ + public class TestClassOutput + { + private readonly TestClass _testClass; + + public TestClassOutput(TestClass testClass) + => _testClass = testClass; + + public void WriteToFile() + { + var filePath = FilePath; + var renderedContents = Render(); + + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + File.WriteAllText(filePath, renderedContents); + } + + private string Render() => Template.Render("TestClass", RenderParameters); + + private object RenderParameters => new + { + _testClass.ClassName, + _testClass.Version, + _testClass.IsDisposable, + Methods, + Namespaces + }; + + private IEnumerable Methods + => _testClass.TestMethods + .Select(testMethod => new TestMethodOutput(testMethod).Render()) + .Concat(_testClass.AdditionalMethods); + + private SortedSet Namespaces + => _testClass.TestMethods + .Where(x => x.ExceptionThrown != null) + .Select(x => x.ExceptionThrown.Namespace) + .Concat(_testClass.Namespaces) + .Append("Xunit") + .ToSortedSet(); + + private string FilePath => Path.Combine("..", "exercises", _testClass.Exercise, FileName); + + private string FileName => $"{_testClass.ClassName}.cs"; + } +} \ No newline at end of file diff --git a/generators/Output/TestMethod.cs b/generators/Output/TestMethod.cs index 47152fc032..a4a57a7859 100644 --- a/generators/Output/TestMethod.cs +++ b/generators/Output/TestMethod.cs @@ -1,12 +1,78 @@ -namespace Generators.Output +using System; +using System.Collections.Generic; +using System.Linq; +using Exercism.CSharp.Exercises; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Input; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Output { public class TestMethod { + private readonly HashSet _inputParameters = new HashSet(StringComparer.OrdinalIgnoreCase); + private readonly HashSet _constructorInputParameters = new HashSet(StringComparer.OrdinalIgnoreCase); + + public TestMethod(CanonicalData canonicalData, CanonicalDataCase canonicalDataCase) + { + Input = new Dictionary(canonicalDataCase.Input, StringComparer.OrdinalIgnoreCase); + Expected = canonicalDataCase.Expected; + Property = canonicalDataCase.Property; + TestMethodName = canonicalDataCase.Description.ToTestMethodName(); + TestMethodNameWithPath = string.Join(" - ", canonicalDataCase.DescriptionPath).ToTestMethodName(); + TestedClass = canonicalData.Exercise.ToTestedClassName(); + TestedMethod = canonicalDataCase.Property.ToTestedMethodName(); + Skip = canonicalDataCase.Index > 0; + + InputParameters = canonicalDataCase.Input.Keys.ToArray(); + } + + public string Act { get; set; } + public string Arrange { get; set; } + public string Assert { get; set; } + + public IDictionary Input { get; } + public dynamic Expected { get; set; } + public string Property { get; } public bool Skip { get; set; } - public string Name { get; set; } - public string Body { get; set; } - public string TemplateName { get; set; } = "TestMethod"; - public string Render() => TemplateRenderer.RenderPartial(TemplateName, new { Name, Body, Skip }); + public bool UseVariablesForInput { get; set; } + public bool UseVariableForExpected { get; set; } + public bool UseVariablesForConstructorParameters { get; set; } + public bool UseVariableForTested { get; set; } + public bool UseVariableForSut + => TestedMethodType == TestedMethodType.InstanceMethod || + TestedMethodType == TestedMethodType.Property; + + public string TestMethodName { get; set; } + public string TestMethodNameWithPath { get; } + public string TestedClass { get; set; } + public string TestedMethod { get; set; } + public TestedMethodType TestedMethodType { get; set; } + public Type ExceptionThrown { get; set; } + + public IReadOnlyCollection InputParameters + { + get => _inputParameters; + set + { + _inputParameters.Clear(); + _inputParameters.UnionWith(value); + + _constructorInputParameters.ExceptWith(value); + } + } + + public IReadOnlyCollection ConstructorInputParameters + { + get => _constructorInputParameters; + set + { + _constructorInputParameters.Clear(); + _constructorInputParameters.UnionWith(value); + + _inputParameters.ExceptWith(value); + } + } } } \ No newline at end of file diff --git a/generators/Output/TestMethodBody.cs b/generators/Output/TestMethodBody.cs deleted file mode 100644 index 19d201af4c..0000000000 --- a/generators/Output/TestMethodBody.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Generators.Input; - -namespace Generators.Output -{ - public abstract class TestMethodBody - { - protected TestMethodBody(CanonicalDataCase canonicalDataCase, CanonicalData canonicalData) - { - CanonicalDataCase = canonicalDataCase; - CanonicalData = canonicalData; - - Data = new TestMethodBodyData(this); - InitializeTemplateParameters(); - } - - public string TemplateName { get; set; } = "TestMethodBody"; - - public CanonicalDataCase CanonicalDataCase { get; } - public CanonicalData CanonicalData { get; } - public TestMethodBodyData Data { get; } - - public virtual bool UseVariablesForInput => CanonicalDataCase.UseVariablesForInput; - public virtual bool UseVariablesForConstructorParameters => CanonicalDataCase.UseVariablesForConstructorParameters; - public virtual bool UseVariableForExpected => CanonicalDataCase.UseVariableForExpected; - public virtual bool UseVariableForTested => CanonicalDataCase.UseVariableForTested; - - public string ArrangeTemplateName { get; set; } = "Arrange"; - public object ArrangeTemplateParameters { get; set; } - - public string ActTemplateName { get; set; } = "Act"; - public object ActTemplateParameters { get; set; } - - public string AssertTemplateName { get; set; } = "AssertEqual"; - public object AssertTemplateParameters { get; set; } - - public string Act { get; set; } - public string Arrange { get; set; } - public string Assert { get; set; } - - public virtual string Render() => TemplateRenderer.RenderPartial(TemplateName, new { Arrange, Act, Assert }); - - private void InitializeTemplateParameters() - { - ArrangeTemplateParameters = new { Data.Variables }; - ActTemplateParameters = new { }; - AssertTemplateParameters = new { Data.ExpectedParameter, Data.TestedValue }; - } - } -} \ No newline at end of file diff --git a/generators/Output/TestMethodBodyData.cs b/generators/Output/TestMethodBodyData.cs deleted file mode 100644 index 5591cd71f8..0000000000 --- a/generators/Output/TestMethodBodyData.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Generators.Input; - -namespace Generators.Output -{ - public class TestMethodBodyData - { - private const string SutVariableName = "sut"; - private const string TestedVariableName = "actual"; - private const string ExpectedVariableName = "expected"; - - private readonly TestMethodBody _testMethodBody; - - public TestMethodBodyData(TestMethodBody testMethodBody) => _testMethodBody = testMethodBody; - - public string TestedValue => _testMethodBody.UseVariableForTested ? TestedVariableName : TestedMethodInvocation; - public string InputParameters => _testMethodBody.UseVariablesForInput ? string.Join(", ", CanonicalDataCase.InputParameters.Select(key => key.ToVariableName())) : ValueFormatter.Format(Input); - public string ExpectedParameter => _testMethodBody.UseVariableForExpected ? ExpectedVariableName : ValueFormatter.Format(CanonicalDataCase.Expected); - public string ConstructorParameters => _testMethodBody.UseVariablesForConstructorParameters ? string.Join(", ", CanonicalDataCase.ConstructorInputParameters.Select(key => key.ToVariableName())) : ValueFormatter.Format(ConstructorInput); - - private CanonicalDataCase CanonicalDataCase => _testMethodBody.CanonicalDataCase; - private CanonicalData CanonicalData => _testMethodBody.CanonicalData; - - private string TestedClassName => CanonicalData.Exercise.ToTestedClassName(); - private string TestedMethodName => CanonicalDataCase.Property.ToTestedMethodName(); - - private IDictionary Input => CanonicalDataCase.InputParameters.ToDictionary(key => key, key => CanonicalDataCase.Input[key]); - private IDictionary ConstructorInput => CanonicalDataCase.ConstructorInputParameters.ToDictionary(key => key, key => CanonicalDataCase.Input[key]); - private object Expected => CanonicalDataCase.Expected; - - private IEnumerable InputVariablesDeclaration => ValueFormatter.FormatVariables(Input); - private IEnumerable ExpectedVariableDeclaration => ValueFormatter.FormatVariable(Expected, ExpectedVariableName); - private IEnumerable ConstructorVariablesDeclaration => ValueFormatter.FormatVariables(ConstructorInput); - private IEnumerable SutVariableDeclaration => new[] { $"var {SutVariableName} = new {TestedClassName}({ConstructorParameters});" }; - private IEnumerable ActualVariableDeclaration => new[] { $"var {TestedVariableName} = {TestedMethodInvocation};" }; - - public IEnumerable Variables - { - get - { - var lines = new List(); - - if (_testMethodBody.UseVariablesForInput) - lines.AddRange(InputVariablesDeclaration); - - if (_testMethodBody.UseVariablesForConstructorParameters) - lines.AddRange(ConstructorVariablesDeclaration); - - if (CanonicalDataCase.TestedMethodType == TestedMethodType.Instance) - lines.AddRange(SutVariableDeclaration); - - if (_testMethodBody.UseVariableForTested) - lines.AddRange(ActualVariableDeclaration); - - if (_testMethodBody.UseVariableForExpected) - lines.AddRange(ExpectedVariableDeclaration); - - return lines; - } - } - - public string TestedMethodInvocation - { - get - { - switch (CanonicalDataCase.TestedMethodType) - { - case TestedMethodType.Static: - return $"{TestedClassName}.{TestedMethodName}({InputParameters})"; - case TestedMethodType.Instance: - return $"{SutVariableName}.{TestedMethodName}({InputParameters})"; - case TestedMethodType.Extension: - return $"{InputParameters}.{TestedMethodName}()"; - default: - throw new ArgumentOutOfRangeException(); - } - } - } - } -} \ No newline at end of file diff --git a/generators/Output/TestMethodBodyWithBooleanCheck.cs b/generators/Output/TestMethodBodyWithBooleanCheck.cs deleted file mode 100644 index 6a8c73d720..0000000000 --- a/generators/Output/TestMethodBodyWithBooleanCheck.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using Generators.Input; - -namespace Generators.Output -{ - public class TestMethodBodyWithBooleanCheck : TestMethodBody - { - public TestMethodBodyWithBooleanCheck(CanonicalDataCase canonicalDataCase, CanonicalData canonicalData) : base(canonicalDataCase, canonicalData) - { - AssertTemplateName = "AssertBoolean"; - AssertTemplateParameters = new { BooleanAssertMethod, Data.TestedValue }; - } - - private string BooleanAssertMethod => Convert.ToBoolean(CanonicalDataCase.Expected).ToString(); - } -} \ No newline at end of file diff --git a/generators/Output/TestMethodBodyWithEqualityCheck.cs b/generators/Output/TestMethodBodyWithEqualityCheck.cs deleted file mode 100644 index 5a19020ee6..0000000000 --- a/generators/Output/TestMethodBodyWithEqualityCheck.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections; -using Generators.Input; - -namespace Generators.Output -{ - public class TestMethodBodyWithEqualityCheck : TestMethodBody - { - public TestMethodBodyWithEqualityCheck(CanonicalDataCase canonicalDataCase, CanonicalData canonicalData) : base(canonicalDataCase, canonicalData) - { - AssertTemplateName = ExpectedIsEmptyEnumerable ? "AssertEqual_Empty" : "AssertEqual"; - AssertTemplateParameters = new { Data.ExpectedParameter, Data.TestedValue }; - } - - public override bool UseVariableForExpected => base.UseVariableForExpected && !ExpectedIsEmptyEnumerable; - - private bool ExpectedIsEmptyEnumerable => - !(CanonicalDataCase.Expected is string) && - CanonicalDataCase.Expected is IEnumerable enumerable - && enumerable.GetEnumerator().MoveNext() == false; - } -} \ No newline at end of file diff --git a/generators/Output/TestMethodBodyWithExceptionCheck.cs b/generators/Output/TestMethodBodyWithExceptionCheck.cs deleted file mode 100644 index 3d61dafa97..0000000000 --- a/generators/Output/TestMethodBodyWithExceptionCheck.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Generators.Input; - -namespace Generators.Output -{ - public class TestMethodBodyWithExceptionCheck : TestMethodBody - { - public TestMethodBodyWithExceptionCheck(CanonicalDataCase canonicalDataCase, CanonicalData canonicalData) : base(canonicalDataCase, canonicalData) - { - AssertTemplateName = "AssertThrowsException"; - AssertTemplateParameters = new { ExceptionType, Data.TestedValue }; - } - - public override bool UseVariableForExpected => false; - public override bool UseVariableForTested => false; - - private string ExceptionType => CanonicalDataCase.ExceptionThrown.Name; - } -} \ No newline at end of file diff --git a/generators/Output/TestMethodBodyWithNullCheck.cs b/generators/Output/TestMethodBodyWithNullCheck.cs deleted file mode 100644 index 03f716f789..0000000000 --- a/generators/Output/TestMethodBodyWithNullCheck.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Generators.Input; - -namespace Generators.Output -{ - public class TestMethodBodyWithNullCheck : TestMethodBody - { - public TestMethodBodyWithNullCheck(CanonicalDataCase canonicalDataCase, CanonicalData canonicalData) : base(canonicalDataCase, canonicalData) - { - AssertTemplateName = "AssertNull"; - AssertTemplateParameters = new { Data.TestedValue }; - } - } -} \ No newline at end of file diff --git a/generators/Output/TestMethodOutput.cs b/generators/Output/TestMethodOutput.cs new file mode 100644 index 0000000000..0b2c773309 --- /dev/null +++ b/generators/Output/TestMethodOutput.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Exercism.CSharp.Exercises; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Input; +using Exercism.CSharp.Output.Rendering; + +namespace Exercism.CSharp.Output +{ + public class TestMethodOutput + { + private const string SutVariableName = "sut"; + private const string TestedVariableName = "actual"; + private const string ExpectedVariableName = "expected"; + + private static readonly Render Renderer = new Render(); + private readonly TestMethod _testMethod; + + public TestMethodOutput(TestMethod testMethod) => _testMethod = testMethod; + + private IEnumerable Variables + { + get + { + var lines = new List(); + + if (_testMethod.UseVariablesForInput) + lines.AddRange(InputVariables); + + if (_testMethod.UseVariablesForConstructorParameters) + lines.AddRange(ConstructorVariables); + + if (_testMethod.UseVariableForSut) + lines.Add(SutVariableDeclaration); + + if (_testMethod.UseVariableForTested) + lines.Add(TestedVariable); + + if (_testMethod.UseVariableForExpected) + lines.Add(ExpectedVariable); + + return lines; + } + } + + private IEnumerable InputVariables => Renderer.Variables(_testMethod.InputParameters.ToDictionary(key => key, key => _testMethod.Input[key])); + private string InputValues => string.Join(", ", _testMethod.InputParameters.Select(key => _testMethod.UseVariablesForInput ? key.ToVariableName() : Renderer.Object(_testMethod.Input[key]))); + + private IEnumerable ConstructorVariables => Renderer.Variables(_testMethod.ConstructorInputParameters.ToDictionary(key => key, key => _testMethod.Input[key])); + private string ConstructorValues => string.Join(", ", _testMethod.ConstructorInputParameters.Select(key => _testMethod.UseVariablesForConstructorParameters ? key.ToVariableName() : Renderer.Object(_testMethod.Input[key]))); + + private string SutVariableDeclaration => Renderer.Variable(SutVariableName, SutParameter); + private string SutParameter => _testMethod.UseVariableForSut ? $"new {_testMethod.TestedClass}({ConstructorValues})" : SutVariableName; + + private string TestedVariable => Renderer.Variable(TestedVariableName, TestedMethodInvocation); + private string TestedValue => _testMethod.UseVariableForTested ? TestedVariableName : TestedMethodInvocation; + + private string ExpectedVariable => Renderer.Variable(ExpectedVariableName, Renderer.ObjectMultiLine(_testMethod.Expected)); + private string ExpectedValue => _testMethod.UseVariableForExpected ? ExpectedVariableName : Renderer.Object(_testMethod.Expected); + + private string TestedMethodInvocation + { + get + { + switch (_testMethod.TestedMethodType) + { + case TestedMethodType.StaticMethod: + return $"{_testMethod.TestedClass}.{_testMethod.TestedMethod}({InputValues})"; + case TestedMethodType.ExtensionMethod: + return $"{InputValues}.{_testMethod.TestedMethod}()"; + case TestedMethodType.InstanceMethod: + return $"{SutVariableName}.{_testMethod.TestedMethod}({InputValues})"; + case TestedMethodType.Property: + return $"{SutVariableName}.{_testMethod.TestedMethod}"; + case TestedMethodType.Constructor: + return $"new {_testMethod.TestedClass}({ConstructorValues})"; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + public string Render() + { + Update(); + + _testMethod.Arrange = _testMethod.Arrange ?? RenderArrange(); + _testMethod.Act = _testMethod.Act ?? RenderAct(); + _testMethod.Assert = _testMethod.Assert ?? RenderAssert(); + + return Template.Render("TestMethod", RenderValues); + } + + private string RenderArrange() => Template.Render("Arrange", new { Variables }); + + private string RenderAct() => Template.Render("Act", new { }); + + private string RenderAssert() + { + switch (CurrentAssertType) + { + case AssertType.Equal: + return Renderer.AssertEqual(ExpectedValue, TestedValue); + case AssertType.Empty: + return Renderer.AssertEmpty(ExpectedValue, TestedValue); + case AssertType.Null: + return Renderer.AssertNull(TestedValue); + case AssertType.Throws: + return Renderer.AssertThrows(_testMethod.ExceptionThrown, TestedValue); + case AssertType.Boolean: + return Renderer.AssertBoolean(Convert.ToBoolean(_testMethod.Expected), TestedValue); + case AssertType.Matches: + return Renderer.AssertMatches(ExpectedValue, TestedValue); + default: + throw new ArgumentOutOfRangeException(); + } + } + + private object RenderValues => new { Name = _testMethod.TestMethodName, _testMethod.Skip, _testMethod.Arrange, _testMethod.Act, _testMethod.Assert }; + + private void Update() + { + switch (CurrentAssertType) + { + case AssertType.Empty: + _testMethod.UseVariableForExpected = false; + break; + case AssertType.Throws: + _testMethod.UseVariableForExpected = false; + _testMethod.UseVariableForTested = false; + break; + } + } + + private AssertType CurrentAssertType + { + get + { + if (_testMethod.ExceptionThrown != null) + return AssertType.Throws; + + switch (_testMethod.Expected) + { + case null: + return AssertType.Null; + case bool _: + return AssertType.Boolean; + case Regex _: + return AssertType.Matches; + default: + return UseEmptyAssertion + ? AssertType.Empty + : AssertType.Equal; + } + } + } + + private bool UseEmptyAssertion + => !(_testMethod.Expected is string) && _testMethod.Expected is IEnumerable enumerable && enumerable.GetEnumerator().MoveNext() == false; + + private enum AssertType + { + Equal, + Empty, + Null, + Throws, + Boolean, + Matches + } + } +} \ No newline at end of file diff --git a/generators/Output/TypesExtensions.cs b/generators/Output/TypesExtensions.cs deleted file mode 100644 index 40dae0590a..0000000000 --- a/generators/Output/TypesExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; - -namespace Generators.Output -{ - public static class TypesExtensions - { - public static IEnumerable SliceColumn(this T[,] array, int column) - { - for (var i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++) - { - yield return array[i, column]; - } - } - - public static IEnumerable SliceRow(this T[,] array, int row) - { - for (var i = array.GetLowerBound(1); i <= array.GetUpperBound(1); i++) - { - yield return array[row, i]; - } - } - } -} \ No newline at end of file diff --git a/generators/Output/ValueFormatter.cs b/generators/Output/ValueFormatter.cs deleted file mode 100644 index 0866656f4d..0000000000 --- a/generators/Output/ValueFormatter.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using Newtonsoft.Json.Linq; - -namespace Generators.Output -{ - public static class ValueFormatter - { - public static string Format(object val) - { - switch (val) - { - case string str: return str.Format(); - case double dbl: return dbl.Format(); - case float flt: return flt.Format(); - case ulong ulng: return ulng.Format(); - case char c: return c.Format(); - case Enum enumeration: return enumeration.Format(); - case Tuple tuple: return tuple.Format(); - case List ints: return ints.Format(); - case List objects: return objects.Format(); - case IEnumerable ints: return ints.Format(); - case IEnumerable strings: return strings.Format(); - case IEnumerable unescapedValues when unescapedValues.Any(): return unescapedValues.Format(); - case IDictionary dict: return dict.Format(); - case IDictionary dict: return dict.Format(); - case IDictionary dict: return dict.Format(); - case IDictionary dict: return dict.Format(); - case JArray jArray: return jArray.Format(); - case int[,] multidimensionalArray: return multidimensionalArray.Format(); - case IEnumerable> tuples: return tuples.Format(); - case IEnumerable> tuples: return tuples.Format(); - case IEnumerable objects: return objects.Format(); - default: return val?.ToString(); - } - } - - public static string[] FormatVariables(IDictionary dict) - => dict.Keys.SelectMany(key => FormatVariable(dict[key], key.ToVariableName())).ToArray(); - - public static string[] FormatVariable(object val, string name) - { - switch (val) - { - case string str when str.Contains("\n"): - return FormatMultiLineString(name, str); - case IEnumerable strings: - if (!strings.Any()) - { - return new[] { $"var {name} = new string[0];" }; - } - - return FormatMultiLineEnumerable(strings.Select((str, i) => str.Format() + (i < strings.Count() - 1 ? "," : "")), name, "new[]"); - case IDictionary dict: - return FormatMultiLineEnumerable(dict.Keys.Select((key, i) => $"[{Format(key)}] = {Format(dict[key])}" + (i < dict.Keys.Count - 1 ? "," : "")), name, "new Dictionary"); - case IDictionary dict: - return FormatMultiLineEnumerable(dict.Keys.Select((key, i) => $"[{Format(key)}] = {Format(dict[key])}" + (i < dict.Keys.Count - 1 ? "," : "")), name, "new Dictionary"); - case IDictionary dict: - return FormatMultiLineEnumerable(dict.Keys.Select((key, i) => $"[{Format(key)}] = {Format(dict[key])}" + (i < dict.Keys.Count - 1 ? "," : "")), name, "new Dictionary"); - case IEnumerable> tuples: - return new[] { tuples.Format() }; - default: - return new[] { $"var {name} = {Format(val)};" }; - } - } - - private static string Format(this string s) => s.EscapeSpecialCharacters().Quote(); - - private static string Format(this char c) => $"'{c}'"; - - private static string Format(this double dbl) => dbl.ToString(CultureInfo.InvariantCulture); - - private static string Format(this float flt) => flt.ToString(CultureInfo.InvariantCulture); - - private static string Format(this int i) => i.ToString(CultureInfo.InvariantCulture); - - private static string Format(this ulong ulng) => $"{ulng}UL"; - - private static string Format(this Enum @enumeration) => - $"{enumeration.GetType().Name}.{enumeration}"; - - private static string Format(this Tuple tuple) => - $"Tuple.Create({tuple.Item1}, {tuple.Item2})"; - - private static string Format(this IEnumerable ints) => ints.Any() ? - $"new[] {{ {string.Join(", ", ints)} }}" : "new int[0]"; - - private static string Format(this IEnumerable strings) => - strings.Any() ? $"new[] {{ {string.Join(", ", strings.Select(Format))} }}" : "new string[0]"; - - private static string Format(this IEnumerable objects) => - objects.Any() ? $"new[] {{ {string.Join(", ", objects.Select(Format))} }}" : "new object[0]"; - - private static string Format(this List ints) => - ints.Any() ? $"new List {{ {string.Join(", ", ints.Select(Format))} }}" : "new List()"; - - private static string Format(this List objects) => - objects.Any() ? $"new List {{ {string.Join(", ", objects.Select(Format))} }}" : "new List()"; - - private static string Format(this IEnumerable unescapedValues) => - $"new[] {{ {string.Join(", ", unescapedValues.Select(Format))} }}"; - - private static string Format(this IEnumerable> tuples) => tuples.Any() ? - $"new[] {{ {string.Join(", ", tuples)} }}" : "new ValueTuple[0]"; - - private static string Format(this IDictionary dict) => - string.Join(", ", dict.Values.Select(Format)); - - private static string Format(this IDictionary dict) => - $"new Dictionary {{ {string.Join(", ", dict.Keys.Select(key => $"[{Format(key)}] = {Format(dict[key])}"))} }}"; - - private static string Format(this IDictionary dict) => - $"new Dictionary {{ {string.Join(", ", dict.Keys.Select(key => $"[{Format(key)}] = {Format(dict[key])}"))} }}"; - - private static string Format(this IDictionary dict) => - $"new Dictionary {{ {string.Join(", ", dict.Keys.Select(key => $"[{Format(key)}] = {Format(dict[key])}"))} }}"; - - private static string Format(this JArray jArray) => - $"new[] {{ {string.Join(", ", jArray.Select(Format))} }}"; - - private static string Format(this int[,] multidimensionalArray) - { - return multidimensionalArray.GetLength(0) > 0 - ? $"new[,]\r\n{{\r\n {string.Join(",\r\n ", Enumerable.Range(0, multidimensionalArray.GetUpperBound(0) + 1).Select(x => multidimensionalArray.SliceRow(x).ToNestedArray()))}\r\n}}" - : "new int[,] { }"; - } - - private static string Format(this IEnumerable> tuples) => - $"new[] {{ {string.Join(", ", tuples.Select(Format))} }}"; - - private static string ToNestedArray(this IEnumerable enumerable) => - enumerable.Any() ? $"{{ {string.Join(", ", enumerable)} }}" : string.Empty; - - private static string[] FormatMultiLineString(string name, string str) - { - var strings = str.Split('\n'); - var formattedStrings = strings - .Select((t, i) => i < strings.Length - 1 - ? $"{Format(t + "\n")} +" - : $"{Format(t)}"); - - return FormatMultiLineVariable(formattedStrings, name); - } - - private static string[] FormatMultiLineEnumerable(IEnumerable enumerable, string name, string constructor = null) - => FormatMultiLineVariable(enumerable.Prepend("{").Append("}"), name, constructor); - - private static string[] FormatMultiLineVariable(IEnumerable enumerable, string name, string constructor = null) - => enumerable.Select(line => line == "{" || line == "}" ? line : line.Indent()) - .AddTrailingSemicolon() - .Prepend($"var {name} = {constructor}") - .ToArray(); - } -} \ No newline at end of file diff --git a/generators/Program.cs b/generators/Program.cs index 479cf734a3..f6e73186c6 100644 --- a/generators/Program.cs +++ b/generators/Program.cs @@ -1,11 +1,11 @@ using System; -using System.Diagnostics; using CommandLine; -using Generators.Input; -using Generators.Output; +using Exercism.CSharp.Exercises; +using Exercism.CSharp.Helpers; +using Exercism.CSharp.Input; using Serilog; -namespace Generators +namespace Exercism.CSharp { public static class Program { @@ -19,9 +19,9 @@ public static int Main(string[] args) .WithParsed(RegenerateTestClasses); return 0; } - catch (Exception exception) when (!Debugger.IsAttached) + catch (Exception exception) { - Log.Error(exception, "Exception occured: {Message}", exception.Message); + Log.Error(exception, "Exception occured: {Exception}", exception.Message); return 1; } } @@ -52,7 +52,7 @@ private static void RegenerateTestClasses(Options options) private static void RegenerateTestClass(Exercise exercise, Options options, CanonicalDataParser canonicalDataParser) { - if (ShouldBeSkipped(exercise, options)) + if (SkipGenerateTestClass(exercise, options)) return; switch (exercise) @@ -75,7 +75,7 @@ private static void RegenerateTestClass(Exercise exercise, Options options, Cano } } - private static bool ShouldBeSkipped(Exercise exercise, Options options) + private static bool SkipGenerateTestClass(Exercise exercise, Options options) => DoesNotMatchFilteredExercise(exercise, options) || DoesNotMatchFilteredStatus(exercise, options); private static bool DoesNotMatchFilteredExercise(Exercise exercise, Options options) diff --git a/generators/TestedMethodType.cs b/generators/TestedMethodType.cs deleted file mode 100644 index 0e8938029d..0000000000 --- a/generators/TestedMethodType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Generators -{ - public enum TestedMethodType - { - Static, - Instance, - Extension - } -} \ No newline at end of file diff --git a/generators/generate.ps1 b/generators/generate.ps1 deleted file mode 100644 index e43799710c..0000000000 --- a/generators/generate.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -Invoke-Expression "dotnet restore" -Invoke-Expression "dotnet run" \ No newline at end of file diff --git a/generators/generate.sh b/generators/generate.sh deleted file mode 100644 index 2f8a56bcd6..0000000000 --- a/generators/generate.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -exec dotnet restore -exec dotnet run \ No newline at end of file