├── language.yml ├── rider-settings └── settings.zip ├── .gitignore ├── src ├── Kata │ ├── Kata.csproj │ └── Monkey.cs ├── Kata.Spec │ ├── CommandDispatch │ │ └── when_dispatching_a_command.cs │ ├── StringCalc │ │ └── when_feeding_the_monkey.cs │ ├── Kata.Spec.csproj │ └── BuildingEntry │ │ └── when_monitoring_an_entrance.cs └── Kata-Starter.sln ├── templates ├── readme.md ├── spec.cs └── sadspec.cs ├── README.md └── katas ├── string_calculator.md └── parking_lot.md /language.yml: -------------------------------------------------------------------------------- 1 | image: gitpod/workspace-dotnet 2 | vscode: 3 | extensions: 4 | - muhammad-sammy.csharp 5 | -------------------------------------------------------------------------------- /rider-settings/settings.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsommardahl/oreilly-kata-starter/HEAD/rider-settings/settings.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | [Bb]in 3 | [Dd]ebug*/ 4 | [Rr]elease*/ 5 | 6 | #Tooling 7 | _ReSharper*/ 8 | *.resharper 9 | *.DotSettings 10 | *.DotSettings.* 11 | [Tt]est[Rr]esult* 12 | .idea/ 13 | 14 | node_modules -------------------------------------------------------------------------------- /src/Kata/Kata.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | latest 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /templates/readme.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | Adding live templates to rider is easy! Check out this link for instructions: https://www.jetbrains.com/help/rider/Creating_and_Editing_Live_Templates.html 4 | 5 | - [spec](spec.cs) 6 | - [sadspec](sadspec.cs) 7 | 8 | The order of steps should be: 9 | - spec_name 10 | - do_something 11 | - sut 12 | -------------------------------------------------------------------------------- /templates/spec.cs: -------------------------------------------------------------------------------- 1 | public class when_$spec_name$ 2 | { 3 | Establish _context = () => { _systemUnderTest = new $sut$ }; 4 | 5 | Because of = () => { _result = _systemUnderTest.Action(); }; 6 | 7 | It should_$do_something$ = () => 8 | { 9 | _result.Should().Be(something); 10 | }; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /templates/sadspec.cs: -------------------------------------------------------------------------------- 1 | public class when_$spec_name$ 2 | { 3 | Establish _context = () => { _systemUnderTest = new $sut$ }; 4 | 5 | Because of = () => { _result = Catch.Exception(()=> _systemUnderTest.Action()); }; 6 | 7 | It should_$do_something$ = () => 8 | { 9 | _result.Message.Should().Be(something); 10 | }; 11 | static Exception _result; 12 | } 13 | -------------------------------------------------------------------------------- /src/Kata/Monkey.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace Kata 5 | { 6 | public class Monkey 7 | { 8 | public Monkey() 9 | { 10 | Belly = new List(); 11 | } 12 | 13 | public IList Belly { get; } 14 | 15 | public void Eat(string food) 16 | { 17 | Belly.Add(food); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Kata.Spec/CommandDispatch/when_dispatching_a_command.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using FluentAssertions; 4 | using Machine.Specifications; 5 | using Moq; 6 | using It = Machine.Specifications.It; 7 | 8 | namespace Kata.Spec.CommandDispatch 9 | { 10 | // 11 | //Create a dispatcher that can match commands with handlers and execute them. 12 | // 13 | // v1 - Name matching and hand-coded test object 14 | // v2 - CanHandle method and mocked handler 15 | } -------------------------------------------------------------------------------- /src/Kata.Spec/StringCalc/when_feeding_the_monkey.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using Machine.Specifications; 4 | 5 | namespace Kata.Spec.StringCalc 6 | { 7 | public class when_feeding_the_monkey 8 | { 9 | static Monkey _systemUnderTest; 10 | 11 | Establish context = () => 12 | _systemUnderTest = new Monkey(); 13 | 14 | Because of = () => 15 | _systemUnderTest.Eat("banana"); 16 | 17 | It should_have_the_food_in_its_belly = () => 18 | _systemUnderTest.Belly.Should().Contain("banana"); 19 | } 20 | } -------------------------------------------------------------------------------- /src/Kata.Spec/Kata.Spec.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | latest 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Kata.Spec/BuildingEntry/when_monitoring_an_entrance.cs: -------------------------------------------------------------------------------- 1 | using Machine.Specifications; 2 | 3 | namespace Kata.Spec.BuildingEntry 4 | { 5 | // public class when_monitoring_an_entrance 6 | // { 7 | // Establish _context = () => 8 | // { 9 | // _systemUnderTest = new EntranceMonitor(); 10 | // }; 11 | // 12 | // Because of = () => { _result = _systemUnderTest.Entrance("123"); }; 13 | // 14 | // It should_log_the_entrance_to_the_db = () => { _result.Should().Be(something); }; 15 | // } 16 | 17 | // Entrance Monitor Kata 18 | // Build a class that can receive info about a badge-in entrance event and react appropriately 19 | 20 | // 1. Log entrance into building to the db including badgeId and dateTime 21 | // 2. Solve "entrance" instantiation problem with Factory (refactor) 22 | // 3. Verify badge Id access based on badge type (implement strategy) 23 | // 4. Notify security on unauthorized access 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to the Kata Starter 2 | 3 | ### For Best Results 4 | 5 | 1) Install Jetbrains Rider 2019.3.1 (free evaluation). 6 | 7 | 2) Install Dotnet SDK 2.2. 8 | 9 | 3) In Rider, install the plugin "Machine Specifications Runner for Rider" (File > Settings > Plugins) 10 | 11 | 4) Make sure everything compiles and the unit tests run and pass (if the tests do not pass, you need to go back and check your versions. If the versions of Rider, Dotnet Core, and the Machine Specifications plugin are not compatible, the tests will not run). 12 | 13 | 5) Fork this repo so that you can push back in your changes. 14 | 15 | ### Prepare Your Mind 16 | 17 | 1) Read up on pairing and katas to get familiar with the concepts. Some starting points might be... 18 | 19 | 2) Get some pointers on how to act while pairing - https://awkwardcoder.com/7-ways-to-win-with-pair-programming-c678c235be2d 20 | 21 | 3) Learn what is a “Kata” and see a few in action - http://codekata.com/ 22 | 23 | 4) Check out the [String Calculator](/katas/string_calculator.md) kata we will be learning. 24 | 25 | ### Extras 26 | 27 | If you'd like to use the live templates that Byron uses, check the [templates folder](templates) for template content and instructions. 28 | -------------------------------------------------------------------------------- /src/Kata-Starter.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kata", "Kata\Kata.csproj", "{E23B873B-193D-44F7-BA0D-8C54AB3AED39}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kata.Spec", "Kata.Spec\Kata.Spec.csproj", "{3726D02E-54DA-49C7-9E2D-9D774D8870E8}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {E23B873B-193D-44F7-BA0D-8C54AB3AED39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {E23B873B-193D-44F7-BA0D-8C54AB3AED39}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {E23B873B-193D-44F7-BA0D-8C54AB3AED39}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {E23B873B-193D-44F7-BA0D-8C54AB3AED39}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {3726D02E-54DA-49C7-9E2D-9D774D8870E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {3726D02E-54DA-49C7-9E2D-9D774D8870E8}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {3726D02E-54DA-49C7-9E2D-9D774D8870E8}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {3726D02E-54DA-49C7-9E2D-9D774D8870E8}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /katas/string_calculator.md: -------------------------------------------------------------------------------- 1 | ## String Calculator Kata 2 | 3 | https://osherove.com/tdd-kata-1 4 | 5 | ### Rules: 6 | * Write one spec at a time. 7 | * All previously passing specs must continue to pass 8 | * All new specs must fail for the right reasons before making them pass 9 | * Verbalize thoughts and code 10 | * Follow the process strictly 11 | * No copy/pasta 12 | * No Regex 13 | 14 | ### Process: 15 | 1. Write spec 16 | 2. Red: Failing for the right reasons 17 | 3. Green: Just enough code to make it pass 18 | 4. Refactor: Can I improve the production code or spec without making any previously passing specs fail. 19 | 5. Repeat 20 | 21 | ### Specs 22 | 1. Given the user input is empty when calculating the sum then it should return zero. 23 | 2. Given the user input is one number when calculating the sum then it should return the same number. (example "3" should equal 3) 24 | 3. Given the user input is two numbers when calculating the sum then it should return the sum of those numbers. (example "1,2" should equal 3) 25 | 4. Given the user input is an unknown amount of numbers when calculating the sum then it should return the sum of all the numbers. (example "1,2,3" should equal 6) 26 | 5. Given the user input is multiple numbers with new line and comma delimiters when calculating the sum then it should return the sum of all the numbers. (example "1\n2,3" should equal 6) 27 | 6. Given the user input is multiple numbers with a custom single-character delimiter when calculating the sum then it should return the sum of all the numbers. (example “//;\n1;2” should return 3) 28 | 7. Given the user input contains one negative number when calculating the sum then it should throw an exception "negatives not allowed: x" (where x is the negative number). 29 | 8. Given the user input contains multiple negative numbers mixed with positive numbers when calculating the sum then it should throw an exception "negatives not allowed: x, y, z" (where x, y, z are only the negative numbers). 30 | 9. Given the user input contains numbers larger than 1000 when calculating the sum it should only sum the numbers less than 1001. (example 2 + 1001 = 2) 31 | 10. Given the user input is multiple numbers with a custom multi-character delimiter when calculating the sum then it should return the sum of all the numbers. (example: “//[***]\n1***2***3” should return 6) 32 | 11. Given the user input is multiple numbers with multiple custom delimiters when calculating the sum then it should return the sum of all the numbers. (example “//[*][%]\n1*2%3” should return 6) 33 | 34 | ### Technique and Form 35 | What do we want people to learn from the practice of this kata? 36 | 37 | * Test-Driven Development 38 | * Plain English spec/observation naming 39 | * Top-down, right to left spec implementation 40 | * Defining classes, methods and new specs from the current spec 41 | * Modified Red-Green-Refactor (Red-Green-Red-Green-Red-Green-Red-Green-Red-Green-REFACTOR) 42 | * No automatically green specs 43 | * Failing for the right reason (explaining code path to failure) 44 | * Pair Programming 45 | * Conversational coding 46 | * Ping pong pair programming pattern (p5) 47 | * Mastery of Tools 48 | * Git SCM (Terminal) 49 | * Good commit messages 50 | * Push 51 | * Pull 52 | * Add 53 | * Commit 54 | * Jetbrains Rider 55 | * Automatically run specs on build 56 | * Panels and sub-windows don’t require excessive navigation/mousing 57 | * Refactorings/Keyboard shortcuts 58 | * Limited mouse use 59 | * Create type 60 | * Define field (type inference) 61 | * Move to folder 62 | * Navigate to failures 63 | * Basic editor navigation 64 | * Build 65 | * Run specs 66 | * Create variable after working out the value 67 | * Alt enter 68 | * Dotnet/C# 69 | * Default argument values 70 | * Basic string parsing 71 | * Extension methods 72 | * Select 73 | * Sum 74 | * Functional string/collection manipulation 75 | * Array vs IEnumerable 76 | -------------------------------------------------------------------------------- /katas/parking_lot.md: -------------------------------------------------------------------------------- 1 | # Parking Lot Kata 2 | 3 | ## Story 4 | 5 | We have a new "smart lot" parking lot. Our parking lot can host many types of vehicles and promotes environmental responsibility by giving discounts to vehicles that are easier on the environment. Even though we have a limited number of spaces today, we hope to expand someday. Also, we hope to start with simple vehicles and start generating revenue before adding more complicated vehicle types. 6 | 7 | ## Rules 8 | 9 | * Follow SOLID principles 10 | * Ping Pong Pairing 11 | * This is a TDD Kata. Red-Green-Refactor (modified) 12 | * Follow "arabic form" when implementing specs. 13 | * No copy pasting 14 | * No Regex 15 | 16 | ## Specs 17 | 18 | Scenario: Normal Car, Plenty of Space, $5 19 | ``` 20 | Given a parking lot with 50 spaces 21 | And a normal car 22 | When the vehicle stays for one day 23 | Then the driver is charged $5 24 | And the lot is left with 49 spaces 25 | ``` 26 | Scenario: Normal Car, One Space Left 27 | ``` 28 | Given a parking lot with 1 spaces 29 | And a normal car 30 | When the vehicle stays for one day 31 | Then the driver is charged $5 32 | And the lot is left with 0 spaces 33 | ``` 34 | Scenario: Normal Car, No Space 35 | ``` 36 | Given a parking lot with 0 spaces 37 | And a normal car 38 | When the vehicle attempts to enters the lot 39 | Then the driver is charged $0 40 | And the car is rejected 41 | ``` 42 | Scenario: Electric Car, Plenty of Space, 50% discount 43 | ``` 44 | Given a parking lot with 50 spaces 45 | And an electric car 46 | When the vehicle stays for one day 47 | Then the driver is charged $2.50 48 | And the lot is left with 49 spaces 49 | ``` 50 | Scenario: Motocycle, Plenty of Space, 1/2 space 51 | ``` 52 | Given a parking lot with 50 spaces 53 | And a motorcycle 54 | When the vehicle stays for one day 55 | Then the driver is charged $3.00 56 | And the lot is left with 49.5 spaces 57 | ``` 58 | Scenario: Normal Car, Trump Sticker, Charge Double 59 | ``` 60 | Given a parking lot with 50 spaces 61 | And a normal car 62 | And the car has a trump sticker 63 | When the vehicle stays for one day 64 | Then the driver is charged $10 65 | And the lot is left with 49 spaces 66 | ``` 67 | Scenario: Bus, Plenty of Space, 2 Spaces, $9 68 | ``` 69 | Given a parking lot with 50 spaces 70 | And a bus 71 | When the vehicle stays for one day 72 | Then the driver is charged $9.00 73 | And the lot is left with 48 spaces 74 | ``` 75 | Scenario: Electric Bus, Plenty of Space, 50% discount 76 | ``` 77 | Given a parking lot with 50 spaces 78 | And an electric bus 79 | When the vehicle stays for one day 80 | Then the driver is charged $4.50 81 | And the lot is left with 48 spaces 82 | ``` 83 | Scenario: Helicopter, Plenty of space, 8 Spaces, $35 84 | ``` 85 | Given a parking lot with 50 spaces 86 | And a helicopter 87 | When the vehicle stays for one day 88 | Then the driver is charged $35 89 | And the lot is left with 42 spaces 90 | ``` 91 | Scenario: Helicopter, Plenty of space, 2 Days 92 | ``` 93 | Given a parking lot with 50 spaces 94 | And a helicopter 95 | When the vehicle stays for two days 96 | Then the driver is charged $70 97 | And the lot is left with 42 spaces 98 | ``` 99 | Scenario: 20% discount for 3 or more days 100 | ``` 101 | Given a parking lot with 50 spaces 102 | And a bus 103 | When the vehicle stays for four days 104 | Then the driver is charged $28.80 105 | And the lot is left with 48 spaces 106 | ``` 107 | Scenario: 30% discount for 6 days or more 108 | ``` 109 | Given a parking lot with 50 spaces 110 | And a normal car 111 | When the vehicle stays for eight days 112 | Then the driver is charged $28 113 | And the lot is left with 49 spaces 114 | ``` 115 | 116 | ## Techniques/Practices 117 | 118 | This is what you should be learning through this kata. 119 | 120 | [To Be Determined] 121 | 122 | ## Inspiration 123 | 124 | This kata was inspired by https://github.com/kamranahmedse/design-patterns-for-humans. 125 | --------------------------------------------------------------------------------