diff --git a/tests/fields/fields.py b/tests/fields/fields.py index b43c92af..194d07d7 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -2,9 +2,6 @@ import datetime import unittest import uuid -import math -import itertools -import re import sys from nose.plugins.skip import SkipTest @@ -13,15 +10,10 @@ import six from decimal import Decimal from bson import DBRef, ObjectId, SON -try: - from bson.int64 import Int64 -except ImportError: - Int64 = long from mongoengine import * -from mongoengine.connection import get_db from mongoengine.base import (BaseDict, BaseField, EmbeddedDocumentList, - _document_registry, LazyReference) + _document_registry) from tests.utils import MongoDBTestCase @@ -284,30 +276,6 @@ class FieldTest(MongoDBTestCase): # attempted. self.assertRaises(ValidationError, ret.validate) - def test_int_and_float_ne_operator(self): - class TestDocument(Document): - int_fld = IntField() - float_fld = FloatField() - - TestDocument.drop_collection() - - TestDocument(int_fld=None, float_fld=None).save() - TestDocument(int_fld=1, float_fld=1).save() - - self.assertEqual(1, TestDocument.objects(int_fld__ne=None).count()) - self.assertEqual(1, TestDocument.objects(float_fld__ne=None).count()) - - def test_long_ne_operator(self): - class TestDocument(Document): - long_fld = LongField() - - TestDocument.drop_collection() - - TestDocument(long_fld=None).save() - TestDocument(long_fld=1).save() - - self.assertEqual(1, TestDocument.objects(long_fld__ne=None).count()) - def test_object_id_validation(self): """Ensure that invalid values cannot be assigned to an ObjectIdField. @@ -351,135 +319,6 @@ class FieldTest(MongoDBTestCase): person.name = 'Shorter name' person.validate() - def test_url_validation(self): - """Ensure that URLFields validate urls properly.""" - class Link(Document): - url = URLField() - - link = Link() - link.url = 'google' - self.assertRaises(ValidationError, link.validate) - - link.url = 'http://www.google.com:8080' - link.validate() - - def test_unicode_url_validation(self): - """Ensure unicode URLs are validated properly.""" - class Link(Document): - url = URLField() - - link = Link() - link.url = u'http://привет.com' - - # TODO fix URL validation - this *IS* a valid URL - # For now we just want to make sure that the error message is correct - try: - link.validate() - self.assertTrue(False) - except ValidationError as e: - self.assertEqual( - unicode(e), - u"ValidationError (Link:None) (Invalid URL: http://\u043f\u0440\u0438\u0432\u0435\u0442.com: ['url'])" - ) - - def test_url_scheme_validation(self): - """Ensure that URLFields validate urls with specific schemes properly. - """ - class Link(Document): - url = URLField() - - class SchemeLink(Document): - url = URLField(schemes=['ws', 'irc']) - - link = Link() - link.url = 'ws://google.com' - self.assertRaises(ValidationError, link.validate) - - scheme_link = SchemeLink() - scheme_link.url = 'ws://google.com' - scheme_link.validate() - - def test_url_allowed_domains(self): - """Allow underscore in domain names. - """ - class Link(Document): - url = URLField() - - link = Link() - link.url = 'https://san_leandro-ca.geebo.com' - link.validate() - - def test_int_validation(self): - """Ensure that invalid values cannot be assigned to int fields. - """ - class Person(Document): - age = IntField(min_value=0, max_value=110) - - person = Person() - person.age = 50 - person.validate() - - person.age = -1 - self.assertRaises(ValidationError, person.validate) - person.age = 120 - self.assertRaises(ValidationError, person.validate) - person.age = 'ten' - self.assertRaises(ValidationError, person.validate) - - def test_long_validation(self): - """Ensure that invalid values cannot be assigned to long fields. - """ - class TestDocument(Document): - value = LongField(min_value=0, max_value=110) - - doc = TestDocument() - doc.value = 50 - doc.validate() - - doc.value = -1 - self.assertRaises(ValidationError, doc.validate) - doc.age = 120 - self.assertRaises(ValidationError, doc.validate) - doc.age = 'ten' - self.assertRaises(ValidationError, doc.validate) - - def test_float_validation(self): - """Ensure that invalid values cannot be assigned to float fields. - """ - class Person(Document): - height = FloatField(min_value=0.1, max_value=3.5) - - class BigPerson(Document): - height = FloatField() - - person = Person() - person.height = 1.89 - person.validate() - - person.height = '2.0' - self.assertRaises(ValidationError, person.validate) - - person.height = 0.01 - self.assertRaises(ValidationError, person.validate) - - person.height = 4.0 - self.assertRaises(ValidationError, person.validate) - - person_2 = Person(height='something invalid') - self.assertRaises(ValidationError, person_2.validate) - - big_person = BigPerson() - - for value, value_type in enumerate(six.integer_types): - big_person.height = value_type(value) - big_person.validate() - - big_person.height = 2 ** 500 - big_person.validate() - - big_person.height = 2 ** 100000 # Too big for a float value - self.assertRaises(ValidationError, big_person.validate) - def test_decimal_validation(self): """Ensure that invalid values cannot be assigned to decimal fields. """ @@ -3534,19 +3373,6 @@ class FieldTest(MongoDBTestCase): with self.assertRaises(FieldDoesNotExist): Doc(bar='test') - def test_long_field_is_considered_as_int64(self): - """ - Tests that long fields are stored as long in mongo, even if long - value is small enough to be an int. - """ - class TestLongFieldConsideredAsInt64(Document): - some_long = LongField() - - doc = TestLongFieldConsideredAsInt64(some_long=42).save() - db = get_db() - self.assertIsInstance(db.test_long_field_considered_as_int64.find()[0]['some_long'], Int64) - self.assertIsInstance(doc.some_long, six.integer_types) - class EmbeddedDocumentListFieldTestCase(MongoDBTestCase): @@ -4493,522 +4319,5 @@ class CachedReferenceFieldTest(MongoDBTestCase): self.assertIsInstance(ocorrence.animal, Animal) -class LazyReferenceFieldTest(MongoDBTestCase): - def test_lazy_reference_config(self): - # Make sure ReferenceField only accepts a document class or a string - # with a document class name. - self.assertRaises(ValidationError, LazyReferenceField, EmbeddedDocument) - - def test_lazy_reference_simple(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = LazyReferenceField(Animal) - - Animal.drop_collection() - Ocurrence.drop_collection() - - animal = Animal(name="Leopard", tag="heavy").save() - Ocurrence(person="test", animal=animal).save() - p = Ocurrence.objects.get() - self.assertIsInstance(p.animal, LazyReference) - fetched_animal = p.animal.fetch() - self.assertEqual(fetched_animal, animal) - # `fetch` keep cache on referenced document by default... - animal.tag = "not so heavy" - animal.save() - double_fetch = p.animal.fetch() - self.assertIs(fetched_animal, double_fetch) - self.assertEqual(double_fetch.tag, "heavy") - # ...unless specified otherwise - fetch_force = p.animal.fetch(force=True) - self.assertIsNot(fetch_force, fetched_animal) - self.assertEqual(fetch_force.tag, "not so heavy") - - def test_lazy_reference_fetch_invalid_ref(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = LazyReferenceField(Animal) - - Animal.drop_collection() - Ocurrence.drop_collection() - - animal = Animal(name="Leopard", tag="heavy").save() - Ocurrence(person="test", animal=animal).save() - animal.delete() - p = Ocurrence.objects.get() - self.assertIsInstance(p.animal, LazyReference) - with self.assertRaises(DoesNotExist): - p.animal.fetch() - - def test_lazy_reference_set(self): - class Animal(Document): - meta = {'allow_inheritance': True} - - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = LazyReferenceField(Animal) - - Animal.drop_collection() - Ocurrence.drop_collection() - - class SubAnimal(Animal): - nick = StringField() - - animal = Animal(name="Leopard", tag="heavy").save() - sub_animal = SubAnimal(nick='doggo', name='dog').save() - for ref in ( - animal, - animal.pk, - DBRef(animal._get_collection_name(), animal.pk), - LazyReference(Animal, animal.pk), - - sub_animal, - sub_animal.pk, - DBRef(sub_animal._get_collection_name(), sub_animal.pk), - LazyReference(SubAnimal, sub_animal.pk), - ): - p = Ocurrence(person="test", animal=ref).save() - p.reload() - self.assertIsInstance(p.animal, LazyReference) - p.animal.fetch() - - def test_lazy_reference_bad_set(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = LazyReferenceField(Animal) - - Animal.drop_collection() - Ocurrence.drop_collection() - - class BadDoc(Document): - pass - - animal = Animal(name="Leopard", tag="heavy").save() - baddoc = BadDoc().save() - for bad in ( - 42, - 'foo', - baddoc, - DBRef(baddoc._get_collection_name(), animal.pk), - LazyReference(BadDoc, animal.pk) - ): - with self.assertRaises(ValidationError): - p = Ocurrence(person="test", animal=bad).save() - - def test_lazy_reference_query_conversion(self): - """Ensure that LazyReferenceFields can be queried using objects and values - of the type of the primary key of the referenced object. - """ - class Member(Document): - user_num = IntField(primary_key=True) - - class BlogPost(Document): - title = StringField() - author = LazyReferenceField(Member, dbref=False) - - Member.drop_collection() - BlogPost.drop_collection() - - m1 = Member(user_num=1) - m1.save() - m2 = Member(user_num=2) - m2.save() - - post1 = BlogPost(title='post 1', author=m1) - post1.save() - - post2 = BlogPost(title='post 2', author=m2) - post2.save() - - post = BlogPost.objects(author=m1).first() - self.assertEqual(post.id, post1.id) - - post = BlogPost.objects(author=m2).first() - self.assertEqual(post.id, post2.id) - - # Same thing by passing a LazyReference instance - post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first() - self.assertEqual(post.id, post2.id) - - def test_lazy_reference_query_conversion_dbref(self): - """Ensure that LazyReferenceFields can be queried using objects and values - of the type of the primary key of the referenced object. - """ - class Member(Document): - user_num = IntField(primary_key=True) - - class BlogPost(Document): - title = StringField() - author = LazyReferenceField(Member, dbref=True) - - Member.drop_collection() - BlogPost.drop_collection() - - m1 = Member(user_num=1) - m1.save() - m2 = Member(user_num=2) - m2.save() - - post1 = BlogPost(title='post 1', author=m1) - post1.save() - - post2 = BlogPost(title='post 2', author=m2) - post2.save() - - post = BlogPost.objects(author=m1).first() - self.assertEqual(post.id, post1.id) - - post = BlogPost.objects(author=m2).first() - self.assertEqual(post.id, post2.id) - - # Same thing by passing a LazyReference instance - post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first() - self.assertEqual(post.id, post2.id) - - def test_lazy_reference_passthrough(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - animal = LazyReferenceField(Animal, passthrough=False) - animal_passthrough = LazyReferenceField(Animal, passthrough=True) - - Animal.drop_collection() - Ocurrence.drop_collection() - - animal = Animal(name="Leopard", tag="heavy").save() - Ocurrence(animal=animal, animal_passthrough=animal).save() - p = Ocurrence.objects.get() - self.assertIsInstance(p.animal, LazyReference) - with self.assertRaises(KeyError): - p.animal['name'] - with self.assertRaises(AttributeError): - p.animal.name - self.assertEqual(p.animal.pk, animal.pk) - - self.assertEqual(p.animal_passthrough.name, "Leopard") - self.assertEqual(p.animal_passthrough['name'], "Leopard") - - # Should not be able to access referenced document's methods - with self.assertRaises(AttributeError): - p.animal.save - with self.assertRaises(KeyError): - p.animal['save'] - - def test_lazy_reference_not_set(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = LazyReferenceField(Animal) - - Animal.drop_collection() - Ocurrence.drop_collection() - - Ocurrence(person='foo').save() - p = Ocurrence.objects.get() - self.assertIs(p.animal, None) - - def test_lazy_reference_equality(self): - class Animal(Document): - name = StringField() - tag = StringField() - - Animal.drop_collection() - - animal = Animal(name="Leopard", tag="heavy").save() - animalref = LazyReference(Animal, animal.pk) - self.assertEqual(animal, animalref) - self.assertEqual(animalref, animal) - - other_animalref = LazyReference(Animal, ObjectId("54495ad94c934721ede76f90")) - self.assertNotEqual(animal, other_animalref) - self.assertNotEqual(other_animalref, animal) - - def test_lazy_reference_embedded(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class EmbeddedOcurrence(EmbeddedDocument): - in_list = ListField(LazyReferenceField(Animal)) - direct = LazyReferenceField(Animal) - - class Ocurrence(Document): - in_list = ListField(LazyReferenceField(Animal)) - in_embedded = EmbeddedDocumentField(EmbeddedOcurrence) - direct = LazyReferenceField(Animal) - - Animal.drop_collection() - Ocurrence.drop_collection() - - animal1 = Animal('doggo').save() - animal2 = Animal('cheeta').save() - - def check_fields_type(occ): - self.assertIsInstance(occ.direct, LazyReference) - for elem in occ.in_list: - self.assertIsInstance(elem, LazyReference) - self.assertIsInstance(occ.in_embedded.direct, LazyReference) - for elem in occ.in_embedded.in_list: - self.assertIsInstance(elem, LazyReference) - - occ = Ocurrence( - in_list=[animal1, animal2], - in_embedded={'in_list': [animal1, animal2], 'direct': animal1}, - direct=animal1 - ).save() - check_fields_type(occ) - occ.reload() - check_fields_type(occ) - occ.direct = animal1.id - occ.in_list = [animal1.id, animal2.id] - occ.in_embedded.direct = animal1.id - occ.in_embedded.in_list = [animal1.id, animal2.id] - check_fields_type(occ) - - -class GenericLazyReferenceFieldTest(MongoDBTestCase): - def test_generic_lazy_reference_simple(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = GenericLazyReferenceField() - - Animal.drop_collection() - Ocurrence.drop_collection() - - animal = Animal(name="Leopard", tag="heavy").save() - Ocurrence(person="test", animal=animal).save() - p = Ocurrence.objects.get() - self.assertIsInstance(p.animal, LazyReference) - fetched_animal = p.animal.fetch() - self.assertEqual(fetched_animal, animal) - # `fetch` keep cache on referenced document by default... - animal.tag = "not so heavy" - animal.save() - double_fetch = p.animal.fetch() - self.assertIs(fetched_animal, double_fetch) - self.assertEqual(double_fetch.tag, "heavy") - # ...unless specified otherwise - fetch_force = p.animal.fetch(force=True) - self.assertIsNot(fetch_force, fetched_animal) - self.assertEqual(fetch_force.tag, "not so heavy") - - def test_generic_lazy_reference_choices(self): - class Animal(Document): - name = StringField() - - class Vegetal(Document): - name = StringField() - - class Mineral(Document): - name = StringField() - - class Ocurrence(Document): - living_thing = GenericLazyReferenceField(choices=[Animal, Vegetal]) - thing = GenericLazyReferenceField() - - Animal.drop_collection() - Vegetal.drop_collection() - Mineral.drop_collection() - Ocurrence.drop_collection() - - animal = Animal(name="Leopard").save() - vegetal = Vegetal(name="Oak").save() - mineral = Mineral(name="Granite").save() - - occ_animal = Ocurrence(living_thing=animal, thing=animal).save() - occ_vegetal = Ocurrence(living_thing=vegetal, thing=vegetal).save() - with self.assertRaises(ValidationError): - Ocurrence(living_thing=mineral).save() - - occ = Ocurrence.objects.get(living_thing=animal) - self.assertEqual(occ, occ_animal) - self.assertIsInstance(occ.thing, LazyReference) - self.assertIsInstance(occ.living_thing, LazyReference) - - occ.thing = vegetal - occ.living_thing = vegetal - occ.save() - - occ.thing = mineral - occ.living_thing = mineral - with self.assertRaises(ValidationError): - occ.save() - - def test_generic_lazy_reference_set(self): - class Animal(Document): - meta = {'allow_inheritance': True} - - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = GenericLazyReferenceField() - - Animal.drop_collection() - Ocurrence.drop_collection() - - class SubAnimal(Animal): - nick = StringField() - - animal = Animal(name="Leopard", tag="heavy").save() - sub_animal = SubAnimal(nick='doggo', name='dog').save() - for ref in ( - animal, - LazyReference(Animal, animal.pk), - {'_cls': 'Animal', '_ref': DBRef(animal._get_collection_name(), animal.pk)}, - - sub_animal, - LazyReference(SubAnimal, sub_animal.pk), - {'_cls': 'SubAnimal', '_ref': DBRef(sub_animal._get_collection_name(), sub_animal.pk)}, - ): - p = Ocurrence(person="test", animal=ref).save() - p.reload() - self.assertIsInstance(p.animal, (LazyReference, Document)) - p.animal.fetch() - - def test_generic_lazy_reference_bad_set(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = GenericLazyReferenceField(choices=['Animal']) - - Animal.drop_collection() - Ocurrence.drop_collection() - - class BadDoc(Document): - pass - - animal = Animal(name="Leopard", tag="heavy").save() - baddoc = BadDoc().save() - for bad in ( - 42, - 'foo', - baddoc, - LazyReference(BadDoc, animal.pk) - ): - with self.assertRaises(ValidationError): - p = Ocurrence(person="test", animal=bad).save() - - def test_generic_lazy_reference_query_conversion(self): - class Member(Document): - user_num = IntField(primary_key=True) - - class BlogPost(Document): - title = StringField() - author = GenericLazyReferenceField() - - Member.drop_collection() - BlogPost.drop_collection() - - m1 = Member(user_num=1) - m1.save() - m2 = Member(user_num=2) - m2.save() - - post1 = BlogPost(title='post 1', author=m1) - post1.save() - - post2 = BlogPost(title='post 2', author=m2) - post2.save() - - post = BlogPost.objects(author=m1).first() - self.assertEqual(post.id, post1.id) - - post = BlogPost.objects(author=m2).first() - self.assertEqual(post.id, post2.id) - - # Same thing by passing a LazyReference instance - post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first() - self.assertEqual(post.id, post2.id) - - def test_generic_lazy_reference_not_set(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class Ocurrence(Document): - person = StringField() - animal = GenericLazyReferenceField() - - Animal.drop_collection() - Ocurrence.drop_collection() - - Ocurrence(person='foo').save() - p = Ocurrence.objects.get() - self.assertIs(p.animal, None) - - def test_generic_lazy_reference_embedded(self): - class Animal(Document): - name = StringField() - tag = StringField() - - class EmbeddedOcurrence(EmbeddedDocument): - in_list = ListField(GenericLazyReferenceField()) - direct = GenericLazyReferenceField() - - class Ocurrence(Document): - in_list = ListField(GenericLazyReferenceField()) - in_embedded = EmbeddedDocumentField(EmbeddedOcurrence) - direct = GenericLazyReferenceField() - - Animal.drop_collection() - Ocurrence.drop_collection() - - animal1 = Animal('doggo').save() - animal2 = Animal('cheeta').save() - - def check_fields_type(occ): - self.assertIsInstance(occ.direct, LazyReference) - for elem in occ.in_list: - self.assertIsInstance(elem, LazyReference) - self.assertIsInstance(occ.in_embedded.direct, LazyReference) - for elem in occ.in_embedded.in_list: - self.assertIsInstance(elem, LazyReference) - - occ = Ocurrence( - in_list=[animal1, animal2], - in_embedded={'in_list': [animal1, animal2], 'direct': animal1}, - direct=animal1 - ).save() - check_fields_type(occ) - occ.reload() - check_fields_type(occ) - animal1_ref = {'_cls': 'Animal', '_ref': DBRef(animal1._get_collection_name(), animal1.pk)} - animal2_ref = {'_cls': 'Animal', '_ref': DBRef(animal2._get_collection_name(), animal2.pk)} - occ.direct = animal1_ref - occ.in_list = [animal1_ref, animal2_ref] - occ.in_embedded.direct = animal1_ref - occ.in_embedded.in_list = [animal1_ref, animal2_ref] - check_fields_type(occ) - - if __name__ == '__main__': unittest.main() diff --git a/tests/fields/test_float_field.py b/tests/fields/test_float_field.py new file mode 100644 index 00000000..fa92cf20 --- /dev/null +++ b/tests/fields/test_float_field.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +import six + +from mongoengine import * + +from tests.utils import MongoDBTestCase + + +class TestFloatField(MongoDBTestCase): + + def test_float_ne_operator(self): + class TestDocument(Document): + float_fld = FloatField() + + TestDocument.drop_collection() + + TestDocument(float_fld=None).save() + TestDocument(float_fld=1).save() + + self.assertEqual(1, TestDocument.objects(float_fld__ne=None).count()) + self.assertEqual(1, TestDocument.objects(float_fld__ne=1).count()) + + def test_validation(self): + """Ensure that invalid values cannot be assigned to float fields. + """ + class Person(Document): + height = FloatField(min_value=0.1, max_value=3.5) + + class BigPerson(Document): + height = FloatField() + + person = Person() + person.height = 1.89 + person.validate() + + person.height = '2.0' + self.assertRaises(ValidationError, person.validate) + + person.height = 0.01 + self.assertRaises(ValidationError, person.validate) + + person.height = 4.0 + self.assertRaises(ValidationError, person.validate) + + person_2 = Person(height='something invalid') + self.assertRaises(ValidationError, person_2.validate) + + big_person = BigPerson() + + for value, value_type in enumerate(six.integer_types): + big_person.height = value_type(value) + big_person.validate() + + big_person.height = 2 ** 500 + big_person.validate() + + big_person.height = 2 ** 100000 # Too big for a float value + self.assertRaises(ValidationError, big_person.validate) diff --git a/tests/fields/test_int_field.py b/tests/fields/test_int_field.py new file mode 100644 index 00000000..1b1f7ad9 --- /dev/null +++ b/tests/fields/test_int_field.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from mongoengine import * + +from tests.utils import MongoDBTestCase + + +class TestIntField(MongoDBTestCase): + + def test_int_validation(self): + """Ensure that invalid values cannot be assigned to int fields. + """ + class Person(Document): + age = IntField(min_value=0, max_value=110) + + person = Person() + person.age = 0 + person.validate() + + person.age = 50 + person.validate() + + person.age = 110 + person.validate() + + person.age = -1 + self.assertRaises(ValidationError, person.validate) + person.age = 120 + self.assertRaises(ValidationError, person.validate) + person.age = 'ten' + self.assertRaises(ValidationError, person.validate) + + def test_ne_operator(self): + class TestDocument(Document): + int_fld = IntField() + + TestDocument.drop_collection() + + TestDocument(int_fld=None).save() + TestDocument(int_fld=1).save() + + self.assertEqual(1, TestDocument.objects(int_fld__ne=None).count()) + self.assertEqual(1, TestDocument.objects(int_fld__ne=1).count()) diff --git a/tests/fields/test_lazy_reference_field.py b/tests/fields/test_lazy_reference_field.py new file mode 100644 index 00000000..a72e8cbe --- /dev/null +++ b/tests/fields/test_lazy_reference_field.py @@ -0,0 +1,524 @@ +# -*- coding: utf-8 -*- +from bson import DBRef, ObjectId + +from mongoengine import * +from mongoengine.base import LazyReference + +from tests.utils import MongoDBTestCase + + +class TestLazyReferenceField(MongoDBTestCase): + def test_lazy_reference_config(self): + # Make sure ReferenceField only accepts a document class or a string + # with a document class name. + self.assertRaises(ValidationError, LazyReferenceField, EmbeddedDocument) + + def test_lazy_reference_simple(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = LazyReferenceField(Animal) + + Animal.drop_collection() + Ocurrence.drop_collection() + + animal = Animal(name="Leopard", tag="heavy").save() + Ocurrence(person="test", animal=animal).save() + p = Ocurrence.objects.get() + self.assertIsInstance(p.animal, LazyReference) + fetched_animal = p.animal.fetch() + self.assertEqual(fetched_animal, animal) + # `fetch` keep cache on referenced document by default... + animal.tag = "not so heavy" + animal.save() + double_fetch = p.animal.fetch() + self.assertIs(fetched_animal, double_fetch) + self.assertEqual(double_fetch.tag, "heavy") + # ...unless specified otherwise + fetch_force = p.animal.fetch(force=True) + self.assertIsNot(fetch_force, fetched_animal) + self.assertEqual(fetch_force.tag, "not so heavy") + + def test_lazy_reference_fetch_invalid_ref(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = LazyReferenceField(Animal) + + Animal.drop_collection() + Ocurrence.drop_collection() + + animal = Animal(name="Leopard", tag="heavy").save() + Ocurrence(person="test", animal=animal).save() + animal.delete() + p = Ocurrence.objects.get() + self.assertIsInstance(p.animal, LazyReference) + with self.assertRaises(DoesNotExist): + p.animal.fetch() + + def test_lazy_reference_set(self): + class Animal(Document): + meta = {'allow_inheritance': True} + + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = LazyReferenceField(Animal) + + Animal.drop_collection() + Ocurrence.drop_collection() + + class SubAnimal(Animal): + nick = StringField() + + animal = Animal(name="Leopard", tag="heavy").save() + sub_animal = SubAnimal(nick='doggo', name='dog').save() + for ref in ( + animal, + animal.pk, + DBRef(animal._get_collection_name(), animal.pk), + LazyReference(Animal, animal.pk), + + sub_animal, + sub_animal.pk, + DBRef(sub_animal._get_collection_name(), sub_animal.pk), + LazyReference(SubAnimal, sub_animal.pk), + ): + p = Ocurrence(person="test", animal=ref).save() + p.reload() + self.assertIsInstance(p.animal, LazyReference) + p.animal.fetch() + + def test_lazy_reference_bad_set(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = LazyReferenceField(Animal) + + Animal.drop_collection() + Ocurrence.drop_collection() + + class BadDoc(Document): + pass + + animal = Animal(name="Leopard", tag="heavy").save() + baddoc = BadDoc().save() + for bad in ( + 42, + 'foo', + baddoc, + DBRef(baddoc._get_collection_name(), animal.pk), + LazyReference(BadDoc, animal.pk) + ): + with self.assertRaises(ValidationError): + p = Ocurrence(person="test", animal=bad).save() + + def test_lazy_reference_query_conversion(self): + """Ensure that LazyReferenceFields can be queried using objects and values + of the type of the primary key of the referenced object. + """ + class Member(Document): + user_num = IntField(primary_key=True) + + class BlogPost(Document): + title = StringField() + author = LazyReferenceField(Member, dbref=False) + + Member.drop_collection() + BlogPost.drop_collection() + + m1 = Member(user_num=1) + m1.save() + m2 = Member(user_num=2) + m2.save() + + post1 = BlogPost(title='post 1', author=m1) + post1.save() + + post2 = BlogPost(title='post 2', author=m2) + post2.save() + + post = BlogPost.objects(author=m1).first() + self.assertEqual(post.id, post1.id) + + post = BlogPost.objects(author=m2).first() + self.assertEqual(post.id, post2.id) + + # Same thing by passing a LazyReference instance + post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first() + self.assertEqual(post.id, post2.id) + + def test_lazy_reference_query_conversion_dbref(self): + """Ensure that LazyReferenceFields can be queried using objects and values + of the type of the primary key of the referenced object. + """ + class Member(Document): + user_num = IntField(primary_key=True) + + class BlogPost(Document): + title = StringField() + author = LazyReferenceField(Member, dbref=True) + + Member.drop_collection() + BlogPost.drop_collection() + + m1 = Member(user_num=1) + m1.save() + m2 = Member(user_num=2) + m2.save() + + post1 = BlogPost(title='post 1', author=m1) + post1.save() + + post2 = BlogPost(title='post 2', author=m2) + post2.save() + + post = BlogPost.objects(author=m1).first() + self.assertEqual(post.id, post1.id) + + post = BlogPost.objects(author=m2).first() + self.assertEqual(post.id, post2.id) + + # Same thing by passing a LazyReference instance + post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first() + self.assertEqual(post.id, post2.id) + + def test_lazy_reference_passthrough(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + animal = LazyReferenceField(Animal, passthrough=False) + animal_passthrough = LazyReferenceField(Animal, passthrough=True) + + Animal.drop_collection() + Ocurrence.drop_collection() + + animal = Animal(name="Leopard", tag="heavy").save() + Ocurrence(animal=animal, animal_passthrough=animal).save() + p = Ocurrence.objects.get() + self.assertIsInstance(p.animal, LazyReference) + with self.assertRaises(KeyError): + p.animal['name'] + with self.assertRaises(AttributeError): + p.animal.name + self.assertEqual(p.animal.pk, animal.pk) + + self.assertEqual(p.animal_passthrough.name, "Leopard") + self.assertEqual(p.animal_passthrough['name'], "Leopard") + + # Should not be able to access referenced document's methods + with self.assertRaises(AttributeError): + p.animal.save + with self.assertRaises(KeyError): + p.animal['save'] + + def test_lazy_reference_not_set(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = LazyReferenceField(Animal) + + Animal.drop_collection() + Ocurrence.drop_collection() + + Ocurrence(person='foo').save() + p = Ocurrence.objects.get() + self.assertIs(p.animal, None) + + def test_lazy_reference_equality(self): + class Animal(Document): + name = StringField() + tag = StringField() + + Animal.drop_collection() + + animal = Animal(name="Leopard", tag="heavy").save() + animalref = LazyReference(Animal, animal.pk) + self.assertEqual(animal, animalref) + self.assertEqual(animalref, animal) + + other_animalref = LazyReference(Animal, ObjectId("54495ad94c934721ede76f90")) + self.assertNotEqual(animal, other_animalref) + self.assertNotEqual(other_animalref, animal) + + def test_lazy_reference_embedded(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class EmbeddedOcurrence(EmbeddedDocument): + in_list = ListField(LazyReferenceField(Animal)) + direct = LazyReferenceField(Animal) + + class Ocurrence(Document): + in_list = ListField(LazyReferenceField(Animal)) + in_embedded = EmbeddedDocumentField(EmbeddedOcurrence) + direct = LazyReferenceField(Animal) + + Animal.drop_collection() + Ocurrence.drop_collection() + + animal1 = Animal('doggo').save() + animal2 = Animal('cheeta').save() + + def check_fields_type(occ): + self.assertIsInstance(occ.direct, LazyReference) + for elem in occ.in_list: + self.assertIsInstance(elem, LazyReference) + self.assertIsInstance(occ.in_embedded.direct, LazyReference) + for elem in occ.in_embedded.in_list: + self.assertIsInstance(elem, LazyReference) + + occ = Ocurrence( + in_list=[animal1, animal2], + in_embedded={'in_list': [animal1, animal2], 'direct': animal1}, + direct=animal1 + ).save() + check_fields_type(occ) + occ.reload() + check_fields_type(occ) + occ.direct = animal1.id + occ.in_list = [animal1.id, animal2.id] + occ.in_embedded.direct = animal1.id + occ.in_embedded.in_list = [animal1.id, animal2.id] + check_fields_type(occ) + + +class TestGenericLazyReferenceField(MongoDBTestCase): + def test_generic_lazy_reference_simple(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = GenericLazyReferenceField() + + Animal.drop_collection() + Ocurrence.drop_collection() + + animal = Animal(name="Leopard", tag="heavy").save() + Ocurrence(person="test", animal=animal).save() + p = Ocurrence.objects.get() + self.assertIsInstance(p.animal, LazyReference) + fetched_animal = p.animal.fetch() + self.assertEqual(fetched_animal, animal) + # `fetch` keep cache on referenced document by default... + animal.tag = "not so heavy" + animal.save() + double_fetch = p.animal.fetch() + self.assertIs(fetched_animal, double_fetch) + self.assertEqual(double_fetch.tag, "heavy") + # ...unless specified otherwise + fetch_force = p.animal.fetch(force=True) + self.assertIsNot(fetch_force, fetched_animal) + self.assertEqual(fetch_force.tag, "not so heavy") + + def test_generic_lazy_reference_choices(self): + class Animal(Document): + name = StringField() + + class Vegetal(Document): + name = StringField() + + class Mineral(Document): + name = StringField() + + class Ocurrence(Document): + living_thing = GenericLazyReferenceField(choices=[Animal, Vegetal]) + thing = GenericLazyReferenceField() + + Animal.drop_collection() + Vegetal.drop_collection() + Mineral.drop_collection() + Ocurrence.drop_collection() + + animal = Animal(name="Leopard").save() + vegetal = Vegetal(name="Oak").save() + mineral = Mineral(name="Granite").save() + + occ_animal = Ocurrence(living_thing=animal, thing=animal).save() + occ_vegetal = Ocurrence(living_thing=vegetal, thing=vegetal).save() + with self.assertRaises(ValidationError): + Ocurrence(living_thing=mineral).save() + + occ = Ocurrence.objects.get(living_thing=animal) + self.assertEqual(occ, occ_animal) + self.assertIsInstance(occ.thing, LazyReference) + self.assertIsInstance(occ.living_thing, LazyReference) + + occ.thing = vegetal + occ.living_thing = vegetal + occ.save() + + occ.thing = mineral + occ.living_thing = mineral + with self.assertRaises(ValidationError): + occ.save() + + def test_generic_lazy_reference_set(self): + class Animal(Document): + meta = {'allow_inheritance': True} + + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = GenericLazyReferenceField() + + Animal.drop_collection() + Ocurrence.drop_collection() + + class SubAnimal(Animal): + nick = StringField() + + animal = Animal(name="Leopard", tag="heavy").save() + sub_animal = SubAnimal(nick='doggo', name='dog').save() + for ref in ( + animal, + LazyReference(Animal, animal.pk), + {'_cls': 'Animal', '_ref': DBRef(animal._get_collection_name(), animal.pk)}, + + sub_animal, + LazyReference(SubAnimal, sub_animal.pk), + {'_cls': 'SubAnimal', '_ref': DBRef(sub_animal._get_collection_name(), sub_animal.pk)}, + ): + p = Ocurrence(person="test", animal=ref).save() + p.reload() + self.assertIsInstance(p.animal, (LazyReference, Document)) + p.animal.fetch() + + def test_generic_lazy_reference_bad_set(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = GenericLazyReferenceField(choices=['Animal']) + + Animal.drop_collection() + Ocurrence.drop_collection() + + class BadDoc(Document): + pass + + animal = Animal(name="Leopard", tag="heavy").save() + baddoc = BadDoc().save() + for bad in ( + 42, + 'foo', + baddoc, + LazyReference(BadDoc, animal.pk) + ): + with self.assertRaises(ValidationError): + p = Ocurrence(person="test", animal=bad).save() + + def test_generic_lazy_reference_query_conversion(self): + class Member(Document): + user_num = IntField(primary_key=True) + + class BlogPost(Document): + title = StringField() + author = GenericLazyReferenceField() + + Member.drop_collection() + BlogPost.drop_collection() + + m1 = Member(user_num=1) + m1.save() + m2 = Member(user_num=2) + m2.save() + + post1 = BlogPost(title='post 1', author=m1) + post1.save() + + post2 = BlogPost(title='post 2', author=m2) + post2.save() + + post = BlogPost.objects(author=m1).first() + self.assertEqual(post.id, post1.id) + + post = BlogPost.objects(author=m2).first() + self.assertEqual(post.id, post2.id) + + # Same thing by passing a LazyReference instance + post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first() + self.assertEqual(post.id, post2.id) + + def test_generic_lazy_reference_not_set(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class Ocurrence(Document): + person = StringField() + animal = GenericLazyReferenceField() + + Animal.drop_collection() + Ocurrence.drop_collection() + + Ocurrence(person='foo').save() + p = Ocurrence.objects.get() + self.assertIs(p.animal, None) + + def test_generic_lazy_reference_embedded(self): + class Animal(Document): + name = StringField() + tag = StringField() + + class EmbeddedOcurrence(EmbeddedDocument): + in_list = ListField(GenericLazyReferenceField()) + direct = GenericLazyReferenceField() + + class Ocurrence(Document): + in_list = ListField(GenericLazyReferenceField()) + in_embedded = EmbeddedDocumentField(EmbeddedOcurrence) + direct = GenericLazyReferenceField() + + Animal.drop_collection() + Ocurrence.drop_collection() + + animal1 = Animal('doggo').save() + animal2 = Animal('cheeta').save() + + def check_fields_type(occ): + self.assertIsInstance(occ.direct, LazyReference) + for elem in occ.in_list: + self.assertIsInstance(elem, LazyReference) + self.assertIsInstance(occ.in_embedded.direct, LazyReference) + for elem in occ.in_embedded.in_list: + self.assertIsInstance(elem, LazyReference) + + occ = Ocurrence( + in_list=[animal1, animal2], + in_embedded={'in_list': [animal1, animal2], 'direct': animal1}, + direct=animal1 + ).save() + check_fields_type(occ) + occ.reload() + check_fields_type(occ) + animal1_ref = {'_cls': 'Animal', '_ref': DBRef(animal1._get_collection_name(), animal1.pk)} + animal2_ref = {'_cls': 'Animal', '_ref': DBRef(animal2._get_collection_name(), animal2.pk)} + occ.direct = animal1_ref + occ.in_list = [animal1_ref, animal2_ref] + occ.in_embedded.direct = animal1_ref + occ.in_embedded.in_list = [animal1_ref, animal2_ref] + check_fields_type(occ) diff --git a/tests/fields/test_long_field.py b/tests/fields/test_long_field.py new file mode 100644 index 00000000..4ab7403d --- /dev/null +++ b/tests/fields/test_long_field.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +import six + +try: + from bson.int64 import Int64 +except ImportError: + Int64 = long + +from mongoengine import * +from mongoengine.connection import get_db + +from tests.utils import MongoDBTestCase + + +class TestLongField(MongoDBTestCase): + + def test_long_field_is_considered_as_int64(self): + """ + Tests that long fields are stored as long in mongo, even if long + value is small enough to be an int. + """ + class TestLongFieldConsideredAsInt64(Document): + some_long = LongField() + + doc = TestLongFieldConsideredAsInt64(some_long=42).save() + db = get_db() + self.assertIsInstance(db.test_long_field_considered_as_int64.find()[0]['some_long'], Int64) + self.assertIsInstance(doc.some_long, six.integer_types) + + def test_long_validation(self): + """Ensure that invalid values cannot be assigned to long fields. + """ + class TestDocument(Document): + value = LongField(min_value=0, max_value=110) + + doc = TestDocument() + doc.value = 50 + doc.validate() + + doc.value = -1 + self.assertRaises(ValidationError, doc.validate) + doc.age = 120 + self.assertRaises(ValidationError, doc.validate) + doc.age = 'ten' + self.assertRaises(ValidationError, doc.validate) + + def test_long_ne_operator(self): + class TestDocument(Document): + long_fld = LongField() + + TestDocument.drop_collection() + + TestDocument(long_fld=None).save() + TestDocument(long_fld=1).save() + + self.assertEqual(1, TestDocument.objects(long_fld__ne=None).count()) diff --git a/tests/fields/test_url_field.py b/tests/fields/test_url_field.py new file mode 100644 index 00000000..0447799e --- /dev/null +++ b/tests/fields/test_url_field.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +from mongoengine import * + +from tests.utils import MongoDBTestCase + + +class TestFloatField(MongoDBTestCase): + + def test_validation(self): + """Ensure that URLFields validate urls properly.""" + class Link(Document): + url = URLField() + + link = Link() + link.url = 'google' + self.assertRaises(ValidationError, link.validate) + + link.url = 'http://www.google.com:8080' + link.validate() + + def test_unicode_url_validation(self): + """Ensure unicode URLs are validated properly.""" + class Link(Document): + url = URLField() + + link = Link() + link.url = u'http://привет.com' + + # TODO fix URL validation - this *IS* a valid URL + # For now we just want to make sure that the error message is correct + with self.assertRaises(ValidationError) as ctx_err: + link.validate() + self.assertEqual(unicode(ctx_err.exception), + u"ValidationError (Link:None) (Invalid URL: http://\u043f\u0440\u0438\u0432\u0435\u0442.com: ['url'])") + + def test_url_scheme_validation(self): + """Ensure that URLFields validate urls with specific schemes properly. + """ + class Link(Document): + url = URLField() + + class SchemeLink(Document): + url = URLField(schemes=['ws', 'irc']) + + link = Link() + link.url = 'ws://google.com' + self.assertRaises(ValidationError, link.validate) + + scheme_link = SchemeLink() + scheme_link.url = 'ws://google.com' + scheme_link.validate() + + def test_underscore_allowed_in_domains_names(self): + class Link(Document): + url = URLField() + + link = Link() + link.url = 'https://san_leandro-ca.geebo.com' + link.validate()