1import unittest
2
3import solution
4
5
6class TestSanity(unittest.TestCase):
7 """Check if all data is present."""
8
9 def test_requirements(self):
10 names = ["Egg", "EggTournament"]
11 unimported = [name for name in names if name not in dir(solution)]
12 self.assertEqual(
13 unimported, [], "\n\nЕлементите по-горе липсват (проверете си имената)!"
14 )
15
16
17if __name__ == "__main__":
18 unittest.main()
1import unittest
2
3from solution import *
4
5
6class EggTestCase(unittest.TestCase):
7 def make_egg(self, *paint_chunks):
8 egg = Egg()
9
10 if paint_chunks:
11 egg.paint(*paint_chunks)
12
13 return egg
14
15 def make_tournament(self, **named_eggs):
16 tournament = EggTournament()
17
18 for name, egg in named_eggs.items():
19 tournament.register(egg, name)
20
21 return tournament
22
23
24class TestEgg(EggTestCase):
25 def test_paint_single_color_full_egg(self):
26 """A fully painted single-color egg should win collisions against a weaker egg from both sides."""
27 egg = self.make_egg(("FFFFFF", 100.0))
28 opponent = self.make_egg(("FF0000", 100.0))
29
30 self.assertIs(egg * opponent, egg)
31 self.assertIs(egg @ opponent, egg)
32
33 def test_paint_exactly_to_100_percent_is_allowed(self):
34 """Painting an egg exactly to 100 percent should not raise an error."""
35 egg = Egg()
36 egg.paint(("FF0000", 99.0))
37 egg.paint(("FFFFFF", 1.0))
38
39 opponent = self.make_egg(("000000", 100.0))
40
41 self.assertIs(egg @ opponent, egg)
42
43 def test_paint_can_be_called_multiple_times(self):
44 """Painting an egg in multiple calls should preserve the full painting order."""
45 egg = Egg()
46 egg.paint(("FFFFFF", 25.0))
47 egg.paint(("FFFFFF", 25.0))
48 egg.paint(("FF0000", 25.0))
49 egg.paint(("FF0000", 25.0))
50
51 top_opponent = self.make_egg(("00FF00", 100.0))
52 bottom_opponent = self.make_egg(("010000", 100.0))
53
54 self.assertIs(egg * top_opponent, egg)
55 self.assertIs(egg @ bottom_opponent, egg)
56
57 def test_paint_overflow_above_100_raises_value_error(self):
58 """Painting an egg above 100 percent should raise a ValueError."""
59 egg = Egg()
60
61 with self.assertRaises(ValueError):
62 egg.paint(("FFFFFF", 100.1))
63
64 def test_paint_overflow_from_existing_fill_raises_value_error(self):
65 """Painting an already partially painted egg above 100 percent should raise a ValueError."""
66 egg = Egg()
67 egg.paint(("FFFFFF", 99.0))
68
69 with self.assertRaises(ValueError):
70 egg.paint(("000000", 1.001))
71
72 def test_paint_overflow_with_multiple_colors_raises_value_error(self):
73 """Painting an egg with multiple new colors whose total overflows 100 percent should raise a ValueError."""
74 egg = Egg()
75 egg.paint(("FFFFFF", 70.0))
76
77 with self.assertRaises(ValueError):
78 egg.paint(("FF0000", 20.0), ("00FF00", 15.0))
79
80 def test_failed_paint_overflow_does_not_change_egg_state(self):
81 """Failing to paint an egg because of overflow should not change its state."""
82 reference_egg = self.make_egg(("FFFFFF", 50.0))
83 tested_egg = self.make_egg(("FFFFFF", 50.0))
84
85 with self.assertRaises(ValueError):
86 tested_egg.paint(("000000", 60.0))
87
88 reference_top_opponent = self.make_egg(("FFFFFE", 50.0))
89 tested_top_opponent = self.make_egg(("FFFFFE", 50.0))
90
91 self.assertIs(reference_egg * reference_top_opponent, reference_egg)
92 self.assertIs(tested_egg * tested_top_opponent, tested_egg)
93
94 reference_bottom_opponent = self.make_egg(("010000", 100.0))
95 tested_bottom_opponent = self.make_egg(("010000", 100.0))
96
97 self.assertIs(reference_egg @ reference_bottom_opponent, reference_bottom_opponent)
98 self.assertIs(tested_egg @ tested_bottom_opponent, tested_bottom_opponent)
99
100 def test_paint_is_case_insensitive_for_hex_colors(self):
101 """Painting an egg with lowercase and uppercase hex colors should produce the same behavior."""
102 lower_case_egg = self.make_egg(("aabbcc", 100.0))
103 upper_case_egg = self.make_egg(("AABBCC", 100.0))
104
105 lower_case_top_opponent = self.make_egg(("AABBCA", 100.0))
106 upper_case_top_opponent = self.make_egg(("AABBCA", 100.0))
107
108 lower_case_bottom_opponent = self.make_egg(("AABBCA", 100.0))
109 upper_case_bottom_opponent = self.make_egg(("AABBCA", 100.0))
110
111 self.assertIs(lower_case_egg * lower_case_top_opponent, lower_case_egg)
112 self.assertIs(upper_case_egg * upper_case_top_opponent, upper_case_egg)
113
114 self.assertIs(lower_case_egg @ lower_case_bottom_opponent, lower_case_egg)
115 self.assertIs(upper_case_egg @ upper_case_bottom_opponent, upper_case_egg)
116
117 def test_paint_order_of_color_chunks_matters(self):
118 """Painting the same colors in different orders should change the collision result."""
119 first_egg = self.make_egg(("FFFFFF", 50.0), ("000000", 50.0))
120 second_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
121
122 self.assertIs(first_egg * second_egg, first_egg)
123 self.assertIs(first_egg @ second_egg, second_egg)
124
125 def test_paint_boundary_exactly_at_50_percent(self):
126 """Painting an egg exactly to the half boundary should keep the two halves separate."""
127 egg = self.make_egg(("FFFFFF", 50.0), ("000000", 50.0))
128 opponent = self.make_egg(("FF0000", 100.0))
129
130 self.assertIs(egg * opponent, egg)
131 self.assertIs(egg @ opponent, opponent)
132
133 def test_paint_chunk_crossing_50_percent_boundary_is_split_correctly(self):
134 """Painting a chunk across the half boundary should split it correctly between the two halves."""
135 egg = self.make_egg(("FFFFFF", 40.0), ("000000", 20.0), ("FF0000", 40.0))
136 opponent = self.make_egg(("DC0000", 100.0))
137
138 self.assertIs(egg * opponent, egg)
139 self.assertIs(egg @ opponent, opponent)
140
141 def test_paint_multiple_calls_can_cross_50_percent_boundary(self):
142 """Painting an egg across the half boundary in multiple calls should split the halves correctly."""
143 egg = Egg()
144 egg.paint(("FFFFFF", 40.0))
145 egg.paint(("000000", 20.0))
146 egg.paint(("FF0000", 40.0))
147
148 opponent = self.make_egg(("DC0000", 100.0))
149
150 self.assertIs(egg * opponent, egg)
151 self.assertIs(egg @ opponent, opponent)
152
153 def test_paint_overflow_with_multiple_colors_should_not_change_the_egg(self):
154 """Failing to overpaint an egg with multiple colors should not change the egg."""
155 egg = Egg()
156 egg.paint(("FFFFFF", 60.0))
157
158 with self.assertRaises(ValueError):
159 egg.paint(("00FF00", 20.0), ("0000FF", 30.0))
160
161 bottom_opponent = self.make_egg(("C80000", 100.0))
162
163 self.assertIs(egg @ bottom_opponent, bottom_opponent)
164
165 def test_top_collision_returns_egg_with_greater_top_strength(self):
166 """A top collision should return the egg with the greater top strength."""
167 stronger_egg = self.make_egg(("FFFFFF", 100.0))
168 weaker_egg = self.make_egg(("FF0000", 100.0))
169
170 self.assertIs(stronger_egg * weaker_egg, stronger_egg)
171
172 def test_bottom_collision_returns_egg_with_greater_bottom_strength(self):
173 """A bottom collision should return the egg with the greater bottom strength."""
174 stronger_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
175 weaker_egg = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
176
177 self.assertIs(stronger_egg @ weaker_egg, stronger_egg)
178
179 def test_same_two_eggs_can_have_different_winners_for_top_and_bottom(self):
180 """The same two eggs should be able to have different winners for top and bottom collisions."""
181 first_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
182 second_egg = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
183
184 self.assertIs(first_egg * second_egg, second_egg)
185 self.assertIs(first_egg @ second_egg, first_egg)
186
187 def test_collision_with_partially_painted_eggs(self):
188 """Partially painted eggs should collide correctly from both sides."""
189 first_egg = self.make_egg(("FFFFFF", 25.0), ("FF0000", 25.0))
190 second_egg = self.make_egg(("AA0000", 25.0), ("AA0000", 25.0), ("FFFFFF", 25.0))
191
192 self.assertIs(first_egg * second_egg, first_egg)
193 self.assertIs(first_egg @ second_egg, second_egg)
194
195 def test_unpainted_half_loses_to_half_painted_black(self):
196 """An unpainted half should lose to a half painted in black."""
197 unpainted_egg = Egg()
198 black_egg = self.make_egg(("000000", 50.0))
199
200 self.assertIs(unpainted_egg * black_egg, black_egg)
201
202 unpainted_egg = Egg()
203 black_egg = self.make_egg(("000000", 50.0))
204
205 self.assertIs(black_egg * unpainted_egg, black_egg)
206
207 def test_collision_result_is_independent_of_operand_order(self):
208 """Swapping the egg operands should not change the collision winner."""
209 top_first_egg = self.make_egg(("FFFFFF", 100.0))
210 top_second_egg = self.make_egg(("FF0000", 100.0))
211
212 self.assertIs(top_first_egg * top_second_egg, top_first_egg)
213
214 reversed_top_first_egg = self.make_egg(("FFFFFF", 100.0))
215 reversed_top_second_egg = self.make_egg(("FF0000", 100.0))
216
217 self.assertIs(reversed_top_second_egg * reversed_top_first_egg, reversed_top_first_egg)
218
219 bottom_first_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
220 bottom_second_egg = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
221
222 self.assertIs(bottom_first_egg @ bottom_second_egg, bottom_first_egg)
223
224 reversed_bottom_first_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
225 reversed_bottom_second_egg = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
226
227 self.assertIs(
228 reversed_bottom_second_egg @ reversed_bottom_first_egg,
229 reversed_bottom_first_egg,
230 )
231
232 def test_losing_side_becomes_unusable(self):
233 """Losing a collision should make the losing side unusable."""
234 top_loser = self.make_egg(("000000", 100.0))
235 top_winner = self.make_egg(("FFFFFF", 100.0))
236 top_opponent = self.make_egg(("FFFFFF", 100.0))
237
238 self.assertIs(top_loser * top_winner, top_winner)
239
240 with self.assertRaises(TypeError):
241 top_loser * top_opponent
242
243 bottom_loser = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
244 bottom_winner = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
245 bottom_opponent = self.make_egg(("000000", 100.0))
246
247 self.assertIs(bottom_loser @ bottom_winner, bottom_winner)
248
249 with self.assertRaises(TypeError):
250 bottom_loser @ bottom_opponent
251
252 def test_broken_side_raises_type_error_regardless_of_operand_position(self):
253 """Using a broken side in a collision should raise a TypeError regardless of operand position."""
254 broken_top_egg = self.make_egg(("000000", 100.0))
255 top_winner = self.make_egg(("FFFFFF", 100.0))
256
257 self.assertIs(broken_top_egg * top_winner, top_winner)
258
259 left_top_opponent = self.make_egg(("FFFFFF", 100.0))
260 right_top_opponent = self.make_egg(("FFFFFF", 100.0))
261
262 with self.assertRaises(TypeError):
263 broken_top_egg * left_top_opponent
264
265 with self.assertRaises(TypeError):
266 right_top_opponent * broken_top_egg
267
268 broken_bottom_egg = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
269 bottom_winner = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
270
271 self.assertIs(broken_bottom_egg @ bottom_winner, bottom_winner)
272
273 left_bottom_opponent = self.make_egg(("FFFFFF", 100.0))
274 right_bottom_opponent = self.make_egg(("FFFFFF", 100.0))
275
276 with self.assertRaises(TypeError):
277 broken_bottom_egg @ left_bottom_opponent
278
279 with self.assertRaises(TypeError):
280 right_bottom_opponent @ broken_bottom_egg
281
282 def test_breaking_one_side_does_not_prevent_using_the_other_side(self):
283 """Breaking one side of an egg should not prevent using the other side."""
284 first_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
285 second_egg = self.make_egg(("FFFFFF", 50.0), ("000000", 50.0))
286
287 self.assertIs(first_egg * second_egg, second_egg)
288 self.assertIs(first_egg @ second_egg, first_egg)
289
290 third_egg = self.make_egg(("FFFFFF", 50.0), ("000000", 50.0))
291 fourth_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
292
293 self.assertIs(third_egg @ fourth_egg, fourth_egg)
294 self.assertIs(third_egg * fourth_egg, third_egg)
295
296 def test_winner_side_does_not_become_broken(self):
297 """Winning a collision should not break the winning side."""
298 winner_egg = self.make_egg(("FFFFFF", 100.0))
299 first_loser = self.make_egg(("000000", 100.0))
300 second_loser = self.make_egg(("FF0000", 100.0))
301
302 self.assertIs(winner_egg * first_loser, winner_egg)
303 self.assertIs(winner_egg * second_loser, winner_egg)
304
305
306class TestEggTournament(EggTestCase):
307 def test_register_invalid_name_raises_value_error(self):
308 """Registering an egg with an invalid name should raise a ValueError."""
309 tournament = EggTournament()
310 egg = Egg()
311
312 with self.assertRaises(ValueError) as context:
313 tournament.register(egg, "123egg")
314
315 self.assertEqual(str(context.exception), "Invalid registration name")
316
317 def test_register_duplicate_name_raises_value_error(self):
318 """Registering an egg with a duplicate name should raise a ValueError."""
319 tournament = EggTournament()
320 first_egg = Egg()
321 second_egg = Egg()
322
323 tournament.register(first_egg, "the_monster")
324
325 with self.assertRaises(ValueError) as context:
326 tournament.register(second_egg, "the_monster")
327
328 self.assertEqual(
329 str(context.exception),
330 "Egg with name the_monster has already been registered",
331 )
332
333 def test_egg_cannot_be_registered_in_second_tournament(self):
334 """Registering an egg in a second tournament should raise a ValueError."""
335 first_tournament = EggTournament()
336 second_tournament = EggTournament()
337 egg = Egg()
338
339 first_tournament.register(egg, "the_monster")
340
341 with self.assertRaises(ValueError) as context:
342 second_tournament.register(egg, "the_monster_again")
343
344 self.assertEqual(
345 str(context.exception),
346 "An egg cannot be registered in multiple tournaments",
347 )
348
349 def test_failed_registration_in_second_tournament_does_not_remove_first_registration(
350 self,
351 ):
352 """Failing to register an egg in a second tournament should not remove its first registration."""
353 first_tournament = EggTournament()
354 second_tournament = EggTournament()
355 egg = Egg()
356
357 first_tournament.register(egg, "the_monster")
358
359 with self.assertRaises(ValueError):
360 second_tournament.register(egg, "the_monster_again")
361
362 self.assertIn(egg, first_tournament)
363 self.assertNotIn(egg, second_tournament)
364
365 def test_collision_between_two_registered_eggs_is_recorded(self):
366 """A collision between two registered eggs should be recorded in the tournament."""
367 first_egg = self.make_egg(("FFFFFF", 100.0))
368 second_egg = self.make_egg(("000000", 100.0))
369 tournament = self.make_tournament(first_egg=first_egg, second_egg=second_egg)
370
371 self.assertIs(first_egg * second_egg, first_egg)
372 self.assertIs(tournament[first_egg, second_egg, "top"], first_egg)
373 self.assertIs(1 @ tournament, first_egg)
374
375 def test_collision_between_unregistered_eggs_is_not_recorded(self):
376 """A collision between unregistered eggs should not be recorded in the tournament."""
377 tournament = EggTournament()
378 first_egg = self.make_egg(("FFFFFF", 100.0))
379 second_egg = self.make_egg(("000000", 100.0))
380
381 self.assertIs(first_egg * second_egg, first_egg)
382
383 with self.assertRaises(KeyError):
384 _ = tournament[first_egg, second_egg, "top"]
385
386 def test_collision_between_registered_and_unregistered_egg_is_not_recorded(self):
387 """A collision between a registered and an unregistered egg should not be recorded in the tournament."""
388 registered_egg = self.make_egg(("FFFFFF", 100.0))
389 unregistered_egg = self.make_egg(("000000", 100.0))
390 tournament = self.make_tournament(registered_egg=registered_egg)
391
392 self.assertIs(registered_egg * unregistered_egg, registered_egg)
393
394 with self.assertRaises(KeyError):
395 _ = tournament[registered_egg, unregistered_egg, "top"]
396
397 def test_egg_broken_outside_tournament_remains_broken_inside_tournament(self):
398 """Breaking an egg outside the tournament should preserve its broken state inside the tournament."""
399 broken_egg = self.make_egg(("000000", 100.0))
400 tournament_opponent = self.make_egg(("FFFFFF", 100.0))
401 outsider = self.make_egg(("FFFFFF", 100.0))
402 tournament = self.make_tournament(broken_egg=broken_egg, tournament_opponent=tournament_opponent)
403
404 self.assertIs(broken_egg * outsider, outsider)
405
406 with self.assertRaises(TypeError):
407 broken_egg * tournament_opponent
408
409 def test_history_lookup_returns_winner_for_top_and_bottom(self):
410 """Looking up recorded top and bottom collisions should return the correct winners."""
411 first_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
412 second_egg = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
413 tournament = self.make_tournament(first_egg=first_egg, second_egg=second_egg)
414
415 self.assertIs(first_egg * second_egg, second_egg)
416 self.assertIs(first_egg @ second_egg, first_egg)
417
418 self.assertIs(tournament[first_egg, second_egg, "top"], second_egg)
419 self.assertIs(tournament[first_egg, second_egg, "bottom"], first_egg)
420
421 def test_history_lookup_with_tuple_key(self):
422 """Looking up a recorded collision with a tuple key should return the winner."""
423 first_egg = self.make_egg(("FFFFFF", 100.0))
424 second_egg = self.make_egg(("000000", 100.0))
425 tournament = self.make_tournament(first_egg=first_egg, second_egg=second_egg)
426
427 self.assertIs(first_egg * second_egg, first_egg)
428 self.assertIs(tournament[first_egg, second_egg, "top"], first_egg)
429
430 def test_history_lookup_with_slice_key(self):
431 """Looking up a recorded collision with a slice key should return the winner."""
432 first_egg = self.make_egg(("FFFFFF", 100.0))
433 second_egg = self.make_egg(("000000", 100.0))
434 tournament = self.make_tournament(first_egg=first_egg, second_egg=second_egg)
435
436 self.assertIs(first_egg * second_egg, first_egg)
437 self.assertIs(tournament[first_egg:second_egg:"top"], first_egg)
438
439 def test_history_lookup_is_symmetric_with_respect_to_egg_order(self):
440 """Looking up a recorded collision in reversed egg order should return the same winner."""
441 first_egg = self.make_egg(("FFFFFF", 100.0))
442 second_egg = self.make_egg(("000000", 100.0))
443 tournament = self.make_tournament(first_egg=first_egg, second_egg=second_egg)
444
445 self.assertIs(first_egg * second_egg, first_egg)
446
447 self.assertIs(tournament[first_egg, second_egg, "top"], first_egg)
448 self.assertIs(tournament[second_egg, first_egg, "top"], first_egg)
449
450 def test_history_lookup_top_and_bottom_are_distinct(self):
451 """Looking up top and bottom collisions should treat them as distinct entries."""
452 first_egg = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
453 second_egg = self.make_egg(("FFFFFF", 50.0), ("FF0000", 50.0))
454 tournament = self.make_tournament(first_egg=first_egg, second_egg=second_egg)
455
456 self.assertIs(first_egg * second_egg, second_egg)
457 self.assertIs(first_egg @ second_egg, first_egg)
458
459 self.assertIs(tournament[first_egg, second_egg, "top"], second_egg)
460 self.assertIs(tournament[first_egg, second_egg, "bottom"], first_egg)
461
462 def test_history_lookup_missing_match_raises_key_error(self):
463 """Looking up a missing recorded collision should raise a KeyError."""
464 first_egg = Egg()
465 second_egg = Egg()
466 tournament = self.make_tournament(first_egg=first_egg, second_egg=second_egg)
467
468 with self.assertRaises(KeyError):
469 _ = tournament[first_egg, second_egg, "top"]
470
471 def test_ranking_unique_position_returns_single_egg(self):
472 """Looking up a unique ranking position should return a single egg."""
473 alpha = self.make_egg(("FFFFFF", 100.0))
474 beta = self.make_egg(("000000", 100.0))
475 tournament = self.make_tournament(alpha=alpha, beta=beta)
476
477 self.assertIs(alpha * beta, alpha)
478 self.assertIs(1 @ tournament, alpha)
479 self.assertIs(2 @ tournament, beta)
480
481 def test_ranking_tied_position_returns_set_of_eggs(self):
482 """Looking up a tied ranking position should return a set of eggs."""
483 alpha = self.make_egg(("FFFFFF", 100.0))
484 beta = self.make_egg(("FFFFFF", 100.0))
485 gamma = self.make_egg(("000000", 100.0))
486 delta = self.make_egg(("000000", 100.0))
487 tournament = self.make_tournament(alpha=alpha, beta=beta, gamma=gamma, delta=delta)
488
489 self.assertIs(alpha * gamma, alpha)
490 self.assertIs(beta * delta, beta)
491
492 self.assertEqual(1 @ tournament, {alpha, beta})
493
494 def test_ranking_uses_dense_ranking_without_skipping_places(self):
495 """Looking up ranking positions should use dense ranking without skipping places."""
496 alpha = self.make_egg(("FFFFFF", 100.0))
497 beta = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
498 gamma = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
499 delta = self.make_egg(("000000", 100.0))
500 epsilon = self.make_egg(("000000", 100.0))
501 tournament = self.make_tournament(
502 alpha=alpha,
503 beta=beta,
504 gamma=gamma,
505 delta=delta,
506 epsilon=epsilon,
507 )
508
509 self.assertIs(alpha * beta, alpha)
510 self.assertIs(alpha * gamma, alpha)
511 self.assertIs(beta @ delta, beta)
512 self.assertIs(gamma @ epsilon, gamma)
513
514 self.assertIs(1 @ tournament, alpha)
515 self.assertEqual(2 @ tournament, {beta, gamma})
516 self.assertEqual(3 @ tournament, {delta, epsilon})
517
518 def test_ranking_missing_position_raises_index_error(self):
519 """Looking up a missing ranking position should raise an IndexError."""
520 alpha = self.make_egg(("FFFFFF", 100.0))
521 beta = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
522 gamma = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
523 delta = self.make_egg(("000000", 100.0))
524 epsilon = self.make_egg(("000000", 100.0))
525 tournament = self.make_tournament(
526 alpha=alpha,
527 beta=beta,
528 gamma=gamma,
529 delta=delta,
530 epsilon=epsilon,
531 )
532
533 self.assertIs(alpha * beta, alpha)
534 self.assertIs(alpha * gamma, alpha)
535 self.assertIs(beta @ delta, beta)
536 self.assertIs(gamma @ epsilon, gamma)
537
538 with self.assertRaises(IndexError):
539 _ = 4 @ tournament
540
541 def test_registered_egg_attribute_returns_position_and_victories(self):
542 """Accessing a registered egg as an attribute should return its position and victories."""
543 alpha = self.make_egg(("FFFFFF", 100.0))
544 beta = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
545 gamma = self.make_egg(("000000", 50.0), ("FFFFFF", 50.0))
546 delta = self.make_egg(("000000", 100.0))
547 epsilon = self.make_egg(("000000", 100.0))
548 tournament = self.make_tournament(
549 alpha=alpha,
550 beta=beta,
551 gamma=gamma,
552 delta=delta,
553 epsilon=epsilon,
554 )
555
556 self.assertIs(alpha * beta, alpha)
557 self.assertIs(alpha * gamma, alpha)
558 self.assertIs(beta @ delta, beta)
559 self.assertIs(gamma @ epsilon, gamma)
560
561 self.assertEqual(
562 tournament.alpha,
563 {"position": 1, "victories": 2},
564 )
565
566 def test_registered_egg_attribute_with_zero_victories_is_accessible(self):
567 """Accessing a registered egg with zero victories should return its position and victories."""
568 alpha = self.make_egg(("FFFFFF", 100.0))
569 beta = self.make_egg(("000000", 100.0))
570 tournament = self.make_tournament(alpha=alpha, beta=beta)
571
572 self.assertIs(alpha * beta, alpha)
573
574 self.assertEqual(
575 tournament.beta,
576 {"position": 2, "victories": 0},
577 )
578
579 def test_missing_egg_attribute_raises_attribute_error(self):
580 """Accessing an unregistered egg as an attribute should raise an AttributeError."""
581 tournament = EggTournament()
582
583 with self.assertRaises(AttributeError) as context:
584 _ = tournament.the_monster
585
586 self.assertEqual(
587 str(context.exception),
588 "Apologies, there is no such egg registered",
589 )
590
591 def test_contains_returns_true_for_registered_egg(self):
592 """Checking membership for a registered egg should return True."""
593 tournament = EggTournament()
594 egg = Egg()
595
596 tournament.register(egg, "inside_egg")
597
598 self.assertIn(egg, tournament)
599
600 def test_contains_returns_false_for_unregistered_egg(self):
601 """Checking membership for an unregistered egg should return False."""
602 tournament = EggTournament()
603 egg = Egg()
604
605 self.assertNotIn(egg, tournament)
606
607
608if __name__ == "__main__":
609 unittest.main()
Виктор Бечев
12.04.2026 22:23Понеже са празници, ще направим и друго. Ще ви дадем един приятелски съвет. За последен път:
Когато сме ви дали конкретен стринг, който искаме като съобщение за грешка *(или някакъв друг стринг, който изрично сме уточнили)* - **използвайте стринга дословно**. Без допълнителни запетаи, точки, без липсващи такива, без думи от вас си или емоджита.
Или пък може да не ни послушате, това е ваше право. Наше право е да напишем тестове, които да фейлнат ако не сте ни послушали. 😛
Весели празници!
| |
Виктор Бечев
09.04.2026 09:53Понеже са празници, добавяме още един ден към крайния срок за домашното. Весело изкарване на празниците и успех!
| |
Илиян Гаврилов
07.04.2026 01:05Също въпрос, ако яйце е участвало в битка и е загубило (счупено напр. отдолу) и после е регистрирано в турнир, за турнира си остава счупено?
Нишка | |
Илиян Гаврилов
07.04.2026 00:53В първите 2 примера е сбъркано за `AA4400` 0x44 = 68, а не 0x44=44 и следователно 170+68=238 и така във втория пример ще стане равенство 238 срещу 238, противоречие с: `"С равенства няма да тестваме."`.
Нишка |