"""
Tests for expressions.py

"""
import unittest

from zope.testing.cleanup import CleanUp

from z3c.pt import expressions


# pylint:disable=protected-access


class TestRenderContentProvider(CleanUp, unittest.TestCase):
    def test_not_found(self):
        from zope.contentprovider.interfaces import ContentProviderLookupError

        context = object()
        request = object()
        view = object()
        name = "a provider"
        econtext = {"context": context, "request": request, "view": view}

        with self.assertRaises(ContentProviderLookupError) as exc:
            expressions.render_content_provider(econtext, name)

        e = exc.exception
        self.assertEqual(e.args, (name, (context, request, view)))

    def test_sets_ilocation_name(self):
        from zope import component
        from zope import interface
        from zope.contentprovider.interfaces import IContentProvider
        from zope.location.interfaces import ILocation

        attrs = {}

        @interface.implementer(ILocation, IContentProvider)
        class Provider:
            def __init__(self, *args):
                pass

            def __setattr__(self, name, value):
                attrs[name] = value

            update = render = lambda s: None

        component.provideAdapter(
            Provider,
            adapts=(object, object, object),
            provides=IContentProvider,
            name="a provider",
        )

        context = object()
        request = object()
        view = object()
        econtext = {"context": context, "request": request, "view": view}

        expressions.render_content_provider(econtext, "a provider")

        self.assertEqual(attrs, {"__name__": "a provider"})


class TestPathExpr(CleanUp, unittest.TestCase):
    def test_translate_empty_string(self):
        import ast

        expr = expressions.PathExpr("")
        result = expr.translate("", "foo")

        self.assertEqual(len(result), 1)
        self.assertIsInstance(result[0], ast.Assign)

    def test_translate_invalid_path(self):
        from chameleon.exc import ExpressionError

        expr = expressions.PathExpr("")
        with self.assertRaises(ExpressionError):
            expr.translate("not valid", None)

    def test_translate_components(self):
        from chameleon.astutil import ASTCodeGenerator
        from chameleon.astutil import node_annotations
        from chameleon.codegen import TemplateCodeGenerator

        expr = expressions.PathExpr("")
        comps = expr._find_translation_components(["a"])

        # First component is skipped
        self.assertEqual(comps, [])

        # Single literal
        comps = expr._find_translation_components(["a", "b"])
        self.assertEqual([s.s for s in comps], ["b"])

        # Multiple literals
        comps = expr._find_translation_components(["a", "b", "c"])
        self.assertEqual([s.s for s in comps], ["b", "c"])

        # Single interpolation---must be longer than one character
        comps = expr._find_translation_components(["a", "?b"])
        self.assertEqual([s.s for s in comps], ["?b"])

        comps = expr._find_translation_components(["a", "?var"])
        self.assertEqual(len(comps), 1)
        code = ASTCodeGenerator(comps[0]).code
        self.assertEqual(code, "(format % args)")
        code = TemplateCodeGenerator(comps[0]).code
        self.assertEqual(code, "('%s' % (var, ))")

        args = node_annotations[comps[0].right]
        code = TemplateCodeGenerator(args).code
        self.assertEqual(code, "(var, )")

        # Multiple interpolations
        comps = expr._find_translation_components(["a", "?var", "?var2"])
        self.assertEqual(len(comps), 2)
        code = ASTCodeGenerator(comps[0]).code
        self.assertEqual(code, "(format % args)")
        code = TemplateCodeGenerator(comps[0]).code
        self.assertEqual(code, "('%s' % (var, ))")

        args = node_annotations[comps[0].right]
        code = TemplateCodeGenerator(args).code
        self.assertEqual(code, "(var, )")

        code = ASTCodeGenerator(comps[1]).code
        self.assertEqual(code, "(format % args)")
        code = TemplateCodeGenerator(comps[1]).code
        self.assertEqual(code, "('%s' % (var2, ))")

        args = node_annotations[comps[1].right]
        code = TemplateCodeGenerator(args).code
        self.assertEqual(code, "(var2, )")

        translated = expr.translate("a/?var/?var2", None)
        self.assertEqual(len(translated), 1)
        code = TemplateCodeGenerator(translated[0]).code
        self.assertEqual(
            code,
            "\nNone = _path_traverse(a, econtext, True, (('%s' % (var, )), "
            "('%s' % (var2, )), ))",
        )
