1
0
Fork 0
pie-time/tests/test_application.py

745 lines
26 KiB
Python

# -*- coding: utf-8 -*-
import datetime
import logging
import os
import sys
import mock
import pygame
from pie_time import application as app_module
from pie_time.application import logging as app_logging
from pie_time.application import EVENT_QUIT, EVENT_CLICK_TO_UNBLANK,\
EVENT_CLICK_TO_PREV_CARD, EVENT_CLICK_TO_NEXT_CARD, RET_OK, RET_ERROR,\
PieTime
from pie_time.card import AbstractCard
class DummyCard(AbstractCard):
def tick(self):
pass
def initialize(self):
self._surface = mock.Mock(spec=pygame.surface.Surface)
class FakeTimer(object):
def __init__(self, step=1, start=None):
if start is None:
self.n = 0 - step
else:
self.n = start
self._step = step
def __call__(self):
self.n += self._step
return self.n
def _now(*args):
return datetime.datetime(*args)
class Test_Application(object):
def _dummy_deck(self):
return [mock.Mock(spec=DummyCard)]
def _dummy_blanker_schedule(self):
return (datetime.timedelta(hours=1), datetime.timedelta(hours=2))
def _mocked_app(self, **kwargs):
mocked_app = PieTime(self._dummy_deck(), **kwargs)
mocked_app.init_pygame = mock.Mock()
mocked_app.get_screen = mock.Mock(
side_effect=lambda: mock.Mock(spec=pygame.Surface)
)
mocked_app._should_blank = mock.Mock(return_value=False)
mocked_app._blank = mock.Mock()
mocked_app._unblank = mock.Mock()
mocked_app.fill_screen = mock.Mock()
mocked_app._clock = mock.Mock(spec=pygame.time.Clock)
mocked_app.destroy_cards = mock.Mock()
mocked_app.quit_pygame = mock.Mock()
mocked_app._start_clock = mock.Mock()
mocked_app._setup_output_stream = mock.Mock()
mocked_app._setup_logging = mock.Mock()
mocked_app._logger = mock.Mock(spec=logging.Logger)
def init_cards(*args, **kwargs):
PieTime.init_cards(mocked_app)
mocked_app.init_cards = mock.Mock(side_effect=init_cards)
def transition_cards(*args, **kwargs):
mocked_app._current_card_idx = 0
mocked_app._current_card_time = 0
mocked_app._transition_cards = mock.Mock(
side_effect=transition_cards
)
return mocked_app
def _make_app(self, *args, **kwargs):
new_app = PieTime(*args, **kwargs)
new_app._logger = mock.Mock(spec=logging.Logger)
return new_app
def test_init_default_settings(self):
deck = self._dummy_deck()
app = self._make_app(deck)
assert app._deck == deck
assert app.screen is None
assert app.screen_size == (320, 240)
assert app.events == []
assert app.log_path is None
assert app._fps == 20
assert app._verbose is False
assert app._blanker_schedule is None
assert app._click_to_unblank_interval is None
assert app._click_to_transition is True
assert app._clock is None
assert app._cards == []
assert app._is_blanked is False
assert app._current_card_idx is None
assert app._current_card_time is None
assert app._should_quit is False
assert len(app._internal_events) == 0
assert app._ctu_timer is None
assert app._output_stream is None
assert app._ctt_region_prev.x == 0
assert app._ctt_region_prev.y == 210
assert app._ctt_region_prev.width == 30
assert app._ctt_region_prev.height == 30
assert app._ctt_region_next.x == 290
assert app._ctt_region_next.y == 210
assert app._ctt_region_next.width == 30
assert app._ctt_region_next.height == 30
def test_init_override_settings(self):
deck = self._dummy_deck()
blanker_schedule = self._dummy_blanker_schedule()
app = self._make_app(
deck, screen_size=(640, 480), fps=60, verbose=True,
blanker_schedule=blanker_schedule,
click_to_unblank_interval=10, click_to_transition=False,
log_path='/path/to/log_file.txt'
)
assert app.screen_size == (640, 480)
assert app.log_path == '/path/to/log_file.txt'
assert app._fps == 60
assert app._verbose is True
assert app._blanker_schedule == blanker_schedule
assert app._click_to_unblank_interval == 10
assert app._click_to_transition is False
def test_should_blank_scheduled(self):
blanker_schedule = self._dummy_blanker_schedule()
app = self._make_app(self._dummy_deck())
assert app._should_blank(now=_now(2014, 10, 15, 9)) is False
app = self._make_app(
self._dummy_deck(), blanker_schedule=blanker_schedule
)
assert app._should_blank(now=_now(2014, 10, 15, 0, 0, 0)) is False
assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is True
assert app._should_blank(now=_now(2014, 10, 15, 1, 30, 0)) is True
assert app._should_blank(now=_now(2014, 10, 15, 1, 59, 59)) is True
assert app._should_blank(now=_now(2014, 10, 15, 2, 0, 0)) is False
assert app._should_blank(now=_now(2014, 10, 15, 9, 0, 0)) is False
blanker_schedule = (
datetime.timedelta(hours=23), datetime.timedelta(hours=6)
)
app = self._make_app(
self._dummy_deck(), blanker_schedule=blanker_schedule
)
assert app._should_blank(now=_now(2014, 10, 15, 0, 0, 0)) is True
assert app._should_blank(now=_now(2014, 10, 15, 5, 59, 59)) is True
assert app._should_blank(now=_now(2014, 10, 15, 6, 0, 0)) is False
assert app._should_blank(now=_now(2014, 10, 15, 12, 0, 0)) is False
assert app._should_blank(now=_now(2014, 10, 15, 22, 59, 59)) is False
assert app._should_blank(now=_now(2014, 10, 15, 23, 0, 0)) is True
def test_should_blank_ctu(self):
ctu = 10
app = self._make_app(self._dummy_deck())
app._has_click_to_unblank_event = mock.Mock(return_value=True)
assert app._should_blank() is False
assert app._ctu_timer is None
app = self._make_app(
self._dummy_deck(),
blanker_schedule=self._dummy_blanker_schedule(),
click_to_unblank_interval=ctu
)
app._is_blanked = True
app._has_click_to_unblank_event = mock.Mock(return_value=True)
assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is False
assert app._ctu_timer == ctu
app = self._make_app(
self._dummy_deck(),
blanker_schedule=self._dummy_blanker_schedule(),
click_to_unblank_interval=ctu
)
app._is_blanked = True
app._ctu_timer = ctu
app._has_click_to_unblank_event = mock.Mock(return_value=False)
app._clock = mock.Mock(spec=pygame.time.Clock)
app._clock.get_time = mock.Mock(return_value=1 * 1000)
assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is False
assert app._ctu_timer == ctu - 1
app = self._make_app(
self._dummy_deck(),
blanker_schedule=self._dummy_blanker_schedule(),
click_to_unblank_interval=ctu
)
app._is_blanked = True
app._ctu_timer = ctu
app._has_click_to_unblank_event = mock.Mock(return_value=False)
app._clock = mock.Mock(spec=pygame.time.Clock)
app._clock.get_time = mock.Mock(return_value=ctu * 1000)
assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is True
assert app._ctu_timer is None
def test_blank(self):
app = self._make_app(self._dummy_deck())
app.screen = mock.Mock(spec=pygame.surface.Surface)
app.will_blank = mock.Mock()
app._blank()
assert app._is_blanked is True
assert app.will_blank.called is True
app.screen.fill.assert_called_with(PieTime.BLANK_COLOR)
def test_unblank(self):
app = self._make_app(self._dummy_deck())
app.init_cards()
app._is_blanked = True
app.will_unblank = mock.Mock()
app._unblank()
assert app._is_blanked is False
assert app.will_unblank.called is True
assert app._cards[0][0].show.call_count == 1
def test_transition_cards(self):
deck = [
(mock.Mock(spec=DummyCard), 1),
(mock.Mock(spec=DummyCard), 1)
]
app = self._make_app(self._dummy_deck())
app.init_cards()
app._transition_cards()
assert app._current_card_idx == 0
assert not app._cards[0][0].hide.called
assert app._cards[0][0].show.call_count == 1
app = self._make_app(deck)
app._clock = mock.Mock(spec=pygame.time.Clock)
timer = FakeTimer(step=2, start=0)
app._clock.get_time = mock.Mock(
side_effect=lambda: timer() * 1000.0
)
app.init_cards()
app._current_card_idx = 0
app._current_card_time = 0
app._transition_cards()
assert app._current_card_idx == 1
assert app._cards[0][0].hide.call_count == 1
assert app._cards[1][0].show.call_count == 1
app._transition_cards()
assert app._current_card_idx == 0
assert app._cards[0][0].show.call_count == 1
assert app._cards[1][0].hide.call_count == 1
def test_transition_cards_forced(self):
deck = [
(mock.Mock(spec=DummyCard), 1),
(mock.Mock(spec=DummyCard), 1)
]
app = self._make_app(deck)
app._clock = mock.Mock(spec=pygame.time.Clock)
timer = FakeTimer(step=2, start=0)
app._clock.get_time = mock.Mock(
side_effect=lambda: timer()
)
app.init_cards()
app._current_card_idx = 0
app._current_card_time = 0
app._transition_cards(direction=1, force=True)
assert app._current_card_idx == 1
app._transition_cards(direction=1, force=True)
assert app._current_card_idx == 0
app._transition_cards(direction=-1, force=True)
assert app._current_card_idx == 1
app._transition_cards(direction=-1, force=True)
assert app._current_card_idx == 0
def test_get_events_quit_pygame(self):
new_event_get = mock.Mock(return_value=[
pygame.event.Event(pygame.QUIT)
])
app = self._make_app(self._dummy_deck())
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
app._get_events()
assert app._internal_events == set([EVENT_QUIT])
def test_get_events_quit_key(self):
new_event_get = mock.Mock(return_value=[
pygame.event.Event(pygame.KEYDOWN, key=PieTime.KEY_QUIT)
])
app = self._make_app(self._dummy_deck())
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
app._get_events()
assert app._internal_events == set([EVENT_QUIT])
def test_get_events_click_to_unblank(self):
new_event_get = mock.Mock(return_value=[
pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(160, 120))
])
app = self._make_app(self._dummy_deck(), click_to_unblank_interval=10)
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
app._is_blanked = False
app._get_events()
assert app._internal_events == set()
app._is_blanked = True
app._get_events()
assert app._internal_events == set([EVENT_CLICK_TO_UNBLANK])
def test_get_events_click_to_prev_card(self):
new_event_get = mock.Mock(return_value=[
pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(10, 230))
])
app = self._make_app(self._dummy_deck(), click_to_transition=True)
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
app._is_blanked = False
app._get_events()
assert app._internal_events == set([EVENT_CLICK_TO_PREV_CARD])
app._is_blanked = True
app._get_events()
assert EVENT_CLICK_TO_PREV_CARD not in app._internal_events
app._click_to_transition = False
app._is_blanked = False
app._get_events()
assert EVENT_CLICK_TO_PREV_CARD not in app._internal_events
def test_get_events_click_to_next_card(self):
new_event_get = mock.Mock(return_value=[
pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(310, 230))
])
app = self._make_app(self._dummy_deck(), click_to_transition=True)
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
app._is_blanked = False
app._get_events()
assert app._internal_events == set([EVENT_CLICK_TO_NEXT_CARD])
app._is_blanked = True
app._get_events()
assert EVENT_CLICK_TO_NEXT_CARD not in app._internal_events
app._click_to_transition = False
app._is_blanked = False
app._get_events()
assert EVENT_CLICK_TO_NEXT_CARD not in app._internal_events
def test_get_events_other_events(self):
events = [
pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(160, 120)),
pygame.event.Event(pygame.KEYDOWN, key=pygame.K_RETURN)
]
new_event_get = mock.Mock(return_value=events)
app = self._make_app(self._dummy_deck(), click_to_transition=True)
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
app._is_blanked = False
app._get_events()
assert app._internal_events == set()
assert app.events == events
def test_has_quit_event(self):
app = self._make_app(self._dummy_deck())
assert app._has_quit_event() is False
app._internal_events.add(EVENT_QUIT)
assert app._has_quit_event() is True
def test_has_click_to_unblank_event(self):
app = self._make_app(self._dummy_deck(), click_to_unblank_interval=10)
assert app._has_click_to_unblank_event() is False
app._internal_events.add(EVENT_CLICK_TO_UNBLANK)
assert app._has_click_to_unblank_event() is True
def test_start_clock(self):
app = self._make_app(self._dummy_deck())
fake_clock = mock.Mock(spec=pygame.time.Clock)
with mock.patch.object(app_module.pygame.time, 'Clock',
return_value=fake_clock):
app._start_clock()
assert app_module.pygame.time.Clock.called is True
assert app._clock == fake_clock
def test_setup_output_stream_no_log_path(self):
deck = self._dummy_deck()
with mock.patch.object(PieTime, '_STREAM_FACTORY'):
with mock.patch.object(PieTime, '_setup_logging'):
app = self._make_app(deck, log_path=None)
app._setup_output_stream()
assert app._output_stream == PieTime._DEFAULT_OUTPUT_STREAM
assert PieTime._STREAM_FACTORY.called is False
def test_setup_output_stream_with_log_path(self):
deck = self._dummy_deck()
fake_file = mock.Mock(spec=file)
with mock.patch.object(PieTime, '_STREAM_FACTORY', new=fake_file):
with mock.patch.object(PieTime, '_setup_logging'):
app = self._make_app(deck, log_path='/path/to/log_file.txt')
app._setup_output_stream()
PieTime._STREAM_FACTORY.assert_called_with(app.log_path, 'a')
assert app._output_stream != fake_file
def test_setup_logging_silent(self):
deck = self._dummy_deck()
fake_logger = mock.Mock(spec=logging.Logger)
fake_requests_logger = mock.Mock(spec=logging.Logger)
fake_handler = mock.Mock(spec=logging.StreamHandler)
fake_formatter = mock.Mock(spec=logging.Formatter)
fake_requests_logger.handlers = ['spam', 'eggs']
fake_requests_logger.removeHandler = mock.Mock()
def fake_getLogger(name):
if name == 'PieTime':
return fake_logger
elif name == 'requests':
return fake_requests_logger
else:
return None
with mock.patch.object(app_logging, 'getLogger',
side_effect=fake_getLogger):
with mock.patch.object(app_logging,
'StreamHandler', return_value=fake_handler):
with mock.patch.object(app_logging,
'Formatter',
return_value=fake_formatter):
app = self._make_app(deck, verbose=False)
app._output_stream = 'spam'
app._setup_logging()
fake_logger.setLevel.assert_called_with(logging.INFO)
fake_requests_logger.setLevel.assert_called_with(
logging.WARNING
)
app_logging.StreamHandler.assert_called_with(
app._output_stream
)
assert app_logging.Formatter.called is True
fake_handler.setFormatter.assert_called_with(
fake_formatter
)
fake_logger.addHandler.assert_called_with(fake_handler)
assert fake_requests_logger.removeHandler.call_count == 2
fake_requests_logger.removeHandler.assert_any_call('spam')
fake_requests_logger.removeHandler.assert_any_call('eggs')
fake_requests_logger.addHandler.assert_called_with(
fake_handler
)
def test_setup_logging_verbose(self):
deck = self._dummy_deck()
fake_logger = mock.Mock(spec=logging.Logger)
fake_requests_logger = mock.Mock(spec=logging.Logger)
fake_requests_logger.handlers = []
def fake_getLogger(name):
if name == 'PieTime':
return fake_logger
elif name == 'requests':
return fake_requests_logger
else:
return None
with mock.patch.object(app_logging, 'getLogger',
side_effect=fake_getLogger):
with mock.patch.object(app_logging, 'StreamHandler'):
with mock.patch.object(app_logging, 'Formatter'):
app = self._make_app(deck, verbose=True)
app._output_stream = 'spam'
app._setup_logging()
fake_logger.setLevel.assert_called_with(logging.DEBUG)
assert fake_requests_logger.setLevel.called is False
def test_logger(self):
app = self._make_app(self._dummy_deck())
assert app.logger is not None
def test_init_pygame(self):
app = self._make_app(self._dummy_deck())
with mock.patch.object(app_module.pygame, 'init'):
with mock.patch.object(app_module.pygame.mouse, 'set_visible'):
app.init_pygame()
assert app_module.pygame.init.called
app_module.pygame.mouse.set_visible.assert_called_with(False)
assert app._clock is None
def test_quit_pygame(self):
app = self._make_app(self._dummy_deck())
with mock.patch.object(app_module.pygame, 'quit'):
app.quit_pygame()
assert app_module.pygame.quit.called
assert app._clock is None
def test_init_cards(self):
deck = [
mock.Mock(spec=DummyCard),
(mock.Mock(spec=DummyCard), 10),
(mock.Mock(spec=DummyCard), 20, {'spam': 'eggs'})
]
app = self._make_app(deck)
app.init_cards()
assert len(app._cards) == 3
app._cards[0][0].set_app.assert_called_with(app)
app._cards[0][0].set_settings.assert_called_with({})
assert app._cards[0][0].initialize.called
assert not app._cards[0][0].show.called
assert app._cards[0][1] == PieTime.CARD_INTERVAL
app._cards[1][0].set_app.assert_called_with(app)
app._cards[1][0].set_settings.assert_called_with({})
assert app._cards[1][0].initialize.called
assert not app._cards[1][0].show.called
assert app._cards[1][1] == 10
app._cards[2][0].set_app.assert_called_with(app)
app._cards[2][0].set_settings.assert_called_with({'spam': 'eggs'})
assert app._cards[2][0].initialize.called
assert not app._cards[2][0].show.called
assert app._cards[2][1] == 20
assert app._current_card_idx is None
assert app._current_card_time is None
def test_destroy_cards(self):
with mock.patch.object(DummyCard, 'quit'):
app = self._make_app([DummyCard])
app.init_cards()
app.destroy_cards()
assert len(app._cards) == 0
assert DummyCard.quit.called
def test_get_screen(self):
with mock.patch.object(app_module.pygame.display, 'set_mode',
return_value='spam'):
app = self._make_app(self._dummy_deck())
screen = app.get_screen()
assert screen == 'spam'
app_module.pygame.display.set_mode.\
assert_called_with(app.screen_size)
def test_fill_screen(self):
app = self._make_app(self._dummy_deck())
app.screen = mock.Mock(pygame.Surface)
app.fill_screen()
app.screen.fill.assert_called_with(PieTime.BACKGROUND_COLOR)
def test_run(self):
app = self._mocked_app()
def new_start_clock(*args, **kwargs):
app._clock.tick = mock.Mock(side_effect=lambda x: app.quit())
app._start_clock = mock.Mock(side_effect=new_start_clock)
new_event_get = mock.Mock(return_value=[])
with mock.patch.object(app_module.sys, 'exit'):
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
with mock.patch.object(app_module.pygame.display, 'flip'):
app.run()
assert app._setup_output_stream.called is True
assert app._setup_logging.called is True
assert app.init_pygame.called
assert app.get_screen.called
assert app.screen is not None
assert app.init_cards.called
assert app._start_clock.called
assert app_module.pygame.event.get.called
assert app._should_blank.called
assert app._unblank.called
assert not app._blank.called
assert app._transition_cards.called
assert app._cards[0][0].tick.called
assert app.fill_screen.called
app.screen.blit.assert_called_with(
app._cards[0][0].surface,
(0, 0, app._cards[0][0].width, app._cards[0][0].height)
)
assert pygame.display.flip.called
app._clock.tick.assert_called_with(app._fps)
assert app.destroy_cards.called
assert app.quit_pygame.called
app_module.sys.exit.assert_called_with(RET_OK)
def test_run_handling_exception(self):
app = self._mocked_app()
app._clock.tick = mock.Mock(side_effect=RuntimeError('spam'))
new_event_get = mock.Mock(return_value=[])
with mock.patch.object(app_module.sys, 'exit'):
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
with mock.patch.object(app_module.pygame.display, 'flip'):
app.run()
sys.exit.assert_called_with(RET_ERROR)
def test_run_handling_quit_event(self):
app = self._mocked_app()
app._get_events = mock.Mock()
app._has_quit_event = mock.Mock(return_value=True)
with mock.patch.object(app_module.sys, 'exit'):
with mock.patch.object(app_module.pygame.display, 'flip'):
app.run()
sys.exit.assert_called_with(RET_OK)
def test_run_blanking(self):
app = self._mocked_app()
timer = FakeTimer()
def should_blank(*args, **kwargs):
return (timer.n % 2 == 1)
app._should_blank = mock.Mock(side_effect=should_blank)
def clock_tick(*args, **kwargs):
timer()
if timer.n == 3:
app.quit()
app._clock.tick = mock.Mock(side_effect=clock_tick)
new_event_get = mock.Mock(return_value=[])
with mock.patch.object(app_module.sys, 'exit'):
with mock.patch.object(app_module.pygame.event, 'get',
new=new_event_get):
with mock.patch.object(app_module.pygame.display, 'flip'):
app.run()
assert app._unblank.call_count == 2
assert app._blank.call_count == 2
def test_run_handling_click_to_prev_event(self):
app = self._mocked_app()
app._internal_events = set([EVENT_CLICK_TO_PREV_CARD])
def clock_tick(*args, **kwargs):
app.quit()
app._clock.tick = mock.Mock(side_effect=clock_tick)
app._get_events = mock.Mock()
with mock.patch.object(app_module.sys, 'exit'):
with mock.patch.object(app_module.pygame.display, 'flip'):
app.run()
app._transition_cards.assert_called_with(
direction=-1, force=True
)
def test_run_handling_click_to_next_event(self):
app = self._mocked_app()
app._internal_events = set([EVENT_CLICK_TO_PREV_CARD])
def clock_tick(*args, **kwargs):
app.quit()
app._clock.tick = mock.Mock(side_effect=clock_tick)
app._get_events = mock.Mock()
with mock.patch.object(app_module.sys, 'exit'):
with mock.patch.object(app_module.pygame.display, 'flip'):
app.run()
app._transition_cards.assert_called_with(
direction=-1, force=True
)
def test_quit(self):
app = self._mocked_app()
app.quit()
assert app._should_quit is True