sanichi-chess_icu 0.1.0
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/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
|