diff --git a/go/Makefile b/go/Makefile new file mode 100644 index 00000000..d060e814 --- /dev/null +++ b/go/Makefile @@ -0,0 +1,20 @@ +NAME := gilded-rose + +# set default compiler +GO := go + +.PHONY: prebuild +prebuild: + +all: lint test + +.PHONY: lint +lint: ## Verifies `golint` passes. + @echo "+ $@" + @golint ./... | grep -v '.pb.go:' | grep -v vendor | tee /dev/stderr + +.PHONY: test +test: prebuild ## Runs the go tests. + @echo "+ $@" + @$(GO) test -v $(shell $(GO) list ./... | grep -v vendor) + diff --git a/go/gilded-rose.go b/go/gilded-rose.go index 57d2f189..8929714a 100644 --- a/go/gilded-rose.go +++ b/go/gilded-rose.go @@ -1,58 +1,159 @@ package main +import "fmt" + type Item struct { name string sellIn, quality int } -func UpdateQuality(items []*Item) { - for i := 0; i < len(items); i++ { +var items = []Item{ + Item{"+5 Dexterity Vest", 10, 20}, + Item{"Aged Brie", 2, 0}, + Item{"Elixir of the Mongoose", 5, 7}, + Item{"Sulfuras, Hand of Ragnaros", 0, 80}, + Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, + Item{"Conjured Mana Cake", 3, 6}, +} - if items[i].name != "Aged Brie" && items[i].name != "Backstage passes to a TAFKAL80ETC concert" { - if items[i].quality > 0 { - if items[i].name != "Sulfuras, Hand of Ragnaros" { - items[i].quality = items[i].quality - 1 - } - } - } else { - if items[i].quality < 50 { - items[i].quality = items[i].quality + 1 - if items[i].name == "Backstage passes to a TAFKAL80ETC concert" { - if items[i].sellIn < 11 { - if items[i].quality < 50 { - items[i].quality = items[i].quality + 1 - } - } - if items[i].sellIn < 6 { - if items[i].quality < 50 { - items[i].quality = items[i].quality + 1 - } - } - } - } - } +type Updatable interface { + Update() +} - if items[i].name != "Sulfuras, Hand of Ragnaros" { - items[i].sellIn = items[i].sellIn - 1 - } +type UpdatableItem func(item *Item) Updatable - if items[i].sellIn < 0 { - if items[i].name != "Aged Brie" { - if items[i].name != "Backstage passes to a TAFKAL80ETC concert" { - if items[i].quality > 0 { - if items[i].name != "Sulfuras, Hand of Ragnaros" { - items[i].quality = items[i].quality - 1 - } - } - } else { - items[i].quality = items[i].quality - items[i].quality - } - } else { - if items[i].quality < 50 { - items[i].quality = items[i].quality + 1 - } +type AgedBrieItem struct { + *Item +} + +func (item *AgedBrieItem) Update() { + item.updateSellIn(-1) + if item.sellIn < 0 { + item.updateQuality(+2) + } else { + item.updateQuality(+1) + } + item.limitQualityToMax(50) +} + +type SulfurasItem struct { + *Item +} + +func (item *SulfurasItem) Update() { +} + +type BackstagePassesItem struct { + *Item +} + +func (item *BackstagePassesItem) Update() { + item.updateSellIn(-1) + sellIn := item.sellIn + switch { + case sellIn >= 10: + item.updateQuality(+1) + case sellIn < 10 && sellIn >= 5: + item.updateQuality(+2) + case sellIn < 15 && sellIn >= 0: + item.updateQuality(+3) + case sellIn < 0: + item.limitQualityToMax(0) + } + item.limitQualityToMax(50) +} + +type RegularItem struct { + *Item +} + +func (item *RegularItem) Update() { + item.updateSellIn(-1) + if item.sellIn < 0 { + item.updateQuality(-2) + } else { + item.updateQuality(-1) + } + item.limitQualityToMin(0) +} + +type ConjuredItem struct { + *Item +} + +func (item *ConjuredItem) Update() { + item.updateSellIn(-1) + if item.sellIn < 0 { + item.updateQuality(-4) + } else { + item.updateQuality(-2) + } + item.limitQualityToMin(0) +} + +func UpdatableItemFactory(createClosure map[string]UpdatableItem, item *Item) Updatable { + create, exists := createClosure[item.name] + if exists { + return create(item) + } + return &RegularItem{ + Item: item, + } +} + +func (item *Item) updateSellIn(updatedBy int) { + item.sellIn += updatedBy +} + +func (item *Item) updateQuality(updatedBy int) { + item.quality += updatedBy +} + +func (item *Item) limitQualityToMax(max int) { + if item.quality > max { + item.quality = max + } +} + +func (item *Item) limitQualityToMin(min int) { + if item.quality < min { + item.quality = min + } +} + +func GildedRose(items []Item) { + creationMap := map[string]UpdatableItem{ + "Aged Brie": func(item *Item) Updatable { + return &AgedBrieItem{ + Item: item, } - } + }, + "Sulfuras, Hand of Ragnaros": func(item *Item) Updatable { + return &SulfurasItem{ + Item: item, + } + }, + "Backstage passes to a TAFKAL80ETC concert": func(item *Item) Updatable { + return &BackstagePassesItem{ + Item: item, + } + }, + "Conjured Mana Cake": func(item *Item) Updatable { + return &ConjuredItem{ + Item: item, + } + }, } + for i := 0; i < len(items); i++ { + updatableItem := UpdatableItemFactory(creationMap, &items[i]) + updatableItem.Update() + } } + +func main() { + fmt.Println("# Before updating") + // fmt.Println(items) + GildedRose(items) +} + diff --git a/go/gilded-rose_test.go b/go/gilded-rose_test.go index 24d64bdd..31dcd7f8 100644 --- a/go/gilded-rose_test.go +++ b/go/gilded-rose_test.go @@ -1,15 +1,73 @@ package main -import "testing" +import ( + "fmt" + "io" + "os" + "testing" +) -func Test_Foo(t *testing.T) { - var items = []*Item{ - &Item{"foo", 0, 0}, - } +var tests = []struct { + startItem Item + expectedItem Item + days int +}{ + {Item{"normal", 10, 20}, Item{"normal", 10, 20}, 0}, + {Item{"normal", 10, 20}, Item{"normal", 0, 10}, 10}, + {Item{"normal", 10, 20}, Item{"normal", -1, 8}, 11}, + {Item{"normal", 10, 20}, Item{"normal", -20, 0}, 30}, + {Item{"Aged Brie", 2, 0}, Item{"Aged Brie", 2, 0}, 0}, + {Item{"Aged Brie", 2, 0}, Item{"Aged Brie", 0, 2}, 2}, + {Item{"Aged Brie", 2, 0}, Item{"Aged Brie", -23, 48}, 25}, + {Item{"Aged Brie", 2, 0}, Item{"Aged Brie", -24, 50}, 26}, + {Item{"Aged Brie", 2, 0}, Item{"Aged Brie", -25, 50}, 27}, + {Item{"Aged Brie", 2, 0}, Item{"Aged Brie", -28, 50}, 30}, + {Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, 0}, + {Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, 15}, + {Item{"Sulfuras, Hand of Ragnaros", 0, 80}, Item{"Sulfuras, Hand of Ragnaros", 0, 80}, 30}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, 0}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 14, 21}, 1}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 13, 22}, 2}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 10, 25}, 5}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 9, 27}, 6}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 8, 29}, 7}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 5, 35}, 10}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 4, 38}, 11}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 3, 41}, 12}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", 0, 50}, 15}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", -1, 0}, 16}, + {Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, Item{"Backstage passes to a TAFKAL80ETC concert", -10, 0}, 25}, + {Item{"Conjured Mana Cake", 3, 6}, Item{"Conjured Mana Cake", 3, 6}, 0}, + {Item{"Conjured Mana Cake", 3, 6}, Item{"Conjured Mana Cake", 2, 4}, 1}, + {Item{"Conjured Mana Cake", 3, 6}, Item{"Conjured Mana Cake", 1, 2}, 2}, + {Item{"Conjured Mana Cake", 3, 6}, Item{"Conjured Mana Cake", 0, 0}, 3}, + {Item{"Conjured Mana Cake", 3, 6}, Item{"Conjured Mana Cake", -1, 0}, 4}, + {Item{"Conjured Mana Cake", 3, 6}, Item{"Conjured Mana Cake", -2, 0}, 5}, + {Item{"Conjured Mana Cake", 3, 6}, Item{"Conjured Mana Cake", -7, 0}, 10}, +} - UpdateQuality(items) - - if items[0].name != "fixme" { - t.Errorf("Name: Expected %s but got %s ", "fixme", items[0].name) +func TestGildedRose(t *testing.T) { + oldStdout := os.Stdout + r, w, _ := os.Pipe() + defer func() { + os.Stdout = oldStdout + w.Close() + if t.Failed() { + fmt.Println("=== Start Captured Stdout ===") + io.Copy(os.Stdout, r) + fmt.Println("=== End Captured Stdout ===") + } + }() + os.Stdout = w + for tn, test := range tests { + items = []Item{test.startItem} + for i := 0; i < test.days; i++ { + main() + } + if items[0] != test.expectedItem { + t.Logf("Test Number[%d]: Expected starting item %+v to equal %+v after %d days: Got %v", tn, test.startItem, test.expectedItem, test.days, items[0]) + t.Fail() + } } } + diff --git a/go/texttest_fixture.go b/go/texttest_fixture.go deleted file mode 100644 index a5b47a77..00000000 --- a/go/texttest_fixture.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strconv" -) - -func main() { - fmt.Println("OMGHAI!") - - var items = []*Item{ - &Item{"+5 Dexterity Vest", 10, 20}, - &Item{"Aged Brie", 2, 0}, - &Item{"Elixir of the Mongoose", 5, 7}, - &Item{"Sulfuras, Hand of Ragnaros", 0, 80}, - &Item{"Sulfuras, Hand of Ragnaros", -1, 80}, - &Item{"Backstage passes to a TAFKAL80ETC concert", 15, 20}, - &Item{"Backstage passes to a TAFKAL80ETC concert", 10, 49}, - &Item{"Backstage passes to a TAFKAL80ETC concert", 5, 49}, - &Item{"Conjured Mana Cake", 3, 6}, // <-- :O - } - - days := 2 - var err error - if len(os.Args) > 1 { - days, err = strconv.Atoi(os.Args[1]) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - days++ - } - - for day := 0; day < days; day++ { - fmt.Printf("-------- day %d --------\n", day) - fmt.Println("name, sellIn, quality") - for i := 0; i < len(items); i++ { - fmt.Println(items[i]) - } - fmt.Println("") - UpdateQuality(items) - } -}