Skip to content

Instantly share code, notes, and snippets.

@mat-mcloughlin
Last active August 29, 2015 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mat-mcloughlin/10970291 to your computer and use it in GitHub Desktop.
Save mat-mcloughlin/10970291 to your computer and use it in GitHub Desktop.
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