# -*- coding: utf-8 -*-
"""
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.location.interfaces import ILocation
        from zope.contentprovider.interfaces import IContentProvider

        attrs = {}

        @interface.implementer(ILocation, IContentProvider)
        class Provider(object):
            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.codegen import TemplateCodeGenerator
        from chameleon.astutil import ASTCodeGenerator
        from chameleon.astutil import node_annotations
        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
        # XXX: Normally this starts with 'None =', but sometimes on Python 2,
        # at least in tox, it starts with '__package__ ='. Why
        # is this?
        code = code.strip().replace("__package__", 'None')
        self.assertEqual(
            code,
            "None = _path_traverse(a, econtext, True, (('%s' % (var, )), ('%s' % (var2, )), ))")
