Migrate tests to pytest (#23544)
* Migrate tests to pytest * Fixup * Use loop fixture in test_check_config * Lintpull/23584/head
parent
d71424f285
commit
407e0c58f9
|
@ -1,25 +1,24 @@
|
|||
"""The tests for the Entity component helper."""
|
||||
# pylint: disable=protected-access
|
||||
import asyncio
|
||||
from collections import OrderedDict
|
||||
import logging
|
||||
import unittest
|
||||
from unittest.mock import patch, Mock
|
||||
from datetime import timedelta
|
||||
|
||||
import asynctest
|
||||
import pytest
|
||||
|
||||
import homeassistant.core as ha
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.components import group
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.setup import setup_component, async_setup_component
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import (
|
||||
get_test_home_assistant, MockPlatform, MockModule, mock_coro,
|
||||
MockPlatform, MockModule, mock_coro,
|
||||
async_fire_time_changed, MockEntity, MockConfigEntry,
|
||||
mock_entity_platform, mock_integration)
|
||||
|
||||
|
@ -27,178 +26,169 @@ _LOGGER = logging.getLogger(__name__)
|
|||
DOMAIN = "test_domain"
|
||||
|
||||
|
||||
class TestHelpersEntityComponent(unittest.TestCase):
|
||||
"""Test homeassistant.helpers.entity_component module."""
|
||||
async def test_setting_up_group(hass):
|
||||
"""Set up the setting of a group."""
|
||||
assert await async_setup_component(hass, 'group', {'group': {}})
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass,
|
||||
group_name='everyone')
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Initialize a test Home Assistant instance."""
|
||||
self.hass = get_test_home_assistant()
|
||||
# No group after setup
|
||||
assert len(hass.states.async_entity_ids()) == 0
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Clean up the test Home Assistant instance."""
|
||||
self.hass.stop()
|
||||
await component.async_add_entities([MockEntity()])
|
||||
await hass.async_block_till_done()
|
||||
|
||||
def test_setting_up_group(self):
|
||||
"""Set up the setting of a group."""
|
||||
setup_component(self.hass, 'group', {'group': {}})
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass,
|
||||
group_name='everyone')
|
||||
# group exists
|
||||
assert len(hass.states.async_entity_ids()) == 2
|
||||
assert hass.states.async_entity_ids('group') == ['group.everyone']
|
||||
|
||||
# No group after setup
|
||||
assert len(self.hass.states.entity_ids()) == 0
|
||||
grp = hass.states.get('group.everyone')
|
||||
|
||||
component.add_entities([MockEntity()])
|
||||
self.hass.block_till_done()
|
||||
assert grp.attributes.get('entity_id') == \
|
||||
('test_domain.unnamed_device',)
|
||||
|
||||
# group exists
|
||||
assert len(self.hass.states.entity_ids()) == 2
|
||||
assert self.hass.states.entity_ids('group') == ['group.everyone']
|
||||
# group extended
|
||||
await component.async_add_entities([MockEntity(name='goodbye')])
|
||||
await hass.async_block_till_done()
|
||||
|
||||
group = self.hass.states.get('group.everyone')
|
||||
assert len(hass.states.async_entity_ids()) == 3
|
||||
grp = hass.states.get('group.everyone')
|
||||
|
||||
assert group.attributes.get('entity_id') == \
|
||||
('test_domain.unnamed_device',)
|
||||
|
||||
# group extended
|
||||
component.add_entities([MockEntity(name='goodbye')])
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(self.hass.states.entity_ids()) == 3
|
||||
group = self.hass.states.get('group.everyone')
|
||||
|
||||
# Ordered in order of added to the group
|
||||
assert group.attributes.get('entity_id') == \
|
||||
('test_domain.goodbye', 'test_domain.unnamed_device')
|
||||
|
||||
def test_setup_loads_platforms(self):
|
||||
"""Test the loading of the platforms."""
|
||||
component_setup = Mock(return_value=True)
|
||||
platform_setup = Mock(return_value=None)
|
||||
|
||||
mock_integration(self.hass,
|
||||
MockModule('test_component', setup=component_setup))
|
||||
# mock the dependencies
|
||||
mock_integration(self.hass,
|
||||
MockModule('mod2', dependencies=['test_component']))
|
||||
mock_entity_platform(self.hass, 'test_domain.mod2',
|
||||
MockPlatform(platform_setup))
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
assert not component_setup.called
|
||||
assert not platform_setup.called
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'mod2',
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.block_till_done()
|
||||
assert component_setup.called
|
||||
assert platform_setup.called
|
||||
|
||||
def test_setup_recovers_when_setup_raises(self):
|
||||
"""Test the setup if exceptions are happening."""
|
||||
platform1_setup = Mock(side_effect=Exception('Broken'))
|
||||
platform2_setup = Mock(return_value=None)
|
||||
|
||||
mock_entity_platform(self.hass, 'test_domain.mod1',
|
||||
MockPlatform(platform1_setup))
|
||||
mock_entity_platform(self.hass, 'test_domain.mod2',
|
||||
MockPlatform(platform2_setup))
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
assert not platform1_setup.called
|
||||
assert not platform2_setup.called
|
||||
|
||||
component.setup(OrderedDict([
|
||||
(DOMAIN, {'platform': 'mod1'}),
|
||||
("{} 2".format(DOMAIN), {'platform': 'non_exist'}),
|
||||
("{} 3".format(DOMAIN), {'platform': 'mod2'}),
|
||||
]))
|
||||
|
||||
self.hass.block_till_done()
|
||||
assert platform1_setup.called
|
||||
assert platform2_setup.called
|
||||
|
||||
@patch('homeassistant.helpers.entity_component.EntityComponent'
|
||||
'._async_setup_platform', return_value=mock_coro())
|
||||
@patch('homeassistant.setup.async_setup_component',
|
||||
return_value=mock_coro(True))
|
||||
def test_setup_does_discovery(self, mock_setup_component, mock_setup):
|
||||
"""Test setup for discovery."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
component.setup({})
|
||||
|
||||
discovery.load_platform(self.hass, DOMAIN, 'platform_test',
|
||||
{'msg': 'discovery_info'}, {DOMAIN: {}})
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert mock_setup.called
|
||||
assert ('platform_test', {}, {'msg': 'discovery_info'}) == \
|
||||
mock_setup.call_args[0]
|
||||
|
||||
@patch('homeassistant.helpers.entity_platform.'
|
||||
'async_track_time_interval')
|
||||
def test_set_scan_interval_via_config(self, mock_track):
|
||||
"""Test the setting of the scan interval via configuration."""
|
||||
def platform_setup(hass, config, add_entities, discovery_info=None):
|
||||
"""Test the platform setup."""
|
||||
add_entities([MockEntity(should_poll=True)])
|
||||
|
||||
mock_entity_platform(self.hass, 'test_domain.platform',
|
||||
MockPlatform(platform_setup))
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'platform',
|
||||
'scan_interval': timedelta(seconds=30),
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.block_till_done()
|
||||
assert mock_track.called
|
||||
assert timedelta(seconds=30) == mock_track.call_args[0][2]
|
||||
|
||||
def test_set_entity_namespace_via_config(self):
|
||||
"""Test setting an entity namespace."""
|
||||
def platform_setup(hass, config, add_entities, discovery_info=None):
|
||||
"""Test the platform setup."""
|
||||
add_entities([
|
||||
MockEntity(name='beer'),
|
||||
MockEntity(name=None),
|
||||
])
|
||||
|
||||
platform = MockPlatform(platform_setup)
|
||||
|
||||
mock_entity_platform(self.hass, 'test_domain.platform', platform)
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'platform',
|
||||
'entity_namespace': 'yummy'
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert sorted(self.hass.states.entity_ids()) == \
|
||||
['test_domain.yummy_beer', 'test_domain.yummy_unnamed_device']
|
||||
# Ordered in order of added to the group
|
||||
assert grp.attributes.get('entity_id') == \
|
||||
('test_domain.goodbye', 'test_domain.unnamed_device')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_extract_from_service_available_device(hass):
|
||||
async def test_setup_loads_platforms(hass):
|
||||
"""Test the loading of the platforms."""
|
||||
component_setup = Mock(return_value=True)
|
||||
platform_setup = Mock(return_value=None)
|
||||
|
||||
mock_integration(hass, MockModule('test_component', setup=component_setup))
|
||||
# mock the dependencies
|
||||
mock_integration(hass, MockModule('mod2', dependencies=['test_component']))
|
||||
mock_entity_platform(hass, 'test_domain.mod2',
|
||||
MockPlatform(platform_setup))
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
assert not component_setup.called
|
||||
assert not platform_setup.called
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'mod2',
|
||||
}
|
||||
})
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert component_setup.called
|
||||
assert platform_setup.called
|
||||
|
||||
|
||||
async def test_setup_recovers_when_setup_raises(hass):
|
||||
"""Test the setup if exceptions are happening."""
|
||||
platform1_setup = Mock(side_effect=Exception('Broken'))
|
||||
platform2_setup = Mock(return_value=None)
|
||||
|
||||
mock_entity_platform(hass, 'test_domain.mod1',
|
||||
MockPlatform(platform1_setup))
|
||||
mock_entity_platform(hass, 'test_domain.mod2',
|
||||
MockPlatform(platform2_setup))
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
assert not platform1_setup.called
|
||||
assert not platform2_setup.called
|
||||
|
||||
component.setup(OrderedDict([
|
||||
(DOMAIN, {'platform': 'mod1'}),
|
||||
("{} 2".format(DOMAIN), {'platform': 'non_exist'}),
|
||||
("{} 3".format(DOMAIN), {'platform': 'mod2'}),
|
||||
]))
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert platform1_setup.called
|
||||
assert platform2_setup.called
|
||||
|
||||
|
||||
@asynctest.patch('homeassistant.helpers.entity_component.EntityComponent'
|
||||
'._async_setup_platform', return_value=mock_coro())
|
||||
@asynctest.patch('homeassistant.setup.async_setup_component',
|
||||
return_value=mock_coro(True))
|
||||
async def test_setup_does_discovery(mock_setup_component, mock_setup, hass):
|
||||
"""Test setup for discovery."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
component.setup({})
|
||||
|
||||
discovery.load_platform(hass, DOMAIN, 'platform_test',
|
||||
{'msg': 'discovery_info'}, {DOMAIN: {}})
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert mock_setup.called
|
||||
assert ('platform_test', {}, {'msg': 'discovery_info'}) == \
|
||||
mock_setup.call_args[0]
|
||||
|
||||
|
||||
@asynctest.patch('homeassistant.helpers.entity_platform.'
|
||||
'async_track_time_interval')
|
||||
async def test_set_scan_interval_via_config(mock_track, hass):
|
||||
"""Test the setting of the scan interval via configuration."""
|
||||
def platform_setup(hass, config, add_entities, discovery_info=None):
|
||||
"""Test the platform setup."""
|
||||
add_entities([MockEntity(should_poll=True)])
|
||||
|
||||
mock_entity_platform(hass, 'test_domain.platform',
|
||||
MockPlatform(platform_setup))
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'platform',
|
||||
'scan_interval': timedelta(seconds=30),
|
||||
}
|
||||
})
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert mock_track.called
|
||||
assert timedelta(seconds=30) == mock_track.call_args[0][2]
|
||||
|
||||
|
||||
async def test_set_entity_namespace_via_config(hass):
|
||||
"""Test setting an entity namespace."""
|
||||
def platform_setup(hass, config, add_entities, discovery_info=None):
|
||||
"""Test the platform setup."""
|
||||
add_entities([
|
||||
MockEntity(name='beer'),
|
||||
MockEntity(name=None),
|
||||
])
|
||||
|
||||
platform = MockPlatform(platform_setup)
|
||||
|
||||
mock_entity_platform(hass, 'test_domain.platform', platform)
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'platform',
|
||||
'entity_namespace': 'yummy'
|
||||
}
|
||||
})
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert sorted(hass.states.async_entity_ids()) == \
|
||||
['test_domain.yummy_beer', 'test_domain.yummy_unnamed_device']
|
||||
|
||||
|
||||
async def test_extract_from_service_available_device(hass):
|
||||
"""Test the extraction of entity from service and device is available."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(name='test_1'),
|
||||
MockEntity(name='test_2', available=False),
|
||||
MockEntity(name='test_3'),
|
||||
|
@ -209,7 +199,7 @@ def test_extract_from_service_available_device(hass):
|
|||
|
||||
assert ['test_domain.test_1', 'test_domain.test_3'] == \
|
||||
sorted(ent.entity_id for ent in
|
||||
(yield from component.async_extract_from_service(call_1)))
|
||||
(await component.async_extract_from_service(call_1)))
|
||||
|
||||
call_2 = ha.ServiceCall('test', 'service', data={
|
||||
'entity_id': ['test_domain.test_3', 'test_domain.test_4'],
|
||||
|
@ -217,11 +207,10 @@ def test_extract_from_service_available_device(hass):
|
|||
|
||||
assert ['test_domain.test_3'] == \
|
||||
sorted(ent.entity_id for ent in
|
||||
(yield from component.async_extract_from_service(call_2)))
|
||||
(await component.async_extract_from_service(call_2)))
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_platform_not_ready(hass):
|
||||
async def test_platform_not_ready(hass):
|
||||
"""Test that we retry when platform not ready."""
|
||||
platform1_setup = Mock(side_effect=[PlatformNotReady, PlatformNotReady,
|
||||
None])
|
||||
|
@ -231,7 +220,7 @@ def test_platform_not_ready(hass):
|
|||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
yield from component.async_setup({
|
||||
await component.async_setup({
|
||||
DOMAIN: {
|
||||
'platform': 'mod1'
|
||||
}
|
||||
|
@ -245,32 +234,31 @@ def test_platform_not_ready(hass):
|
|||
with patch('homeassistant.util.dt.utcnow', return_value=utcnow):
|
||||
# Should not trigger attempt 2
|
||||
async_fire_time_changed(hass, utcnow + timedelta(seconds=29))
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
assert len(platform1_setup.mock_calls) == 1
|
||||
|
||||
# Should trigger attempt 2
|
||||
async_fire_time_changed(hass, utcnow + timedelta(seconds=30))
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
assert len(platform1_setup.mock_calls) == 2
|
||||
assert 'test_domain.mod1' not in hass.config.components
|
||||
|
||||
# This should not trigger attempt 3
|
||||
async_fire_time_changed(hass, utcnow + timedelta(seconds=59))
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
assert len(platform1_setup.mock_calls) == 2
|
||||
|
||||
# Trigger attempt 3, which succeeds
|
||||
async_fire_time_changed(hass, utcnow + timedelta(seconds=60))
|
||||
yield from hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
assert len(platform1_setup.mock_calls) == 3
|
||||
assert 'test_domain.mod1' in hass.config.components
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_extract_from_service_returns_all_if_no_entity_id(hass):
|
||||
async def test_extract_from_service_returns_all_if_no_entity_id(hass):
|
||||
"""Test the extraction of everything from service."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(name='test_1'),
|
||||
MockEntity(name='test_2'),
|
||||
])
|
||||
|
@ -279,14 +267,13 @@ def test_extract_from_service_returns_all_if_no_entity_id(hass):
|
|||
|
||||
assert ['test_domain.test_1', 'test_domain.test_2'] == \
|
||||
sorted(ent.entity_id for ent in
|
||||
(yield from component.async_extract_from_service(call)))
|
||||
(await component.async_extract_from_service(call)))
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_extract_from_service_filter_out_non_existing_entities(hass):
|
||||
async def test_extract_from_service_filter_out_non_existing_entities(hass):
|
||||
"""Test the extraction of non existing entities from service."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(name='test_1'),
|
||||
MockEntity(name='test_2'),
|
||||
])
|
||||
|
@ -297,28 +284,26 @@ def test_extract_from_service_filter_out_non_existing_entities(hass):
|
|||
|
||||
assert ['test_domain.test_2'] == \
|
||||
[ent.entity_id for ent
|
||||
in (yield from component.async_extract_from_service(call))]
|
||||
in await component.async_extract_from_service(call)]
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_extract_from_service_no_group_expand(hass):
|
||||
async def test_extract_from_service_no_group_expand(hass):
|
||||
"""Test not expanding a group."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
test_group = yield from group.Group.async_create_group(
|
||||
test_group = await group.Group.async_create_group(
|
||||
hass, 'test_group', ['light.Ceiling', 'light.Kitchen'])
|
||||
yield from component.async_add_entities([test_group])
|
||||
await component.async_add_entities([test_group])
|
||||
|
||||
call = ha.ServiceCall('test', 'service', {
|
||||
'entity_id': ['group.test_group']
|
||||
})
|
||||
|
||||
extracted = yield from component.async_extract_from_service(
|
||||
extracted = await component.async_extract_from_service(
|
||||
call, expand_group=False)
|
||||
assert extracted == [test_group]
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_dependencies_platform(hass):
|
||||
async def test_setup_dependencies_platform(hass):
|
||||
"""Test we setup the dependencies of a platform.
|
||||
|
||||
We're explictely testing that we process dependencies even if a component
|
||||
|
@ -331,7 +316,7 @@ def test_setup_dependencies_platform(hass):
|
|||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
yield from component.async_setup({
|
||||
await component.async_setup({
|
||||
DOMAIN: {
|
||||
'platform': 'test_component',
|
||||
}
|
||||
|
@ -355,7 +340,7 @@ async def test_setup_entry(hass):
|
|||
|
||||
assert await component.async_setup_entry(entry)
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
p_hass, p_entry, p_add_entities = mock_setup_entry.mock_calls[0][1]
|
||||
p_hass, p_entry, _ = mock_setup_entry.mock_calls[0][1]
|
||||
assert p_hass is hass
|
||||
assert p_entry is entry
|
||||
|
||||
|
@ -448,7 +433,7 @@ async def test_set_service_race(hass):
|
|||
await async_setup_component(hass, 'group', {})
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass, group_name='yo')
|
||||
|
||||
for i in range(2):
|
||||
for _ in range(2):
|
||||
hass.async_create_task(component.async_add_entities([MockEntity()]))
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
"""Tests for the EntityPlatform helper."""
|
||||
import asyncio
|
||||
import logging
|
||||
import unittest
|
||||
from unittest.mock import patch, Mock, MagicMock
|
||||
from datetime import timedelta
|
||||
|
||||
import asynctest
|
||||
import pytest
|
||||
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.entity import generate_entity_id
|
||||
from homeassistant.helpers.entity import async_generate_entity_id
|
||||
from homeassistant.helpers.entity_component import (
|
||||
EntityComponent, DEFAULT_SCAN_INTERVAL)
|
||||
from homeassistant.helpers import entity_platform, entity_registry
|
||||
|
@ -16,7 +16,7 @@ from homeassistant.helpers import entity_platform, entity_registry
|
|||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import (
|
||||
get_test_home_assistant, MockPlatform, fire_time_changed, mock_registry,
|
||||
MockPlatform, async_fire_time_changed, mock_registry,
|
||||
MockEntity, MockEntityPlatform, MockConfigEntry, mock_entity_platform)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -24,164 +24,158 @@ DOMAIN = "test_domain"
|
|||
PLATFORM = 'test_platform'
|
||||
|
||||
|
||||
class TestHelpersEntityPlatform(unittest.TestCase):
|
||||
"""Test homeassistant.helpers.entity_component module."""
|
||||
async def test_polling_only_updates_entities_it_should_poll(hass):
|
||||
"""Test the polling of only updated entities."""
|
||||
component = EntityComponent(
|
||||
_LOGGER, DOMAIN, hass, timedelta(seconds=20))
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Initialize a test Home Assistant instance."""
|
||||
self.hass = get_test_home_assistant()
|
||||
no_poll_ent = MockEntity(should_poll=False)
|
||||
no_poll_ent.async_update = Mock()
|
||||
poll_ent = MockEntity(should_poll=True)
|
||||
poll_ent.async_update = Mock()
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Clean up the test Home Assistant instance."""
|
||||
self.hass.stop()
|
||||
await component.async_add_entities([no_poll_ent, poll_ent])
|
||||
|
||||
def test_polling_only_updates_entities_it_should_poll(self):
|
||||
"""Test the polling of only updated entities."""
|
||||
component = EntityComponent(
|
||||
_LOGGER, DOMAIN, self.hass, timedelta(seconds=20))
|
||||
no_poll_ent.async_update.reset_mock()
|
||||
poll_ent.async_update.reset_mock()
|
||||
|
||||
no_poll_ent = MockEntity(should_poll=False)
|
||||
no_poll_ent.async_update = Mock()
|
||||
poll_ent = MockEntity(should_poll=True)
|
||||
poll_ent.async_update = Mock()
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
component.add_entities([no_poll_ent, poll_ent])
|
||||
|
||||
no_poll_ent.async_update.reset_mock()
|
||||
poll_ent.async_update.reset_mock()
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=20))
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert not no_poll_ent.async_update.called
|
||||
assert poll_ent.async_update.called
|
||||
|
||||
def test_polling_updates_entities_with_exception(self):
|
||||
"""Test the updated entities that not break with an exception."""
|
||||
component = EntityComponent(
|
||||
_LOGGER, DOMAIN, self.hass, timedelta(seconds=20))
|
||||
|
||||
update_ok = []
|
||||
update_err = []
|
||||
|
||||
def update_mock():
|
||||
"""Mock normal update."""
|
||||
update_ok.append(None)
|
||||
|
||||
def update_mock_err():
|
||||
"""Mock error update."""
|
||||
update_err.append(None)
|
||||
raise AssertionError("Fake error update")
|
||||
|
||||
ent1 = MockEntity(should_poll=True)
|
||||
ent1.update = update_mock_err
|
||||
ent2 = MockEntity(should_poll=True)
|
||||
ent2.update = update_mock
|
||||
ent3 = MockEntity(should_poll=True)
|
||||
ent3.update = update_mock
|
||||
ent4 = MockEntity(should_poll=True)
|
||||
ent4.update = update_mock
|
||||
|
||||
component.add_entities([ent1, ent2, ent3, ent4])
|
||||
|
||||
update_ok.clear()
|
||||
update_err.clear()
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow() + timedelta(seconds=20))
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(update_ok) == 3
|
||||
assert len(update_err) == 1
|
||||
|
||||
def test_update_state_adds_entities(self):
|
||||
"""Test if updating poll entities cause an entity to be added works."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
ent1 = MockEntity()
|
||||
ent2 = MockEntity(should_poll=True)
|
||||
|
||||
component.add_entities([ent2])
|
||||
assert 1 == len(self.hass.states.entity_ids())
|
||||
ent2.update = lambda *_: component.add_entities([ent1])
|
||||
|
||||
fire_time_changed(
|
||||
self.hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL
|
||||
)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert 2 == len(self.hass.states.entity_ids())
|
||||
|
||||
def test_update_state_adds_entities_with_update_before_add_true(self):
|
||||
"""Test if call update before add to state machine."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
ent = MockEntity()
|
||||
ent.update = Mock(spec_set=True)
|
||||
|
||||
component.add_entities([ent], True)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert 1 == len(self.hass.states.entity_ids())
|
||||
assert ent.update.called
|
||||
|
||||
def test_update_state_adds_entities_with_update_before_add_false(self):
|
||||
"""Test if not call update before add to state machine."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
ent = MockEntity()
|
||||
ent.update = Mock(spec_set=True)
|
||||
|
||||
component.add_entities([ent], False)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert 1 == len(self.hass.states.entity_ids())
|
||||
assert not ent.update.called
|
||||
|
||||
@patch('homeassistant.helpers.entity_platform.'
|
||||
'async_track_time_interval')
|
||||
def test_set_scan_interval_via_platform(self, mock_track):
|
||||
"""Test the setting of the scan interval via platform."""
|
||||
def platform_setup(hass, config, add_entities, discovery_info=None):
|
||||
"""Test the platform setup."""
|
||||
add_entities([MockEntity(should_poll=True)])
|
||||
|
||||
platform = MockPlatform(platform_setup)
|
||||
platform.SCAN_INTERVAL = timedelta(seconds=30)
|
||||
|
||||
mock_entity_platform(self.hass, 'test_domain.platform', platform)
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'platform',
|
||||
}
|
||||
})
|
||||
|
||||
self.hass.block_till_done()
|
||||
assert mock_track.called
|
||||
assert timedelta(seconds=30) == mock_track.call_args[0][2]
|
||||
|
||||
def test_adding_entities_with_generator_and_thread_callback(self):
|
||||
"""Test generator in add_entities that calls thread method.
|
||||
|
||||
We should make sure we resolve the generator to a list before passing
|
||||
it into an async context.
|
||||
"""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
|
||||
|
||||
def create_entity(number):
|
||||
"""Create entity helper."""
|
||||
entity = MockEntity()
|
||||
entity.entity_id = generate_entity_id(DOMAIN + '.{}',
|
||||
'Number', hass=self.hass)
|
||||
return entity
|
||||
|
||||
component.add_entities(create_entity(i) for i in range(2))
|
||||
assert not no_poll_ent.async_update.called
|
||||
assert poll_ent.async_update.called
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_platform_warn_slow_setup(hass):
|
||||
async def test_polling_updates_entities_with_exception(hass):
|
||||
"""Test the updated entities that not break with an exception."""
|
||||
component = EntityComponent(
|
||||
_LOGGER, DOMAIN, hass, timedelta(seconds=20))
|
||||
|
||||
update_ok = []
|
||||
update_err = []
|
||||
|
||||
def update_mock():
|
||||
"""Mock normal update."""
|
||||
update_ok.append(None)
|
||||
|
||||
def update_mock_err():
|
||||
"""Mock error update."""
|
||||
update_err.append(None)
|
||||
raise AssertionError("Fake error update")
|
||||
|
||||
ent1 = MockEntity(should_poll=True)
|
||||
ent1.update = update_mock_err
|
||||
ent2 = MockEntity(should_poll=True)
|
||||
ent2.update = update_mock
|
||||
ent3 = MockEntity(should_poll=True)
|
||||
ent3.update = update_mock
|
||||
ent4 = MockEntity(should_poll=True)
|
||||
ent4.update = update_mock
|
||||
|
||||
await component.async_add_entities([ent1, ent2, ent3, ent4])
|
||||
|
||||
update_ok.clear()
|
||||
update_err.clear()
|
||||
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(update_ok) == 3
|
||||
assert len(update_err) == 1
|
||||
|
||||
|
||||
async def test_update_state_adds_entities(hass):
|
||||
"""Test if updating poll entities cause an entity to be added works."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
ent1 = MockEntity()
|
||||
ent2 = MockEntity(should_poll=True)
|
||||
|
||||
await component.async_add_entities([ent2])
|
||||
assert len(hass.states.async_entity_ids()) == 1
|
||||
ent2.update = lambda *_: component.add_entities([ent1])
|
||||
|
||||
async_fire_time_changed(
|
||||
hass, dt_util.utcnow() + DEFAULT_SCAN_INTERVAL
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_entity_ids()) == 2
|
||||
|
||||
|
||||
async def test_update_state_adds_entities_with_update_before_add_true(hass):
|
||||
"""Test if call update before add to state machine."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
ent = MockEntity()
|
||||
ent.update = Mock(spec_set=True)
|
||||
|
||||
await component.async_add_entities([ent], True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_entity_ids()) == 1
|
||||
assert ent.update.called
|
||||
|
||||
|
||||
async def test_update_state_adds_entities_with_update_before_add_false(hass):
|
||||
"""Test if not call update before add to state machine."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
ent = MockEntity()
|
||||
ent.update = Mock(spec_set=True)
|
||||
|
||||
await component.async_add_entities([ent], False)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.states.async_entity_ids()) == 1
|
||||
assert not ent.update.called
|
||||
|
||||
|
||||
@asynctest.patch('homeassistant.helpers.entity_platform.'
|
||||
'async_track_time_interval')
|
||||
async def test_set_scan_interval_via_platform(mock_track, hass):
|
||||
"""Test the setting of the scan interval via platform."""
|
||||
def platform_setup(hass, config, add_entities, discovery_info=None):
|
||||
"""Test the platform setup."""
|
||||
add_entities([MockEntity(should_poll=True)])
|
||||
|
||||
platform = MockPlatform(platform_setup)
|
||||
platform.SCAN_INTERVAL = timedelta(seconds=30)
|
||||
|
||||
mock_entity_platform(hass, 'test_domain.platform', platform)
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
component.setup({
|
||||
DOMAIN: {
|
||||
'platform': 'platform',
|
||||
}
|
||||
})
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert mock_track.called
|
||||
assert timedelta(seconds=30) == mock_track.call_args[0][2]
|
||||
|
||||
|
||||
async def test_adding_entities_with_generator_and_thread_callback(hass):
|
||||
"""Test generator in add_entities that calls thread method.
|
||||
|
||||
We should make sure we resolve the generator to a list before passing
|
||||
it into an async context.
|
||||
"""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
def create_entity(number):
|
||||
"""Create entity helper."""
|
||||
entity = MockEntity()
|
||||
entity.entity_id = async_generate_entity_id(DOMAIN + '.{}',
|
||||
'Number', hass=hass)
|
||||
return entity
|
||||
|
||||
await component.async_add_entities(create_entity(i) for i in range(2))
|
||||
|
||||
|
||||
async def test_platform_warn_slow_setup(hass):
|
||||
"""Warn we log when platform setup takes a long time."""
|
||||
platform = MockPlatform()
|
||||
|
||||
|
@ -191,7 +185,7 @@ def test_platform_warn_slow_setup(hass):
|
|||
|
||||
with patch.object(hass.loop, 'call_later', MagicMock()) \
|
||||
as mock_call:
|
||||
yield from component.async_setup({
|
||||
await component.async_setup({
|
||||
DOMAIN: {
|
||||
'platform': 'platform',
|
||||
}
|
||||
|
@ -208,21 +202,19 @@ def test_platform_warn_slow_setup(hass):
|
|||
assert mock_call().cancel.called
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_platform_error_slow_setup(hass, caplog):
|
||||
async def test_platform_error_slow_setup(hass, caplog):
|
||||
"""Don't block startup more than SLOW_SETUP_MAX_WAIT."""
|
||||
with patch.object(entity_platform, 'SLOW_SETUP_MAX_WAIT', 0):
|
||||
called = []
|
||||
|
||||
@asyncio.coroutine
|
||||
def setup_platform(*args):
|
||||
async def setup_platform(*args):
|
||||
called.append(1)
|
||||
yield from asyncio.sleep(1, loop=hass.loop)
|
||||
await asyncio.sleep(1, loop=hass.loop)
|
||||
|
||||
platform = MockPlatform(async_setup_platform=setup_platform)
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
mock_entity_platform(hass, 'test_domain.test_platform', platform)
|
||||
yield from component.async_setup({
|
||||
await component.async_setup({
|
||||
DOMAIN: {
|
||||
'platform': 'test_platform',
|
||||
}
|
||||
|
@ -232,23 +224,21 @@ def test_platform_error_slow_setup(hass, caplog):
|
|||
assert 'test_platform is taking longer than 0 seconds' in caplog.text
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_updated_state_used_for_entity_id(hass):
|
||||
async def test_updated_state_used_for_entity_id(hass):
|
||||
"""Test that first update results used for entity ID generation."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
class MockEntityNameFetcher(MockEntity):
|
||||
"""Mock entity that fetches a friendly name."""
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
async def async_update(self):
|
||||
"""Mock update that assigns a name."""
|
||||
self._values['name'] = "Living Room"
|
||||
|
||||
yield from component.async_add_entities([MockEntityNameFetcher()], True)
|
||||
await component.async_add_entities([MockEntityNameFetcher()], True)
|
||||
|
||||
entity_ids = hass.states.async_entity_ids()
|
||||
assert 1 == len(entity_ids)
|
||||
assert len(entity_ids) == 1
|
||||
assert entity_ids[0] == "test_domain.living_room"
|
||||
|
||||
|
||||
|
@ -374,8 +364,7 @@ async def test_parallel_updates_sync_platform_with_constant(hass):
|
|||
assert entity.parallel_updates._value == 2
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_raise_error_on_update(hass):
|
||||
async def test_raise_error_on_update(hass):
|
||||
"""Test the add entity if they raise an error on update."""
|
||||
updates = []
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
@ -389,63 +378,58 @@ def test_raise_error_on_update(hass):
|
|||
entity1.update = _raise
|
||||
entity2.update = lambda: updates.append(1)
|
||||
|
||||
yield from component.async_add_entities([entity1, entity2], True)
|
||||
await component.async_add_entities([entity1, entity2], True)
|
||||
|
||||
assert len(updates) == 1
|
||||
assert 1 in updates
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_async_remove_with_platform(hass):
|
||||
async def test_async_remove_with_platform(hass):
|
||||
"""Remove an entity from a platform."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
entity1 = MockEntity(name='test_1')
|
||||
yield from component.async_add_entities([entity1])
|
||||
await component.async_add_entities([entity1])
|
||||
assert len(hass.states.async_entity_ids()) == 1
|
||||
yield from entity1.async_remove()
|
||||
await entity1.async_remove()
|
||||
assert len(hass.states.async_entity_ids()) == 0
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_not_adding_duplicate_entities_with_unique_id(hass):
|
||||
async def test_not_adding_duplicate_entities_with_unique_id(hass):
|
||||
"""Test for not adding duplicate entities."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(name='test1', unique_id='not_very_unique')])
|
||||
|
||||
assert len(hass.states.async_entity_ids()) == 1
|
||||
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(name='test2', unique_id='not_very_unique')])
|
||||
|
||||
assert len(hass.states.async_entity_ids()) == 1
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_using_prescribed_entity_id(hass):
|
||||
async def test_using_prescribed_entity_id(hass):
|
||||
"""Test for using predefined entity ID."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(name='bla', entity_id='hello.world')])
|
||||
assert 'hello.world' in hass.states.async_entity_ids()
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_using_prescribed_entity_id_with_unique_id(hass):
|
||||
async def test_using_prescribed_entity_id_with_unique_id(hass):
|
||||
"""Test for ammending predefined entity ID because currently exists."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(entity_id='test_domain.world')])
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(entity_id='test_domain.world', unique_id='bla')])
|
||||
|
||||
assert 'test_domain.world_2' in hass.states.async_entity_ids()
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_using_prescribed_entity_id_which_is_registered(hass):
|
||||
async def test_using_prescribed_entity_id_which_is_registered(hass):
|
||||
"""Test not allowing predefined entity ID that already registered."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
registry = mock_registry(hass)
|
||||
|
@ -454,14 +438,13 @@ def test_using_prescribed_entity_id_which_is_registered(hass):
|
|||
DOMAIN, 'test', '1234', suggested_object_id='world')
|
||||
|
||||
# This entity_id will be rewritten
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(entity_id='test_domain.world')])
|
||||
|
||||
assert 'test_domain.world_2' in hass.states.async_entity_ids()
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_name_which_conflict_with_registered(hass):
|
||||
async def test_name_which_conflict_with_registered(hass):
|
||||
"""Test not generating conflicting entity ID based on name."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
registry = mock_registry(hass)
|
||||
|
@ -470,24 +453,22 @@ def test_name_which_conflict_with_registered(hass):
|
|||
registry.async_get_or_create(
|
||||
DOMAIN, 'test', '1234', suggested_object_id='world')
|
||||
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(name='world')])
|
||||
|
||||
assert 'test_domain.world_2' in hass.states.async_entity_ids()
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_entity_with_name_and_entity_id_getting_registered(hass):
|
||||
async def test_entity_with_name_and_entity_id_getting_registered(hass):
|
||||
"""Ensure that entity ID is used for registration."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(unique_id='1234', name='bla',
|
||||
entity_id='test_domain.world')])
|
||||
assert 'test_domain.world' in hass.states.async_entity_ids()
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_overriding_name_from_registry(hass):
|
||||
async def test_overriding_name_from_registry(hass):
|
||||
"""Test that we can override a name via the Entity Registry."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
mock_registry(hass, {
|
||||
|
@ -499,7 +480,7 @@ def test_overriding_name_from_registry(hass):
|
|||
name='Overridden'
|
||||
)
|
||||
})
|
||||
yield from component.async_add_entities([
|
||||
await component.async_add_entities([
|
||||
MockEntity(unique_id='1234', name='Device Name')])
|
||||
|
||||
state = hass.states.get('test_domain.world')
|
||||
|
@ -507,18 +488,16 @@ def test_overriding_name_from_registry(hass):
|
|||
assert state.name == 'Overridden'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_registry_respect_entity_namespace(hass):
|
||||
async def test_registry_respect_entity_namespace(hass):
|
||||
"""Test that the registry respects entity namespace."""
|
||||
mock_registry(hass)
|
||||
platform = MockEntityPlatform(hass, entity_namespace='ns')
|
||||
entity = MockEntity(unique_id='1234', name='Device Name')
|
||||
yield from platform.async_add_entities([entity])
|
||||
await platform.async_add_entities([entity])
|
||||
assert entity.entity_id == 'test_domain.ns_device_name'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_registry_respect_entity_disabled(hass):
|
||||
async def test_registry_respect_entity_disabled(hass):
|
||||
"""Test that the registry respects entity disabled."""
|
||||
mock_registry(hass, {
|
||||
'test_domain.world': entity_registry.RegistryEntry(
|
||||
|
@ -531,7 +510,7 @@ def test_registry_respect_entity_disabled(hass):
|
|||
})
|
||||
platform = MockEntityPlatform(hass)
|
||||
entity = MockEntity(unique_id='1234')
|
||||
yield from platform.async_add_entities([entity])
|
||||
await platform.async_add_entities([entity])
|
||||
assert entity.entity_id is None
|
||||
assert hass.states.async_entity_ids() == []
|
||||
|
||||
|
@ -643,12 +622,11 @@ async def test_reset_cancels_retry_setup(hass):
|
|||
assert ent_platform._async_cancel_retry_setup is None
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_not_fails_with_adding_empty_entities_(hass):
|
||||
async def test_not_fails_with_adding_empty_entities_(hass):
|
||||
"""Test for not fails on empty entities list."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
yield from component.async_add_entities([])
|
||||
await component.async_add_entities([])
|
||||
|
||||
assert len(hass.states.async_entity_ids()) == 0
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,53 +1,43 @@
|
|||
"""Test Home Assistant icon util methods."""
|
||||
import unittest
|
||||
|
||||
|
||||
class TestIconUtil(unittest.TestCase):
|
||||
"""Test icon util methods."""
|
||||
def test_battery_icon():
|
||||
"""Test icon generator for battery sensor."""
|
||||
from homeassistant.helpers.icon import icon_for_battery_level
|
||||
|
||||
def test_battery_icon(self):
|
||||
"""Test icon generator for battery sensor."""
|
||||
from homeassistant.helpers.icon import icon_for_battery_level
|
||||
assert icon_for_battery_level(None, True) == 'mdi:battery-unknown'
|
||||
assert icon_for_battery_level(None, False) == 'mdi:battery-unknown'
|
||||
|
||||
assert 'mdi:battery-unknown' == \
|
||||
icon_for_battery_level(None, True)
|
||||
assert 'mdi:battery-unknown' == \
|
||||
icon_for_battery_level(None, False)
|
||||
assert icon_for_battery_level(5, True) == 'mdi:battery-outline'
|
||||
assert icon_for_battery_level(5, False) == 'mdi:battery-alert'
|
||||
|
||||
assert 'mdi:battery-outline' == \
|
||||
icon_for_battery_level(5, True)
|
||||
assert 'mdi:battery-alert' == \
|
||||
icon_for_battery_level(5, False)
|
||||
assert icon_for_battery_level(100, True) == 'mdi:battery-charging-100'
|
||||
assert icon_for_battery_level(100, False) == 'mdi:battery'
|
||||
|
||||
assert 'mdi:battery-charging-100' == \
|
||||
icon_for_battery_level(100, True)
|
||||
assert 'mdi:battery' == \
|
||||
icon_for_battery_level(100, False)
|
||||
|
||||
iconbase = 'mdi:battery'
|
||||
for level in range(0, 100, 5):
|
||||
print('Level: %d. icon: %s, charging: %s'
|
||||
% (level, icon_for_battery_level(level, False),
|
||||
icon_for_battery_level(level, True)))
|
||||
if level <= 10:
|
||||
postfix_charging = '-outline'
|
||||
elif level <= 30:
|
||||
postfix_charging = '-charging-20'
|
||||
elif level <= 50:
|
||||
postfix_charging = '-charging-40'
|
||||
elif level <= 70:
|
||||
postfix_charging = '-charging-60'
|
||||
elif level <= 90:
|
||||
postfix_charging = '-charging-80'
|
||||
else:
|
||||
postfix_charging = '-charging-100'
|
||||
if 5 < level < 95:
|
||||
postfix = '-{}'.format(int(round(level / 10 - .01)) * 10)
|
||||
elif level <= 5:
|
||||
postfix = '-alert'
|
||||
else:
|
||||
postfix = ''
|
||||
assert iconbase + postfix == \
|
||||
icon_for_battery_level(level, False)
|
||||
assert iconbase + postfix_charging == \
|
||||
icon_for_battery_level(level, True)
|
||||
iconbase = 'mdi:battery'
|
||||
for level in range(0, 100, 5):
|
||||
print('Level: %d. icon: %s, charging: %s'
|
||||
% (level, icon_for_battery_level(level, False),
|
||||
icon_for_battery_level(level, True)))
|
||||
if level <= 10:
|
||||
postfix_charging = '-outline'
|
||||
elif level <= 30:
|
||||
postfix_charging = '-charging-20'
|
||||
elif level <= 50:
|
||||
postfix_charging = '-charging-40'
|
||||
elif level <= 70:
|
||||
postfix_charging = '-charging-60'
|
||||
elif level <= 90:
|
||||
postfix_charging = '-charging-80'
|
||||
else:
|
||||
postfix_charging = '-charging-100'
|
||||
if 5 < level < 95:
|
||||
postfix = '-{}'.format(int(round(level / 10 - .01)) * 10)
|
||||
elif level <= 5:
|
||||
postfix = '-alert'
|
||||
else:
|
||||
postfix = ''
|
||||
assert iconbase + postfix == \
|
||||
icon_for_battery_level(level, False)
|
||||
assert iconbase + postfix_charging == \
|
||||
icon_for_battery_level(level, True)
|
||||
|
|
|
@ -1,50 +1,35 @@
|
|||
"""Test component helpers."""
|
||||
# pylint: disable=protected-access
|
||||
from collections import OrderedDict
|
||||
import unittest
|
||||
|
||||
from homeassistant import helpers
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
def test_extract_domain_configs():
|
||||
"""Test the extraction of domain configuration."""
|
||||
config = {
|
||||
'zone': None,
|
||||
'zoner': None,
|
||||
'zone ': None,
|
||||
'zone Hallo': None,
|
||||
'zone 100': None,
|
||||
}
|
||||
|
||||
assert set(['zone', 'zone Hallo', 'zone 100']) == \
|
||||
set(helpers.extract_domain_configs(config, 'zone'))
|
||||
|
||||
|
||||
class TestHelpers(unittest.TestCase):
|
||||
"""Tests homeassistant.helpers module."""
|
||||
def test_config_per_platform():
|
||||
"""Test config per platform method."""
|
||||
config = OrderedDict([
|
||||
('zone', {'platform': 'hello'}),
|
||||
('zoner', None),
|
||||
('zone Hallo', [1, {'platform': 'hello 2'}]),
|
||||
('zone 100', None),
|
||||
])
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def setUp(self):
|
||||
"""Init needed objects."""
|
||||
self.hass = get_test_home_assistant()
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def tearDown(self):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_extract_domain_configs(self):
|
||||
"""Test the extraction of domain configuration."""
|
||||
config = {
|
||||
'zone': None,
|
||||
'zoner': None,
|
||||
'zone ': None,
|
||||
'zone Hallo': None,
|
||||
'zone 100': None,
|
||||
}
|
||||
|
||||
assert set(['zone', 'zone Hallo', 'zone 100']) == \
|
||||
set(helpers.extract_domain_configs(config, 'zone'))
|
||||
|
||||
def test_config_per_platform(self):
|
||||
"""Test config per platform method."""
|
||||
config = OrderedDict([
|
||||
('zone', {'platform': 'hello'}),
|
||||
('zoner', None),
|
||||
('zone Hallo', [1, {'platform': 'hello 2'}]),
|
||||
('zone 100', None),
|
||||
])
|
||||
|
||||
assert [
|
||||
('hello', config['zone']),
|
||||
(None, 1),
|
||||
('hello 2', config['zone Hallo'][1]),
|
||||
] == list(helpers.config_per_platform(config, 'zone'))
|
||||
assert [
|
||||
('hello', config['zone']),
|
||||
(None, 1),
|
||||
('hello 2', config['zone Hallo'][1]),
|
||||
] == list(helpers.config_per_platform(config, 'zone'))
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
"""Tests for the intent helpers."""
|
||||
|
||||
import unittest
|
||||
import voluptuous as vol
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import State
|
||||
from homeassistant.helpers import (intent, config_validation as cv)
|
||||
import pytest
|
||||
|
||||
|
||||
class MockIntentHandler(intent.IntentHandler):
|
||||
|
@ -25,23 +25,20 @@ def test_async_match_state():
|
|||
assert state is state1
|
||||
|
||||
|
||||
class TestIntentHandler(unittest.TestCase):
|
||||
"""Test the Home Assistant event helpers."""
|
||||
def test_async_validate_slots():
|
||||
"""Test async_validate_slots of IntentHandler."""
|
||||
handler1 = MockIntentHandler({
|
||||
vol.Required('name'): cv.string,
|
||||
})
|
||||
|
||||
def test_async_validate_slots(self):
|
||||
"""Test async_validate_slots of IntentHandler."""
|
||||
handler1 = MockIntentHandler({
|
||||
vol.Required('name'): cv.string,
|
||||
})
|
||||
|
||||
with pytest.raises(vol.error.MultipleInvalid):
|
||||
handler1.async_validate_slots({})
|
||||
with pytest.raises(vol.error.MultipleInvalid):
|
||||
handler1.async_validate_slots({'name': 1})
|
||||
with pytest.raises(vol.error.MultipleInvalid):
|
||||
handler1.async_validate_slots({'name': 'kitchen'})
|
||||
handler1.async_validate_slots({'name': {'value': 'kitchen'}})
|
||||
handler1.async_validate_slots({
|
||||
'name': {'value': 'kitchen'},
|
||||
'probability': {'value': '0.5'}
|
||||
})
|
||||
with pytest.raises(vol.error.MultipleInvalid):
|
||||
handler1.async_validate_slots({})
|
||||
with pytest.raises(vol.error.MultipleInvalid):
|
||||
handler1.async_validate_slots({'name': 1})
|
||||
with pytest.raises(vol.error.MultipleInvalid):
|
||||
handler1.async_validate_slots({'name': 'kitchen'})
|
||||
handler1.async_validate_slots({'name': {'value': 'kitchen'}})
|
||||
handler1.async_validate_slots({
|
||||
'name': {'value': 'kitchen'},
|
||||
'probability': {'value': '0.5'}
|
||||
})
|
||||
|
|
|
@ -1,58 +1,57 @@
|
|||
"""Tests Home Assistant location helpers."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE
|
||||
from homeassistant.core import State
|
||||
from homeassistant.helpers import location
|
||||
|
||||
|
||||
class TestHelpersLocation(unittest.TestCase):
|
||||
def test_has_location_with_invalid_states():
|
||||
"""Set up the tests."""
|
||||
|
||||
def test_has_location_with_invalid_states(self):
|
||||
"""Set up the tests."""
|
||||
for state in (None, 1, "hello", object):
|
||||
assert not location.has_location(state)
|
||||
|
||||
def test_has_location_with_states_with_invalid_locations(self):
|
||||
"""Set up the tests."""
|
||||
state = State('hello.world', 'invalid', {
|
||||
ATTR_LATITUDE: 'no number',
|
||||
ATTR_LONGITUDE: 123.12
|
||||
})
|
||||
for state in (None, 1, "hello", object):
|
||||
assert not location.has_location(state)
|
||||
|
||||
def test_has_location_with_states_with_valid_location(self):
|
||||
"""Set up the tests."""
|
||||
state = State('hello.world', 'invalid', {
|
||||
ATTR_LATITUDE: 123.12,
|
||||
ATTR_LONGITUDE: 123.12
|
||||
})
|
||||
assert location.has_location(state)
|
||||
|
||||
def test_closest_with_no_states_with_location(self):
|
||||
"""Set up the tests."""
|
||||
state = State('light.test', 'on')
|
||||
state2 = State('light.test', 'on', {
|
||||
ATTR_LATITUDE: 'invalid',
|
||||
ATTR_LONGITUDE: 123.45,
|
||||
})
|
||||
state3 = State('light.test', 'on', {
|
||||
ATTR_LONGITUDE: 123.45,
|
||||
})
|
||||
def test_has_location_with_states_with_invalid_locations():
|
||||
"""Set up the tests."""
|
||||
state = State('hello.world', 'invalid', {
|
||||
ATTR_LATITUDE: 'no number',
|
||||
ATTR_LONGITUDE: 123.12
|
||||
})
|
||||
assert not location.has_location(state)
|
||||
|
||||
assert \
|
||||
location.closest(123.45, 123.45, [state, state2, state3]) is None
|
||||
|
||||
def test_closest_returns_closest(self):
|
||||
"""Test ."""
|
||||
state = State('light.test', 'on', {
|
||||
ATTR_LATITUDE: 124.45,
|
||||
ATTR_LONGITUDE: 124.45,
|
||||
})
|
||||
state2 = State('light.test', 'on', {
|
||||
ATTR_LATITUDE: 125.45,
|
||||
ATTR_LONGITUDE: 125.45,
|
||||
})
|
||||
def test_has_location_with_states_with_valid_location():
|
||||
"""Set up the tests."""
|
||||
state = State('hello.world', 'invalid', {
|
||||
ATTR_LATITUDE: 123.12,
|
||||
ATTR_LONGITUDE: 123.12
|
||||
})
|
||||
assert location.has_location(state)
|
||||
|
||||
assert state == location.closest(123.45, 123.45, [state, state2])
|
||||
|
||||
def test_closest_with_no_states_with_location():
|
||||
"""Set up the tests."""
|
||||
state = State('light.test', 'on')
|
||||
state2 = State('light.test', 'on', {
|
||||
ATTR_LATITUDE: 'invalid',
|
||||
ATTR_LONGITUDE: 123.45,
|
||||
})
|
||||
state3 = State('light.test', 'on', {
|
||||
ATTR_LONGITUDE: 123.45,
|
||||
})
|
||||
|
||||
assert \
|
||||
location.closest(123.45, 123.45, [state, state2, state3]) is None
|
||||
|
||||
|
||||
def test_closest_returns_closest():
|
||||
"""Test ."""
|
||||
state = State('light.test', 'on', {
|
||||
ATTR_LATITUDE: 124.45,
|
||||
ATTR_LONGITUDE: 124.45,
|
||||
})
|
||||
state2 = State('light.test', 'on', {
|
||||
ATTR_LATITUDE: 125.45,
|
||||
ATTR_LONGITUDE: 125.45,
|
||||
})
|
||||
|
||||
assert state == location.closest(123.45, 123.45, [state, state2])
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,13 +1,12 @@
|
|||
"""Test state helpers."""
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
import homeassistant.core as ha
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.const import (SERVICE_TURN_ON, SERVICE_TURN_OFF)
|
||||
from homeassistant.util.async_ import run_coroutine_threadsafe
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.helpers import state
|
||||
from homeassistant.const import (
|
||||
|
@ -18,8 +17,7 @@ from homeassistant.const import (
|
|||
from homeassistant.components.sun import (STATE_ABOVE_HORIZON,
|
||||
STATE_BELOW_HORIZON)
|
||||
|
||||
from tests.common import get_test_home_assistant, mock_service
|
||||
import pytest
|
||||
from tests.common import async_mock_service
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
@ -82,141 +80,134 @@ def test_call_to_component(hass):
|
|||
context=context)
|
||||
|
||||
|
||||
class TestStateHelpers(unittest.TestCase):
|
||||
"""Test the Home Assistant event helpers."""
|
||||
async def test_get_changed_since(hass):
|
||||
"""Test get_changed_since."""
|
||||
point1 = dt_util.utcnow()
|
||||
point2 = point1 + timedelta(seconds=5)
|
||||
point3 = point2 + timedelta(seconds=5)
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
run_coroutine_threadsafe(async_setup_component(
|
||||
self.hass, 'homeassistant', {}), self.hass.loop).result()
|
||||
with patch('homeassistant.core.dt_util.utcnow', return_value=point1):
|
||||
hass.states.async_set('light.test', 'on')
|
||||
state1 = hass.states.get('light.test')
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Stop when tests are finished."""
|
||||
self.hass.stop()
|
||||
with patch('homeassistant.core.dt_util.utcnow', return_value=point2):
|
||||
hass.states.async_set('light.test2', 'on')
|
||||
state2 = hass.states.get('light.test2')
|
||||
|
||||
def test_get_changed_since(self):
|
||||
"""Test get_changed_since."""
|
||||
point1 = dt_util.utcnow()
|
||||
point2 = point1 + timedelta(seconds=5)
|
||||
point3 = point2 + timedelta(seconds=5)
|
||||
with patch('homeassistant.core.dt_util.utcnow', return_value=point3):
|
||||
hass.states.async_set('light.test3', 'on')
|
||||
state3 = hass.states.get('light.test3')
|
||||
|
||||
with patch('homeassistant.core.dt_util.utcnow', return_value=point1):
|
||||
self.hass.states.set('light.test', 'on')
|
||||
state1 = self.hass.states.get('light.test')
|
||||
assert [state2, state3] == \
|
||||
state.get_changed_since([state1, state2, state3], point2)
|
||||
|
||||
with patch('homeassistant.core.dt_util.utcnow', return_value=point2):
|
||||
self.hass.states.set('light.test2', 'on')
|
||||
state2 = self.hass.states.get('light.test2')
|
||||
|
||||
with patch('homeassistant.core.dt_util.utcnow', return_value=point3):
|
||||
self.hass.states.set('light.test3', 'on')
|
||||
state3 = self.hass.states.get('light.test3')
|
||||
async def test_reproduce_with_no_entity(hass):
|
||||
"""Test reproduce_state with no entity."""
|
||||
calls = async_mock_service(hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
assert [state2, state3] == \
|
||||
state.get_changed_since([state1, state2, state3], point2)
|
||||
await state.async_reproduce_state(hass, ha.State('light.test', 'on'))
|
||||
|
||||
def test_reproduce_with_no_entity(self):
|
||||
"""Test reproduce_state with no entity."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'on'))
|
||||
assert len(calls) == 0
|
||||
assert hass.states.get('light.test') is None
|
||||
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(calls) == 0
|
||||
assert self.hass.states.get('light.test') is None
|
||||
async def test_reproduce_turn_on(hass):
|
||||
"""Test reproduce_state with SERVICE_TURN_ON."""
|
||||
calls = async_mock_service(hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
def test_reproduce_turn_on(self):
|
||||
"""Test reproduce_state with SERVICE_TURN_ON."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
hass.states.async_set('light.test', 'off')
|
||||
|
||||
self.hass.states.set('light.test', 'off')
|
||||
await state.async_reproduce_state(hass, ha.State('light.test', 'on'))
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'on'))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
self.hass.block_till_done()
|
||||
assert len(calls) > 0
|
||||
last_call = calls[-1]
|
||||
assert last_call.domain == 'light'
|
||||
assert SERVICE_TURN_ON == last_call.service
|
||||
assert ['light.test'] == last_call.data.get('entity_id')
|
||||
|
||||
assert len(calls) > 0
|
||||
last_call = calls[-1]
|
||||
assert 'light' == last_call.domain
|
||||
assert SERVICE_TURN_ON == last_call.service
|
||||
assert ['light.test'] == last_call.data.get('entity_id')
|
||||
|
||||
def test_reproduce_turn_off(self):
|
||||
"""Test reproduce_state with SERVICE_TURN_OFF."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_OFF)
|
||||
async def test_reproduce_turn_off(hass):
|
||||
"""Test reproduce_state with SERVICE_TURN_OFF."""
|
||||
calls = async_mock_service(hass, 'light', SERVICE_TURN_OFF)
|
||||
|
||||
self.hass.states.set('light.test', 'on')
|
||||
hass.states.async_set('light.test', 'on')
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'off'))
|
||||
await state.async_reproduce_state(hass, ha.State('light.test', 'off'))
|
||||
|
||||
self.hass.block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) > 0
|
||||
last_call = calls[-1]
|
||||
assert 'light' == last_call.domain
|
||||
assert SERVICE_TURN_OFF == last_call.service
|
||||
assert ['light.test'] == last_call.data.get('entity_id')
|
||||
assert len(calls) > 0
|
||||
last_call = calls[-1]
|
||||
assert last_call.domain == 'light'
|
||||
assert SERVICE_TURN_OFF == last_call.service
|
||||
assert ['light.test'] == last_call.data.get('entity_id')
|
||||
|
||||
def test_reproduce_complex_data(self):
|
||||
"""Test reproduce_state with complex service data."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
self.hass.states.set('light.test', 'off')
|
||||
async def test_reproduce_complex_data(hass):
|
||||
"""Test reproduce_state with complex service data."""
|
||||
calls = async_mock_service(hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
complex_data = ['hello', {'11': '22'}]
|
||||
hass.states.async_set('light.test', 'off')
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'on', {
|
||||
'complex': complex_data
|
||||
}))
|
||||
complex_data = ['hello', {'11': '22'}]
|
||||
|
||||
self.hass.block_till_done()
|
||||
await state.async_reproduce_state(hass, ha.State('light.test', 'on', {
|
||||
'complex': complex_data
|
||||
}))
|
||||
|
||||
assert len(calls) > 0
|
||||
last_call = calls[-1]
|
||||
assert 'light' == last_call.domain
|
||||
assert SERVICE_TURN_ON == last_call.service
|
||||
assert complex_data == last_call.data.get('complex')
|
||||
await hass.async_block_till_done()
|
||||
|
||||
def test_reproduce_bad_state(self):
|
||||
"""Test reproduce_state with bad state."""
|
||||
calls = mock_service(self.hass, 'light', SERVICE_TURN_ON)
|
||||
assert len(calls) > 0
|
||||
last_call = calls[-1]
|
||||
assert last_call.domain == 'light'
|
||||
assert SERVICE_TURN_ON == last_call.service
|
||||
assert complex_data == last_call.data.get('complex')
|
||||
|
||||
self.hass.states.set('light.test', 'off')
|
||||
|
||||
state.reproduce_state(self.hass, ha.State('light.test', 'bad'))
|
||||
async def test_reproduce_bad_state(hass):
|
||||
"""Test reproduce_state with bad state."""
|
||||
calls = async_mock_service(hass, 'light', SERVICE_TURN_ON)
|
||||
|
||||
self.hass.block_till_done()
|
||||
hass.states.async_set('light.test', 'off')
|
||||
|
||||
assert len(calls) == 0
|
||||
assert 'off' == self.hass.states.get('light.test').state
|
||||
await state.async_reproduce_state(hass, ha.State('light.test', 'bad'))
|
||||
|
||||
def test_as_number_states(self):
|
||||
"""Test state_as_number with states."""
|
||||
zero_states = (STATE_OFF, STATE_CLOSED, STATE_UNLOCKED,
|
||||
STATE_BELOW_HORIZON, STATE_NOT_HOME)
|
||||
one_states = (STATE_ON, STATE_OPEN, STATE_LOCKED, STATE_ABOVE_HORIZON,
|
||||
STATE_HOME)
|
||||
for _state in zero_states:
|
||||
assert 0 == state.state_as_number(
|
||||
ha.State('domain.test', _state, {}))
|
||||
for _state in one_states:
|
||||
assert 1 == state.state_as_number(
|
||||
ha.State('domain.test', _state, {}))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
def test_as_number_coercion(self):
|
||||
"""Test state_as_number with number."""
|
||||
for _state in ('0', '0.0', 0, 0.0):
|
||||
assert 0.0 == state.state_as_number(
|
||||
ha.State('domain.test', _state, {}))
|
||||
for _state in ('1', '1.0', 1, 1.0):
|
||||
assert 1.0 == state.state_as_number(
|
||||
ha.State('domain.test', _state, {}))
|
||||
assert len(calls) == 0
|
||||
assert hass.states.get('light.test').state == 'off'
|
||||
|
||||
def test_as_number_invalid_cases(self):
|
||||
"""Test state_as_number with invalid cases."""
|
||||
for _state in ('', 'foo', 'foo.bar', None, False, True, object,
|
||||
object()):
|
||||
with pytest.raises(ValueError):
|
||||
state.state_as_number(ha.State('domain.test', _state, {}))
|
||||
|
||||
async def test_as_number_states(hass):
|
||||
"""Test state_as_number with states."""
|
||||
zero_states = (STATE_OFF, STATE_CLOSED, STATE_UNLOCKED,
|
||||
STATE_BELOW_HORIZON, STATE_NOT_HOME)
|
||||
one_states = (STATE_ON, STATE_OPEN, STATE_LOCKED, STATE_ABOVE_HORIZON,
|
||||
STATE_HOME)
|
||||
for _state in zero_states:
|
||||
assert state.state_as_number(ha.State('domain.test', _state, {})) == 0
|
||||
for _state in one_states:
|
||||
assert state.state_as_number(ha.State('domain.test', _state, {})) == 1
|
||||
|
||||
|
||||
async def test_as_number_coercion(hass):
|
||||
"""Test state_as_number with number."""
|
||||
for _state in ('0', '0.0', 0, 0.0):
|
||||
assert state.state_as_number(
|
||||
ha.State('domain.test', _state, {})) == 0.0
|
||||
for _state in ('1', '1.0', 1, 1.0):
|
||||
assert state.state_as_number(
|
||||
ha.State('domain.test', _state, {})) == 1.0
|
||||
|
||||
|
||||
async def test_as_number_invalid_cases(hass):
|
||||
"""Test state_as_number with invalid cases."""
|
||||
for _state in ('', 'foo', 'foo.bar', None, False, True, object,
|
||||
object()):
|
||||
with pytest.raises(ValueError):
|
||||
state.state_as_number(ha.State('domain.test', _state, {}))
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""The tests for the Sun helpers."""
|
||||
# pylint: disable=protected-access
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from datetime import timedelta, datetime
|
||||
|
||||
|
@ -8,223 +7,214 @@ from homeassistant.const import SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET
|
|||
import homeassistant.util.dt as dt_util
|
||||
import homeassistant.helpers.sun as sun
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
def test_next_events(hass):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
|
||||
latitude = hass.config.latitude
|
||||
longitude = hass.config.longitude
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_dawn = (astral.dawn_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_dawn > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_dusk = (astral.dusk_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_dusk > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_midnight = (astral.solar_midnight_utc(
|
||||
utc_today + timedelta(days=mod), longitude))
|
||||
if next_midnight > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_noon = (astral.solar_noon_utc(
|
||||
utc_today + timedelta(days=mod), longitude))
|
||||
if next_noon > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_rising = (astral.sunrise_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_rising > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_setting = (astral.sunset_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_setting > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
with patch('homeassistant.helpers.condition.dt_util.utcnow',
|
||||
return_value=utc_now):
|
||||
assert next_dawn == sun.get_astral_event_next(
|
||||
hass, 'dawn')
|
||||
assert next_dusk == sun.get_astral_event_next(
|
||||
hass, 'dusk')
|
||||
assert next_midnight == sun.get_astral_event_next(
|
||||
hass, 'solar_midnight')
|
||||
assert next_noon == sun.get_astral_event_next(
|
||||
hass, 'solar_noon')
|
||||
assert next_rising == sun.get_astral_event_next(
|
||||
hass, SUN_EVENT_SUNRISE)
|
||||
assert next_setting == sun.get_astral_event_next(
|
||||
hass, SUN_EVENT_SUNSET)
|
||||
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
class TestSun(unittest.TestCase):
|
||||
"""Test the sun helpers."""
|
||||
def test_date_events(hass):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
|
||||
def setUp(self):
|
||||
"""Set up things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
|
||||
def tearDown(self):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
latitude = hass.config.latitude
|
||||
longitude = hass.config.longitude
|
||||
|
||||
def test_next_events(self):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
dawn = astral.dawn_utc(utc_today, latitude, longitude)
|
||||
dusk = astral.dusk_utc(utc_today, latitude, longitude)
|
||||
midnight = astral.solar_midnight_utc(utc_today, longitude)
|
||||
noon = astral.solar_noon_utc(utc_today, longitude)
|
||||
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
|
||||
sunset = astral.sunset_utc(utc_today, latitude, longitude)
|
||||
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
assert dawn == sun.get_astral_event_date(
|
||||
hass, 'dawn', utc_today)
|
||||
assert dusk == sun.get_astral_event_date(
|
||||
hass, 'dusk', utc_today)
|
||||
assert midnight == sun.get_astral_event_date(
|
||||
hass, 'solar_midnight', utc_today)
|
||||
assert noon == sun.get_astral_event_date(
|
||||
hass, 'solar_noon', utc_today)
|
||||
assert sunrise == sun.get_astral_event_date(
|
||||
hass, SUN_EVENT_SUNRISE, utc_today)
|
||||
assert sunset == sun.get_astral_event_date(
|
||||
hass, SUN_EVENT_SUNSET, utc_today)
|
||||
|
||||
latitude = self.hass.config.latitude
|
||||
longitude = self.hass.config.longitude
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_dawn = (astral.dawn_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_dawn > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
def test_date_events_default_date(hass):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_dusk = (astral.dusk_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_dusk > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_midnight = (astral.solar_midnight_utc(
|
||||
utc_today + timedelta(days=mod), longitude))
|
||||
if next_midnight > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
latitude = hass.config.latitude
|
||||
longitude = hass.config.longitude
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_noon = (astral.solar_noon_utc(
|
||||
utc_today + timedelta(days=mod), longitude))
|
||||
if next_noon > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_rising = (astral.sunrise_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_rising > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
mod = -1
|
||||
while True:
|
||||
next_setting = (astral.sunset_utc(
|
||||
utc_today + timedelta(days=mod), latitude, longitude))
|
||||
if next_setting > utc_now:
|
||||
break
|
||||
mod += 1
|
||||
|
||||
with patch('homeassistant.helpers.condition.dt_util.utcnow',
|
||||
return_value=utc_now):
|
||||
assert next_dawn == sun.get_astral_event_next(
|
||||
self.hass, 'dawn')
|
||||
assert next_dusk == sun.get_astral_event_next(
|
||||
self.hass, 'dusk')
|
||||
assert next_midnight == sun.get_astral_event_next(
|
||||
self.hass, 'solar_midnight')
|
||||
assert next_noon == sun.get_astral_event_next(
|
||||
self.hass, 'solar_noon')
|
||||
assert next_rising == sun.get_astral_event_next(
|
||||
self.hass, SUN_EVENT_SUNRISE)
|
||||
assert next_setting == sun.get_astral_event_next(
|
||||
self.hass, SUN_EVENT_SUNSET)
|
||||
|
||||
def test_date_events(self):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
|
||||
latitude = self.hass.config.latitude
|
||||
longitude = self.hass.config.longitude
|
||||
|
||||
dawn = astral.dawn_utc(utc_today, latitude, longitude)
|
||||
dusk = astral.dusk_utc(utc_today, latitude, longitude)
|
||||
midnight = astral.solar_midnight_utc(utc_today, longitude)
|
||||
noon = astral.solar_noon_utc(utc_today, longitude)
|
||||
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
|
||||
sunset = astral.sunset_utc(utc_today, latitude, longitude)
|
||||
dawn = astral.dawn_utc(utc_today, latitude, longitude)
|
||||
dusk = astral.dusk_utc(utc_today, latitude, longitude)
|
||||
midnight = astral.solar_midnight_utc(utc_today, longitude)
|
||||
noon = astral.solar_noon_utc(utc_today, longitude)
|
||||
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
|
||||
sunset = astral.sunset_utc(utc_today, latitude, longitude)
|
||||
|
||||
with patch('homeassistant.util.dt.now', return_value=utc_now):
|
||||
assert dawn == sun.get_astral_event_date(
|
||||
self.hass, 'dawn', utc_today)
|
||||
hass, 'dawn', utc_today)
|
||||
assert dusk == sun.get_astral_event_date(
|
||||
self.hass, 'dusk', utc_today)
|
||||
hass, 'dusk', utc_today)
|
||||
assert midnight == sun.get_astral_event_date(
|
||||
self.hass, 'solar_midnight', utc_today)
|
||||
hass, 'solar_midnight', utc_today)
|
||||
assert noon == sun.get_astral_event_date(
|
||||
self.hass, 'solar_noon', utc_today)
|
||||
hass, 'solar_noon', utc_today)
|
||||
assert sunrise == sun.get_astral_event_date(
|
||||
self.hass, SUN_EVENT_SUNRISE, utc_today)
|
||||
hass, SUN_EVENT_SUNRISE, utc_today)
|
||||
assert sunset == sun.get_astral_event_date(
|
||||
self.hass, SUN_EVENT_SUNSET, utc_today)
|
||||
hass, SUN_EVENT_SUNSET, utc_today)
|
||||
|
||||
def test_date_events_default_date(self):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
def test_date_events_accepts_datetime(hass):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
|
||||
latitude = self.hass.config.latitude
|
||||
longitude = self.hass.config.longitude
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
|
||||
dawn = astral.dawn_utc(utc_today, latitude, longitude)
|
||||
dusk = astral.dusk_utc(utc_today, latitude, longitude)
|
||||
midnight = astral.solar_midnight_utc(utc_today, longitude)
|
||||
noon = astral.solar_noon_utc(utc_today, longitude)
|
||||
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
|
||||
sunset = astral.sunset_utc(utc_today, latitude, longitude)
|
||||
latitude = hass.config.latitude
|
||||
longitude = hass.config.longitude
|
||||
|
||||
with patch('homeassistant.util.dt.now', return_value=utc_now):
|
||||
assert dawn == sun.get_astral_event_date(
|
||||
self.hass, 'dawn', utc_today)
|
||||
assert dusk == sun.get_astral_event_date(
|
||||
self.hass, 'dusk', utc_today)
|
||||
assert midnight == sun.get_astral_event_date(
|
||||
self.hass, 'solar_midnight', utc_today)
|
||||
assert noon == sun.get_astral_event_date(
|
||||
self.hass, 'solar_noon', utc_today)
|
||||
assert sunrise == sun.get_astral_event_date(
|
||||
self.hass, SUN_EVENT_SUNRISE, utc_today)
|
||||
assert sunset == sun.get_astral_event_date(
|
||||
self.hass, SUN_EVENT_SUNSET, utc_today)
|
||||
dawn = astral.dawn_utc(utc_today, latitude, longitude)
|
||||
dusk = astral.dusk_utc(utc_today, latitude, longitude)
|
||||
midnight = astral.solar_midnight_utc(utc_today, longitude)
|
||||
noon = astral.solar_noon_utc(utc_today, longitude)
|
||||
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
|
||||
sunset = astral.sunset_utc(utc_today, latitude, longitude)
|
||||
|
||||
def test_date_events_accepts_datetime(self):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 8, 0, 0, tzinfo=dt_util.UTC)
|
||||
from astral import Astral
|
||||
assert dawn == sun.get_astral_event_date(
|
||||
hass, 'dawn', utc_now)
|
||||
assert dusk == sun.get_astral_event_date(
|
||||
hass, 'dusk', utc_now)
|
||||
assert midnight == sun.get_astral_event_date(
|
||||
hass, 'solar_midnight', utc_now)
|
||||
assert noon == sun.get_astral_event_date(
|
||||
hass, 'solar_noon', utc_now)
|
||||
assert sunrise == sun.get_astral_event_date(
|
||||
hass, SUN_EVENT_SUNRISE, utc_now)
|
||||
assert sunset == sun.get_astral_event_date(
|
||||
hass, SUN_EVENT_SUNSET, utc_now)
|
||||
|
||||
astral = Astral()
|
||||
utc_today = utc_now.date()
|
||||
|
||||
latitude = self.hass.config.latitude
|
||||
longitude = self.hass.config.longitude
|
||||
def test_is_up(hass):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 12, 0, 0, tzinfo=dt_util.UTC)
|
||||
with patch('homeassistant.helpers.condition.dt_util.utcnow',
|
||||
return_value=utc_now):
|
||||
assert not sun.is_up(hass)
|
||||
|
||||
dawn = astral.dawn_utc(utc_today, latitude, longitude)
|
||||
dusk = astral.dusk_utc(utc_today, latitude, longitude)
|
||||
midnight = astral.solar_midnight_utc(utc_today, longitude)
|
||||
noon = astral.solar_noon_utc(utc_today, longitude)
|
||||
sunrise = astral.sunrise_utc(utc_today, latitude, longitude)
|
||||
sunset = astral.sunset_utc(utc_today, latitude, longitude)
|
||||
utc_now = datetime(2016, 11, 1, 18, 0, 0, tzinfo=dt_util.UTC)
|
||||
with patch('homeassistant.helpers.condition.dt_util.utcnow',
|
||||
return_value=utc_now):
|
||||
assert sun.is_up(hass)
|
||||
|
||||
assert dawn == sun.get_astral_event_date(
|
||||
self.hass, 'dawn', utc_now)
|
||||
assert dusk == sun.get_astral_event_date(
|
||||
self.hass, 'dusk', utc_now)
|
||||
assert midnight == sun.get_astral_event_date(
|
||||
self.hass, 'solar_midnight', utc_now)
|
||||
assert noon == sun.get_astral_event_date(
|
||||
self.hass, 'solar_noon', utc_now)
|
||||
assert sunrise == sun.get_astral_event_date(
|
||||
self.hass, SUN_EVENT_SUNRISE, utc_now)
|
||||
assert sunset == sun.get_astral_event_date(
|
||||
self.hass, SUN_EVENT_SUNSET, utc_now)
|
||||
|
||||
def test_is_up(self):
|
||||
"""Test retrieving next sun events."""
|
||||
utc_now = datetime(2016, 11, 1, 12, 0, 0, tzinfo=dt_util.UTC)
|
||||
with patch('homeassistant.helpers.condition.dt_util.utcnow',
|
||||
return_value=utc_now):
|
||||
assert not sun.is_up(self.hass)
|
||||
def test_norway_in_june(hass):
|
||||
"""Test location in Norway where the sun doesn't set in summer."""
|
||||
hass.config.latitude = 69.6
|
||||
hass.config.longitude = 18.8
|
||||
|
||||
utc_now = datetime(2016, 11, 1, 18, 0, 0, tzinfo=dt_util.UTC)
|
||||
with patch('homeassistant.helpers.condition.dt_util.utcnow',
|
||||
return_value=utc_now):
|
||||
assert sun.is_up(self.hass)
|
||||
june = datetime(2016, 6, 1, tzinfo=dt_util.UTC)
|
||||
|
||||
def test_norway_in_june(self):
|
||||
"""Test location in Norway where the sun doesn't set in summer."""
|
||||
self.hass.config.latitude = 69.6
|
||||
self.hass.config.longitude = 18.8
|
||||
print(sun.get_astral_event_date(hass, SUN_EVENT_SUNRISE,
|
||||
datetime(2017, 7, 25)))
|
||||
print(sun.get_astral_event_date(hass, SUN_EVENT_SUNSET,
|
||||
datetime(2017, 7, 25)))
|
||||
|
||||
june = datetime(2016, 6, 1, tzinfo=dt_util.UTC)
|
||||
print(sun.get_astral_event_date(hass, SUN_EVENT_SUNRISE,
|
||||
datetime(2017, 7, 26)))
|
||||
print(sun.get_astral_event_date(hass, SUN_EVENT_SUNSET,
|
||||
datetime(2017, 7, 26)))
|
||||
|
||||
print(sun.get_astral_event_date(self.hass, SUN_EVENT_SUNRISE,
|
||||
datetime(2017, 7, 25)))
|
||||
print(sun.get_astral_event_date(self.hass, SUN_EVENT_SUNSET,
|
||||
datetime(2017, 7, 25)))
|
||||
|
||||
print(sun.get_astral_event_date(self.hass, SUN_EVENT_SUNRISE,
|
||||
datetime(2017, 7, 26)))
|
||||
print(sun.get_astral_event_date(self.hass, SUN_EVENT_SUNSET,
|
||||
datetime(2017, 7, 26)))
|
||||
|
||||
assert sun.get_astral_event_next(self.hass, SUN_EVENT_SUNRISE, june) \
|
||||
== datetime(2016, 7, 25, 23, 23, 39, tzinfo=dt_util.UTC)
|
||||
assert sun.get_astral_event_next(self.hass, SUN_EVENT_SUNSET, june) \
|
||||
== datetime(2016, 7, 26, 22, 19, 1, tzinfo=dt_util.UTC)
|
||||
assert sun.get_astral_event_date(self.hass, SUN_EVENT_SUNRISE, june) \
|
||||
is None
|
||||
assert sun.get_astral_event_date(self.hass, SUN_EVENT_SUNSET, june) \
|
||||
is None
|
||||
assert sun.get_astral_event_next(hass, SUN_EVENT_SUNRISE, june) \
|
||||
== datetime(2016, 7, 25, 23, 23, 39, tzinfo=dt_util.UTC)
|
||||
assert sun.get_astral_event_next(hass, SUN_EVENT_SUNSET, june) \
|
||||
== datetime(2016, 7, 26, 22, 19, 1, tzinfo=dt_util.UTC)
|
||||
assert sun.get_astral_event_date(hass, SUN_EVENT_SUNRISE, june) \
|
||||
is None
|
||||
assert sun.get_astral_event_date(hass, SUN_EVENT_SUNSET, june) \
|
||||
is None
|
||||
|
|
|
@ -1,50 +1,34 @@
|
|||
"""Tests Home Assistant temperature helpers."""
|
||||
import unittest
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
import pytest
|
||||
|
||||
from homeassistant.const import (
|
||||
TEMP_CELSIUS, PRECISION_WHOLE, TEMP_FAHRENHEIT, PRECISION_HALVES,
|
||||
PRECISION_TENTHS)
|
||||
from homeassistant.helpers.temperature import display_temp
|
||||
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||
import pytest
|
||||
|
||||
TEMP = 24.636626
|
||||
|
||||
|
||||
class TestHelpersTemperature(unittest.TestCase):
|
||||
"""Set up the temperature tests."""
|
||||
def test_temperature_not_a_number(hass):
|
||||
"""Test that temperature is a number."""
|
||||
temp = "Temperature"
|
||||
with pytest.raises(Exception) as exception:
|
||||
display_temp(hass, temp, TEMP_CELSIUS, PRECISION_HALVES)
|
||||
|
||||
def setUp(self):
|
||||
"""Set up the tests."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.unit_system = METRIC_SYSTEM
|
||||
assert "Temperature is not a number: {}".format(temp) \
|
||||
in str(exception)
|
||||
|
||||
def tearDown(self):
|
||||
"""Stop down stuff we started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_temperature_not_a_number(self):
|
||||
"""Test that temperature is a number."""
|
||||
temp = "Temperature"
|
||||
with pytest.raises(Exception) as exception:
|
||||
display_temp(self.hass, temp, TEMP_CELSIUS, PRECISION_HALVES)
|
||||
def test_celsius_halves(hass):
|
||||
"""Test temperature to celsius rounding to halves."""
|
||||
assert display_temp(hass, TEMP, TEMP_CELSIUS, PRECISION_HALVES) == 24.5
|
||||
|
||||
assert "Temperature is not a number: {}".format(temp) \
|
||||
in str(exception)
|
||||
|
||||
def test_celsius_halves(self):
|
||||
"""Test temperature to celsius rounding to halves."""
|
||||
assert 24.5 == display_temp(
|
||||
self.hass, TEMP, TEMP_CELSIUS, PRECISION_HALVES)
|
||||
def test_celsius_tenths(hass):
|
||||
"""Test temperature to celsius rounding to tenths."""
|
||||
assert display_temp(hass, TEMP, TEMP_CELSIUS, PRECISION_TENTHS) == 24.6
|
||||
|
||||
def test_celsius_tenths(self):
|
||||
"""Test temperature to celsius rounding to tenths."""
|
||||
assert 24.6 == display_temp(
|
||||
self.hass, TEMP, TEMP_CELSIUS, PRECISION_TENTHS)
|
||||
|
||||
def test_fahrenheit_wholes(self):
|
||||
"""Test temperature to fahrenheit rounding to wholes."""
|
||||
assert -4 == display_temp(
|
||||
self.hass, TEMP, TEMP_FAHRENHEIT, PRECISION_WHOLE)
|
||||
def test_fahrenheit_wholes(hass):
|
||||
"""Test temperature to fahrenheit rounding to wholes."""
|
||||
assert display_temp(hass, TEMP, TEMP_FAHRENHEIT, PRECISION_WHOLE) == -4
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,6 @@
|
|||
"""Test check_config script."""
|
||||
import asyncio
|
||||
import logging
|
||||
import os # noqa: F401 pylint: disable=unused-import
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import homeassistant.scripts.check_config as check_config
|
||||
|
@ -36,149 +34,138 @@ def normalize_yaml_files(check_dict):
|
|||
for key in sorted(check_dict['yaml_files'].keys())]
|
||||
|
||||
|
||||
# pylint: disable=unsubscriptable-object
|
||||
class TestCheckConfig(unittest.TestCase):
|
||||
"""Tests for the homeassistant.scripts.check_config module."""
|
||||
# pylint: disable=no-self-use,invalid-name
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_bad_core_config(isfile_patch, loop):
|
||||
"""Test a bad core config setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BAD_CORE_CONFIG,
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['except'].keys() == {'homeassistant'}
|
||||
assert res['except']['homeassistant'][1] == {'unit_system': 'bad'}
|
||||
|
||||
def setUp(self):
|
||||
"""Prepare the test."""
|
||||
# Somewhere in the tests our event loop gets killed,
|
||||
# this ensures we have one.
|
||||
try:
|
||||
asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
|
||||
# Will allow seeing full diff
|
||||
self.maxDiff = None # pylint: disable=invalid-name
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_config_platform_valid(isfile_patch, loop):
|
||||
"""Test a valid platform setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: demo',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['components'].keys() == {'homeassistant', 'light'}
|
||||
assert res['components']['light'] == [{'platform': 'demo'}]
|
||||
assert res['except'] == {}
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
|
||||
# pylint: disable=no-self-use,invalid-name
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_bad_core_config(self, isfile_patch):
|
||||
"""Test a bad core config setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BAD_CORE_CONFIG,
|
||||
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_component_platform_not_found(isfile_patch, loop):
|
||||
"""Test errors if component or platform not found."""
|
||||
# Make sure they don't exist
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'beer:',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['components'].keys() == {'homeassistant'}
|
||||
assert res['except'] == {
|
||||
check_config.ERROR_STR: ['Integration not found: beer']}
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: beer',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['components'].keys() == {'homeassistant', 'light'}
|
||||
assert res['components']['light'] == []
|
||||
assert res['except'] == {
|
||||
check_config.ERROR_STR: [
|
||||
'Integration beer not found when trying to verify its '
|
||||
'light platform.',
|
||||
]}
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
|
||||
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_secrets(isfile_patch, loop):
|
||||
"""Test secrets config checking method."""
|
||||
secrets_path = get_test_config_dir('secrets.yaml')
|
||||
|
||||
files = {
|
||||
get_test_config_dir(YAML_CONFIG_FILE): BASE_CONFIG + (
|
||||
'http:\n'
|
||||
' api_password: !secret http_pw'),
|
||||
secrets_path: (
|
||||
'logger: debug\n'
|
||||
'http_pw: abc123'),
|
||||
}
|
||||
|
||||
with patch_yaml_files(files):
|
||||
|
||||
res = check_config.check(get_test_config_dir(), True)
|
||||
|
||||
assert res['except'] == {}
|
||||
assert res['components'].keys() == {'homeassistant', 'http'}
|
||||
assert res['components']['http'] == {
|
||||
'api_password': 'abc123',
|
||||
'cors_allowed_origins': [],
|
||||
'ip_ban_enabled': True,
|
||||
'login_attempts_threshold': -1,
|
||||
'server_host': '0.0.0.0',
|
||||
'server_port': 8123,
|
||||
'trusted_networks': [],
|
||||
'ssl_profile': 'modern',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['except'].keys() == {'homeassistant'}
|
||||
assert res['except']['homeassistant'][1] == {'unit_system': 'bad'}
|
||||
assert res['secret_cache'] == {secrets_path: {'http_pw': 'abc123'}}
|
||||
assert res['secrets'] == {'http_pw': 'abc123'}
|
||||
assert normalize_yaml_files(res) == [
|
||||
'.../configuration.yaml', '.../secrets.yaml']
|
||||
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_config_platform_valid(self, isfile_patch):
|
||||
"""Test a valid platform setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: demo',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['components'].keys() == {'homeassistant', 'light'}
|
||||
assert res['components']['light'] == [{'platform': 'demo'}]
|
||||
assert res['except'] == {}
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_component_platform_not_found(self, isfile_patch):
|
||||
"""Test errors if component or platform not found."""
|
||||
# Make sure they don't exist
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'beer:',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['components'].keys() == {'homeassistant'}
|
||||
assert res['except'] == {
|
||||
check_config.ERROR_STR: ['Integration not found: beer']}
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_package_invalid(isfile_patch, loop):
|
||||
"""Test a valid platform setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + (
|
||||
' packages:\n'
|
||||
' p1:\n'
|
||||
' group: ["a"]'),
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: beer',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
assert res['components'].keys() == {'homeassistant', 'light'}
|
||||
assert res['components']['light'] == []
|
||||
assert res['except'] == {
|
||||
check_config.ERROR_STR: [
|
||||
'Integration beer not found when trying to verify its '
|
||||
'light platform.',
|
||||
]}
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
assert res['except'].keys() == {'homeassistant.packages.p1.group'}
|
||||
assert res['except']['homeassistant.packages.p1.group'][1] == \
|
||||
{'group': ['a']}
|
||||
assert len(res['except']) == 1
|
||||
assert res['components'].keys() == {'homeassistant'}
|
||||
assert len(res['components']) == 1
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_secrets(self, isfile_patch):
|
||||
"""Test secrets config checking method."""
|
||||
secrets_path = get_test_config_dir('secrets.yaml')
|
||||
|
||||
files = {
|
||||
get_test_config_dir(YAML_CONFIG_FILE): BASE_CONFIG + (
|
||||
'http:\n'
|
||||
' api_password: !secret http_pw'),
|
||||
secrets_path: (
|
||||
'logger: debug\n'
|
||||
'http_pw: abc123'),
|
||||
}
|
||||
|
||||
with patch_yaml_files(files):
|
||||
|
||||
res = check_config.check(get_test_config_dir(), True)
|
||||
|
||||
assert res['except'] == {}
|
||||
assert res['components'].keys() == {'homeassistant', 'http'}
|
||||
assert res['components']['http'] == {
|
||||
'api_password': 'abc123',
|
||||
'cors_allowed_origins': [],
|
||||
'ip_ban_enabled': True,
|
||||
'login_attempts_threshold': -1,
|
||||
'server_host': '0.0.0.0',
|
||||
'server_port': 8123,
|
||||
'trusted_networks': [],
|
||||
'ssl_profile': 'modern',
|
||||
}
|
||||
assert res['secret_cache'] == {secrets_path: {'http_pw': 'abc123'}}
|
||||
assert res['secrets'] == {'http_pw': 'abc123'}
|
||||
assert normalize_yaml_files(res) == [
|
||||
'.../configuration.yaml', '.../secrets.yaml']
|
||||
|
||||
@patch('os.path.isfile', return_value=True)
|
||||
def test_package_invalid(self, isfile_patch):
|
||||
"""Test a valid platform setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + (
|
||||
' packages:\n'
|
||||
' p1:\n'
|
||||
' group: ["a"]'),
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir())
|
||||
|
||||
assert res['except'].keys() == {'homeassistant.packages.p1.group'}
|
||||
assert res['except']['homeassistant.packages.p1.group'][1] == \
|
||||
{'group': ['a']}
|
||||
assert len(res['except']) == 1
|
||||
assert res['components'].keys() == {'homeassistant'}
|
||||
assert len(res['components']) == 1
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert len(res['yaml_files']) == 1
|
||||
|
||||
def test_bootstrap_error(self):
|
||||
"""Test a valid platform setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'automation: !include no.yaml',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir(YAML_CONFIG_FILE))
|
||||
err = res['except'].pop(check_config.ERROR_STR)
|
||||
assert len(err) == 1
|
||||
assert res['except'] == {}
|
||||
assert res['components'] == {} # No components, load failed
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert res['yaml_files'] == {}
|
||||
def test_bootstrap_error(loop):
|
||||
"""Test a valid platform setup."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + 'automation: !include no.yaml',
|
||||
}
|
||||
with patch_yaml_files(files):
|
||||
res = check_config.check(get_test_config_dir(YAML_CONFIG_FILE))
|
||||
err = res['except'].pop(check_config.ERROR_STR)
|
||||
assert len(err) == 1
|
||||
assert res['except'] == {}
|
||||
assert res['components'] == {} # No components, load failed
|
||||
assert res['secret_cache'] == {}
|
||||
assert res['secrets'] == {}
|
||||
assert res['yaml_files'] == {}
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
"""Test script init."""
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import homeassistant.scripts as scripts
|
||||
|
||||
|
||||
class TestScripts(unittest.TestCase):
|
||||
"""Tests homeassistant.scripts module."""
|
||||
|
||||
@patch('homeassistant.scripts.get_default_config_dir',
|
||||
return_value='/default')
|
||||
def test_config_per_platform(self, mock_def):
|
||||
"""Test config per platform method."""
|
||||
self.assertEqual(scripts.get_default_config_dir(), '/default')
|
||||
self.assertEqual(scripts.extract_config_dir(), '/default')
|
||||
self.assertEqual(scripts.extract_config_dir(['']), '/default')
|
||||
self.assertEqual(scripts.extract_config_dir(['-c', '/arg']), '/arg')
|
||||
self.assertEqual(scripts.extract_config_dir(['--config', '/a']), '/a')
|
||||
@patch('homeassistant.scripts.get_default_config_dir',
|
||||
return_value='/default')
|
||||
def test_config_per_platform(mock_def):
|
||||
"""Test config per platform method."""
|
||||
assert scripts.get_default_config_dir() == '/default'
|
||||
assert scripts.extract_config_dir() == '/default'
|
||||
assert scripts.extract_config_dir(['']) == '/default'
|
||||
assert scripts.extract_config_dir(['-c', '/arg']) == '/arg'
|
||||
assert scripts.extract_config_dir(['--config', '/a']) == '/a'
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# pylint: disable=protected-access
|
||||
import asyncio
|
||||
import os
|
||||
import unittest
|
||||
import unittest.mock as mock
|
||||
from collections import OrderedDict
|
||||
from ipaddress import ip_network
|
||||
|
@ -23,7 +22,6 @@ from homeassistant.const import (
|
|||
CONF_AUTH_PROVIDERS, CONF_AUTH_MFA_MODULES)
|
||||
from homeassistant.util import location as location_util, dt as dt_util
|
||||
from homeassistant.util.yaml import SECRET_YAML
|
||||
from homeassistant.util.async_ import run_coroutine_threadsafe
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.components.config.group import (
|
||||
CONFIG_PATH as GROUP_CONFIG_PATH)
|
||||
|
@ -36,7 +34,7 @@ from homeassistant.components.config.customize import (
|
|||
import homeassistant.scripts.check_config as check_config
|
||||
|
||||
from tests.common import (
|
||||
get_test_config_dir, get_test_home_assistant, patch_yaml_files)
|
||||
get_test_config_dir, patch_yaml_files)
|
||||
|
||||
CONFIG_DIR = get_test_config_dir()
|
||||
YAML_PATH = os.path.join(CONFIG_DIR, config_util.YAML_CONFIG_FILE)
|
||||
|
@ -55,512 +53,508 @@ def create_file(path):
|
|||
pass
|
||||
|
||||
|
||||
class TestConfig(unittest.TestCase):
|
||||
"""Test the configutils."""
|
||||
def teardown():
|
||||
"""Clean up."""
|
||||
dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def setUp(self):
|
||||
"""Initialize a test Home Assistant instance."""
|
||||
self.hass = get_test_home_assistant()
|
||||
if os.path.isfile(YAML_PATH):
|
||||
os.remove(YAML_PATH)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def tearDown(self):
|
||||
"""Clean up."""
|
||||
dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE
|
||||
if os.path.isfile(SECRET_PATH):
|
||||
os.remove(SECRET_PATH)
|
||||
|
||||
if os.path.isfile(YAML_PATH):
|
||||
os.remove(YAML_PATH)
|
||||
if os.path.isfile(VERSION_PATH):
|
||||
os.remove(VERSION_PATH)
|
||||
|
||||
if os.path.isfile(SECRET_PATH):
|
||||
os.remove(SECRET_PATH)
|
||||
if os.path.isfile(GROUP_PATH):
|
||||
os.remove(GROUP_PATH)
|
||||
|
||||
if os.path.isfile(VERSION_PATH):
|
||||
os.remove(VERSION_PATH)
|
||||
if os.path.isfile(AUTOMATIONS_PATH):
|
||||
os.remove(AUTOMATIONS_PATH)
|
||||
|
||||
if os.path.isfile(GROUP_PATH):
|
||||
os.remove(GROUP_PATH)
|
||||
if os.path.isfile(SCRIPTS_PATH):
|
||||
os.remove(SCRIPTS_PATH)
|
||||
|
||||
if os.path.isfile(AUTOMATIONS_PATH):
|
||||
os.remove(AUTOMATIONS_PATH)
|
||||
if os.path.isfile(CUSTOMIZE_PATH):
|
||||
os.remove(CUSTOMIZE_PATH)
|
||||
|
||||
if os.path.isfile(SCRIPTS_PATH):
|
||||
os.remove(SCRIPTS_PATH)
|
||||
|
||||
if os.path.isfile(CUSTOMIZE_PATH):
|
||||
os.remove(CUSTOMIZE_PATH)
|
||||
def test_create_default_config():
|
||||
"""Test creation of default config."""
|
||||
config_util.create_default_config(CONFIG_DIR, False)
|
||||
|
||||
self.hass.stop()
|
||||
assert os.path.isfile(YAML_PATH)
|
||||
assert os.path.isfile(SECRET_PATH)
|
||||
assert os.path.isfile(VERSION_PATH)
|
||||
assert os.path.isfile(GROUP_PATH)
|
||||
assert os.path.isfile(AUTOMATIONS_PATH)
|
||||
assert os.path.isfile(CUSTOMIZE_PATH)
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
def test_create_default_config(self):
|
||||
"""Test creation of default config."""
|
||||
config_util.create_default_config(CONFIG_DIR, False)
|
||||
|
||||
assert os.path.isfile(YAML_PATH)
|
||||
assert os.path.isfile(SECRET_PATH)
|
||||
assert os.path.isfile(VERSION_PATH)
|
||||
assert os.path.isfile(GROUP_PATH)
|
||||
assert os.path.isfile(AUTOMATIONS_PATH)
|
||||
assert os.path.isfile(CUSTOMIZE_PATH)
|
||||
def test_find_config_file_yaml():
|
||||
"""Test if it finds a YAML config file."""
|
||||
create_file(YAML_PATH)
|
||||
|
||||
def test_find_config_file_yaml(self):
|
||||
"""Test if it finds a YAML config file."""
|
||||
create_file(YAML_PATH)
|
||||
assert YAML_PATH == config_util.find_config_file(CONFIG_DIR)
|
||||
|
||||
assert YAML_PATH == config_util.find_config_file(CONFIG_DIR)
|
||||
|
||||
@mock.patch('builtins.print')
|
||||
def test_ensure_config_exists_creates_config(self, mock_print):
|
||||
"""Test that calling ensure_config_exists.
|
||||
@mock.patch('builtins.print')
|
||||
def test_ensure_config_exists_creates_config(mock_print):
|
||||
"""Test that calling ensure_config_exists.
|
||||
|
||||
If not creates a new config file.
|
||||
"""
|
||||
config_util.ensure_config_exists(CONFIG_DIR, False)
|
||||
If not creates a new config file.
|
||||
"""
|
||||
config_util.ensure_config_exists(CONFIG_DIR, False)
|
||||
|
||||
assert os.path.isfile(YAML_PATH)
|
||||
assert mock_print.called
|
||||
assert os.path.isfile(YAML_PATH)
|
||||
assert mock_print.called
|
||||
|
||||
def test_ensure_config_exists_uses_existing_config(self):
|
||||
"""Test that calling ensure_config_exists uses existing config."""
|
||||
create_file(YAML_PATH)
|
||||
config_util.ensure_config_exists(CONFIG_DIR, False)
|
||||
|
||||
with open(YAML_PATH) as f:
|
||||
content = f.read()
|
||||
def test_ensure_config_exists_uses_existing_config():
|
||||
"""Test that calling ensure_config_exists uses existing config."""
|
||||
create_file(YAML_PATH)
|
||||
config_util.ensure_config_exists(CONFIG_DIR, False)
|
||||
|
||||
# File created with create_file are empty
|
||||
assert '' == content
|
||||
with open(YAML_PATH) as f:
|
||||
content = f.read()
|
||||
|
||||
def test_load_yaml_config_converts_empty_files_to_dict(self):
|
||||
"""Test that loading an empty file returns an empty dict."""
|
||||
create_file(YAML_PATH)
|
||||
# File created with create_file are empty
|
||||
assert content == ''
|
||||
|
||||
assert isinstance(config_util.load_yaml_config_file(YAML_PATH), dict)
|
||||
|
||||
def test_load_yaml_config_raises_error_if_not_dict(self):
|
||||
"""Test error raised when YAML file is not a dict."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write('5')
|
||||
def test_load_yaml_config_converts_empty_files_to_dict():
|
||||
"""Test that loading an empty file returns an empty dict."""
|
||||
create_file(YAML_PATH)
|
||||
|
||||
with pytest.raises(HomeAssistantError):
|
||||
config_util.load_yaml_config_file(YAML_PATH)
|
||||
assert isinstance(config_util.load_yaml_config_file(YAML_PATH), dict)
|
||||
|
||||
def test_load_yaml_config_raises_error_if_malformed_yaml(self):
|
||||
"""Test error raised if invalid YAML."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write(':')
|
||||
|
||||
with pytest.raises(HomeAssistantError):
|
||||
config_util.load_yaml_config_file(YAML_PATH)
|
||||
def test_load_yaml_config_raises_error_if_not_dict():
|
||||
"""Test error raised when YAML file is not a dict."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write('5')
|
||||
|
||||
def test_load_yaml_config_raises_error_if_unsafe_yaml(self):
|
||||
"""Test error raised if unsafe YAML."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write('hello: !!python/object/apply:os.system')
|
||||
with pytest.raises(HomeAssistantError):
|
||||
config_util.load_yaml_config_file(YAML_PATH)
|
||||
|
||||
with pytest.raises(HomeAssistantError):
|
||||
config_util.load_yaml_config_file(YAML_PATH)
|
||||
|
||||
def test_load_yaml_config_preserves_key_order(self):
|
||||
"""Test removal of library."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write('hello: 2\n')
|
||||
f.write('world: 1\n')
|
||||
def test_load_yaml_config_raises_error_if_malformed_yaml():
|
||||
"""Test error raised if invalid YAML."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write(':')
|
||||
|
||||
assert [('hello', 2), ('world', 1)] == \
|
||||
list(config_util.load_yaml_config_file(YAML_PATH).items())
|
||||
with pytest.raises(HomeAssistantError):
|
||||
config_util.load_yaml_config_file(YAML_PATH)
|
||||
|
||||
@mock.patch('homeassistant.util.location.detect_location_info',
|
||||
return_value=location_util.LocationInfo(
|
||||
'0.0.0.0', 'US', 'United States', 'CA', 'California',
|
||||
'San Diego', '92122', 'America/Los_Angeles', 32.8594,
|
||||
-117.2073, True))
|
||||
@mock.patch('homeassistant.util.location.elevation', return_value=101)
|
||||
@mock.patch('builtins.print')
|
||||
def test_create_default_config_detect_location(self, mock_detect,
|
||||
mock_elev, mock_print):
|
||||
"""Test that detect location sets the correct config keys."""
|
||||
config_util.ensure_config_exists(CONFIG_DIR)
|
||||
|
||||
config = config_util.load_yaml_config_file(YAML_PATH)
|
||||
def test_load_yaml_config_raises_error_if_unsafe_yaml():
|
||||
"""Test error raised if unsafe YAML."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write('hello: !!python/object/apply:os.system')
|
||||
|
||||
assert DOMAIN in config
|
||||
with pytest.raises(HomeAssistantError):
|
||||
config_util.load_yaml_config_file(YAML_PATH)
|
||||
|
||||
ha_conf = config[DOMAIN]
|
||||
|
||||
expected_values = {
|
||||
CONF_LATITUDE: 32.8594,
|
||||
CONF_LONGITUDE: -117.2073,
|
||||
CONF_ELEVATION: 101,
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
|
||||
CONF_NAME: 'Home',
|
||||
CONF_TIME_ZONE: 'America/Los_Angeles',
|
||||
CONF_CUSTOMIZE: OrderedDict(),
|
||||
}
|
||||
def test_load_yaml_config_preserves_key_order():
|
||||
"""Test removal of library."""
|
||||
with open(YAML_PATH, 'w') as f:
|
||||
f.write('hello: 2\n')
|
||||
f.write('world: 1\n')
|
||||
|
||||
assert expected_values == ha_conf
|
||||
assert mock_print.called
|
||||
assert [('hello', 2), ('world', 1)] == \
|
||||
list(config_util.load_yaml_config_file(YAML_PATH).items())
|
||||
|
||||
@mock.patch('builtins.print')
|
||||
def test_create_default_config_returns_none_if_write_error(self,
|
||||
mock_print):
|
||||
"""Test the writing of a default configuration.
|
||||
|
||||
Non existing folder returns None.
|
||||
"""
|
||||
assert config_util.create_default_config(
|
||||
os.path.join(CONFIG_DIR, 'non_existing_dir/'), False) is None
|
||||
assert mock_print.called
|
||||
@mock.patch('homeassistant.util.location.detect_location_info',
|
||||
return_value=location_util.LocationInfo(
|
||||
'0.0.0.0', 'US', 'United States', 'CA', 'California',
|
||||
'San Diego', '92122', 'America/Los_Angeles', 32.8594,
|
||||
-117.2073, True))
|
||||
@mock.patch('homeassistant.util.location.elevation', return_value=101)
|
||||
@mock.patch('builtins.print')
|
||||
def test_create_default_config_detect_location(mock_detect,
|
||||
mock_elev, mock_print):
|
||||
"""Test that detect location sets the correct config keys."""
|
||||
config_util.ensure_config_exists(CONFIG_DIR)
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
def test_core_config_schema(self):
|
||||
"""Test core config schema."""
|
||||
for value in (
|
||||
{CONF_UNIT_SYSTEM: 'K'},
|
||||
{'time_zone': 'non-exist'},
|
||||
{'latitude': '91'},
|
||||
{'longitude': -181},
|
||||
{'customize': 'bla'},
|
||||
{'customize': {'light.sensor': 100}},
|
||||
{'customize': {'entity_id': []}},
|
||||
):
|
||||
with pytest.raises(MultipleInvalid):
|
||||
config_util.CORE_CONFIG_SCHEMA(value)
|
||||
config = config_util.load_yaml_config_file(YAML_PATH)
|
||||
|
||||
config_util.CORE_CONFIG_SCHEMA({
|
||||
'name': 'Test name',
|
||||
'latitude': '-23.45',
|
||||
'longitude': '123.45',
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
|
||||
'customize': {
|
||||
'sensor.temperature': {
|
||||
'hidden': True,
|
||||
},
|
||||
assert DOMAIN in config
|
||||
|
||||
ha_conf = config[DOMAIN]
|
||||
|
||||
expected_values = {
|
||||
CONF_LATITUDE: 32.8594,
|
||||
CONF_LONGITUDE: -117.2073,
|
||||
CONF_ELEVATION: 101,
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
|
||||
CONF_NAME: 'Home',
|
||||
CONF_TIME_ZONE: 'America/Los_Angeles',
|
||||
CONF_CUSTOMIZE: OrderedDict(),
|
||||
}
|
||||
|
||||
assert expected_values == ha_conf
|
||||
assert mock_print.called
|
||||
|
||||
|
||||
@mock.patch('builtins.print')
|
||||
def test_create_default_config_returns_none_if_write_error(mock_print):
|
||||
"""Test the writing of a default configuration.
|
||||
|
||||
Non existing folder returns None.
|
||||
"""
|
||||
assert config_util.create_default_config(
|
||||
os.path.join(CONFIG_DIR, 'non_existing_dir/'), False) is None
|
||||
assert mock_print.called
|
||||
|
||||
|
||||
def test_core_config_schema():
|
||||
"""Test core config schema."""
|
||||
for value in (
|
||||
{CONF_UNIT_SYSTEM: 'K'},
|
||||
{'time_zone': 'non-exist'},
|
||||
{'latitude': '91'},
|
||||
{'longitude': -181},
|
||||
{'customize': 'bla'},
|
||||
{'customize': {'light.sensor': 100}},
|
||||
{'customize': {'entity_id': []}},
|
||||
):
|
||||
with pytest.raises(MultipleInvalid):
|
||||
config_util.CORE_CONFIG_SCHEMA(value)
|
||||
|
||||
config_util.CORE_CONFIG_SCHEMA({
|
||||
'name': 'Test name',
|
||||
'latitude': '-23.45',
|
||||
'longitude': '123.45',
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
|
||||
'customize': {
|
||||
'sensor.temperature': {
|
||||
'hidden': True,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
def test_customize_dict_schema():
|
||||
"""Test basic customize config validation."""
|
||||
values = (
|
||||
{ATTR_FRIENDLY_NAME: None},
|
||||
{ATTR_HIDDEN: '2'},
|
||||
{ATTR_ASSUMED_STATE: '2'},
|
||||
)
|
||||
|
||||
for val in values:
|
||||
print(val)
|
||||
with pytest.raises(MultipleInvalid):
|
||||
config_util.CUSTOMIZE_DICT_SCHEMA(val)
|
||||
|
||||
assert config_util.CUSTOMIZE_DICT_SCHEMA({
|
||||
ATTR_FRIENDLY_NAME: 2,
|
||||
ATTR_HIDDEN: '1',
|
||||
ATTR_ASSUMED_STATE: '0',
|
||||
}) == {
|
||||
ATTR_FRIENDLY_NAME: '2',
|
||||
ATTR_HIDDEN: True,
|
||||
ATTR_ASSUMED_STATE: False
|
||||
}
|
||||
|
||||
|
||||
def test_customize_glob_is_ordered():
|
||||
"""Test that customize_glob preserves order."""
|
||||
conf = config_util.CORE_CONFIG_SCHEMA(
|
||||
{'customize_glob': OrderedDict()})
|
||||
assert isinstance(conf['customize_glob'], OrderedDict)
|
||||
|
||||
|
||||
async def _compute_state(hass, config):
|
||||
await config_util.async_process_ha_core_config(hass, config)
|
||||
|
||||
entity = Entity()
|
||||
entity.entity_id = 'test.test'
|
||||
entity.hass = hass
|
||||
entity.schedule_update_ha_state()
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return hass.states.get('test.test')
|
||||
|
||||
|
||||
async def test_entity_customization(hass):
|
||||
"""Test entity customization through configuration."""
|
||||
config = {CONF_LATITUDE: 50,
|
||||
CONF_LONGITUDE: 50,
|
||||
CONF_NAME: 'Test',
|
||||
CONF_CUSTOMIZE: {'test.test': {'hidden': True}}}
|
||||
|
||||
state = await _compute_state(hass, config)
|
||||
|
||||
assert state.attributes['hidden']
|
||||
|
||||
|
||||
@mock.patch('homeassistant.config.shutil')
|
||||
@mock.patch('homeassistant.config.os')
|
||||
def test_remove_lib_on_upgrade(mock_os, mock_shutil, hass):
|
||||
"""Test removal of library on upgrade from before 0.50."""
|
||||
ha_version = '0.49.0'
|
||||
mock_os.path.isdir = mock.Mock(return_value=True)
|
||||
mock_open = mock.mock_open()
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
hass.config.path = mock.Mock()
|
||||
config_util.process_ha_config_upgrade(hass)
|
||||
hass_path = hass.config.path.return_value
|
||||
|
||||
assert mock_os.path.isdir.call_count == 1
|
||||
assert mock_os.path.isdir.call_args == mock.call(hass_path)
|
||||
assert mock_shutil.rmtree.call_count == 1
|
||||
assert mock_shutil.rmtree.call_args == mock.call(hass_path)
|
||||
|
||||
|
||||
def test_process_config_upgrade(hass):
|
||||
"""Test update of version on upgrade."""
|
||||
ha_version = '0.92.0'
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True), \
|
||||
mock.patch.object(config_util, '__version__', '0.91.0'):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
config_util.process_ha_config_upgrade(hass)
|
||||
|
||||
assert opened_file.write.call_count == 1
|
||||
assert opened_file.write.call_args == mock.call('0.91.0')
|
||||
|
||||
|
||||
def test_config_upgrade_same_version(hass):
|
||||
"""Test no update of version on no upgrade."""
|
||||
ha_version = __version__
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
config_util.process_ha_config_upgrade(hass)
|
||||
|
||||
assert opened_file.write.call_count == 0
|
||||
|
||||
|
||||
@mock.patch('homeassistant.config.find_config_file', mock.Mock())
|
||||
def test_config_upgrade_no_file(hass):
|
||||
"""Test update of version on upgrade, with no version file."""
|
||||
mock_open = mock.mock_open()
|
||||
mock_open.side_effect = [FileNotFoundError(),
|
||||
mock.DEFAULT,
|
||||
mock.DEFAULT]
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
config_util.process_ha_config_upgrade(hass)
|
||||
assert opened_file.write.call_count == 1
|
||||
assert opened_file.write.call_args == mock.call(__version__)
|
||||
|
||||
|
||||
@mock.patch('homeassistant.config.shutil')
|
||||
@mock.patch('homeassistant.config.os')
|
||||
@mock.patch('homeassistant.config.find_config_file', mock.Mock())
|
||||
def test_migrate_file_on_upgrade(mock_os, mock_shutil, hass):
|
||||
"""Test migrate of config files on upgrade."""
|
||||
ha_version = '0.7.0'
|
||||
|
||||
mock_os.path.isdir = mock.Mock(return_value=True)
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
|
||||
def _mock_isfile(filename):
|
||||
return True
|
||||
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True), \
|
||||
mock.patch('homeassistant.config.os.path.isfile', _mock_isfile):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
hass.config.path = mock.Mock()
|
||||
|
||||
config_util.process_ha_config_upgrade(hass)
|
||||
|
||||
assert mock_os.rename.call_count == 1
|
||||
|
||||
|
||||
@mock.patch('homeassistant.config.shutil')
|
||||
@mock.patch('homeassistant.config.os')
|
||||
@mock.patch('homeassistant.config.find_config_file', mock.Mock())
|
||||
def test_migrate_no_file_on_upgrade(mock_os, mock_shutil, hass):
|
||||
"""Test not migrating config files on upgrade."""
|
||||
ha_version = '0.7.0'
|
||||
|
||||
mock_os.path.isdir = mock.Mock(return_value=True)
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
|
||||
def _mock_isfile(filename):
|
||||
return False
|
||||
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True), \
|
||||
mock.patch('homeassistant.config.os.path.isfile', _mock_isfile):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
hass.config.path = mock.Mock()
|
||||
|
||||
config_util.process_ha_config_upgrade(hass)
|
||||
|
||||
assert mock_os.rename.call_count == 0
|
||||
|
||||
|
||||
async def test_loading_configuration(hass):
|
||||
"""Test loading core config onto hass object."""
|
||||
hass.config = mock.Mock()
|
||||
|
||||
await config_util.async_process_ha_core_config(hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL,
|
||||
'time_zone': 'America/New_York',
|
||||
'whitelist_external_dirs': '/tmp',
|
||||
})
|
||||
|
||||
assert hass.config.latitude == 60
|
||||
assert hass.config.longitude == 50
|
||||
assert hass.config.elevation == 25
|
||||
assert hass.config.location_name == 'Huis'
|
||||
assert hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL
|
||||
assert hass.config.time_zone.zone == 'America/New_York'
|
||||
assert len(hass.config.whitelist_external_dirs) == 2
|
||||
assert '/tmp' in hass.config.whitelist_external_dirs
|
||||
|
||||
|
||||
async def test_loading_configuration_temperature_unit(hass):
|
||||
"""Test backward compatibility when loading core config."""
|
||||
hass.config = mock.Mock()
|
||||
|
||||
await config_util.async_process_ha_core_config(hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'America/New_York',
|
||||
})
|
||||
|
||||
assert hass.config.latitude == 60
|
||||
assert hass.config.longitude == 50
|
||||
assert hass.config.elevation == 25
|
||||
assert hass.config.location_name == 'Huis'
|
||||
assert hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert hass.config.time_zone.zone == 'America/New_York'
|
||||
|
||||
|
||||
async def test_loading_configuration_from_packages(hass):
|
||||
"""Test loading packages config onto hass object config."""
|
||||
hass.config = mock.Mock()
|
||||
|
||||
await config_util.async_process_ha_core_config(hass, {
|
||||
'latitude': 39,
|
||||
'longitude': -1,
|
||||
'elevation': 500,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'Europe/Madrid',
|
||||
'packages': {
|
||||
'package_1': {'wake_on_lan': None},
|
||||
'package_2': {'light': {'platform': 'hue'},
|
||||
'media_extractor': None,
|
||||
'sun': None}},
|
||||
})
|
||||
|
||||
# Empty packages not allowed
|
||||
with pytest.raises(MultipleInvalid):
|
||||
await config_util.async_process_ha_core_config(hass, {
|
||||
'latitude': 39,
|
||||
'longitude': -1,
|
||||
'elevation': 500,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'Europe/Madrid',
|
||||
'packages': {'empty_package': None},
|
||||
})
|
||||
|
||||
def test_customize_dict_schema(self):
|
||||
"""Test basic customize config validation."""
|
||||
values = (
|
||||
{ATTR_FRIENDLY_NAME: None},
|
||||
{ATTR_HIDDEN: '2'},
|
||||
{ATTR_ASSUMED_STATE: '2'},
|
||||
)
|
||||
|
||||
for val in values:
|
||||
print(val)
|
||||
with pytest.raises(MultipleInvalid):
|
||||
config_util.CUSTOMIZE_DICT_SCHEMA(val)
|
||||
@asynctest.mock.patch('homeassistant.util.location.detect_location_info',
|
||||
autospec=True, return_value=location_util.LocationInfo(
|
||||
'0.0.0.0', 'US', 'United States', 'CA', 'California',
|
||||
'San Diego', '92122', 'America/Los_Angeles', 32.8594,
|
||||
-117.2073, True))
|
||||
@asynctest.mock.patch('homeassistant.util.location.elevation',
|
||||
autospec=True, return_value=101)
|
||||
async def test_discovering_configuration(mock_detect, mock_elevation, hass):
|
||||
"""Test auto discovery for missing core configs."""
|
||||
hass.config.latitude = None
|
||||
hass.config.longitude = None
|
||||
hass.config.elevation = None
|
||||
hass.config.location_name = None
|
||||
hass.config.time_zone = None
|
||||
|
||||
assert config_util.CUSTOMIZE_DICT_SCHEMA({
|
||||
ATTR_FRIENDLY_NAME: 2,
|
||||
ATTR_HIDDEN: '1',
|
||||
ATTR_ASSUMED_STATE: '0',
|
||||
}) == {
|
||||
ATTR_FRIENDLY_NAME: '2',
|
||||
ATTR_HIDDEN: True,
|
||||
ATTR_ASSUMED_STATE: False
|
||||
}
|
||||
await config_util.async_process_ha_core_config(hass, {})
|
||||
|
||||
def test_customize_glob_is_ordered(self):
|
||||
"""Test that customize_glob preserves order."""
|
||||
conf = config_util.CORE_CONFIG_SCHEMA(
|
||||
{'customize_glob': OrderedDict()})
|
||||
assert isinstance(conf['customize_glob'], OrderedDict)
|
||||
assert hass.config.latitude == 32.8594
|
||||
assert hass.config.longitude == -117.2073
|
||||
assert hass.config.elevation == 101
|
||||
assert hass.config.location_name == 'San Diego'
|
||||
assert hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert hass.config.units.is_metric
|
||||
assert hass.config.time_zone.zone == 'America/Los_Angeles'
|
||||
|
||||
def _compute_state(self, config):
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(self.hass, config),
|
||||
self.hass.loop).result()
|
||||
|
||||
entity = Entity()
|
||||
entity.entity_id = 'test.test'
|
||||
entity.hass = self.hass
|
||||
entity.schedule_update_ha_state()
|
||||
@asynctest.mock.patch('homeassistant.util.location.detect_location_info',
|
||||
autospec=True, return_value=None)
|
||||
@asynctest.mock.patch('homeassistant.util.location.elevation', return_value=0)
|
||||
async def test_discovering_configuration_auto_detect_fails(mock_detect,
|
||||
mock_elevation,
|
||||
hass):
|
||||
"""Test config remains unchanged if discovery fails."""
|
||||
hass.config = Config()
|
||||
hass.config.config_dir = "/test/config"
|
||||
|
||||
self.hass.block_till_done()
|
||||
await config_util.async_process_ha_core_config(hass, {})
|
||||
|
||||
return self.hass.states.get('test.test')
|
||||
blankConfig = Config()
|
||||
assert hass.config.latitude == blankConfig.latitude
|
||||
assert hass.config.longitude == blankConfig.longitude
|
||||
assert hass.config.elevation == blankConfig.elevation
|
||||
assert hass.config.location_name == blankConfig.location_name
|
||||
assert hass.config.units == blankConfig.units
|
||||
assert hass.config.time_zone == blankConfig.time_zone
|
||||
assert len(hass.config.whitelist_external_dirs) == 1
|
||||
assert "/test/config/www" in hass.config.whitelist_external_dirs
|
||||
|
||||
def test_entity_customization(self):
|
||||
"""Test entity customization through configuration."""
|
||||
config = {CONF_LATITUDE: 50,
|
||||
CONF_LONGITUDE: 50,
|
||||
CONF_NAME: 'Test',
|
||||
CONF_CUSTOMIZE: {'test.test': {'hidden': True}}}
|
||||
|
||||
state = self._compute_state(config)
|
||||
@asynctest.mock.patch(
|
||||
'homeassistant.scripts.check_config.check_ha_config_file')
|
||||
async def test_check_ha_config_file_correct(mock_check, hass):
|
||||
"""Check that restart propagates to stop."""
|
||||
mock_check.return_value = check_config.HomeAssistantConfig()
|
||||
assert await config_util.async_check_ha_config_file(hass) is None
|
||||
|
||||
assert state.attributes['hidden']
|
||||
|
||||
@mock.patch('homeassistant.config.shutil')
|
||||
@mock.patch('homeassistant.config.os')
|
||||
def test_remove_lib_on_upgrade(self, mock_os, mock_shutil):
|
||||
"""Test removal of library on upgrade from before 0.50."""
|
||||
ha_version = '0.49.0'
|
||||
mock_os.path.isdir = mock.Mock(return_value=True)
|
||||
mock_open = mock.mock_open()
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
self.hass.config.path = mock.Mock()
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
hass_path = self.hass.config.path.return_value
|
||||
@asynctest.mock.patch(
|
||||
'homeassistant.scripts.check_config.check_ha_config_file')
|
||||
async def test_check_ha_config_file_wrong(mock_check, hass):
|
||||
"""Check that restart with a bad config doesn't propagate to stop."""
|
||||
mock_check.return_value = check_config.HomeAssistantConfig()
|
||||
mock_check.return_value.add_error("bad")
|
||||
|
||||
assert mock_os.path.isdir.call_count == 1
|
||||
assert mock_os.path.isdir.call_args == mock.call(hass_path)
|
||||
assert mock_shutil.rmtree.call_count == 1
|
||||
assert mock_shutil.rmtree.call_args == mock.call(hass_path)
|
||||
|
||||
def test_process_config_upgrade(self):
|
||||
"""Test update of version on upgrade."""
|
||||
ha_version = '0.92.0'
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True), \
|
||||
mock.patch.object(config_util, '__version__', '0.91.0'):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
|
||||
assert opened_file.write.call_count == 1
|
||||
assert opened_file.write.call_args == mock.call('0.91.0')
|
||||
|
||||
def test_config_upgrade_same_version(self):
|
||||
"""Test no update of version on no upgrade."""
|
||||
ha_version = __version__
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
|
||||
assert opened_file.write.call_count == 0
|
||||
|
||||
@mock.patch('homeassistant.config.find_config_file', mock.Mock())
|
||||
def test_config_upgrade_no_file(self):
|
||||
"""Test update of version on upgrade, with no version file."""
|
||||
mock_open = mock.mock_open()
|
||||
mock_open.side_effect = [FileNotFoundError(),
|
||||
mock.DEFAULT,
|
||||
mock.DEFAULT]
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
assert opened_file.write.call_count == 1
|
||||
assert opened_file.write.call_args == mock.call(__version__)
|
||||
|
||||
@mock.patch('homeassistant.config.shutil')
|
||||
@mock.patch('homeassistant.config.os')
|
||||
@mock.patch('homeassistant.config.find_config_file', mock.Mock())
|
||||
def test_migrate_file_on_upgrade(self, mock_os, mock_shutil):
|
||||
"""Test migrate of config files on upgrade."""
|
||||
ha_version = '0.7.0'
|
||||
|
||||
mock_os.path.isdir = mock.Mock(return_value=True)
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
|
||||
def _mock_isfile(filename):
|
||||
return True
|
||||
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True), \
|
||||
mock.patch(
|
||||
'homeassistant.config.os.path.isfile', _mock_isfile):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
self.hass.config.path = mock.Mock()
|
||||
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
|
||||
assert mock_os.rename.call_count == 1
|
||||
|
||||
@mock.patch('homeassistant.config.shutil')
|
||||
@mock.patch('homeassistant.config.os')
|
||||
@mock.patch('homeassistant.config.find_config_file', mock.Mock())
|
||||
def test_migrate_no_file_on_upgrade(self, mock_os, mock_shutil):
|
||||
"""Test not migrating config files on upgrade."""
|
||||
ha_version = '0.7.0'
|
||||
|
||||
mock_os.path.isdir = mock.Mock(return_value=True)
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
|
||||
def _mock_isfile(filename):
|
||||
return False
|
||||
|
||||
with mock.patch('homeassistant.config.open', mock_open, create=True), \
|
||||
mock.patch(
|
||||
'homeassistant.config.os.path.isfile', _mock_isfile):
|
||||
opened_file = mock_open.return_value
|
||||
# pylint: disable=no-member
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
self.hass.config.path = mock.Mock()
|
||||
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
|
||||
assert mock_os.rename.call_count == 0
|
||||
|
||||
def test_loading_configuration(self):
|
||||
"""Test loading core config onto hass object."""
|
||||
self.hass.config = mock.Mock()
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(self.hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL,
|
||||
'time_zone': 'America/New_York',
|
||||
'whitelist_external_dirs': '/tmp',
|
||||
}), self.hass.loop).result()
|
||||
|
||||
assert self.hass.config.latitude == 60
|
||||
assert self.hass.config.longitude == 50
|
||||
assert self.hass.config.elevation == 25
|
||||
assert self.hass.config.location_name == 'Huis'
|
||||
assert self.hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL
|
||||
assert self.hass.config.time_zone.zone == 'America/New_York'
|
||||
assert len(self.hass.config.whitelist_external_dirs) == 2
|
||||
assert '/tmp' in self.hass.config.whitelist_external_dirs
|
||||
|
||||
def test_loading_configuration_temperature_unit(self):
|
||||
"""Test backward compatibility when loading core config."""
|
||||
self.hass.config = mock.Mock()
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(self.hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'America/New_York',
|
||||
}), self.hass.loop).result()
|
||||
|
||||
assert self.hass.config.latitude == 60
|
||||
assert self.hass.config.longitude == 50
|
||||
assert self.hass.config.elevation == 25
|
||||
assert self.hass.config.location_name == 'Huis'
|
||||
assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert self.hass.config.time_zone.zone == 'America/New_York'
|
||||
|
||||
def test_loading_configuration_from_packages(self):
|
||||
"""Test loading packages config onto hass object config."""
|
||||
self.hass.config = mock.Mock()
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(self.hass, {
|
||||
'latitude': 39,
|
||||
'longitude': -1,
|
||||
'elevation': 500,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'Europe/Madrid',
|
||||
'packages': {
|
||||
'package_1': {'wake_on_lan': None},
|
||||
'package_2': {'light': {'platform': 'hue'},
|
||||
'media_extractor': None,
|
||||
'sun': None}},
|
||||
}), self.hass.loop).result()
|
||||
|
||||
# Empty packages not allowed
|
||||
with pytest.raises(MultipleInvalid):
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(self.hass, {
|
||||
'latitude': 39,
|
||||
'longitude': -1,
|
||||
'elevation': 500,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'Europe/Madrid',
|
||||
'packages': {'empty_package': None},
|
||||
}), self.hass.loop).result()
|
||||
|
||||
@mock.patch('homeassistant.util.location.detect_location_info',
|
||||
autospec=True, return_value=location_util.LocationInfo(
|
||||
'0.0.0.0', 'US', 'United States', 'CA', 'California',
|
||||
'San Diego', '92122', 'America/Los_Angeles', 32.8594,
|
||||
-117.2073, True))
|
||||
@mock.patch('homeassistant.util.location.elevation',
|
||||
autospec=True, return_value=101)
|
||||
def test_discovering_configuration(self, mock_detect, mock_elevation):
|
||||
"""Test auto discovery for missing core configs."""
|
||||
self.hass.config.latitude = None
|
||||
self.hass.config.longitude = None
|
||||
self.hass.config.elevation = None
|
||||
self.hass.config.location_name = None
|
||||
self.hass.config.time_zone = None
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(
|
||||
self.hass, {}), self.hass.loop
|
||||
).result()
|
||||
|
||||
assert self.hass.config.latitude == 32.8594
|
||||
assert self.hass.config.longitude == -117.2073
|
||||
assert self.hass.config.elevation == 101
|
||||
assert self.hass.config.location_name == 'San Diego'
|
||||
assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert self.hass.config.units.is_metric
|
||||
assert self.hass.config.time_zone.zone == 'America/Los_Angeles'
|
||||
|
||||
@mock.patch('homeassistant.util.location.detect_location_info',
|
||||
autospec=True, return_value=None)
|
||||
@mock.patch('homeassistant.util.location.elevation', return_value=0)
|
||||
def test_discovering_configuration_auto_detect_fails(self, mock_detect,
|
||||
mock_elevation):
|
||||
"""Test config remains unchanged if discovery fails."""
|
||||
self.hass.config = Config()
|
||||
self.hass.config.config_dir = "/test/config"
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(
|
||||
self.hass, {}), self.hass.loop
|
||||
).result()
|
||||
|
||||
blankConfig = Config()
|
||||
assert self.hass.config.latitude == blankConfig.latitude
|
||||
assert self.hass.config.longitude == blankConfig.longitude
|
||||
assert self.hass.config.elevation == blankConfig.elevation
|
||||
assert self.hass.config.location_name == blankConfig.location_name
|
||||
assert self.hass.config.units == blankConfig.units
|
||||
assert self.hass.config.time_zone == blankConfig.time_zone
|
||||
assert len(self.hass.config.whitelist_external_dirs) == 1
|
||||
assert "/test/config/www" in self.hass.config.whitelist_external_dirs
|
||||
|
||||
@asynctest.mock.patch(
|
||||
'homeassistant.scripts.check_config.check_ha_config_file')
|
||||
def test_check_ha_config_file_correct(self, mock_check):
|
||||
"""Check that restart propagates to stop."""
|
||||
mock_check.return_value = check_config.HomeAssistantConfig()
|
||||
assert run_coroutine_threadsafe(
|
||||
config_util.async_check_ha_config_file(self.hass),
|
||||
self.hass.loop
|
||||
).result() is None
|
||||
|
||||
@asynctest.mock.patch(
|
||||
'homeassistant.scripts.check_config.check_ha_config_file')
|
||||
def test_check_ha_config_file_wrong(self, mock_check):
|
||||
"""Check that restart with a bad config doesn't propagate to stop."""
|
||||
mock_check.return_value = check_config.HomeAssistantConfig()
|
||||
mock_check.return_value.add_error("bad")
|
||||
|
||||
assert run_coroutine_threadsafe(
|
||||
config_util.async_check_ha_config_file(self.hass),
|
||||
self.hass.loop
|
||||
).result() == 'bad'
|
||||
assert await config_util.async_check_ha_config_file(hass) == 'bad'
|
||||
|
||||
|
||||
@asynctest.mock.patch('homeassistant.config.os.path.isfile',
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
"""Test Home Assistant color util methods."""
|
||||
import unittest
|
||||
import homeassistant.util.color as color_util
|
||||
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.util.color as color_util
|
||||
|
||||
GAMUT = color_util.GamutType(color_util.XYPoint(0.704, 0.296),
|
||||
color_util.XYPoint(0.2151, 0.7106),
|
||||
color_util.XYPoint(0.138, 0.08))
|
||||
|
@ -22,408 +21,340 @@ GAMUT_INVALID_4 = color_util.GamutType(color_util.XYPoint(0.1, 0.1),
|
|||
color_util.XYPoint(0.7, 0.7))
|
||||
|
||||
|
||||
class TestColorUtil(unittest.TestCase):
|
||||
"""Test color util methods."""
|
||||
# pylint: disable=invalid-name
|
||||
def test_color_RGB_to_xy_brightness():
|
||||
"""Test color_RGB_to_xy_brightness."""
|
||||
assert color_util.color_RGB_to_xy_brightness(0, 0, 0) == (0, 0, 0)
|
||||
assert color_util.color_RGB_to_xy_brightness(255, 255, 255) == \
|
||||
(0.323, 0.329, 255)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def test_color_RGB_to_xy_brightness(self):
|
||||
"""Test color_RGB_to_xy_brightness."""
|
||||
assert (0, 0, 0) == \
|
||||
color_util.color_RGB_to_xy_brightness(0, 0, 0)
|
||||
assert (0.323, 0.329, 255) == \
|
||||
color_util.color_RGB_to_xy_brightness(255, 255, 255)
|
||||
assert color_util.color_RGB_to_xy_brightness(0, 0, 255) == \
|
||||
(0.136, 0.04, 12)
|
||||
|
||||
assert (0.136, 0.04, 12) == \
|
||||
color_util.color_RGB_to_xy_brightness(0, 0, 255)
|
||||
assert color_util.color_RGB_to_xy_brightness(0, 255, 0) == \
|
||||
(0.172, 0.747, 170)
|
||||
|
||||
assert (0.172, 0.747, 170) == \
|
||||
color_util.color_RGB_to_xy_brightness(0, 255, 0)
|
||||
assert color_util.color_RGB_to_xy_brightness(255, 0, 0) == \
|
||||
(0.701, 0.299, 72)
|
||||
|
||||
assert (0.701, 0.299, 72) == \
|
||||
color_util.color_RGB_to_xy_brightness(255, 0, 0)
|
||||
assert color_util.color_RGB_to_xy_brightness(128, 0, 0) == \
|
||||
(0.701, 0.299, 16)
|
||||
|
||||
assert (0.701, 0.299, 16) == \
|
||||
color_util.color_RGB_to_xy_brightness(128, 0, 0)
|
||||
assert color_util.color_RGB_to_xy_brightness(255, 0, 0, GAMUT) == \
|
||||
(0.7, 0.299, 72)
|
||||
|
||||
assert (0.7, 0.299, 72) == \
|
||||
color_util.color_RGB_to_xy_brightness(255, 0, 0, GAMUT)
|
||||
assert color_util.color_RGB_to_xy_brightness(0, 255, 0, GAMUT) == \
|
||||
(0.215, 0.711, 170)
|
||||
|
||||
assert (0.215, 0.711, 170) == \
|
||||
color_util.color_RGB_to_xy_brightness(0, 255, 0, GAMUT)
|
||||
assert color_util.color_RGB_to_xy_brightness(0, 0, 255, GAMUT) == \
|
||||
(0.138, 0.08, 12)
|
||||
|
||||
assert (0.138, 0.08, 12) == \
|
||||
color_util.color_RGB_to_xy_brightness(0, 0, 255, GAMUT)
|
||||
|
||||
def test_color_RGB_to_xy(self):
|
||||
"""Test color_RGB_to_xy."""
|
||||
assert (0, 0) == \
|
||||
color_util.color_RGB_to_xy(0, 0, 0)
|
||||
assert (0.323, 0.329) == \
|
||||
color_util.color_RGB_to_xy(255, 255, 255)
|
||||
def test_color_RGB_to_xy():
|
||||
"""Test color_RGB_to_xy."""
|
||||
assert color_util.color_RGB_to_xy(0, 0, 0) == (0, 0)
|
||||
assert color_util.color_RGB_to_xy(255, 255, 255) == (0.323, 0.329)
|
||||
|
||||
assert (0.136, 0.04) == \
|
||||
color_util.color_RGB_to_xy(0, 0, 255)
|
||||
assert color_util.color_RGB_to_xy(0, 0, 255) == (0.136, 0.04)
|
||||
|
||||
assert (0.172, 0.747) == \
|
||||
color_util.color_RGB_to_xy(0, 255, 0)
|
||||
assert color_util.color_RGB_to_xy(0, 255, 0) == (0.172, 0.747)
|
||||
|
||||
assert (0.701, 0.299) == \
|
||||
color_util.color_RGB_to_xy(255, 0, 0)
|
||||
assert color_util.color_RGB_to_xy(255, 0, 0) == (0.701, 0.299)
|
||||
|
||||
assert (0.701, 0.299) == \
|
||||
color_util.color_RGB_to_xy(128, 0, 0)
|
||||
assert color_util.color_RGB_to_xy(128, 0, 0) == (0.701, 0.299)
|
||||
|
||||
assert (0.138, 0.08) == \
|
||||
color_util.color_RGB_to_xy(0, 0, 255, GAMUT)
|
||||
assert color_util.color_RGB_to_xy(0, 0, 255, GAMUT) == (0.138, 0.08)
|
||||
|
||||
assert (0.215, 0.711) == \
|
||||
color_util.color_RGB_to_xy(0, 255, 0, GAMUT)
|
||||
assert color_util.color_RGB_to_xy(0, 255, 0, GAMUT) == (0.215, 0.711)
|
||||
|
||||
assert (0.7, 0.299) == \
|
||||
color_util.color_RGB_to_xy(255, 0, 0, GAMUT)
|
||||
assert color_util.color_RGB_to_xy(255, 0, 0, GAMUT) == (0.7, 0.299)
|
||||
|
||||
def test_color_xy_brightness_to_RGB(self):
|
||||
"""Test color_xy_brightness_to_RGB."""
|
||||
assert (0, 0, 0) == \
|
||||
color_util.color_xy_brightness_to_RGB(1, 1, 0)
|
||||
|
||||
assert (194, 186, 169) == \
|
||||
color_util.color_xy_brightness_to_RGB(.35, .35, 128)
|
||||
def test_color_xy_brightness_to_RGB():
|
||||
"""Test color_xy_brightness_to_RGB."""
|
||||
assert color_util.color_xy_brightness_to_RGB(1, 1, 0) == (0, 0, 0)
|
||||
|
||||
assert (255, 243, 222) == \
|
||||
color_util.color_xy_brightness_to_RGB(.35, .35, 255)
|
||||
assert color_util.color_xy_brightness_to_RGB(.35, .35, 128) == \
|
||||
(194, 186, 169)
|
||||
|
||||
assert (255, 0, 60) == \
|
||||
color_util.color_xy_brightness_to_RGB(1, 0, 255)
|
||||
assert color_util.color_xy_brightness_to_RGB(.35, .35, 255) == \
|
||||
(255, 243, 222)
|
||||
|
||||
assert (0, 255, 0) == \
|
||||
color_util.color_xy_brightness_to_RGB(0, 1, 255)
|
||||
assert color_util.color_xy_brightness_to_RGB(1, 0, 255) == (255, 0, 60)
|
||||
|
||||
assert (0, 63, 255) == \
|
||||
color_util.color_xy_brightness_to_RGB(0, 0, 255)
|
||||
assert color_util.color_xy_brightness_to_RGB(0, 1, 255) == (0, 255, 0)
|
||||
|
||||
assert (255, 0, 3) == \
|
||||
color_util.color_xy_brightness_to_RGB(1, 0, 255, GAMUT)
|
||||
assert color_util.color_xy_brightness_to_RGB(0, 0, 255) == (0, 63, 255)
|
||||
|
||||
assert (82, 255, 0) == \
|
||||
color_util.color_xy_brightness_to_RGB(0, 1, 255, GAMUT)
|
||||
assert color_util.color_xy_brightness_to_RGB(1, 0, 255, GAMUT) == \
|
||||
(255, 0, 3)
|
||||
|
||||
assert (9, 85, 255) == \
|
||||
color_util.color_xy_brightness_to_RGB(0, 0, 255, GAMUT)
|
||||
assert color_util.color_xy_brightness_to_RGB(0, 1, 255, GAMUT) == \
|
||||
(82, 255, 0)
|
||||
|
||||
def test_color_xy_to_RGB(self):
|
||||
"""Test color_xy_to_RGB."""
|
||||
assert (255, 243, 222) == \
|
||||
color_util.color_xy_to_RGB(.35, .35)
|
||||
assert color_util.color_xy_brightness_to_RGB(0, 0, 255, GAMUT) == \
|
||||
(9, 85, 255)
|
||||
|
||||
assert (255, 0, 60) == \
|
||||
color_util.color_xy_to_RGB(1, 0)
|
||||
|
||||
assert (0, 255, 0) == \
|
||||
color_util.color_xy_to_RGB(0, 1)
|
||||
def test_color_xy_to_RGB():
|
||||
"""Test color_xy_to_RGB."""
|
||||
assert color_util.color_xy_to_RGB(.35, .35) == (255, 243, 222)
|
||||
|
||||
assert (0, 63, 255) == \
|
||||
color_util.color_xy_to_RGB(0, 0)
|
||||
assert color_util.color_xy_to_RGB(1, 0) == (255, 0, 60)
|
||||
|
||||
assert (255, 0, 3) == \
|
||||
color_util.color_xy_to_RGB(1, 0, GAMUT)
|
||||
assert color_util.color_xy_to_RGB(0, 1) == (0, 255, 0)
|
||||
|
||||
assert (82, 255, 0) == \
|
||||
color_util.color_xy_to_RGB(0, 1, GAMUT)
|
||||
assert color_util.color_xy_to_RGB(0, 0) == (0, 63, 255)
|
||||
|
||||
assert (9, 85, 255) == \
|
||||
color_util.color_xy_to_RGB(0, 0, GAMUT)
|
||||
assert color_util.color_xy_to_RGB(1, 0, GAMUT) == (255, 0, 3)
|
||||
|
||||
def test_color_RGB_to_hsv(self):
|
||||
"""Test color_RGB_to_hsv."""
|
||||
assert (0, 0, 0) == \
|
||||
color_util.color_RGB_to_hsv(0, 0, 0)
|
||||
assert color_util.color_xy_to_RGB(0, 1, GAMUT) == (82, 255, 0)
|
||||
|
||||
assert (0, 0, 100) == \
|
||||
color_util.color_RGB_to_hsv(255, 255, 255)
|
||||
assert color_util.color_xy_to_RGB(0, 0, GAMUT) == (9, 85, 255)
|
||||
|
||||
assert (240, 100, 100) == \
|
||||
color_util.color_RGB_to_hsv(0, 0, 255)
|
||||
|
||||
assert (120, 100, 100) == \
|
||||
color_util.color_RGB_to_hsv(0, 255, 0)
|
||||
def test_color_RGB_to_hsv():
|
||||
"""Test color_RGB_to_hsv."""
|
||||
assert color_util.color_RGB_to_hsv(0, 0, 0) == (0, 0, 0)
|
||||
|
||||
assert (0, 100, 100) == \
|
||||
color_util.color_RGB_to_hsv(255, 0, 0)
|
||||
assert color_util.color_RGB_to_hsv(255, 255, 255) == (0, 0, 100)
|
||||
|
||||
def test_color_hsv_to_RGB(self):
|
||||
"""Test color_hsv_to_RGB."""
|
||||
assert (0, 0, 0) == \
|
||||
color_util.color_hsv_to_RGB(0, 0, 0)
|
||||
assert color_util.color_RGB_to_hsv(0, 0, 255) == (240, 100, 100)
|
||||
|
||||
assert (255, 255, 255) == \
|
||||
color_util.color_hsv_to_RGB(0, 0, 100)
|
||||
assert color_util.color_RGB_to_hsv(0, 255, 0) == (120, 100, 100)
|
||||
|
||||
assert (0, 0, 255) == \
|
||||
color_util.color_hsv_to_RGB(240, 100, 100)
|
||||
assert color_util.color_RGB_to_hsv(255, 0, 0) == (0, 100, 100)
|
||||
|
||||
assert (0, 255, 0) == \
|
||||
color_util.color_hsv_to_RGB(120, 100, 100)
|
||||
|
||||
assert (255, 0, 0) == \
|
||||
color_util.color_hsv_to_RGB(0, 100, 100)
|
||||
def test_color_hsv_to_RGB():
|
||||
"""Test color_hsv_to_RGB."""
|
||||
assert color_util.color_hsv_to_RGB(0, 0, 0) == (0, 0, 0)
|
||||
|
||||
def test_color_hsb_to_RGB(self):
|
||||
"""Test color_hsb_to_RGB."""
|
||||
assert (0, 0, 0) == \
|
||||
color_util.color_hsb_to_RGB(0, 0, 0)
|
||||
assert color_util.color_hsv_to_RGB(0, 0, 100) == (255, 255, 255)
|
||||
|
||||
assert (255, 255, 255) == \
|
||||
color_util.color_hsb_to_RGB(0, 0, 1.0)
|
||||
assert color_util.color_hsv_to_RGB(240, 100, 100) == (0, 0, 255)
|
||||
|
||||
assert (0, 0, 255) == \
|
||||
color_util.color_hsb_to_RGB(240, 1.0, 1.0)
|
||||
assert color_util.color_hsv_to_RGB(120, 100, 100) == (0, 255, 0)
|
||||
|
||||
assert (0, 255, 0) == \
|
||||
color_util.color_hsb_to_RGB(120, 1.0, 1.0)
|
||||
assert color_util.color_hsv_to_RGB(0, 100, 100) == (255, 0, 0)
|
||||
|
||||
assert (255, 0, 0) == \
|
||||
color_util.color_hsb_to_RGB(0, 1.0, 1.0)
|
||||
|
||||
def test_color_xy_to_hs(self):
|
||||
"""Test color_xy_to_hs."""
|
||||
assert (47.294, 100) == \
|
||||
color_util.color_xy_to_hs(1, 1)
|
||||
def test_color_hsb_to_RGB():
|
||||
"""Test color_hsb_to_RGB."""
|
||||
assert color_util.color_hsb_to_RGB(0, 0, 0) == (0, 0, 0)
|
||||
|
||||
assert (38.182, 12.941) == \
|
||||
color_util.color_xy_to_hs(.35, .35)
|
||||
assert color_util.color_hsb_to_RGB(0, 0, 1.0) == (255, 255, 255)
|
||||
|
||||
assert (345.882, 100) == \
|
||||
color_util.color_xy_to_hs(1, 0)
|
||||
assert color_util.color_hsb_to_RGB(240, 1.0, 1.0) == (0, 0, 255)
|
||||
|
||||
assert (120, 100) == \
|
||||
color_util.color_xy_to_hs(0, 1)
|
||||
assert color_util.color_hsb_to_RGB(120, 1.0, 1.0) == (0, 255, 0)
|
||||
|
||||
assert (225.176, 100) == \
|
||||
color_util.color_xy_to_hs(0, 0)
|
||||
assert color_util.color_hsb_to_RGB(0, 1.0, 1.0) == (255, 0, 0)
|
||||
|
||||
assert (359.294, 100) == \
|
||||
color_util.color_xy_to_hs(1, 0, GAMUT)
|
||||
|
||||
assert (100.706, 100) == \
|
||||
color_util.color_xy_to_hs(0, 1, GAMUT)
|
||||
def test_color_xy_to_hs():
|
||||
"""Test color_xy_to_hs."""
|
||||
assert color_util.color_xy_to_hs(1, 1) == (47.294, 100)
|
||||
|
||||
assert (221.463, 96.471) == \
|
||||
color_util.color_xy_to_hs(0, 0, GAMUT)
|
||||
assert color_util.color_xy_to_hs(.35, .35) == (38.182, 12.941)
|
||||
|
||||
def test_color_hs_to_xy(self):
|
||||
"""Test color_hs_to_xy."""
|
||||
assert (0.151, 0.343) == \
|
||||
color_util.color_hs_to_xy(180, 100)
|
||||
assert color_util.color_xy_to_hs(1, 0) == (345.882, 100)
|
||||
|
||||
assert (0.356, 0.321) == \
|
||||
color_util.color_hs_to_xy(350, 12.5)
|
||||
assert color_util.color_xy_to_hs(0, 1) == (120, 100)
|
||||
|
||||
assert (0.229, 0.474) == \
|
||||
color_util.color_hs_to_xy(140, 50)
|
||||
assert color_util.color_xy_to_hs(0, 0) == (225.176, 100)
|
||||
|
||||
assert (0.474, 0.317) == \
|
||||
color_util.color_hs_to_xy(0, 40)
|
||||
assert color_util.color_xy_to_hs(1, 0, GAMUT) == (359.294, 100)
|
||||
|
||||
assert (0.323, 0.329) == \
|
||||
color_util.color_hs_to_xy(360, 0)
|
||||
assert color_util.color_xy_to_hs(0, 1, GAMUT) == (100.706, 100)
|
||||
|
||||
assert (0.7, 0.299) == \
|
||||
color_util.color_hs_to_xy(0, 100, GAMUT)
|
||||
assert color_util.color_xy_to_hs(0, 0, GAMUT) == (221.463, 96.471)
|
||||
|
||||
assert (0.215, 0.711) == \
|
||||
color_util.color_hs_to_xy(120, 100, GAMUT)
|
||||
|
||||
assert (0.17, 0.34) == \
|
||||
color_util.color_hs_to_xy(180, 100, GAMUT)
|
||||
def test_color_hs_to_xy():
|
||||
"""Test color_hs_to_xy."""
|
||||
assert color_util.color_hs_to_xy(180, 100) == (0.151, 0.343)
|
||||
|
||||
assert (0.138, 0.08) == \
|
||||
color_util.color_hs_to_xy(240, 100, GAMUT)
|
||||
assert color_util.color_hs_to_xy(350, 12.5) == (0.356, 0.321)
|
||||
|
||||
assert (0.7, 0.299) == \
|
||||
color_util.color_hs_to_xy(360, 100, GAMUT)
|
||||
assert color_util.color_hs_to_xy(140, 50) == (0.229, 0.474)
|
||||
|
||||
def test_rgb_hex_to_rgb_list(self):
|
||||
"""Test rgb_hex_to_rgb_list."""
|
||||
assert [255, 255, 255] == \
|
||||
color_util.rgb_hex_to_rgb_list('ffffff')
|
||||
assert color_util.color_hs_to_xy(0, 40) == (0.474, 0.317)
|
||||
|
||||
assert [0, 0, 0] == \
|
||||
color_util.rgb_hex_to_rgb_list('000000')
|
||||
assert color_util.color_hs_to_xy(360, 0) == (0.323, 0.329)
|
||||
|
||||
assert [255, 255, 255, 255] == \
|
||||
color_util.rgb_hex_to_rgb_list('ffffffff')
|
||||
assert color_util.color_hs_to_xy(0, 100, GAMUT) == (0.7, 0.299)
|
||||
|
||||
assert [0, 0, 0, 0] == \
|
||||
color_util.rgb_hex_to_rgb_list('00000000')
|
||||
assert color_util.color_hs_to_xy(120, 100, GAMUT) == (0.215, 0.711)
|
||||
|
||||
assert [51, 153, 255] == \
|
||||
color_util.rgb_hex_to_rgb_list('3399ff')
|
||||
assert color_util.color_hs_to_xy(180, 100, GAMUT) == (0.17, 0.34)
|
||||
|
||||
assert [51, 153, 255, 0] == \
|
||||
color_util.rgb_hex_to_rgb_list('3399ff00')
|
||||
assert color_util.color_hs_to_xy(240, 100, GAMUT) == (0.138, 0.08)
|
||||
|
||||
def test_color_name_to_rgb_valid_name(self):
|
||||
"""Test color_name_to_rgb."""
|
||||
assert (255, 0, 0) == \
|
||||
color_util.color_name_to_rgb('red')
|
||||
assert color_util.color_hs_to_xy(360, 100, GAMUT) == (0.7, 0.299)
|
||||
|
||||
assert (0, 0, 255) == \
|
||||
color_util.color_name_to_rgb('blue')
|
||||
|
||||
assert (0, 128, 0) == \
|
||||
color_util.color_name_to_rgb('green')
|
||||
def test_rgb_hex_to_rgb_list():
|
||||
"""Test rgb_hex_to_rgb_list."""
|
||||
assert [255, 255, 255] == \
|
||||
color_util.rgb_hex_to_rgb_list('ffffff')
|
||||
|
||||
# spaces in the name
|
||||
assert (72, 61, 139) == \
|
||||
color_util.color_name_to_rgb('dark slate blue')
|
||||
assert [0, 0, 0] == \
|
||||
color_util.rgb_hex_to_rgb_list('000000')
|
||||
|
||||
# spaces removed from name
|
||||
assert (72, 61, 139) == \
|
||||
color_util.color_name_to_rgb('darkslateblue')
|
||||
assert (72, 61, 139) == \
|
||||
color_util.color_name_to_rgb('dark slateblue')
|
||||
assert (72, 61, 139) == \
|
||||
color_util.color_name_to_rgb('darkslate blue')
|
||||
assert [255, 255, 255, 255] == \
|
||||
color_util.rgb_hex_to_rgb_list('ffffffff')
|
||||
|
||||
def test_color_name_to_rgb_unknown_name_raises_value_error(self):
|
||||
"""Test color_name_to_rgb."""
|
||||
with pytest.raises(ValueError):
|
||||
color_util.color_name_to_rgb('not a color')
|
||||
assert [0, 0, 0, 0] == \
|
||||
color_util.rgb_hex_to_rgb_list('00000000')
|
||||
|
||||
def test_color_rgb_to_rgbw(self):
|
||||
"""Test color_rgb_to_rgbw."""
|
||||
assert (0, 0, 0, 0) == \
|
||||
color_util.color_rgb_to_rgbw(0, 0, 0)
|
||||
assert [51, 153, 255] == \
|
||||
color_util.rgb_hex_to_rgb_list('3399ff')
|
||||
|
||||
assert (0, 0, 0, 255) == \
|
||||
color_util.color_rgb_to_rgbw(255, 255, 255)
|
||||
assert [51, 153, 255, 0] == \
|
||||
color_util.rgb_hex_to_rgb_list('3399ff00')
|
||||
|
||||
assert (255, 0, 0, 0) == \
|
||||
color_util.color_rgb_to_rgbw(255, 0, 0)
|
||||
|
||||
assert (0, 255, 0, 0) == \
|
||||
color_util.color_rgb_to_rgbw(0, 255, 0)
|
||||
def test_color_name_to_rgb_valid_name():
|
||||
"""Test color_name_to_rgb."""
|
||||
assert color_util.color_name_to_rgb('red') == (255, 0, 0)
|
||||
|
||||
assert (0, 0, 255, 0) == \
|
||||
color_util.color_rgb_to_rgbw(0, 0, 255)
|
||||
assert color_util.color_name_to_rgb('blue') == (0, 0, 255)
|
||||
|
||||
assert (255, 127, 0, 0) == \
|
||||
color_util.color_rgb_to_rgbw(255, 127, 0)
|
||||
assert color_util.color_name_to_rgb('green') == (0, 128, 0)
|
||||
|
||||
assert (255, 0, 0, 253) == \
|
||||
color_util.color_rgb_to_rgbw(255, 127, 127)
|
||||
# spaces in the name
|
||||
assert color_util.color_name_to_rgb('dark slate blue') == (72, 61, 139)
|
||||
|
||||
assert (0, 0, 0, 127) == \
|
||||
color_util.color_rgb_to_rgbw(127, 127, 127)
|
||||
# spaces removed from name
|
||||
assert color_util.color_name_to_rgb('darkslateblue') == (72, 61, 139)
|
||||
assert color_util.color_name_to_rgb('dark slateblue') == (72, 61, 139)
|
||||
assert color_util.color_name_to_rgb('darkslate blue') == (72, 61, 139)
|
||||
|
||||
def test_color_rgbw_to_rgb(self):
|
||||
"""Test color_rgbw_to_rgb."""
|
||||
assert (0, 0, 0) == \
|
||||
color_util.color_rgbw_to_rgb(0, 0, 0, 0)
|
||||
|
||||
assert (255, 255, 255) == \
|
||||
color_util.color_rgbw_to_rgb(0, 0, 0, 255)
|
||||
def test_color_name_to_rgb_unknown_name_raises_value_error():
|
||||
"""Test color_name_to_rgb."""
|
||||
with pytest.raises(ValueError):
|
||||
color_util.color_name_to_rgb('not a color')
|
||||
|
||||
assert (255, 0, 0) == \
|
||||
color_util.color_rgbw_to_rgb(255, 0, 0, 0)
|
||||
|
||||
assert (0, 255, 0) == \
|
||||
color_util.color_rgbw_to_rgb(0, 255, 0, 0)
|
||||
def test_color_rgb_to_rgbw():
|
||||
"""Test color_rgb_to_rgbw."""
|
||||
assert color_util.color_rgb_to_rgbw(0, 0, 0) == (0, 0, 0, 0)
|
||||
|
||||
assert (0, 0, 255) == \
|
||||
color_util.color_rgbw_to_rgb(0, 0, 255, 0)
|
||||
assert color_util.color_rgb_to_rgbw(255, 255, 255) == (0, 0, 0, 255)
|
||||
|
||||
assert (255, 127, 0) == \
|
||||
color_util.color_rgbw_to_rgb(255, 127, 0, 0)
|
||||
assert color_util.color_rgb_to_rgbw(255, 0, 0) == (255, 0, 0, 0)
|
||||
|
||||
assert (255, 127, 127) == \
|
||||
color_util.color_rgbw_to_rgb(255, 0, 0, 253)
|
||||
assert color_util.color_rgb_to_rgbw(0, 255, 0) == (0, 255, 0, 0)
|
||||
|
||||
assert (127, 127, 127) == \
|
||||
color_util.color_rgbw_to_rgb(0, 0, 0, 127)
|
||||
assert color_util.color_rgb_to_rgbw(0, 0, 255) == (0, 0, 255, 0)
|
||||
|
||||
def test_color_rgb_to_hex(self):
|
||||
"""Test color_rgb_to_hex."""
|
||||
assert color_util.color_rgb_to_hex(255, 255, 255) == 'ffffff'
|
||||
assert color_util.color_rgb_to_hex(0, 0, 0) == '000000'
|
||||
assert color_util.color_rgb_to_hex(51, 153, 255) == '3399ff'
|
||||
assert color_util.color_rgb_to_hex(255, 67.9204190, 0) == 'ff4400'
|
||||
assert color_util.color_rgb_to_rgbw(255, 127, 0) == (255, 127, 0, 0)
|
||||
|
||||
def test_gamut(self):
|
||||
"""Test gamut functions."""
|
||||
assert color_util.check_valid_gamut(GAMUT)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_1)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_2)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_3)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_4)
|
||||
assert color_util.color_rgb_to_rgbw(255, 127, 127) == (255, 0, 0, 253)
|
||||
|
||||
assert color_util.color_rgb_to_rgbw(127, 127, 127) == (0, 0, 0, 127)
|
||||
|
||||
class ColorTemperatureMiredToKelvinTests(unittest.TestCase):
|
||||
"""Test color_temperature_mired_to_kelvin."""
|
||||
|
||||
def test_should_return_25000_kelvin_when_input_is_40_mired(self):
|
||||
"""Function should return 25000K if given 40 mired."""
|
||||
kelvin = color_util.color_temperature_mired_to_kelvin(40)
|
||||
assert 25000 == kelvin
|
||||
def test_color_rgbw_to_rgb():
|
||||
"""Test color_rgbw_to_rgb."""
|
||||
assert color_util.color_rgbw_to_rgb(0, 0, 0, 0) == (0, 0, 0)
|
||||
|
||||
def test_should_return_5000_kelvin_when_input_is_200_mired(self):
|
||||
"""Function should return 5000K if given 200 mired."""
|
||||
kelvin = color_util.color_temperature_mired_to_kelvin(200)
|
||||
assert 5000 == kelvin
|
||||
|
||||
|
||||
class ColorTemperatureKelvinToMiredTests(unittest.TestCase):
|
||||
"""Test color_temperature_kelvin_to_mired."""
|
||||
|
||||
def test_should_return_40_mired_when_input_is_25000_kelvin(self):
|
||||
"""Function should return 40 mired when given 25000 Kelvin."""
|
||||
mired = color_util.color_temperature_kelvin_to_mired(25000)
|
||||
assert 40 == mired
|
||||
|
||||
def test_should_return_200_mired_when_input_is_5000_kelvin(self):
|
||||
"""Function should return 200 mired when given 5000 Kelvin."""
|
||||
mired = color_util.color_temperature_kelvin_to_mired(5000)
|
||||
assert 200 == mired
|
||||
assert color_util.color_rgbw_to_rgb(0, 0, 0, 255) == (255, 255, 255)
|
||||
|
||||
assert color_util.color_rgbw_to_rgb(255, 0, 0, 0) == (255, 0, 0)
|
||||
|
||||
class ColorTemperatureToRGB(unittest.TestCase):
|
||||
"""Test color_temperature_to_rgb."""
|
||||
assert color_util.color_rgbw_to_rgb(0, 255, 0, 0) == (0, 255, 0)
|
||||
|
||||
def test_returns_same_value_for_any_two_temperatures_below_1000(self):
|
||||
"""Function should return same value for 999 Kelvin and 0 Kelvin."""
|
||||
rgb_1 = color_util.color_temperature_to_rgb(999)
|
||||
rgb_2 = color_util.color_temperature_to_rgb(0)
|
||||
assert rgb_1 == rgb_2
|
||||
assert color_util.color_rgbw_to_rgb(0, 0, 255, 0) == (0, 0, 255)
|
||||
|
||||
def test_returns_same_value_for_any_two_temperatures_above_40000(self):
|
||||
"""Function should return same value for 40001K and 999999K."""
|
||||
rgb_1 = color_util.color_temperature_to_rgb(40001)
|
||||
rgb_2 = color_util.color_temperature_to_rgb(999999)
|
||||
assert rgb_1 == rgb_2
|
||||
assert color_util.color_rgbw_to_rgb(255, 127, 0, 0) == (255, 127, 0)
|
||||
|
||||
def test_should_return_pure_white_at_6600(self):
|
||||
"""
|
||||
Function should return red=255, blue=255, green=255 when given 6600K.
|
||||
assert color_util.color_rgbw_to_rgb(255, 0, 0, 253) == (255, 127, 127)
|
||||
|
||||
6600K is considered "pure white" light.
|
||||
This is just a rough estimate because the formula itself is a "best
|
||||
guess" approach.
|
||||
"""
|
||||
rgb = color_util.color_temperature_to_rgb(6600)
|
||||
assert (255, 255, 255) == rgb
|
||||
|
||||
def test_color_above_6600_should_have_more_blue_than_red_or_green(self):
|
||||
"""Function should return a higher blue value for blue-ish light."""
|
||||
rgb = color_util.color_temperature_to_rgb(6700)
|
||||
assert rgb[2] > rgb[1]
|
||||
assert rgb[2] > rgb[0]
|
||||
|
||||
def test_color_below_6600_should_have_more_red_than_blue_or_green(self):
|
||||
"""Function should return a higher red value for red-ish light."""
|
||||
rgb = color_util.color_temperature_to_rgb(6500)
|
||||
assert rgb[0] > rgb[1]
|
||||
assert rgb[0] > rgb[2]
|
||||
assert color_util.color_rgbw_to_rgb(0, 0, 0, 127) == (127, 127, 127)
|
||||
|
||||
|
||||
def test_color_rgb_to_hex():
|
||||
"""Test color_rgb_to_hex."""
|
||||
assert color_util.color_rgb_to_hex(255, 255, 255) == 'ffffff'
|
||||
assert color_util.color_rgb_to_hex(0, 0, 0) == '000000'
|
||||
assert color_util.color_rgb_to_hex(51, 153, 255) == '3399ff'
|
||||
assert color_util.color_rgb_to_hex(255, 67.9204190, 0) == 'ff4400'
|
||||
|
||||
|
||||
def test_gamut():
|
||||
"""Test gamut functions."""
|
||||
assert color_util.check_valid_gamut(GAMUT)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_1)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_2)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_3)
|
||||
assert not color_util.check_valid_gamut(GAMUT_INVALID_4)
|
||||
|
||||
|
||||
def test_should_return_25000_kelvin_when_input_is_40_mired():
|
||||
"""Function should return 25000K if given 40 mired."""
|
||||
kelvin = color_util.color_temperature_mired_to_kelvin(40)
|
||||
assert kelvin == 25000
|
||||
|
||||
|
||||
def test_should_return_5000_kelvin_when_input_is_200_mired():
|
||||
"""Function should return 5000K if given 200 mired."""
|
||||
kelvin = color_util.color_temperature_mired_to_kelvin(200)
|
||||
assert kelvin == 5000
|
||||
|
||||
|
||||
def test_should_return_40_mired_when_input_is_25000_kelvin():
|
||||
"""Function should return 40 mired when given 25000 Kelvin."""
|
||||
mired = color_util.color_temperature_kelvin_to_mired(25000)
|
||||
assert mired == 40
|
||||
|
||||
|
||||
def test_should_return_200_mired_when_input_is_5000_kelvin():
|
||||
"""Function should return 200 mired when given 5000 Kelvin."""
|
||||
mired = color_util.color_temperature_kelvin_to_mired(5000)
|
||||
assert mired == 200
|
||||
|
||||
|
||||
def test_returns_same_value_for_any_two_temperatures_below_1000():
|
||||
"""Function should return same value for 999 Kelvin and 0 Kelvin."""
|
||||
rgb_1 = color_util.color_temperature_to_rgb(999)
|
||||
rgb_2 = color_util.color_temperature_to_rgb(0)
|
||||
assert rgb_1 == rgb_2
|
||||
|
||||
|
||||
def test_returns_same_value_for_any_two_temperatures_above_40000():
|
||||
"""Function should return same value for 40001K and 999999K."""
|
||||
rgb_1 = color_util.color_temperature_to_rgb(40001)
|
||||
rgb_2 = color_util.color_temperature_to_rgb(999999)
|
||||
assert rgb_1 == rgb_2
|
||||
|
||||
|
||||
def test_should_return_pure_white_at_6600():
|
||||
"""
|
||||
Function should return red=255, blue=255, green=255 when given 6600K.
|
||||
|
||||
6600K is considered "pure white" light.
|
||||
This is just a rough estimate because the formula itself is a "best
|
||||
guess" approach.
|
||||
"""
|
||||
rgb = color_util.color_temperature_to_rgb(6600)
|
||||
assert (255, 255, 255) == rgb
|
||||
|
||||
|
||||
def test_color_above_6600_should_have_more_blue_than_red_or_green():
|
||||
"""Function should return a higher blue value for blue-ish light."""
|
||||
rgb = color_util.color_temperature_to_rgb(6700)
|
||||
assert rgb[2] > rgb[1]
|
||||
assert rgb[2] > rgb[0]
|
||||
|
||||
|
||||
def test_color_below_6600_should_have_more_red_than_blue_or_green():
|
||||
"""Function should return a higher red value for red-ish light."""
|
||||
rgb = color_util.color_temperature_to_rgb(6500)
|
||||
assert rgb[0] > rgb[1]
|
||||
assert rgb[0] > rgb[2]
|
||||
|
||||
|
||||
def test_get_color_in_voluptuous():
|
||||
|
|
|
@ -1,79 +1,68 @@
|
|||
"""Test homeassistant distance utility functions."""
|
||||
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
import homeassistant.util.distance as distance_util
|
||||
from homeassistant.const import (LENGTH_KILOMETERS, LENGTH_METERS, LENGTH_FEET,
|
||||
LENGTH_MILES)
|
||||
import pytest
|
||||
|
||||
INVALID_SYMBOL = 'bob'
|
||||
VALID_SYMBOL = LENGTH_KILOMETERS
|
||||
|
||||
|
||||
class TestDistanceUtil(unittest.TestCase):
|
||||
"""Test the distance utility functions."""
|
||||
def test_convert_same_unit():
|
||||
"""Test conversion from any unit to same unit."""
|
||||
assert distance_util.convert(5, LENGTH_KILOMETERS, LENGTH_KILOMETERS) == 5
|
||||
assert distance_util.convert(2, LENGTH_METERS, LENGTH_METERS) == 2
|
||||
assert distance_util.convert(10, LENGTH_MILES, LENGTH_MILES) == 10
|
||||
assert distance_util.convert(9, LENGTH_FEET, LENGTH_FEET) == 9
|
||||
|
||||
def test_convert_same_unit(self):
|
||||
"""Test conversion from any unit to same unit."""
|
||||
assert 5 == distance_util.convert(5, LENGTH_KILOMETERS,
|
||||
LENGTH_KILOMETERS)
|
||||
assert 2 == distance_util.convert(2, LENGTH_METERS,
|
||||
LENGTH_METERS)
|
||||
assert 10 == distance_util.convert(10, LENGTH_MILES, LENGTH_MILES)
|
||||
assert 9 == distance_util.convert(9, LENGTH_FEET, LENGTH_FEET)
|
||||
|
||||
def test_convert_invalid_unit(self):
|
||||
"""Test exception is thrown for invalid units."""
|
||||
with pytest.raises(ValueError):
|
||||
distance_util.convert(5, INVALID_SYMBOL,
|
||||
VALID_SYMBOL)
|
||||
def test_convert_invalid_unit():
|
||||
"""Test exception is thrown for invalid units."""
|
||||
with pytest.raises(ValueError):
|
||||
distance_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
distance_util.convert(5, VALID_SYMBOL,
|
||||
INVALID_SYMBOL)
|
||||
with pytest.raises(ValueError):
|
||||
distance_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)
|
||||
|
||||
def test_convert_nonnumeric_value(self):
|
||||
"""Test exception is thrown for nonnumeric type."""
|
||||
with pytest.raises(TypeError):
|
||||
distance_util.convert('a', LENGTH_KILOMETERS, LENGTH_METERS)
|
||||
|
||||
def test_convert_from_miles(self):
|
||||
"""Test conversion from miles to other units."""
|
||||
miles = 5
|
||||
assert distance_util.convert(
|
||||
miles, LENGTH_MILES, LENGTH_KILOMETERS
|
||||
) == 8.04672
|
||||
assert distance_util.convert(miles, LENGTH_MILES, LENGTH_METERS) == \
|
||||
8046.72
|
||||
assert distance_util.convert(miles, LENGTH_MILES, LENGTH_FEET) == \
|
||||
26400.0008448
|
||||
def test_convert_nonnumeric_value():
|
||||
"""Test exception is thrown for nonnumeric type."""
|
||||
with pytest.raises(TypeError):
|
||||
distance_util.convert('a', LENGTH_KILOMETERS, LENGTH_METERS)
|
||||
|
||||
def test_convert_from_feet(self):
|
||||
"""Test conversion from feet to other units."""
|
||||
feet = 5000
|
||||
assert distance_util.convert(feet, LENGTH_FEET, LENGTH_KILOMETERS) == \
|
||||
1.524
|
||||
assert distance_util.convert(feet, LENGTH_FEET, LENGTH_METERS) == \
|
||||
1524
|
||||
assert distance_util.convert(feet, LENGTH_FEET, LENGTH_MILES) == \
|
||||
0.9469694040000001
|
||||
|
||||
def test_convert_from_kilometers(self):
|
||||
"""Test conversion from kilometers to other units."""
|
||||
km = 5
|
||||
assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_FEET) == \
|
||||
16404.2
|
||||
assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_METERS) == \
|
||||
5000
|
||||
assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_MILES) == \
|
||||
3.106855
|
||||
def test_convert_from_miles():
|
||||
"""Test conversion from miles to other units."""
|
||||
miles = 5
|
||||
assert distance_util.convert(miles, LENGTH_MILES, LENGTH_KILOMETERS) == \
|
||||
8.04672
|
||||
assert distance_util.convert(miles, LENGTH_MILES, LENGTH_METERS) == 8046.72
|
||||
assert distance_util.convert(miles, LENGTH_MILES, LENGTH_FEET) == \
|
||||
26400.0008448
|
||||
|
||||
def test_convert_from_meters(self):
|
||||
"""Test conversion from meters to other units."""
|
||||
m = 5000
|
||||
assert distance_util.convert(m, LENGTH_METERS, LENGTH_FEET) == \
|
||||
16404.2
|
||||
assert distance_util.convert(m, LENGTH_METERS, LENGTH_KILOMETERS) == \
|
||||
5
|
||||
assert distance_util.convert(m, LENGTH_METERS, LENGTH_MILES) == \
|
||||
3.106855
|
||||
|
||||
def test_convert_from_feet():
|
||||
"""Test conversion from feet to other units."""
|
||||
feet = 5000
|
||||
assert distance_util.convert(feet, LENGTH_FEET, LENGTH_KILOMETERS) == 1.524
|
||||
assert distance_util.convert(feet, LENGTH_FEET, LENGTH_METERS) == 1524
|
||||
assert distance_util.convert(feet, LENGTH_FEET, LENGTH_MILES) == \
|
||||
0.9469694040000001
|
||||
|
||||
|
||||
def test_convert_from_kilometers():
|
||||
"""Test conversion from kilometers to other units."""
|
||||
km = 5
|
||||
assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_FEET) == 16404.2
|
||||
assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_METERS) == 5000
|
||||
assert distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_MILES) == \
|
||||
3.106855
|
||||
|
||||
|
||||
def test_convert_from_meters():
|
||||
"""Test conversion from meters to other units."""
|
||||
m = 5000
|
||||
assert distance_util.convert(m, LENGTH_METERS, LENGTH_FEET) == 16404.2
|
||||
assert distance_util.convert(m, LENGTH_METERS, LENGTH_KILOMETERS) == 5
|
||||
assert distance_util.convert(m, LENGTH_METERS, LENGTH_MILES) == 3.106855
|
||||
|
|
|
@ -1,253 +1,266 @@
|
|||
"""Test Home Assistant date util methods."""
|
||||
import unittest
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import homeassistant.util.dt as dt_util
|
||||
import pytest
|
||||
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
DEFAULT_TIME_ZONE = dt_util.DEFAULT_TIME_ZONE
|
||||
TEST_TIME_ZONE = 'America/Los_Angeles'
|
||||
|
||||
|
||||
class TestDateUtil(unittest.TestCase):
|
||||
"""Test util date methods."""
|
||||
def teardown():
|
||||
"""Stop everything that was started."""
|
||||
dt_util.set_default_time_zone(DEFAULT_TIME_ZONE)
|
||||
|
||||
def setUp(self):
|
||||
"""Set up the tests."""
|
||||
self.orig_default_time_zone = dt_util.DEFAULT_TIME_ZONE
|
||||
|
||||
def tearDown(self):
|
||||
"""Stop everything that was started."""
|
||||
dt_util.set_default_time_zone(self.orig_default_time_zone)
|
||||
def test_get_time_zone_retrieves_valid_time_zone():
|
||||
"""Test getting a time zone."""
|
||||
time_zone = dt_util.get_time_zone(TEST_TIME_ZONE)
|
||||
|
||||
def test_get_time_zone_retrieves_valid_time_zone(self):
|
||||
"""Test getting a time zone."""
|
||||
time_zone = dt_util.get_time_zone(TEST_TIME_ZONE)
|
||||
assert time_zone is not None
|
||||
assert TEST_TIME_ZONE == time_zone.zone
|
||||
|
||||
assert time_zone is not None
|
||||
assert TEST_TIME_ZONE == time_zone.zone
|
||||
|
||||
def test_get_time_zone_returns_none_for_garbage_time_zone(self):
|
||||
"""Test getting a non existing time zone."""
|
||||
time_zone = dt_util.get_time_zone("Non existing time zone")
|
||||
def test_get_time_zone_returns_none_for_garbage_time_zone():
|
||||
"""Test getting a non existing time zone."""
|
||||
time_zone = dt_util.get_time_zone("Non existing time zone")
|
||||
|
||||
assert time_zone is None
|
||||
assert time_zone is None
|
||||
|
||||
def test_set_default_time_zone(self):
|
||||
"""Test setting default time zone."""
|
||||
time_zone = dt_util.get_time_zone(TEST_TIME_ZONE)
|
||||
|
||||
dt_util.set_default_time_zone(time_zone)
|
||||
def test_set_default_time_zone():
|
||||
"""Test setting default time zone."""
|
||||
time_zone = dt_util.get_time_zone(TEST_TIME_ZONE)
|
||||
|
||||
# We cannot compare the timezones directly because of DST
|
||||
assert time_zone.zone == dt_util.now().tzinfo.zone
|
||||
dt_util.set_default_time_zone(time_zone)
|
||||
|
||||
def test_utcnow(self):
|
||||
"""Test the UTC now method."""
|
||||
assert abs(dt_util.utcnow().replace(tzinfo=None)-datetime.utcnow()) < \
|
||||
timedelta(seconds=1)
|
||||
# We cannot compare the timezones directly because of DST
|
||||
assert time_zone.zone == dt_util.now().tzinfo.zone
|
||||
|
||||
def test_now(self):
|
||||
"""Test the now method."""
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))
|
||||
|
||||
assert abs(
|
||||
dt_util.as_utc(dt_util.now()).replace(
|
||||
tzinfo=None
|
||||
) - datetime.utcnow()
|
||||
) < timedelta(seconds=1)
|
||||
def test_utcnow():
|
||||
"""Test the UTC now method."""
|
||||
assert abs(dt_util.utcnow().replace(tzinfo=None)-datetime.utcnow()) < \
|
||||
timedelta(seconds=1)
|
||||
|
||||
def test_as_utc_with_naive_object(self):
|
||||
"""Test the now method."""
|
||||
utcnow = datetime.utcnow()
|
||||
|
||||
assert utcnow == dt_util.as_utc(utcnow).replace(tzinfo=None)
|
||||
def test_now():
|
||||
"""Test the now method."""
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))
|
||||
|
||||
def test_as_utc_with_utc_object(self):
|
||||
"""Test UTC time with UTC object."""
|
||||
utcnow = dt_util.utcnow()
|
||||
assert abs(
|
||||
dt_util.as_utc(dt_util.now()).replace(
|
||||
tzinfo=None
|
||||
) - datetime.utcnow()
|
||||
) < timedelta(seconds=1)
|
||||
|
||||
assert utcnow == dt_util.as_utc(utcnow)
|
||||
|
||||
def test_as_utc_with_local_object(self):
|
||||
"""Test the UTC time with local object."""
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))
|
||||
localnow = dt_util.now()
|
||||
utcnow = dt_util.as_utc(localnow)
|
||||
def test_as_utc_with_naive_object():
|
||||
"""Test the now method."""
|
||||
utcnow = datetime.utcnow()
|
||||
|
||||
assert localnow == utcnow
|
||||
assert localnow.tzinfo != utcnow.tzinfo
|
||||
assert utcnow == dt_util.as_utc(utcnow).replace(tzinfo=None)
|
||||
|
||||
def test_as_local_with_naive_object(self):
|
||||
"""Test local time with native object."""
|
||||
now = dt_util.now()
|
||||
assert abs(now-dt_util.as_local(datetime.utcnow())) < \
|
||||
timedelta(seconds=1)
|
||||
|
||||
def test_as_local_with_local_object(self):
|
||||
"""Test local with local object."""
|
||||
now = dt_util.now()
|
||||
assert now == now
|
||||
def test_as_utc_with_utc_object():
|
||||
"""Test UTC time with UTC object."""
|
||||
utcnow = dt_util.utcnow()
|
||||
|
||||
def test_as_local_with_utc_object(self):
|
||||
"""Test local time with UTC object."""
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))
|
||||
assert utcnow == dt_util.as_utc(utcnow)
|
||||
|
||||
utcnow = dt_util.utcnow()
|
||||
localnow = dt_util.as_local(utcnow)
|
||||
|
||||
assert localnow == utcnow
|
||||
assert localnow.tzinfo != utcnow.tzinfo
|
||||
def test_as_utc_with_local_object():
|
||||
"""Test the UTC time with local object."""
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))
|
||||
localnow = dt_util.now()
|
||||
utcnow = dt_util.as_utc(localnow)
|
||||
|
||||
def test_utc_from_timestamp(self):
|
||||
"""Test utc_from_timestamp method."""
|
||||
assert datetime(1986, 7, 9, tzinfo=dt_util.UTC) == \
|
||||
dt_util.utc_from_timestamp(521251200)
|
||||
assert localnow == utcnow
|
||||
assert localnow.tzinfo != utcnow.tzinfo
|
||||
|
||||
def test_as_timestamp(self):
|
||||
"""Test as_timestamp method."""
|
||||
ts = 1462401234
|
||||
utc_dt = dt_util.utc_from_timestamp(ts)
|
||||
assert ts == dt_util.as_timestamp(utc_dt)
|
||||
utc_iso = utc_dt.isoformat()
|
||||
assert ts == dt_util.as_timestamp(utc_iso)
|
||||
|
||||
# confirm the ability to handle a string passed in
|
||||
delta = dt_util.as_timestamp("2016-01-01 12:12:12")
|
||||
delta -= dt_util.as_timestamp("2016-01-01 12:12:11")
|
||||
assert 1 == delta
|
||||
def test_as_local_with_naive_object():
|
||||
"""Test local time with native object."""
|
||||
now = dt_util.now()
|
||||
assert abs(now-dt_util.as_local(datetime.utcnow())) < \
|
||||
timedelta(seconds=1)
|
||||
|
||||
def test_parse_datetime_converts_correctly(self):
|
||||
"""Test parse_datetime converts strings."""
|
||||
assert \
|
||||
datetime(1986, 7, 9, 12, 0, 0, tzinfo=dt_util.UTC) == \
|
||||
dt_util.parse_datetime("1986-07-09T12:00:00Z")
|
||||
|
||||
utcnow = dt_util.utcnow()
|
||||
def test_as_local_with_local_object():
|
||||
"""Test local with local object."""
|
||||
now = dt_util.now()
|
||||
assert now == now
|
||||
|
||||
assert utcnow == dt_util.parse_datetime(utcnow.isoformat())
|
||||
|
||||
def test_parse_datetime_returns_none_for_incorrect_format(self):
|
||||
"""Test parse_datetime returns None if incorrect format."""
|
||||
assert dt_util.parse_datetime("not a datetime string") is None
|
||||
def test_as_local_with_utc_object():
|
||||
"""Test local time with UTC object."""
|
||||
dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE))
|
||||
|
||||
def test_get_age(self):
|
||||
"""Test get_age."""
|
||||
diff = dt_util.now() - timedelta(seconds=0)
|
||||
assert dt_util.get_age(diff) == "0 seconds"
|
||||
utcnow = dt_util.utcnow()
|
||||
localnow = dt_util.as_local(utcnow)
|
||||
|
||||
diff = dt_util.now() - timedelta(seconds=1)
|
||||
assert dt_util.get_age(diff) == "1 second"
|
||||
assert localnow == utcnow
|
||||
assert localnow.tzinfo != utcnow.tzinfo
|
||||
|
||||
diff = dt_util.now() - timedelta(seconds=30)
|
||||
assert dt_util.get_age(diff) == "30 seconds"
|
||||
|
||||
diff = dt_util.now() - timedelta(minutes=5)
|
||||
assert dt_util.get_age(diff) == "5 minutes"
|
||||
def test_utc_from_timestamp():
|
||||
"""Test utc_from_timestamp method."""
|
||||
assert datetime(1986, 7, 9, tzinfo=dt_util.UTC) == \
|
||||
dt_util.utc_from_timestamp(521251200)
|
||||
|
||||
diff = dt_util.now() - timedelta(minutes=1)
|
||||
assert dt_util.get_age(diff) == "1 minute"
|
||||
|
||||
diff = dt_util.now() - timedelta(minutes=300)
|
||||
assert dt_util.get_age(diff) == "5 hours"
|
||||
def test_as_timestamp():
|
||||
"""Test as_timestamp method."""
|
||||
ts = 1462401234
|
||||
utc_dt = dt_util.utc_from_timestamp(ts)
|
||||
assert ts == dt_util.as_timestamp(utc_dt)
|
||||
utc_iso = utc_dt.isoformat()
|
||||
assert ts == dt_util.as_timestamp(utc_iso)
|
||||
|
||||
diff = dt_util.now() - timedelta(minutes=320)
|
||||
assert dt_util.get_age(diff) == "5 hours"
|
||||
# confirm the ability to handle a string passed in
|
||||
delta = dt_util.as_timestamp("2016-01-01 12:12:12")
|
||||
delta -= dt_util.as_timestamp("2016-01-01 12:12:11")
|
||||
assert delta == 1
|
||||
|
||||
diff = dt_util.now() - timedelta(minutes=2*60*24)
|
||||
assert dt_util.get_age(diff) == "2 days"
|
||||
|
||||
diff = dt_util.now() - timedelta(minutes=32*60*24)
|
||||
assert dt_util.get_age(diff) == "1 month"
|
||||
def test_parse_datetime_converts_correctly():
|
||||
"""Test parse_datetime converts strings."""
|
||||
assert \
|
||||
datetime(1986, 7, 9, 12, 0, 0, tzinfo=dt_util.UTC) == \
|
||||
dt_util.parse_datetime("1986-07-09T12:00:00Z")
|
||||
|
||||
diff = dt_util.now() - timedelta(minutes=365*60*24)
|
||||
assert dt_util.get_age(diff) == "1 year"
|
||||
utcnow = dt_util.utcnow()
|
||||
|
||||
def test_parse_time_expression(self):
|
||||
"""Test parse_time_expression."""
|
||||
assert [x for x in range(60)] == \
|
||||
dt_util.parse_time_expression('*', 0, 59)
|
||||
assert [x for x in range(60)] == \
|
||||
dt_util.parse_time_expression(None, 0, 59)
|
||||
assert utcnow == dt_util.parse_datetime(utcnow.isoformat())
|
||||
|
||||
assert [x for x in range(0, 60, 5)] == \
|
||||
dt_util.parse_time_expression('/5', 0, 59)
|
||||
|
||||
assert [1, 2, 3] == \
|
||||
dt_util.parse_time_expression([2, 1, 3], 0, 59)
|
||||
def test_parse_datetime_returns_none_for_incorrect_format():
|
||||
"""Test parse_datetime returns None if incorrect format."""
|
||||
assert dt_util.parse_datetime("not a datetime string") is None
|
||||
|
||||
assert [x for x in range(24)] == \
|
||||
dt_util.parse_time_expression('*', 0, 23)
|
||||
|
||||
assert [42] == \
|
||||
dt_util.parse_time_expression(42, 0, 59)
|
||||
def test_get_age():
|
||||
"""Test get_age."""
|
||||
diff = dt_util.now() - timedelta(seconds=0)
|
||||
assert dt_util.get_age(diff) == "0 seconds"
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
dt_util.parse_time_expression(61, 0, 60)
|
||||
diff = dt_util.now() - timedelta(seconds=1)
|
||||
assert dt_util.get_age(diff) == "1 second"
|
||||
|
||||
def test_find_next_time_expression_time_basic(self):
|
||||
"""Test basic stuff for find_next_time_expression_time."""
|
||||
def find(dt, hour, minute, second):
|
||||
"""Call test_find_next_time_expression_time."""
|
||||
seconds = dt_util.parse_time_expression(second, 0, 59)
|
||||
minutes = dt_util.parse_time_expression(minute, 0, 59)
|
||||
hours = dt_util.parse_time_expression(hour, 0, 23)
|
||||
diff = dt_util.now() - timedelta(seconds=30)
|
||||
assert dt_util.get_age(diff) == "30 seconds"
|
||||
|
||||
return dt_util.find_next_time_expression_time(
|
||||
dt, seconds, minutes, hours)
|
||||
diff = dt_util.now() - timedelta(minutes=5)
|
||||
assert dt_util.get_age(diff) == "5 minutes"
|
||||
|
||||
assert datetime(2018, 10, 7, 10, 30, 0) == \
|
||||
find(datetime(2018, 10, 7, 10, 20, 0), '*', '/30', 0)
|
||||
diff = dt_util.now() - timedelta(minutes=1)
|
||||
assert dt_util.get_age(diff) == "1 minute"
|
||||
|
||||
assert datetime(2018, 10, 7, 10, 30, 0) == \
|
||||
find(datetime(2018, 10, 7, 10, 30, 0), '*', '/30', 0)
|
||||
diff = dt_util.now() - timedelta(minutes=300)
|
||||
assert dt_util.get_age(diff) == "5 hours"
|
||||
|
||||
assert datetime(2018, 10, 7, 12, 30, 30) == \
|
||||
find(datetime(2018, 10, 7, 10, 30, 0), '/3', '/30', [30, 45])
|
||||
diff = dt_util.now() - timedelta(minutes=320)
|
||||
assert dt_util.get_age(diff) == "5 hours"
|
||||
|
||||
assert datetime(2018, 10, 8, 5, 0, 0) == \
|
||||
find(datetime(2018, 10, 7, 10, 30, 0), 5, 0, 0)
|
||||
diff = dt_util.now() - timedelta(minutes=2*60*24)
|
||||
assert dt_util.get_age(diff) == "2 days"
|
||||
|
||||
def test_find_next_time_expression_time_dst(self):
|
||||
"""Test daylight saving time for find_next_time_expression_time."""
|
||||
tz = dt_util.get_time_zone('Europe/Vienna')
|
||||
dt_util.set_default_time_zone(tz)
|
||||
diff = dt_util.now() - timedelta(minutes=32*60*24)
|
||||
assert dt_util.get_age(diff) == "1 month"
|
||||
|
||||
def find(dt, hour, minute, second):
|
||||
"""Call test_find_next_time_expression_time."""
|
||||
seconds = dt_util.parse_time_expression(second, 0, 59)
|
||||
minutes = dt_util.parse_time_expression(minute, 0, 59)
|
||||
hours = dt_util.parse_time_expression(hour, 0, 23)
|
||||
diff = dt_util.now() - timedelta(minutes=365*60*24)
|
||||
assert dt_util.get_age(diff) == "1 year"
|
||||
|
||||
return dt_util.find_next_time_expression_time(
|
||||
dt, seconds, minutes, hours)
|
||||
|
||||
# Entering DST, clocks are rolled forward
|
||||
assert tz.localize(datetime(2018, 3, 26, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 3, 25, 1, 50, 0)), 2, 30, 0)
|
||||
def test_parse_time_expression():
|
||||
"""Test parse_time_expression."""
|
||||
assert [x for x in range(60)] == \
|
||||
dt_util.parse_time_expression('*', 0, 59)
|
||||
assert [x for x in range(60)] == \
|
||||
dt_util.parse_time_expression(None, 0, 59)
|
||||
|
||||
assert tz.localize(datetime(2018, 3, 26, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 3, 25, 3, 50, 0)), 2, 30, 0)
|
||||
assert [x for x in range(0, 60, 5)] == \
|
||||
dt_util.parse_time_expression('/5', 0, 59)
|
||||
|
||||
assert tz.localize(datetime(2018, 3, 26, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 3, 26, 1, 50, 0)), 2, 30, 0)
|
||||
assert [1, 2, 3] == \
|
||||
dt_util.parse_time_expression([2, 1, 3], 0, 59)
|
||||
|
||||
# Leaving DST, clocks are rolled back
|
||||
assert tz.localize(datetime(2018, 10, 28, 2, 30, 0), is_dst=False) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=False),
|
||||
2, 30, 0)
|
||||
assert [x for x in range(24)] == \
|
||||
dt_util.parse_time_expression('*', 0, 23)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 28, 2, 30, 0), is_dst=False) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=True),
|
||||
2, 30, 0)
|
||||
assert [42] == \
|
||||
dt_util.parse_time_expression(42, 0, 59)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 28, 4, 30, 0), is_dst=False) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=True),
|
||||
4, 30, 0)
|
||||
with pytest.raises(ValueError):
|
||||
dt_util.parse_time_expression(61, 0, 60)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 28, 2, 30, 0), is_dst=True) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=True),
|
||||
2, 30, 0)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 29, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=False),
|
||||
2, 30, 0)
|
||||
def test_find_next_time_expression_time_basic():
|
||||
"""Test basic stuff for find_next_time_expression_time."""
|
||||
def find(dt, hour, minute, second):
|
||||
"""Call test_find_next_time_expression_time."""
|
||||
seconds = dt_util.parse_time_expression(second, 0, 59)
|
||||
minutes = dt_util.parse_time_expression(minute, 0, 59)
|
||||
hours = dt_util.parse_time_expression(hour, 0, 23)
|
||||
|
||||
return dt_util.find_next_time_expression_time(
|
||||
dt, seconds, minutes, hours)
|
||||
|
||||
assert datetime(2018, 10, 7, 10, 30, 0) == \
|
||||
find(datetime(2018, 10, 7, 10, 20, 0), '*', '/30', 0)
|
||||
|
||||
assert datetime(2018, 10, 7, 10, 30, 0) == \
|
||||
find(datetime(2018, 10, 7, 10, 30, 0), '*', '/30', 0)
|
||||
|
||||
assert datetime(2018, 10, 7, 12, 30, 30) == \
|
||||
find(datetime(2018, 10, 7, 10, 30, 0), '/3', '/30', [30, 45])
|
||||
|
||||
assert datetime(2018, 10, 8, 5, 0, 0) == \
|
||||
find(datetime(2018, 10, 7, 10, 30, 0), 5, 0, 0)
|
||||
|
||||
|
||||
def test_find_next_time_expression_time_dst():
|
||||
"""Test daylight saving time for find_next_time_expression_time."""
|
||||
tz = dt_util.get_time_zone('Europe/Vienna')
|
||||
dt_util.set_default_time_zone(tz)
|
||||
|
||||
def find(dt, hour, minute, second):
|
||||
"""Call test_find_next_time_expression_time."""
|
||||
seconds = dt_util.parse_time_expression(second, 0, 59)
|
||||
minutes = dt_util.parse_time_expression(minute, 0, 59)
|
||||
hours = dt_util.parse_time_expression(hour, 0, 23)
|
||||
|
||||
return dt_util.find_next_time_expression_time(
|
||||
dt, seconds, minutes, hours)
|
||||
|
||||
# Entering DST, clocks are rolled forward
|
||||
assert tz.localize(datetime(2018, 3, 26, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 3, 25, 1, 50, 0)), 2, 30, 0)
|
||||
|
||||
assert tz.localize(datetime(2018, 3, 26, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 3, 25, 3, 50, 0)), 2, 30, 0)
|
||||
|
||||
assert tz.localize(datetime(2018, 3, 26, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 3, 26, 1, 50, 0)), 2, 30, 0)
|
||||
|
||||
# Leaving DST, clocks are rolled back
|
||||
assert tz.localize(datetime(2018, 10, 28, 2, 30, 0), is_dst=False) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=False),
|
||||
2, 30, 0)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 28, 2, 30, 0), is_dst=False) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=True),
|
||||
2, 30, 0)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 28, 4, 30, 0), is_dst=False) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=True),
|
||||
4, 30, 0)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 28, 2, 30, 0), is_dst=True) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 5, 0), is_dst=True),
|
||||
2, 30, 0)
|
||||
|
||||
assert tz.localize(datetime(2018, 10, 29, 2, 30, 0)) == \
|
||||
find(tz.localize(datetime(2018, 10, 28, 2, 55, 0), is_dst=False),
|
||||
2, 30, 0)
|
||||
|
|
|
@ -1,223 +1,228 @@
|
|||
"""Test Home Assistant util methods."""
|
||||
import unittest
|
||||
from unittest.mock import patch, MagicMock
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from homeassistant import util
|
||||
import homeassistant.util.dt as dt_util
|
||||
import pytest
|
||||
|
||||
from homeassistant import util
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
class TestUtil(unittest.TestCase):
|
||||
"""Test util methods."""
|
||||
|
||||
def test_sanitize_filename(self):
|
||||
"""Test sanitize_filename."""
|
||||
assert "test" == util.sanitize_filename("test")
|
||||
assert "test" == util.sanitize_filename("/test")
|
||||
assert "test" == util.sanitize_filename("..test")
|
||||
assert "test" == util.sanitize_filename("\\test")
|
||||
assert "test" == util.sanitize_filename("\\../test")
|
||||
def test_sanitize_filename():
|
||||
"""Test sanitize_filename."""
|
||||
assert util.sanitize_filename("test") == 'test'
|
||||
assert util.sanitize_filename("/test") == 'test'
|
||||
assert util.sanitize_filename("..test") == 'test'
|
||||
assert util.sanitize_filename("\\test") == 'test'
|
||||
assert util.sanitize_filename("\\../test") == 'test'
|
||||
|
||||
def test_sanitize_path(self):
|
||||
"""Test sanitize_path."""
|
||||
assert "test/path" == util.sanitize_path("test/path")
|
||||
assert "test/path" == util.sanitize_path("~test/path")
|
||||
assert "//test/path" == util.sanitize_path("~/../test/path")
|
||||
|
||||
def test_slugify(self):
|
||||
"""Test slugify."""
|
||||
assert "t_est" == util.slugify("T-!@#$!#@$!$est")
|
||||
assert "test_more" == util.slugify("Test More")
|
||||
assert "test_more" == util.slugify("Test_(More)")
|
||||
assert "test_more" == util.slugify("Tèst_Mörê")
|
||||
assert "b8_27_eb_00_00_00" == util.slugify("B8:27:EB:00:00:00")
|
||||
assert "test_com" == util.slugify("test.com")
|
||||
assert "greg_phone_exp_wayp1" == \
|
||||
util.slugify("greg_phone - exp_wayp1")
|
||||
assert "we_are_we_are_a_test_calendar" == \
|
||||
util.slugify("We are, we are, a... Test Calendar")
|
||||
assert "test_aouss_aou" == util.slugify("Tèst_äöüß_ÄÖÜ")
|
||||
assert "ying_shi_ma" == util.slugify("影師嗎")
|
||||
assert "keihuonto" == util.slugify("けいふぉんと")
|
||||
def test_sanitize_path():
|
||||
"""Test sanitize_path."""
|
||||
assert util.sanitize_path("test/path") == 'test/path'
|
||||
assert util.sanitize_path("~test/path") == 'test/path'
|
||||
assert util.sanitize_path("~/../test/path") == '//test/path'
|
||||
|
||||
def test_repr_helper(self):
|
||||
"""Test repr_helper."""
|
||||
assert "A" == util.repr_helper("A")
|
||||
assert "5" == util.repr_helper(5)
|
||||
assert "True" == util.repr_helper(True)
|
||||
assert "test=1" == util.repr_helper({"test": 1})
|
||||
assert "1986-07-09T12:00:00+00:00" == \
|
||||
util.repr_helper(datetime(1986, 7, 9, 12, 0, 0))
|
||||
|
||||
def test_convert(self):
|
||||
"""Test convert."""
|
||||
assert 5 == util.convert("5", int)
|
||||
assert 5.0 == util.convert("5", float)
|
||||
assert util.convert("True", bool) is True
|
||||
assert 1 == util.convert("NOT A NUMBER", int, 1)
|
||||
assert 1 == util.convert(None, int, 1)
|
||||
assert 1 == util.convert(object, int, 1)
|
||||
def test_slugify():
|
||||
"""Test slugify."""
|
||||
assert util.slugify("T-!@#$!#@$!$est") == 't_est'
|
||||
assert util.slugify("Test More") == 'test_more'
|
||||
assert util.slugify("Test_(More)") == 'test_more'
|
||||
assert util.slugify("Tèst_Mörê") == 'test_more'
|
||||
assert util.slugify("B8:27:EB:00:00:00") == 'b8_27_eb_00_00_00'
|
||||
assert util.slugify("test.com") == 'test_com'
|
||||
assert util.slugify("greg_phone - exp_wayp1") == 'greg_phone_exp_wayp1'
|
||||
assert util.slugify("We are, we are, a... Test Calendar") == \
|
||||
'we_are_we_are_a_test_calendar'
|
||||
assert util.slugify("Tèst_äöüß_ÄÖÜ") == 'test_aouss_aou'
|
||||
assert util.slugify("影師嗎") == 'ying_shi_ma'
|
||||
assert util.slugify("けいふぉんと") == 'keihuonto'
|
||||
|
||||
def test_ensure_unique_string(self):
|
||||
"""Test ensure_unique_string."""
|
||||
assert "Beer_3" == \
|
||||
util.ensure_unique_string("Beer", ["Beer", "Beer_2"])
|
||||
assert "Beer" == \
|
||||
util.ensure_unique_string("Beer", ["Wine", "Soda"])
|
||||
|
||||
def test_ordered_enum(self):
|
||||
"""Test the ordered enum class."""
|
||||
class TestEnum(util.OrderedEnum):
|
||||
"""Test enum that can be ordered."""
|
||||
def test_repr_helper():
|
||||
"""Test repr_helper."""
|
||||
assert util.repr_helper("A") == 'A'
|
||||
assert util.repr_helper(5) == '5'
|
||||
assert util.repr_helper(True) == 'True'
|
||||
assert util.repr_helper({"test": 1}) == 'test=1'
|
||||
assert util.repr_helper(datetime(1986, 7, 9, 12, 0, 0)) == \
|
||||
'1986-07-09T12:00:00+00:00'
|
||||
|
||||
FIRST = 1
|
||||
SECOND = 2
|
||||
THIRD = 3
|
||||
|
||||
assert TestEnum.SECOND >= TestEnum.FIRST
|
||||
assert TestEnum.SECOND >= TestEnum.SECOND
|
||||
assert not (TestEnum.SECOND >= TestEnum.THIRD)
|
||||
def test_convert():
|
||||
"""Test convert."""
|
||||
assert util.convert("5", int) == 5
|
||||
assert util.convert("5", float) == 5.0
|
||||
assert util.convert("True", bool) is True
|
||||
assert util.convert("NOT A NUMBER", int, 1) == 1
|
||||
assert util.convert(None, int, 1) == 1
|
||||
assert util.convert(object, int, 1) == 1
|
||||
|
||||
assert TestEnum.SECOND > TestEnum.FIRST
|
||||
assert not (TestEnum.SECOND > TestEnum.SECOND)
|
||||
assert not (TestEnum.SECOND > TestEnum.THIRD)
|
||||
|
||||
assert not (TestEnum.SECOND <= TestEnum.FIRST)
|
||||
assert TestEnum.SECOND <= TestEnum.SECOND
|
||||
assert TestEnum.SECOND <= TestEnum.THIRD
|
||||
def test_ensure_unique_string():
|
||||
"""Test ensure_unique_string."""
|
||||
assert util.ensure_unique_string("Beer", ["Beer", "Beer_2"]) == 'Beer_3'
|
||||
assert util.ensure_unique_string("Beer", ["Wine", "Soda"]) == 'Beer'
|
||||
|
||||
assert not (TestEnum.SECOND < TestEnum.FIRST)
|
||||
assert not (TestEnum.SECOND < TestEnum.SECOND)
|
||||
assert TestEnum.SECOND < TestEnum.THIRD
|
||||
|
||||
# Python will raise a TypeError if the <, <=, >, >= methods
|
||||
# raise a NotImplemented error.
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST < 1
|
||||
def test_ordered_enum():
|
||||
"""Test the ordered enum class."""
|
||||
class TestEnum(util.OrderedEnum):
|
||||
"""Test enum that can be ordered."""
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST <= 1
|
||||
FIRST = 1
|
||||
SECOND = 2
|
||||
THIRD = 3
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST > 1
|
||||
assert TestEnum.SECOND >= TestEnum.FIRST
|
||||
assert TestEnum.SECOND >= TestEnum.SECOND
|
||||
assert TestEnum.SECOND < TestEnum.THIRD
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST >= 1
|
||||
assert TestEnum.SECOND > TestEnum.FIRST
|
||||
assert TestEnum.SECOND <= TestEnum.SECOND
|
||||
assert TestEnum.SECOND <= TestEnum.THIRD
|
||||
|
||||
def test_throttle(self):
|
||||
"""Test the add cooldown decorator."""
|
||||
calls1 = []
|
||||
calls2 = []
|
||||
assert TestEnum.SECOND > TestEnum.FIRST
|
||||
assert TestEnum.SECOND <= TestEnum.SECOND
|
||||
assert TestEnum.SECOND <= TestEnum.THIRD
|
||||
|
||||
@util.Throttle(timedelta(seconds=4))
|
||||
def test_throttle1():
|
||||
calls1.append(1)
|
||||
assert TestEnum.SECOND >= TestEnum.FIRST
|
||||
assert TestEnum.SECOND >= TestEnum.SECOND
|
||||
assert TestEnum.SECOND < TestEnum.THIRD
|
||||
|
||||
@util.Throttle(timedelta(seconds=4), timedelta(seconds=2))
|
||||
def test_throttle2():
|
||||
calls2.append(1)
|
||||
# Python will raise a TypeError if the <, <=, >, >= methods
|
||||
# raise a NotImplemented error.
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST < 1
|
||||
|
||||
now = dt_util.utcnow()
|
||||
plus3 = now + timedelta(seconds=3)
|
||||
plus5 = plus3 + timedelta(seconds=2)
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST <= 1
|
||||
|
||||
# Call first time and ensure methods got called
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST > 1
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
TestEnum.FIRST >= 1
|
||||
|
||||
|
||||
def test_throttle():
|
||||
"""Test the add cooldown decorator."""
|
||||
calls1 = []
|
||||
calls2 = []
|
||||
|
||||
@util.Throttle(timedelta(seconds=4))
|
||||
def test_throttle1():
|
||||
calls1.append(1)
|
||||
|
||||
@util.Throttle(timedelta(seconds=4), timedelta(seconds=2))
|
||||
def test_throttle2():
|
||||
calls2.append(1)
|
||||
|
||||
now = dt_util.utcnow()
|
||||
plus3 = now + timedelta(seconds=3)
|
||||
plus5 = plus3 + timedelta(seconds=2)
|
||||
|
||||
# Call first time and ensure methods got called
|
||||
test_throttle1()
|
||||
test_throttle2()
|
||||
|
||||
assert len(calls1) == 1
|
||||
assert len(calls2) == 1
|
||||
|
||||
# Call second time. Methods should not get called
|
||||
test_throttle1()
|
||||
test_throttle2()
|
||||
|
||||
assert len(calls1) == 1
|
||||
assert len(calls2) == 1
|
||||
|
||||
# Call again, overriding throttle, only first one should fire
|
||||
test_throttle1(no_throttle=True)
|
||||
test_throttle2(no_throttle=True)
|
||||
|
||||
assert len(calls1) == 2
|
||||
assert len(calls2) == 1
|
||||
|
||||
with patch('homeassistant.util.utcnow', return_value=plus3):
|
||||
test_throttle1()
|
||||
test_throttle2()
|
||||
|
||||
assert 1 == len(calls1)
|
||||
assert 1 == len(calls2)
|
||||
assert len(calls1) == 2
|
||||
assert len(calls2) == 1
|
||||
|
||||
# Call second time. Methods should not get called
|
||||
with patch('homeassistant.util.utcnow', return_value=plus5):
|
||||
test_throttle1()
|
||||
test_throttle2()
|
||||
|
||||
assert 1 == len(calls1)
|
||||
assert 1 == len(calls2)
|
||||
assert len(calls1) == 3
|
||||
assert len(calls2) == 2
|
||||
|
||||
# Call again, overriding throttle, only first one should fire
|
||||
test_throttle1(no_throttle=True)
|
||||
test_throttle2(no_throttle=True)
|
||||
|
||||
assert 2 == len(calls1)
|
||||
assert 1 == len(calls2)
|
||||
def test_throttle_per_instance():
|
||||
"""Test that the throttle method is done per instance of a class."""
|
||||
class Tester:
|
||||
"""A tester class for the throttle."""
|
||||
|
||||
with patch('homeassistant.util.utcnow', return_value=plus3):
|
||||
test_throttle1()
|
||||
test_throttle2()
|
||||
@util.Throttle(timedelta(seconds=1))
|
||||
def hello(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
|
||||
assert 2 == len(calls1)
|
||||
assert 1 == len(calls2)
|
||||
assert Tester().hello()
|
||||
assert Tester().hello()
|
||||
|
||||
with patch('homeassistant.util.utcnow', return_value=plus5):
|
||||
test_throttle1()
|
||||
test_throttle2()
|
||||
|
||||
assert 3 == len(calls1)
|
||||
assert 2 == len(calls2)
|
||||
def test_throttle_on_method():
|
||||
"""Test that throttle works when wrapping a method."""
|
||||
class Tester:
|
||||
"""A tester class for the throttle."""
|
||||
|
||||
def test_throttle_per_instance(self):
|
||||
"""Test that the throttle method is done per instance of a class."""
|
||||
class Tester:
|
||||
"""A tester class for the throttle."""
|
||||
def hello(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
|
||||
@util.Throttle(timedelta(seconds=1))
|
||||
def hello(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
tester = Tester()
|
||||
throttled = util.Throttle(timedelta(seconds=1))(tester.hello)
|
||||
|
||||
assert Tester().hello()
|
||||
assert Tester().hello()
|
||||
assert throttled()
|
||||
assert throttled() is None
|
||||
|
||||
def test_throttle_on_method(self):
|
||||
"""Test that throttle works when wrapping a method."""
|
||||
class Tester:
|
||||
"""A tester class for the throttle."""
|
||||
|
||||
def hello(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
def test_throttle_on_two_method():
|
||||
"""Test that throttle works when wrapping two methods."""
|
||||
class Tester:
|
||||
"""A test class for the throttle."""
|
||||
|
||||
tester = Tester()
|
||||
throttled = util.Throttle(timedelta(seconds=1))(tester.hello)
|
||||
@util.Throttle(timedelta(seconds=1))
|
||||
def hello(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
|
||||
assert throttled()
|
||||
assert throttled() is None
|
||||
@util.Throttle(timedelta(seconds=1))
|
||||
def goodbye(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
|
||||
def test_throttle_on_two_method(self):
|
||||
"""Test that throttle works when wrapping two methods."""
|
||||
class Tester:
|
||||
"""A test class for the throttle."""
|
||||
tester = Tester()
|
||||
|
||||
@util.Throttle(timedelta(seconds=1))
|
||||
def hello(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
assert tester.hello()
|
||||
assert tester.goodbye()
|
||||
|
||||
@util.Throttle(timedelta(seconds=1))
|
||||
def goodbye(self):
|
||||
"""Test the throttle."""
|
||||
return True
|
||||
|
||||
tester = Tester()
|
||||
@patch.object(util, 'random')
|
||||
def test_get_random_string(mock_random):
|
||||
"""Test get random string."""
|
||||
results = ['A', 'B', 'C']
|
||||
|
||||
assert tester.hello()
|
||||
assert tester.goodbye()
|
||||
def mock_choice(choices):
|
||||
return results.pop(0)
|
||||
|
||||
@patch.object(util, 'random')
|
||||
def test_get_random_string(self, mock_random):
|
||||
"""Test get random string."""
|
||||
results = ['A', 'B', 'C']
|
||||
generator = MagicMock()
|
||||
generator.choice.side_effect = mock_choice
|
||||
mock_random.SystemRandom.return_value = generator
|
||||
|
||||
def mock_choice(choices):
|
||||
return results.pop(0)
|
||||
|
||||
generator = MagicMock()
|
||||
generator.choice.side_effect = mock_choice
|
||||
mock_random.SystemRandom.return_value = generator
|
||||
|
||||
assert util.get_random_string(length=3) == 'ABC'
|
||||
assert util.get_random_string(length=3) == 'ABC'
|
||||
|
||||
|
||||
async def test_throttle_async():
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
from json import JSONEncoder
|
||||
import os
|
||||
import unittest
|
||||
from unittest.mock import Mock
|
||||
import sys
|
||||
from tempfile import mkdtemp
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.util.json import (
|
||||
SerializationError, load_json, save_json)
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
import pytest
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
# Test data that can be saved as JSON
|
||||
TEST_JSON_A = {"a": 1, "B": "two"}
|
||||
|
@ -19,75 +20,82 @@ TEST_JSON_B = {"a": "one", "B": 2}
|
|||
TEST_BAD_OBJECT = {("A",): 1}
|
||||
# Test data that can not be loaded as JSON
|
||||
TEST_BAD_SERIALIED = "THIS IS NOT JSON\n"
|
||||
TMP_DIR = None
|
||||
|
||||
|
||||
class TestJSON(unittest.TestCase):
|
||||
"""Test util.json save and load."""
|
||||
def setup():
|
||||
"""Set up for tests."""
|
||||
global TMP_DIR
|
||||
TMP_DIR = mkdtemp()
|
||||
|
||||
def setUp(self):
|
||||
"""Set up for tests."""
|
||||
self.tmp_dir = mkdtemp()
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up after tests."""
|
||||
for fname in os.listdir(self.tmp_dir):
|
||||
os.remove(os.path.join(self.tmp_dir, fname))
|
||||
os.rmdir(self.tmp_dir)
|
||||
def teardown():
|
||||
"""Clean up after tests."""
|
||||
for fname in os.listdir(TMP_DIR):
|
||||
os.remove(os.path.join(TMP_DIR, fname))
|
||||
os.rmdir(TMP_DIR)
|
||||
|
||||
def _path_for(self, leaf_name):
|
||||
return os.path.join(self.tmp_dir, leaf_name+".json")
|
||||
|
||||
def test_save_and_load(self):
|
||||
"""Test saving and loading back."""
|
||||
fname = self._path_for("test1")
|
||||
save_json(fname, TEST_JSON_A)
|
||||
data = load_json(fname)
|
||||
assert data == TEST_JSON_A
|
||||
def _path_for(leaf_name):
|
||||
return os.path.join(TMP_DIR, leaf_name+".json")
|
||||
|
||||
# Skipped on Windows
|
||||
@unittest.skipIf(sys.platform.startswith('win'),
|
||||
"private permissions not supported on Windows")
|
||||
def test_save_and_load_private(self):
|
||||
"""Test we can load private files and that they are protected."""
|
||||
fname = self._path_for("test2")
|
||||
save_json(fname, TEST_JSON_A, private=True)
|
||||
data = load_json(fname)
|
||||
assert data == TEST_JSON_A
|
||||
stats = os.stat(fname)
|
||||
assert stats.st_mode & 0o77 == 0
|
||||
|
||||
def test_overwrite_and_reload(self):
|
||||
"""Test that we can overwrite an existing file and read back."""
|
||||
fname = self._path_for("test3")
|
||||
save_json(fname, TEST_JSON_A)
|
||||
save_json(fname, TEST_JSON_B)
|
||||
data = load_json(fname)
|
||||
assert data == TEST_JSON_B
|
||||
def test_save_and_load():
|
||||
"""Test saving and loading back."""
|
||||
fname = _path_for("test1")
|
||||
save_json(fname, TEST_JSON_A)
|
||||
data = load_json(fname)
|
||||
assert data == TEST_JSON_A
|
||||
|
||||
def test_save_bad_data(self):
|
||||
"""Test error from trying to save unserialisable data."""
|
||||
fname = self._path_for("test4")
|
||||
with pytest.raises(SerializationError):
|
||||
save_json(fname, TEST_BAD_OBJECT)
|
||||
|
||||
def test_load_bad_data(self):
|
||||
"""Test error from trying to load unserialisable data."""
|
||||
fname = self._path_for("test5")
|
||||
with open(fname, "w") as fh:
|
||||
fh.write(TEST_BAD_SERIALIED)
|
||||
with pytest.raises(HomeAssistantError):
|
||||
load_json(fname)
|
||||
# Skipped on Windows
|
||||
@unittest.skipIf(sys.platform.startswith('win'),
|
||||
"private permissions not supported on Windows")
|
||||
def test_save_and_load_private():
|
||||
"""Test we can load private files and that they are protected."""
|
||||
fname = _path_for("test2")
|
||||
save_json(fname, TEST_JSON_A, private=True)
|
||||
data = load_json(fname)
|
||||
assert data == TEST_JSON_A
|
||||
stats = os.stat(fname)
|
||||
assert stats.st_mode & 0o77 == 0
|
||||
|
||||
def test_custom_encoder(self):
|
||||
"""Test serializing with a custom encoder."""
|
||||
class MockJSONEncoder(JSONEncoder):
|
||||
"""Mock JSON encoder."""
|
||||
|
||||
def default(self, o):
|
||||
"""Mock JSON encode method."""
|
||||
return "9"
|
||||
def test_overwrite_and_reload():
|
||||
"""Test that we can overwrite an existing file and read back."""
|
||||
fname = _path_for("test3")
|
||||
save_json(fname, TEST_JSON_A)
|
||||
save_json(fname, TEST_JSON_B)
|
||||
data = load_json(fname)
|
||||
assert data == TEST_JSON_B
|
||||
|
||||
fname = self._path_for("test6")
|
||||
save_json(fname, Mock(), encoder=MockJSONEncoder)
|
||||
data = load_json(fname)
|
||||
self.assertEqual(data, "9")
|
||||
|
||||
def test_save_bad_data():
|
||||
"""Test error from trying to save unserialisable data."""
|
||||
fname = _path_for("test4")
|
||||
with pytest.raises(SerializationError):
|
||||
save_json(fname, TEST_BAD_OBJECT)
|
||||
|
||||
|
||||
def test_load_bad_data():
|
||||
"""Test error from trying to load unserialisable data."""
|
||||
fname = _path_for("test5")
|
||||
with open(fname, "w") as fh:
|
||||
fh.write(TEST_BAD_SERIALIED)
|
||||
with pytest.raises(HomeAssistantError):
|
||||
load_json(fname)
|
||||
|
||||
|
||||
def test_custom_encoder():
|
||||
"""Test serializing with a custom encoder."""
|
||||
class MockJSONEncoder(JSONEncoder):
|
||||
"""Mock JSON encoder."""
|
||||
|
||||
def default(self, o):
|
||||
"""Mock JSON encode method."""
|
||||
return "9"
|
||||
|
||||
fname = _path_for("test6")
|
||||
save_json(fname, Mock(), encoder=MockJSONEncoder)
|
||||
data = load_json(fname)
|
||||
assert data == "9"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""Test homeassistant pressure utility functions."""
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from homeassistant.const import (PRESSURE_PA, PRESSURE_HPA, PRESSURE_MBAR,
|
||||
|
@ -10,57 +9,50 @@ INVALID_SYMBOL = 'bob'
|
|||
VALID_SYMBOL = PRESSURE_PA
|
||||
|
||||
|
||||
class TestPressureUtil(unittest.TestCase):
|
||||
"""Test the pressure utility functions."""
|
||||
def test_convert_same_unit():
|
||||
"""Test conversion from any unit to same unit."""
|
||||
assert pressure_util.convert(2, PRESSURE_PA, PRESSURE_PA) == 2
|
||||
assert pressure_util.convert(3, PRESSURE_HPA, PRESSURE_HPA) == 3
|
||||
assert pressure_util.convert(4, PRESSURE_MBAR, PRESSURE_MBAR) == 4
|
||||
assert pressure_util.convert(5, PRESSURE_INHG, PRESSURE_INHG) == 5
|
||||
|
||||
def test_convert_same_unit(self):
|
||||
"""Test conversion from any unit to same unit."""
|
||||
assert pressure_util.convert(2, PRESSURE_PA, PRESSURE_PA) == 2
|
||||
assert pressure_util.convert(3, PRESSURE_HPA, PRESSURE_HPA) == 3
|
||||
assert pressure_util.convert(4, PRESSURE_MBAR, PRESSURE_MBAR) == 4
|
||||
assert pressure_util.convert(5, PRESSURE_INHG, PRESSURE_INHG) == 5
|
||||
|
||||
def test_convert_invalid_unit(self):
|
||||
"""Test exception is thrown for invalid units."""
|
||||
with pytest.raises(ValueError):
|
||||
pressure_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL)
|
||||
def test_convert_invalid_unit():
|
||||
"""Test exception is thrown for invalid units."""
|
||||
with pytest.raises(ValueError):
|
||||
pressure_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
pressure_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)
|
||||
with pytest.raises(ValueError):
|
||||
pressure_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)
|
||||
|
||||
def test_convert_nonnumeric_value(self):
|
||||
"""Test exception is thrown for nonnumeric type."""
|
||||
with pytest.raises(TypeError):
|
||||
pressure_util.convert('a', PRESSURE_HPA, PRESSURE_INHG)
|
||||
|
||||
def test_convert_from_hpascals(self):
|
||||
"""Test conversion from hPA to other units."""
|
||||
hpascals = 1000
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_PSI),
|
||||
14.5037743897)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_INHG),
|
||||
29.5299801647)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_PA),
|
||||
100000)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_MBAR),
|
||||
1000)
|
||||
def test_convert_nonnumeric_value():
|
||||
"""Test exception is thrown for nonnumeric type."""
|
||||
with pytest.raises(TypeError):
|
||||
pressure_util.convert('a', PRESSURE_HPA, PRESSURE_INHG)
|
||||
|
||||
def test_convert_from_inhg(self):
|
||||
"""Test conversion from inHg to other units."""
|
||||
inhg = 30
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_PSI),
|
||||
14.7346266155)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_HPA),
|
||||
1015.9167)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_PA),
|
||||
101591.67)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_MBAR),
|
||||
1015.9167)
|
||||
|
||||
def test_convert_from_hpascals():
|
||||
"""Test conversion from hPA to other units."""
|
||||
hpascals = 1000
|
||||
assert pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_PSI) == \
|
||||
pytest.approx(14.5037743897)
|
||||
assert pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_INHG) == \
|
||||
pytest.approx(29.5299801647)
|
||||
assert pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_PA) == \
|
||||
pytest.approx(100000)
|
||||
assert pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_MBAR) == \
|
||||
pytest.approx(1000)
|
||||
|
||||
|
||||
def test_convert_from_inhg():
|
||||
"""Test conversion from inHg to other units."""
|
||||
inhg = 30
|
||||
assert pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_PSI) == \
|
||||
pytest.approx(14.7346266155)
|
||||
assert pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_HPA) == \
|
||||
pytest.approx(1015.9167)
|
||||
assert pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_PA) == \
|
||||
pytest.approx(101591.67)
|
||||
assert pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_MBAR) == \
|
||||
pytest.approx(1015.9167)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""Test Home Assistant ruamel.yaml loader."""
|
||||
import os
|
||||
import unittest
|
||||
from tempfile import mkdtemp
|
||||
import pytest
|
||||
|
||||
|
@ -114,45 +113,51 @@ views:
|
|||
cards: !include cards.yaml
|
||||
"""
|
||||
|
||||
TMP_DIR = None
|
||||
|
||||
class TestYAML(unittest.TestCase):
|
||||
"""Test lovelace.yaml save and load."""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up for tests."""
|
||||
self.tmp_dir = mkdtemp()
|
||||
self.yaml = YAML(typ='rt')
|
||||
def setup():
|
||||
"""Set up for tests."""
|
||||
global TMP_DIR
|
||||
TMP_DIR = mkdtemp()
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up after tests."""
|
||||
for fname in os.listdir(self.tmp_dir):
|
||||
os.remove(os.path.join(self.tmp_dir, fname))
|
||||
os.rmdir(self.tmp_dir)
|
||||
|
||||
def _path_for(self, leaf_name):
|
||||
return os.path.join(self.tmp_dir, leaf_name+".yaml")
|
||||
def teardown():
|
||||
"""Clean up after tests."""
|
||||
for fname in os.listdir(TMP_DIR):
|
||||
os.remove(os.path.join(TMP_DIR, fname))
|
||||
os.rmdir(TMP_DIR)
|
||||
|
||||
def test_save_and_load(self):
|
||||
"""Test saving and loading back."""
|
||||
fname = self._path_for("test1")
|
||||
open(fname, "w+").close()
|
||||
util_yaml.save_yaml(fname, self.yaml.load(TEST_YAML_A))
|
||||
data = util_yaml.load_yaml(fname, True)
|
||||
assert data == self.yaml.load(TEST_YAML_A)
|
||||
|
||||
def test_overwrite_and_reload(self):
|
||||
"""Test that we can overwrite an existing file and read back."""
|
||||
fname = self._path_for("test2")
|
||||
open(fname, "w+").close()
|
||||
util_yaml.save_yaml(fname, self.yaml.load(TEST_YAML_A))
|
||||
util_yaml.save_yaml(fname, self.yaml.load(TEST_YAML_B))
|
||||
data = util_yaml.load_yaml(fname, True)
|
||||
assert data == self.yaml.load(TEST_YAML_B)
|
||||
def _path_for(leaf_name):
|
||||
return os.path.join(TMP_DIR, leaf_name+".yaml")
|
||||
|
||||
def test_load_bad_data(self):
|
||||
"""Test error from trying to load unserialisable data."""
|
||||
fname = self._path_for("test3")
|
||||
with open(fname, "w") as fh:
|
||||
fh.write(TEST_BAD_YAML)
|
||||
with pytest.raises(HomeAssistantError):
|
||||
util_yaml.load_yaml(fname, True)
|
||||
|
||||
def test_save_and_load():
|
||||
"""Test saving and loading back."""
|
||||
yaml = YAML(typ='rt')
|
||||
fname = _path_for("test1")
|
||||
open(fname, "w+").close()
|
||||
util_yaml.save_yaml(fname, yaml.load(TEST_YAML_A))
|
||||
data = util_yaml.load_yaml(fname, True)
|
||||
assert data == yaml.load(TEST_YAML_A)
|
||||
|
||||
|
||||
def test_overwrite_and_reload():
|
||||
"""Test that we can overwrite an existing file and read back."""
|
||||
yaml = YAML(typ='rt')
|
||||
fname = _path_for("test2")
|
||||
open(fname, "w+").close()
|
||||
util_yaml.save_yaml(fname, yaml.load(TEST_YAML_A))
|
||||
util_yaml.save_yaml(fname, yaml.load(TEST_YAML_B))
|
||||
data = util_yaml.load_yaml(fname, True)
|
||||
assert data == yaml.load(TEST_YAML_B)
|
||||
|
||||
|
||||
def test_load_bad_data():
|
||||
"""Test error from trying to load unserialisable data."""
|
||||
fname = _path_for("test3")
|
||||
with open(fname, "w") as fh:
|
||||
fh.write(TEST_BAD_YAML)
|
||||
with pytest.raises(HomeAssistantError):
|
||||
util_yaml.load_yaml(fname, True)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""Test the unit system helper."""
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from homeassistant.util.unit_system import (
|
||||
UnitSystem,
|
||||
|
@ -19,141 +19,138 @@ from homeassistant.const import (
|
|||
TEMPERATURE,
|
||||
VOLUME
|
||||
)
|
||||
import pytest
|
||||
|
||||
SYSTEM_NAME = 'TEST'
|
||||
INVALID_UNIT = 'INVALID'
|
||||
|
||||
|
||||
class TestUnitSystem(unittest.TestCase):
|
||||
"""Test the unit system helper."""
|
||||
def test_invalid_units():
|
||||
"""Test errors are raised when invalid units are passed in."""
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, INVALID_UNIT, LENGTH_METERS, VOLUME_LITERS,
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
|
||||
def test_invalid_units(self):
|
||||
"""Test errors are raised when invalid units are passed in."""
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, INVALID_UNIT, LENGTH_METERS, VOLUME_LITERS,
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, INVALID_UNIT, VOLUME_LITERS,
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, INVALID_UNIT, VOLUME_LITERS,
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, INVALID_UNIT,
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, INVALID_UNIT,
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS,
|
||||
INVALID_UNIT, PRESSURE_PA)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS,
|
||||
INVALID_UNIT, PRESSURE_PA)
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS,
|
||||
MASS_GRAMS, INVALID_UNIT)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS,
|
||||
MASS_GRAMS, INVALID_UNIT)
|
||||
|
||||
def test_invalid_value(self):
|
||||
"""Test no conversion happens if value is non-numeric."""
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.length('25a', LENGTH_KILOMETERS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.temperature('50K', TEMP_CELSIUS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.volume('50L', VOLUME_LITERS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.pressure('50Pa', PRESSURE_PA)
|
||||
def test_invalid_value():
|
||||
"""Test no conversion happens if value is non-numeric."""
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.length('25a', LENGTH_KILOMETERS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.temperature('50K', TEMP_CELSIUS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.volume('50L', VOLUME_LITERS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.pressure('50Pa', PRESSURE_PA)
|
||||
|
||||
def test_as_dict(self):
|
||||
"""Test that the as_dict() method returns the expected dictionary."""
|
||||
expected = {
|
||||
LENGTH: LENGTH_KILOMETERS,
|
||||
TEMPERATURE: TEMP_CELSIUS,
|
||||
VOLUME: VOLUME_LITERS,
|
||||
MASS: MASS_GRAMS,
|
||||
PRESSURE: PRESSURE_PA
|
||||
}
|
||||
|
||||
assert expected == METRIC_SYSTEM.as_dict()
|
||||
def test_as_dict():
|
||||
"""Test that the as_dict() method returns the expected dictionary."""
|
||||
expected = {
|
||||
LENGTH: LENGTH_KILOMETERS,
|
||||
TEMPERATURE: TEMP_CELSIUS,
|
||||
VOLUME: VOLUME_LITERS,
|
||||
MASS: MASS_GRAMS,
|
||||
PRESSURE: PRESSURE_PA
|
||||
}
|
||||
|
||||
def test_temperature_same_unit(self):
|
||||
"""Test no conversion happens if to unit is same as from unit."""
|
||||
assert 5 == \
|
||||
METRIC_SYSTEM.temperature(5,
|
||||
METRIC_SYSTEM.temperature_unit)
|
||||
assert expected == METRIC_SYSTEM.as_dict()
|
||||
|
||||
def test_temperature_unknown_unit(self):
|
||||
"""Test no conversion happens if unknown unit."""
|
||||
with pytest.raises(ValueError):
|
||||
METRIC_SYSTEM.temperature(5, 'K')
|
||||
|
||||
def test_temperature_to_metric(self):
|
||||
"""Test temperature conversion to metric system."""
|
||||
assert 25 == \
|
||||
METRIC_SYSTEM.temperature(25, METRIC_SYSTEM.temperature_unit)
|
||||
assert 26.7 == \
|
||||
round(METRIC_SYSTEM.temperature(
|
||||
80, IMPERIAL_SYSTEM.temperature_unit), 1)
|
||||
def test_temperature_same_unit():
|
||||
"""Test no conversion happens if to unit is same as from unit."""
|
||||
assert METRIC_SYSTEM.temperature(5, METRIC_SYSTEM.temperature_unit) == 5
|
||||
|
||||
def test_temperature_to_imperial(self):
|
||||
"""Test temperature conversion to imperial system."""
|
||||
assert 77 == \
|
||||
IMPERIAL_SYSTEM.temperature(77, IMPERIAL_SYSTEM.temperature_unit)
|
||||
assert 77 == \
|
||||
IMPERIAL_SYSTEM.temperature(25, METRIC_SYSTEM.temperature_unit)
|
||||
|
||||
def test_length_unknown_unit(self):
|
||||
"""Test length conversion with unknown from unit."""
|
||||
with pytest.raises(ValueError):
|
||||
METRIC_SYSTEM.length(5, 'fr')
|
||||
def test_temperature_unknown_unit():
|
||||
"""Test no conversion happens if unknown unit."""
|
||||
with pytest.raises(ValueError):
|
||||
METRIC_SYSTEM.temperature(5, 'K')
|
||||
|
||||
def test_length_to_metric(self):
|
||||
"""Test length conversion to metric system."""
|
||||
assert 100 == \
|
||||
METRIC_SYSTEM.length(100, METRIC_SYSTEM.length_unit)
|
||||
assert 8.04672 == \
|
||||
METRIC_SYSTEM.length(5, IMPERIAL_SYSTEM.length_unit)
|
||||
|
||||
def test_length_to_imperial(self):
|
||||
"""Test length conversion to imperial system."""
|
||||
assert 100 == \
|
||||
IMPERIAL_SYSTEM.length(100,
|
||||
IMPERIAL_SYSTEM.length_unit)
|
||||
assert 3.106855 == \
|
||||
IMPERIAL_SYSTEM.length(5, METRIC_SYSTEM.length_unit)
|
||||
def test_temperature_to_metric():
|
||||
"""Test temperature conversion to metric system."""
|
||||
assert METRIC_SYSTEM.temperature(25, METRIC_SYSTEM.temperature_unit) == 25
|
||||
assert round(METRIC_SYSTEM.temperature(
|
||||
80, IMPERIAL_SYSTEM.temperature_unit), 1) == 26.7
|
||||
|
||||
def test_pressure_same_unit(self):
|
||||
"""Test no conversion happens if to unit is same as from unit."""
|
||||
assert 5 == \
|
||||
METRIC_SYSTEM.pressure(5, METRIC_SYSTEM.pressure_unit)
|
||||
|
||||
def test_pressure_unknown_unit(self):
|
||||
"""Test no conversion happens if unknown unit."""
|
||||
with pytest.raises(ValueError):
|
||||
METRIC_SYSTEM.pressure(5, 'K')
|
||||
def test_temperature_to_imperial():
|
||||
"""Test temperature conversion to imperial system."""
|
||||
assert IMPERIAL_SYSTEM.temperature(
|
||||
77, IMPERIAL_SYSTEM.temperature_unit) == 77
|
||||
assert IMPERIAL_SYSTEM.temperature(
|
||||
25, METRIC_SYSTEM.temperature_unit) == 77
|
||||
|
||||
def test_pressure_to_metric(self):
|
||||
"""Test pressure conversion to metric system."""
|
||||
assert 25 == \
|
||||
METRIC_SYSTEM.pressure(25, METRIC_SYSTEM.pressure_unit)
|
||||
self.assertAlmostEqual(
|
||||
METRIC_SYSTEM.pressure(14.7, IMPERIAL_SYSTEM.pressure_unit),
|
||||
101352.932, places=1)
|
||||
|
||||
def test_pressure_to_imperial(self):
|
||||
"""Test pressure conversion to imperial system."""
|
||||
assert 77 == \
|
||||
IMPERIAL_SYSTEM.pressure(77, IMPERIAL_SYSTEM.pressure_unit)
|
||||
self.assertAlmostEqual(
|
||||
IMPERIAL_SYSTEM.pressure(101352.932, METRIC_SYSTEM.pressure_unit),
|
||||
14.7, places=4)
|
||||
def test_length_unknown_unit():
|
||||
"""Test length conversion with unknown from unit."""
|
||||
with pytest.raises(ValueError):
|
||||
METRIC_SYSTEM.length(5, 'fr')
|
||||
|
||||
def test_properties(self):
|
||||
"""Test the unit properties are returned as expected."""
|
||||
assert LENGTH_KILOMETERS == METRIC_SYSTEM.length_unit
|
||||
assert TEMP_CELSIUS == METRIC_SYSTEM.temperature_unit
|
||||
assert MASS_GRAMS == METRIC_SYSTEM.mass_unit
|
||||
assert VOLUME_LITERS == METRIC_SYSTEM.volume_unit
|
||||
assert PRESSURE_PA == METRIC_SYSTEM.pressure_unit
|
||||
|
||||
def test_is_metric(self):
|
||||
"""Test the is metric flag."""
|
||||
assert METRIC_SYSTEM.is_metric
|
||||
assert not IMPERIAL_SYSTEM.is_metric
|
||||
def test_length_to_metric():
|
||||
"""Test length conversion to metric system."""
|
||||
assert METRIC_SYSTEM.length(100, METRIC_SYSTEM.length_unit) == 100
|
||||
assert METRIC_SYSTEM.length(5, IMPERIAL_SYSTEM.length_unit) == 8.04672
|
||||
|
||||
|
||||
def test_length_to_imperial():
|
||||
"""Test length conversion to imperial system."""
|
||||
assert IMPERIAL_SYSTEM.length(100, IMPERIAL_SYSTEM.length_unit) == 100
|
||||
assert IMPERIAL_SYSTEM.length(5, METRIC_SYSTEM.length_unit) == 3.106855
|
||||
|
||||
|
||||
def test_pressure_same_unit():
|
||||
"""Test no conversion happens if to unit is same as from unit."""
|
||||
assert METRIC_SYSTEM.pressure(5, METRIC_SYSTEM.pressure_unit) == 5
|
||||
|
||||
|
||||
def test_pressure_unknown_unit():
|
||||
"""Test no conversion happens if unknown unit."""
|
||||
with pytest.raises(ValueError):
|
||||
METRIC_SYSTEM.pressure(5, 'K')
|
||||
|
||||
|
||||
def test_pressure_to_metric():
|
||||
"""Test pressure conversion to metric system."""
|
||||
assert METRIC_SYSTEM.pressure(25, METRIC_SYSTEM.pressure_unit) == 25
|
||||
assert METRIC_SYSTEM.pressure(14.7, IMPERIAL_SYSTEM.pressure_unit) == \
|
||||
pytest.approx(101352.932, abs=1e-1)
|
||||
|
||||
|
||||
def test_pressure_to_imperial():
|
||||
"""Test pressure conversion to imperial system."""
|
||||
assert IMPERIAL_SYSTEM.pressure(77, IMPERIAL_SYSTEM.pressure_unit) == 77
|
||||
assert IMPERIAL_SYSTEM.pressure(
|
||||
101352.932, METRIC_SYSTEM.pressure_unit) == \
|
||||
pytest.approx(14.7, abs=1e-4)
|
||||
|
||||
|
||||
def test_properties():
|
||||
"""Test the unit properties are returned as expected."""
|
||||
assert LENGTH_KILOMETERS == METRIC_SYSTEM.length_unit
|
||||
assert TEMP_CELSIUS == METRIC_SYSTEM.temperature_unit
|
||||
assert MASS_GRAMS == METRIC_SYSTEM.mass_unit
|
||||
assert VOLUME_LITERS == METRIC_SYSTEM.volume_unit
|
||||
assert PRESSURE_PA == METRIC_SYSTEM.pressure_unit
|
||||
|
||||
|
||||
def test_is_metric():
|
||||
"""Test the is metric flag."""
|
||||
assert METRIC_SYSTEM.is_metric
|
||||
assert not IMPERIAL_SYSTEM.is_metric
|
||||
|
|
|
@ -1,49 +1,45 @@
|
|||
"""Test homeassistant volume utility functions."""
|
||||
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
import homeassistant.util.volume as volume_util
|
||||
from homeassistant.const import (VOLUME_LITERS, VOLUME_MILLILITERS,
|
||||
VOLUME_GALLONS, VOLUME_FLUID_OUNCE)
|
||||
import pytest
|
||||
|
||||
INVALID_SYMBOL = 'bob'
|
||||
VALID_SYMBOL = VOLUME_LITERS
|
||||
|
||||
|
||||
class TestVolumeUtil(unittest.TestCase):
|
||||
"""Test the volume utility functions."""
|
||||
def test_convert_same_unit():
|
||||
"""Test conversion from any unit to same unit."""
|
||||
assert volume_util.convert(2, VOLUME_LITERS, VOLUME_LITERS) == 2
|
||||
assert volume_util.convert(3, VOLUME_MILLILITERS, VOLUME_MILLILITERS) == 3
|
||||
assert volume_util.convert(4, VOLUME_GALLONS, VOLUME_GALLONS) == 4
|
||||
assert volume_util.convert(5, VOLUME_FLUID_OUNCE, VOLUME_FLUID_OUNCE) == 5
|
||||
|
||||
def test_convert_same_unit(self):
|
||||
"""Test conversion from any unit to same unit."""
|
||||
assert 2 == volume_util.convert(2, VOLUME_LITERS, VOLUME_LITERS)
|
||||
assert 3 == volume_util.convert(3, VOLUME_MILLILITERS,
|
||||
VOLUME_MILLILITERS)
|
||||
assert 4 == volume_util.convert(4, VOLUME_GALLONS,
|
||||
VOLUME_GALLONS)
|
||||
assert 5 == volume_util.convert(5, VOLUME_FLUID_OUNCE,
|
||||
VOLUME_FLUID_OUNCE)
|
||||
|
||||
def test_convert_invalid_unit(self):
|
||||
"""Test exception is thrown for invalid units."""
|
||||
with pytest.raises(ValueError):
|
||||
volume_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL)
|
||||
def test_convert_invalid_unit():
|
||||
"""Test exception is thrown for invalid units."""
|
||||
with pytest.raises(ValueError):
|
||||
volume_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
volume_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)
|
||||
with pytest.raises(ValueError):
|
||||
volume_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)
|
||||
|
||||
def test_convert_nonnumeric_value(self):
|
||||
"""Test exception is thrown for nonnumeric type."""
|
||||
with pytest.raises(TypeError):
|
||||
volume_util.convert('a', VOLUME_GALLONS, VOLUME_LITERS)
|
||||
|
||||
def test_convert_from_liters(self):
|
||||
"""Test conversion from liters to other units."""
|
||||
liters = 5
|
||||
assert volume_util.convert(liters, VOLUME_LITERS,
|
||||
VOLUME_GALLONS) == 1.321
|
||||
def test_convert_nonnumeric_value():
|
||||
"""Test exception is thrown for nonnumeric type."""
|
||||
with pytest.raises(TypeError):
|
||||
volume_util.convert('a', VOLUME_GALLONS, VOLUME_LITERS)
|
||||
|
||||
def test_convert_from_gallons(self):
|
||||
"""Test conversion from gallons to other units."""
|
||||
gallons = 5
|
||||
assert volume_util.convert(gallons, VOLUME_GALLONS,
|
||||
VOLUME_LITERS) == 18.925
|
||||
|
||||
def test_convert_from_liters():
|
||||
"""Test conversion from liters to other units."""
|
||||
liters = 5
|
||||
assert volume_util.convert(liters, VOLUME_LITERS, VOLUME_GALLONS) == 1.321
|
||||
|
||||
|
||||
def test_convert_from_gallons():
|
||||
"""Test conversion from gallons to other units."""
|
||||
gallons = 5
|
||||
assert volume_util.convert(gallons, VOLUME_GALLONS,
|
||||
VOLUME_LITERS) == 18.925
|
||||
|
|
|
@ -21,256 +21,269 @@ def mock_credstash():
|
|||
yield mock_credstash
|
||||
|
||||
|
||||
class TestYaml(unittest.TestCase):
|
||||
"""Test util.yaml loader."""
|
||||
def test_simple_list():
|
||||
"""Test simple list."""
|
||||
conf = "config:\n - simple\n - list"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['config'] == ["simple", "list"]
|
||||
|
||||
# pylint: disable=no-self-use, invalid-name
|
||||
|
||||
def test_simple_list(self):
|
||||
"""Test simple list."""
|
||||
conf = "config:\n - simple\n - list"
|
||||
def test_simple_dict():
|
||||
"""Test simple dict."""
|
||||
conf = "key: value"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['key'] == 'value'
|
||||
|
||||
|
||||
def test_unhashable_key():
|
||||
"""Test an unhasable key."""
|
||||
files = {YAML_CONFIG_FILE: 'message:\n {{ states.state }}'}
|
||||
with pytest.raises(HomeAssistantError), \
|
||||
patch_yaml_files(files):
|
||||
load_yaml_config_file(YAML_CONFIG_FILE)
|
||||
|
||||
|
||||
def test_no_key():
|
||||
"""Test item without a key."""
|
||||
files = {YAML_CONFIG_FILE: 'a: a\nnokeyhere'}
|
||||
with pytest.raises(HomeAssistantError), \
|
||||
patch_yaml_files(files):
|
||||
yaml.load_yaml(YAML_CONFIG_FILE)
|
||||
|
||||
|
||||
def test_environment_variable():
|
||||
"""Test config file with environment variable."""
|
||||
os.environ["PASSWORD"] = "secret_password"
|
||||
conf = "password: !env_var PASSWORD"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['password'] == "secret_password"
|
||||
del os.environ["PASSWORD"]
|
||||
|
||||
|
||||
def test_environment_variable_default():
|
||||
"""Test config file with default value for environment variable."""
|
||||
conf = "password: !env_var PASSWORD secret_password"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['password'] == "secret_password"
|
||||
|
||||
|
||||
def test_invalid_environment_variable():
|
||||
"""Test config file with no environment variable sat."""
|
||||
conf = "password: !env_var PASSWORD"
|
||||
with pytest.raises(HomeAssistantError):
|
||||
with io.StringIO(conf) as file:
|
||||
yaml.yaml.safe_load(file)
|
||||
|
||||
|
||||
def test_include_yaml():
|
||||
"""Test include yaml."""
|
||||
with patch_yaml_files({'test.yaml': 'value'}):
|
||||
conf = 'key: !include test.yaml'
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['config'] == ["simple", "list"]
|
||||
assert doc["key"] == "value"
|
||||
|
||||
def test_simple_dict(self):
|
||||
"""Test simple dict."""
|
||||
conf = "key: value"
|
||||
with patch_yaml_files({'test.yaml': None}):
|
||||
conf = 'key: !include test.yaml'
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['key'] == 'value'
|
||||
assert doc["key"] == {}
|
||||
|
||||
def test_unhashable_key(self):
|
||||
"""Test an unhasable key."""
|
||||
files = {YAML_CONFIG_FILE: 'message:\n {{ states.state }}'}
|
||||
with pytest.raises(HomeAssistantError), \
|
||||
patch_yaml_files(files):
|
||||
load_yaml_config_file(YAML_CONFIG_FILE)
|
||||
|
||||
def test_no_key(self):
|
||||
"""Test item without a key."""
|
||||
files = {YAML_CONFIG_FILE: 'a: a\nnokeyhere'}
|
||||
with pytest.raises(HomeAssistantError), \
|
||||
patch_yaml_files(files):
|
||||
yaml.load_yaml(YAML_CONFIG_FILE)
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_list(mock_walk):
|
||||
"""Test include dir list yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', [], ['two.yaml', 'one.yaml']],
|
||||
]
|
||||
|
||||
def test_environment_variable(self):
|
||||
"""Test config file with environment variable."""
|
||||
os.environ["PASSWORD"] = "secret_password"
|
||||
conf = "password: !env_var PASSWORD"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['password'] == "secret_password"
|
||||
del os.environ["PASSWORD"]
|
||||
|
||||
def test_environment_variable_default(self):
|
||||
"""Test config file with default value for environment variable."""
|
||||
conf = "password: !env_var PASSWORD secret_password"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc['password'] == "secret_password"
|
||||
|
||||
def test_invalid_environment_variable(self):
|
||||
"""Test config file with no environment variable sat."""
|
||||
conf = "password: !env_var PASSWORD"
|
||||
with pytest.raises(HomeAssistantError):
|
||||
with io.StringIO(conf) as file:
|
||||
yaml.yaml.safe_load(file)
|
||||
|
||||
def test_include_yaml(self):
|
||||
"""Test include yaml."""
|
||||
with patch_yaml_files({'test.yaml': 'value'}):
|
||||
conf = 'key: !include test.yaml'
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == "value"
|
||||
|
||||
with patch_yaml_files({'test.yaml': None}):
|
||||
conf = 'key: !include test.yaml'
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == {}
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_list(self, mock_walk):
|
||||
"""Test include dir list yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', [], ['two.yaml', 'one.yaml']],
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
with patch_yaml_files({
|
||||
'/tmp/one.yaml': 'one',
|
||||
'/tmp/two.yaml': 'two',
|
||||
}):
|
||||
conf = "key: !include_dir_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == sorted(["one", "two"])
|
||||
}):
|
||||
conf = "key: !include_dir_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == sorted(["one", "two"])
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_list_recursive(self, mock_walk):
|
||||
"""Test include dir recursive list yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['zero.yaml']],
|
||||
['/tmp/tmp2', [], ['one.yaml', 'two.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_list_recursive(mock_walk):
|
||||
"""Test include dir recursive list yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['zero.yaml']],
|
||||
['/tmp/tmp2', [], ['one.yaml', 'two.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
'/tmp/zero.yaml': 'zero',
|
||||
'/tmp/tmp2/one.yaml': 'one',
|
||||
'/tmp/tmp2/two.yaml': 'two'
|
||||
}):
|
||||
conf = "key: !include_dir_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
|
||||
}):
|
||||
conf = "key: !include_dir_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_named(self, mock_walk):
|
||||
"""Test include dir named yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', [], ['first.yaml', 'second.yaml', 'secrets.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_named(mock_walk):
|
||||
"""Test include dir named yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', [], ['first.yaml', 'second.yaml', 'secrets.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
'/tmp/first.yaml': 'one',
|
||||
'/tmp/second.yaml': 'two'
|
||||
}):
|
||||
conf = "key: !include_dir_named /tmp"
|
||||
correct = {'first': 'one', 'second': 'two'}
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == correct
|
||||
}):
|
||||
conf = "key: !include_dir_named /tmp"
|
||||
correct = {'first': 'one', 'second': 'two'}
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == correct
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_named_recursive(self, mock_walk):
|
||||
"""Test include dir named yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['first.yaml']],
|
||||
['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_named_recursive(mock_walk):
|
||||
"""Test include dir named yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['first.yaml']],
|
||||
['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
'/tmp/first.yaml': 'one',
|
||||
'/tmp/tmp2/second.yaml': 'two',
|
||||
'/tmp/tmp2/third.yaml': 'three'
|
||||
}):
|
||||
conf = "key: !include_dir_named /tmp"
|
||||
correct = {'first': 'one', 'second': 'two', 'third': 'three'}
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert doc["key"] == correct
|
||||
}):
|
||||
conf = "key: !include_dir_named /tmp"
|
||||
correct = {'first': 'one', 'second': 'two', 'third': 'three'}
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert doc["key"] == correct
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_list(self, mock_walk):
|
||||
"""Test include dir merge list yaml."""
|
||||
mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
|
||||
|
||||
with patch_yaml_files({
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_list(mock_walk):
|
||||
"""Test include dir merge list yaml."""
|
||||
mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
|
||||
|
||||
with patch_yaml_files({
|
||||
'/tmp/first.yaml': '- one',
|
||||
'/tmp/second.yaml': '- two\n- three'
|
||||
}):
|
||||
conf = "key: !include_dir_merge_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert sorted(doc["key"]) == sorted(["one", "two", "three"])
|
||||
}):
|
||||
conf = "key: !include_dir_merge_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert sorted(doc["key"]) == sorted(["one", "two", "three"])
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_list_recursive(self, mock_walk):
|
||||
"""Test include dir merge list yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['first.yaml']],
|
||||
['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_list_recursive(mock_walk):
|
||||
"""Test include dir merge list yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['first.yaml']],
|
||||
['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
'/tmp/first.yaml': '- one',
|
||||
'/tmp/tmp2/second.yaml': '- two',
|
||||
'/tmp/tmp2/third.yaml': '- three\n- four'
|
||||
}):
|
||||
conf = "key: !include_dir_merge_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert sorted(doc["key"]) == sorted(["one", "two",
|
||||
"three", "four"])
|
||||
}):
|
||||
conf = "key: !include_dir_merge_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert sorted(doc["key"]) == sorted(["one", "two",
|
||||
"three", "four"])
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_named(self, mock_walk):
|
||||
"""Test include dir merge named yaml."""
|
||||
mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
|
||||
|
||||
files = {
|
||||
'/tmp/first.yaml': 'key1: one',
|
||||
'/tmp/second.yaml': 'key2: two\nkey3: three',
|
||||
}
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_named(mock_walk):
|
||||
"""Test include dir merge named yaml."""
|
||||
mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
|
||||
|
||||
with patch_yaml_files(files):
|
||||
conf = "key: !include_dir_merge_named /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == {
|
||||
"key1": "one",
|
||||
"key2": "two",
|
||||
"key3": "three"
|
||||
}
|
||||
files = {
|
||||
'/tmp/first.yaml': 'key1: one',
|
||||
'/tmp/second.yaml': 'key2: two\nkey3: three',
|
||||
}
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_named_recursive(self, mock_walk):
|
||||
"""Test include dir merge named yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['first.yaml']],
|
||||
['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
with patch_yaml_files(files):
|
||||
conf = "key: !include_dir_merge_named /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert doc["key"] == {
|
||||
"key1": "one",
|
||||
"key2": "two",
|
||||
"key3": "three"
|
||||
}
|
||||
|
||||
with patch_yaml_files({
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
def test_include_dir_merge_named_recursive(mock_walk):
|
||||
"""Test include dir merge named yaml."""
|
||||
mock_walk.return_value = [
|
||||
['/tmp', ['tmp2', '.ignore', 'ignore'], ['first.yaml']],
|
||||
['/tmp/tmp2', [], ['second.yaml', 'third.yaml']],
|
||||
['/tmp/ignore', [], ['.ignore.yaml']]
|
||||
]
|
||||
|
||||
with patch_yaml_files({
|
||||
'/tmp/first.yaml': 'key1: one',
|
||||
'/tmp/tmp2/second.yaml': 'key2: two',
|
||||
'/tmp/tmp2/third.yaml': 'key3: three\nkey4: four'
|
||||
}):
|
||||
conf = "key: !include_dir_merge_named /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert doc["key"] == {
|
||||
"key1": "one",
|
||||
"key2": "two",
|
||||
"key3": "three",
|
||||
"key4": "four"
|
||||
}
|
||||
}):
|
||||
conf = "key: !include_dir_merge_named /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert doc["key"] == {
|
||||
"key1": "one",
|
||||
"key2": "two",
|
||||
"key3": "three",
|
||||
"key4": "four"
|
||||
}
|
||||
|
||||
@patch('homeassistant.util.yaml.open', create=True)
|
||||
def test_load_yaml_encoding_error(self, mock_open):
|
||||
"""Test raising a UnicodeDecodeError."""
|
||||
mock_open.side_effect = UnicodeDecodeError('', b'', 1, 0, '')
|
||||
with pytest.raises(HomeAssistantError):
|
||||
yaml.load_yaml('test')
|
||||
|
||||
def test_dump(self):
|
||||
"""The that the dump method returns empty None values."""
|
||||
assert yaml.dump({'a': None, 'b': 'b'}) == 'a:\nb: b\n'
|
||||
@patch('homeassistant.util.yaml.open', create=True)
|
||||
def test_load_yaml_encoding_error(mock_open):
|
||||
"""Test raising a UnicodeDecodeError."""
|
||||
mock_open.side_effect = UnicodeDecodeError('', b'', 1, 0, '')
|
||||
with pytest.raises(HomeAssistantError):
|
||||
yaml.load_yaml('test')
|
||||
|
||||
def test_dump_unicode(self):
|
||||
"""The that the dump method returns empty None values."""
|
||||
assert yaml.dump({'a': None, 'b': 'привет'}) == 'a:\nb: привет\n'
|
||||
|
||||
def test_dump():
|
||||
"""The that the dump method returns empty None values."""
|
||||
assert yaml.dump({'a': None, 'b': 'b'}) == 'a:\nb: b\n'
|
||||
|
||||
|
||||
def test_dump_unicode():
|
||||
"""The that the dump method returns empty None values."""
|
||||
assert yaml.dump({'a': None, 'b': 'привет'}) == 'a:\nb: привет\n'
|
||||
|
||||
|
||||
FILES = {}
|
||||
|
@ -415,9 +428,9 @@ class TestSecrets(unittest.TestCase):
|
|||
def test_secrets_are_not_dict(self):
|
||||
"""Did secrets handle non-dict file."""
|
||||
FILES[self._secret_path] = (
|
||||
'- http_pw: pwhttp\n'
|
||||
' comp1_un: un1\n'
|
||||
' comp1_pw: pw1\n')
|
||||
'- http_pw: pwhttp\n'
|
||||
' comp1_un: un1\n'
|
||||
' comp1_pw: pw1\n')
|
||||
yaml.clear_secret_cache()
|
||||
with pytest.raises(HomeAssistantError):
|
||||
load_yaml(self._yaml_path,
|
||||
|
|
Loading…
Reference in New Issue