sanichi-chess_icu 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG +2 -0
- data/LICENCE +22 -0
- data/README.rdoc +11 -0
- data/Rakefile +41 -0
- data/VERSION.yml +4 -0
- data/lib/chess_icu.rb +3 -0
- data/lib/name.rb +217 -0
- data/lib/player.rb +143 -0
- data/lib/result.rb +103 -0
- data/lib/tournament.rb +81 -0
- data/lib/tournament_fcsv.rb +155 -0
- data/lib/util.rb +15 -0
- data/spec/name_spec.rb +172 -0
- data/spec/player_spec.rb +276 -0
- data/spec/result_spec.rb +165 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/tournament_fcsv_spec.rb +306 -0
- data/spec/tournament_spec.rb +166 -0
- data/spec/util_spec.rb +33 -0
- metadata +78 -0
data/spec/player_spec.rb
ADDED
@@ -0,0 +1,276 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
describe Player do
|
5
|
+
context "a typical player" do
|
6
|
+
it "should have a name, number and some results" do
|
7
|
+
lambda do
|
8
|
+
player = Player.new('Mark', 'Orr', 1)
|
9
|
+
player.add_result(Result.new(1, 1, 'W', :opponent => 37, :score => 'W', :colour => 'W'))
|
10
|
+
player.add_result(Result.new(2, 1, 'W', :opponent => 13, :score => 'W', :colour => 'B'))
|
11
|
+
player.add_result(Result.new(3, 1, 'W', :opponent => 7, :score => 'D', :colour => 'W'))
|
12
|
+
end.should_not raise_error
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "names" do
|
17
|
+
it "should be specified in constructor" do
|
18
|
+
p = Player.new('Mark', 'Orr', 1)
|
19
|
+
p.first_name.should == 'Mark'
|
20
|
+
p.last_name.should == 'Orr'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be resettable via accessors" do
|
24
|
+
p = Player.new('Mark', 'Orr', 1)
|
25
|
+
p.first_name= 'Gary'
|
26
|
+
p.last_name= 'Kasparov'
|
27
|
+
p.first_name.should == 'Gary'
|
28
|
+
p.last_name.should == 'Kasparov'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not contain invalid characters" do
|
32
|
+
lambda { Player.new('12', 'Orr', 1) }.should raise_error(/invalid first name/)
|
33
|
+
lambda { Player.new('Mark', '*!', 1) }.should raise_error(/invalid last name/)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not have empty last name" do
|
37
|
+
lambda { Player.new('Mark', '', 1) }.should raise_error(/invalid last name/)
|
38
|
+
lambda { Player.new('', 'Orr', 1) }.should raise_error(/invalid first name/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "both names can be returned together" do
|
42
|
+
p = Player.new('Mark', 'Orr', 1)
|
43
|
+
p.name.should == 'Orr, Mark'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "names should be automatically canonicalised" do
|
47
|
+
p = Player.new(' maRk J l ', ' ORR', 1)
|
48
|
+
p.name.should == 'Orr, Mark J. L.'
|
49
|
+
p.first_name = 'z'
|
50
|
+
p.name.should == 'Orr, Z.'
|
51
|
+
p.last_name = " o meFiSto "
|
52
|
+
p.name.should == "O'Mefisto, Z."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "number" do
|
57
|
+
it "should just be an integer" do
|
58
|
+
Player.new('Mark', 'Orr', 3).num.should == 3
|
59
|
+
Player.new('Mark', 'Orr', -7).num.should == -7
|
60
|
+
Player.new('Mark', 'Orr', ' -4 ').num.should == -4
|
61
|
+
Player.new('Mark', 'Orr', '0').num.should == 0
|
62
|
+
lambda { Player.new('Mark', 'Orr', ' ') }.should raise_error(/invalid player number/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "ID" do
|
67
|
+
it "defaults to nil" do
|
68
|
+
Player.new('Mark', 'Orr', 3).id.should be_nil
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should be a positive integer" do
|
72
|
+
Player.new('Mark', 'Orr', 3, :id => 1350).id.should == 1350
|
73
|
+
Player.new('Gary', 'Kasparov', 4, :id => '4100018').id.should == 4100018
|
74
|
+
lambda { Player.new('Mark', 'Orr', 3, :id => ' 0 ') }.should raise_error(/invalid ID/)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "federation" do
|
79
|
+
it "defaults to nil" do
|
80
|
+
Player.new('Mark', 'Orr', 3).fed.should be_nil
|
81
|
+
Player.new('Mark', 'Orr', 3, :fed => ' ').fed.should be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should consist of at least three letters" do
|
85
|
+
Player.new('Gary', 'Kasparov', 1, :fed => 'RUS').fed.should == 'RUS'
|
86
|
+
Player.new('Mark', 'Orr', 3, :fed => ' Ireland ').fed.should == 'Ireland'
|
87
|
+
lambda { Player.new('Danny', 'Kopec', 3, :fed => 'US') }.should raise_error(/invalid federation/)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "title" do
|
92
|
+
it "defaults to nil" do
|
93
|
+
Player.new('Mark', 'Orr', 3).title.should be_nil
|
94
|
+
Player.new('Mark', 'Orr', 3, :title => ' ').title.should be_nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should be one of national, candidate, FIDE, international or grand master" do
|
98
|
+
Player.new('Gary', 'Kasparov', 1, :title => 'GM').title.should == 'GM'
|
99
|
+
Player.new('Mark', 'Orr', 2, :title => ' im ').title.should == 'IM'
|
100
|
+
Player.new('Pia', 'Cramling', 3, :title => ' wg ').title.should == 'WGM'
|
101
|
+
Player.new('Philip', 'Short', 4, :title => 'F ').title.should == 'FM'
|
102
|
+
Player.new('Gearoidin', 'Ui Laighleis', 5, :title => 'wc').title.should == 'WCM'
|
103
|
+
Player.new('Eamon', 'Keogh', 6, :title => 'nm').title.should == 'NM'
|
104
|
+
lambda { Player.new('Mark', 'Orr', 3, :title => 'Dr') }.should raise_error(/invalid chess title/)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "rating" do
|
109
|
+
it "defaults to nil" do
|
110
|
+
Player.new('Mark', 'Orr', 3).rating.should be_nil
|
111
|
+
Player.new('Mark', 'Orr', 3, :rating => ' ').rating.should be_nil
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should be a positive integer" do
|
115
|
+
Player.new('Gary', 'Kasparov', 1, :rating => 2800).rating.should == 2800
|
116
|
+
Player.new('Mark', 'Orr', 2, :rating => ' 2100 ').rating.should == 2100
|
117
|
+
lambda { Player.new('Mark', 'Orr', 3, :rating => -2100) }.should raise_error(/invalid rating/)
|
118
|
+
lambda { Player.new('Mark', 'Orr', 3, :rating => 'IM') }.should raise_error(/invalid rating/)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "rank" do
|
123
|
+
it "defaults to nil" do
|
124
|
+
Player.new('Mark', 'Orr', 3).rank.should be_nil
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should be a positive integer" do
|
128
|
+
Player.new('Mark', 'Orr', 3, :rank => 1).rank.should == 1
|
129
|
+
Player.new('Gary', 'Kasparov', 4, :rank => ' 29 ').rank.should == 29
|
130
|
+
lambda { Player.new('Mark', 'Orr', 3, :rank => 0) }.should raise_error(/invalid rank/)
|
131
|
+
lambda { Player.new('Mark', 'Orr', 3, :rank => ' -1 ') }.should raise_error(/invalid rank/)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "date of birth" do
|
136
|
+
it "defaults to nil" do
|
137
|
+
Player.new('Mark', 'Orr', 3).dob.should be_nil
|
138
|
+
Player.new('Mark', 'Orr', 3, :dob => ' ').dob.should be_nil
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should be a yyyy-mm-dd date" do
|
142
|
+
Player.new('Mark', 'Orr', 3, :dob => '1955-11-09').dob.should == '1955-11-09'
|
143
|
+
lambda { Player.new('Mark', 'Orr', 3, :dob => 'X') }.should raise_error(/invalid DOB/)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "results and points" do
|
148
|
+
it "should initialise to an empty array" do
|
149
|
+
results = Player.new('Mark', 'Orr', 3).results
|
150
|
+
results.should be_instance_of Array
|
151
|
+
results.size.should == 0
|
152
|
+
end
|
153
|
+
|
154
|
+
it "can be added to" do
|
155
|
+
player = Player.new('Mark', 'Orr', 3)
|
156
|
+
player.add_result(Result.new(1, 3, 'W', :opponent => 1))
|
157
|
+
player.add_result(Result.new(2, 3, 'D', :opponent => 2))
|
158
|
+
player.add_result(Result.new(3, 3, 'L', :opponent => 4))
|
159
|
+
results = player.results
|
160
|
+
results.should be_instance_of Array
|
161
|
+
results.size.should == 3
|
162
|
+
player.points.should == 1.5
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should not allow mismatched player numbers" do
|
166
|
+
player = Player.new('Mark', 'Orr', 3)
|
167
|
+
lambda { player.add_result(Result.new(1, 4, 'W', :opponent => 1)) }.should raise_error(/player number .* matched/)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should enforce unique round numbers" do
|
171
|
+
player = Player.new('Mark', 'Orr', 3)
|
172
|
+
player.add_result(Result.new(1, 3, 'W', :opponent => 1))
|
173
|
+
player.add_result(Result.new(2, 3, 'D', :opponent => 2))
|
174
|
+
lambda { player.add_result(Result.new(2, 3, 'L', :opponent => 4)) }.should raise_error(/round number .* unique/)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context "looking up results" do
|
179
|
+
before(:all) do
|
180
|
+
@p = Player.new('Mark', 'Orr', 1)
|
181
|
+
@p.add_result(Result.new(1, 1, 'W', :opponent => 37, :score => 'W', :colour => 'W'))
|
182
|
+
@p.add_result(Result.new(2, 1, 'W', :opponent => 13, :score => 'W', :colour => 'B'))
|
183
|
+
@p.add_result(Result.new(3, 1, 'W', :opponent => 7, :score => 'D', :colour => 'W'))
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should find results by round number" do
|
187
|
+
@p.find_result(1).opponent.should == 37
|
188
|
+
@p.find_result(2).opponent.should == 13
|
189
|
+
@p.find_result(3).opponent.should == 7
|
190
|
+
@p.find_result(4).should be_nil
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "subsumption" do
|
195
|
+
before(:each) do
|
196
|
+
@p1 = Player.new('Mark', 'Orr', 1, :id => 1350)
|
197
|
+
@p2 = Player.new('Mark', 'Orr', 2, :rating => 2100, :title => 'IM', :fed => 'IRL')
|
198
|
+
@p3 = Player.new('Gearoidin', 'Ui Laighleis', 3, :rating => 1600, :title => 'WIM', :fed => 'IRL')
|
199
|
+
end
|
200
|
+
|
201
|
+
it "takes on the ID, rating, title and fed of the other player but not the player number" do
|
202
|
+
@p1.subsume(@p2)
|
203
|
+
@p1.num.should == 1
|
204
|
+
@p1.id.should == 1350
|
205
|
+
@p1.rating.should == 2100
|
206
|
+
@p1.title.should == 'IM'
|
207
|
+
@p1.fed.should == 'IRL'
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should have a kind of symmetry" do
|
211
|
+
p1 = @p1.dup
|
212
|
+
p2 = @p2.dup
|
213
|
+
p1.subsume(p2).eql?(@p2.subsume(@p1))
|
214
|
+
end
|
215
|
+
|
216
|
+
it "cannot be done with unequal objects" do
|
217
|
+
lambda { @p1.subsume(@p3) }.should raise_error(/cannot merge.*not strictly equal/)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "loose equality" do
|
222
|
+
before(:all) do
|
223
|
+
@mark1 = Player.new('Mark', 'Orr', 1)
|
224
|
+
@mark2 = Player.new('Mark', 'Orr', 2, :fed => 'IRL')
|
225
|
+
@mark3 = Player.new('Mark', 'Orr', 3, :fed => 'USA')
|
226
|
+
@mark4 = Player.new('Mark', 'Sax', 4, :def => 'HUN')
|
227
|
+
@john1 = Player.new('John', 'Orr', 5, :fed => 'IRL')
|
228
|
+
end
|
229
|
+
|
230
|
+
it "any player is equal to itself" do
|
231
|
+
(@mark1 == @mark1).should be_true
|
232
|
+
end
|
233
|
+
|
234
|
+
it "two players are equal if their names are the same and their federations do not conflict" do
|
235
|
+
(@mark1 == @mark2).should be_true
|
236
|
+
end
|
237
|
+
|
238
|
+
it "two players cannot be equal if they have different names" do
|
239
|
+
(@mark1 == @mark4).should be_false
|
240
|
+
(@mark1 == @john1).should be_false
|
241
|
+
end
|
242
|
+
|
243
|
+
it "two players cannot be equal if they have different federations" do
|
244
|
+
(@mark2 == @mark3).should be_false
|
245
|
+
(@mark1 == @mark3).should be_true
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context "strict equality" do
|
250
|
+
before(:all) do
|
251
|
+
@mark1 = Player.new('Mark', 'Orr', 1)
|
252
|
+
@mark2 = Player.new('Mark', 'Orr', 2, :id => 1350, :rating => 2100, :title => 'IM')
|
253
|
+
@mark3 = Player.new('Mark', 'Orr', 3, :id => 1530)
|
254
|
+
@mark4 = Player.new('Mark', 'Orr', 4, :rating => 2200)
|
255
|
+
@mark5 = Player.new('Mark', 'Orr', 5, :title => 'GM')
|
256
|
+
end
|
257
|
+
|
258
|
+
it "any player is equal to itself" do
|
259
|
+
@mark1.eql?(@mark1).should be_true
|
260
|
+
@mark1.eql?(@mark1).should be_true
|
261
|
+
end
|
262
|
+
|
263
|
+
it "two players are equal as long as their ID, rating and title do not conflict" do
|
264
|
+
@mark1.eql?(@mark2).should be_true
|
265
|
+
@mark3.eql?(@mark4).should be_true
|
266
|
+
@mark4.eql?(@mark5).should be_true
|
267
|
+
end
|
268
|
+
|
269
|
+
it "two players are not equal if their ID, rating or title conflict" do
|
270
|
+
@mark2.eql?(@mark3).should be_false
|
271
|
+
@mark2.eql?(@mark4).should be_false
|
272
|
+
@mark2.eql?(@mark5).should be_false
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
data/spec/result_spec.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
describe Result do
|
5
|
+
context "a typical result" do
|
6
|
+
it "should have a round, player number and score plus optional opponent number, colour and rateable flag" do
|
7
|
+
lambda { Result.new(3, 5, 'W', :opponent => 11, :colour => 'W') }.should_not raise_error
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context "round number" do
|
12
|
+
it "should be a positive integer" do
|
13
|
+
lambda { Result.new(-2, 2, 0) }.should raise_error(/invalid round number/)
|
14
|
+
lambda { Result.new(0, 2, 0) }.should raise_error(/invalid round number/)
|
15
|
+
Result.new(1, 2, 0).round.should == 1
|
16
|
+
Result.new(' 3 ', 2, 0).round.should == 3
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "player number" do
|
21
|
+
it "should be an integer" do
|
22
|
+
lambda { Result.new(1, ' ', 0) }.should raise_error(/invalid player number/)
|
23
|
+
Result.new(1, 2, 0).player.should == 2
|
24
|
+
Result.new(1, ' 0 ', 0).player.should == 0
|
25
|
+
Result.new(1, -5, 0).player.should == -5
|
26
|
+
Result.new(1, " 9 ", 0).player.should == 9
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "score" do
|
31
|
+
[1, 1.0, 'W', 'w', '+'].each do |score|
|
32
|
+
it "should be 'W' for #{score}, #{score.class}" do
|
33
|
+
Result.new(1, 2, score).score.should == 'W'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
[0, 0.0, 'L', 'l', '-'].each do |score|
|
37
|
+
it "should be 'L' for #{score}, #{score.class}" do
|
38
|
+
Result.new(1, 2, score).score.should == 'L'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
['½', 0.5, 'D', 'd', '='].each do |score|
|
42
|
+
it "should be 'L' for #{score}, #{score.class}" do
|
43
|
+
Result.new(1, 2, score).score.should == 'D'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
['', ' ', 'x', 2, -1.0, nil].each do |score|
|
47
|
+
it "should raise error for invalid score (#{score})" do
|
48
|
+
lambda { Result.new(1, 2, score) }.should raise_error(/invalid score/)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
it "should be expressable as a number" do
|
52
|
+
Result.new(1, 2, 'W').points.should == 1.0
|
53
|
+
Result.new(1, 2, 'L').points.should == 0.0
|
54
|
+
Result.new(1, 2, 'D').points.should == 0.5
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "colour" do
|
59
|
+
it "should be 'W' or 'B' or nil (unknown)" do
|
60
|
+
Result.new(4, 1, 0).colour.should be_nil
|
61
|
+
Result.new(4, 1, 0, :colour => 'W').colour.should == 'W'
|
62
|
+
Result.new(4, 1, 0, :colour => 'white').colour.should == 'W'
|
63
|
+
Result.new(4, 1, 0, :colour => ' b ').colour.should == 'B'
|
64
|
+
Result.new(4, 1, 0, :colour => ' BLACK ').colour.should == 'B'
|
65
|
+
lambda { Result.new(4, 1, 0, :colour => 'red') }.should raise_error(/invalid colour/)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "opponent number" do
|
70
|
+
it "should be nil (the default) or an integer" do
|
71
|
+
Result.new(4, 1, 0).opponent.should be_nil
|
72
|
+
Result.new(4, 1, 0, :opponent => nil).opponent.should be_nil
|
73
|
+
Result.new(4, 1, 0, :opponent => ' ').opponent.should be_nil
|
74
|
+
Result.new(4, 1, 0, :opponent => 0).opponent.should == 0
|
75
|
+
Result.new(4, 1, 0, :opponent => 2).opponent.should == 2
|
76
|
+
Result.new(4, 1, 0, :opponent => -6).opponent.should == -6
|
77
|
+
Result.new(4, 1, 0, :opponent => ' 10 ').opponent.should == 10
|
78
|
+
lambda { Result.new(4, 1, 0, :opponent => 'X') }.should raise_error(/invalid opponent number/)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should be different to player number" do
|
82
|
+
lambda { Result.new(4, 1, 0, :opponent => 1) }.should raise_error(/opponent .* player .* different/)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "rateable flag" do
|
87
|
+
it "should default to false if there is no opponent" do
|
88
|
+
Result.new(4, 1, 0).rateable.should be_false
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should default to true if there is an opponent" do
|
92
|
+
Result.new(4, 1, 0, :opponent => 10).rateable.should be_true
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should change if an opponent is added" do
|
96
|
+
r = Result.new(4, 1, 0)
|
97
|
+
r.opponent = 5;
|
98
|
+
r.rateable.should be_true
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should be settable to false from the constructor" do
|
102
|
+
Result.new(4, 1, 0, :opponent => 10, :rateable => false).rateable.should be_false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should be settable to false using the accessor" do
|
106
|
+
r = Result.new(4, 1, 0, :opponent => 10)
|
107
|
+
r.rateable= false
|
108
|
+
r.rateable.should be_false
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should not be settable to true if there is no opponent" do
|
112
|
+
r = Result.new(4, 1, 0)
|
113
|
+
r.rateable= true
|
114
|
+
r.rateable.should be_false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "reversed result" do
|
119
|
+
it "should be nil if there is no opponent" do
|
120
|
+
Result.new(4, 1, 0).reverse.should be_nil
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should have player and opponent swapped" do
|
124
|
+
r = Result.new(4, 1, 0, :opponent => 2).reverse
|
125
|
+
r.player.should == 2
|
126
|
+
r.opponent.should == 1
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should have reversed result" do
|
130
|
+
Result.new(4, 1, 0, :opponent => 2).reverse.score.should == 'W'
|
131
|
+
Result.new(4, 1, 1, :opponent => 2).reverse.score.should == 'L'
|
132
|
+
Result.new(4, 1, '=', :opponent => 2).reverse.score.should == 'D'
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should preserve rateability" do
|
136
|
+
Result.new(4, 1, 0, :opponent => 2).reverse.rateable.should be_true
|
137
|
+
Result.new(4, 1, 0, :opponent => 2, :rateable => false).reverse.rateable.should be_false
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "loose equality" do
|
142
|
+
before(:each) do
|
143
|
+
@r1 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
|
144
|
+
@r2 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
|
145
|
+
@r3 = Result.new(2, 1, 0, :opponent => 2, :colour => 'W')
|
146
|
+
@r4 = Result.new(1, 3, 0, :opponent => 2, :colour => 'W')
|
147
|
+
@r5 = Result.new(1, 1, 1, :opponent => 2, :colour => 'W')
|
148
|
+
@r6 = Result.new(1, 1, 0, :opponent => 3, :colour => 'W')
|
149
|
+
@r7 = Result.new(1, 1, 0, :opponent => 2, :colour => 'B')
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should be equal if the round, player numbers, result and colour all match" do
|
153
|
+
(@r1 == @r2).should be_true
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should not be equal if the round, player numbers, result or colour do not match" do
|
157
|
+
(@r1 == @r3).should be_false
|
158
|
+
(@r1 == @r4).should be_false
|
159
|
+
(@r1 == @r5).should be_false
|
160
|
+
(@r1 == @r6).should be_false
|
161
|
+
(@r1 == @r7).should be_false
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,306 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
class Tournament
|
5
|
+
describe ForeignCSV do
|
6
|
+
def check_player(num, first, last, results, rateable, points, other={})
|
7
|
+
p = @t.player(num)
|
8
|
+
p.first_name.should == first
|
9
|
+
p.last_name.should == last
|
10
|
+
p.id.should == other[:id]
|
11
|
+
p.rating.should == other[:rating]
|
12
|
+
p.fed.should == other[:fed]
|
13
|
+
p.title.should == other[:title]
|
14
|
+
p.results.size.should == results
|
15
|
+
p.results.select{|r| r.rateable}.size.should == rateable
|
16
|
+
p.points.should == points
|
17
|
+
end
|
18
|
+
|
19
|
+
context "a typical tournament" do
|
20
|
+
before(:all) do
|
21
|
+
@csv = <<CSV
|
22
|
+
Event,"Bangor Open, 2003"
|
23
|
+
Start,1st July 2003
|
24
|
+
Rounds,4
|
25
|
+
Website,http://www.icu.ie/tournaments/display.php?id=371
|
26
|
+
|
27
|
+
Player,3364,Ui Laighleis,Gearoidin
|
28
|
+
1,0,B,Cronin,April,2005,,IRL
|
29
|
+
2,=,W,Connolly,Suzanne,1950,,IRL
|
30
|
+
3,=,-
|
31
|
+
4,1,B,Powell,Linda,1850,,WLS
|
32
|
+
Total,2
|
33
|
+
CSV
|
34
|
+
@f = ForeignCSV.new(@csv)
|
35
|
+
@t = @f.tournament
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have a name" do
|
39
|
+
@t.name.should == 'Bangor Open, 2003'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have a start date" do
|
43
|
+
@t.start.should == '2003-07-01'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have a number of rounds" do
|
47
|
+
@t.rounds.should == 4
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should have a website" do
|
51
|
+
@t.site.should == 'http://www.icu.ie/tournaments/display.php?id=371'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should have some players" do
|
55
|
+
@t.should have(4).players
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should have correct player details" do
|
59
|
+
check_player(1, 'Gearoidin', 'Ui Laighleis', 4, 3, 2.0, :id => 3364)
|
60
|
+
check_player(2, 'April', 'Cronin', 1, 0, 1.0, :rating => 2005, :fed => 'IRL')
|
61
|
+
check_player(3, 'Suzanne', 'Connolly', 1, 0, 0.5, :rating => 1950, :fed => 'IRL')
|
62
|
+
check_player(4, 'Linda', 'Powell', 1, 0, 0.0, :rating => 1850, :fed => 'WLS')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "a tournament with more than one player" do
|
67
|
+
before(:all) do
|
68
|
+
@csv = <<CSV
|
69
|
+
Event,"Edinburgh Masters, 2007"
|
70
|
+
Start,3rd January 2007
|
71
|
+
Rounds,2
|
72
|
+
Website,http://www.chesscenter.com/twic/twic.html
|
73
|
+
|
74
|
+
Player,3364,Ui Laighleis,Gearoidin
|
75
|
+
1,=,W,Kasparov,Gary,2800,GM,RUS
|
76
|
+
2,=,B,Cronin,April,2005,,IRL
|
77
|
+
Total,1.0
|
78
|
+
|
79
|
+
Player,1350,Orr,Mark
|
80
|
+
1,=,W,Cronin,April,2005,,IRL
|
81
|
+
2,1,B,Fischer,Bobby,2700,GM,USA
|
82
|
+
Total,1.5
|
83
|
+
CSV
|
84
|
+
@f = ForeignCSV.new(@csv)
|
85
|
+
@t = @f.tournament
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should have the usual basic details" do
|
89
|
+
@t.name.should == 'Edinburgh Masters, 2007'
|
90
|
+
@t.start.should == '2007-01-03'
|
91
|
+
@t.rounds.should == 2
|
92
|
+
@t.site.should == 'http://www.chesscenter.com/twic/twic.html'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should have the correct number of players" do
|
96
|
+
@t.should have(5).players
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should have correct player details" do
|
100
|
+
check_player(1, 'Gearoidin', 'Ui Laighleis', 2, 2, 1.0, :id => 3364)
|
101
|
+
check_player(4, 'Mark', 'Orr', 2, 2, 1.5, :id => 1350)
|
102
|
+
check_player(2, 'Gary', 'Kasparov', 1, 0, 0.5, :rating => 2800, :fed => 'RUS', :title => 'GM')
|
103
|
+
check_player(3, 'April', 'Cronin', 2, 0, 1.0, :rating => 2005, :fed => 'IRL')
|
104
|
+
check_player(5, 'Bobby', 'Fischer', 1, 0, 0.0, :rating => 2700, :fed => 'USA', :title => 'GM')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "a tournament where someone is both a player and an opponent" do
|
109
|
+
before(:all) do
|
110
|
+
@csv = <<CSV
|
111
|
+
Event,"Bratto Open, 2001"
|
112
|
+
Start,7th March 2001
|
113
|
+
Rounds,2
|
114
|
+
Website,http://www.federscacchi.it/
|
115
|
+
|
116
|
+
Player,3364,Ui Laighleis,Gearoidin
|
117
|
+
1,=,W,Kasparov,Gary,2800,,RUS
|
118
|
+
2,=,B,Orr,Mark,2100,IM,IRL
|
119
|
+
Total,1.0
|
120
|
+
|
121
|
+
Player,1350,Orr,Mark
|
122
|
+
1,=,W,Cronin,April,2005,,IRL
|
123
|
+
2,=,W,Ui Laighleis,Gearoidin,1800,,IRL
|
124
|
+
Total,1.0
|
125
|
+
CSV
|
126
|
+
@f = ForeignCSV.new(@csv)
|
127
|
+
@t = @f.tournament
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should have the usual basic details" do
|
131
|
+
@t.name.should == 'Bratto Open, 2001'
|
132
|
+
@t.start.should == '2001-03-07'
|
133
|
+
@t.rounds.should == 2
|
134
|
+
@t.site.should == 'http://www.federscacchi.it/'
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should have the correct number of players" do
|
138
|
+
@t.should have(4).players
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should have correct player details" do
|
142
|
+
check_player(1, 'Gearoidin', 'Ui Laighleis', 2, 2, 1.0, :rating => 1800, :fed => 'IRL', :id => 3364)
|
143
|
+
check_player(3, 'Mark', 'Orr', 2, 2, 1.0, :rating => 2100, :fed => 'IRL', :id => 1350, :title => 'IM')
|
144
|
+
check_player(2, 'Gary', 'Kasparov', 1, 0, 0.5, :rating => 2800, :fed => 'RUS')
|
145
|
+
check_player(4, 'April', 'Cronin', 1, 0, 0.5, :rating => 2005, :fed => 'IRL')
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "a file that contains spurious white space and other untidiness" do
|
150
|
+
before(:all) do
|
151
|
+
@csv = <<CSV
|
152
|
+
|
153
|
+
Event," Bratto Open, 2001 "
|
154
|
+
Start, 7th March 2001
|
155
|
+
Rounds, 2
|
156
|
+
Website, http://www.federscacchi.it/
|
157
|
+
Player ,3364 , ui Laighleis, gearoidin
|
158
|
+
|
159
|
+
1, = ,W, kasparov, gary, 2800 , g , Rus
|
160
|
+
|
161
|
+
2 ,=, b, Orr , Mark,2100, iM , irl
|
162
|
+
Total,1.0
|
163
|
+
|
164
|
+
CSV
|
165
|
+
@f = ForeignCSV.new(@csv)
|
166
|
+
@t = @f.tournament
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should have the correct basic details" do
|
170
|
+
@t.name.should == 'Bratto Open, 2001'
|
171
|
+
@t.start.should == '2001-03-07'
|
172
|
+
@t.rounds.should == 2
|
173
|
+
@t.site.should == 'http://www.federscacchi.it/'
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should have the correct number of players" do
|
177
|
+
@t.should have(3).players
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should have correct player details" do
|
181
|
+
check_player(1, 'Gearoidin', 'Ui Laighleis', 2, 2, 1.0, :id => 3364)
|
182
|
+
check_player(2, 'Gary', 'Kasparov', 1, 0, 0.5, :rating => 2800, :fed => 'RUS', :title => 'GM')
|
183
|
+
check_player(3, 'Mark', 'Orr', 1, 0, 0.5, :rating => 2100, :fed => 'IRL', :title => 'IM')
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "invalid files" do
|
188
|
+
it "a blank file is invalid" do
|
189
|
+
lambda { ForeignCSV.new(' ') }.should raise_error(/event/i)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "the event should come first" do
|
193
|
+
csv = <<CSV
|
194
|
+
Start,7th March 2001
|
195
|
+
Event,"Bratto Open, 2001"
|
196
|
+
Rounds,2
|
197
|
+
Website,http://www.federscacchi.it/
|
198
|
+
CSV
|
199
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 1.*event/i)
|
200
|
+
end
|
201
|
+
|
202
|
+
it "the start should come second" do
|
203
|
+
csv = <<CSV
|
204
|
+
Event,"Bratto Open, 2001"
|
205
|
+
Rounds,2
|
206
|
+
Start,7th March 2001
|
207
|
+
Website,http://www.federscacchi.it/
|
208
|
+
CSV
|
209
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 2.*start/i)
|
210
|
+
end
|
211
|
+
|
212
|
+
it "the number of rounds should come third" do
|
213
|
+
csv = <<CSV
|
214
|
+
Event,"Bratto Open, 2001"
|
215
|
+
Start,7th March 2001
|
216
|
+
Website,http://www.federscacchi.it/
|
217
|
+
Rounds,2
|
218
|
+
CSV
|
219
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 3.*rounds/i)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "there should be a web site" do
|
223
|
+
csv = <<CSV
|
224
|
+
Event,"Bratto Open, 2001"
|
225
|
+
Start,7th March 2001
|
226
|
+
Rounds,2
|
227
|
+
|
228
|
+
CSV
|
229
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 4.*site/i)
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should have at least one player" do
|
233
|
+
csv = <<CSV
|
234
|
+
Event,"Bratto Open, 2001"
|
235
|
+
Start,7th March 2001
|
236
|
+
Rounds,2
|
237
|
+
Website,http://www.federscacchi.it/
|
238
|
+
CSV
|
239
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 4.*no players/i)
|
240
|
+
end
|
241
|
+
|
242
|
+
it "the player needs to have a valid ID number" do
|
243
|
+
csv = <<CSV
|
244
|
+
Event,"Bratto Open, 2001"
|
245
|
+
Start,7th March 2001
|
246
|
+
Rounds,2
|
247
|
+
Website,http://www.federscacchi.it/
|
248
|
+
|
249
|
+
Player,0,Ui Laighleis,Gearoidin
|
250
|
+
CSV
|
251
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 6.*number/i)
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should have the right number of results for each player" do
|
255
|
+
csv = <<CSV
|
256
|
+
Event,"Bratto Open, 2001"
|
257
|
+
Start,7th March 2001
|
258
|
+
Rounds,2
|
259
|
+
Website,http://www.federscacchi.it/
|
260
|
+
|
261
|
+
Player,3364,Ui Laighleis,Gearoidin
|
262
|
+
1,=,W,Kasparov,Gary,2800,GM,RUS
|
263
|
+
Total,0.5
|
264
|
+
CSV
|
265
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 8.*round/i)
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should have correct totals" do
|
269
|
+
csv = <<CSV
|
270
|
+
Event,"Bratto Open, 2001"
|
271
|
+
Start,7th March 2001
|
272
|
+
Rounds,2
|
273
|
+
Website,http://www.federscacchi.it/
|
274
|
+
|
275
|
+
Player,3364,Ui Laighleis,Gearoidin
|
276
|
+
1,=,W,Kasparov,Gary,2800,GM,RUS
|
277
|
+
2,=,B,Orr,Mark,2100,IM,IRL
|
278
|
+
Total,1.5
|
279
|
+
CSV
|
280
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 9.*total/i)
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
it "players who match by name and federation should match in all other details" do
|
285
|
+
csv = <<CSV
|
286
|
+
Event,"Bratto Open, 2001"
|
287
|
+
Start,7th March 2001
|
288
|
+
Rounds,2
|
289
|
+
Website,http://www.federscacchi.it/
|
290
|
+
|
291
|
+
Player,3364,Ui Laighleis,Gearoidin
|
292
|
+
1,=,W,Kasparov,Gary,2800,GM,RUS
|
293
|
+
2,=,B,Orr,Mark,2100,IM,IRL
|
294
|
+
Total,1.0
|
295
|
+
|
296
|
+
Player,1350,Orr,Mark
|
297
|
+
1,=,W,Fischer,Bobby,2700,,USA
|
298
|
+
2,=,B,Kasparov,Gary,2850,GM,RUS
|
299
|
+
Total,1.0
|
300
|
+
CSV
|
301
|
+
lambda { ForeignCSV.new(csv) }.should raise_error(/line 13.*same name.*conflicting/i)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|