993 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			993 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Python
		
	
	
"""Test config validators."""
 | 
						|
from datetime import date, datetime, timedelta
 | 
						|
import enum
 | 
						|
import os
 | 
						|
from socket import _GLOBAL_DEFAULT_TIMEOUT
 | 
						|
from unittest.mock import Mock, patch
 | 
						|
import uuid
 | 
						|
 | 
						|
import pytest
 | 
						|
import voluptuous as vol
 | 
						|
 | 
						|
import homeassistant
 | 
						|
import homeassistant.helpers.config_validation as cv
 | 
						|
 | 
						|
 | 
						|
def test_boolean():
 | 
						|
    """Test boolean validation."""
 | 
						|
    schema = vol.Schema(cv.boolean)
 | 
						|
 | 
						|
    for value in ('T', 'negative', 'lock'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in ('true', 'On', '1', 'YES', 'enable', 1, True):
 | 
						|
        assert schema(value)
 | 
						|
 | 
						|
    for value in ('false', 'Off', '0', 'NO', 'disable', 0, False):
 | 
						|
        assert not schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_latitude():
 | 
						|
    """Test latitude validation."""
 | 
						|
    schema = vol.Schema(cv.latitude)
 | 
						|
 | 
						|
    for value in ('invalid', None, -91, 91, '-91', '91', '123.01A'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in ('-89', 89, '12.34'):
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_longitude():
 | 
						|
    """Test longitude validation."""
 | 
						|
    schema = vol.Schema(cv.longitude)
 | 
						|
 | 
						|
    for value in ('invalid', None, -181, 181, '-181', '181', '123.01A'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in ('-179', 179, '12.34'):
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_port():
 | 
						|
    """Test TCP/UDP network port."""
 | 
						|
    schema = vol.Schema(cv.port)
 | 
						|
 | 
						|
    for value in ('invalid', None, -1, 0, 80000, '81000'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in ('1000', 21, 24574):
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_isfile():
 | 
						|
    """Validate that the value is an existing file."""
 | 
						|
    schema = vol.Schema(cv.isfile)
 | 
						|
 | 
						|
    fake_file = 'this-file-does-not.exist'
 | 
						|
    assert not os.path.isfile(fake_file)
 | 
						|
 | 
						|
    for value in ('invalid', None, -1, 0, 80000, fake_file):
 | 
						|
        with pytest.raises(vol.Invalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    # patching methods that allow us to fake a file existing
 | 
						|
    # with write access
 | 
						|
    with patch('os.path.isfile', Mock(return_value=True)), \
 | 
						|
            patch('os.access', Mock(return_value=True)):
 | 
						|
        schema('test.txt')
 | 
						|
 | 
						|
 | 
						|
def test_url():
 | 
						|
    """Test URL."""
 | 
						|
    schema = vol.Schema(cv.url)
 | 
						|
 | 
						|
    for value in ('invalid', None, 100, 'htp://ha.io', 'http//ha.io',
 | 
						|
                  'http://??,**', 'https://??,**'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in ('http://localhost', 'https://localhost/test/index.html',
 | 
						|
                  'http://home-assistant.io', 'http://home-assistant.io/test/',
 | 
						|
                  'https://community.home-assistant.io/'):
 | 
						|
        assert schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_platform_config():
 | 
						|
    """Test platform config validation."""
 | 
						|
    options = (
 | 
						|
        {},
 | 
						|
        {'hello': 'world'},
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            cv.PLATFORM_SCHEMA(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        {'platform': 'mqtt'},
 | 
						|
        {'platform': 'mqtt', 'beer': 'yes'},
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        cv.PLATFORM_SCHEMA_BASE(value)
 | 
						|
 | 
						|
 | 
						|
def test_ensure_list():
 | 
						|
    """Test ensure_list."""
 | 
						|
    schema = vol.Schema(cv.ensure_list)
 | 
						|
    assert [] == schema(None)
 | 
						|
    assert [1] == schema(1)
 | 
						|
    assert [1] == schema([1])
 | 
						|
    assert ['1'] == schema('1')
 | 
						|
    assert ['1'] == schema(['1'])
 | 
						|
    assert [{'1': '2'}] == schema({'1': '2'})
 | 
						|
 | 
						|
 | 
						|
def test_entity_id():
 | 
						|
    """Test entity ID validation."""
 | 
						|
    schema = vol.Schema(cv.entity_id)
 | 
						|
 | 
						|
    with pytest.raises(vol.MultipleInvalid):
 | 
						|
        schema('invalid_entity')
 | 
						|
 | 
						|
    assert schema('sensor.LIGHT') == 'sensor.light'
 | 
						|
 | 
						|
 | 
						|
def test_entity_ids():
 | 
						|
    """Test entity ID validation."""
 | 
						|
    schema = vol.Schema(cv.entity_ids)
 | 
						|
 | 
						|
    options = (
 | 
						|
        'invalid_entity',
 | 
						|
        'sensor.light,sensor_invalid',
 | 
						|
        ['invalid_entity'],
 | 
						|
        ['sensor.light', 'sensor_invalid'],
 | 
						|
        ['sensor.light,sensor_invalid'],
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        [],
 | 
						|
        ['sensor.light'],
 | 
						|
        'sensor.light'
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        schema(value)
 | 
						|
 | 
						|
    assert schema('sensor.LIGHT, light.kitchen ') == [
 | 
						|
        'sensor.light', 'light.kitchen'
 | 
						|
    ]
 | 
						|
 | 
						|
 | 
						|
def test_entity_domain():
 | 
						|
    """Test entity domain validation."""
 | 
						|
    schema = vol.Schema(cv.entity_domain('sensor'))
 | 
						|
 | 
						|
    options = (
 | 
						|
        'invalid_entity',
 | 
						|
        'cover.demo',
 | 
						|
    )
 | 
						|
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            print(value)
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    assert schema('sensor.LIGHT') == 'sensor.light'
 | 
						|
 | 
						|
 | 
						|
def test_entities_domain():
 | 
						|
    """Test entities domain validation."""
 | 
						|
    schema = vol.Schema(cv.entities_domain('sensor'))
 | 
						|
 | 
						|
    options = (
 | 
						|
        None,
 | 
						|
        '',
 | 
						|
        'invalid_entity',
 | 
						|
        ['sensor.light', 'cover.demo'],
 | 
						|
        ['sensor.light', 'sensor_invalid'],
 | 
						|
    )
 | 
						|
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        'sensor.light',
 | 
						|
        ['SENSOR.light'],
 | 
						|
        ['sensor.light', 'sensor.demo']
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        schema(value)
 | 
						|
 | 
						|
    assert schema('sensor.LIGHT, sensor.demo ') == [
 | 
						|
        'sensor.light', 'sensor.demo'
 | 
						|
    ]
 | 
						|
    assert schema(['sensor.light', 'SENSOR.demo']) == [
 | 
						|
        'sensor.light', 'sensor.demo'
 | 
						|
    ]
 | 
						|
 | 
						|
 | 
						|
def test_ensure_list_csv():
 | 
						|
    """Test ensure_list_csv."""
 | 
						|
    schema = vol.Schema(cv.ensure_list_csv)
 | 
						|
 | 
						|
    options = (
 | 
						|
        None,
 | 
						|
        12,
 | 
						|
        [],
 | 
						|
        ['string'],
 | 
						|
        'string1,string2'
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        schema(value)
 | 
						|
 | 
						|
    assert schema('string1, string2 ') == [
 | 
						|
        'string1', 'string2'
 | 
						|
    ]
 | 
						|
 | 
						|
 | 
						|
def test_event_schema():
 | 
						|
    """Test event_schema validation."""
 | 
						|
    options = (
 | 
						|
        {}, None,
 | 
						|
        {
 | 
						|
            'event_data': {},
 | 
						|
        },
 | 
						|
        {
 | 
						|
            'event': 'state_changed',
 | 
						|
            'event_data': 1,
 | 
						|
        },
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            cv.EVENT_SCHEMA(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        {'event': 'state_changed'},
 | 
						|
        {'event': 'state_changed', 'event_data': {'hello': 'world'}},
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        cv.EVENT_SCHEMA(value)
 | 
						|
 | 
						|
 | 
						|
def test_icon():
 | 
						|
    """Test icon validation."""
 | 
						|
    schema = vol.Schema(cv.icon)
 | 
						|
 | 
						|
    for value in (False, 'work'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    schema('mdi:work')
 | 
						|
    schema('custom:prefix')
 | 
						|
 | 
						|
 | 
						|
def test_time_period():
 | 
						|
    """Test time_period validation."""
 | 
						|
    schema = vol.Schema(cv.time_period)
 | 
						|
 | 
						|
    options = (
 | 
						|
        None, '', 'hello:world', '12:', '12:34:56:78',
 | 
						|
        {}, {'wrong_key': -10}
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        '8:20', '23:59', '-8:20', '-23:59:59', '-48:00', {'minutes': 5}, 1, '5'
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        schema(value)
 | 
						|
 | 
						|
    assert timedelta(seconds=180) == schema('180')
 | 
						|
    assert timedelta(hours=23, minutes=59) == schema('23:59')
 | 
						|
    assert -1 * timedelta(hours=1, minutes=15) == schema('-1:15')
 | 
						|
 | 
						|
 | 
						|
def test_remove_falsy():
 | 
						|
    """Test remove falsy."""
 | 
						|
    assert cv.remove_falsy([0, None, 1, "1", {}, [], ""]) == [1, "1"]
 | 
						|
 | 
						|
 | 
						|
def test_service():
 | 
						|
    """Test service validation."""
 | 
						|
    schema = vol.Schema(cv.service)
 | 
						|
 | 
						|
    with pytest.raises(vol.MultipleInvalid):
 | 
						|
        schema('invalid_turn_on')
 | 
						|
 | 
						|
    schema('homeassistant.turn_on')
 | 
						|
 | 
						|
 | 
						|
def test_service_schema():
 | 
						|
    """Test service_schema validation."""
 | 
						|
    options = (
 | 
						|
        {}, None,
 | 
						|
        {
 | 
						|
            'service': 'homeassistant.turn_on',
 | 
						|
            'service_template': 'homeassistant.turn_on'
 | 
						|
        },
 | 
						|
        {
 | 
						|
            'data': {'entity_id': 'light.kitchen'},
 | 
						|
        },
 | 
						|
        {
 | 
						|
            'service': 'homeassistant.turn_on',
 | 
						|
            'data': None
 | 
						|
        },
 | 
						|
        {
 | 
						|
            'service': 'homeassistant.turn_on',
 | 
						|
            'data_template': {
 | 
						|
                'brightness': '{{ no_end'
 | 
						|
            }
 | 
						|
        },
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            cv.SERVICE_SCHEMA(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        {'service': 'homeassistant.turn_on'},
 | 
						|
        {
 | 
						|
            'service': 'homeassistant.turn_on',
 | 
						|
            'entity_id': 'light.kitchen',
 | 
						|
        },
 | 
						|
        {
 | 
						|
            'service': 'light.turn_on',
 | 
						|
            'entity_id': 'all',
 | 
						|
        },
 | 
						|
        {
 | 
						|
            'service': 'homeassistant.turn_on',
 | 
						|
            'entity_id': ['light.kitchen', 'light.ceiling'],
 | 
						|
        },
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        cv.SERVICE_SCHEMA(value)
 | 
						|
 | 
						|
 | 
						|
def test_slug():
 | 
						|
    """Test slug validation."""
 | 
						|
    schema = vol.Schema(cv.slug)
 | 
						|
 | 
						|
    for value in (None, 'hello world'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in (12345, 'hello'):
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_string():
 | 
						|
    """Test string validation."""
 | 
						|
    schema = vol.Schema(cv.string)
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema(None)
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema([])
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema({})
 | 
						|
 | 
						|
    for value in (True, 1, 'hello'):
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_temperature_unit():
 | 
						|
    """Test temperature unit validation."""
 | 
						|
    schema = vol.Schema(cv.temperature_unit)
 | 
						|
 | 
						|
    with pytest.raises(vol.MultipleInvalid):
 | 
						|
        schema('K')
 | 
						|
 | 
						|
    schema('C')
 | 
						|
    schema('F')
 | 
						|
 | 
						|
 | 
						|
def test_x10_address():
 | 
						|
    """Test x10 addr validator."""
 | 
						|
    schema = vol.Schema(cv.x10_address)
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema('Q1')
 | 
						|
        schema('q55')
 | 
						|
        schema('garbage_addr')
 | 
						|
 | 
						|
    schema('a1')
 | 
						|
    schema('C11')
 | 
						|
 | 
						|
 | 
						|
def test_template():
 | 
						|
    """Test template validator."""
 | 
						|
    schema = vol.Schema(cv.template)
 | 
						|
 | 
						|
    for value in (None, '{{ partial_print }', '{% if True %}Hello', ['test']):
 | 
						|
        with pytest.raises(vol.Invalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        1, 'Hello',
 | 
						|
        '{{ beer }}',
 | 
						|
        '{% if 1 == 1 %}Hello{% else %}World{% endif %}',
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_template_complex():
 | 
						|
    """Test template_complex validator."""
 | 
						|
    schema = vol.Schema(cv.template_complex)
 | 
						|
 | 
						|
    for value in (None, '{{ partial_print }', '{% if True %}Hello'):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        1, 'Hello',
 | 
						|
        '{{ beer }}',
 | 
						|
        '{% if 1 == 1 %}Hello{% else %}World{% endif %}',
 | 
						|
        {'test': 1, 'test2': '{{ beer }}'},
 | 
						|
        ['{{ beer }}', 1]
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        schema(value)
 | 
						|
 | 
						|
    # ensure the validator didn't mutate the input
 | 
						|
    assert options == (
 | 
						|
        1, 'Hello',
 | 
						|
        '{{ beer }}',
 | 
						|
        '{% if 1 == 1 %}Hello{% else %}World{% endif %}',
 | 
						|
        {'test': 1, 'test2': '{{ beer }}'},
 | 
						|
        ['{{ beer }}', 1]
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
def test_time_zone():
 | 
						|
    """Test time zone validation."""
 | 
						|
    schema = vol.Schema(cv.time_zone)
 | 
						|
 | 
						|
    with pytest.raises(vol.MultipleInvalid):
 | 
						|
        schema('America/Do_Not_Exist')
 | 
						|
 | 
						|
    schema('America/Los_Angeles')
 | 
						|
    schema('UTC')
 | 
						|
 | 
						|
 | 
						|
def test_date():
 | 
						|
    """Test date validation."""
 | 
						|
    schema = vol.Schema(cv.date)
 | 
						|
 | 
						|
    for value in ['Not a date', '23:42', '2016-11-23T18:59:08']:
 | 
						|
        with pytest.raises(vol.Invalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    schema(datetime.now().date())
 | 
						|
    schema('2016-11-23')
 | 
						|
 | 
						|
 | 
						|
def test_time():
 | 
						|
    """Test date validation."""
 | 
						|
    schema = vol.Schema(cv.time)
 | 
						|
 | 
						|
    for value in ['Not a time', '2016-11-23', '2016-11-23T18:59:08']:
 | 
						|
        with pytest.raises(vol.Invalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    schema(datetime.now().time())
 | 
						|
    schema('23:42:00')
 | 
						|
    schema('23:42')
 | 
						|
 | 
						|
 | 
						|
def test_datetime():
 | 
						|
    """Test date time validation."""
 | 
						|
    schema = vol.Schema(cv.datetime)
 | 
						|
    for value in [date.today(), 'Wrong DateTime', '2016-11-23']:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    schema(datetime.now())
 | 
						|
    schema('2016-11-23T18:59:08')
 | 
						|
 | 
						|
 | 
						|
@pytest.fixture
 | 
						|
def schema():
 | 
						|
    """Create a schema used for testing deprecation."""
 | 
						|
    return vol.Schema({
 | 
						|
        'venus': cv.boolean,
 | 
						|
        'mars': cv.boolean,
 | 
						|
        'jupiter': cv.boolean
 | 
						|
    })
 | 
						|
 | 
						|
 | 
						|
@pytest.fixture
 | 
						|
def version(monkeypatch):
 | 
						|
    """Patch the version used for testing to 0.5.0."""
 | 
						|
    monkeypatch.setattr(homeassistant.const, '__version__', '0.5.0')
 | 
						|
 | 
						|
 | 
						|
def test_deprecated_with_no_optionals(caplog, schema):
 | 
						|
    """
 | 
						|
    Test deprecation behaves correctly when optional params are None.
 | 
						|
 | 
						|
    Expected behavior:
 | 
						|
        - Outputs the appropriate deprecation warning if key is detected
 | 
						|
        - Processes schema without changing any values
 | 
						|
        - No warning or difference in output if key is not provided
 | 
						|
    """
 | 
						|
    deprecated_schema = vol.All(
 | 
						|
        cv.deprecated('mars'),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert caplog.records[0].name == __name__
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please remove it from your configuration") in caplog.text
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    caplog.clear()
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
 | 
						|
    test_data = {'venus': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
 | 
						|
def test_deprecated_with_replacement_key(caplog, schema):
 | 
						|
    """
 | 
						|
    Test deprecation behaves correctly when only a replacement key is provided.
 | 
						|
 | 
						|
    Expected behavior:
 | 
						|
        - Outputs the appropriate deprecation warning if key is detected
 | 
						|
        - Processes schema moving the value from key to replacement_key
 | 
						|
        - Processes schema changing nothing if only replacement_key provided
 | 
						|
        - No warning if only replacement_key provided
 | 
						|
        - No warning or difference in output if neither key nor
 | 
						|
            replacement_key are provided
 | 
						|
    """
 | 
						|
    deprecated_schema = vol.All(
 | 
						|
        cv.deprecated('mars', replacement_key='jupiter'),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please replace it with 'jupiter'") in caplog.text
 | 
						|
    assert {'jupiter': True} == output
 | 
						|
 | 
						|
    caplog.clear()
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
 | 
						|
    test_data = {'jupiter': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    test_data = {'venus': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
 | 
						|
def test_deprecated_with_invalidation_version(caplog, schema, version):
 | 
						|
    """
 | 
						|
    Test deprecation behaves correctly with only an invalidation_version.
 | 
						|
 | 
						|
    Expected behavior:
 | 
						|
        - Outputs the appropriate deprecation warning if key is detected
 | 
						|
        - Processes schema without changing any values
 | 
						|
        - No warning or difference in output if key is not provided
 | 
						|
        - Once the invalidation_version is crossed, raises vol.Invalid if key
 | 
						|
            is detected
 | 
						|
    """
 | 
						|
    deprecated_schema = vol.All(
 | 
						|
        cv.deprecated('mars', invalidation_version='1.0.0'),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
 | 
						|
    message = ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
               "please remove it from your configuration. "
 | 
						|
               "This option will become invalid in version 1.0.0")
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert message in caplog.text
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    caplog.clear()
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
 | 
						|
    test_data = {'venus': False}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    invalidated_schema = vol.All(
 | 
						|
        cv.deprecated('mars', invalidation_version='0.1.0'),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
    test_data = {'mars': True}
 | 
						|
    with pytest.raises(vol.MultipleInvalid) as exc_info:
 | 
						|
        invalidated_schema(test_data)
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please remove it from your configuration. This option will "
 | 
						|
            "become invalid in version 0.1.0") == str(exc_info.value)
 | 
						|
 | 
						|
 | 
						|
def test_deprecated_with_replacement_key_and_invalidation_version(
 | 
						|
        caplog, schema, version
 | 
						|
):
 | 
						|
    """
 | 
						|
    Test deprecation behaves with a replacement key & invalidation_version.
 | 
						|
 | 
						|
    Expected behavior:
 | 
						|
        - Outputs the appropriate deprecation warning if key is detected
 | 
						|
        - Processes schema moving the value from key to replacement_key
 | 
						|
        - Processes schema changing nothing if only replacement_key provided
 | 
						|
        - No warning if only replacement_key provided
 | 
						|
        - No warning or difference in output if neither key nor
 | 
						|
            replacement_key are provided
 | 
						|
        - Once the invalidation_version is crossed, raises vol.Invalid if key
 | 
						|
        is detected
 | 
						|
    """
 | 
						|
    deprecated_schema = vol.All(
 | 
						|
        cv.deprecated(
 | 
						|
            'mars', replacement_key='jupiter', invalidation_version='1.0.0'
 | 
						|
        ),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
 | 
						|
    warning = ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
               "please replace it with 'jupiter'. This option will become "
 | 
						|
               "invalid in version 1.0.0")
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert warning in caplog.text
 | 
						|
    assert {'jupiter': True} == output
 | 
						|
 | 
						|
    caplog.clear()
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
 | 
						|
    test_data = {'jupiter': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    test_data = {'venus': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    invalidated_schema = vol.All(
 | 
						|
        cv.deprecated(
 | 
						|
            'mars', replacement_key='jupiter', invalidation_version='0.1.0'
 | 
						|
        ),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
    test_data = {'mars': True}
 | 
						|
    with pytest.raises(vol.MultipleInvalid) as exc_info:
 | 
						|
        invalidated_schema(test_data)
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please replace it with 'jupiter'. This option will become "
 | 
						|
            "invalid in version 0.1.0") == str(exc_info.value)
 | 
						|
 | 
						|
 | 
						|
def test_deprecated_with_default(caplog, schema):
 | 
						|
    """
 | 
						|
    Test deprecation behaves correctly with a default value.
 | 
						|
 | 
						|
    This is likely a scenario that would never occur.
 | 
						|
 | 
						|
    Expected behavior:
 | 
						|
        - Behaves identically as when the default value was not present
 | 
						|
    """
 | 
						|
    deprecated_schema = vol.All(
 | 
						|
        cv.deprecated('mars', default=False),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert caplog.records[0].name == __name__
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please remove it from your configuration") in caplog.text
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    caplog.clear()
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
 | 
						|
    test_data = {'venus': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
 | 
						|
def test_deprecated_with_replacement_key_and_default(caplog, schema):
 | 
						|
    """
 | 
						|
    Test deprecation with a replacement key and default.
 | 
						|
 | 
						|
    Expected behavior:
 | 
						|
        - Outputs the appropriate deprecation warning if key is detected
 | 
						|
        - Processes schema moving the value from key to replacement_key
 | 
						|
        - Processes schema changing nothing if only replacement_key provided
 | 
						|
        - No warning if only replacement_key provided
 | 
						|
        - No warning if neither key nor replacement_key are provided
 | 
						|
            - Adds replacement_key with default value in this case
 | 
						|
    """
 | 
						|
    deprecated_schema = vol.All(
 | 
						|
        cv.deprecated('mars', replacement_key='jupiter', default=False),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please replace it with 'jupiter'") in caplog.text
 | 
						|
    assert {'jupiter': True} == output
 | 
						|
 | 
						|
    caplog.clear()
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
 | 
						|
    test_data = {'jupiter': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    test_data = {'venus': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert {'venus': True, 'jupiter': False} == output
 | 
						|
 | 
						|
    deprecated_schema_with_default = vol.All(
 | 
						|
        vol.Schema({
 | 
						|
            'venus': cv.boolean,
 | 
						|
            vol.Optional('mars', default=False): cv.boolean,
 | 
						|
            vol.Optional('jupiter', default=False): cv.boolean
 | 
						|
        }),
 | 
						|
        cv.deprecated('mars', replacement_key='jupiter', default=False)
 | 
						|
    )
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema_with_default(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please replace it with 'jupiter'") in caplog.text
 | 
						|
    assert {'jupiter': True} == output
 | 
						|
 | 
						|
 | 
						|
def test_deprecated_with_replacement_key_invalidation_version_default(
 | 
						|
        caplog, schema, version
 | 
						|
):
 | 
						|
    """
 | 
						|
    Test deprecation with a replacement key, invalidation_version & default.
 | 
						|
 | 
						|
    Expected behavior:
 | 
						|
        - Outputs the appropriate deprecation warning if key is detected
 | 
						|
        - Processes schema moving the value from key to replacement_key
 | 
						|
        - Processes schema changing nothing if only replacement_key provided
 | 
						|
        - No warning if only replacement_key provided
 | 
						|
        - No warning if neither key nor replacement_key are provided
 | 
						|
            - Adds replacement_key with default value in this case
 | 
						|
        - Once the invalidation_version is crossed, raises vol.Invalid if key
 | 
						|
        is detected
 | 
						|
    """
 | 
						|
    deprecated_schema = vol.All(
 | 
						|
        cv.deprecated(
 | 
						|
            'mars', replacement_key='jupiter', invalidation_version='1.0.0',
 | 
						|
            default=False
 | 
						|
        ),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
 | 
						|
    test_data = {'mars': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 1
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please replace it with 'jupiter'. This option will become "
 | 
						|
            "invalid in version 1.0.0") in caplog.text
 | 
						|
    assert {'jupiter': True} == output
 | 
						|
 | 
						|
    caplog.clear()
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
 | 
						|
    test_data = {'jupiter': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert test_data == output
 | 
						|
 | 
						|
    test_data = {'venus': True}
 | 
						|
    output = deprecated_schema(test_data.copy())
 | 
						|
    assert len(caplog.records) == 0
 | 
						|
    assert {'venus': True, 'jupiter': False} == output
 | 
						|
 | 
						|
    invalidated_schema = vol.All(
 | 
						|
        cv.deprecated(
 | 
						|
            'mars', replacement_key='jupiter', invalidation_version='0.1.0'
 | 
						|
        ),
 | 
						|
        schema
 | 
						|
    )
 | 
						|
    test_data = {'mars': True}
 | 
						|
    with pytest.raises(vol.MultipleInvalid) as exc_info:
 | 
						|
        invalidated_schema(test_data)
 | 
						|
    assert ("The 'mars' option (with value 'True') is deprecated, "
 | 
						|
            "please replace it with 'jupiter'. This option will become "
 | 
						|
            "invalid in version 0.1.0") == str(exc_info.value)
 | 
						|
 | 
						|
 | 
						|
def test_key_dependency():
 | 
						|
    """Test key_dependency validator."""
 | 
						|
    schema = vol.Schema(cv.key_dependency('beer', 'soda'))
 | 
						|
 | 
						|
    options = (
 | 
						|
        {'beer': None}
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    options = (
 | 
						|
        {'beer': None, 'soda': None},
 | 
						|
        {'soda': None}, {}
 | 
						|
    )
 | 
						|
    for value in options:
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_has_at_most_one_key():
 | 
						|
    """Test has_at_most_one_key validator."""
 | 
						|
    schema = vol.Schema(cv.has_at_most_one_key('beer', 'soda'))
 | 
						|
 | 
						|
    for value in (None, [], {'beer': None, 'soda': None}):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in ({}, {'beer': None}, {'soda': None}):
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_has_at_least_one_key():
 | 
						|
    """Test has_at_least_one_key validator."""
 | 
						|
    schema = vol.Schema(cv.has_at_least_one_key('beer', 'soda'))
 | 
						|
 | 
						|
    for value in (None, [], {}, {'wine': None}):
 | 
						|
        with pytest.raises(vol.MultipleInvalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    for value in ({'beer': None}, {'soda': None}):
 | 
						|
        schema(value)
 | 
						|
 | 
						|
 | 
						|
def test_enum():
 | 
						|
    """Test enum validator."""
 | 
						|
    class TestEnum(enum.Enum):
 | 
						|
        """Test enum."""
 | 
						|
 | 
						|
        value1 = "Value 1"
 | 
						|
        value2 = "Value 2"
 | 
						|
 | 
						|
    schema = vol.Schema(cv.enum(TestEnum))
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema('value3')
 | 
						|
 | 
						|
 | 
						|
def test_socket_timeout():  # pylint: disable=invalid-name
 | 
						|
    """Test socket timeout validator."""
 | 
						|
    schema = vol.Schema(cv.socket_timeout)
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema(0.0)
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema(-1)
 | 
						|
 | 
						|
    assert _GLOBAL_DEFAULT_TIMEOUT == schema(None)
 | 
						|
 | 
						|
    assert schema(1) == 1.0
 | 
						|
 | 
						|
 | 
						|
def test_matches_regex():
 | 
						|
    """Test matches_regex validator."""
 | 
						|
    schema = vol.Schema(cv.matches_regex('.*uiae.*'))
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema(1.0)
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema("  nrtd   ")
 | 
						|
 | 
						|
    test_str = "This is a test including uiae."
 | 
						|
    assert schema(test_str) == test_str
 | 
						|
 | 
						|
 | 
						|
def test_is_regex():
 | 
						|
    """Test the is_regex validator."""
 | 
						|
    schema = vol.Schema(cv.is_regex)
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema("(")
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        schema({"a dict": "is not a regex"})
 | 
						|
 | 
						|
    valid_re = ".*"
 | 
						|
    schema(valid_re)
 | 
						|
 | 
						|
 | 
						|
def test_comp_entity_ids():
 | 
						|
    """Test config validation for component entity IDs."""
 | 
						|
    schema = vol.Schema(cv.comp_entity_ids)
 | 
						|
 | 
						|
    for valid in ('ALL', 'all', 'AlL', 'light.kitchen', ['light.kitchen'],
 | 
						|
                  ['light.kitchen', 'light.ceiling'], []):
 | 
						|
        schema(valid)
 | 
						|
 | 
						|
    for invalid in (['light.kitchen', 'not-entity-id'], '*', ''):
 | 
						|
        with pytest.raises(vol.Invalid):
 | 
						|
            schema(invalid)
 | 
						|
 | 
						|
 | 
						|
def test_schema_with_slug_keys_allows_old_slugs(caplog):
 | 
						|
    """Test schema with slug keys allowing old slugs."""
 | 
						|
    schema = cv.schema_with_slug_keys(str)
 | 
						|
 | 
						|
    with patch.dict(cv.INVALID_SLUGS_FOUND, clear=True):
 | 
						|
        for value in ('_world', 'wow__yeah'):
 | 
						|
            caplog.clear()
 | 
						|
            # Will raise if not allowing old slugs
 | 
						|
            schema({value: 'yo'})
 | 
						|
            assert "Found invalid slug {}".format(value) in caplog.text
 | 
						|
 | 
						|
        assert len(cv.INVALID_SLUGS_FOUND) == 2
 | 
						|
 | 
						|
 | 
						|
def test_entity_id_allow_old_validation(caplog):
 | 
						|
    """Test schema allowing old entity_ids."""
 | 
						|
    schema = vol.Schema(cv.entity_id)
 | 
						|
 | 
						|
    with patch.dict(cv.INVALID_ENTITY_IDS_FOUND, clear=True):
 | 
						|
        for value in ('hello.__world', 'great.wow__yeah'):
 | 
						|
            caplog.clear()
 | 
						|
            # Will raise if not allowing old entity ID
 | 
						|
            schema(value)
 | 
						|
            assert "Found invalid entity_id {}".format(value) in caplog.text
 | 
						|
 | 
						|
        assert len(cv.INVALID_ENTITY_IDS_FOUND) == 2
 | 
						|
 | 
						|
 | 
						|
def test_uuid4_hex(caplog):
 | 
						|
    """Test uuid validation."""
 | 
						|
    schema = vol.Schema(cv.uuid4_hex)
 | 
						|
 | 
						|
    for value in ['Not a hex string', '0', 0]:
 | 
						|
        with pytest.raises(vol.Invalid):
 | 
						|
            schema(value)
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        # the 13th char should be 4
 | 
						|
        schema('a03d31b22eee1acc9b90eec40be6ed23')
 | 
						|
 | 
						|
    with pytest.raises(vol.Invalid):
 | 
						|
        # the 17th char should be 8-a
 | 
						|
        schema('a03d31b22eee4acc7b90eec40be6ed23')
 | 
						|
 | 
						|
    _hex = uuid.uuid4().hex
 | 
						|
    assert schema(_hex) == _hex
 | 
						|
    assert schema(_hex.upper()) == _hex
 |