icu_tournament 0.8.9
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.
- data/.gitignore +4 -0
- data/LICENCE +22 -0
- data/README.rdoc +75 -0
- data/Rakefile +57 -0
- data/VERSION.yml +5 -0
- data/lib/icu_tournament.rb +8 -0
- data/lib/icu_tournament/federation.rb +303 -0
- data/lib/icu_tournament/name.rb +274 -0
- data/lib/icu_tournament/player.rb +204 -0
- data/lib/icu_tournament/result.rb +191 -0
- data/lib/icu_tournament/team.rb +90 -0
- data/lib/icu_tournament/tournament.rb +508 -0
- data/lib/icu_tournament/tournament_fcsv.rb +310 -0
- data/lib/icu_tournament/tournament_krause.rb +329 -0
- data/lib/icu_tournament/util.rb +156 -0
- data/spec/federation_spec.rb +176 -0
- data/spec/name_spec.rb +208 -0
- data/spec/player_spec.rb +313 -0
- data/spec/result_spec.rb +203 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/team_spec.rb +60 -0
- data/spec/tournament_fcsv_spec.rb +548 -0
- data/spec/tournament_krause_spec.rb +379 -0
- data/spec/tournament_spec.rb +733 -0
- data/spec/util_spec.rb +357 -0
- metadata +97 -0
@@ -0,0 +1,379 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
class Tournament
|
5
|
+
describe Krause do
|
6
|
+
def check_player(num, first, last, other={})
|
7
|
+
p = @t.player(num)
|
8
|
+
p.first_name.should == first
|
9
|
+
p.last_name.should == last
|
10
|
+
p.gender.should == other[:gender]
|
11
|
+
p.title.should == other[:title]
|
12
|
+
p.rating.should == other[:rating]
|
13
|
+
p.fed.should == other[:fed]
|
14
|
+
p.id.should == other[:id]
|
15
|
+
p.dob.should == other[:dob]
|
16
|
+
p.rank.should == other[:rank]
|
17
|
+
end
|
18
|
+
|
19
|
+
def check_results(num, results, points)
|
20
|
+
p = @t.player(num)
|
21
|
+
p.results.size.should == results
|
22
|
+
p.points.should == points
|
23
|
+
end
|
24
|
+
|
25
|
+
context "a typical tournament" do
|
26
|
+
before(:all) do
|
27
|
+
krause = <<KRAUSE
|
28
|
+
012 Las Vegas National Open
|
29
|
+
022 Las Vegas
|
30
|
+
032 USA
|
31
|
+
042 2008.06.07
|
32
|
+
052 2008.06.09
|
33
|
+
062 3
|
34
|
+
072 3
|
35
|
+
082 1
|
36
|
+
092 All-Play-All
|
37
|
+
102 Hans Scmidt
|
38
|
+
112 Gerry Graham, Herbert Scarry
|
39
|
+
122 60 in 2hr, 30 in 1hr, rest in 1hr
|
40
|
+
013 Coaching Team 1 2 3
|
41
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2
|
42
|
+
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
43
|
+
132 08.06.07 08.06.08 08.06.09
|
44
|
+
001 1 w Ui Laighleis,Gearoidin 1985 IRL 2501171 1964.06.10 1.0 2 2 b 0 3 w 1
|
45
|
+
001 2 m m Orr,Mark 2258 IRL 2500035 1955.11.09 2.0 1 1 w 1 3 b 1
|
46
|
+
001 3 m g Bologan,Viktor 2663 MDA 13900048 1971.01.01 0.0 3 1 b 0 2 w 0
|
47
|
+
KRAUSE
|
48
|
+
@p = ICU::Tournament::Krause.new
|
49
|
+
@t = @p.parse!(krause)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have a name, city and federation" do
|
53
|
+
@t.name.should == 'Las Vegas National Open'
|
54
|
+
@t.city.should == 'Las Vegas'
|
55
|
+
@t.fed.should == 'USA'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should have start and end dates" do
|
59
|
+
@t.start.should == '2008-06-07'
|
60
|
+
@t.finish.should == '2008-06-09'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should have a number of rounds, a type and a time control" do
|
64
|
+
@t.rounds.should == 3
|
65
|
+
@t.last_round.should == 3
|
66
|
+
@t.type.should == 'All-Play-All'
|
67
|
+
@t.time_control.should == '60 in 2hr, 30 in 1hr, rest in 1hr'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have an arbiter and deputies" do
|
71
|
+
@t.arbiter.should == 'Hans Scmidt'
|
72
|
+
@t.deputy.should == 'Gerry Graham, Herbert Scarry'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should have players and their details" do
|
76
|
+
@t.should have(3).players
|
77
|
+
check_player(1, 'Gearoidin', 'Ui Laighleis', :gender => 'F', :rating => 1985, :fed => 'IRL', :id => 2501171, :dob => '1964-06-10', :rank => 2)
|
78
|
+
check_player(2, 'Mark', 'Orr', :gender => 'M', :rating => 2258, :fed => 'IRL', :id => 2500035, :dob => '1955-11-09', :rank => 1, :title => 'IM')
|
79
|
+
check_player(3, 'Viktor', 'Bologan', :gender => 'M', :rating => 2663, :fed => 'MDA', :id => 13900048, :dob => '1971-01-01', :rank => 3, :title => 'GM')
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should have correct results for each player" do
|
83
|
+
check_results(1, 2, 1.0)
|
84
|
+
check_results(2, 2, 2.0)
|
85
|
+
check_results(3, 2, 0.0)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should have correct round dates" do
|
89
|
+
@t.round_dates.join('|').should == '2008-06-07|2008-06-08|2008-06-09'
|
90
|
+
end
|
91
|
+
|
92
|
+
it "the parser should retain comment lines" do
|
93
|
+
comments = <<COMMENTS
|
94
|
+
062 3
|
95
|
+
072 3
|
96
|
+
082 1
|
97
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2
|
98
|
+
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
99
|
+
COMMENTS
|
100
|
+
@p.comments.should == comments
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "the documentation example" do
|
105
|
+
before(:all) do
|
106
|
+
krause = <<KRAUSE
|
107
|
+
012 Fantasy Tournament
|
108
|
+
032 IRL
|
109
|
+
042 2009.09.09
|
110
|
+
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
111
|
+
132 09.09.09 09.09.10 09.09.11
|
112
|
+
001 1 w Mouse,Minerva 1900 USA 1234567 1928.05.15 1.0 2 2 b 0 3 w 1
|
113
|
+
001 2 m m Duck,Daffy 2200 IRL 7654321 1937.04.17 2.0 1 1 w 1 3 b 1
|
114
|
+
001 3 m g Mouse,Mickey 2600 USA 1726354 1928.05.15 0.0 3 1 b 0 2 w 0
|
115
|
+
KRAUSE
|
116
|
+
@p = ICU::Tournament::Krause.new
|
117
|
+
@t = @p.parse!(krause)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should have a name and federation" do
|
121
|
+
@t.name.should == 'Fantasy Tournament'
|
122
|
+
@t.fed.should == 'IRL'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should have a various dates" do
|
126
|
+
@t.start.should == '2009-09-09'
|
127
|
+
@t.finish.should == '2009-09-11'
|
128
|
+
@t.round_dates.join('|').should == '2009-09-09|2009-09-10|2009-09-11'
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should have a number of rounds" do
|
132
|
+
@t.rounds.should == 3
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should have players and their details" do
|
136
|
+
@t.should have(3).players
|
137
|
+
check_player(1, 'Minerva', 'Mouse', :gender => 'F', :rating => 1900, :fed => 'USA', :id => 1234567, :dob => '1928-05-15', :rank => 2)
|
138
|
+
check_player(2, 'Daffy', 'Duck', :gender => 'M', :rating => 2200, :fed => 'IRL', :id => 7654321, :dob => '1937-04-17', :rank => 1, :title => 'IM')
|
139
|
+
check_player(3, 'Mickey', 'Mouse', :gender => 'M', :rating => 2600, :fed => 'USA', :id => 1726354, :dob => '1928-05-15', :rank => 3, :title => 'GM')
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should have correct results for each player" do
|
143
|
+
check_results(1, 2, 1.0)
|
144
|
+
check_results(2, 2, 2.0)
|
145
|
+
check_results(3, 2, 0.0)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "the parser should retain comment lines" do
|
149
|
+
@p.comments.should == "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "the README serialisation example" do
|
154
|
+
before(:all) do
|
155
|
+
@t = ICU::Tournament.new('World Championship', '1972-07-11')
|
156
|
+
@t.add_player(ICU::Player.new('Robert J.', 'Fischer', 1))
|
157
|
+
@t.add_player(ICU::Player.new('Boris V.', 'Spassky', 2))
|
158
|
+
@t.add_result(ICU::Result.new(1, 1, 'L', :opponent => 2, :colour => 'B'))
|
159
|
+
@t.add_result(ICU::Result.new(2, 1, 'L', :opponent => 2, :colour => 'W', :rateable => false))
|
160
|
+
@t.add_result(ICU::Result.new(3, 1, 'W', :opponent => 2, :colour => 'B'))
|
161
|
+
@t.add_result(ICU::Result.new(4, 1, 'W', :opponent => 2, :colour => 'B'))
|
162
|
+
serializer = ICU::Tournament::Krause.new
|
163
|
+
@k = serializer.serialize(@t)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should produce a valid tournament" do
|
167
|
+
@t.invalid.should be_false
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should produce output that looks reasonable" do
|
171
|
+
@k.should match(/Fischer,Robert J\./)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "serialisation" do
|
176
|
+
before(:all) do
|
177
|
+
@krause = <<KRAUSE
|
178
|
+
012 Las Vegas National Open
|
179
|
+
022 Las Vegas
|
180
|
+
032 USA
|
181
|
+
042 2008-06-07
|
182
|
+
052 2008-06-10
|
183
|
+
092 All-Play-All
|
184
|
+
102 Hans Scmidt
|
185
|
+
112 Gerry Graham, Herbert Scarry
|
186
|
+
122 60 in 2hr, 30 in 1hr, rest in 1hr
|
187
|
+
013 Boys 2 3
|
188
|
+
013 Girls 1 4
|
189
|
+
132 08-06-07 08-06-08 08-06-09
|
190
|
+
001 1 w Ui Laighleis,Gearoidin 1985 IRL 2501171 1964-06-10 2.0 2 2 b 0 3 w + 4 b 1
|
191
|
+
001 2 m m Orr,Mark 2258 IRL 2500035 1955-11-09 2.5 1 1 w 1 0000 - = 3 b 1
|
192
|
+
001 3 m g Bologan,Viktor 2663 MDA 13900048 1971-01-01 0.0 4 1 b - 2 w 0
|
193
|
+
001 4 wg Cramling,Pia 2500 SWE 1700030 1963-04-23 0.5 3 0000 - = 1 w 0
|
194
|
+
KRAUSE
|
195
|
+
@p = ICU::Tournament::Krause.new
|
196
|
+
@t = @p.parse!(@krause)
|
197
|
+
@q = ICU::Tournament::Krause.new
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should serialize back to the original if the input is fully canonicalised" do
|
201
|
+
@q.serialize(@t).should == @krause
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should serialize using the convenience method of the tournament object" do
|
205
|
+
@t.serialize('Krause').should == @krause
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should return nil on invalid input" do
|
209
|
+
@q.serialize('Rubbish').should be_nil
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context "auto-ranking" do
|
214
|
+
before(:all) do
|
215
|
+
@krause = <<KRAUSE
|
216
|
+
012 Las Vegas National Open
|
217
|
+
042 2008-06-07
|
218
|
+
001 1 w Ui Laighleis,Gearoidin 1985 IRL 2501171 1964-06-10 1.0 2 b 0 3 w 1
|
219
|
+
001 2 m m Orr,Mark 2258 IRL 2500035 1955-11-09 2.0 1 w 1 3 b 1
|
220
|
+
001 3 m g Bologan,Viktor 2663 MDA 13900048 1971-01-01 0.0 1 b 0 2 w 0
|
221
|
+
KRAUSE
|
222
|
+
@p = ICU::Tournament::Krause.new
|
223
|
+
@t = @p.parse!(@krause)
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should have rankings automatically set" do
|
227
|
+
@t.player(1).rank.should == 2
|
228
|
+
@t.player(2).rank.should == 1
|
229
|
+
@t.player(3).rank.should == 3
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
context "renumbering" do
|
234
|
+
before(:all) do
|
235
|
+
@krause = <<KRAUSE
|
236
|
+
012 Las Vegas National Open
|
237
|
+
042 2008-06-07
|
238
|
+
001 10 w Ui Laighleis,Gearoidin 1985 IRL 1.0 20 b 0 30 w 1
|
239
|
+
001 20 m m Orr,Mark 2258 IRL 2.0 10 w 1 30 b 1
|
240
|
+
001 30 m g Bologan,Viktor 2663 MDA 0.0 10 b 0 20 w 0
|
241
|
+
KRAUSE
|
242
|
+
@p = ICU::Tournament::Krause.new
|
243
|
+
@t = @p.parse!(@krause)
|
244
|
+
@reordered = <<REORDERED
|
245
|
+
012 Las Vegas National Open
|
246
|
+
042 2008-06-07
|
247
|
+
001 1 m m Orr,Mark 2258 IRL 2.0 1 2 w 1 3 b 1
|
248
|
+
001 2 w Ui Laighleis,Gearoidin 1985 IRL 1.0 2 1 b 0 3 w 1
|
249
|
+
001 3 m g Bologan,Viktor 2663 MDA 0.0 3 2 b 0 1 w 0
|
250
|
+
REORDERED
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should serialise correctly after renumbering by rank" do
|
254
|
+
@t.renumber
|
255
|
+
@p.serialize(@t).should == @reordered
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
context "serialisation of a manually build tournament" do
|
260
|
+
before(:all) do
|
261
|
+
@krause = <<KRAUSE
|
262
|
+
012 Las Vegas National Open
|
263
|
+
042 2008-06-07
|
264
|
+
001 1 w Ui Laighleis,Gearoidin 1985 IRL 2501171 1964-06-10 1.0 2 b 0 3 w 1
|
265
|
+
001 2 m Orr,Mark 2258 IRL 2500035 1955-11-09 2.0 1 w 1 3 b 1
|
266
|
+
001 3 g Bologan,Viktor 2663 MDA 13900048 1971-01-01 0.0 1 b 0 2 w 0
|
267
|
+
KRAUSE
|
268
|
+
@p = ICU::Tournament::Krause.new
|
269
|
+
@t = ICU::Tournament.new('Las Vegas National Open', '2008-06-07')
|
270
|
+
@t.add_player(ICU::Player.new('Gearoidin', 'Ui Laighleis', 1, :rating => 1985, :id => 2501171, :dob => '1964-06-10', :fed => 'IRL', :gender => 'f'))
|
271
|
+
@t.add_player(ICU::Player.new('Mark', 'Orr', 2, :rating => 2258, :id => 2500035, :dob => '1955-11-09', :fed => 'IRL', :title => 'm'))
|
272
|
+
@t.add_player(ICU::Player.new('Viktor', 'Bologan', 3, :rating => 2663, :id => 13900048, :dob => '1971-01-01', :fed => 'MDA', :title => 'g'))
|
273
|
+
@t.add_result(ICU::Result.new(1, 1, 'L', :opponent => 2, :colour => 'B'))
|
274
|
+
@t.add_result(ICU::Result.new(2, 1, 'W', :opponent => 3, :colour => 'W'))
|
275
|
+
@t.add_result(ICU::Result.new(3, 2, 'W', :opponent => 3, :colour => 'B'))
|
276
|
+
@output = @p.serialize(@t)
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should serialise manually build tournaments" do
|
280
|
+
@output.should == @krause
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context "errors" do
|
285
|
+
before(:each) do
|
286
|
+
@k = <<KRAUSE
|
287
|
+
012 Gonzaga Classic
|
288
|
+
022 Dublin
|
289
|
+
032 IRL
|
290
|
+
042 2008-02-01
|
291
|
+
052 2008-02-03
|
292
|
+
062 12
|
293
|
+
092 Swiss
|
294
|
+
102 Michael Germaine, mlgermaine@eircom.net
|
295
|
+
122 120 minutes per player per game
|
296
|
+
001 1 Griffiths,Ryan Rhys IRL 2502054 4.0 1 0000 - = 3 b 1 8 w 1 5 b = 7 w 1
|
297
|
+
001 2 Hotak,Marian SVK 14909677 3.5 2 3 w 0 6 b = 11 w 1 8 b 1 5 w 1
|
298
|
+
001 3 Duffy,Seamus IRL 3.0 3 2 b 1 1 w 0 4 w 1 6 b = 8 w =
|
299
|
+
001 4 Cafolla,Peter IRL 2500884 3.0 4 7 b 1 5 w = 3 b 0 11 b + 6 w =
|
300
|
+
001 5 Ferry,Edward SCO 2461587 3.0 5 10 b 1 4 b = 9 w 1 1 w = 2 b 0
|
301
|
+
001 6 Boyle,Bernard IRL 2501830 3.0 6 12 b = 2 w = 10 b 1 3 w = 4 b =
|
302
|
+
001 7 McCarthy,Tim IRL 2500710 2.5 7 4 w 0 10 w = 12 b + 9 b 1 1 b 0
|
303
|
+
001 8 Benson,Oisin P. IRL 2501821 2.0 8 0000 - = 11 w 1 1 b 0 2 w 0 3 b =
|
304
|
+
001 9 Murray,David B. IRL 2501511 2.0 9 11 b = 12 w + 5 b 0 7 w 0 10 w =
|
305
|
+
001 10 Moser,Philippe SUI 1308041 1.5 10 5 w 0 7 b = 6 w 0 0000 - = 9 b =
|
306
|
+
001 11 Barbosa,Paulo POR 1904612 1.5 11 9 w = 8 b 0 2 b 0 4 w - 0000 - +
|
307
|
+
001 12 McCabe,Darren IRL 2500760 0.5 12 6 w = 9 b - 7 w -
|
308
|
+
KRAUSE
|
309
|
+
@p = ICU::Tournament::Krause.new
|
310
|
+
end
|
311
|
+
|
312
|
+
it "the unaltered example is valid Krause" do
|
313
|
+
t = @p.parse(@k).should be_instance_of(ICU::Tournament)
|
314
|
+
end
|
315
|
+
|
316
|
+
it "removing the line on which the tournament name is specified should cause an error" do
|
317
|
+
@k.sub!('012 Gonzaga Classic', '')
|
318
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/name missing/)
|
319
|
+
end
|
320
|
+
|
321
|
+
it "blanking the tournament name should cause an error" do
|
322
|
+
@k.sub!('Gonzaga Classic', '')
|
323
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/name missing/)
|
324
|
+
end
|
325
|
+
|
326
|
+
it "blanking the start date should cause an error" do
|
327
|
+
@k.sub!('2008-02-01', '2008-02-04')
|
328
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/start.*after.*end/)
|
329
|
+
end
|
330
|
+
|
331
|
+
it "the start cannot be later than the end date" do
|
332
|
+
@k.sub!('2008-02-01', '')
|
333
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/start date missing/)
|
334
|
+
end
|
335
|
+
|
336
|
+
it "creating a duplicate player number should cause an error" do
|
337
|
+
@k.sub!(' 2 ', ' 1 ')
|
338
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/player number/)
|
339
|
+
end
|
340
|
+
|
341
|
+
it "creating a duplicate rank number should not cause an error becuse the tournament will be reranked" do
|
342
|
+
@k.sub!('4.0 1', '4.0 2')
|
343
|
+
t = @p.parse!(@k)
|
344
|
+
t.player(1).rank.should == 1
|
345
|
+
end
|
346
|
+
|
347
|
+
it "referring to a non-existant player number should cause an error" do
|
348
|
+
@k.sub!(' 3 b 1', '33 b 1')
|
349
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/opponent number/)
|
350
|
+
end
|
351
|
+
|
352
|
+
it "inconsistent colours should cause an error" do
|
353
|
+
@k.sub!('3 b 1', '3 w 1')
|
354
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/result/)
|
355
|
+
end
|
356
|
+
|
357
|
+
it "inconsistent scores should cause an error" do
|
358
|
+
@k.sub!('3 b 1', '3 b =')
|
359
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/result/)
|
360
|
+
end
|
361
|
+
|
362
|
+
it "inconsistent totals should cause an error" do
|
363
|
+
@k.sub!('4.0', '4.5')
|
364
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/total/)
|
365
|
+
end
|
366
|
+
|
367
|
+
it "invalid federations should cause an error" do
|
368
|
+
@k.sub!('SCO', 'XYZ')
|
369
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/federation/)
|
370
|
+
end
|
371
|
+
|
372
|
+
it "removing any player that somebody else has played should cause an error" do
|
373
|
+
@k.sub!(/^001 12.*$/, '')
|
374
|
+
lambda { t = @p.parse!(@k) }.should raise_error(/opponent/)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
@@ -0,0 +1,733 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
describe Tournament do
|
5
|
+
context "a basic tournament" do
|
6
|
+
it "has a name, start date, some players and some results" do
|
7
|
+
lambda do
|
8
|
+
t = Tournament.new('Bangor Bash', '2009-11-09')
|
9
|
+
t.add_player(Player.new('Bobby', 'Fischer', 1))
|
10
|
+
t.add_player(Player.new('Garry', 'Kasparov', 2))
|
11
|
+
t.add_player(Player.new('Mark', 'Orr', 3))
|
12
|
+
t.add_result(Result.new(1, 1, '=', :opponent => 2, :colour => 'W'))
|
13
|
+
t.add_result(Result.new(2, 2, 'L', :opponent => 3, :colour => 'W'))
|
14
|
+
t.add_result(Result.new(3, 3, 'W', :opponent => 1, :colour => 'W'))
|
15
|
+
t.validate!
|
16
|
+
end.should_not raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "documentation example" do
|
21
|
+
before(:each) do
|
22
|
+
@t = t = ICU::Tournament.new('Bangor Masters', '2009-11-09')
|
23
|
+
t.add_player(ICU::Player.new('Bobby', 'Fischer', 10))
|
24
|
+
t.add_player(ICU::Player.new('Garry', 'Kasparov', 20))
|
25
|
+
t.add_player(ICU::Player.new('Mark', 'Orr', 30))
|
26
|
+
t.add_result(ICU::Result.new(1, 10, 'D', :opponent => 30, :colour => 'W'))
|
27
|
+
t.add_result(ICU::Result.new(2, 20, 'W', :opponent => 30, :colour => 'B'))
|
28
|
+
t.add_result(ICU::Result.new(3, 20, 'L', :opponent => 10, :colour => 'W'))
|
29
|
+
t.validate!(:rerank => true)
|
30
|
+
@s = <<EOS
|
31
|
+
012 Bangor Masters
|
32
|
+
042 2009-11-09
|
33
|
+
001 10 Fischer,Bobby 1.5 1 30 w = 20 b 1
|
34
|
+
001 20 Kasparov,Garry 1.0 2 30 b 1 10 w 0
|
35
|
+
001 30 Orr,Mark 0.5 3 10 b = 20 w 0
|
36
|
+
EOS
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should serialize to Krause" do
|
40
|
+
parser = ICU::Tournament::Krause.new
|
41
|
+
parser.serialize(@t).should == @s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "name" do
|
46
|
+
before(:each) do
|
47
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
48
|
+
end
|
49
|
+
|
50
|
+
it "must be specified in constructor" do
|
51
|
+
@t.name.should == 'Edinburgh Masters'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "can be replaced by accessor" do
|
55
|
+
@t.name = 'Bangor Bashers'
|
56
|
+
@t.name.should == 'Bangor Bashers'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not be blank or without letters" do
|
60
|
+
lambda { Tournament.new(' ', '2009-11-09') }.should raise_error(/invalid.*name/)
|
61
|
+
lambda { @t.name = '333' }.should raise_error(/invalid.*name/)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "city" do
|
66
|
+
before(:each) do
|
67
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09', :city => 'Edinburgh')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "may be specified in constructor" do
|
71
|
+
@t.city.should == 'Edinburgh'
|
72
|
+
end
|
73
|
+
|
74
|
+
it "can be replaced by accessor" do
|
75
|
+
@t.city = 'Glasgow'
|
76
|
+
@t.city.should == 'Glasgow'
|
77
|
+
end
|
78
|
+
|
79
|
+
it "can be set to nil" do
|
80
|
+
@t.city = ''
|
81
|
+
@t.city.should be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should not be without letters if set" do
|
85
|
+
lambda { @t.city = '123' }.should raise_error(/invalid.*city/)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "federation" do
|
90
|
+
before(:each) do
|
91
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09', :fed => 'SCO')
|
92
|
+
end
|
93
|
+
|
94
|
+
it "may be specified in constructor" do
|
95
|
+
@t.fed.should == 'SCO'
|
96
|
+
end
|
97
|
+
|
98
|
+
it "can be replaced by accessor" do
|
99
|
+
@t.fed = 'IRL'
|
100
|
+
@t.fed.should == 'IRL'
|
101
|
+
end
|
102
|
+
|
103
|
+
it "can be set to nil" do
|
104
|
+
@t.fed = ''
|
105
|
+
@t.fed.should be_nil
|
106
|
+
end
|
107
|
+
|
108
|
+
it "three letters will automatically be upcased" do
|
109
|
+
@t.fed = 'rus'
|
110
|
+
@t.fed.should == 'RUS'
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not be without letters if set" do
|
114
|
+
lambda { @t.fed = '123' }.should raise_error(/invalid.*federation/)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "start date" do
|
119
|
+
before(:each) do
|
120
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
121
|
+
end
|
122
|
+
|
123
|
+
it "must be specified in constructor" do
|
124
|
+
@t.start.should == '2009-11-09'
|
125
|
+
end
|
126
|
+
|
127
|
+
it "can be replaced by accessor" do
|
128
|
+
@t.start = '16th June 2010'
|
129
|
+
@t.start.should == '2010-06-16'
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should be a valid date" do
|
133
|
+
lambda { Tournament.new('Edinburgh Masters', ' ') }.should raise_error(/invalid.*date/)
|
134
|
+
lambda { @t.start = 'X' }.should raise_error(/invalid.*date/)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "finish date" do
|
139
|
+
before(:each) do
|
140
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09', :finish => '12th November 2009')
|
141
|
+
end
|
142
|
+
|
143
|
+
it "may be specified in constructor" do
|
144
|
+
@t.finish.should == '2009-11-12'
|
145
|
+
end
|
146
|
+
|
147
|
+
it "can be replaced by accessor" do
|
148
|
+
@t.finish = '16th December 2009'
|
149
|
+
@t.finish.should == '2009-12-16'
|
150
|
+
end
|
151
|
+
|
152
|
+
it "can be set to nil" do
|
153
|
+
@t.finish = ''
|
154
|
+
@t.finish.should be_nil
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should be a valid date" do
|
158
|
+
lambda { Tournament.new('Edinburgh Masters', '2009-11-09', :finish => 'next week') }.should raise_error(/invalid.*date/)
|
159
|
+
lambda { @t.finish = 'X' }.should raise_error(/invalid.*date/)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "rounds" do
|
164
|
+
it "defaults to nil" do
|
165
|
+
Tournament.new('Edinburgh Masters', '2009-11-09').rounds.should be_nil
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should be a positive integer or nil" do
|
169
|
+
Tournament.new('Edinburgh Masters', '2009-11-09', :rounds => 3).rounds.should == 3
|
170
|
+
Tournament.new('Edinburgh Masters', '2009-11-09', :rounds => ' 10 ').rounds.should == 10
|
171
|
+
Tournament.new('Edinburgh Masters', '2009-11-09', :rounds => nil).rounds.should be_nil
|
172
|
+
lambda { Tournament.new('Edinburgh Masters', '2009-11-09', :rounds => ' 0 ') }.should raise_error(/invalid.*rounds/)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context "last_round" do
|
177
|
+
before(:each) do
|
178
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
179
|
+
@t.add_player(@mark = Player.new('Mark', 'Orr', 1))
|
180
|
+
@t.add_player(@gary = Player.new('Gary', 'Kasparov', 2))
|
181
|
+
@t.add_player(@boby = Player.new('Bobby', 'Fischer', 3))
|
182
|
+
end
|
183
|
+
|
184
|
+
it "depends on the players results" do
|
185
|
+
@t.last_round.should == 0
|
186
|
+
@t.add_result(Result.new(1, 1, 'W', :opponent => 2))
|
187
|
+
@t.last_round.should == 1
|
188
|
+
@t.add_result(Result.new(2, 2, 'D', :opponent => 3))
|
189
|
+
@t.last_round.should == 2
|
190
|
+
@t.add_result(Result.new(5, 3, 'L', :opponent => 1))
|
191
|
+
@t.last_round.should == 5
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context "round date" do
|
196
|
+
before(:each) do
|
197
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should default to none" do
|
201
|
+
@t.round_dates.size.should == 0
|
202
|
+
end
|
203
|
+
|
204
|
+
it "can be added one by one in any order" do
|
205
|
+
@t.add_round_date('2009-11-11')
|
206
|
+
@t.add_round_date('09/11/2009')
|
207
|
+
@t.add_round_date('10th November 2009')
|
208
|
+
@t.round_dates.join('|').should == '2009-11-09|2009-11-10|2009-11-11'
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context "site" do
|
213
|
+
it "defaults to nil" do
|
214
|
+
Tournament.new('Edinburgh Masters', '2009-11-09').site.should be_nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should be a reasonably valid looking URL" do
|
218
|
+
Tournament.new('Edinburgh Masters', '2009-11-09', :site => 'https://www.bbc.co.uk').site.should == 'https://www.bbc.co.uk'
|
219
|
+
Tournament.new('Edinburgh Masters', '2009-11-09', :site => 'www.icu.ie/event.php?id=1').site.should == 'http://www.icu.ie/event.php?id=1'
|
220
|
+
lambda { Tournament.new('Edinburgh Masters', '2009-11-09', :site => 'X') }.should raise_error(/invalid.*site/)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context "type, arbiter, deputy and time control" do
|
225
|
+
before(:each) do
|
226
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09', :type => 'Swiss', :arbiter => 'Gerry Graham', :deputy => 'Herbert Scarry', :time_control => '120 minutes')
|
227
|
+
end
|
228
|
+
|
229
|
+
it "may be specified in constructor" do
|
230
|
+
@t.type.should == 'Swiss'
|
231
|
+
@t.arbiter.should == 'Gerry Graham'
|
232
|
+
@t.deputy.should == 'Herbert Scarry'
|
233
|
+
@t.time_control.should == '120 minutes'
|
234
|
+
end
|
235
|
+
|
236
|
+
it "can be replaced by accessor" do
|
237
|
+
@t.type = 'all-play-all'
|
238
|
+
@t.type.should == 'all-play-all'
|
239
|
+
@t.arbiter = 'Michael Crowe'
|
240
|
+
@t.arbiter.should == 'Michael Crowe'
|
241
|
+
@t.deputy = 'Mark Orr'
|
242
|
+
@t.deputy.should == 'Mark Orr'
|
243
|
+
@t.time_control = '90 minutes'
|
244
|
+
@t.time_control.should == '90 minutes'
|
245
|
+
end
|
246
|
+
|
247
|
+
it "can be set to nil" do
|
248
|
+
@t.type = ''
|
249
|
+
@t.type.should be_nil
|
250
|
+
@t.arbiter = ''
|
251
|
+
@t.arbiter.should be_nil
|
252
|
+
@t.deputy = ''
|
253
|
+
@t.deputy.should be_nil
|
254
|
+
@t.time_control = ''
|
255
|
+
@t.time_control.should be_nil
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should be valid" do
|
259
|
+
lambda { @t.type = '123' }.should raise_error(/invalid.*type/)
|
260
|
+
lambda { @t.arbiter = '123' }.should raise_error(/invalid.*arbiter/)
|
261
|
+
lambda { @t.deputy = '123' }.should raise_error(/invalid.*deputy/)
|
262
|
+
lambda { @t.time_control = 'abc' }.should raise_error(/invalid.*time.*control/)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
context "players" do
|
267
|
+
before(:each) do
|
268
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should have unique numbers" do
|
272
|
+
@t.add_player(Player.new('Mark', 'Orr', 1))
|
273
|
+
lambda { @t.add_player(Player.new('Bobby', 'Fischer', 1)) }.should raise_error(/player.*unique/)
|
274
|
+
end
|
275
|
+
|
276
|
+
it "can be added one at a time" do
|
277
|
+
@t.add_player(Player.new('Mark', 'Orr', -1))
|
278
|
+
@t.add_player(Player.new('Gary', 'Kasparov', -2))
|
279
|
+
@t.add_player(Player.new('Bobby', 'Fischer', -3))
|
280
|
+
@t.players.size.should == 3
|
281
|
+
@t.player(-1).first_name.should == 'Mark'
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context "results" do
|
286
|
+
before(:each) do
|
287
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09', :rounds => 3)
|
288
|
+
@t.add_player(@mark = Player.new('Mark', 'Orr', 1))
|
289
|
+
@t.add_player(@gary = Player.new('Gary', 'Kasparov', 2))
|
290
|
+
@t.add_player(@boby = Player.new('Bobby', 'Fischer', 3))
|
291
|
+
end
|
292
|
+
|
293
|
+
it "can be added one at a time" do
|
294
|
+
@t.add_result(Result.new(1, 1, 'W', :opponent => 2))
|
295
|
+
@t.add_result(Result.new(2, 2, 'D', :opponent => 3))
|
296
|
+
@t.add_result(Result.new(3, 3, 'L', :opponent => 1))
|
297
|
+
@mark.results.size.should == 2
|
298
|
+
@mark.points.should == 2.0
|
299
|
+
@gary.results.size.should == 2
|
300
|
+
@gary.points.should == 0.5
|
301
|
+
@boby.results.size.should == 2
|
302
|
+
@boby.points.should == 0.5
|
303
|
+
end
|
304
|
+
|
305
|
+
it "can be added symmetrically or asymmetrically with respect to rateability" do
|
306
|
+
@t.add_result(Result.new(1, 1, 'W', :opponent => 2))
|
307
|
+
@mark.results[0].rateable.should be_true
|
308
|
+
@gary.results[0].rateable.should be_true
|
309
|
+
@t.add_result(Result.new(2, 1, 'W', :opponent => 3), false)
|
310
|
+
@mark.results[1].rateable.should be_true
|
311
|
+
@boby.results[0].rateable.should be_false
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should have a defined player" do
|
315
|
+
lambda { @t.add_result(Result.new(1, 4, 'L', :opponent => 1)) }.should raise_error(/player.*exist/)
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should have a defined opponent" do
|
319
|
+
lambda { @t.add_result(Result.new(1, 1, 'W', :opponent => 4)) }.should raise_error(/opponent.*exist/)
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should be consistent with the tournament's number of rounds" do
|
323
|
+
lambda { @t.add_result(Result.new(4, 1, 'W', :opponent => 2)) }.should raise_error(/round/)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context "finding players" do
|
328
|
+
before(:all) do
|
329
|
+
@t = Tournament.new('Bangor Bash', '2009-11-09')
|
330
|
+
@t.add_player(Player.new('Bobby', 'Fischer', 1, :fed => 'USA'))
|
331
|
+
@t.add_player(Player.new('Garry', 'Gary Kasparov', 2, :fed => 'RUS'))
|
332
|
+
@t.add_player(Player.new('Mark', 'Orr', 3, :fed => 'IRL'))
|
333
|
+
end
|
334
|
+
|
335
|
+
it "should find players based on loose equality" do
|
336
|
+
@t.find_player(Player.new('Mark', 'Orr', 4, :fed => 'IRL')).num.should == 3
|
337
|
+
@t.find_player(Player.new('Mark', 'Orr', 4, :fed => 'USA')).should be_nil
|
338
|
+
@t.find_player(Player.new('Mark', 'Sax', 4, :fed => 'IRL')).should be_nil
|
339
|
+
@t.find_player(Player.new('John', 'Orr', 4, :fed => 'IRL')).should be_nil
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context "teams" do
|
344
|
+
before(:each) do
|
345
|
+
@t = Tournament.new('Bangor Bash', '2009-11-09')
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should be able to create a new team, add it and retrieve it" do
|
349
|
+
team = Team.new('Wandering Dragons')
|
350
|
+
@t.add_team(team).should be_an_instance_of Team
|
351
|
+
@t.get_team(' wandering dragons ').should be_an_instance_of Team
|
352
|
+
@t.get_team('Blundering Bishops').should be_nil
|
353
|
+
end
|
354
|
+
|
355
|
+
it "should be able to create and add a new team and retrieve it" do
|
356
|
+
@t.add_team('Blundering Bishops').should be_an_instance_of Team
|
357
|
+
@t.get_team(' blundering bishops ').should be_an_instance_of Team
|
358
|
+
@t.get_team('Wandering Dragons').should be_nil
|
359
|
+
end
|
360
|
+
|
361
|
+
it "should throw and exception if there is an attempt to add a team with a name that matches an existing team" do
|
362
|
+
lambda { @t.add_team('Blundering Bishops') }.should_not raise_error
|
363
|
+
lambda { @t.add_team('Wandering Dragons') }.should_not raise_error
|
364
|
+
lambda { @t.add_team(' wandering dragons ') }.should raise_error(/similar.*exists/)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
context "validation" do
|
369
|
+
before(:each) do
|
370
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
371
|
+
@t.add_player(@mark = Player.new('Mark', 'Orr', 1))
|
372
|
+
@t.add_player(@gary = Player.new('Gary', 'Kasparov', 2))
|
373
|
+
@t.add_player(@boby = Player.new('Bobby', 'Fischer', 3))
|
374
|
+
@t.add_result(Result.new(1, 1, 'W', :opponent => 2))
|
375
|
+
@t.add_result(Result.new(2, 2, 'W', :opponent => 3))
|
376
|
+
@t.add_result(Result.new(3, 3, 'L', :opponent => 1))
|
377
|
+
@t.add_round_date('2009-11-09')
|
378
|
+
@t.add_round_date('2009-11-10')
|
379
|
+
@t.add_round_date('2009-11-11')
|
380
|
+
end
|
381
|
+
|
382
|
+
it "should be valid" do
|
383
|
+
@t.invalid.should be_false
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should have side effect of setting number of rounds" do
|
387
|
+
@t.rounds.should be_nil
|
388
|
+
@t.invalid
|
389
|
+
@t.rounds.should == 3
|
390
|
+
end
|
391
|
+
|
392
|
+
it "should detect an inconsistent start date" do
|
393
|
+
@t.start = '2009-11-10'
|
394
|
+
lambda { @t.validate! }.should raise_error(/first round.*before.*start/)
|
395
|
+
end
|
396
|
+
|
397
|
+
it "should detect an inconsistent finish date" do
|
398
|
+
@t.finish = '2009-11-10'
|
399
|
+
lambda { @t.validate! }.should raise_error(/last round.*after.*end/)
|
400
|
+
end
|
401
|
+
|
402
|
+
it "should have side effect of setting missing finish date" do
|
403
|
+
@t.finish.should be_nil
|
404
|
+
@t.invalid
|
405
|
+
@t.finish.should == '2009-11-11'
|
406
|
+
end
|
407
|
+
|
408
|
+
it "should detect inconsistent round dates" do
|
409
|
+
@t.add_round_date('2009-11-12')
|
410
|
+
lambda { @t.validate! }.should raise_error(/round dates.*match.*rounds/)
|
411
|
+
end
|
412
|
+
|
413
|
+
it "should have the side effect of providing missing ranks if the rerank option is set" do
|
414
|
+
@t.players.select{ |p| p.rank }.size.should == 0
|
415
|
+
@t.invalid(:rerank => true)
|
416
|
+
@t.player(1).rank.should == 1
|
417
|
+
@t.player(2).rank.should == 2
|
418
|
+
@t.player(3).rank.should == 3
|
419
|
+
end
|
420
|
+
|
421
|
+
it "should have the side effect of correcting bad ranks if the rerank option is set" do
|
422
|
+
@t.player(1).rank = 2
|
423
|
+
@t.player(2).rank = 1
|
424
|
+
@t.player(3).rank = 3
|
425
|
+
@t.invalid(:rerank => true)
|
426
|
+
@t.player(1).rank.should == 1
|
427
|
+
@t.player(2).rank.should == 2
|
428
|
+
@t.player(3).rank.should == 3
|
429
|
+
end
|
430
|
+
|
431
|
+
it "should detect missranked players" do
|
432
|
+
@t.player(1).rank = 2
|
433
|
+
@t.player(2).rank = 1
|
434
|
+
@t.player(3).rank = 3
|
435
|
+
lambda { @t.validate! }.should raise_error(/player 2.*above.*player 1/)
|
436
|
+
end
|
437
|
+
|
438
|
+
it "should be valid if there are teams, every player is in one of them, and no team has an invalid member" do
|
439
|
+
team1 = Team.new('International Masters')
|
440
|
+
team2 = Team.new('World Champions')
|
441
|
+
@t.add_team(team1)
|
442
|
+
@t.add_team(team2)
|
443
|
+
@t.invalid.should match(/not.*member/)
|
444
|
+
team1.add_member(1)
|
445
|
+
team2.add_member(2)
|
446
|
+
team2.add_member(3)
|
447
|
+
@t.invalid.should be_false
|
448
|
+
team1.add_member(4)
|
449
|
+
@t.invalid.should match(/not.*valid/)
|
450
|
+
end
|
451
|
+
|
452
|
+
it "should not be valid if one player is in more than one team" do
|
453
|
+
team1 = Team.new('XInternational Masters')
|
454
|
+
team1.add_member(1)
|
455
|
+
team2 = Team.new('XWorld Champions')
|
456
|
+
team2.add_member(2)
|
457
|
+
team2.add_member(3)
|
458
|
+
@t.add_team(team1)
|
459
|
+
@t.add_team(team2)
|
460
|
+
@t.invalid.should be_false
|
461
|
+
team1.add_member(2)
|
462
|
+
@t.invalid.should match(/already.*member/)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
context "renumbering" do
|
467
|
+
before(:each) do
|
468
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
469
|
+
@t.add_player(@mark = Player.new('Mark', 'Orr', 20))
|
470
|
+
@t.add_player(@boby = Player.new('Bobby', 'Fischer', 10))
|
471
|
+
@t.add_player(@gary = Player.new('Gary', 'Kasparov', 30))
|
472
|
+
@t.add_result(Result.new(1, 20, 'W', :opponent => 10))
|
473
|
+
@t.add_result(Result.new(2, 30, 'W', :opponent => 10))
|
474
|
+
@t.add_result(Result.new(3, 20, 'W', :opponent => 30))
|
475
|
+
end
|
476
|
+
|
477
|
+
it "sample tournament is valid but unranked" do
|
478
|
+
@t.invalid.should be_false
|
479
|
+
@t.player(10).rank.should be_nil
|
480
|
+
@t.players.map{ |p| p.num }.join('|').should == '10|20|30'
|
481
|
+
@t.players.map{ |p| p.last_name }.join('|').should == 'Fischer|Orr|Kasparov'
|
482
|
+
end
|
483
|
+
|
484
|
+
it "should be renumberable by name in the absence of ranking" do
|
485
|
+
@t.renumber
|
486
|
+
@t.invalid.should be_false
|
487
|
+
@t.players.map{ |p| p.num }.join('|').should == '1|2|3'
|
488
|
+
@t.players.map{ |p| p.last_name }.join('|').should == 'Fischer|Kasparov|Orr'
|
489
|
+
end
|
490
|
+
|
491
|
+
it "should be renumberable by rank if the tournament is ranked" do
|
492
|
+
@t.rerank.renumber
|
493
|
+
@t.invalid.should be_false
|
494
|
+
@t.players.map{ |p| p.num }.join('|').should == '1|2|3'
|
495
|
+
@t.players.map{ |p| p.rank }.join('|').should == '1|2|3'
|
496
|
+
@t.players.map{ |p| p.last_name }.join('|').should == 'Orr|Kasparov|Fischer'
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should be renumberable by name even if the tourament is ranked" do
|
500
|
+
@t.rerank.renumber(:name)
|
501
|
+
@t.invalid.should be_false
|
502
|
+
@t.players.map{ |p| p.num }.join('|').should == '1|2|3'
|
503
|
+
@t.players.map{ |p| p.last_name }.join('|').should == 'Fischer|Kasparov|Orr'
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
context "reranking" do
|
508
|
+
before(:each) do
|
509
|
+
@t = Tournament.new('Edinburgh Masters', '2009-11-09')
|
510
|
+
@t.add_player(@boby = Player.new('Bobby', 'Fischer', 1))
|
511
|
+
@t.add_player(@gary = Player.new('Gary', 'Kasparov', 2))
|
512
|
+
@t.add_player(@boby = Player.new('Micky', 'Mouse', 3))
|
513
|
+
@t.add_player(@boby = Player.new('Minnie', 'Mouse', 4))
|
514
|
+
@t.add_player(@boby = Player.new('Gearoidin', 'Ui Laighleis', 5))
|
515
|
+
@t.add_player(@mark = Player.new('Mark', 'Orr', 6))
|
516
|
+
@t.add_result(Result.new(1, 1, 'W', :opponent => 6, :colour => 'W'))
|
517
|
+
@t.add_result(Result.new(2, 1, 'W', :opponent => 3, :colour => 'B'))
|
518
|
+
@t.add_result(Result.new(3, 1, 'W', :opponent => 5, :colour => 'W'))
|
519
|
+
@t.add_result(Result.new(1, 2, 'W', :opponent => 5, :colour => 'B'))
|
520
|
+
@t.add_result(Result.new(2, 2, 'W', :opponent => 4, :colour => 'W'))
|
521
|
+
@t.add_result(Result.new(3, 2, 'W', :opponent => 3, :colour => 'B'))
|
522
|
+
@t.add_result(Result.new(1, 3, 'W', :opponent => 4, :colour => 'W'))
|
523
|
+
@t.add_result(Result.new(3, 4, 'W', :opponent => 6, :colour => 'W'))
|
524
|
+
@t.add_result(Result.new(2, 5, 'D', :opponent => 6, :colour => 'W'))
|
525
|
+
end
|
526
|
+
|
527
|
+
it "should initially be valid but unranked" do
|
528
|
+
@t.invalid.should be_false
|
529
|
+
@t.player(1).rank.should be_nil
|
530
|
+
end
|
531
|
+
|
532
|
+
it "should have correct default tie break scores" do
|
533
|
+
scores = @t.tie_break_scores
|
534
|
+
scores[1].should == 'Fischer, Bobby'
|
535
|
+
scores[5].should == 'Ui Laighleis, Gearoidin'
|
536
|
+
end
|
537
|
+
|
538
|
+
it "should have correct actual scores" do
|
539
|
+
@t.player(1).points.should == 3.0
|
540
|
+
@t.player(2).points.should == 3.0
|
541
|
+
@t.player(3).points.should == 1.0
|
542
|
+
@t.player(4).points.should == 1.0
|
543
|
+
@t.player(5).points.should == 0.5
|
544
|
+
@t.player(6).points.should == 0.5
|
545
|
+
end
|
546
|
+
|
547
|
+
it "should have correct Buchholz tie break scores" do
|
548
|
+
scores = @t.tie_break_scores("Buchholz")
|
549
|
+
scores[1].should == 2.0
|
550
|
+
scores[2].should == 2.5
|
551
|
+
scores[3].should == 7.0
|
552
|
+
scores[4].should == 4.5
|
553
|
+
scores[5].should == 6.5
|
554
|
+
scores[6].should == 4.5
|
555
|
+
end
|
556
|
+
|
557
|
+
it "Buchholz should be sensitive to unplayed games" do
|
558
|
+
@t.player(1).find_result(1).opponent = nil
|
559
|
+
@t.player(6).find_result(1).opponent = nil
|
560
|
+
scores = @t.tie_break_scores("Buchholz")
|
561
|
+
scores[1].should == 1.5 # 0.5 from Orr changed to 0
|
562
|
+
scores[2].should == 2.5 # didn't play Fischer or Orr so unaffected
|
563
|
+
scores[3].should == 6.5 # 3 from Fischer's changed to 2.5
|
564
|
+
scores[4].should == 5.0 # 0.5 from Orr changed to 1 (because Orr's unrated loss to Fischer now counts as a draw)
|
565
|
+
scores[5].should == 6.5 # 3 from Fischer changed to 2.5, 0.5 from Orr changed to 1 (cancels out)
|
566
|
+
scores[6].should == 1.5 # 3 from Fischer changed to 0
|
567
|
+
end
|
568
|
+
|
569
|
+
it "should have correct Neustadtl tie break scores" do
|
570
|
+
scores = @t.tie_break_scores(:neustadtl)
|
571
|
+
scores[1].should == 2.0
|
572
|
+
scores[2].should == 2.5
|
573
|
+
scores[3].should == 1.0
|
574
|
+
scores[4].should == 0.5
|
575
|
+
scores[5].should == 0.25
|
576
|
+
scores[6].should == 0.25
|
577
|
+
end
|
578
|
+
|
579
|
+
it "Neustadtl should be sensitive to unplayed games" do
|
580
|
+
@t.player(1).find_result(1).opponent = nil
|
581
|
+
@t.player(6).find_result(1).opponent = nil
|
582
|
+
scores = @t.tie_break_scores("Neustadtl")
|
583
|
+
scores[1].should == 1.5 # 0.5 from Orr changed to 0
|
584
|
+
scores[2].should == 2.5 # didn't play Fischer or Orr so unaffected
|
585
|
+
scores[3].should == 1.0 # win against Minnie unaffected
|
586
|
+
scores[4].should == 1.0 # 0.5 from Orr changed to 1 (because Orr's unrated loss to Fischer now counts as a draw)
|
587
|
+
scores[5].should == 0.5 # 0.25 from Orr changed to 0.5
|
588
|
+
scores[6].should == 0.25 # loss against Fisher and unplayed against Fisher equivalent
|
589
|
+
end
|
590
|
+
|
591
|
+
it "should have correct Harkness tie break scores" do
|
592
|
+
scores = @t.tie_break_scores('harkness')
|
593
|
+
scores[1].should == 0.5
|
594
|
+
scores[2].should == 1.0
|
595
|
+
scores[3].should == 3.0
|
596
|
+
scores[4].should == 1.0
|
597
|
+
scores[5].should == 3.0
|
598
|
+
scores[6].should == 1.0
|
599
|
+
end
|
600
|
+
|
601
|
+
it "should have correct Modified Median tie break scores" do
|
602
|
+
scores = @t.tie_break_scores('Modified Median')
|
603
|
+
scores[1].should == 1.5
|
604
|
+
scores[2].should == 2.0
|
605
|
+
scores[3].should == 4.0
|
606
|
+
scores[4].should == 1.5
|
607
|
+
scores[5].should == 3.5
|
608
|
+
scores[6].should == 1.5
|
609
|
+
end
|
610
|
+
|
611
|
+
it "should have correct tie break scores for number of blacks" do
|
612
|
+
scores = @t.tie_break_scores('Blacks')
|
613
|
+
scores[3].should == 0
|
614
|
+
scores[4].should == 2
|
615
|
+
end
|
616
|
+
|
617
|
+
it "number of blacks should should be sensitive to unplayed games" do
|
618
|
+
@t.player(2).find_result(1).opponent = nil
|
619
|
+
@t.player(4).find_result(1).opponent = nil
|
620
|
+
scores = @t.tie_break_scores(:blacks)
|
621
|
+
scores[3].should == 0
|
622
|
+
scores[4].should == 1
|
623
|
+
end
|
624
|
+
|
625
|
+
it "should have correct tie break scores for number of wins" do
|
626
|
+
scores = @t.tie_break_scores(:wins)
|
627
|
+
scores[1].should == 3
|
628
|
+
scores[6].should == 0
|
629
|
+
end
|
630
|
+
|
631
|
+
it "number of wins should should be sensitive to unplayed games" do
|
632
|
+
@t.player(1).find_result(1).opponent = nil
|
633
|
+
@t.player(6).find_result(1).opponent = nil
|
634
|
+
scores = @t.tie_break_scores('WINS')
|
635
|
+
scores[1].should == 2
|
636
|
+
scores[6].should == 0
|
637
|
+
end
|
638
|
+
|
639
|
+
it "should use names for tie breaking by default" do
|
640
|
+
@t.rerank
|
641
|
+
@t.player(1).rank.should == 1 # 3.0/"Fischer"
|
642
|
+
@t.player(2).rank.should == 2 # 3.0/"Kasparov"
|
643
|
+
@t.player(3).rank.should == 3 # 1.0/"Mouse,Mickey"
|
644
|
+
@t.player(4).rank.should == 4 # 1.0/"Mouse,Minnie"
|
645
|
+
@t.player(6).rank.should == 5 # 0.5/"Ui"
|
646
|
+
@t.player(5).rank.should == 6 # 0.5/"Orr"
|
647
|
+
end
|
648
|
+
|
649
|
+
it "should be configurable to use Buchholz" do
|
650
|
+
@t.rerank('Buchholz')
|
651
|
+
@t.player(2).rank.should == 1 # 3.0/2.5
|
652
|
+
@t.player(1).rank.should == 2 # 3.0/2.0
|
653
|
+
@t.player(3).rank.should == 3 # 1.0/7.0
|
654
|
+
@t.player(4).rank.should == 4 # 1.0/4.5
|
655
|
+
@t.player(5).rank.should == 5 # 0.5/6.5
|
656
|
+
@t.player(6).rank.should == 6 # 0.5/4.5
|
657
|
+
end
|
658
|
+
|
659
|
+
it "should be configurable to use Neustadtl" do
|
660
|
+
@t.rerank(:neustadtl)
|
661
|
+
@t.player(2).rank.should == 1 # 3.0/2.5
|
662
|
+
@t.player(1).rank.should == 2 # 3.0/2.0
|
663
|
+
@t.player(3).rank.should == 3 # 1.0/1.0
|
664
|
+
@t.player(4).rank.should == 4 # 1.0/0.5
|
665
|
+
@t.player(6).rank.should == 5 # 0.5/0.25/"Orr"
|
666
|
+
@t.player(5).rank.should == 6 # 0.5/0.25/"Ui"
|
667
|
+
end
|
668
|
+
|
669
|
+
it "should be configurable to use number of blacks" do
|
670
|
+
@t.rerank(:blacks)
|
671
|
+
@t.player(2).rank.should == 1 # 3.0/2
|
672
|
+
@t.player(1).rank.should == 2 # 3.0/1
|
673
|
+
@t.player(4).rank.should == 3 # 1.0/2
|
674
|
+
@t.player(3).rank.should == 4 # 1.0/1
|
675
|
+
@t.player(6).rank.should == 5 # 0.5/2
|
676
|
+
@t.player(5).rank.should == 6 # 0.5/1
|
677
|
+
end
|
678
|
+
|
679
|
+
it "should be configurable to use number of wins" do
|
680
|
+
@t.rerank(:wins)
|
681
|
+
@t.player(1).rank.should == 1 # 3.0/3/"Fi"
|
682
|
+
@t.player(2).rank.should == 2 # 3.0/3/"Ka"
|
683
|
+
@t.player(3).rank.should == 3 # 1.0/1/"Mic"
|
684
|
+
@t.player(4).rank.should == 4 # 1.0/1/"Min"
|
685
|
+
@t.player(6).rank.should == 5 # 0.5/0/"Orr"
|
686
|
+
@t.player(5).rank.should == 6 # 0.5/0/"Ui"
|
687
|
+
end
|
688
|
+
|
689
|
+
it "should exhibit equivalence between Neustadtl and Sonneborn-Berger" do
|
690
|
+
@t.rerank('Sonneborn-Berger')
|
691
|
+
(1..6).inject(''){ |t,r| t << @t.player(r).rank.to_s }.should == '213465'
|
692
|
+
end
|
693
|
+
|
694
|
+
it "should be able to use more than one method" do
|
695
|
+
@t.rerank(:neustadtl, :buchholz)
|
696
|
+
@t.player(2).rank.should == 1 # 3.0/2.5
|
697
|
+
@t.player(1).rank.should == 2 # 3.0/2.0
|
698
|
+
@t.player(3).rank.should == 3 # 1.0/1.0
|
699
|
+
@t.player(4).rank.should == 4 # 1.0/0.5
|
700
|
+
@t.player(5).rank.should == 5 # 0.5/0.25/6.5
|
701
|
+
@t.player(6).rank.should == 6 # 0.5/0.25/4.5
|
702
|
+
end
|
703
|
+
|
704
|
+
it "should throw exception on invalid tie break method" do
|
705
|
+
lambda { @t.rerank(:no_such_tie_break_method) }.should raise_error(/invalid.*method/)
|
706
|
+
end
|
707
|
+
|
708
|
+
it "should throw exception on invalid tie break method via validation" do
|
709
|
+
lambda { @t.validate!(:rerank => :stupid_tie_break_method) }.should raise_error(/invalid.*method/)
|
710
|
+
end
|
711
|
+
|
712
|
+
it "should be possible as a side effect of validation" do
|
713
|
+
@t.invalid(:rerank => :buchholz).should be_false
|
714
|
+
@t.player(2).rank.should == 1 # 3/3
|
715
|
+
@t.player(1).rank.should == 2 # 3/2
|
716
|
+
@t.player(3).rank.should == 3 # 1/7
|
717
|
+
@t.player(4).rank.should == 4 # 1/4
|
718
|
+
@t.player(5).rank.should == 5 # 1/6
|
719
|
+
@t.player(6).rank.should == 6 # 0/5
|
720
|
+
end
|
721
|
+
|
722
|
+
it "should be possible as a side effect of validation with multiple tie break methods" do
|
723
|
+
@t.invalid(:rerank => [:neustadtl, :buchholz]).should be_false
|
724
|
+
@t.player(2).rank.should == 1 # 3/3
|
725
|
+
@t.player(1).rank.should == 2 # 3/2
|
726
|
+
@t.player(3).rank.should == 3 # 1/7
|
727
|
+
@t.player(4).rank.should == 4 # 1/4
|
728
|
+
@t.player(5).rank.should == 5 # 1/6
|
729
|
+
@t.player(6).rank.should == 6 # 0/5
|
730
|
+
end
|
731
|
+
end
|
732
|
+
end
|
733
|
+
end
|