#!/usr/bin/env python

from __future__ import print_function, unicode_literals, absolute_import, division
__docformat__ = "restructuredtext en"

logger = __import__('logging').getLogger(__name__)

# disable: accessing protected members, too many methods
# pylint: disable=W0212,R0904


from hamcrest import is_not
from hamcrest import contains

from hamcrest import has_length
from hamcrest import assert_that
from hamcrest import has_property
from hamcrest import calling
from hamcrest import raises
does_not = is_not

import unittest

from zope import interface
from . import IUnicode

from nti.schema.field import Number
from nti.schema.field import Object


from nti.schema.field import DictFromObject
from nti.schema.field import ValidTextLine as TextLine

from ..schema import PermissiveSchemaConfigured

from nti.schema.interfaces import IBeforeDictAssignedEvent


class TestMisc(unittest.TestCase):

    def test_fixup_name(self):
        from zope.schema.fieldproperty import FieldPropertyStoredThroughField

        field = Object(IUnicode)
        field.__name__ = 'field'

        field_property = FieldPropertyStoredThroughField(field)
        field = field_property.field

        assert_that(field, has_property('__name__', '__st_field_st'))
        assert_that(field, has_property('__fixup_name__', 'field'))

class TestSchemaConfigured(unittest.TestCase):

    def test_init(self):
        class IA(interface.Interface):
            field = Number()

        @interface.implementer(IA)
        class A(PermissiveSchemaConfigured):
            pass

        # All of these are valid ways to call it
        A()
        A(thing='abc')
        a = A(field=1)
        assert_that(a, has_property('field', 1))

        # But we can flip off the extra
        A.SC_PERMISSIVE = False
        A()
        assert_that(calling(A).with_args(thing=1),
                    raises(TypeError, 'non schema keyword'))
        a = A(field=1)
        assert_that(a, has_property('field', 1))


from . import SchemaLayer
from zope.component import eventtesting

class TestConfigured(unittest.TestCase):

    layer = SchemaLayer


    def test_dict(self):

        dict_field = DictFromObject(key_type=TextLine(), value_type=Number())
        dict_field.__name__ = 'dict'

        class X(object):
            pass

        x = X()
        dict_field.set(x, dict_field.fromObject({'k': '1'}))

        assert_that(x, has_property('dict', {'k': 1.0}))

        events = eventtesting.getEvents(IBeforeDictAssignedEvent)
        assert_that(events, has_length(1))
        assert_that(events, contains(has_property('object', {'k': 1.0})))
