def test_cancel_two_cards_animation_with_callback(self):
    card_widget_1 = CardWidget(Card(Suit.SPADES, CardValue.QUEEN))
    card_widget_1.pos = 0, 0
    card_widget_2 = CardWidget(Card(Suit.SPADES, CardValue.KING))
    card_widget_2.pos = self.window.size[0], 0
    float_layout = FloatLayout()
    float_layout.add_widget(card_widget_1)
    float_layout.add_widget(card_widget_2)
    self.render(float_layout)

    self.assert_pixels_almost_equal([0, 0], card_widget_1.pos)
    self.assert_pixels_almost_equal([self.window.size[0], 0], card_widget_2.pos)
    animation_controller = AnimationController()
    animation_1 = Animation(x=self.window.size[0], y=self.window.size[1],
                            duration=5)
    on_complete_callback_1 = Mock()
    animation_1.bind(on_complete=on_complete_callback_1)
    animation_controller.add_card_animation(card_widget_1, animation_1)
    animation_2 = Animation(x=0, y=self.window.size[1],
                            duration=2 * animation_1.duration)
    on_complete_callback_2 = Mock()
    animation_2.bind(on_complete=on_complete_callback_2)
    animation_controller.add_card_animation(card_widget_2, animation_2)
    on_both_animations_complete_callback = Mock()
    self.assertFalse(animation_controller.is_running)
    animation_controller.start(on_both_animations_complete_callback)
    self.assertTrue(animation_controller.is_running)

    on_complete_callback_1.assert_not_called()
    on_complete_callback_2.assert_not_called()
    on_both_animations_complete_callback.assert_not_called()

    # Advance a couple of frames to move the cards a little bit, but not
    # complete any animation.
    self.advance_frames(5)
    self.assertNotEqual(0, card_widget_1.x)
    self.assertNotEqual(0, card_widget_1.y)
    self.assertNotEqual(self.window.size[0], card_widget_2.x)
    self.assertNotEqual(0, card_widget_2.y)

    # No callback should be called.
    on_complete_callback_1.assert_not_called()
    on_complete_callback_2.assert_not_called()
    on_both_animations_complete_callback.assert_not_called()

    # Cancel the animations.
    self.assertTrue(animation_controller.is_running)
    animation_controller.cancel()
    self.assertFalse(animation_controller.is_running)

    # All callbacks should be called.
    on_complete_callback_1.assert_called_once()
    on_complete_callback_2.assert_called_once()
    on_both_animations_complete_callback.assert_called_once()

    # Verify that the AnimationController can be reused.
    animation_controller.add_card_animation(card_widget_1, animation_1)
  def test_animate_two_cards_with_callback(self):
    card_widget_1 = CardWidget(Card(Suit.SPADES, CardValue.QUEEN))
    card_widget_1.pos = 0, 0
    card_widget_2 = CardWidget(Card(Suit.SPADES, CardValue.KING))
    card_widget_2.pos = self.window.size[0], 0
    float_layout = FloatLayout()
    float_layout.add_widget(card_widget_1)
    float_layout.add_widget(card_widget_2)
    self.render(float_layout)

    self.assert_pixels_almost_equal([0, 0], card_widget_1.pos)
    self.assert_pixels_almost_equal([self.window.size[0], 0], card_widget_2.pos)
    animation_controller = AnimationController()
    animation_1 = Animation(x=self.window.size[0], y=self.window.size[1],
                            duration=0.5)
    on_complete_callback_1 = Mock()
    animation_1.bind(on_complete=on_complete_callback_1)
    animation_controller.add_card_animation(card_widget_1, animation_1)
    animation_2 = Animation(x=0, y=self.window.size[1],
                            duration=2 * animation_1.duration)
    on_complete_callback_2 = Mock()
    animation_2.bind(on_complete=on_complete_callback_2)
    animation_controller.add_card_animation(card_widget_2, animation_2)
    on_both_animations_complete_callback = Mock()
    self.assertFalse(animation_controller.is_running)
    animation_controller.start(on_both_animations_complete_callback)
    self.assertTrue(animation_controller.is_running)

    on_complete_callback_1.assert_not_called()
    on_complete_callback_2.assert_not_called()
    on_both_animations_complete_callback.assert_not_called()

    self.wait_for_mock_callback(on_complete_callback_1)
    self.assertTrue(animation_controller.is_running)
    self.assert_pixels_almost_equal(self.window.size, card_widget_1.pos)
    on_complete_callback_2.assert_not_called()
    on_both_animations_complete_callback.assert_not_called()

    self.wait_for_mock_callback(on_complete_callback_2)
    self.assertFalse(animation_controller.is_running)
    self.assert_pixels_almost_equal(self.window.size, card_widget_1.pos)
    self.assert_pixels_almost_equal([0, self.window.size[1]], card_widget_2.pos)
    on_both_animations_complete_callback.assert_called_once()

    # Verify that the AnimationController can be reused.
    self.assertFalse(animation_controller.is_running)
    animation_controller.add_card_animation(card_widget_1, animation_1)
  def test_animate_one_card_no_callback(self):
    card_widget = CardWidget(Card(Suit.SPADES, CardValue.QUEEN))
    card_widget.pos = 0, 0
    float_layout = FloatLayout()
    float_layout.add_widget(card_widget)
    self.render(float_layout)

    self.assert_pixels_almost_equal([0, 0], card_widget.pos)
    animation_controller = AnimationController()
    animation = Animation(x=self.window.size[0], y=self.window.size[1])
    on_complete_callback = Mock()
    animation.bind(on_complete=on_complete_callback)
    animation_controller.add_card_animation(card_widget, animation)
    self.assertFalse(animation_controller.is_running)
    animation_controller.start()
    self.assertTrue(animation_controller.is_running)
    self.wait_for_mock_callback(on_complete_callback)
    self.assertFalse(animation_controller.is_running)
    self.assert_pixels_almost_equal(self.window.size, card_widget.pos)