diff --git a/TypeScript/app/gilded-rose.ts b/TypeScript/app/gilded-rose.ts index db58d678..6d50231a 100644 --- a/TypeScript/app/gilded-rose.ts +++ b/TypeScript/app/gilded-rose.ts @@ -1,69 +1,11 @@ -export class Item { - name: string; - sellIn: number; - quality: number; - - constructor(name, sellIn, quality) { - this.name = name; - this.sellIn = sellIn; - this.quality = quality; - } -} - +import Item from "./models/Item"; +import { UpdateStrategyFactory } from "./updateStrategyFactory"; export class GildedRose { - items: Array; + private constructor() {} - constructor(items = [] as Array) { - this.items = items; - } - - updateQuality() { - for (let i = 0; i < this.items.length; i++) { - if (this.items[i].name != 'Aged Brie' && this.items[i].name != 'Backstage passes to a TAFKAL80ETC concert') { - if (this.items[i].quality > 0) { - if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') { - this.items[i].quality = this.items[i].quality - 1 - } - } - } else { - if (this.items[i].quality < 50) { - this.items[i].quality = this.items[i].quality + 1 - if (this.items[i].name == 'Backstage passes to a TAFKAL80ETC concert') { - if (this.items[i].sellIn < 11) { - if (this.items[i].quality < 50) { - this.items[i].quality = this.items[i].quality + 1 - } - } - if (this.items[i].sellIn < 6) { - if (this.items[i].quality < 50) { - this.items[i].quality = this.items[i].quality + 1 - } - } - } - } - } - if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') { - this.items[i].sellIn = this.items[i].sellIn - 1; - } - if (this.items[i].sellIn < 0) { - if (this.items[i].name != 'Aged Brie') { - if (this.items[i].name != 'Backstage passes to a TAFKAL80ETC concert') { - if (this.items[i].quality > 0) { - if (this.items[i].name != 'Sulfuras, Hand of Ragnaros') { - this.items[i].quality = this.items[i].quality - 1 - } - } - } else { - this.items[i].quality = this.items[i].quality - this.items[i].quality - } - } else { - if (this.items[i].quality < 50) { - this.items[i].quality = this.items[i].quality + 1 - } - } - } - } - - return this.items; + static updateQuality(items = [] as Array) { + let updatedItems = items.map( + item => UpdateStrategyFactory.getUpdateStrategy(item).updateItem(item)); + return updatedItems; } } diff --git a/TypeScript/app/models/Item.ts b/TypeScript/app/models/Item.ts new file mode 100644 index 00000000..636c95d0 --- /dev/null +++ b/TypeScript/app/models/Item.ts @@ -0,0 +1,11 @@ +export default class Item { + name: string; + sellIn: number; + quality: number; + + constructor(name, sellIn, quality) { + this.name = name; + this.sellIn = sellIn; + this.quality = quality; + } +} diff --git a/TypeScript/app/updateStrategies/AgedBrieStrategy.ts b/TypeScript/app/updateStrategies/AgedBrieStrategy.ts new file mode 100644 index 00000000..979bb7c6 --- /dev/null +++ b/TypeScript/app/updateStrategies/AgedBrieStrategy.ts @@ -0,0 +1,12 @@ +import Item from "./../models/Item"; +import IUpdateStrategy from "./IUpdateStrategy"; + +export default class AgedBrieStrategy implements IUpdateStrategy { + constructor(private qualityFactor : number) {} + + updateItem(item: Item) : Item { + let quality = Math.min(50, item.quality + 1 * this.qualityFactor); + let sellIn = item.sellIn - 1; + return new Item(item.name, sellIn, quality); + } +} diff --git a/TypeScript/app/updateStrategies/BackstagePassStrategy.ts b/TypeScript/app/updateStrategies/BackstagePassStrategy.ts new file mode 100644 index 00000000..4a08d043 --- /dev/null +++ b/TypeScript/app/updateStrategies/BackstagePassStrategy.ts @@ -0,0 +1,20 @@ +import Item from "./../models/Item"; +import IUpdateStrategy from "./IUpdateStrategy"; + +export default class BackstagePassStrategy implements IUpdateStrategy { + updateItem(item: Item) : Item { + let increaseFactor = this.getIncreaseFactor(item.sellIn); + let newQuality = + increaseFactor + ? Math.min(50, item.quality + increaseFactor) + : 0; + let newSellIn = item.sellIn - 1; + return new Item(item.name, newSellIn, newQuality); + } + + private getIncreaseFactor(sellIn: number){ + if (sellIn > 10) return 1; + if (sellIn <= 10 && sellIn > 5) return 2; + if (sellIn <= 5 && sellIn > 0) return 3; + } +} diff --git a/TypeScript/app/updateStrategies/DefaultStrategy.ts b/TypeScript/app/updateStrategies/DefaultStrategy.ts new file mode 100644 index 00000000..f182540c --- /dev/null +++ b/TypeScript/app/updateStrategies/DefaultStrategy.ts @@ -0,0 +1,13 @@ +import Item from "./../models/Item"; +import IUpdateStrategy from "./IUpdateStrategy"; + + +export default class DefaultStrategy implements IUpdateStrategy { + constructor(private qualityFactor : number) {} + + updateItem(item: Item) : Item { + let newQuality = Math.max(0, item.quality - this.qualityFactor); + let newSellIn = item.sellIn - 1; + return new Item(item.name, newSellIn, newQuality); + } +} diff --git a/TypeScript/app/updateStrategies/IUpdateStrategy.ts b/TypeScript/app/updateStrategies/IUpdateStrategy.ts new file mode 100644 index 00000000..6672321d --- /dev/null +++ b/TypeScript/app/updateStrategies/IUpdateStrategy.ts @@ -0,0 +1,6 @@ +import Item from "./../models/Item"; + + +export default interface IUpdateStrategy { + updateItem(item: Item) : Item; +} diff --git a/TypeScript/app/updateStrategies/NoUpdateStrategy.ts b/TypeScript/app/updateStrategies/NoUpdateStrategy.ts new file mode 100644 index 00000000..af7b1af1 --- /dev/null +++ b/TypeScript/app/updateStrategies/NoUpdateStrategy.ts @@ -0,0 +1,8 @@ +import Item from "@/models/Item"; +import IUpdateStrategy from "./IUpdateStrategy"; + +export default class NoUpdateStrategy implements IUpdateStrategy { + updateItem(item: Item) : Item { + return new Item(item.name, item.sellIn, item.quality); + } +} \ No newline at end of file diff --git a/TypeScript/app/updateStrategies/conjuredStrategy.ts b/TypeScript/app/updateStrategies/conjuredStrategy.ts new file mode 100644 index 00000000..ebec9ffe --- /dev/null +++ b/TypeScript/app/updateStrategies/conjuredStrategy.ts @@ -0,0 +1,12 @@ +import Item from "./../models/Item"; +import IUpdateStrategy from "./IUpdateStrategy"; + +export default class ConjuredStrategy implements IUpdateStrategy { + constructor(private qualityFactor : number) {} + + updateItem(item: Item) : Item { + let quality = Math.max(0, item.quality - 2 * this.qualityFactor); + let sellIn = item.sellIn - 1; + return new Item(item.name, sellIn, quality); + } +} diff --git a/TypeScript/app/updateStrategyFactory.ts b/TypeScript/app/updateStrategyFactory.ts new file mode 100644 index 00000000..44a7abca --- /dev/null +++ b/TypeScript/app/updateStrategyFactory.ts @@ -0,0 +1,27 @@ +import Item from "./models/Item"; +import AgedBrieStrategy from "./updateStrategies/AgedBrieStrategy"; +import BackstagePassStrategy from "./updateStrategies/BackstagePassStrategy"; +import ConjuredStrategy from "./updateStrategies/conjuredStrategy"; +import DefaultStrategy from "./updateStrategies/DefaultStrategy"; +import IUpdateStrategy from "./updateStrategies/IUpdateStrategy"; +import NoUpdateStrategy from "./updateStrategies/NoUpdateStrategy"; + +export class UpdateStrategyFactory { + static getUpdateStrategy(item: Item): IUpdateStrategy { + + let qualityFactor = item.sellIn <= 0 ? 2 : 1; + + switch (item.name) { + case 'Aged Brie': + return new AgedBrieStrategy(qualityFactor); + case 'Sulfuras, Hand of Ragnaros': + return new NoUpdateStrategy(); + case 'Backstage passes to a TAFKAL80ETC concert': + return new BackstagePassStrategy(); + case 'conjured': + return new ConjuredStrategy(qualityFactor); + default: + return new DefaultStrategy(qualityFactor); + } + } +} \ No newline at end of file diff --git a/TypeScript/test/golden-master-text-test.ts b/TypeScript/test/golden-master-text-test.ts index 2259b975..8545207b 100644 --- a/TypeScript/test/golden-master-text-test.ts +++ b/TypeScript/test/golden-master-text-test.ts @@ -1,4 +1,5 @@ -import { Item, GildedRose } from '../app/gilded-rose'; +import { GildedRose } from '../app/gilded-rose'; +import Item from "../app/models/Item"; const items = [ new Item("+5 Dexterity Vest", 10, 20), // @@ -12,9 +13,6 @@ const items = [ // this conjured item does not work properly yet new Item("Conjured Mana Cake", 3, 6)]; - -const gildedRose = new GildedRose(items); - let days: number = 2; if (process.argv.length > 2) { days = +process.argv[2]; @@ -28,5 +26,5 @@ for (let i = 0; i < days; i++) { }); console.log(); - gildedRose.updateQuality(); + GildedRose.updateQuality(items); } diff --git a/TypeScript/test/jest/gilded-rose.spec.ts b/TypeScript/test/jest/gilded-rose.spec.ts index 65330750..337a4c9b 100644 --- a/TypeScript/test/jest/gilded-rose.spec.ts +++ b/TypeScript/test/jest/gilded-rose.spec.ts @@ -1,9 +1,46 @@ -import { Item, GildedRose } from '@/gilded-rose'; +import { GildedRose } from '@/gilded-rose'; +import Item from "@/models/Item"; describe('Gilded Rose', () => { - it('should foo', () => { - const gildedRose = new GildedRose([new Item('foo', 0, 0)]); - const items = gildedRose.updateQuality(); - expect(items[0].name).toBe('fixme'); - }); + it.each` + name | quality | expectedQuality | sellIn | expectedSellIn | description + ${'abc def'} | ${0} | ${0} | ${8} | ${7} | ${"quality should not be negative"} + ${'abc def'} | ${0} | ${0} | ${0} | ${-1} | ${"sellIn should decrease"} + ${'abc def'} | ${8} | ${6} | ${0} | ${-1} | ${"quality should decrease twice after sellIn is negative"} + ${'Aged Brie'} | ${0} | ${1} | ${8} | ${7} | ${"should increase quality by 1"} + ${'Aged Brie'} | ${0} | ${2} | ${0} | ${-1} | ${"should increase quality by 1"} + ${'Aged Brie'} | ${50} | ${50} | ${8} | ${7} | ${"quality should not be higher than 50"} + ${'conjured'} | ${0} | ${0} | ${8} | ${7} | ${"quality should not be negative"} + ${'conjured'} | ${0} | ${0} | ${0} | ${-1} | ${"quality should not be negative"} + ${'conjured'} | ${4} | ${2} | ${8} | ${7} | ${"quality should decrease by 2"} + ${'conjured'} | ${4} | ${0} | ${0} | ${-1} | ${"quality should decrease by 4 when sellIn is <= 0"} + ${'Sulfuras, Hand of Ragnaros'} | ${10} | ${10} | ${10} | ${10} | ${"should not change "} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${11}| ${11} | ${10} | ${"quality increases by 1 for sellIn > 10"} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${11}| ${30} | ${29} | ${"quality increases by 1 for sellIn > 10"} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${12}| ${10} | ${9} | ${"quality increases by 2 for sellIn <= 10 && > 5"} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${12}| ${6} | ${5} | ${"quality increases by 2 for sellIn <= 10 && > 5"} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${13}| ${5} | ${4} | ${"quality increases by 3 for sellIn <= 5 && >= 0"} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${13}| ${1} | ${0} | ${"quality increases by 3 for sellIn <= 5 && > 0"} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${0} | ${0} | ${-1} | ${"quality is 0 if sellIn is exceeded"} + ${'Backstage passes to a TAFKAL80ETC concert'} | ${10}| ${0} | ${-1} | ${-2} | ${"quality is 0 if sellIn is exceeded"} +`("'$description' for '$name' with quality '$quality' and sellIn '$sellIn'", ({name, quality, expectedQuality, sellIn, expectedSellIn, description}) => { + const item1 = new Item(name, sellIn, quality); + const items = GildedRose.updateQuality([item1]); + expect(items[0].name).toBe(name); + expect(items[0].quality).toBe(expectedQuality); + expect(items[0].sellIn).toBe(expectedSellIn); + }); + + it("should be correct for 2 items", () => { + const item1 = new Item('abc def', 8, 5); + const item2 = new Item('Aged Brie', 10, 2); + const items = GildedRose.updateQuality([item1, item2]); + expect(items[0].name).toBe(item1.name); + expect(items[0].quality).toBe(4); + expect(items[0].sellIn).toBe(7); + expect(items[1].name).toBe(item2.name); + expect(items[1].quality).toBe(3); + expect(items[1].sellIn).toBe(9); + }); }); + diff --git a/TypeScript/test/mocha/gilded-rose.spec.ts b/TypeScript/test/mocha/gilded-rose.spec.ts index 02cd24c5..ab7b82ae 100644 --- a/TypeScript/test/mocha/gilded-rose.spec.ts +++ b/TypeScript/test/mocha/gilded-rose.spec.ts @@ -1,10 +1,11 @@ import { expect } from 'chai'; -import { Item, GildedRose } from '@/gilded-rose'; +import { GildedRose } from '@/gilded-rose'; +import Item from "@/models/Item"; describe('Gilded Rose', () => { it('should foo', () => { - const gildedRose = new GildedRose([new Item('foo', 0, 0)]); - const items = gildedRose.updateQuality(); - expect(items[0].name).to.equal('fixme'); + // const gildedRose = new GildedRose([new Item('foo', 0, 0)]); + // const items = gildedRose.updateQuality(); + expect("items[0].name").to.equal('fixme'); }); });