-
-
Save thinkbeforecoding/9218171 to your computer and use it in GitHub Desktop.
Other try without query expression. articles is now a map.
This file contains hidden or 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
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
using System; | |
using System.Collections.Generic; | |
using System.Collections.Immutable; | |
using System.Linq; | |
namespace TDDCoverage | |
{ | |
public class Order | |
{ | |
public class Line | |
{ | |
public readonly String ArticleId; | |
public readonly decimal Amount; | |
public Line(String ArticleId, decimal Amount) | |
{ | |
this.ArticleId = ArticleId; | |
this.Amount = Amount; | |
} | |
} | |
public readonly IEnumerable<Line> Lines; | |
public Order(IEnumerable<Line> Lines) | |
{ | |
this.Lines = Lines; | |
} | |
public class LineList : List<Line> | |
{ | |
public void Add(String ArticleId, decimal Amount) | |
{ | |
this.Add(new Line(ArticleId,Amount)); | |
} | |
} | |
} | |
public class Invoice | |
{ | |
public class Item | |
{ | |
public readonly String Name; | |
public readonly decimal Amount, Price, VAT; | |
public Item(String Name, decimal Amount, decimal Price, decimal VAT) | |
{ | |
this.Name = Name; | |
this.Amount = Amount; | |
this.Price = Price; | |
this.VAT = VAT; | |
} | |
public override bool Equals(object obj) | |
{ | |
var x = obj as Item; | |
return x != null && | |
x.Name == Name && | |
x.Price == Price && | |
x.VAT == VAT && | |
x.Amount == Amount; | |
} | |
public override int GetHashCode() | |
{ | |
return Name.GetHashCode() ^ Price.GetHashCode() ^ VAT.GetHashCode() ^ Amount.GetHashCode(); | |
} | |
} | |
public readonly IEnumerable<Item> Items; | |
public Invoice(IEnumerable<Item> Items) | |
{ | |
this.Items = Items; | |
} | |
public class ItemList:List<Item> | |
{ | |
public void Add(String Name, decimal Amount, decimal Price, decimal VAT) | |
{ | |
this.Add(new Item(Name,Amount,Price,VAT)); | |
} | |
} | |
} | |
public enum VATCode | |
{ | |
Unknown, | |
Regular, | |
Food, | |
None | |
} | |
public class VATRates : Dictionary<VATCode, decimal> { } | |
public class Article | |
{ | |
public readonly string Id; | |
public readonly VATCode VATCode; | |
public readonly string Name; | |
public readonly decimal Price; | |
public Article(string Id, string Name, decimal Price, VATCode VAT) | |
{ | |
this.Id = Id; | |
this.Name = Name; | |
this.Price = Price; | |
this.VATCode = VAT; | |
} | |
public class Dictionary : Dictionary<string, Article> | |
{ | |
public void Add(string Id, string Name, int Price, VATCode VATCode) | |
{ | |
this.Add(Id, new Article(Id, Name, Price, VATCode)); | |
} | |
} | |
} | |
public class ArticleNotFoundException : Exception { } | |
public class VATRateNotFoundException : Exception { } | |
class Invoicer | |
{ | |
private VATRates VATRates; | |
private Article.Dictionary Articles; | |
public Invoicer(VATRates VATRates, Article.Dictionary Articles) | |
{ | |
this.VATRates = VATRates; | |
this.Articles = Articles; | |
} | |
public Invoice BillOrder(Order o) | |
{ | |
Invoice.ItemList items = new Invoice.ItemList(); | |
foreach (var orderline in o.Lines) | |
{ | |
Article article; | |
Decimal vatcode; | |
if (!Articles.TryGetValue(orderline.ArticleId, out article)) throw new ArticleNotFoundException(); | |
if (!VATRates.TryGetValue(article.VATCode, out vatcode)) throw new VATRateNotFoundException(); | |
var total = orderline.Amount * article.Price; | |
items.Add(article.Name, orderline.Amount, total, total * vatcode); | |
} | |
return new Invoice(items); | |
} | |
} | |
[TestClass] | |
public class Bill_order_tests | |
{ | |
Invoicer SUT; | |
Order.LineList OrderLines; | |
string unknown_article_id, article_id_with_unknown_vat; | |
[TestInitialize] | |
public void Setup() | |
{ | |
var rates = new VATRates(); | |
rates.Add(VATCode.Regular, .21M); | |
rates.Add(VATCode.Food, .06M); | |
rates.Add(VATCode.None, 0); | |
var articles = new Article.Dictionary(); | |
articles.Add("HTC-123", "HTC One Two TTT", 1000, VATCode.Regular); | |
articles.Add("APPL", "Apple blah", 1, VATCode.Food); | |
articles.Add("RNV", "Stairs renovation", 1500, VATCode.None); | |
articles.Add("???", "VAT Unknown", 123, VATCode.Unknown); | |
SUT = new Invoicer(rates, articles); | |
OrderLines = new Order.LineList(); | |
OrderLines.Add("HTC-123", 1); | |
OrderLines.Add("APPL", 12); | |
OrderLines.Add("RNV", 1); | |
unknown_article_id = "XYZ"; | |
article_id_with_unknown_vat = "???"; | |
} | |
[TestMethod] | |
public void Bill_an_order() | |
{ | |
var invoice = SUT.BillOrder(new Order(OrderLines)); | |
var invoiceItems = invoice.Items.ToArray(); | |
var expectedItems = new Invoice.ItemList(); | |
expectedItems.Add("HTC One Two TTT", 1, 1000, 210); | |
expectedItems.Add("Apple blah", 12, 12, 0.72M); | |
expectedItems.Add("Stairs renovation", 1, 1500, 0); | |
Assert.AreEqual(invoiceItems[0], expectedItems[0]); | |
Assert.AreEqual(invoiceItems[1], expectedItems[1]); | |
Assert.AreEqual(invoiceItems[2], expectedItems[2]); | |
} | |
[TestMethod] | |
[ExpectedException(typeof(ArticleNotFoundException))] | |
public void Bill_an_order_with_an_unkown_article() | |
{ | |
OrderLines.Add(unknown_article_id, 5); | |
SUT.BillOrder(new Order(OrderLines)); | |
} | |
[TestMethod] | |
[ExpectedException(typeof(VATRateNotFoundException))] | |
public void Bill_an_order_with_an_unknown_VAT_code() | |
{ | |
OrderLines.Add(article_id_with_unknown_vat, 5); | |
SUT.BillOrder(new Order(OrderLines)); | |
} | |
} | |
} |
This file contains hidden or 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
open System | |
type OrderLine = { ArticleId: string; Amount: decimal } | |
type Order = { Lines: OrderLine list} | |
type VATType = | Unknown | Regular | Food | NoVAT | |
type VatRates = Map<VATType, decimal> | |
type InvoiceItem = {Name:string; Amount: decimal; Price: decimal; VAT: decimal} | |
type Invoice = { Items: InvoiceItem list} | |
type Article = {ArticleId: string; Name: string; Price: decimal; VATCode: VATType} | |
type Articles = Article list | |
exception ArticleNotFoundException | |
type Result<'T> = Success of 'T | Failure of exn | |
module Invoicer = | |
let billOrder vatRates order articles = | |
let getVat article = Map.find article.VATCode vatRates | |
let invoice list (line:OrderLine) = | |
match list, Map.tryFind line.ArticleId articles with | |
| Success l, Some article -> | |
Success ( { Name = article.Name | |
Amount = line.Amount | |
Price = article.Price | |
VAT = getVat article} :: l) | |
| _ -> Failure (ArticleNotFoundException) | |
order.Lines | |
|> List.fold invoice (Success []) | |
|> function | |
| Success lines -> Success { Items = lines } | |
| Failure ex -> Failure ex |
Just changed it to return a Result oft Invoice instead of a Result of InvoiceItem list
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In this version, it returns a Success or a failure. No more exceptions.