## $Id: test_textlinechoice.py 7196 2011-11-25 07:44:52Z henrik $
##
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
"""Test TextLineChoice
"""
import unittest
from zope.interface import implements, directlyProvides
from zope.schema import vocabulary
from zope.schema.interfaces import (
    InvalidValue, ValidationError,
    IVocabulary, ISource, IContextSourceBinder,)
from zope.schema.tests.test_strfield import TextLineTest
from waeup.sirp.schema import TextLineChoice

# Define some helper functions, classes, vars for tests
class DummyRegistry(vocabulary.VocabularyRegistry):
    def get(self, object, name):
        v = SampleVocabulary()
        v.object = object
        v.name = name
        return v

class SampleTerm(object):
    pass

SAMPLE_VALUES = [u'a', u'b', u'c', u'd']
class SampleVocabulary(object):
    implements(IVocabulary)

    def __iter__(self):
        return iter([self.getTerm(x) for x in SAMPLE_VALUES])

    def __contains__(self, value):
        return value in SAMPLE_VALUES
        return 0 <= value < 10

    def __len__(self):
        return len(SAMPLE_VALUES)

    def getTerm(self, value):
        if value in self:
            t = SampleTerm()
            t.value = value
            t.upper = value.upper() #2 * value
            return t
        raise LookupError("no such value: %r" % value)

class LetterASource(object):
    # A source that contains all strings with letter 'a'
    implements(ISource)
    required_letter = 'a'
    def __contains__(self, value):
        return self.required_letter in value
letter_a_source = LetterASource()

def letter_source_binder(context):
    source = LetterASource()
    source.required_letter = context.req_letter
    return source
directlyProvides(letter_source_binder, IContextSourceBinder)

class SampleContext(object):
    req_letter = 'b'



class TextLineChoiceAsTextLineTest(TextLineTest):
    # Tests to guarantee TextLine like behaviour of TextLineChoice
    # i.e. make sure that a TextLineChoice can everything a TextLine can
    _Field_Factory = TextLineChoice

class TextLineChoice_Values_Tests(unittest.TestCase):
    # Tests to guarantee values support
    def test_create_vocabulary(self):
        choice = TextLineChoice(values=[1, 3])
        self.assertEqual([term.value for term in choice.vocabulary], [1, 3])

    def test_validate_string(self):
        choice = TextLineChoice(values=[u'a', u'c'])
        choice.validate(u'a')
        #choice.validate('c')
        choice.validate(u'c')
        self.assertRaises(InvalidValue, choice.validate, u'd')

    def test_validate_strings(self):
        choice = TextLineChoice(values=[u'foo', u'bar'])
        choice.validate(u'foo')
        choice.validate(u'bar')
        choice.validate(u'bar')
        self.assertRaises(InvalidValue, choice.validate, u'baz')

class TextLineChoice_Vocabulary_Tests(unittest.TestCase):
    # Tests of the TextLineChoice Field using vocabularies.
    # Most tests were copied (slightly modified) from zope.schema.tests.

    def setUp(self):
        vocabulary._clear()

    def tearDown(self):
        vocabulary._clear()

    def check_preconstructed(self, cls, okval, badval):
        v = SampleVocabulary()
        field = cls(vocabulary=v)
        self.assert_(field.vocabulary is v)
        self.assert_(field.vocabularyName is None)
        bound = field.bind(None)
        self.assert_(bound.vocabulary is v)
        self.assert_(bound.vocabularyName is None)
        bound.default = okval
        self.assertEqual(bound.default, okval)
        self.assertRaises(ValidationError, setattr, bound, "default", badval)

    def test_preconstructed_vocabulary(self):
        self.check_preconstructed(TextLineChoice, u'a', u'z')

    def check_constructed(self, cls, okval, badval):
        vocabulary.setVocabularyRegistry(DummyRegistry())
        field = cls(vocabulary="vocab")
        self.assert_(field.vocabulary is None)
        self.assertEqual(field.vocabularyName, "vocab")
        o = object()
        bound = field.bind(o)
        self.assert_(isinstance(bound.vocabulary, SampleVocabulary))
        bound.default = okval
        self.assertEqual(bound.default, okval)
        self.assertRaises(ValidationError, setattr, bound, "default", badval)

    def test_constructed_vocabulary(self):
        self.check_constructed(TextLineChoice, u'a', u'z')

    def test_create_vocabulary(self):
        vocabulary.setVocabularyRegistry(DummyRegistry())
        field = TextLineChoice(vocabulary="vocab")
        o = object()
        bound = field.bind(o)
        self.assertEqual([term.value for term in bound.vocabulary],
                         SAMPLE_VALUES)

    def test_undefined_vocabulary(self):
        choice = TextLineChoice(vocabulary="unknown")
        self.assertRaises(ValueError, choice.validate, u"value")

class TextLineChoice_Source_Tests(unittest.TestCase):
    # Tests of the TextLineChoice Field using sources.

    def test_simple_source(self):
        choice = TextLineChoice(__name__='astring', source=letter_a_source)
        bound = choice.bind(object())
        self.assertEqual(bound.vocabulary, letter_a_source)
        return

    def test_validate_simple_source(self):
        choice = TextLineChoice(__name__='astring', source=letter_a_source)
        bound = choice.bind(object())
        bound.validate(u'string_with_letter_a')
        self.assertRaises(
            InvalidValue, bound.validate, u'other_string')
        return

    def test_contextual_source(self):
        # make sure we can pass contextual sources
        choice = TextLineChoice(__name__='astring', source=letter_source_binder)
        bound = choice.bind(SampleContext()) # requires 'b' instead of 'a'
        self.assertTrue(isinstance(bound.vocabulary, LetterASource))
        self.assertTrue(bound.vocabulary is not letter_a_source)
        return

    def test_validate_contextual_source(self):
        # make sure the values from context are considered
        choice = TextLineChoice(__name__='astring', source=letter_source_binder)
        bound = choice.bind(SampleContext()) # requires 'b' instead of 'a'
        bound.validate(u'string_with_letter_b')
        self.assertRaises(
            InvalidValue, bound.validate, u'other_string') # no 'b'
        return

def test_suite():
    # We must define a test suite as we do not want the imported
    # TextLineTest to be collected by testrunner.
    return unittest.TestSuite((
        unittest.makeSuite(TextLineChoiceAsTextLineTest),
        unittest.makeSuite(TextLineChoice_Values_Tests),
        unittest.makeSuite(TextLineChoice_Vocabulary_Tests),
        unittest.makeSuite(TextLineChoice_Source_Tests),
        ))
