From b11b0ff8e1efb8fde5130b0512e68250ca233107 Mon Sep 17 00:00:00 2001 From: Facundo Alvarez Date: Tue, 14 Feb 2023 11:17:32 +0100 Subject: [PATCH] Update: Refactored the codebase by adding more tests and implementing conjured items. --- .gitignore | 1 + python/gilded_rose.py | 147 +++++++++++++++++++++---------- python/test_gilded_rose.py | 153 +++++++++++++++++++++++++++++---- python/texttest_fixture.py | 62 ++++++------- texttests/ThirtyDays/stdout.gr | 8 +- texttests/config.gr | 8 +- 6 files changed, 279 insertions(+), 100 deletions(-) diff --git a/.gitignore b/.gitignore index 95bd72b9..20374295 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ obj vendor .idea *.iml +__pycache__ \ No newline at end of file diff --git a/python/gilded_rose.py b/python/gilded_rose.py index 4f21ea64..7284d7b9 100755 --- a/python/gilded_rose.py +++ b/python/gilded_rose.py @@ -1,46 +1,101 @@ -# -*- coding: utf-8 -*- - -class GildedRose(object): - - def __init__(self, items): - self.items = items - - def update_quality(self): - for item in self.items: - if item.name != "Aged Brie" and item.name != "Backstage passes to a TAFKAL80ETC concert": - if item.quality > 0: - if item.name != "Sulfuras, Hand of Ragnaros": - item.quality = item.quality - 1 - else: - if item.quality < 50: - item.quality = item.quality + 1 - if item.name == "Backstage passes to a TAFKAL80ETC concert": - if item.sell_in < 11: - if item.quality < 50: - item.quality = item.quality + 1 - if item.sell_in < 6: - if item.quality < 50: - item.quality = item.quality + 1 - if item.name != "Sulfuras, Hand of Ragnaros": - item.sell_in = item.sell_in - 1 - if item.sell_in < 0: - if item.name != "Aged Brie": - if item.name != "Backstage passes to a TAFKAL80ETC concert": - if item.quality > 0: - if item.name != "Sulfuras, Hand of Ragnaros": - item.quality = item.quality - 1 - else: - item.quality = item.quality - item.quality - else: - if item.quality < 50: - item.quality = item.quality + 1 - - -class Item: - def __init__(self, name, sell_in, quality): - self.name = name - self.sell_in = sell_in - self.quality = quality - - def __repr__(self): - return "%s, %s, %s" % (self.name, self.sell_in, self.quality) +class Item: + def __init__(self, name, sell_in, quality): + self.name = name + self.sell_in = sell_in + self.quality = quality + + def __repr__(self): + return f"{self.name}, {self.sell_in}, {self.quality}" + +class RegularItem(Item): + def update_quality(self): + if self.quality > 0: + self.quality -= 1 + if self.sell_in < 1: + if self.quality > 0: + self.quality -= 1 + self.sell_in -= 1 + + +class AgedBrie(Item): + def update_quality(self): + if self.quality < 50: + self.quality += 1 + if self.sell_in < 1: + if self.quality < 50: + self.quality += 1 + self.sell_in -= 1 + +class ElixirOfTheMongoose(Item): + def update_quality(self): + if self.quality > 0: + self.quality -= 1 + if self.sell_in < 1: + if self.quality > 0: + self.quality -= 1 + self.sell_in -= 1 + +class Sulfuras(Item): + def __init__(self, name, sell_in, quality): + super().__init__(name, sell_in, quality) + self.quality = 80 + + def update_quality(self): + pass + +class BackstagePass(Item): + def update_quality(self): + if self.quality < 50: + self.quality += 1 + if self.sell_in < 11: + if self.quality < 50: + self.quality += 1 + if self.sell_in < 6: + if self.quality < 50: + self.quality += 1 + if self.sell_in < 1: + self.quality = 0 + self.sell_in -= 1 + +class ConjuredItem(Item): + def update_quality(self): + if self.quality > 0: + self.quality -= 2 + if self.sell_in < 1: + if self.quality > 0: + self.quality -= 2 + self.sell_in -= 1 + + +class GildedRose: + def __init__(self, items: list): + self.items = self._special_items(items) + + def update_quality(self): + for item in self.items: + item.update_quality() + + def _special_items(self, items): + special_item_classes = { + "Aged Brie": AgedBrie, + "Elixir Of the Mongoose": ElixirOfTheMongoose, + "Sulfuras, Hand of Ragnaros": Sulfuras, + "Backstage passes": BackstagePass, + "Conjured": ConjuredItem + } + + corrected_list = [] + for item in items: + special_item_class = self._get_special_item_class(item.name, special_item_classes) + corrected_list.append(special_item_class(item.name, item.sell_in, item.quality)) + + return corrected_list + + def _get_special_item_class(self, item_name, special_item_classes): + for name, cls in special_item_classes.items(): + if name.lower() in item_name.lower() or item_name.lower() in name.lower(): + return cls + return RegularItem + + def get_items(self): + return self.items \ No newline at end of file diff --git a/python/test_gilded_rose.py b/python/test_gilded_rose.py index 616934e0..54af64b6 100644 --- a/python/test_gilded_rose.py +++ b/python/test_gilded_rose.py @@ -1,16 +1,137 @@ -# -*- coding: utf-8 -*- -import unittest - -from gilded_rose import Item, GildedRose - - -class GildedRoseTest(unittest.TestCase): - def test_foo(self): - items = [Item("foo", 0, 0)] - gilded_rose = GildedRose(items) - gilded_rose.update_quality() - self.assertEquals("fixme", items[0].name) - - -if __name__ == '__main__': - unittest.main() +import unittest +from gilded_rose import ( + GildedRose, + Item, + RegularItem, + AgedBrie, + ElixirOfTheMongoose, + Sulfuras, + BackstagePass, + ConjuredItem, +) + + +class TestGildedRose(unittest.TestCase): + def setUp(self): + self.items = [ + Item(name="+5 Dexterity Vest", sell_in=10, quality=20), + Item(name="Aged Brie", sell_in=2, quality=0), + Item(name="Elixir of the Mongoose", sell_in=5, quality=7), + Item(name="Sulfuras, Hand of Ragnaros", sell_in=29, quality=80), + Item( + name="Backstage passes to a TAFKAL80ETC concert", sell_in=15, quality=20 + ), + Item(name="Conjured", sell_in=3, quality=13), + ] + + self.gilded_rose = GildedRose(self.items) + + def test_update_quality(self): + # Test quality update after 4 days + for i in range(4): + self.gilded_rose.update_quality() + + items = self.gilded_rose.get_items() + self.assertEqual(items[0].quality, 16) + self.assertEqual(items[0].sell_in, 6) + self.assertEqual(items[1].quality, 6) + self.assertEqual(items[1].sell_in, -2) + self.assertEqual(items[2].quality, 3) + self.assertEqual(items[2].sell_in, 1) + self.assertEqual(items[3].quality, 80) + self.assertEqual(items[3].sell_in, 29) + self.assertEqual(items[4].quality, 24) + self.assertEqual(items[4].sell_in, 11) + self.assertEqual(items[5].quality, 3) + self.assertEqual(items[5].sell_in, -1) + + def test_special_item(self): + # Test special item creation + items = self.gilded_rose._special_items(self.items) + self.assertIsInstance(items[0], RegularItem) + self.assertIsInstance(items[1], AgedBrie) + self.assertIsInstance(items[2], ElixirOfTheMongoose) + self.assertIsInstance(items[3], Sulfuras) + self.assertIsInstance(items[4], BackstagePass) + self.assertIsInstance(items[5], ConjuredItem) + + def test_regular_item(self): + # Test case 1: check that quality of a RegularItem decreases by 1 per day before sell_in date, and by 2 after + items = [ + Item(name="+5 Dexterity Vest", sell_in=5, quality=20), + Item(name="+5 Strength Vest", sell_in=-1, quality=20), + ] + gilded_rose = GildedRose(items) + for days in range(5): + gilded_rose.update_quality() + + self.assertEqual(gilded_rose.get_items()[0].quality, 15) + self.assertEqual(gilded_rose.get_items()[1].quality, 10) + + def test_aged_brie(self): + # Test case 2: check that quality of AgedBrie increases by 1 per day before sell_in date, and by 2 after + items = [ + Item(name="Aged Brie", sell_in=10, quality=0), + Item(name="Aged Brie President", sell_in=-1, quality=0), + ] + + gilded_rose = GildedRose(items) + for days in range(5): + gilded_rose.update_quality() + + self.assertEqual(gilded_rose.get_items()[0].quality, 5) + self.assertEqual(gilded_rose.get_items()[1].quality, 10) + + def test_sulfuras(self): + # Test case 3: check that Sulfuras never decreases in quality or sell_in + items = [Item(name="Sulfuras, Hand of Ragnaros", sell_in=10, quality=80)] + gilded_rose = GildedRose(items) + gilded_rose.update_quality() + self.assertEqual(gilded_rose.get_items()[0].quality, 80) + self.assertEqual(gilded_rose.get_items()[0].sell_in, 10) + + def test_backstage_pass(self): + # Test case 4: check that BackstagePass increases by 1 per day before sell_in date, by 2 before 10 days, and by 3 before 5 days, and quality drops to 0 after the concert + items = [ + Item( + name="Backstage passes to a TAFKAL80ETC concert", sell_in=15, quality=10 + ) + ] + + gilded_rose = GildedRose(items) + for days in range(15, 10, -1): + gilded_rose.update_quality() + self.assertEqual(gilded_rose.get_items()[0].quality, 15) + + for days in range(10, 5, -1): + gilded_rose.update_quality() + self.assertEqual(gilded_rose.get_items()[0].quality, 25) + + for days in range(5, 0, -1): + gilded_rose.update_quality() + self.assertEqual(gilded_rose.get_items()[0].quality, 40) + + for days in range(0, -2, -1): + gilded_rose.update_quality() + self.assertEqual(gilded_rose.get_items()[0].quality, 0) + + def test_conjured(self): + # Test case 5: check that ConjuredItem decreases in quality twice as fast as RegularItem + items = [ + Item(name="Conjured", sell_in=10, quality=20), + Item(name="+10 Agility Dagger", sell_in=10, quality=20), + ] + gilded_rose = GildedRose(items) + items = gilded_rose.get_items() + for days in range(5): + gilded_rose.update_quality() + + self.assertIsInstance(items[0], ConjuredItem) + self.assertIsInstance(items[1], RegularItem) + self.assertEqual(items[0].quality, 10) + self.assertEqual(items[1].quality, 15) + self.assertGreater(items[1].quality, items[0].quality) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/texttest_fixture.py b/python/texttest_fixture.py index 86af5ef7..4c30cdc1 100644 --- a/python/texttest_fixture.py +++ b/python/texttest_fixture.py @@ -1,30 +1,32 @@ -# -*- coding: utf-8 -*- -from __future__ import print_function - -from gilded_rose import * - -if __name__ == "__main__": - print ("OMGHAI!") - items = [ - Item(name="+5 Dexterity Vest", sell_in=10, quality=20), - Item(name="Aged Brie", sell_in=2, quality=0), - Item(name="Elixir of the Mongoose", sell_in=5, quality=7), - Item(name="Sulfuras, Hand of Ragnaros", sell_in=0, quality=80), - Item(name="Sulfuras, Hand of Ragnaros", sell_in=-1, quality=80), - Item(name="Backstage passes to a TAFKAL80ETC concert", sell_in=15, quality=20), - Item(name="Backstage passes to a TAFKAL80ETC concert", sell_in=10, quality=49), - Item(name="Backstage passes to a TAFKAL80ETC concert", sell_in=5, quality=49), - Item(name="Conjured Mana Cake", sell_in=3, quality=6), # <-- :O - ] - - days = 2 - import sys - if len(sys.argv) > 1: - days = int(sys.argv[1]) + 1 - for day in range(days): - print("-------- day %s --------" % day) - print("name, sellIn, quality") - for item in items: - print(item) - print("") - GildedRose(items).update_quality() +# -*- coding: utf-8 -*- +from __future__ import print_function + +from gilded_rose import * + +if __name__ == "__main__": + print ("OMGHAI!") + items = [ + Item(name="+5 Dexterity Vest", sell_in=10, quality=20), + Item(name="Aged Brie", sell_in=2, quality=0), + Item(name="Elixir of the Mongoose", sell_in=5, quality=7), + Item(name="Sulfuras, Hand of Ragnaros", sell_in=0, quality=80), + Item(name="Sulfuras, Hand of Ragnaros", sell_in=-1, quality=80), + Item(name="Backstage passes to a TAFKAL80ETC concert", sell_in=15, quality=20), + Item(name="Backstage passes to a TAFKAL80ETC concert", sell_in=10, quality=49), + Item(name="Backstage passes to a TAFKAL80ETC concert", sell_in=5, quality=49), + Item(name="Conjured Mana Cake", sell_in=3, quality=6), # <-- :O + ] + + gilded_rose = GildedRose(items) + items = gilded_rose.get_items() + days = 30 + import sys + if len(sys.argv) > 1: + days = int(sys.argv[1]) + 1 + for day in range(days): + print("-------- day %s --------" % day) + print("name, sellIn, quality") + for item in items: + print(item) + print("") + gilded_rose.update_quality() diff --git a/texttests/ThirtyDays/stdout.gr b/texttests/ThirtyDays/stdout.gr index a04e48ac..4e7237ff 100644 --- a/texttests/ThirtyDays/stdout.gr +++ b/texttests/ThirtyDays/stdout.gr @@ -21,7 +21,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 14, 21 Backstage passes to a TAFKAL80ETC concert, 9, 50 Backstage passes to a TAFKAL80ETC concert, 4, 50 -Conjured Mana Cake, 2, 5 +Conjured Mana Cake, 2, 4 -------- day 2 -------- name, sellIn, quality @@ -33,7 +33,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 13, 22 Backstage passes to a TAFKAL80ETC concert, 8, 50 Backstage passes to a TAFKAL80ETC concert, 3, 50 -Conjured Mana Cake, 1, 4 +Conjured Mana Cake, 1, 2 -------- day 3 -------- name, sellIn, quality @@ -45,7 +45,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 12, 23 Backstage passes to a TAFKAL80ETC concert, 7, 50 Backstage passes to a TAFKAL80ETC concert, 2, 50 -Conjured Mana Cake, 0, 3 +Conjured Mana Cake, 0, 0 -------- day 4 -------- name, sellIn, quality @@ -57,7 +57,7 @@ Sulfuras, Hand of Ragnaros, -1, 80 Backstage passes to a TAFKAL80ETC concert, 11, 24 Backstage passes to a TAFKAL80ETC concert, 6, 50 Backstage passes to a TAFKAL80ETC concert, 1, 50 -Conjured Mana Cake, -1, 1 +Conjured Mana Cake, -1, 0 -------- day 5 -------- name, sellIn, quality diff --git a/texttests/config.gr b/texttests/config.gr index 7183e174..e1fcc2d3 100755 --- a/texttests/config.gr +++ b/texttests/config.gr @@ -1,12 +1,12 @@ full_name:Gilded Rose Refactoring Kata # set your preferred editor and diff tool. -view_program:subl -diff_program:meld +view_program:code +diff_program:code # Settings for the Python version -#executable:${TEXTTEST_HOME}/python/texttest_fixture.py -#interpreter:python +executable:/home/facu/Downloads/codigos/Entrevistas_codigos/StockAgile/GildedRose-Refactoring-Kata/python/texttest_fixture.py +interpreter:python3 # Settings for the cpp version #executable:${TEXTTEST_HOME}/cpp/cmake-build-debug/test/cpp_texttest/GildedRoseTextTests