lemonade_stand 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/bin/play_ls +48 -0
- data/lemonade_stand.gemspec +25 -0
- data/lib/lemonade_stand.rb +7 -0
- data/lib/lemonade_stand/choice.rb +43 -0
- data/lib/lemonade_stand/day.rb +39 -0
- data/lib/lemonade_stand/display.rb +10 -0
- data/lib/lemonade_stand/event.rb +36 -0
- data/lib/lemonade_stand/events/heat_wave_event.rb +11 -0
- data/lib/lemonade_stand/events/normal_event.rb +11 -0
- data/lib/lemonade_stand/events/rain_event.rb +15 -0
- data/lib/lemonade_stand/events/storm_event.rb +11 -0
- data/lib/lemonade_stand/events/street_work_event.rb +11 -0
- data/lib/lemonade_stand/game.rb +52 -0
- data/lib/lemonade_stand/player.rb +18 -0
- data/lib/lemonade_stand/result.rb +31 -0
- data/lib/lemonade_stand/version.rb +3 -0
- data/lib/lemonade_stand/weather.rb +32 -0
- data/spec/lemonade_stand/choice_spec.rb +116 -0
- data/spec/lemonade_stand/day_spec.rb +241 -0
- data/spec/lemonade_stand/display_spec.rb +18 -0
- data/spec/lemonade_stand/event_spec.rb +306 -0
- data/spec/lemonade_stand/game_spec.rb +215 -0
- data/spec/lemonade_stand/player_spec.rb +27 -0
- data/spec/lemonade_stand/result_spec.rb +84 -0
- data/spec/lemonade_stand/weather_spec.rb +70 -0
- data/spec/spec_helper.rb +4 -0
- metadata +141 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module LemonadeStand
|
2
|
+
|
3
|
+
class Result
|
4
|
+
|
5
|
+
attr_reader :glasses_sold
|
6
|
+
attr_reader :choice
|
7
|
+
attr_reader :day
|
8
|
+
|
9
|
+
def initialize data
|
10
|
+
@glasses_sold = data[:glasses_sold]
|
11
|
+
@choice = data[:choice]
|
12
|
+
@day = data[:day]
|
13
|
+
end
|
14
|
+
|
15
|
+
def income
|
16
|
+
(@glasses_sold * @choice.price_per_glass).round 2
|
17
|
+
end
|
18
|
+
|
19
|
+
def expenses
|
20
|
+
glasses_cost = @choice.glasses_made * @day.cost_per_glass
|
21
|
+
signs_cost = 15 * @choice.signs
|
22
|
+
(glasses_cost + signs_cost).round 2
|
23
|
+
end
|
24
|
+
|
25
|
+
def profit
|
26
|
+
(income - expenses).round 2
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module LemonadeStand
|
2
|
+
|
3
|
+
class Weather
|
4
|
+
|
5
|
+
def initialize type
|
6
|
+
@type = type
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(meth, *args, &blk)
|
10
|
+
meth.to_s == "#{@type}?"
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
@type.to_s.split('_').map { |x| x == 'and' ? x : x.capitalize! }.join(' ')
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.weather_for day
|
18
|
+
type = if day.number < 3
|
19
|
+
:sunny
|
20
|
+
else
|
21
|
+
case rand(10)
|
22
|
+
when 0..5 then :sunny
|
23
|
+
when 6..7 then :cloudy
|
24
|
+
else :hot_and_dry
|
25
|
+
end
|
26
|
+
end
|
27
|
+
new type
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe LemonadeStand::Choice do
|
4
|
+
|
5
|
+
let(:choice) { LemonadeStand::Choice.new }
|
6
|
+
|
7
|
+
describe "calculate sales" do
|
8
|
+
|
9
|
+
describe "sales factor" do
|
10
|
+
|
11
|
+
[
|
12
|
+
[1, 51.6],
|
13
|
+
[2, 49.2],
|
14
|
+
[3, 46.8],
|
15
|
+
[7, 37.2],
|
16
|
+
[8, 34.8],
|
17
|
+
[9, 32.4],
|
18
|
+
[10, 30.0],
|
19
|
+
[11, 24.79],
|
20
|
+
[12, 20.83],
|
21
|
+
[16, 11.72],
|
22
|
+
[17, 10.38],
|
23
|
+
[18, 9.26],
|
24
|
+
].map { |x| Struct.new(:price, :expected).new(*x) }.each do |example|
|
25
|
+
|
26
|
+
describe "price is #{example.price}" do
|
27
|
+
|
28
|
+
before do
|
29
|
+
choice.price_per_glass = example.price
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should have a sales factor of #{example.expected}" do
|
33
|
+
choice.send(:sales_factor).round(2).must_equal example.expected
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "signs factor" do
|
44
|
+
[
|
45
|
+
[0, 0],
|
46
|
+
[1, 0.39],
|
47
|
+
[2, 0.63],
|
48
|
+
[5, 0.92],
|
49
|
+
[10, 0.99],
|
50
|
+
[100, 1.0],
|
51
|
+
].map { |x| Struct.new(:signs, :expected).new(*x) }.each do |example|
|
52
|
+
|
53
|
+
describe "purchased #{example.signs} signs" do
|
54
|
+
|
55
|
+
before do
|
56
|
+
choice.signs = example.signs
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return factor of #{example.expected}" do
|
60
|
+
choice.send(:signs_factor).round(2).must_equal example.expected
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "max sales" do
|
70
|
+
[
|
71
|
+
[1, 0, 51.60],
|
72
|
+
[1, 1, 71.90],
|
73
|
+
[1, 2, 84.22],
|
74
|
+
[1, 100, 103.20],
|
75
|
+
[9, 0, 32.40],
|
76
|
+
[9, 0, 32.40],
|
77
|
+
[9, 1, 45.15],
|
78
|
+
[9, 5, 62.14],
|
79
|
+
[9, 10, 64.58],
|
80
|
+
[9, 100, 64.80],
|
81
|
+
[16, 0, 11.72],
|
82
|
+
[16, 100, 23.44],
|
83
|
+
].map { |x| Struct.new(:price_per_glass, :signs, :expected).new(*x) }.each do |example|
|
84
|
+
|
85
|
+
describe "#{example.price_per_glass} glasses with #{example.signs} signs" do
|
86
|
+
|
87
|
+
before do
|
88
|
+
choice.price_per_glass = example.price_per_glass
|
89
|
+
choice.signs = example.signs
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return max sales of #{example.expected}" do
|
93
|
+
choice.max_sales.round(2).must_equal example.expected
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "dropping decimal points" do
|
103
|
+
[:signs, :price_per_glass, :glasses_made].each do |property|
|
104
|
+
describe property do
|
105
|
+
it "drop the decimal points" do
|
106
|
+
choice = LemonadeStand::Choice.new
|
107
|
+
choice.send("#{property}=".to_sym, 1.01)
|
108
|
+
choice.send(property).must_equal 1
|
109
|
+
choice.send("#{property}=".to_sym, 2.99)
|
110
|
+
choice.send(property).must_equal 2
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe LemonadeStand::Day do
|
4
|
+
|
5
|
+
let(:day) { LemonadeStand::Day.new }
|
6
|
+
|
7
|
+
describe "the weather" do
|
8
|
+
|
9
|
+
it "should pull the weather" do
|
10
|
+
weather = Object.new
|
11
|
+
LemonadeStand::Weather.stubs(:weather_for).with(day).returns weather
|
12
|
+
day.weather.must_be_same_as weather
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return the same projected weather report" do
|
16
|
+
weather = Object.new
|
17
|
+
LemonadeStand::Weather.expects(:weather_for).returns weather
|
18
|
+
day.weather
|
19
|
+
day.weather # this call will fail if called twice
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "sales_for" do
|
25
|
+
|
26
|
+
let(:day) { LemonadeStand::Day.new }
|
27
|
+
let(:choice) { Object.new }
|
28
|
+
|
29
|
+
let(:glasses_sold) { Object.new }
|
30
|
+
|
31
|
+
before do
|
32
|
+
day.stubs(:calculate_glasses_sold).with(choice).returns glasses_sold
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return a result" do
|
36
|
+
result = day.sales_for choice
|
37
|
+
result.is_a?(LemonadeStand::Result).must_equal true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return the calculated sales" do
|
41
|
+
result = day.sales_for choice
|
42
|
+
result.glasses_sold.must_equal glasses_sold
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should pass along the day" do
|
46
|
+
result = day.sales_for choice
|
47
|
+
result.day.must_be_same_as day
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should pass along the choice" do
|
51
|
+
result = day.sales_for choice
|
52
|
+
result.choice.must_be_same_as choice
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "calculate glasses sold" do
|
58
|
+
|
59
|
+
let(:choice) { LemonadeStand::Choice.new }
|
60
|
+
|
61
|
+
let(:event) do
|
62
|
+
e = Object.new
|
63
|
+
# default to an event that does not modify the number
|
64
|
+
def e.modify choice
|
65
|
+
choice.max_sales
|
66
|
+
end
|
67
|
+
e
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:day) do
|
71
|
+
d = LemonadeStand::Day.new
|
72
|
+
d.stubs(:event).returns event
|
73
|
+
d
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "no glasses were made" do
|
77
|
+
before { choice.glasses_made = 0 }
|
78
|
+
|
79
|
+
describe "and the max sales for the day was 1" do
|
80
|
+
before { choice.stubs(:max_sales).returns 1 }
|
81
|
+
|
82
|
+
it "should report that no glasses were sold" do
|
83
|
+
day.calculate_glasses_sold(choice).must_equal 0
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "2 glasses were made" do
|
90
|
+
before { choice.glasses_made = 2 }
|
91
|
+
|
92
|
+
describe "and max sales for the day was 3" do
|
93
|
+
before { choice.stubs(:max_sales).returns 3 }
|
94
|
+
|
95
|
+
it "should report that 2 glasses was sold" do
|
96
|
+
day.calculate_glasses_sold(choice).must_equal 2
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "and the day's event modified the glasses to 3" do
|
100
|
+
before { event.stubs(:modify).with(choice).returns 3 }
|
101
|
+
|
102
|
+
it "should report that 2 were returned" do
|
103
|
+
day.calculate_glasses_sold(choice).must_equal 2
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "and the day's event modified the glasses to 4" do
|
108
|
+
before { event.stubs(:modify).with(choice).returns 4 }
|
109
|
+
|
110
|
+
it "should report that 2 were returned" do
|
111
|
+
day.calculate_glasses_sold(choice).must_equal 2
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "and max sales for the day was 1" do
|
117
|
+
before { choice.stubs(:max_sales).returns 1 }
|
118
|
+
|
119
|
+
it "should report that 1 glass was sold" do
|
120
|
+
day.calculate_glasses_sold(choice).must_equal 1
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "4 glasses were made" do
|
127
|
+
before { choice.glasses_made = 4 }
|
128
|
+
|
129
|
+
describe "and max sales for the day was 3" do
|
130
|
+
before { choice.stubs(:max_sales).returns 3 }
|
131
|
+
|
132
|
+
it "should report that 3 glasses was sold" do
|
133
|
+
day.calculate_glasses_sold(choice).must_equal 3
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "and the day's event modified the glasses to 4" do
|
137
|
+
before { event.stubs(:modify).with(choice).returns 4 }
|
138
|
+
|
139
|
+
it "should report that 4 were returned" do
|
140
|
+
day.calculate_glasses_sold(choice).must_equal 4
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "and the day's event modified the glasses to 5" do
|
145
|
+
before { event.stubs(:modify).with(choice).returns 5 }
|
146
|
+
|
147
|
+
it "should report that 4 were returned" do
|
148
|
+
day.calculate_glasses_sold(choice).must_equal 4
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "and max sales for the day was 1" do
|
154
|
+
before { choice.stubs(:max_sales).returns 1 }
|
155
|
+
|
156
|
+
it "should report that 1 glass was sold" do
|
157
|
+
day.calculate_glasses_sold(choice).must_equal 1
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "5.001 glasses were made" do
|
164
|
+
before { choice.glasses_made = 5.001 }
|
165
|
+
|
166
|
+
describe "and max sales for the day was 3.01" do
|
167
|
+
before { choice.stubs(:max_sales).returns 3.01 }
|
168
|
+
|
169
|
+
it "should report that 3 glasses was sold" do
|
170
|
+
day.calculate_glasses_sold(choice).must_equal 3
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "and the day's event modified the glasses to 5.01" do
|
174
|
+
before { event.stubs(:modify).with(choice).returns 5.01 }
|
175
|
+
|
176
|
+
it "should report that 5 were returned" do
|
177
|
+
day.calculate_glasses_sold(choice).must_equal 5
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "and the day's event modified the glasses to 5.002" do
|
182
|
+
before { event.stubs(:modify).with(choice).returns 5.002 }
|
183
|
+
|
184
|
+
it "should report that 5 were returned" do
|
185
|
+
day.calculate_glasses_sold(choice).must_equal 5
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "and max sales for the day was 1.01" do
|
191
|
+
before { choice.stubs(:max_sales).returns 1.01 }
|
192
|
+
|
193
|
+
it "should report that 1 glass was sold" do
|
194
|
+
day.calculate_glasses_sold(choice).must_equal 1
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
describe "event" do
|
204
|
+
|
205
|
+
let(:event) { Object.new }
|
206
|
+
|
207
|
+
before { LemonadeStand::Event.stubs(:for).with(day).returns(event).then.returns(Object.new) }
|
208
|
+
|
209
|
+
it "should look up the event for the day" do
|
210
|
+
day.event.must_be_same_as event
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should return the same day on every call" do
|
214
|
+
day.event.must_be_same_as day.event
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "cost per glass" do
|
220
|
+
|
221
|
+
[
|
222
|
+
[1, 2],
|
223
|
+
[2, 2],
|
224
|
+
[3, 4],
|
225
|
+
[4, 4],
|
226
|
+
[5, 5],
|
227
|
+
[6, 5],
|
228
|
+
].map { |x| Struct.new(:day_number, :cost).new *x }.each do |example|
|
229
|
+
|
230
|
+
describe "day #{example.day_number}" do
|
231
|
+
before { day.stubs(:number).returns example.day_number }
|
232
|
+
it "should equal #{example.cost}" do
|
233
|
+
day.cost_per_glass.must_equal example.cost
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe "display" do
|
4
|
+
[
|
5
|
+
[0, '$0.00'],
|
6
|
+
[1, '$0.01'],
|
7
|
+
[10, '$0.10'],
|
8
|
+
[100, '$1.00'],
|
9
|
+
[123, '$1.23'],
|
10
|
+
].map { |a| Struct.new(:input, :expected).new *a }.each do |example|
|
11
|
+
describe "money" do
|
12
|
+
it "should convert #{example.input} to #{example.expected}" do
|
13
|
+
LemonadeStand::Display
|
14
|
+
.money(example.input).must_equal example.expected
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe LemonadeStand::Event do
|
4
|
+
|
5
|
+
describe "for" do
|
6
|
+
|
7
|
+
let(:day) { Struct.new(:weather).new weather }
|
8
|
+
let(:weather) { Object.new }
|
9
|
+
|
10
|
+
before do
|
11
|
+
weather.stubs(:cloudy?).returns false
|
12
|
+
weather.stubs(:hot_and_dry?).returns false
|
13
|
+
weather.stubs(:sunny?).returns false
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "and the weather is cloudy" do
|
17
|
+
|
18
|
+
before { weather.stubs(:cloudy?).returns true }
|
19
|
+
|
20
|
+
it "should return a cloudy event" do
|
21
|
+
cloudy_event = Object.new
|
22
|
+
LemonadeStand::Event.stubs(:cloudy_event_for).with(day).returns cloudy_event
|
23
|
+
result = LemonadeStand::Event.for(day)
|
24
|
+
result.must_be_same_as cloudy_event
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "and the weather is hot and dry" do
|
30
|
+
|
31
|
+
before { weather.stubs(:hot_and_dry?).returns true }
|
32
|
+
|
33
|
+
it "should return a hot and dry event" do
|
34
|
+
event = Object.new
|
35
|
+
LemonadeStand::Event.stubs(:hot_and_dry_event_for).with(day).returns event
|
36
|
+
result = LemonadeStand::Event.for(day)
|
37
|
+
result.must_be_same_as event
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "a sunny day" do
|
43
|
+
|
44
|
+
before { weather.stubs(:sunny?).returns true }
|
45
|
+
|
46
|
+
it "should return a sunny event" do
|
47
|
+
event = Object.new
|
48
|
+
LemonadeStand::Event.stubs(:sunny_event_for).with(day).returns event
|
49
|
+
result = LemonadeStand::Event.for(day)
|
50
|
+
result.must_be_same_as event
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "a sunny event" do
|
58
|
+
|
59
|
+
let(:day) { Struct.new(:number).new 0 }
|
60
|
+
|
61
|
+
(0...25).to_a.each do |random_value|
|
62
|
+
describe "random 0-99 is #{random_value}" do
|
63
|
+
|
64
|
+
before { LemonadeStand::Event.stubs(:rand).with(100).returns random_value }
|
65
|
+
|
66
|
+
[1, 2].each do |day_number|
|
67
|
+
describe "and the day number is #{day_number}" do
|
68
|
+
|
69
|
+
before { day.stubs(:number).returns day_number }
|
70
|
+
|
71
|
+
it "should return a normal work event" do
|
72
|
+
event = Object.new
|
73
|
+
LemonadeStand::Event.stubs(:build).with(:normal).returns event
|
74
|
+
result = LemonadeStand::Event.sunny_event_for day
|
75
|
+
result.must_be_same_as event
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
(3..10).to_a.each do |day_number|
|
82
|
+
describe "and the day number is #{day_number}" do
|
83
|
+
|
84
|
+
before { day.stubs(:number).returns day_number }
|
85
|
+
|
86
|
+
it "should return a normal event" do
|
87
|
+
event = Object.new
|
88
|
+
LemonadeStand::Event.stubs(:build).with(:street_work).returns event
|
89
|
+
result = LemonadeStand::Event.sunny_event_for day
|
90
|
+
result.must_be_same_as event
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
(25..100).to_a.each do |random_value|
|
100
|
+
describe "random 0-99 is #{random_value}" do
|
101
|
+
before { LemonadeStand::Event.stubs(:rand).with(100).returns random_value }
|
102
|
+
|
103
|
+
describe "and day is 3" do
|
104
|
+
before { day.number = 3 }
|
105
|
+
|
106
|
+
it "should return a normal day" do
|
107
|
+
event = Object.new
|
108
|
+
LemonadeStand::Event.stubs(:build).with(:normal).returns event
|
109
|
+
result = LemonadeStand::Event.sunny_event_for day
|
110
|
+
result.must_be_same_as event
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "a cloudy event" do
|
120
|
+
|
121
|
+
let(:day) { Object.new }
|
122
|
+
|
123
|
+
(0...25).to_a.each do |random_value|
|
124
|
+
describe "random 0-99 is #{random_value}" do
|
125
|
+
|
126
|
+
before { LemonadeStand::Event.stubs(:rand).with(100).returns random_value }
|
127
|
+
|
128
|
+
it "should return a normal work event" do
|
129
|
+
event = Object.new
|
130
|
+
LemonadeStand::Event.stubs(:build).with(:storm).returns event
|
131
|
+
result = LemonadeStand::Event.cloudy_event_for day
|
132
|
+
result.must_be_same_as event
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
(25..100).to_a.each do |random_value|
|
139
|
+
describe "random 0-99 is #{random_value}" do
|
140
|
+
|
141
|
+
before { LemonadeStand::Event.stubs(:rand).with(100).returns random_value }
|
142
|
+
|
143
|
+
it "should return a normal day" do
|
144
|
+
event = Object.new
|
145
|
+
LemonadeStand::Event.stubs(:build).with(:rain).returns event
|
146
|
+
result = LemonadeStand::Event.cloudy_event_for day
|
147
|
+
result.must_be_same_as event
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "a hot and dry event" do
|
156
|
+
it "should return a heat wave" do
|
157
|
+
event = Object.new
|
158
|
+
LemonadeStand::Event.stubs(:build).with(:heat_wave).returns event
|
159
|
+
result = LemonadeStand::Event.hot_and_dry_event_for nil
|
160
|
+
result.must_be_same_as event
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "build" do
|
165
|
+
[
|
166
|
+
[:rain, LemonadeStand::RainEvent],
|
167
|
+
[:storm, LemonadeStand::StormEvent],
|
168
|
+
[:heat_wave, LemonadeStand::HeatWaveEvent],
|
169
|
+
[:street_work, LemonadeStand::StreetWorkEvent],
|
170
|
+
[:normal, LemonadeStand::NormalEvent],
|
171
|
+
].map { |x| Struct.new(:type, :klass).new *x }.each do |example|
|
172
|
+
describe "building #{example.type}" do
|
173
|
+
it "should create an #{example.klass}" do
|
174
|
+
LemonadeStand::Event.build(example.type)
|
175
|
+
.is_a?(example.klass).must_equal true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
[
|
182
|
+
LemonadeStand::RainEvent,
|
183
|
+
LemonadeStand::StormEvent,
|
184
|
+
LemonadeStand::HeatWaveEvent,
|
185
|
+
LemonadeStand::StreetWorkEvent,
|
186
|
+
LemonadeStand::NormalEvent,
|
187
|
+
].each do |type|
|
188
|
+
describe type do
|
189
|
+
it "should be an event" do
|
190
|
+
type.new
|
191
|
+
.is_a?(LemonadeStand::Event)
|
192
|
+
.must_equal true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
describe LemonadeStand::NormalEvent do
|
200
|
+
|
201
|
+
describe "modify" do
|
202
|
+
|
203
|
+
let(:choice) { Struct.new(:max_sales).new Object.new }
|
204
|
+
|
205
|
+
it "should return the default max sales" do
|
206
|
+
event = LemonadeStand::NormalEvent.new
|
207
|
+
result = event.modify choice
|
208
|
+
result.must_be_same_as choice.max_sales
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
describe LemonadeStand::HeatWaveEvent do
|
217
|
+
[
|
218
|
+
[1, 2],
|
219
|
+
[2, 4],
|
220
|
+
[3, 6],
|
221
|
+
].map { |x| Struct.new(:max_sales, :expected).new *x }.each do |example|
|
222
|
+
describe "multiple examples" do
|
223
|
+
it "should double the maximum sales" do
|
224
|
+
choice = Struct.new(:max_sales).new example.max_sales
|
225
|
+
result = LemonadeStand::HeatWaveEvent.new.modify choice
|
226
|
+
result.must_equal example.expected
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe LemonadeStand::HeatWaveEvent do
|
233
|
+
it "should return 0" do
|
234
|
+
result = LemonadeStand::StormEvent.new.modify nil
|
235
|
+
result.must_equal 0
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
describe LemonadeStand::StreetWorkEvent do
|
240
|
+
|
241
|
+
let(:choice) { Struct.new(:glasses_made).new Object.new }
|
242
|
+
let(:event) { LemonadeStand::StreetWorkEvent.new }
|
243
|
+
|
244
|
+
(0...2).to_a.each do |random_value|
|
245
|
+
describe "random 0-4 is #{random_value}" do
|
246
|
+
before { event.stubs(:rand).with(4).returns random_value }
|
247
|
+
it "should return 0" do
|
248
|
+
result = event.modify choice
|
249
|
+
result.must_equal 0
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "random 0-4 is 3" do
|
255
|
+
before { event.stubs(:rand).with(4).returns 3 }
|
256
|
+
it "should return the glasses sold" do
|
257
|
+
result = event.modify choice
|
258
|
+
result.must_be_same_as choice.glasses_made
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe LemonadeStand::RainEvent do
|
264
|
+
|
265
|
+
let(:choice) { Struct.new(:glasses_made).new Object.new }
|
266
|
+
let(:event) { LemonadeStand::RainEvent.new }
|
267
|
+
|
268
|
+
[
|
269
|
+
[0.0001, 0.30, 10, 7],
|
270
|
+
[0.9999, 0.80, 10, 2],
|
271
|
+
[0.0329, 0.32, 100, 68],
|
272
|
+
[0.5, 0.55, 100, 45],
|
273
|
+
].map { |x| Struct.new(:random, :chance_of_rain, :previous_max_sales, :new_max_sales).new *x }.each do |example|
|
274
|
+
|
275
|
+
describe "chance of rain" do
|
276
|
+
|
277
|
+
before { event.stubs(:rand).returns example.random }
|
278
|
+
|
279
|
+
it "should calculate the chance of rain (#{example.chance_of_rain})" do
|
280
|
+
event.chance_of_rain.must_equal example.chance_of_rain
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "calculating sales for the day" do
|
286
|
+
|
287
|
+
before do
|
288
|
+
event.stubs(:rand).returns example.random
|
289
|
+
choice.stubs(:max_sales).returns example.previous_max_sales
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should alter the max sales according to the chance of rain" do
|
293
|
+
result = event.modify choice
|
294
|
+
result.must_equal example.new_max_sales
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should return an integer" do
|
298
|
+
result = event.modify choice
|
299
|
+
result.class.must_equal Fixnum
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|