import unittest

import mongoext.collection as collection
import mongoext.document as document
import mongoext.scheme as scheme
import mongoext.exc as exc

from . import (
    fixture,
    utils,
)


class Document(document.Document):
    content = scheme.String()
    client_id = scheme.Integer(required=True)


class InheritedDocument(Document):
    author_id = scheme.Integer()


class TestInitialization(unittest.TestCase):
    def test_full_success(self):
        Document(client_id=1, content='content')

    def test_partial_success(self):
        Document(content='content')

    def test_undefined_field(self):
        Document(user_id=1)

    def test_empty_initialization(self):
        Document()


class TestSetAttribute(unittest.TestCase):
    def setUp(self):
        self.document = Document()

    def test_set_undefined_attribute(self):
        self.document.user_id = 1

    def test_set_defined_attribute(self):
        self.document.content = 'content'

    def test_set_defined_attribute_cast_failure(self):
        with self.assertRaises(exc.ValidationError):
            self.document.client_id = 'a'


class TestToDict(unittest.TestCase):
    def test_full_document(self):
        data = {
            '_id': None,
            'client_id': 1,
            'content': u'content',
        }
        document = Document(**data)
        self.assertEqual(dict(document), data)

    def test_partial_document(self):
        document = Document(client_id=1)
        self.assertEqual(dict(document), {
            '_id': None,
            'client_id': 1,
            'content': None,
        })

    def test_inherited_document(self):
        document = InheritedDocument(client_id=1, author_id=1)
        expected = {
            '_id': None,
            'client_id': 1,
            'content': None,
            'author_id': 1,
        }
        self.assertEqual(dict(document), expected)


class TestRepr(unittest.TestCase):
    def test_repr(self):
        self.assertEqual(repr(Document()), '<Document: None>')


class TestDictBehavior(unittest.TestCase):
    def test_getitem(self):
        document = InheritedDocument(client_id=1)
        expected = 1
        self.assertEqual(document['client_id'], expected)


class Collection(collection.Collection):
    CONNECTION = utils.get_connection()

    DATABASE = 'db'
    NAME = 'collection'


class TestSave(unittest.TestCase):
    def setUp(self):
        self.collection = Collection(Document)

    def test_save(self):
        document = Document()
        document.client_id = 1
        document.content = 'content'
        self.collection.save(document)
        self.assertIsNotNone(document._id)

    def test_update(self):
        document = Document()
        document.client_id = 1
        document.content = 'content'
        self.collection.save(document)
        document.content = u''
        self.collection.save(document)
        document = self.collection.find_one(document._id)
        self.assertEqual(document.content, u'')

    def test_scheme_error_save(self):
        document = Document()
        document.content = 'content'
        with self.assertRaises(exc.ValidationError):
            self.collection.save(document)


class ModelTestCase(fixture.MongoextTestCase):
    def test_find(self):
        fields = {
            'created_ts': 1,
            'title': 1,
        }
        cursor = fixture.Collection(fixture.Document).find({'created_ts': {'$gte': 1}}, fields).sort('created_ts')
        self.assertTrue(all([lambda: isinstance(c, fixture.Document) for c in cursor]))

    def test_save(self):
        cursor = fixture.Collection(fixture.Document).find({'created_ts': {'$gte': 1}}).sort('created_ts')
        model = [c for c in cursor][0]
        fixture.Collection(fixture.Document).save(model)

    def test_fail_save(self):
        fields = {
            'created_ts': 1,
            'title': 1,
        }
        cursor = fixture.Collection(fixture.Document).find({'created_ts': {'$gte': 1}}, fields).sort('created_ts')
        model = [c for c in cursor][0]
        model.created_ts = None
        with self.assertRaises(exc.ValidationError):
            fixture.Collection(fixture.Document).save(model)

    def test_fail_insert(self):
        with self.assertRaises(TypeError):
            fixture.Collection(fixture.Document).insert_one(True)

    def test_repr(self):
        model = fixture.Collection(fixture.Document).find_one()
        self.assertTrue(isinstance(repr(model), str))

@@ -372,24 +372,92 @@
 Integer()%0A%0A%0A
+class ChangedDocument(Document):%0A    client_id = scheme.Integer()%0A%0A%0A
 class TestIn
@@ -1964,24 +1964,166 @@
  expected)%0A%0A
+    def test_changed_inherited_document(self):%0A        document = ChangedDocument(content='')%0A        self.assertEqual(document.content, '')%0A%0A
 %0Aclass TestR
@@ -2369,77 +2369,431 @@
     
-expected = 1%0A        self.assertEqual(document%5B'client_id'%5D, expected
+self.assertEqual(document%5B'client_id'%5D, 1)%0A%0A    def test_setitem(self):%0A        document = Document(client_id=1)%0A        document%5B'author_id'%5D = 2%0A        self.assertEqual(document%5B'author_id'%5D, 2)%0A%0A    def test_delitem(self):%0A        document = InheritedDocument(client_id=1, author_id=2)%0A        self.assertIsNotNone(document%5B'author_id'%5D)%0A        del document%5B'author_id'%5D%0A        self.assertIsNone(document%5B'author_id'%5D
 )%0A%0A%0A

add dict behavior tests