test_application.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. # -*- coding: utf-8 -*-
  2. import datetime
  3. import logging
  4. import os
  5. import sys
  6. import mock
  7. import pygame
  8. from pie_time import application as app_module
  9. from pie_time.application import logging as app_logging
  10. from pie_time.application import EVENT_QUIT, EVENT_CLICK_TO_UNBLANK,\
  11. EVENT_CLICK_TO_PREV_CARD, EVENT_CLICK_TO_NEXT_CARD, RET_OK, RET_ERROR,\
  12. PieTime
  13. from pie_time.card import AbstractCard
  14. class DummyCard(AbstractCard):
  15. def tick(self):
  16. pass
  17. def initialize(self):
  18. self._surface = mock.Mock(spec=pygame.surface.Surface)
  19. class FakeTimer(object):
  20. def __init__(self, step=1, start=None):
  21. if start is None:
  22. self.n = 0 - step
  23. else:
  24. self.n = start
  25. self._step = step
  26. def __call__(self):
  27. self.n += self._step
  28. return self.n
  29. def _now(*args):
  30. return datetime.datetime(*args)
  31. class Test_Application(object):
  32. def _dummy_deck(self):
  33. return [mock.Mock(spec=DummyCard)]
  34. def _dummy_blanker_schedule(self):
  35. return (datetime.timedelta(hours=1), datetime.timedelta(hours=2))
  36. def _mocked_app(self, **kwargs):
  37. mocked_app = PieTime(self._dummy_deck(), **kwargs)
  38. mocked_app.init_pygame = mock.Mock()
  39. mocked_app.get_screen = mock.Mock(
  40. side_effect=lambda: mock.Mock(spec=pygame.Surface)
  41. )
  42. mocked_app._should_blank = mock.Mock(return_value=False)
  43. mocked_app._blank = mock.Mock()
  44. mocked_app._unblank = mock.Mock()
  45. mocked_app.fill_screen = mock.Mock()
  46. mocked_app._clock = mock.Mock(spec=pygame.time.Clock)
  47. mocked_app.destroy_cards = mock.Mock()
  48. mocked_app.quit_pygame = mock.Mock()
  49. mocked_app._start_clock = mock.Mock()
  50. mocked_app._setup_output_stream = mock.Mock()
  51. mocked_app._setup_logging = mock.Mock()
  52. mocked_app._logger = mock.Mock(spec=logging.Logger)
  53. def init_cards(*args, **kwargs):
  54. PieTime.init_cards(mocked_app)
  55. mocked_app.init_cards = mock.Mock(side_effect=init_cards)
  56. def transition_cards(*args, **kwargs):
  57. mocked_app._current_card_idx = 0
  58. mocked_app._current_card_time = 0
  59. mocked_app._transition_cards = mock.Mock(
  60. side_effect=transition_cards
  61. )
  62. return mocked_app
  63. def _make_app(self, *args, **kwargs):
  64. new_app = PieTime(*args, **kwargs)
  65. new_app._logger = mock.Mock(spec=logging.Logger)
  66. return new_app
  67. def test_init_default_settings(self):
  68. deck = self._dummy_deck()
  69. app = self._make_app(deck)
  70. assert app._deck == deck
  71. assert app.screen is None
  72. assert app.screen_size == (320, 240)
  73. assert app.events == []
  74. assert app.log_path is None
  75. assert app._fps == 20
  76. assert app._verbose is False
  77. assert app._blanker_schedule is None
  78. assert app._click_to_unblank_interval is None
  79. assert app._click_to_transition is True
  80. assert app._clock is None
  81. assert app._cards == []
  82. assert app._is_blanked is False
  83. assert app._current_card_idx is None
  84. assert app._current_card_time is None
  85. assert app._should_quit is False
  86. assert len(app._internal_events) == 0
  87. assert app._ctu_timer is None
  88. assert app._output_stream is None
  89. assert app._ctt_region_prev.x == 0
  90. assert app._ctt_region_prev.y == 210
  91. assert app._ctt_region_prev.width == 30
  92. assert app._ctt_region_prev.height == 30
  93. assert app._ctt_region_next.x == 290
  94. assert app._ctt_region_next.y == 210
  95. assert app._ctt_region_next.width == 30
  96. assert app._ctt_region_next.height == 30
  97. def test_init_override_settings(self):
  98. deck = self._dummy_deck()
  99. blanker_schedule = self._dummy_blanker_schedule()
  100. app = self._make_app(
  101. deck, screen_size=(640, 480), fps=60, verbose=True,
  102. blanker_schedule=blanker_schedule,
  103. click_to_unblank_interval=10, click_to_transition=False,
  104. log_path='/path/to/log_file.txt'
  105. )
  106. assert app.screen_size == (640, 480)
  107. assert app.log_path == '/path/to/log_file.txt'
  108. assert app._fps == 60
  109. assert app._verbose is True
  110. assert app._blanker_schedule == blanker_schedule
  111. assert app._click_to_unblank_interval == 10
  112. assert app._click_to_transition is False
  113. def test_should_blank_scheduled(self):
  114. blanker_schedule = self._dummy_blanker_schedule()
  115. app = self._make_app(self._dummy_deck())
  116. assert app._should_blank(now=_now(2014, 10, 15, 9)) is False
  117. app = self._make_app(
  118. self._dummy_deck(), blanker_schedule=blanker_schedule
  119. )
  120. assert app._should_blank(now=_now(2014, 10, 15, 0, 0, 0)) is False
  121. assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is True
  122. assert app._should_blank(now=_now(2014, 10, 15, 1, 30, 0)) is True
  123. assert app._should_blank(now=_now(2014, 10, 15, 1, 59, 59)) is True
  124. assert app._should_blank(now=_now(2014, 10, 15, 2, 0, 0)) is False
  125. assert app._should_blank(now=_now(2014, 10, 15, 9, 0, 0)) is False
  126. blanker_schedule = (
  127. datetime.timedelta(hours=23), datetime.timedelta(hours=6)
  128. )
  129. app = self._make_app(
  130. self._dummy_deck(), blanker_schedule=blanker_schedule
  131. )
  132. assert app._should_blank(now=_now(2014, 10, 15, 0, 0, 0)) is True
  133. assert app._should_blank(now=_now(2014, 10, 15, 5, 59, 59)) is True
  134. assert app._should_blank(now=_now(2014, 10, 15, 6, 0, 0)) is False
  135. assert app._should_blank(now=_now(2014, 10, 15, 12, 0, 0)) is False
  136. assert app._should_blank(now=_now(2014, 10, 15, 22, 59, 59)) is False
  137. assert app._should_blank(now=_now(2014, 10, 15, 23, 0, 0)) is True
  138. def test_should_blank_ctu(self):
  139. ctu = 10
  140. app = self._make_app(self._dummy_deck())
  141. app._has_click_to_unblank_event = mock.Mock(return_value=True)
  142. assert app._should_blank() is False
  143. assert app._ctu_timer is None
  144. app = self._make_app(
  145. self._dummy_deck(),
  146. blanker_schedule=self._dummy_blanker_schedule(),
  147. click_to_unblank_interval=ctu
  148. )
  149. app._is_blanked = True
  150. app._has_click_to_unblank_event = mock.Mock(return_value=True)
  151. assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is False
  152. assert app._ctu_timer == ctu
  153. app = self._make_app(
  154. self._dummy_deck(),
  155. blanker_schedule=self._dummy_blanker_schedule(),
  156. click_to_unblank_interval=ctu
  157. )
  158. app._is_blanked = True
  159. app._ctu_timer = ctu
  160. app._has_click_to_unblank_event = mock.Mock(return_value=False)
  161. app._clock = mock.Mock(spec=pygame.time.Clock)
  162. app._clock.get_time = mock.Mock(return_value=1 * 1000)
  163. assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is False
  164. assert app._ctu_timer == ctu - 1
  165. app = self._make_app(
  166. self._dummy_deck(),
  167. blanker_schedule=self._dummy_blanker_schedule(),
  168. click_to_unblank_interval=ctu
  169. )
  170. app._is_blanked = True
  171. app._ctu_timer = ctu
  172. app._has_click_to_unblank_event = mock.Mock(return_value=False)
  173. app._clock = mock.Mock(spec=pygame.time.Clock)
  174. app._clock.get_time = mock.Mock(return_value=ctu * 1000)
  175. assert app._should_blank(now=_now(2014, 10, 15, 1, 0, 0)) is True
  176. assert app._ctu_timer is None
  177. def test_blank(self):
  178. app = self._make_app(self._dummy_deck())
  179. app.screen = mock.Mock(spec=pygame.surface.Surface)
  180. app.will_blank = mock.Mock()
  181. app._blank()
  182. assert app._is_blanked is True
  183. assert app.will_blank.called is True
  184. app.screen.fill.assert_called_with(PieTime.BLANK_COLOR)
  185. def test_unblank(self):
  186. app = self._make_app(self._dummy_deck())
  187. app.init_cards()
  188. app._is_blanked = True
  189. app.will_unblank = mock.Mock()
  190. app._unblank()
  191. assert app._is_blanked is False
  192. assert app.will_unblank.called is True
  193. assert app._cards[0][0].show.call_count == 1
  194. def test_transition_cards(self):
  195. deck = [
  196. (mock.Mock(spec=DummyCard), 1),
  197. (mock.Mock(spec=DummyCard), 1)
  198. ]
  199. app = self._make_app(self._dummy_deck())
  200. app.init_cards()
  201. app._transition_cards()
  202. assert app._current_card_idx == 0
  203. assert not app._cards[0][0].hide.called
  204. assert app._cards[0][0].show.call_count == 1
  205. app = self._make_app(deck)
  206. app._clock = mock.Mock(spec=pygame.time.Clock)
  207. timer = FakeTimer(step=2, start=0)
  208. app._clock.get_time = mock.Mock(
  209. side_effect=lambda: timer() * 1000.0
  210. )
  211. app.init_cards()
  212. app._current_card_idx = 0
  213. app._current_card_time = 0
  214. app._transition_cards()
  215. assert app._current_card_idx == 1
  216. assert app._cards[0][0].hide.call_count == 1
  217. assert app._cards[1][0].show.call_count == 1
  218. app._transition_cards()
  219. assert app._current_card_idx == 0
  220. assert app._cards[0][0].show.call_count == 1
  221. assert app._cards[1][0].hide.call_count == 1
  222. def test_transition_cards_forced(self):
  223. deck = [
  224. (mock.Mock(spec=DummyCard), 1),
  225. (mock.Mock(spec=DummyCard), 1)
  226. ]
  227. app = self._make_app(deck)
  228. app._clock = mock.Mock(spec=pygame.time.Clock)
  229. timer = FakeTimer(step=2, start=0)
  230. app._clock.get_time = mock.Mock(
  231. side_effect=lambda: timer()
  232. )
  233. app.init_cards()
  234. app._current_card_idx = 0
  235. app._current_card_time = 0
  236. app._transition_cards(direction=1, force=True)
  237. assert app._current_card_idx == 1
  238. app._transition_cards(direction=1, force=True)
  239. assert app._current_card_idx == 0
  240. app._transition_cards(direction=-1, force=True)
  241. assert app._current_card_idx == 1
  242. app._transition_cards(direction=-1, force=True)
  243. assert app._current_card_idx == 0
  244. def test_get_events_quit_pygame(self):
  245. new_event_get = mock.Mock(return_value=[
  246. pygame.event.Event(pygame.QUIT)
  247. ])
  248. app = self._make_app(self._dummy_deck())
  249. with mock.patch.object(app_module.pygame.event, 'get',
  250. new=new_event_get):
  251. app._get_events()
  252. assert app._internal_events == set([EVENT_QUIT])
  253. def test_get_events_quit_key(self):
  254. new_event_get = mock.Mock(return_value=[
  255. pygame.event.Event(pygame.KEYDOWN, key=PieTime.KEY_QUIT)
  256. ])
  257. app = self._make_app(self._dummy_deck())
  258. with mock.patch.object(app_module.pygame.event, 'get',
  259. new=new_event_get):
  260. app._get_events()
  261. assert app._internal_events == set([EVENT_QUIT])
  262. def test_get_events_click_to_unblank(self):
  263. new_event_get = mock.Mock(return_value=[
  264. pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(160, 120))
  265. ])
  266. app = self._make_app(self._dummy_deck(), click_to_unblank_interval=10)
  267. with mock.patch.object(app_module.pygame.event, 'get',
  268. new=new_event_get):
  269. app._is_blanked = False
  270. app._get_events()
  271. assert app._internal_events == set()
  272. app._is_blanked = True
  273. app._get_events()
  274. assert app._internal_events == set([EVENT_CLICK_TO_UNBLANK])
  275. def test_get_events_click_to_prev_card(self):
  276. new_event_get = mock.Mock(return_value=[
  277. pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(10, 230))
  278. ])
  279. app = self._make_app(self._dummy_deck(), click_to_transition=True)
  280. with mock.patch.object(app_module.pygame.event, 'get',
  281. new=new_event_get):
  282. app._is_blanked = False
  283. app._get_events()
  284. assert app._internal_events == set([EVENT_CLICK_TO_PREV_CARD])
  285. app._is_blanked = True
  286. app._get_events()
  287. assert EVENT_CLICK_TO_PREV_CARD not in app._internal_events
  288. app._click_to_transition = False
  289. app._is_blanked = False
  290. app._get_events()
  291. assert EVENT_CLICK_TO_PREV_CARD not in app._internal_events
  292. def test_get_events_click_to_next_card(self):
  293. new_event_get = mock.Mock(return_value=[
  294. pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(310, 230))
  295. ])
  296. app = self._make_app(self._dummy_deck(), click_to_transition=True)
  297. with mock.patch.object(app_module.pygame.event, 'get',
  298. new=new_event_get):
  299. app._is_blanked = False
  300. app._get_events()
  301. assert app._internal_events == set([EVENT_CLICK_TO_NEXT_CARD])
  302. app._is_blanked = True
  303. app._get_events()
  304. assert EVENT_CLICK_TO_NEXT_CARD not in app._internal_events
  305. app._click_to_transition = False
  306. app._is_blanked = False
  307. app._get_events()
  308. assert EVENT_CLICK_TO_NEXT_CARD not in app._internal_events
  309. def test_get_events_other_events(self):
  310. events = [
  311. pygame.event.Event(pygame.MOUSEBUTTONDOWN, pos=(160, 120)),
  312. pygame.event.Event(pygame.KEYDOWN, key=pygame.K_RETURN)
  313. ]
  314. new_event_get = mock.Mock(return_value=events)
  315. app = self._make_app(self._dummy_deck(), click_to_transition=True)
  316. with mock.patch.object(app_module.pygame.event, 'get',
  317. new=new_event_get):
  318. app._is_blanked = False
  319. app._get_events()
  320. assert app._internal_events == set()
  321. assert app.events == events
  322. def test_has_quit_event(self):
  323. app = self._make_app(self._dummy_deck())
  324. assert app._has_quit_event() is False
  325. app._internal_events.add(EVENT_QUIT)
  326. assert app._has_quit_event() is True
  327. def test_has_click_to_unblank_event(self):
  328. app = self._make_app(self._dummy_deck(), click_to_unblank_interval=10)
  329. assert app._has_click_to_unblank_event() is False
  330. app._internal_events.add(EVENT_CLICK_TO_UNBLANK)
  331. assert app._has_click_to_unblank_event() is True
  332. def test_start_clock(self):
  333. app = self._make_app(self._dummy_deck())
  334. fake_clock = mock.Mock(spec=pygame.time.Clock)
  335. with mock.patch.object(app_module.pygame.time, 'Clock',
  336. return_value=fake_clock):
  337. app._start_clock()
  338. assert app_module.pygame.time.Clock.called is True
  339. assert app._clock == fake_clock
  340. def test_setup_output_stream_no_log_path(self):
  341. deck = self._dummy_deck()
  342. with mock.patch.object(PieTime, '_STREAM_FACTORY'):
  343. with mock.patch.object(PieTime, '_setup_logging'):
  344. app = self._make_app(deck, log_path=None)
  345. app._setup_output_stream()
  346. assert app._output_stream == PieTime._DEFAULT_OUTPUT_STREAM
  347. assert PieTime._STREAM_FACTORY.called is False
  348. def test_setup_output_stream_with_log_path(self):
  349. deck = self._dummy_deck()
  350. fake_file = mock.Mock(spec=file)
  351. with mock.patch.object(PieTime, '_STREAM_FACTORY', new=fake_file):
  352. with mock.patch.object(PieTime, '_setup_logging'):
  353. app = self._make_app(deck, log_path='/path/to/log_file.txt')
  354. app._setup_output_stream()
  355. PieTime._STREAM_FACTORY.assert_called_with(app.log_path, 'a')
  356. assert app._output_stream != fake_file
  357. def test_setup_logging_silent(self):
  358. deck = self._dummy_deck()
  359. fake_logger = mock.Mock(spec=logging.Logger)
  360. fake_requests_logger = mock.Mock(spec=logging.Logger)
  361. fake_handler = mock.Mock(spec=logging.StreamHandler)
  362. fake_formatter = mock.Mock(spec=logging.Formatter)
  363. fake_requests_logger.handlers = ['spam', 'eggs']
  364. fake_requests_logger.removeHandler = mock.Mock()
  365. def fake_getLogger(name):
  366. if name == 'PieTime':
  367. return fake_logger
  368. elif name == 'requests':
  369. return fake_requests_logger
  370. else:
  371. return None
  372. with mock.patch.object(app_logging, 'getLogger',
  373. side_effect=fake_getLogger):
  374. with mock.patch.object(app_logging,
  375. 'StreamHandler', return_value=fake_handler):
  376. with mock.patch.object(app_logging,
  377. 'Formatter',
  378. return_value=fake_formatter):
  379. app = self._make_app(deck, verbose=False)
  380. app._output_stream = 'spam'
  381. app._setup_logging()
  382. fake_logger.setLevel.assert_called_with(logging.INFO)
  383. fake_requests_logger.setLevel.assert_called_with(
  384. logging.WARNING
  385. )
  386. app_logging.StreamHandler.assert_called_with(
  387. app._output_stream
  388. )
  389. assert app_logging.Formatter.called is True
  390. fake_handler.setFormatter.assert_called_with(
  391. fake_formatter
  392. )
  393. fake_logger.addHandler.assert_called_with(fake_handler)
  394. assert fake_requests_logger.removeHandler.call_count == 2
  395. fake_requests_logger.removeHandler.assert_any_call('spam')
  396. fake_requests_logger.removeHandler.assert_any_call('eggs')
  397. fake_requests_logger.addHandler.assert_called_with(
  398. fake_handler
  399. )
  400. def test_setup_logging_verbose(self):
  401. deck = self._dummy_deck()
  402. fake_logger = mock.Mock(spec=logging.Logger)
  403. fake_requests_logger = mock.Mock(spec=logging.Logger)
  404. fake_requests_logger.handlers = []
  405. def fake_getLogger(name):
  406. if name == 'PieTime':
  407. return fake_logger
  408. elif name == 'requests':
  409. return fake_requests_logger
  410. else:
  411. return None
  412. with mock.patch.object(app_logging, 'getLogger',
  413. side_effect=fake_getLogger):
  414. with mock.patch.object(app_logging, 'StreamHandler'):
  415. with mock.patch.object(app_logging, 'Formatter'):
  416. app = self._make_app(deck, verbose=True)
  417. app._output_stream = 'spam'
  418. app._setup_logging()
  419. fake_logger.setLevel.assert_called_with(logging.DEBUG)
  420. assert fake_requests_logger.setLevel.called is False
  421. def test_logger(self):
  422. app = self._make_app(self._dummy_deck())
  423. assert app.logger is not None
  424. def test_init_pygame(self):
  425. app = self._make_app(self._dummy_deck())
  426. with mock.patch.object(app_module.pygame, 'init'):
  427. with mock.patch.object(app_module.pygame.mouse, 'set_visible'):
  428. app.init_pygame()
  429. assert app_module.pygame.init.called
  430. app_module.pygame.mouse.set_visible.assert_called_with(False)
  431. assert app._clock is None
  432. def test_quit_pygame(self):
  433. app = self._make_app(self._dummy_deck())
  434. with mock.patch.object(app_module.pygame, 'quit'):
  435. app.quit_pygame()
  436. assert app_module.pygame.quit.called
  437. assert app._clock is None
  438. def test_init_cards(self):
  439. deck = [
  440. mock.Mock(spec=DummyCard),
  441. (mock.Mock(spec=DummyCard), 10),
  442. (mock.Mock(spec=DummyCard), 20, {'spam': 'eggs'})
  443. ]
  444. app = self._make_app(deck)
  445. app.init_cards()
  446. assert len(app._cards) == 3
  447. app._cards[0][0].set_app.assert_called_with(app)
  448. app._cards[0][0].set_settings.assert_called_with({})
  449. assert app._cards[0][0].initialize.called
  450. assert not app._cards[0][0].show.called
  451. assert app._cards[0][1] == PieTime.CARD_INTERVAL
  452. app._cards[1][0].set_app.assert_called_with(app)
  453. app._cards[1][0].set_settings.assert_called_with({})
  454. assert app._cards[1][0].initialize.called
  455. assert not app._cards[1][0].show.called
  456. assert app._cards[1][1] == 10
  457. app._cards[2][0].set_app.assert_called_with(app)
  458. app._cards[2][0].set_settings.assert_called_with({'spam': 'eggs'})
  459. assert app._cards[2][0].initialize.called
  460. assert not app._cards[2][0].show.called
  461. assert app._cards[2][1] == 20
  462. assert app._current_card_idx is None
  463. assert app._current_card_time is None
  464. def test_destroy_cards(self):
  465. with mock.patch.object(DummyCard, 'quit'):
  466. app = self._make_app([DummyCard])
  467. app.init_cards()
  468. app.destroy_cards()
  469. assert len(app._cards) == 0
  470. assert DummyCard.quit.called
  471. def test_get_screen(self):
  472. with mock.patch.object(app_module.pygame.display, 'set_mode',
  473. return_value='spam'):
  474. app = self._make_app(self._dummy_deck())
  475. screen = app.get_screen()
  476. assert screen == 'spam'
  477. app_module.pygame.display.set_mode.\
  478. assert_called_with(app.screen_size)
  479. def test_fill_screen(self):
  480. app = self._make_app(self._dummy_deck())
  481. app.screen = mock.Mock(pygame.Surface)
  482. app.fill_screen()
  483. app.screen.fill.assert_called_with(PieTime.BACKGROUND_COLOR)
  484. def test_run(self):
  485. app = self._mocked_app()
  486. def new_start_clock(*args, **kwargs):
  487. app._clock.tick = mock.Mock(side_effect=lambda x: app.quit())
  488. app._start_clock = mock.Mock(side_effect=new_start_clock)
  489. new_event_get = mock.Mock(return_value=[])
  490. with mock.patch.object(app_module.sys, 'exit'):
  491. with mock.patch.object(app_module.pygame.event, 'get',
  492. new=new_event_get):
  493. with mock.patch.object(app_module.pygame.display, 'flip'):
  494. app.run()
  495. assert app._setup_output_stream.called is True
  496. assert app._setup_logging.called is True
  497. assert app.init_pygame.called
  498. assert app.get_screen.called
  499. assert app.screen is not None
  500. assert app.init_cards.called
  501. assert app._start_clock.called
  502. assert app_module.pygame.event.get.called
  503. assert app._should_blank.called
  504. assert app._unblank.called
  505. assert not app._blank.called
  506. assert app._transition_cards.called
  507. assert app._cards[0][0].tick.called
  508. assert app.fill_screen.called
  509. app.screen.blit.assert_called_with(
  510. app._cards[0][0].surface,
  511. (0, 0, app._cards[0][0].width, app._cards[0][0].height)
  512. )
  513. assert pygame.display.flip.called
  514. app._clock.tick.assert_called_with(app._fps)
  515. assert app.destroy_cards.called
  516. assert app.quit_pygame.called
  517. app_module.sys.exit.assert_called_with(RET_OK)
  518. def test_run_handling_exception(self):
  519. app = self._mocked_app()
  520. app._clock.tick = mock.Mock(side_effect=RuntimeError('spam'))
  521. new_event_get = mock.Mock(return_value=[])
  522. with mock.patch.object(app_module.sys, 'exit'):
  523. with mock.patch.object(app_module.pygame.event, 'get',
  524. new=new_event_get):
  525. with mock.patch.object(app_module.pygame.display, 'flip'):
  526. app.run()
  527. sys.exit.assert_called_with(RET_ERROR)
  528. def test_run_handling_quit_event(self):
  529. app = self._mocked_app()
  530. app._get_events = mock.Mock()
  531. app._has_quit_event = mock.Mock(return_value=True)
  532. with mock.patch.object(app_module.sys, 'exit'):
  533. with mock.patch.object(app_module.pygame.display, 'flip'):
  534. app.run()
  535. sys.exit.assert_called_with(RET_OK)
  536. def test_run_blanking(self):
  537. app = self._mocked_app()
  538. timer = FakeTimer()
  539. def should_blank(*args, **kwargs):
  540. return (timer.n % 2 == 1)
  541. app._should_blank = mock.Mock(side_effect=should_blank)
  542. def clock_tick(*args, **kwargs):
  543. timer()
  544. if timer.n == 3:
  545. app.quit()
  546. app._clock.tick = mock.Mock(side_effect=clock_tick)
  547. new_event_get = mock.Mock(return_value=[])
  548. with mock.patch.object(app_module.sys, 'exit'):
  549. with mock.patch.object(app_module.pygame.event, 'get',
  550. new=new_event_get):
  551. with mock.patch.object(app_module.pygame.display, 'flip'):
  552. app.run()
  553. assert app._unblank.call_count == 2
  554. assert app._blank.call_count == 2
  555. def test_run_handling_click_to_prev_event(self):
  556. app = self._mocked_app()
  557. app._internal_events = set([EVENT_CLICK_TO_PREV_CARD])
  558. def clock_tick(*args, **kwargs):
  559. app.quit()
  560. app._clock.tick = mock.Mock(side_effect=clock_tick)
  561. app._get_events = mock.Mock()
  562. with mock.patch.object(app_module.sys, 'exit'):
  563. with mock.patch.object(app_module.pygame.display, 'flip'):
  564. app.run()
  565. app._transition_cards.assert_called_with(
  566. direction=-1, force=True
  567. )
  568. def test_run_handling_click_to_next_event(self):
  569. app = self._mocked_app()
  570. app._internal_events = set([EVENT_CLICK_TO_PREV_CARD])
  571. def clock_tick(*args, **kwargs):
  572. app.quit()
  573. app._clock.tick = mock.Mock(side_effect=clock_tick)
  574. app._get_events = mock.Mock()
  575. with mock.patch.object(app_module.sys, 'exit'):
  576. with mock.patch.object(app_module.pygame.display, 'flip'):
  577. app.run()
  578. app._transition_cards.assert_called_with(
  579. direction=-1, force=True
  580. )
  581. def test_quit(self):
  582. app = self._mocked_app()
  583. app.quit()
  584. assert app._should_quit is True