Skip to content

Instantly share code, notes, and snippets.

@JakubOboza
Created August 20, 2014 15:27
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 JakubOboza/af1f8b90f9de7f472dcb to your computer and use it in GitHub Desktop.
Save JakubOboza/af1f8b90f9de7f472dcb to your computer and use it in GitHub Desktop.
require 'minitest/autorun'
# Money are in floats for simplicity, it should be bigint
# Promotions are prioritized in order [A,B] => A rule is applied first, B rule is applied second
class Item
attr_accessor :name, :price, :product_code
def initialize(name, price, product_code)
@name = name
@price = price
@product_code = product_code
end
end
class OverLimitPromoRule
attr_reader :limit
def initialize(limit = 60)
@limit = limit
end
attr_accessor :cart
def discount(total, cart)
@cart = cart
if total > @limit
return total * 0.1
end
end
end
class TwoOrMorePromoRule
attr_accessor :cart, :product_code, :unit_discount
def initialize(product_code, unit_discount)
@product_code = product_code
@unit_discount = unit_discount
end
def discount(total, cart)
promo_items = cart.select {|item| item.product_code == @product_code }
if promo_items.size > 1
return promo_items.size * @unit_discount
end
end
end
class Checkout
attr_reader :promo_rules, :cart
def initialize(promo_rules)
@cart = []
@promo_rules = promo_rules
end
def scan(item)
@cart << item
end
def total
raw_total = @cart.inject(0){|acc, item| acc += item.price }
total = @promo_rules.inject(raw_total){|total, rule| total -= rule.discount(total, @cart).to_f }.round(2)
end
end
describe Item do
it "has name, price and product code" do
[:name, :price, :product_code].each do |field|
Item.new("Travel Card Holder", 9.25, "001" ).must_respond_to field
end
end
end
describe OverLimitPromoRule do
it "can produce discount for a cart" do
cart = [
Item.new("Travel Card Holder", 40.0, "001"),
Item.new("Travel Card Holder Holder", 60.0, "002")
]
OverLimitPromoRule.new.discount(100, cart).must_equal 10.0
end
it "don't give any discount if you are below limit" do
cart = [
Item.new("Travel Card Holder", 4.0, "001"),
Item.new("Travel Card Holder Holder", 6.0, "002")
]
OverLimitPromoRule.new.discount(10, cart).must_be_nil
end
end
describe TwoOrMorePromoRule do
it "can produce discount for a cart" do
cart = [
Item.new("Travel Card Holder", 9.25, "001"),
Item.new("Travel Card Holder", 9.25, "001"),
Item.new("Travel Card Holder Holder", 60.0, "002")
]
TwoOrMorePromoRule.new("001", 0.75).discount(100, cart).must_equal 1.50
end
it "don't give any discount if you are below limit" do
cart = [
Item.new("Travel Card Holder", 4.0, "001"),
Item.new("Travel Card Holder Holder", 6.0, "002")
]
TwoOrMorePromoRule.new("001", 0.75).discount(100, cart).must_be_nil
end
end
describe Checkout do
before do
@promotional_rules = [
TwoOrMorePromoRule.new("001", 0.75),
OverLimitPromoRule.new
]
@item1 = Item.new("Travel Card Holder", 9.25, "001")
@item2 = Item.new("Personalised cufflinks", 45.00, "002")
@item3 = Item.new("Kids T-shirt", 19.95, "003")
@co = Checkout.new(@promotional_rules)
end
describe "it can checkout!" do
it "must not explode and give you back value" do
@co.scan(@item1)
@co.scan(@item2)
price = @co.total
price.wont_be_nil
end
it "must give back for 66.78 basket 001,002,003" do
@co.scan(@item1)
@co.scan(@item2)
@co.scan(@item3)
@co.total.must_equal 66.78
end
it "must give back for 36.95 basket 001,003,001" do
@co.scan(@item1)
@co.scan(@item3)
@co.scan(@item1)
@co.total.must_equal 36.95
end
it "must give back for 73.76 basket 001,002,001,003" do
@co.scan(@item1)
@co.scan(@item2)
@co.scan(@item1)
@co.scan(@item3)
@co.total.must_equal 73.76
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment