Last active
August 29, 2015 13:59
-
-
Save mat-mcloughlin/10970291 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Kata | |
{ | |
using System.Collections.Generic; | |
using System.Linq; | |
using Xunit; | |
public interface ICheckout | |
{ | |
void Scan(string item); | |
int GetTotalPrice(); | |
} | |
public class Tests | |
{ | |
[Fact] | |
public void GivesZeroWhenNoItems() | |
{ | |
var expected = 0; | |
var priceList = new Dictionary<string, int>(); | |
var checkout = new Checkout(priceList); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
[Fact] | |
public void ScanningOneItemGivesPrice() | |
{ | |
var expected = 50; | |
var priceList = new Dictionary<string, int> { { "A", 50 } }; | |
var checkout = new Checkout(priceList); | |
checkout.Scan("A"); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
[Fact] | |
public void ScanningTwoItemGivesPrice() | |
{ | |
var expected = 100; | |
var priceList = new Dictionary<string, int> { { "A", 50 } }; | |
var checkout = new Checkout(priceList); | |
checkout.Scan("A"); | |
checkout.Scan("A"); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
[Fact] | |
public void ScanningThreeItemGivesPriceMinusDiscount() | |
{ | |
var expected = 130; | |
var priceList = new Dictionary<string, int> { { "A", 50 } }; | |
var discounts = new List<Discount> { new Discount { Item = "A", Amount = 20, Rule = 3 } }; | |
var checkout = new Checkout(priceList, discounts); | |
checkout.Scan("A"); | |
checkout.Scan("A"); | |
checkout.Scan("A"); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
/* At this point here I choose to change the tests to pass in the discounts | |
* Just an integer value for how much to discount */ | |
[Fact] | |
public void ScanningThreeItemsGivesPriceMinusDiscountWhenRuleIsThreeOrMore() | |
{ | |
var expected = 130; | |
var discounts = new List<Discount> { new Discount { Item = "A", Amount = 20, Rule = 3 } }; | |
var priceList = new Dictionary<string, int> { { "A", 50 }, { "B", 30 } }; | |
var checkout = new Checkout(priceList, discounts); | |
checkout.Scan("A"); | |
checkout.Scan("A"); | |
checkout.Scan("A"); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
/* Refactoring to make discount calculation easier */ | |
[Fact] | |
public void ScanningTwoDifferentItemsGivesTotalPrice() | |
{ | |
var expected = 80; | |
var priceList = new Dictionary<string, int> { { "A", 50 }, { "B", 30 } }; | |
var checkout = new Checkout(priceList); | |
checkout.Scan("A"); | |
checkout.Scan("B"); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
/* In order to get the above test to pass I changed the code to go from storing an int value of items | |
* to a list of string so it could store different types. */ | |
[Fact] | |
public void ScanningThreeDifferentItemsGivesTotalPrice() | |
{ | |
var expected = 100; | |
var priceList = new Dictionary<string, int> { { "A", 50 }, { "B", 30 }, { "C", 20 } }; | |
var checkout = new Checkout(priceList); | |
checkout.Scan("A"); | |
checkout.Scan("B"); | |
checkout.Scan("C"); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
/* In order to get the above to test changed the code from having the price in GetTotalPrice() method | |
* to passing the pricelist into the constructor */ | |
/* Did some refactoring */ | |
[Fact] | |
public void ScanningTwoDifferentItemsWithDifferentDiscountsGivesTotalPrice() | |
{ | |
var expected = 100; | |
var discounts = new List<Discount> | |
{ | |
new Discount { Item = "A", Amount = 20, Rule = 3 }, | |
new Discount { Item = "B", Amount = 15, Rule = 2 } | |
}; | |
var priceList = new Dictionary<string, int> { { "A", 50 }, { "B", 30 }, { "C", 20 } }; | |
var checkout = new Checkout(priceList, discounts); | |
checkout.Scan("A"); | |
checkout.Scan("B"); | |
checkout.Scan("C"); | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
/* Had to change the constructor from accepting integer values for discount value and rule to a list of | |
* discounts to handle different items, going back up and changing the tests, I made it optional */ | |
/* Did a bit of refactoring. | |
} | |
public class FinalTests | |
{ | |
[Fact] | |
public void Tests() | |
{ | |
this.RunTest("BAB", 95); | |
this.RunTest("AAAAAAAA", 360); | |
this.RunTest("BABCDAB", 215); | |
this.RunTest("ABCDABCDABCD", 325); | |
this.RunTest("AAAABBBCCCC", 335); | |
this.RunTest("AAABBBBCCCCDD", 340); | |
} | |
private void RunTest(string items, int expected) | |
{ | |
var discounts = new List<Discount> | |
{ | |
new Discount { Item = "A", Amount = 20, Rule = 3 }, | |
new Discount { Item = "B", Amount = 15, Rule = 2 } | |
}; | |
var priceList = new Dictionary<string, int> { { "A", 50 }, { "B", 30 }, { "C", 20 }, { "D", 20 } }; | |
var checkout = new Checkout(priceList, discounts); | |
foreach (var item in items) | |
{ | |
checkout.Scan(item.ToString()); | |
} | |
var actual = checkout.GetTotalPrice(); | |
Assert.Equal(expected, actual); | |
} | |
} | |
public class Checkout : ICheckout | |
{ | |
private readonly IList<Discount> discounts; | |
private readonly IDictionary<string, int> priceList; | |
private readonly IList<string> items; | |
public Checkout(IDictionary<string, int> priceList, IList<Discount> discounts = null) | |
{ | |
this.items = new List<string>(); | |
this.discounts = discounts ?? new List<Discount>(); | |
this.priceList = priceList; | |
} | |
public void Scan(string item) | |
{ | |
this.items.Add(item); | |
} | |
public int GetTotalPrice() | |
{ | |
var total = this.items.Sum(item => this.priceList[item]); | |
foreach (var discount in this.discounts) | |
{ | |
var itemCount = this.items.Count(i => i == discount.Item); | |
total -= (itemCount / discount.Rule) * discount.Amount; | |
} | |
return total; | |
} | |
} | |
public class Discount | |
{ | |
public string Item { get; set; } | |
public int Rule { get; set; } | |
public int Amount { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment