icu_tournament 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,313 @@
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 integer/)
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 positive integer/)
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 == 'IRL'
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('Mark', 'Quinn', 2, :title => 'm').title.should == 'IM'
101
+ Player.new('Pia', 'Cramling', 3, :title => ' wg ').title.should == 'WGM'
102
+ Player.new('Philip', 'Short', 4, :title => 'F ').title.should == 'FM'
103
+ Player.new('Gearoidin', 'Ui Laighleis', 5, :title => 'wc').title.should == 'WCM'
104
+ Player.new('Gearoidin', 'Ui Laighleis', 7, :title => 'wm').title.should == 'WIM'
105
+ Player.new('Eamon', 'Keogh', 6, :title => 'nm').title.should == 'NM'
106
+ lambda { Player.new('Mark', 'Orr', 3, :title => 'Dr') }.should raise_error(/invalid chess title/)
107
+ end
108
+ end
109
+
110
+ context "rating" do
111
+ it "defaults to nil" do
112
+ Player.new('Mark', 'Orr', 3).rating.should be_nil
113
+ Player.new('Mark', 'Orr', 3, :rating => ' ').rating.should be_nil
114
+ end
115
+
116
+ it "should be a positive integer" do
117
+ Player.new('Gary', 'Kasparov', 1, :rating => 2800).rating.should == 2800
118
+ Player.new('Mark', 'Orr', 2, :rating => ' 2100 ').rating.should == 2100
119
+ lambda { Player.new('Mark', 'Orr', 3, :rating => -2100) }.should raise_error(/invalid positive integer/)
120
+ lambda { Player.new('Mark', 'Orr', 3, :rating => 'IM') }.should raise_error(/invalid positive integer/)
121
+ end
122
+ end
123
+
124
+ context "rank" do
125
+ it "defaults to nil" do
126
+ Player.new('Mark', 'Orr', 3).rank.should be_nil
127
+ end
128
+
129
+ it "should be a positive integer" do
130
+ Player.new('Mark', 'Orr', 3, :rank => 1).rank.should == 1
131
+ Player.new('Gary', 'Kasparov', 4, :rank => ' 29 ').rank.should == 29
132
+ lambda { Player.new('Mark', 'Orr', 3, :rank => 0) }.should raise_error(/invalid positive integer/)
133
+ lambda { Player.new('Mark', 'Orr', 3, :rank => ' -1 ') }.should raise_error(/invalid positive integer/)
134
+ end
135
+ end
136
+
137
+ context "date of birth" do
138
+ it "defaults to nil" do
139
+ Player.new('Mark', 'Orr', 3).dob.should be_nil
140
+ Player.new('Mark', 'Orr', 3, :dob => ' ').dob.should be_nil
141
+ end
142
+
143
+ it "should be a yyyy-mm-dd date" do
144
+ Player.new('Mark', 'Orr', 3, :dob => '1955-11-09').dob.should == '1955-11-09'
145
+ lambda { Player.new('Mark', 'Orr', 3, :dob => 'X') }.should raise_error(/invalid.*dob/)
146
+ end
147
+ end
148
+
149
+ context "gender" do
150
+ it "defaults to nil" do
151
+ Player.new('Mark', 'Orr', 3).gender.should be_nil
152
+ Player.new('Mark', 'Orr', 3, :gender => ' ').gender.should be_nil
153
+ end
154
+
155
+ it "should be either M or F" do
156
+ Player.new('Mark', 'Orr', 3, :gender => 'male').gender.should == 'M'
157
+ Player.new('April', 'Cronin', 3, :gender => 'woman').gender.should == 'F'
158
+ end
159
+
160
+ it "should raise an exception if the gender is not specified properly" do
161
+ lambda { Player.new('Mark', 'Orr', 3, :gender => 'X') }.should raise_error(/invalid gender/)
162
+ end
163
+ end
164
+
165
+ context "results and points" do
166
+ it "should initialise to an empty array" do
167
+ results = Player.new('Mark', 'Orr', 3).results
168
+ results.should be_instance_of Array
169
+ results.size.should == 0
170
+ end
171
+
172
+ it "can be added to" do
173
+ player = Player.new('Mark', 'Orr', 3)
174
+ player.add_result(Result.new(1, 3, 'W', :opponent => 1))
175
+ player.add_result(Result.new(2, 3, 'D', :opponent => 2))
176
+ player.add_result(Result.new(3, 3, 'L', :opponent => 4))
177
+ results = player.results
178
+ results.should be_instance_of Array
179
+ results.size.should == 3
180
+ player.points.should == 1.5
181
+ end
182
+
183
+ it "should not allow mismatched player numbers" do
184
+ player = Player.new('Mark', 'Orr', 3)
185
+ lambda { player.add_result(Result.new(1, 4, 'W', :opponent => 1)) }.should raise_error(/player number .* matched/)
186
+ end
187
+
188
+ it "should enforce unique round numbers" do
189
+ player = Player.new('Mark', 'Orr', 3)
190
+ player.add_result(Result.new(1, 3, 'W', :opponent => 1))
191
+ player.add_result(Result.new(2, 3, 'D', :opponent => 2))
192
+ lambda { player.add_result(Result.new(2, 3, 'L', :opponent => 4)) }.should raise_error(/round number .* unique/)
193
+ end
194
+ end
195
+
196
+ context "looking up results" do
197
+ before(:all) do
198
+ @p = Player.new('Mark', 'Orr', 1)
199
+ @p.add_result(Result.new(1, 1, 'W', :opponent => 37, :score => 'W', :colour => 'W'))
200
+ @p.add_result(Result.new(2, 1, 'W', :opponent => 13, :score => 'W', :colour => 'B'))
201
+ @p.add_result(Result.new(3, 1, 'W', :opponent => 7, :score => 'D', :colour => 'W'))
202
+ end
203
+
204
+ it "should find results by round number" do
205
+ @p.find_result(1).opponent.should == 37
206
+ @p.find_result(2).opponent.should == 13
207
+ @p.find_result(3).opponent.should == 7
208
+ @p.find_result(4).should be_nil
209
+ end
210
+ end
211
+
212
+ context "merge" do
213
+ before(:each) do
214
+ @p1 = Player.new('Mark', 'Orr', 1, :id => 1350)
215
+ @p2 = Player.new('Mark', 'Orr', 2, :rating => 2100, :title => 'IM', :fed => 'IRL')
216
+ @p3 = Player.new('Gearoidin', 'Ui Laighleis', 3, :rating => 1600, :title => 'WIM', :fed => 'IRL')
217
+ end
218
+
219
+ it "takes on the ID, rating, title and fed of the other player but not the player number" do
220
+ @p1.merge(@p2)
221
+ @p1.num.should == 1
222
+ @p1.id.should == 1350
223
+ @p1.rating.should == 2100
224
+ @p1.title.should == 'IM'
225
+ @p1.fed.should == 'IRL'
226
+ end
227
+
228
+ it "should have a kind of symmetry" do
229
+ p1 = @p1.dup
230
+ p2 = @p2.dup
231
+ p1.merge(p2).eql?(@p2.merge(@p1))
232
+ end
233
+
234
+ it "cannot be done with unequal objects" do
235
+ lambda { @p1.merge(@p3) }.should raise_error(/cannot merge.*not equal/)
236
+ end
237
+ end
238
+
239
+ context "renumber the player numbers" do
240
+ before(:each) do
241
+ @p = Player.new('Mark', 'Orr', 10)
242
+ @p.add_result(Result.new(1, 10, 'W', :opponent => 20))
243
+ @p.add_result(Result.new(2, 10, 'W', :opponent => 30))
244
+ end
245
+
246
+ it "should renumber successfully if the map has the relevant player numbers" do
247
+ map = { 10 => 1, 20 => 2, 30 => 3 }
248
+ @p.renumber(map).num.should == 1
249
+ @p.results.map{ |r| r.opponent }.sort.join('').should == '23'
250
+ end
251
+
252
+ it "should raise exception if a player number is not in the map" do
253
+ lambda { @p.renumber({ 100 => 1, 20 => 2, 30 => 3 }) }.should raise_error(/player.*10.*not found/)
254
+ lambda { @p.renumber({ 10 => 1, 200 => 2, 30 => 3 }) }.should raise_error(/opponent.*20.*not found/)
255
+ end
256
+ end
257
+
258
+ context "loose equality" do
259
+ before(:all) do
260
+ @mark1 = Player.new('Mark', 'Orr', 1)
261
+ @mark2 = Player.new('Mark', 'Orr', 2, :fed => 'IRL')
262
+ @mark3 = Player.new('Mark', 'Orr', 3, :fed => 'USA')
263
+ @mark4 = Player.new('Mark', 'Sax', 4, :def => 'HUN')
264
+ @john1 = Player.new('John', 'Orr', 5, :fed => 'IRL')
265
+ end
266
+
267
+ it "any player is equal to itself" do
268
+ (@mark1 == @mark1).should be_true
269
+ end
270
+
271
+ it "two players are equal if their names are the same and their federations do not conflict" do
272
+ (@mark1 == @mark2).should be_true
273
+ end
274
+
275
+ it "two players cannot be equal if they have different names" do
276
+ (@mark1 == @mark4).should be_false
277
+ (@mark1 == @john1).should be_false
278
+ end
279
+
280
+ it "two players cannot be equal if they have different federations" do
281
+ (@mark2 == @mark3).should be_false
282
+ (@mark1 == @mark3).should be_true
283
+ end
284
+ end
285
+
286
+ context "strict equality" do
287
+ before(:all) do
288
+ @mark1 = Player.new('Mark', 'Orr', 1)
289
+ @mark2 = Player.new('Mark', 'Orr', 2, :id => 1350, :rating => 2100, :title => 'IM')
290
+ @mark3 = Player.new('Mark', 'Orr', 3, :id => 1530)
291
+ @mark4 = Player.new('Mark', 'Orr', 4, :rating => 2200)
292
+ @mark5 = Player.new('Mark', 'Orr', 5, :title => 'GM')
293
+ end
294
+
295
+ it "any player is equal to itself" do
296
+ @mark1.eql?(@mark1).should be_true
297
+ @mark1.eql?(@mark1).should be_true
298
+ end
299
+
300
+ it "two players are equal as long as their ID, rating and title do not conflict" do
301
+ @mark1.eql?(@mark2).should be_true
302
+ @mark3.eql?(@mark4).should be_true
303
+ @mark4.eql?(@mark5).should be_true
304
+ end
305
+
306
+ it "two players are not equal if their ID, rating or title conflict" do
307
+ @mark2.eql?(@mark3).should be_false
308
+ @mark2.eql?(@mark4).should be_false
309
+ @mark2.eql?(@mark5).should be_false
310
+ end
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,203 @@
1
+ # encoding: utf-8
2
+
3
+ require File.dirname(__FILE__) + '/spec_helper'
4
+
5
+ module ICU
6
+ describe Result do
7
+ context "a typical result" do
8
+ it "should have a round, player number and score plus optional opponent number, colour and rateable flag" do
9
+ lambda { Result.new(3, 5, 'W', :opponent => 11, :colour => 'W') }.should_not raise_error
10
+ end
11
+ end
12
+
13
+ context "round number" do
14
+ it "should be a positive integer" do
15
+ lambda { Result.new(-2, 2, 0) }.should raise_error(/invalid positive integer/)
16
+ lambda { Result.new(0, 2, 0) }.should raise_error(/invalid positive integer/)
17
+ Result.new(1, 2, 0).round.should == 1
18
+ Result.new(' 3 ', 2, 0).round.should == 3
19
+ end
20
+ end
21
+
22
+ context "player number" do
23
+ it "should be an integer" do
24
+ lambda { Result.new(1, ' ', 0) }.should raise_error(/invalid integer/)
25
+ Result.new(1, 2, 0).player.should == 2
26
+ Result.new(1, ' 0 ', 0).player.should == 0
27
+ Result.new(1, -5, 0).player.should == -5
28
+ Result.new(1, " 9 ", 0).player.should == 9
29
+ end
30
+ end
31
+
32
+ context "score" do
33
+ [1, 1.0, 'W', 'w', '+'].each do |score|
34
+ it "should be 'W' for #{score}, #{score.class}" do
35
+ Result.new(1, 2, score).score.should == 'W'
36
+ end
37
+ end
38
+ [0, 0.0, 'L', 'l', '-'].each do |score|
39
+ it "should be 'L' for #{score}, #{score.class}" do
40
+ Result.new(1, 2, score).score.should == 'L'
41
+ end
42
+ end
43
+ ['½', 0.5, 'D', 'd', '='].each do |score|
44
+ it "should be 'L' for #{score}, #{score.class}" do
45
+ Result.new(1, 2, score).score.should == 'D'
46
+ end
47
+ end
48
+ ['', ' ', 'x', 2, -1.0, nil].each do |score|
49
+ it "should raise error for invalid score (#{score})" do
50
+ lambda { Result.new(1, 2, score) }.should raise_error(/invalid score/)
51
+ end
52
+ end
53
+ it "should be expressable as a number" do
54
+ Result.new(1, 2, 'W').points.should == 1.0
55
+ Result.new(1, 2, 'L').points.should == 0.0
56
+ Result.new(1, 2, 'D').points.should == 0.5
57
+ end
58
+ end
59
+
60
+ context "colour" do
61
+ it "should be 'W' or 'B' or nil (unknown)" do
62
+ Result.new(4, 1, 0).colour.should be_nil
63
+ Result.new(4, 1, 0, :colour => 'W').colour.should == 'W'
64
+ Result.new(4, 1, 0, :colour => 'white').colour.should == 'W'
65
+ Result.new(4, 1, 0, :colour => ' b ').colour.should == 'B'
66
+ Result.new(4, 1, 0, :colour => ' BLACK ').colour.should == 'B'
67
+ lambda { Result.new(4, 1, 0, :colour => 'red') }.should raise_error(/invalid colour/)
68
+ end
69
+ end
70
+
71
+ context "opponent number" do
72
+ it "should be nil (the default) or an integer" do
73
+ Result.new(4, 1, 0).opponent.should be_nil
74
+ Result.new(4, 1, 0, :opponent => nil).opponent.should be_nil
75
+ Result.new(4, 1, 0, :opponent => ' ').opponent.should be_nil
76
+ Result.new(4, 1, 0, :opponent => 0).opponent.should == 0
77
+ Result.new(4, 1, 0, :opponent => 2).opponent.should == 2
78
+ Result.new(4, 1, 0, :opponent => -6).opponent.should == -6
79
+ Result.new(4, 1, 0, :opponent => ' 10 ').opponent.should == 10
80
+ lambda { Result.new(4, 1, 0, :opponent => 'X') }.should raise_error(/invalid opponent number/)
81
+ end
82
+
83
+ it "should be different to player number" do
84
+ lambda { Result.new(4, 1, 0, :opponent => 1) }.should raise_error(/opponent .* player .* different/)
85
+ end
86
+ end
87
+
88
+ context "rateable flag" do
89
+ it "should default to false if there is no opponent" do
90
+ Result.new(4, 1, 0).rateable.should be_false
91
+ end
92
+
93
+ it "should default to true if there is an opponent" do
94
+ Result.new(4, 1, 0, :opponent => 10).rateable.should be_true
95
+ end
96
+
97
+ it "should change if an opponent is added" do
98
+ r = Result.new(4, 1, 0)
99
+ r.opponent = 5;
100
+ r.rateable.should be_true
101
+ end
102
+
103
+ it "should be settable to false from the constructor" do
104
+ Result.new(4, 1, 0, :opponent => 10, :rateable => false).rateable.should be_false
105
+ end
106
+
107
+ it "should be settable to false using the accessor" do
108
+ r = Result.new(4, 1, 0, :opponent => 10)
109
+ r.rateable= false
110
+ r.rateable.should be_false
111
+ end
112
+
113
+ it "should not be settable to true if there is no opponent" do
114
+ r = Result.new(4, 1, 0)
115
+ r.rateable= true
116
+ r.rateable.should be_false
117
+ end
118
+ end
119
+
120
+ context "reversed result" do
121
+ it "should be nil if there is no opponent" do
122
+ Result.new(4, 1, 0).reverse.should be_nil
123
+ end
124
+
125
+ it "should have player and opponent swapped" do
126
+ r = Result.new(4, 1, 0, :opponent => 2).reverse
127
+ r.player.should == 2
128
+ r.opponent.should == 1
129
+ end
130
+
131
+ it "should have reversed result" do
132
+ Result.new(4, 1, 0, :opponent => 2).reverse.score.should == 'W'
133
+ Result.new(4, 1, 1, :opponent => 2).reverse.score.should == 'L'
134
+ Result.new(4, 1, '=', :opponent => 2).reverse.score.should == 'D'
135
+ end
136
+
137
+ it "should preserve rateability" do
138
+ Result.new(4, 1, 0, :opponent => 2).reverse.rateable.should be_true
139
+ Result.new(4, 1, 0, :opponent => 2, :rateable => false).reverse.rateable.should be_false
140
+ end
141
+ end
142
+
143
+ context "renumber the player numbers in a result" do
144
+ before(:each) do
145
+ @r1 = Result.new(1, 4, 0)
146
+ @r2 = Result.new(2, 3, 1, :opponent => 4, :color => 'B')
147
+ end
148
+
149
+ it "should renumber successfully if the map has the relevant player numbers" do
150
+ map = { 4 => 1, 3 => 2 }
151
+ @r1.renumber(map).player.should == 1
152
+ @r2.renumber(map).player.should == 2
153
+ @r1.opponent.should be_nil
154
+ @r2.opponent.should == 1
155
+ end
156
+
157
+ it "should raise exception if a player number is not in the map" do
158
+ lambda { @r1.renumber({ 5 => 1, 3 => 2 }) }.should raise_error(/player.*4.*not found/)
159
+ end
160
+ end
161
+
162
+ context "loose equality" do
163
+ before(:each) do
164
+ @r1 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
165
+ @r2 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
166
+ @r3 = Result.new(2, 1, 0, :opponent => 2, :colour => 'W')
167
+ @r4 = Result.new(1, 3, 0, :opponent => 2, :colour => 'W')
168
+ @r5 = Result.new(1, 1, 1, :opponent => 2, :colour => 'W')
169
+ @r6 = Result.new(1, 1, 0, :opponent => 3, :colour => 'W')
170
+ @r7 = Result.new(1, 1, 0, :opponent => 2, :colour => 'B')
171
+ end
172
+
173
+ it "should be equal if the round, player numbers, result and colour all match" do
174
+ (@r1 == @r1).should be_true
175
+ (@r1 == @r2).should be_true
176
+ end
177
+
178
+ it "should not be equal if the round, player numbers, result or colour do not match" do
179
+ (@r1 == @r3).should be_false
180
+ (@r1 == @r4).should be_false
181
+ (@r1 == @r5).should be_false
182
+ (@r1 == @r6).should be_false
183
+ (@r1 == @r7).should be_false
184
+ end
185
+ end
186
+
187
+ context "strict equality" do
188
+ before(:each) do
189
+ @r1 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
190
+ @r2 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W')
191
+ @r3 = Result.new(1, 1, 0, :opponent => 2, :colour => 'W', :rateable => false)
192
+ @r4 = Result.new(2, 1, 0, :opponent => 2, :colour => 'W')
193
+ end
194
+
195
+ it "should only be equal if everything is the same" do
196
+ @r1.eql?(@r1).should be_true
197
+ @r1.eql?(@r2).should be_true
198
+ @r1.eql?(@r3).should be_false
199
+ @r1.eql?(@r4).should be_false
200
+ end
201
+ end
202
+ end
203
+ end