# -*- coding: utf-8 -*-
"""
    Unit tests for salt.utils.yamlloader.SaltYamlSafeLoader
"""

# Import python libs
from __future__ import absolute_import, print_function, unicode_literals

import collections
import textwrap

import salt.utils.files

# Import 3rd-party libs
from salt.ext import six
from salt.utils.yamlloader import SaltYamlSafeLoader
from tests.support.mock import mock_open, patch

# Import Salt Testing Libs
from tests.support.unit import TestCase

# Import Salt Libs
from yaml.constructor import ConstructorError


class YamlLoaderTestCase(TestCase):
    """
    TestCase for salt.utils.yamlloader module
    """

    @staticmethod
    def render_yaml(data):
        """
        Takes a YAML string, puts it into a mock file, passes that to the YAML
        SaltYamlSafeLoader and then returns the rendered/parsed YAML data
        """
        if six.PY2:
            # On Python 2, data read from a filehandle will not already be
            # unicode, so we need to encode it first to properly simulate
            # reading from a file. This is because unicode_literals is imported
            # and all of the data to be used in mock_open will be a unicode
            # type. Encoding will make it a str.
            data = salt.utils.data.encode(data)
        with patch("salt.utils.files.fopen", mock_open(read_data=data)) as mocked_file:
            with salt.utils.files.fopen(mocked_file) as mocked_stream:
                return SaltYamlSafeLoader(mocked_stream).get_data()

    @staticmethod
    def raise_error(value):
        raise TypeError("{0!r} is not a unicode string".format(value))

    def assert_unicode(self, value):
        """
        Make sure the entire data structure is unicode
        """
        if six.PY3:
            return
        if isinstance(value, six.string_types):
            if not isinstance(value, six.text_type):
                self.raise_error(value)
        elif isinstance(value, collections.Mapping):
            for k, v in six.iteritems(value):
                self.assert_unicode(k)
                self.assert_unicode(v)
        elif isinstance(value, collections.Iterable):
            for item in value:
                self.assert_unicode(item)

    def assert_matches(self, ret, expected):
        self.assertEqual(ret, expected)
        self.assert_unicode(ret)

    def test_yaml_basics(self):
        """
        Test parsing an ordinary path
        """
        self.assert_matches(
            self.render_yaml(
                textwrap.dedent(
                    """\
                p1:
                  - alpha
                  - beta"""
                )
            ),
            {"p1": ["alpha", "beta"]},
        )

    def test_yaml_merge(self):
        """
        Test YAML anchors
        """
        # Simple merge test
        self.assert_matches(
            self.render_yaml(
                textwrap.dedent(
                    """\
                p1: &p1
                  v1: alpha
                p2:
                  <<: *p1
                  v2: beta"""
                )
            ),
            {"p1": {"v1": "alpha"}, "p2": {"v1": "alpha", "v2": "beta"}},
        )

        # Test that keys/nodes are overwritten
        self.assert_matches(
            self.render_yaml(
                textwrap.dedent(
                    """\
                p1: &p1
                  v1: alpha
                p2:
                  <<: *p1
                  v1: new_alpha"""
                )
            ),
            {"p1": {"v1": "alpha"}, "p2": {"v1": "new_alpha"}},
        )

        # Test merging of lists
        self.assert_matches(
            self.render_yaml(
                textwrap.dedent(
                    """\
                p1: &p1
                  v1: &v1
                    - t1
                    - t2
                p2:
                  v2: *v1"""
                )
            ),
            {"p2": {"v2": ["t1", "t2"]}, "p1": {"v1": ["t1", "t2"]}},
        )

    def test_yaml_duplicates(self):
        """
        Test that duplicates still throw an error
        """
        with self.assertRaises(ConstructorError):
            self.render_yaml(
                textwrap.dedent(
                    """\
                p1: alpha
                p1: beta"""
                )
            )

        with self.assertRaises(ConstructorError):
            self.render_yaml(
                textwrap.dedent(
                    """\
                p1: &p1
                  v1: alpha
                p2:
                  <<: *p1
                  v2: beta
                  v2: betabeta"""
                )
            )

    def test_yaml_with_plain_scalars(self):
        """
        Test that plain (i.e. unqoted) string and non-string scalars are
        properly handled
        """
        self.assert_matches(
            self.render_yaml(
                textwrap.dedent(
                    """\
                foo:
                  b: {foo: bar, one: 1, list: [1, two, 3]}"""
                )
            ),
            {"foo": {"b": {"foo": "bar", "one": 1, "list": [1, "two", 3]}}},
        )

@@ -1,28 +1,4 @@
-# -*- coding: utf-8 -*-%0A
 %22%22%22%0A
@@ -66,212 +66,48 @@
 %22%22%0A%0A
-# Import python libs%0Afrom __future__ import absolute_import, print_function, unicode_literals%0A%0Aimport collections%0Aimport textwrap%0A%0Aimport salt.utils.files%0A%0A# Import 3rd-party libs%0Afrom salt.ext import six
+import textwrap%0A%0Aimport salt.utils.files
 %0Afro
@@ -207,36 +207,8 @@
 atch
-%0A%0A# Import Salt Testing Libs
 %0Afro
@@ -247,28 +247,8 @@
 Case
-%0A%0A# Import Salt Libs
 %0Afro
@@ -625,1485 +625,225 @@
     
-if six.PY2:%0A            # On Python 2, data read from a filehandle will not already be%0A            # unicode, so we need to encode it first to properly simulate%0A            # reading from a file. This is because unicode_literals is imported%0A            # and all of the data to be used in mock_open will be a unicode%0A            # type. Encoding will make it a str.%0A            data = salt.utils.data.encode(data)%0A        with patch(%22salt.utils.files.fopen%22, mock_open(read_data=data)) as mocked_file:%0A            with salt.utils.files.fopen(mocked_file) as mocked_stream:%0A                return SaltYamlSafeLoader(mocked_stream).get_data()%0A%0A    @staticmethod%0A    def raise_error(value):%0A        raise TypeError(%22%7B0!r%7D is not a unicode string%22.format(value))%0A%0A    def assert_unicode(self, value):%0A        %22%22%22%0A        Make sure the entire data structure is unicode%0A        %22%22%22%0A        if six.PY3:%0A            return%0A        if isinstance(value, six.string_types):%0A            if not isinstance(value, six.text_type):%0A                self.raise_error(value)%0A        elif isinstance(value, collections.Mapping):%0A            for k, v in six.iteritems(value):%0A                self.assert_unicode(k)%0A                self.assert_unicode(v)%0A        elif isinstance(value, collections.Iterable):%0A            for item in value:%0A                self.assert_unicode(item)%0A%0A    def assert_matches(self, ret, expected):%0A        self.assertEqual(ret, expected)%0A        self.assert_unicode(ret
+with patch(%22salt.utils.files.fopen%22, mock_open(read_data=data)) as mocked_file:%0A            with salt.utils.files.fopen(mocked_file) as mocked_stream:%0A                return SaltYamlSafeLoader(mocked_stream).get_data(
 )%0A%0A 
@@ -950,32 +950,29 @@
  self.assert
-_matches
+Equal
 (%0A          
@@ -1330,32 +1330,29 @@
  self.assert
-_matches
+Equal
 (%0A          
@@ -1737,32 +1737,29 @@
  self.assert
-_matches
+Equal
 (%0A          
@@ -2124,32 +2124,29 @@
  self.assert
-_matches
+Equal
 (%0A          
@@ -3340,16 +3340,13 @@
 sert
-_matches
+Equal
 (%0A  

Drop Py2 and six on tests/unit/utils/test_yamlloader.py