from __future__ import unicode_literals

# This needs to stay as the first import, it sets up paths.
from gaetest_common import DummyPostData, fill_authors

from google.appengine.ext import ndb
from unittest import TestCase
from wtforms import Form, TextField, IntegerField, BooleanField
from wtforms.compat import text_type
from wtforms_appengine.fields import KeyPropertyField
from wtforms_appengine.ndb import model_form

import second_ndb_module

class Author(ndb.Model):
    name = ndb.StringProperty(required=True)
    city = ndb.StringProperty()
    age = ndb.IntegerProperty(required=True)
    is_admin = ndb.BooleanProperty(default=False)


class Book(ndb.Model):
    author = ndb.KeyProperty(kind=Author)


class TestKeyPropertyField(TestCase):
    nosegae_datastore_v3 = True

    class F(Form):
        author = KeyPropertyField(reference_class=Author)

    def setUp(self):
        self.authors = fill_authors(Author)
        self.first_author_id = self.authors[0].key.id()

    def tearDown(self):
        for author in Author.query():
            author.key.delete()

    def test_no_data(self):
        form = self.F()
        form.author.query = Author.query().order(Author.name)

        assert not form.validate()
        ichoices = list(form.author.iter_choices())
        self.assertEqual(len(ichoices), len(self.authors))
        for author, (key, label, selected) in zip(self.authors, ichoices):
            self.assertEqual(key, text_type(author.key.id()))

    def test_form_data(self):
        # Valid data
        form = self.F(DummyPostData(author=text_type(self.first_author_id)))
        form.author.query = Author.query().order(Author.name)
        assert form.validate()
        ichoices = list(form.author.iter_choices())
        self.assertEqual(len(ichoices), len(self.authors))
        self.assertEqual(list(x[2] for x in ichoices), [True, False, False])

        # Bogus Data
        form = self.F(DummyPostData(author='fooflaf'))
        assert not form.validate()
        print list(form.author.iter_choices())
        assert all(x[2] is False for x in form.author.iter_choices())


class TestModelForm(TestCase):
    nosegae_datastore_v3 = True

    EXPECTED_AUTHOR = [('name', TextField), ('city', TextField), ('age', IntegerField), ('is_admin', BooleanField)]

    def test_author(self):
        form = model_form(Author)
        for (expected_name, expected_type), field in zip(self.EXPECTED_AUTHOR, form()):
            self.assertEqual(field.name, expected_name)
            self.assertEqual(type(field), expected_type)

    def test_book(self):
        authors = set(text_type(x.key.id()) for x in fill_authors(Author))
        authors.add('__None')
        form = model_form(Book)
        keys = set()
        for key, b, c in form().author.iter_choices():
            keys.add(key)

        self.assertEqual(authors, keys)

    def test_second_book(self):
        authors = set(text_type(x.key.id()) for x in fill_authors(Author))
        authors.add('__None')
        form = model_form(second_ndb_module.SecondBook)
        keys = set()
        for key, b, c in form().author.iter_choices():
            keys.add(key)

        self.assertEqual(authors, keys)

@@ -354,16 +354,35 @@
 s import
+ JsonPropertyField,
  KeyProp
@@ -728,16 +728,639 @@
 uthor)%0A%0A
+class TestJsonPropertyField(TestCase):%0A    nosegae_datastore_v3 = True%0A%0A    class F(Form):%0A        field = JsonPropertyField()%0A%0A    def test_round_trip(self):%0A        # Valid data%0A        test_data = %7Bu'a': %7B'b': 3, 'c': %5B'a', 1, False%5D%7D%7D%0A%0A        form = self.F()%0A        form.process(data=%7B'field': test_data%7D)%0A        raw_string = form.field._value()%0A        assert form.validate()%0A        form2 = self.F()%0A        form2.process(formdata=DummyPostData(field=raw_string))%0A        assert form.validate()%0A        # Test that we get back the same structure we serialized%0A        self.assertEqual(test_data, form2.field.data)%0A
 %0Aclass T

Add tests for JsonPropertyField round-tripping.