Skip to content

Instantly share code, notes, and snippets.

@agonzalezro
Created January 30, 2014 09:09
Show Gist options
  • Save agonzalezro/8705016 to your computer and use it in GitHub Desktop.
Save agonzalezro/8705016 to your computer and use it in GitHub Desktop.
import unittest
PRICE_KEY = 'price'
OFFER_AFTER_KEY = 'offer_after'
DISCOUNT_KEY = 'discount'
PRODUCT_PRICING_DETAILS = {
'A': {
PRICE_KEY: 50,
OFFER_AFTER_KEY: 3,
DISCOUNT_KEY: 20
},
'B': {
PRICE_KEY: 30,
OFFER_AFTER_KEY: 2,
DISCOUNT_KEY: 15
},
'C': {
PRICE_KEY: 20
},
'D': {
PRICE_KEY: 15
}
}
class ProductNotFound(Exception):
pass
def _can_apply_discount_to_product(product):
return DISCOUNT_KEY in PRODUCT_PRICING_DETAILS[product]
def _price_for_product(product):
if product in PRODUCT_PRICING_DETAILS:
return PRODUCT_PRICING_DETAILS[product][PRICE_KEY]
raise ProductNotFound
def _get_discount(product, quantity):
discount_total = 0
if _can_apply_discount_to_product(product):
discount = PRODUCT_PRICING_DETAILS[product][DISCOUNT_KEY]
how_many_times_apply = (
quantity / PRODUCT_PRICING_DETAILS[product][OFFER_AFTER_KEY]
)
discount_total = discount * how_many_times_apply
return discount_total
def price_for_basket(basket):
counters = {}
total = 0
total_discount = 0
for product in basket:
total += _price_for_product(product)
counters.setdefault(product, 0)
counters[product] += 1
for product, quantity in counters.iteritems():
total_discount += _get_discount(product, quantity)
return total - total_discount
class Test(unittest.TestCase):
def test_no_products(self):
"""No products given should return 0."""
self.assertEqual(price_for_basket(''), 0)
def test_one_product_type_A(self):
"""Test that given a product type A the total is 50 pounds."""
self.assertEqual(price_for_basket('A'), 50)
def test_two_products_type_A(self):
"""Test that given two products type A the total is 100 pounds."""
self.assertEqual(price_for_basket('AA'), 100)
def test_product_type_A_offer(self):
"""Test that given 3 or more products type A the offer is applied."""
self.assertEqual(price_for_basket('AAA'), 130)
self.assertEqual(price_for_basket('AAAA'), 180)
self.assertEqual(price_for_basket('AAAAAA'), 260)
def test_one_product_type_B(self):
"""Test that one product B have a value of 30."""
self.assertEqual(price_for_basket('B'), 30)
def test_two_products_type_B(self):
"""Test that 2 product of type B have a value of 45 (discount applied).
"""
self.assertEqual(price_for_basket('BB'), 45)
def test_product_type_B_offers(self):
"""Test that discounts for the product B are applied."""
self.assertEqual(price_for_basket('BBBB'), 90)
self.assertEqual(price_for_basket('BBBBB'), 120)
def test_product_type_A_and_B(self):
"""Test that a mixed basket return proper values."""
self.assertEqual(price_for_basket('AB'), 80)
def test_special_offer_A_and_single_B(self):
"""Test that a basket with 3 As and one B is going to apply the
discount for A and a normal price for B.
"""
self.assertEqual(price_for_basket('ABAA'), 160)
def test_one_product_type_C(self):
"""Test that giving one product of type C the value of the basket will
be 20.
"""
self.assertEqual(price_for_basket('C'), 20)
def test_two_products_type_C(self):
"""Test that giving two products of type C no disccounts are going to
be applied.
"""
self.assertEqual(price_for_basket('CC'), 40)
def test_one_product_type_D(self):
"""Test that one product of type D is going to have a value of 15."""
self.assertEqual(price_for_basket('D'), 15)
def test_mixed_basket(self):
expected = 115
self.assertEqual(price_for_basket('ABCD'), expected)
self.assertEqual(price_for_basket('DCBA'), expected)
self.assertEqual(price_for_basket('BDCA'), expected)
def test_non_expected_product(self):
"""Test that an unexpected product raises a ProductNotFound exception.
"""
self.assertRaises(ProductNotFound, price_for_basket, 'E')
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment