Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
TDDBC Nagano 0.1
# -*- coding: utf-8 -*-
class VendingMachine
attr_reader :total_money
class Drink
@hash = {}
attr_reader :id, :price
def initialize(id, price)
@id, @price = id, price
end
def self.add(drink)
@hash[drink.id] = drink
end
def self.by_id(id)
@hash[id]
end
def self.list
@hash.values
end
end
COLA = Drink.new('cola', 120)
Drink.add(COLA)
def initialize
@total_money = 0
@total_sales = 0
@stock = {
'cola' => 5
}
@cache_stock = {
10 => 10,
50 => 10,
100 => 10,
500 => 10,
1000 => 5,
}
end
def input(money)
unless [10, 50, 100, 500, 1000].include? money
raise ArgumentError, "invalid money type: #{money}"
end
@cache_stock[money] += 1
@total_money += money
end
def stock(id)
@stock[id]
end
def cache_stock(money_type)
@cache_stock[money_type]
end
def buyable
Drink.list.each do |drink|
if @total_money >= drink.price && @stock[drink.id] > 0
return [drink.id]
end
end
[]
end
def buy(id)
drink = Drink.by_id(id)
if @total_money < drink.price
raise '投入金額が不足しています'
end
if stock(id) <= 0
raise '商品の在庫がありません'
end
balance = @total_money - drink.price
[1000, 500, 100, 50, 10].each do |type|
num = balance / type
@cache_stock[type] -= num
balance -= type * num
end
@stock[id] -= 1
@total_sales += drink.price
@total_money = 0
end
def sales
@total_sales
end
end
# -*- coding: utf-8 -*-
require 'vending_machine'
describe VendingMachine do
let(:vm){VendingMachine.new}
[10, 50, 100, 500, 1000].each do |m|
context "#{m}円玉を投入" do
it "合計金額が#{m}になる" do
vm.input(m)
vm.total_money.should == m
end
end
end
context '1円玉を投入' do
it 'エラーになる' do
expect{vm.input(1)}.to raise_error(ArgumentError, "invalid money type: 1")
end
end
context 'お金を複数回投入' do
it '#total_money が投入した全金額の合計になる' do
vm.input(100)
vm.input(500)
vm.input(10)
vm.total_money.should == 610
end
end
it '在庫としてコーラ5個がある' do
vm.stock('cola').should == 5
end
context '投入金額が120円未満' do
it '#buyable 空配列が返る' do
vm.input(100)
vm.input(10)
vm.buyable.should == []
end
context '飲み物を購入する' do
it 'エラーになる' do
expect{vm.buy('cola')}.to raise_error(RuntimeError, '投入金額が不足しています')
end
end
end
context '投入金額が120円以上' do
before do
vm.input(100)
vm.input(10)
vm.input(10)
end
it '#buyable 購入可能な飲み物一覧が返る' do
vm.buyable.should == ['cola']
end
context '飲み物を購入する' do
before do
vm.buy('cola')
end
it '購入した飲み物の在庫が減る' do
vm.stock('cola').should == 4
end
it '売り上げ金額が加算される' do
vm.sales.should == 120
end
end
end
context 'コーラが2個売れると' do
before do
vm.input(500)
vm.buy('cola')
vm.input(500)
vm.buy('cola')
end
it '売り上げ金額が240円になる' do
vm.sales.should == 240
end
it 'コーラの在庫が3個になる' do
vm.stock('cola').should == 3
end
end
context 'コーラが売り切れ状態で120円投入' do
before do
5.times do
vm.input(100)
vm.input(10)
vm.input(10)
vm.buy('cola')
end
vm.input(100)
vm.input(10)
vm.input(10)
end
it '#buyable が空配列' do
vm.buyable.should == []
end
it '#buy がエラー' do
expect{vm.buy('cola')}.to raise_error(RuntimeError, '商品の在庫がありません')
end
end
it '現金として 1000円が5枚, 硬貨が各10枚ある' do
[10, 50, 100, 500].each do |m|
vm.cache_stock(m).should == 10
end
vm.cache_stock(1000).should == 5
end
context '100円玉2枚でコーラを買う' do
before do
vm.input(100)
vm.input(100)
vm.buy('cola')
end
it '現金として100円玉が12枚、50円玉が9枚, 10円玉が7枚になる' do
vm.cache_stock(100).should == 12
vm.cache_stock(50).should == 9
vm.cache_stock(10).should == 7
end
it '投入金額が 0 になる' do
vm.total_money.should == 0
end
end
context '10円玉が1枚しかない状態' do
before do
3.times do
vm.input(100)
vm.input(100)
vm.buy('cola')
end
end
it 'コーラを購入' do
vm.input(100)
vm.input(100)
expect{vm.buy('cola')}.to raise_error(RuntimeError, 'お釣りが不足しています')
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment