diff --git a/homeassistant/util/yaml.py b/homeassistant/util/yaml.py index 517ed6c4fb0..e083f3d4b32 100644 --- a/homeassistant/util/yaml.py +++ b/homeassistant/util/yaml.py @@ -1,7 +1,7 @@ """YAML utility functions.""" import logging import os -from collections import OrderedDict +from collections import Counter, OrderedDict import yaml @@ -36,7 +36,11 @@ def _include_yaml(loader, node): def _ordered_dict(loader, node): """Load YAML mappings into an ordered dict to preserve key order.""" loader.flatten_mapping(node) - return OrderedDict(loader.construct_pairs(node)) + nodes = loader.construct_pairs(node) + dups = [k for k, v in Counter(k for k, _ in nodes).items() if v > 1] + if dups: + raise yaml.YAMLError("ERROR: duplicate keys: {}".format(dups)) + return OrderedDict(nodes) yaml.SafeLoader.add_constructor('!include', _include_yaml) diff --git a/tests/util/test_yaml.py b/tests/util/test_yaml.py new file mode 100644 index 00000000000..e865b5bba32 --- /dev/null +++ b/tests/util/test_yaml.py @@ -0,0 +1,34 @@ +"""Test Home Assistant yaml loader.""" +import io +import unittest + +from homeassistant.util import yaml + + +class TestYaml(unittest.TestCase): + """Test util.yaml loader.""" + + def test_simple_list(self): + """Test simple list.""" + conf = "config:\n - simple\n - list" + with io.StringIO(conf) as f: + doc = yaml.yaml.safe_load(f) + assert doc['config'] == ["simple", "list"] + + def test_simple_dict(self): + """Test simple dict.""" + conf = "key: value" + with io.StringIO(conf) as f: + doc = yaml.yaml.safe_load(f) + assert doc['key'] == 'value' + + def test_duplicate_key(self): + """Test simple dict.""" + conf = "key: thing1\nkey: thing2" + try: + with io.StringIO(conf) as f: + yaml.yaml.safe_load(f) + except Exception: + pass + else: + assert 0