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

698 lines
25 KiB
Python

# -*- coding: utf-8 -*-
import threading
import mock
import pygame
import requests
from pie_time.application import PieTime
from pie_time.cards import weather as card_module
class Test_WeatherCard(object):
def _dummy_card(self, city='Wroclaw,PL', api_key='API key', **settings):
app = PieTime(None, screen_size=(320, 240))
app._logger = mock.Mock()
app.path_for_resource = mock.Mock(
side_effect=lambda resource: resource
)
card = card_module.WeatherCard()
card.set_app(app)
if city:
settings['city'] = city
if api_key:
settings['api_key'] = api_key
card.set_settings(settings)
return card
def _ok_payload(self):
return {
"base": "cmc stations",
"clouds": {
"all": 20
},
"cod": 200,
"coord": {
"lat": 51.1,
"lon": 17.03
},
"dt": 1413815400,
"id": 3081368,
"main": {
"humidity": 59,
"pressure": 1013,
"temp": 17,
"temp_max": 17,
"temp_min": 17
},
"name": "Wroclaw",
"sys": {
"country": "PL",
"id": 5375,
"message": 0.1316,
"sunrise": 1413782666,
"sunset": 1413820124,
"type": 1
},
"weather": [
{
"description": "few clouds",
"icon": "02d",
"id": 801,
"main": "Clouds"
}
],
"wind": {
"deg": 280,
"speed": 6.2
}
}
def test_initialize_no_city(self):
card = self._dummy_card(city=None)
try:
card.initialize()
except Exception as exc:
assert isinstance(exc, AssertionError)
assert exc.args[0] == 'Configuration error: missing city'
else:
assert False, 'Nothing was raised :('
def test_initialize_no_api_key(self):
card = self._dummy_card(api_key=None)
try:
card.initialize()
except Exception as exc:
assert isinstance(exc, AssertionError)
assert exc.args[0] == 'Configuration error: missing API key'
else:
assert False, 'Nothing was raised :('
def test_initialize(self):
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card = self._dummy_card()
card._refresh_conditions = mock.Mock()
card.initialize()
assert card._text_font is not None
assert card._temp_font is not None
assert card._icon_font is not None
assert card._timer is None
assert card._current_conditions is None
assert card._refresh_conditions.called
def test_refresh_conditions_requests_error(self):
fake_timer = mock.Mock(spec=threading.Timer)
fake_timer.start = mock.Mock()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
with mock.patch.object(card_module.requests, 'get',
side_effect=RuntimeError('TODO')):
with mock.patch.object(card_module, 'Timer',
return_value=fake_timer):
card = self._dummy_card()
card.initialize(refresh=False)
card._refresh_conditions()
assert card_module.requests.get.called
assert card._current_conditions is None
assert card._timer is not None
card_module.Timer.assert_called_with(
card.REFRESH_INTERVAL, card._refresh_conditions
)
assert card._timer.start.called
def test_refresh_conditions_bad_status_code(self):
fake_response = mock.Mock(spec=requests.Response)
fake_response.status_code = 404
fake_timer = mock.Mock(spec=threading.Timer)
fake_timer.start = mock.Mock()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
with mock.patch.object(card_module.requests, 'get',
return_value=fake_response):
with mock.patch.object(card_module, 'Timer',
return_value=fake_timer):
card = self._dummy_card()
card.initialize(refresh=False)
card._refresh_conditions()
assert card_module.requests.get.called
assert card._current_conditions is None
assert card._timer is not None
card_module.Timer.assert_called_with(
card.REFRESH_INTERVAL, card._refresh_conditions
)
assert card._timer.start.called
def test_refresh_conditions_missing_weather_object(self):
payload = self._ok_payload()
payload['weather'] = []
fake_response = mock.Mock(spec=requests.Response)
fake_response.json = mock.Mock(return_value=payload)
fake_response.status_code = 200
fake_timer = mock.Mock(spec=threading.Timer)
fake_timer.start = mock.Mock()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
with mock.patch.object(card_module.requests, 'get',
return_value=fake_response):
with mock.patch.object(card_module, 'Timer',
return_value=fake_timer):
card = self._dummy_card()
card.initialize(refresh=False)
card._refresh_conditions()
assert card_module.requests.get.called
assert card._current_conditions is None
assert card._timer is not None
card_module.Timer.assert_called_with(
card.REFRESH_INTERVAL, card._refresh_conditions
)
assert card._timer.start.called
def test_refresh_conditions_missing_conditions(self):
payload = self._ok_payload()
payload['weather'][0].pop('main')
fake_response = mock.Mock(spec=requests.Response)
fake_response.json = mock.Mock(return_value=payload)
fake_response.status_code = 200
fake_timer = mock.Mock(spec=threading.Timer)
fake_timer.start = mock.Mock()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
with mock.patch.object(card_module.requests, 'get',
return_value=fake_response):
with mock.patch.object(card_module, 'Timer',
return_value=fake_timer):
card = self._dummy_card()
card.initialize(refresh=False)
card._refresh_conditions()
assert card_module.requests.get.called
assert card._current_conditions is None
assert card._timer is not None
card_module.Timer.assert_called_with(
card.REFRESH_INTERVAL, card._refresh_conditions
)
assert card._timer.start.called
def test_refresh_conditions_missing_temp(self):
payload = self._ok_payload()
payload['main'].pop('temp')
fake_response = mock.Mock(spec=requests.Response)
fake_response.json = mock.Mock(return_value=payload)
fake_response.status_code = 200
fake_timer = mock.Mock(spec=threading.Timer)
fake_timer.start = mock.Mock()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
with mock.patch.object(card_module.requests, 'get',
return_value=fake_response):
with mock.patch.object(card_module, 'Timer',
return_value=fake_timer):
card = self._dummy_card()
card.initialize(refresh=False)
card._refresh_conditions()
assert card_module.requests.get.called
assert card._current_conditions is None
assert card._timer is not None
card_module.Timer.assert_called_with(
card.REFRESH_INTERVAL, card._refresh_conditions
)
assert card._timer.start.called
def test_refresh_conditions(self):
payload = self._ok_payload()
fake_response = mock.Mock(spec=requests.Response)
fake_response.json = mock.Mock(return_value=payload)
fake_response.status_code = 200
fake_timer = mock.Mock(spec=threading.Timer)
fake_timer.start = mock.Mock()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
with mock.patch.object(card_module.requests, 'get',
return_value=fake_response):
with mock.patch.object(card_module, 'Timer',
return_value=fake_timer):
card = self._dummy_card()
card.initialize(refresh=False)
card._refresh_conditions()
assert card_module.requests.get.called
assert card._current_conditions == {
'conditions': payload['weather'][0]['main'],
'icon': payload['weather'][0]['icon'],
'temperature': payload['main']['temp'],
}
assert card._timer is not None
card_module.Timer.assert_called_with(
card.REFRESH_INTERVAL, card._refresh_conditions
)
assert card._timer.start.called
def test_refresh_conditions_no_icon(self):
payload = self._ok_payload()
payload['weather'][0].pop('icon')
fake_response = mock.Mock(spec=requests.Response)
fake_response.json = mock.Mock(return_value=payload)
fake_response.status_code = 200
fake_timer = mock.Mock(spec=threading.Timer)
fake_timer.start = mock.Mock()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
with mock.patch.object(card_module.requests, 'get',
return_value=fake_response):
with mock.patch.object(card_module, 'Timer',
return_value=fake_timer):
card = self._dummy_card()
card.initialize(refresh=False)
card._refresh_conditions()
assert card_module.requests.get.called
assert card._current_conditions == {
'conditions': payload['weather'][0]['main'],
'icon': None,
'temperature': payload['main']['temp'],
}
assert card._timer is not None
card_module.Timer.assert_called_with(
card.REFRESH_INTERVAL, card._refresh_conditions
)
assert card._timer.start.called
def test_render_city(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_city()
card._text_font.render.assert_called_with(
card._settings['city'], True, card.WHITE
)
assert isinstance(surface, pygame.surface.Surface)
def test_render_city_override_color(self):
card = self._dummy_card(city_color=(255, 0, 0))
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_city()
card._text_font.render.assert_called_with(
card._settings['city'], True, (255, 0, 0)
)
assert isinstance(surface, pygame.surface.Surface)
def test_render_conditions(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._current_conditions = {
'conditions': 'clouds'
}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_conditions()
card._text_font.render.assert_called_with(
'Clouds', True, card.WHITE
)
assert isinstance(surface, pygame.surface.Surface)
def test_render_conditions_override_color(self):
card = self._dummy_card(conditions_color=(255, 0, 0))
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._current_conditions = {
'conditions': 'clouds'
}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_conditions()
card._text_font.render.assert_called_with(
'Clouds', True, (255, 0, 0)
)
assert isinstance(surface, pygame.surface.Surface)
def test_render_icon(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
icon_code = '01d'
card._current_conditions = {'icon': icon_code}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_icon()
card._icon_font.render.assert_called_with(
card.WEATHER_CODE_TO_ICON[icon_code], True, card.WHITE
)
assert isinstance(surface, pygame.surface.Surface)
def test_render_icon_override_color(self):
card = self._dummy_card(icon_color=(255, 0, 0))
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
icon_code = '01d'
card._current_conditions = {'icon': icon_code}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_icon()
card._icon_font.render.assert_called_with(
card.WEATHER_CODE_TO_ICON[icon_code], True, (255, 0, 0)
)
assert isinstance(surface, pygame.surface.Surface)
def test_render_icon_no_icon(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
icon_code = None
card._current_conditions = {'icon': icon_code}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_icon()
assert card._icon_font.render.called is False
assert surface is None
def test_render_icon_unknown_icon(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
icon_code = 'spam'
card._current_conditions = {'icon': icon_code}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_icon()
assert card._icon_font.render.called is False
assert surface is None
def test_render_temperature(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._current_conditions = {
'temperature': 17
}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_temperature()
card._text_font.render.assert_called_with(
u'17°', True, card.WHITE
)
assert isinstance(surface, pygame.surface.Surface)
def test_render_temperature_override_color(self):
card = self._dummy_card(temperature_color=(255, 0, 0))
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._current_conditions = {
'temperature': 17
}
card._text_font.render = mock.Mock(
return_value=mock.Mock(spec=pygame.surface.Surface)
)
surface = card._render_temperature()
card._text_font.render.assert_called_with(
u'17°', True, (255, 0, 0)
)
assert isinstance(surface, pygame.surface.Surface)
def test_quit(self):
card = self._dummy_card()
card._timer = None
card.quit()
card = self._dummy_card()
card._timer = mock.Mock(spec=threading.Timer)
card._timer.cancel = mock.Mock()
card.quit()
assert card._timer.cancel.called
def test_tick_redraw(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._current_conditions = {
'conditions': 'Clouds',
'icon': '01d',
'temperature': 17
}
card._surface = mock.Mock(spec=pygame.surface.Surface)
city_surface = mock.Mock(spec=pygame.surface.Surface)
city_surface.get_size = mock.Mock(return_value=(120, 40))
card._render_city = mock.Mock(return_value=city_surface)
conditions_surface = mock.Mock(spec=pygame.surface.Surface)
conditions_surface.get_size = mock.Mock(return_value=(200, 40))
card._render_conditions = mock.Mock(
return_value=conditions_surface
)
icon_surface = mock.Mock(spec=pygame.surface.Surface)
icon_surface.get_size = mock.Mock(return_value=(128, 128))
card._render_icon = mock.Mock(return_value=icon_surface)
temperature_surface = mock.Mock(spec=pygame.surface.Surface)
temperature_surface.get_size = mock.Mock(return_value=(100, 82))
card._render_temperature = mock.Mock(
return_value=temperature_surface
)
card.tick()
card.surface.blit.assert_any_call(
city_surface, (100, 0, 120, 40)
)
card.surface.blit.assert_any_call(
conditions_surface, (60, 200, 200, 40)
)
card.surface.blit.assert_any_call(
icon_surface, (34, 56, 128, 128)
)
card.surface.blit.assert_any_call(
temperature_surface, (186, 79, 100, 82)
)
assert card._should_redraw is False
def test_tick_dont_redraw(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._should_redraw = False
card._surface = mock.Mock(spec=pygame.surface.Surface)
city_surface = mock.Mock(spec=pygame.surface.Surface)
city_surface.get_size = mock.Mock(return_value=(120, 40))
card._render_city = mock.Mock(return_value=city_surface)
conditions_surface = mock.Mock(spec=pygame.surface.Surface)
conditions_surface.get_size = mock.Mock(return_value=(200, 40))
card._render_conditions = mock.Mock(
return_value=conditions_surface
)
icon_surface = mock.Mock(spec=pygame.surface.Surface)
icon_surface.get_size = mock.Mock(return_value=(128, 128))
card._render_icon = mock.Mock(return_value=icon_surface)
temperature_surface = mock.Mock(spec=pygame.surface.Surface)
temperature_surface.get_size = mock.Mock(return_value=(100, 82))
card._render_temperature = mock.Mock(
return_value=temperature_surface
)
card.tick()
assert card._render_city.called is False
assert card._render_conditions.called is False
assert card._render_icon.called is False
assert card._render_temperature.called is False
assert card.surface.blit.called is False
assert card._should_redraw is False
def test_tick_without_icon(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._current_conditions = {
'conditions': 'Clouds',
'icon': '01d',
'temperature': 17
}
card._surface = mock.Mock(spec=pygame.surface.Surface)
city_surface = mock.Mock(spec=pygame.surface.Surface)
city_surface.get_size = mock.Mock(return_value=(120, 40))
card._render_city = mock.Mock(return_value=city_surface)
conditions_surface = mock.Mock(spec=pygame.surface.Surface)
conditions_surface.get_size = mock.Mock(return_value=(200, 40))
card._render_conditions = mock.Mock(
return_value=conditions_surface
)
card._render_icon = mock.Mock(return_value=None)
temperature_surface = mock.Mock(spec=pygame.surface.Surface)
temperature_surface.get_size = mock.Mock(return_value=(100, 82))
card._render_temperature = mock.Mock(
return_value=temperature_surface
)
card.tick()
card.surface.blit.assert_any_call(
city_surface, (100, 0, 120, 40)
)
card.surface.blit.assert_any_call(
conditions_surface, (60, 200, 200, 40)
)
card.surface.blit.assert_any_call(
temperature_surface, (110, 79, 100, 82)
)
assert card._should_redraw is False
def test_tick_without_conditions(self):
card = self._dummy_card()
with mock.patch.object(card_module.pygame.font, 'Font',
spec=pygame.font.Font):
card.initialize(refresh=False)
card._surface = mock.Mock(spec=pygame.surface.Surface)
city_surface = mock.Mock(spec=pygame.surface.Surface)
city_surface.get_size = mock.Mock(return_value=(120, 40))
card._render_city = mock.Mock(return_value=city_surface)
card._render_conditions = mock.Mock()
card._render_icon = mock.Mock()
card._render_temperature = mock.Mock()
card.tick()
assert card.surface.blit.call_count == 1
card.surface.blit.assert_called_with(
city_surface, (100, 0, 120, 40)
)
assert card._render_conditions.called is False
assert card._render_icon.called is False
assert card._render_temperature.called is False
assert card._should_redraw is False