diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/__init__.py | 1 | ||||
-rw-r--r-- | tests/compat.py | 27 | ||||
-rw-r--r-- | tests/cyclic/__init__.py | 0 | ||||
-rw-r--r-- | tests/cyclic/bar.py | 37 | ||||
-rw-r--r-- | tests/cyclic/foo.py | 38 | ||||
-rw-r--r-- | tests/test_base.py | 88 | ||||
-rw-r--r-- | tests/test_containers.py | 33 | ||||
-rw-r--r-- | tests/test_declarations.py | 52 | ||||
-rw-r--r-- | tests/test_using.py | 508 | ||||
-rw-r--r-- | tests/test_utils.py | 232 |
10 files changed, 949 insertions, 67 deletions
diff --git a/tests/__init__.py b/tests/__init__.py index 7ab3567..80a96a4 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -5,3 +5,4 @@ from .test_base import * from .test_containers import * from .test_declarations import * from .test_using import * +from .test_utils import * diff --git a/tests/compat.py b/tests/compat.py new file mode 100644 index 0000000..15fa3ae --- /dev/null +++ b/tests/compat.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2011 Raphaël Barrois +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +"""Compatibility tools for tests""" + +try: + import unittest2 as unittest +except ImportError: + import unittest diff --git a/tests/cyclic/__init__.py b/tests/cyclic/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/cyclic/__init__.py diff --git a/tests/cyclic/bar.py b/tests/cyclic/bar.py new file mode 100644 index 0000000..cc90930 --- /dev/null +++ b/tests/cyclic/bar.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2011-2012 Raphaël Barrois +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +"""Helper to test circular factory dependencies.""" + +import factory + +class Bar(object): + def __init__(self, foo, y): + self.foo = foo + self.y = y + + +class BarFactory(factory.Factory): + FACTORY_FOR = Bar + + y = 13 + foo = factory.CircularSubFactory('cyclic.foo', 'FooFactory') + diff --git a/tests/cyclic/foo.py b/tests/cyclic/foo.py new file mode 100644 index 0000000..e6f8896 --- /dev/null +++ b/tests/cyclic/foo.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2011-2012 Raphaël Barrois +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +"""Helper to test circular factory dependencies.""" + +import factory + +from cyclic import bar + +class Foo(object): + def __init__(self, bar, x): + self.bar = bar + self.x = x + + +class FooFactory(factory.Factory): + FACTORY_FOR = Foo + + x = 42 + bar = factory.SubFactory(bar.BarFactory) diff --git a/tests/test_base.py b/tests/test_base.py index 8da655e..7ec3d0e 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -20,12 +20,13 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -import unittest import warnings from factory import base from factory import declarations +from .compat import unittest + class TestObject(object): def __init__(self, one=None, two=None, three=None, four=None): self.one = one @@ -34,19 +35,25 @@ class TestObject(object): self.four = four class FakeDjangoModel(object): - class FakeDjangoManager(object): - def create(self, **kwargs): - fake_model = FakeDjangoModel(**kwargs) - fake_model.id = 1 - return fake_model - - objects = FakeDjangoManager() + @classmethod + def create(cls, **kwargs): + instance = cls(**kwargs) + instance.id = 1 + return instance def __init__(self, **kwargs): for name, value in kwargs.iteritems(): setattr(self, name, value) self.id = None +class FakeModelFactory(base.Factory): + ABSTRACT_FACTORY = True + + @classmethod + def _create(cls, target_class, *args, **kwargs): + return target_class.create(**kwargs) + + class TestModel(FakeDjangoModel): pass @@ -66,6 +73,8 @@ class FactoryTestCase(unittest.TestCase): def testLazyAttributeNonExistentParam(self): class TestObjectFactory(base.Factory): + FACTORY_FOR = TestObject + one = declarations.LazyAttribute(lambda a: a.does_not_exist ) self.assertRaises(AttributeError, TestObjectFactory) @@ -73,9 +82,13 @@ class FactoryTestCase(unittest.TestCase): def testInheritanceWithSequence(self): """Tests that sequence IDs are shared between parent and son.""" class TestObjectFactory(base.Factory): + FACTORY_FOR = TestObject + one = declarations.Sequence(lambda a: a) class TestSubFactory(TestObjectFactory): + FACTORY_FOR = TestObject + pass parent = TestObjectFactory.build() @@ -96,6 +109,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): base.Factory.default_strategy = base.BUILD_STRATEGY class TestModelFactory(base.Factory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory() @@ -105,7 +120,9 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): def testCreateStrategy(self): # Default default_strategy - class TestModelFactory(base.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory() @@ -116,6 +133,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): base.Factory.default_strategy = base.STUB_STRATEGY class TestModelFactory(base.Factory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory() @@ -126,12 +145,16 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): base.Factory.default_strategy = 'unknown' class TestModelFactory(base.Factory): + FACTORY_FOR = TestModel + one = 'one' self.assertRaises(base.Factory.UnknownStrategy, TestModelFactory) def testStubWithNonStubStrategy(self): class TestModelFactory(base.StubFactory): + FACTORY_FOR = TestModel + one = 'one' TestModelFactory.default_strategy = base.CREATE_STRATEGY @@ -141,6 +164,16 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): TestModelFactory.default_strategy = base.BUILD_STRATEGY self.assertRaises(base.StubFactory.UnsupportedStrategy, TestModelFactory) + def test_change_strategy(self): + @base.use_strategy(base.CREATE_STRATEGY) + class TestModelFactory(base.StubFactory): + FACTORY_FOR = TestModel + + one = 'one' + + self.assertEqual(base.CREATE_STRATEGY, TestModelFactory.default_strategy) + + class FactoryCreationTestCase(unittest.TestCase): def testFactoryFor(self): class TestFactory(base.Factory): @@ -149,8 +182,10 @@ class FactoryCreationTestCase(unittest.TestCase): self.assertTrue(isinstance(TestFactory.build(), TestObject)) def testAutomaticAssociatedClassDiscovery(self): - class TestObjectFactory(base.Factory): - pass + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + class TestObjectFactory(base.Factory): + pass self.assertTrue(isinstance(TestObjectFactory.build(), TestObject)) @@ -159,8 +194,7 @@ class FactoryCreationTestCase(unittest.TestCase): with warnings.catch_warnings(record=True) as w: # Clear the warning registry. - if hasattr(base, '__warningregistry__'): - base.__warningregistry__.clear() + __warningregistry__.clear() warnings.simplefilter('always') class TestObjectFactory(base.Factory): @@ -177,6 +211,8 @@ class FactoryCreationTestCase(unittest.TestCase): def testInheritanceWithStub(self): class TestObjectFactory(base.StubFactory): + FACTORY_FOR = TestObject + pass class TestFactory(TestObjectFactory): @@ -185,7 +221,9 @@ class FactoryCreationTestCase(unittest.TestCase): self.assertEqual(TestFactory.default_strategy, base.STUB_STRATEGY) def testCustomCreation(self): - class TestModelFactory(base.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + @classmethod def _prepare(cls, create, **kwargs): kwargs['four'] = 4 @@ -220,5 +258,27 @@ class FactoryCreationTestCase(unittest.TestCase): self.assertTrue('autodiscovery' not in str(e)) +class PostGenerationParsingTestCase(unittest.TestCase): + + def test_extraction(self): + class TestObjectFactory(base.Factory): + FACTORY_FOR = TestObject + + foo = declarations.PostGenerationDeclaration() + + self.assertIn('foo', TestObjectFactory._postgen_declarations) + + def test_classlevel_extraction(self): + class TestObjectFactory(base.Factory): + FACTORY_FOR = TestObject + + foo = declarations.PostGenerationDeclaration() + foo__bar = 42 + + self.assertIn('foo', TestObjectFactory._postgen_declarations) + self.assertIn('foo__bar', TestObjectFactory._declarations) + + + if __name__ == '__main__': unittest.main() diff --git a/tests/test_containers.py b/tests/test_containers.py index 6e58573..b1ed6ed 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -20,12 +20,12 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -import unittest - from factory import base from factory import containers from factory import declarations +from .compat import unittest + class LazyStubTestCase(unittest.TestCase): def test_basic(self): stub = containers.LazyStub({'one': 1, 'two': 2}) @@ -178,6 +178,17 @@ class DeclarationDictTestCase(unittest.TestCase): self.assertEqual(set(['one', 'three']), set(d)) self.assertEqual(set([1, 3]), set(d.values())) + def test_update_with_public_ignores_factory_attributes(self): + """Ensure that a DeclarationDict ignores FACTORY_ keys.""" + d = containers.DeclarationDict() + d.update_with_public({ + 'one': 1, + 'FACTORY_FOR': 2, + 'FACTORY_ARG_PARAMETERS': 3, + }) + self.assertEqual(['one'], list(d)) + self.assertEqual([1], list(d.values())) + class AttributeBuilderTestCase(unittest.TestCase): def test_empty(self): @@ -316,6 +327,24 @@ class AttributeBuilderTestCase(unittest.TestCase): ab = containers.AttributeBuilder(FakeFactory, {'one': 4, 'three': la}) self.assertEqual({'one': 4, 'two': 8, 'three': 8}, ab.build(create=False)) + def test_subfields(self): + class FakeInnerFactory(object): + pass + + sf = declarations.SubFactory(FakeInnerFactory) + + class FakeFactory(object): + @classmethod + def declarations(cls, extra): + d = {'one': sf, 'two': 2} + d.update(extra) + return d + + ab = containers.AttributeBuilder(FakeFactory, {'one__blah': 1, 'two__bar': 2}) + self.assertTrue(ab.has_subfields(sf)) + self.assertEqual(['one'], ab._subfields.keys()) + self.assertEqual(2, ab._attrs['two__bar']) + def test_sub_factory(self): pass diff --git a/tests/test_declarations.py b/tests/test_declarations.py index 7215a54..c0b3539 100644 --- a/tests/test_declarations.py +++ b/tests/test_declarations.py @@ -20,9 +20,12 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -import unittest +import datetime -from factory.declarations import deepgetattr, OrderedDeclaration, Sequence +from factory.declarations import deepgetattr, CircularSubFactory, OrderedDeclaration, \ + PostGenerationDeclaration, Sequence + +from .compat import unittest class OrderedDeclarationTestCase(unittest.TestCase): def test_errors(self): @@ -54,6 +57,51 @@ class DigTestCase(unittest.TestCase): self.assertEqual(42, deepgetattr(obj, 'a.b.c.n.x', 42)) +class PostGenerationDeclarationTestCase(unittest.TestCase): + def test_extract_no_prefix(self): + decl = PostGenerationDeclaration() + + extracted, kwargs = decl.extract('foo', {'foo': 13, 'foo__bar': 42}) + self.assertEqual(extracted, 13) + self.assertEqual(kwargs, {'bar': 42}) + + def test_extract_with_prefix(self): + decl = PostGenerationDeclaration(extract_prefix='blah') + + extracted, kwargs = decl.extract('foo', + {'foo': 13, 'foo__bar': 42, 'blah': 42, 'blah__baz': 1}) + self.assertEqual(extracted, 42) + self.assertEqual(kwargs, {'baz': 1}) + + +class CircularSubFactoryTestCase(unittest.TestCase): + def test_lazyness(self): + f = CircularSubFactory('factory.declarations', 'Sequence', x=3) + self.assertEqual(None, f.factory) + + self.assertEqual({'x': 3}, f.defaults) + + factory_class = f.get_factory() + self.assertEqual(Sequence, factory_class) + + def test_cache(self): + orig_date = datetime.date + f = CircularSubFactory('datetime', 'date') + self.assertEqual(None, f.factory) + + factory_class = f.get_factory() + self.assertEqual(orig_date, factory_class) + + try: + # Modify original value + datetime.date = None + # Repeat import + factory_class = f.get_factory() + self.assertEqual(orig_date, factory_class) + + finally: + # IMPORTANT: restore attribute. + datetime.date = orig_date if __name__ == '__main__': unittest.main() diff --git a/tests/test_using.py b/tests/test_using.py index 7f9f09c..7e141eb 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -20,10 +20,15 @@ # THE SOFTWARE. """Tests using factory.""" -import unittest + +import functools +import os +import sys +import warnings import factory +from .compat import unittest class TestObject(object): @@ -34,24 +39,49 @@ class TestObject(object): self.four = four self.five = five -class FakeDjangoModel(object): - class FakeDjangoManager(object): + +class FakeModel(object): + @classmethod + def create(cls, **kwargs): + instance = cls(**kwargs) + instance.id = 1 + return instance + + class FakeModelManager(object): def create(self, **kwargs): - fake_model = FakeDjangoModel(**kwargs) - fake_model.id = 1 - return fake_model + instance = FakeModel.create(**kwargs) + instance.id = 2 + return instance - objects = FakeDjangoManager() + objects = FakeModelManager() def __init__(self, **kwargs): for name, value in kwargs.iteritems(): setattr(self, name, value) self.id = None -class TestModel(FakeDjangoModel): + +class FakeModelFactory(factory.Factory): + ABSTRACT_FACTORY = True + + @classmethod + def _create(cls, target_class, *args, **kwargs): + return target_class.create(**kwargs) + + +class TestModel(FakeModel): pass +def disable_warnings(fun): + @functools.wraps(fun) + def decorated(*args, **kwargs): + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + return fun(*args, **kwargs) + return decorated + + class SimpleBuildTestCase(unittest.TestCase): """Tests the minimalist 'factory.build/create' functions.""" @@ -82,19 +112,21 @@ class SimpleBuildTestCase(unittest.TestCase): self.assertEqual(obj.three, 3) self.assertEqual(obj.four, None) + @disable_warnings def test_create(self): - obj = factory.create(FakeDjangoModel, foo='bar') - self.assertEqual(obj.id, 1) + obj = factory.create(FakeModel, foo='bar') + self.assertEqual(obj.id, 2) self.assertEqual(obj.foo, 'bar') + @disable_warnings def test_create_batch(self): - objs = factory.create_batch(FakeDjangoModel, 4, foo='bar') + objs = factory.create_batch(FakeModel, 4, foo='bar') self.assertEqual(4, len(objs)) self.assertEqual(4, len(set(objs))) for obj in objs: - self.assertEqual(obj.id, 1) + self.assertEqual(obj.id, 2) self.assertEqual(obj.foo, 'bar') def test_stub(self): @@ -103,7 +135,7 @@ class SimpleBuildTestCase(unittest.TestCase): self.assertFalse(hasattr(obj, 'two')) def test_stub_batch(self): - objs = factory.stub_batch(FakeDjangoModel, 4, foo='bar') + objs = factory.stub_batch(FakeModel, 4, foo='bar') self.assertEqual(4, len(objs)) self.assertEqual(4, len(set(objs))) @@ -113,22 +145,23 @@ class SimpleBuildTestCase(unittest.TestCase): self.assertEqual(obj.foo, 'bar') def test_generate_build(self): - obj = factory.generate(FakeDjangoModel, factory.BUILD_STRATEGY, foo='bar') + obj = factory.generate(FakeModel, factory.BUILD_STRATEGY, foo='bar') self.assertEqual(obj.id, None) self.assertEqual(obj.foo, 'bar') + @disable_warnings def test_generate_create(self): - obj = factory.generate(FakeDjangoModel, factory.CREATE_STRATEGY, foo='bar') - self.assertEqual(obj.id, 1) + obj = factory.generate(FakeModel, factory.CREATE_STRATEGY, foo='bar') + self.assertEqual(obj.id, 2) self.assertEqual(obj.foo, 'bar') def test_generate_stub(self): - obj = factory.generate(FakeDjangoModel, factory.STUB_STRATEGY, foo='bar') + obj = factory.generate(FakeModel, factory.STUB_STRATEGY, foo='bar') self.assertFalse(hasattr(obj, 'id')) self.assertEqual(obj.foo, 'bar') def test_generate_batch_build(self): - objs = factory.generate_batch(FakeDjangoModel, factory.BUILD_STRATEGY, 20, foo='bar') + objs = factory.generate_batch(FakeModel, factory.BUILD_STRATEGY, 20, foo='bar') self.assertEqual(20, len(objs)) self.assertEqual(20, len(set(objs))) @@ -137,18 +170,19 @@ class SimpleBuildTestCase(unittest.TestCase): self.assertEqual(obj.id, None) self.assertEqual(obj.foo, 'bar') + @disable_warnings def test_generate_batch_create(self): - objs = factory.generate_batch(FakeDjangoModel, factory.CREATE_STRATEGY, 20, foo='bar') + objs = factory.generate_batch(FakeModel, factory.CREATE_STRATEGY, 20, foo='bar') self.assertEqual(20, len(objs)) self.assertEqual(20, len(set(objs))) for obj in objs: - self.assertEqual(obj.id, 1) + self.assertEqual(obj.id, 2) self.assertEqual(obj.foo, 'bar') def test_generate_batch_stub(self): - objs = factory.generate_batch(FakeDjangoModel, factory.STUB_STRATEGY, 20, foo='bar') + objs = factory.generate_batch(FakeModel, factory.STUB_STRATEGY, 20, foo='bar') self.assertEqual(20, len(objs)) self.assertEqual(20, len(set(objs))) @@ -158,17 +192,18 @@ class SimpleBuildTestCase(unittest.TestCase): self.assertEqual(obj.foo, 'bar') def test_simple_generate_build(self): - obj = factory.simple_generate(FakeDjangoModel, False, foo='bar') + obj = factory.simple_generate(FakeModel, False, foo='bar') self.assertEqual(obj.id, None) self.assertEqual(obj.foo, 'bar') + @disable_warnings def test_simple_generate_create(self): - obj = factory.simple_generate(FakeDjangoModel, True, foo='bar') - self.assertEqual(obj.id, 1) + obj = factory.simple_generate(FakeModel, True, foo='bar') + self.assertEqual(obj.id, 2) self.assertEqual(obj.foo, 'bar') def test_simple_generate_batch_build(self): - objs = factory.simple_generate_batch(FakeDjangoModel, False, 20, foo='bar') + objs = factory.simple_generate_batch(FakeModel, False, 20, foo='bar') self.assertEqual(20, len(objs)) self.assertEqual(20, len(set(objs))) @@ -177,14 +212,15 @@ class SimpleBuildTestCase(unittest.TestCase): self.assertEqual(obj.id, None) self.assertEqual(obj.foo, 'bar') + @disable_warnings def test_simple_generate_batch_create(self): - objs = factory.simple_generate_batch(FakeDjangoModel, True, 20, foo='bar') + objs = factory.simple_generate_batch(FakeModel, True, 20, foo='bar') self.assertEqual(20, len(objs)) self.assertEqual(20, len(set(objs))) for obj in objs: - self.assertEqual(obj.id, 1) + self.assertEqual(obj.id, 2) self.assertEqual(obj.foo, 'bar') def test_make_factory(self): @@ -203,16 +239,31 @@ class SimpleBuildTestCase(unittest.TestCase): self.assertEqual(obj.four, None) -class FactoryTestCase(unittest.TestCase): +class UsingFactoryTestCase(unittest.TestCase): def testAttribute(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 'one' test_object = TestObjectFactory.build() self.assertEqual(test_object.one, 'one') + def test_abstract(self): + class SomeAbstractFactory(factory.Factory): + ABSTRACT_FACTORY = True + one = 'one' + + class InheritedFactory(SomeAbstractFactory): + FACTORY_FOR = TestObject + + test_object = InheritedFactory.build() + self.assertEqual(test_object.one, 'one') + def testSequence(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.Sequence(lambda n: 'one' + n) two = factory.Sequence(lambda n: 'two' + n) @@ -226,6 +277,8 @@ class FactoryTestCase(unittest.TestCase): def testSequenceCustomBegin(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @classmethod def _setup_next_sequence(cls): return 42 @@ -243,6 +296,8 @@ class FactoryTestCase(unittest.TestCase): def test_sequence_batch(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.Sequence(lambda n: 'one' + n) two = factory.Sequence(lambda n: 'two' + n) @@ -256,6 +311,8 @@ class FactoryTestCase(unittest.TestCase): def testLazyAttribute(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.LazyAttribute(lambda a: 'abc' ) two = factory.LazyAttribute(lambda a: a.one + ' xyz') @@ -265,6 +322,8 @@ class FactoryTestCase(unittest.TestCase): def testLazyAttributeSequence(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.LazyAttributeSequence(lambda a, n: 'abc' + n) two = factory.LazyAttributeSequence(lambda a, n: a.one + ' xyz' + n) @@ -278,6 +337,8 @@ class FactoryTestCase(unittest.TestCase): def testLazyAttributeDecorator(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @factory.lazy_attribute def one(a): return 'one' @@ -290,6 +351,8 @@ class FactoryTestCase(unittest.TestCase): n = 3 class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 'xx' two = factory.SelfAttribute('one') three = TmpObj() @@ -304,6 +367,8 @@ class FactoryTestCase(unittest.TestCase): def testSequenceDecorator(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @factory.sequence def one(n): return 'one' + n @@ -313,6 +378,8 @@ class FactoryTestCase(unittest.TestCase): def testLazyAttributeSequenceDecorator(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @factory.lazy_attribute_sequence def one(a, n): return 'one' + n @@ -326,6 +393,8 @@ class FactoryTestCase(unittest.TestCase): def testBuildWithParameters(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.Sequence(lambda n: 'one' + n) two = factory.Sequence(lambda n: 'two' + n) @@ -339,7 +408,9 @@ class FactoryTestCase(unittest.TestCase): self.assertEqual(test_object1.two, 'two1') def testCreate(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory.create() @@ -347,7 +418,9 @@ class FactoryTestCase(unittest.TestCase): self.assertTrue(test_model.id) def test_create_batch(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' objs = TestModelFactory.create_batch(20, two=factory.Sequence(int)) @@ -361,7 +434,9 @@ class FactoryTestCase(unittest.TestCase): self.assertTrue(obj.id) def test_generate_build(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory.generate(factory.BUILD_STRATEGY) @@ -369,7 +444,9 @@ class FactoryTestCase(unittest.TestCase): self.assertFalse(test_model.id) def test_generate_create(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory.generate(factory.CREATE_STRATEGY) @@ -377,7 +454,9 @@ class FactoryTestCase(unittest.TestCase): self.assertTrue(test_model.id) def test_generate_stub(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory.generate(factory.STUB_STRATEGY) @@ -385,7 +464,9 @@ class FactoryTestCase(unittest.TestCase): self.assertFalse(hasattr(test_model, 'id')) def test_generate_batch_build(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' objs = TestModelFactory.generate_batch(factory.BUILD_STRATEGY, 20, two='two') @@ -399,7 +480,9 @@ class FactoryTestCase(unittest.TestCase): self.assertFalse(obj.id) def test_generate_batch_create(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' objs = TestModelFactory.generate_batch(factory.CREATE_STRATEGY, 20, two='two') @@ -413,7 +496,9 @@ class FactoryTestCase(unittest.TestCase): self.assertTrue(obj.id) def test_generate_batch_stub(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' objs = TestModelFactory.generate_batch(factory.STUB_STRATEGY, 20, two='two') @@ -427,7 +512,9 @@ class FactoryTestCase(unittest.TestCase): self.assertFalse(hasattr(obj, 'id')) def test_simple_generate_build(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory.simple_generate(False) @@ -435,7 +522,9 @@ class FactoryTestCase(unittest.TestCase): self.assertFalse(test_model.id) def test_simple_generate_create(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' test_model = TestModelFactory.simple_generate(True) @@ -443,7 +532,9 @@ class FactoryTestCase(unittest.TestCase): self.assertTrue(test_model.id) def test_simple_generate_batch_build(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' objs = TestModelFactory.simple_generate_batch(False, 20, two='two') @@ -457,7 +548,9 @@ class FactoryTestCase(unittest.TestCase): self.assertFalse(obj.id) def test_simple_generate_batch_create(self): - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 'one' objs = TestModelFactory.simple_generate_batch(True, 20, two='two') @@ -472,6 +565,8 @@ class FactoryTestCase(unittest.TestCase): def test_stub_batch(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') three = factory.Sequence(lambda n: int(n)) @@ -489,6 +584,8 @@ class FactoryTestCase(unittest.TestCase): def testInheritance(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -509,6 +606,8 @@ class FactoryTestCase(unittest.TestCase): def testInheritanceWithInheritedClass(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -524,6 +623,8 @@ class FactoryTestCase(unittest.TestCase): def testDualInheritance(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 'one' class TestOtherFactory(factory.Factory): @@ -540,12 +641,13 @@ class FactoryTestCase(unittest.TestCase): self.assertEqual('three', obj.three) self.assertEqual('four', obj.four) + @disable_warnings def testSetCreationFunction(self): def creation_function(class_to_create, **kwargs): return "This doesn't even return an instance of {0}".format(class_to_create.__name__) - class TestModelFactory(factory.Factory): - pass + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel TestModelFactory.set_creation_function(creation_function) @@ -554,6 +656,8 @@ class FactoryTestCase(unittest.TestCase): def testClassMethodAccessible(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @classmethod def alt_create(cls, **kwargs): return kwargs @@ -562,6 +666,8 @@ class FactoryTestCase(unittest.TestCase): def testStaticMethodAccessible(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @staticmethod def alt_create(**kwargs): return kwargs @@ -569,16 +675,65 @@ class FactoryTestCase(unittest.TestCase): self.assertEqual(TestObjectFactory.alt_create(foo=1), {"foo": 1}) +class NonKwargParametersTestCase(unittest.TestCase): + def test_build(self): + class TestObject(object): + def __init__(self, *args, **kwargs): + self.args = args + self.kwargs = kwargs + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + FACTORY_ARG_PARAMETERS = ('one', 'two',) + + one = 1 + two = 2 + three = 3 + + obj = TestObjectFactory.build() + self.assertEqual((1, 2), obj.args) + self.assertEqual({'three': 3}, obj.kwargs) + + def test_create(self): + class TestObject(object): + def __init__(self, *args, **kwargs): + self.args = None + self.kwargs = None + + @classmethod + def create(cls, *args, **kwargs): + inst = cls() + inst.args = args + inst.kwargs = kwargs + return inst + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + FACTORY_ARG_PARAMETERS = ('one', 'two') + + one = 1 + two = 2 + three = 3 + + @classmethod + def _create(cls, target_class, *args, **kwargs): + return target_class.create(*args, **kwargs) + + obj = TestObjectFactory.create() + self.assertEqual((1, 2), obj.args) + self.assertEqual({'three': 3}, obj.kwargs) + + class SubFactoryTestCase(unittest.TestCase): def testSubFactory(self): - class TestModel2(FakeDjangoModel): + class TestModel2(FakeModel): pass - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): FACTORY_FOR = TestModel one = 3 - class TestModel2Factory(factory.Factory): + class TestModel2Factory(FakeModelFactory): FACTORY_FOR = TestModel2 two = factory.SubFactory(TestModelFactory, one=1) @@ -588,13 +743,13 @@ class SubFactoryTestCase(unittest.TestCase): self.assertEqual(1, test_model.two.id) def testSubFactoryWithLazyFields(self): - class TestModel2(FakeDjangoModel): + class TestModel2(FakeModel): pass - class TestModelFactory(factory.Factory): + class TestModelFactory(FakeModelFactory): FACTORY_FOR = TestModel - class TestModel2Factory(factory.Factory): + class TestModel2Factory(FakeModelFactory): FACTORY_FOR = TestModel2 two = factory.SubFactory(TestModelFactory, one=factory.Sequence(lambda n: 'x%sx' % n), @@ -605,7 +760,7 @@ class SubFactoryTestCase(unittest.TestCase): self.assertEqual('x0x', test_model.two.one) self.assertEqual('x0xx0x', test_model.two.two) - def testSubFactoryOverriding(self): + def testSubFactoryAndSequence(self): class TestObject(object): def __init__(self, **kwargs): for k, v in kwargs.iteritems(): @@ -614,9 +769,36 @@ class SubFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): FACTORY_FOR = TestObject + one = factory.Sequence(lambda n: int(n)) + class WrappingTestObjectFactory(factory.Factory): FACTORY_FOR = TestObject + wrapped = factory.SubFactory(TestObjectFactory) + + wrapping = WrappingTestObjectFactory.build() + self.assertEqual(0, wrapping.wrapped.one) + wrapping = WrappingTestObjectFactory.build() + self.assertEqual(1, wrapping.wrapped.one) + + def testSubFactoryOverriding(self): + class TestObject(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + + class OtherTestObject(object): + def __init__(self, **kwargs): + for k, v in kwargs.iteritems(): + setattr(self, k, v) + + class WrappingTestObjectFactory(factory.Factory): + FACTORY_FOR = OtherTestObject + wrapped = factory.SubFactory(TestObjectFactory, two=2, four=4) wrapped__two = 4 wrapped__three = 3 @@ -759,11 +941,85 @@ class SubFactoryTestCase(unittest.TestCase): self.assertEqual(outer.side_a.inner_from_a.a, outer.foo * 2) self.assertEqual(outer.side_a.inner_from_a.b, 4) + def test_nonstrict_container_attribute(self): + class TestModel2(FakeModel): + pass + + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 3 + two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=False) + + class TestModel2Factory(FakeModelFactory): + FACTORY_FOR = TestModel2 + one = 1 + two = factory.SubFactory(TestModelFactory, one=1) + + obj = TestModel2Factory.build() + self.assertEqual(1, obj.one) + self.assertEqual(1, obj.two.one) + self.assertEqual(1, obj.two.two) + + obj = TestModelFactory() + self.assertEqual(3, obj.one) + self.assertEqual(0, obj.two) + + def test_strict_container_attribute(self): + class TestModel2(FakeModel): + pass + + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 3 + two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=True) + + class TestModel2Factory(FakeModelFactory): + FACTORY_FOR = TestModel2 + one = 1 + two = factory.SubFactory(TestModelFactory, one=1) + + obj = TestModel2Factory.build() + self.assertEqual(1, obj.one) + self.assertEqual(1, obj.two.one) + self.assertEqual(1, obj.two.two) + + self.assertRaises(TypeError, TestModelFactory.build) + + def test_function_container_attribute(self): + class TestModel2(FakeModel): + pass + + class TestModelFactory(FakeModelFactory): + FACTORY_FOR = TestModel + one = 3 + + @factory.container_attribute + def two(self, containers): + if containers: + return len(containers) + return 42 + + class TestModel2Factory(FakeModelFactory): + FACTORY_FOR = TestModel2 + one = 1 + two = factory.SubFactory(TestModelFactory, one=1) + + obj = TestModel2Factory.build() + self.assertEqual(1, obj.one) + self.assertEqual(1, obj.two.one) + self.assertEqual(1, obj.two.two) + + obj = TestModelFactory() + self.assertEqual(3, obj.one) + self.assertEqual(42, obj.two) + class IteratorTestCase(unittest.TestCase): def test_iterator(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.Iterator(xrange(10, 30)) objs = TestObjectFactory.build_batch(20) @@ -773,6 +1029,8 @@ class IteratorTestCase(unittest.TestCase): def test_infinite_iterator(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.InfiniteIterator(xrange(5)) objs = TestObjectFactory.build_batch(20) @@ -782,6 +1040,8 @@ class IteratorTestCase(unittest.TestCase): def test_infinite_iterator_list_comprehension(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.InfiniteIterator([j * 3 for j in xrange(5)]) # Scope bleeding: j will end up in TestObjectFactory's scope. @@ -790,6 +1050,8 @@ class IteratorTestCase(unittest.TestCase): def test_infinite_iterator_list_comprehension_protected(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = factory.InfiniteIterator([_j * 3 for _j in xrange(5)]) # Scope bleeding : _j will end up in TestObjectFactory's scope. @@ -801,6 +1063,8 @@ class IteratorTestCase(unittest.TestCase): def test_iterator_decorator(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @factory.iterator def one(): for i in xrange(10, 50): @@ -813,6 +1077,8 @@ class IteratorTestCase(unittest.TestCase): def test_infinite_iterator_decorator(self): class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + @factory.infinite_iterator def one(): for i in xrange(5): @@ -824,6 +1090,150 @@ class IteratorTestCase(unittest.TestCase): self.assertEqual(i % 5, obj.one) +class PostGenerationTestCase(unittest.TestCase): + def test_post_generation(self): + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + one = 1 + + @factory.post_generation() + def incr_one(self, _create, _increment): + self.one += 1 + + obj = TestObjectFactory.build() + self.assertEqual(2, obj.one) + self.assertFalse(hasattr(obj, 'incr_one')) + + obj = TestObjectFactory.build(one=2) + self.assertEqual(3, obj.one) + self.assertFalse(hasattr(obj, 'incr_one')) + + def test_post_generation_extraction(self): + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + one = 1 + + @factory.post_generation() + def incr_one(self, _create, increment=1): + self.one += increment + + obj = TestObjectFactory.build(incr_one=2) + self.assertEqual(3, obj.one) + self.assertFalse(hasattr(obj, 'incr_one')) + + obj = TestObjectFactory.build(one=2, incr_one=2) + self.assertEqual(4, obj.one) + self.assertFalse(hasattr(obj, 'incr_one')) + + def test_post_generation_extraction_lambda(self): + + def my_lambda(obj, create, extracted, **kwargs): + self.assertTrue(isinstance(obj, TestObject)) + self.assertFalse(create) + self.assertEqual(extracted, 42) + self.assertEqual(kwargs, {'foo': 13}) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + bar = factory.PostGeneration(my_lambda) + + obj = TestObjectFactory.build(bar=42, bar__foo=13) + + def test_post_generation_method_call(self): + calls = [] + + class TestObject(object): + def __init__(self, one=None, two=None): + self.one = one + self.two = two + self.extra = None + + def call(self, *args, **kwargs): + self.extra = (args, kwargs) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 3 + two = 2 + post_call = factory.PostGenerationMethodCall('call', one=1) + + obj = TestObjectFactory.build() + self.assertEqual(3, obj.one) + self.assertEqual(2, obj.two) + self.assertEqual(((), {'one': 1}), obj.extra) + + obj = TestObjectFactory.build(post_call__one=2, post_call__two=3) + self.assertEqual(3, obj.one) + self.assertEqual(2, obj.two) + self.assertEqual(((), {'one': 2, 'two': 3}), obj.extra) + + def test_related_factory(self): + class TestRelatedObject(object): + def __init__(self, obj=None, one=None, two=None): + obj.related = self + self.one = one + self.two = two + self.three = obj + + class TestRelatedObjectFactory(factory.Factory): + FACTORY_FOR = TestRelatedObject + one = 1 + two = factory.LazyAttribute(lambda o: o.one + 1) + + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + one = 3 + two = 2 + three = factory.RelatedFactory(TestRelatedObjectFactory, name='obj') + + obj = TestObjectFactory.build() + # Normal fields + self.assertEqual(3, obj.one) + self.assertEqual(2, obj.two) + # RelatedFactory was built + self.assertIsNone(obj.three) + self.assertIsNotNone(obj.related) + self.assertEqual(1, obj.related.one) + self.assertEqual(2, obj.related.two) + # RelatedFactory was passed "parent" object + self.assertEqual(obj, obj.related.three) + + obj = TestObjectFactory.build(three__one=3) + # Normal fields + self.assertEqual(3, obj.one) + self.assertEqual(2, obj.two) + # RelatedFactory was build + self.assertIsNone(obj.three) + self.assertIsNotNone(obj.related) + # three__one was correctly parse + self.assertEqual(3, obj.related.one) + self.assertEqual(4, obj.related.two) + # RelatedFactory received "parent" object + self.assertEqual(obj, obj.related.three) + + +class CircularTestCase(unittest.TestCase): + def test_example(self): + sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) + + from cyclic import foo + f = foo.FooFactory.build(bar__foo=None) + self.assertEqual(42, f.x) + self.assertEqual(13, f.bar.y) + self.assertIsNone(f.bar.foo) + + from cyclic import bar + b = bar.BarFactory.build(foo__bar__foo__bar=None) + self.assertEqual(13, b.y) + self.assertEqual(42, b.foo.x) + self.assertEqual(13, b.foo.bar.y) + self.assertEqual(42, b.foo.bar.foo.x) + self.assertIsNone(b.foo.bar.foo.bar) + + if __name__ == '__main__': unittest.main() diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..9aaafc1 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2010 Mark Sandstrom +# Copyright (c) 2011 Raphaël Barrois +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + + +from factory import utils + +from .compat import unittest + + +class ExtractDictTestCase(unittest.TestCase): + def test_empty_dict(self): + self.assertEqual({}, utils.extract_dict('foo', {})) + + def test_unused_key(self): + self.assertEqual({}, utils.extract_dict('foo', {'bar__baz': 42})) + + def test_empty_key(self): + self.assertEqual({}, utils.extract_dict('', {'foo': 13, 'bar__baz': 42})) + d = {'foo': 13, 'bar__baz': 42, '__foo': 1} + self.assertEqual({'foo': 1}, utils.extract_dict('', d)) + self.assertNotIn('__foo', d) + + def test_one_key(self): + d = {'foo': 13, 'foo__baz': 42, '__foo': 1} + self.assertEqual({'baz': 42}, utils.extract_dict('foo', d, pop=False)) + self.assertEqual(42, d['foo__baz']) + + self.assertEqual({'baz': 42}, utils.extract_dict('foo', d, pop=True)) + self.assertNotIn('foo__baz', d) + + def test_one_key_excluded(self): + d = {'foo': 13, 'foo__baz': 42, '__foo': 1} + self.assertEqual({}, + utils.extract_dict('foo', d, pop=False, exclude=('foo__baz',))) + self.assertEqual(42, d['foo__baz']) + + self.assertEqual({}, + utils.extract_dict('foo', d, pop=True, exclude=('foo__baz',))) + self.assertIn('foo__baz', d) + + def test_many_keys(self): + d = {'foo': 13, 'foo__baz': 42, 'foo__foo__bar': 2, 'foo__bar': 3, '__foo': 1} + self.assertEqual({'foo__bar': 2, 'bar': 3, 'baz': 42}, + utils.extract_dict('foo', d, pop=False)) + self.assertEqual(42, d['foo__baz']) + self.assertEqual(3, d['foo__bar']) + self.assertEqual(2, d['foo__foo__bar']) + + self.assertEqual({'foo__bar': 2, 'bar': 3, 'baz': 42}, + utils.extract_dict('foo', d, pop=True)) + self.assertNotIn('foo__baz', d) + self.assertNotIn('foo__bar', d) + self.assertNotIn('foo__foo__bar', d) + + def test_many_keys_excluded(self): + d = {'foo': 13, 'foo__baz': 42, 'foo__foo__bar': 2, 'foo__bar': 3, '__foo': 1} + self.assertEqual({'foo__bar': 2, 'baz': 42}, + utils.extract_dict('foo', d, pop=False, exclude=('foo__bar', 'bar'))) + self.assertEqual(42, d['foo__baz']) + self.assertEqual(3, d['foo__bar']) + self.assertEqual(2, d['foo__foo__bar']) + + self.assertEqual({'foo__bar': 2, 'baz': 42}, + utils.extract_dict('foo', d, pop=True, exclude=('foo__bar', 'bar'))) + self.assertNotIn('foo__baz', d) + self.assertIn('foo__bar', d) + self.assertNotIn('foo__foo__bar', d) + + +class MultiExtractDictTestCase(unittest.TestCase): + def test_empty_dict(self): + self.assertEqual({'foo': {}}, utils.multi_extract_dict(['foo'], {})) + + def test_unused_key(self): + self.assertEqual({'foo': {}}, + utils.multi_extract_dict(['foo'], {'bar__baz': 42})) + self.assertEqual({'foo': {}, 'baz': {}}, + utils.multi_extract_dict(['foo', 'baz'], {'bar__baz': 42})) + + def test_no_key(self): + self.assertEqual({}, utils.multi_extract_dict([], {'bar__baz': 42})) + + def test_empty_key(self): + self.assertEqual({'': {}}, + utils.multi_extract_dict([''], {'foo': 13, 'bar__baz': 42})) + + d = {'foo': 13, 'bar__baz': 42, '__foo': 1} + self.assertEqual({'': {'foo': 1}}, + utils.multi_extract_dict([''], d)) + self.assertNotIn('__foo', d) + + def test_one_extracted(self): + d = {'foo': 13, 'foo__baz': 42, '__foo': 1} + self.assertEqual({'foo': {'baz': 42}}, + utils.multi_extract_dict(['foo'], d, pop=False)) + self.assertEqual(42, d['foo__baz']) + + self.assertEqual({'foo': {'baz': 42}}, + utils.multi_extract_dict(['foo'], d, pop=True)) + self.assertNotIn('foo__baz', d) + + def test_many_extracted(self): + d = {'foo': 13, 'foo__baz': 42, 'foo__foo__bar': 2, 'foo__bar': 3, '__foo': 1} + self.assertEqual({'foo': {'foo__bar': 2, 'bar': 3, 'baz': 42}}, + utils.multi_extract_dict(['foo'], d, pop=False)) + self.assertEqual(42, d['foo__baz']) + self.assertEqual(3, d['foo__bar']) + self.assertEqual(2, d['foo__foo__bar']) + + self.assertEqual({'foo': {'foo__bar': 2, 'bar': 3, 'baz': 42}}, + utils.multi_extract_dict(['foo'], d, pop=True)) + self.assertNotIn('foo__baz', d) + self.assertNotIn('foo__bar', d) + self.assertNotIn('foo__foo__bar', d) + + def test_many_keys_one_extracted(self): + d = {'foo': 13, 'foo__baz': 42, '__foo': 1} + self.assertEqual({'foo': {'baz': 42}, 'baz': {}}, + utils.multi_extract_dict(['foo', 'baz'], d, pop=False)) + self.assertEqual(42, d['foo__baz']) + + self.assertEqual({'foo': {'baz': 42}, 'baz': {}}, + utils.multi_extract_dict(['foo', 'baz'], d, pop=True)) + self.assertNotIn('foo__baz', d) + + def test_many_keys_many_extracted(self): + d = { + 'foo': 13, + 'foo__baz': 42, 'foo__foo__bar': 2, 'foo__bar': 3, + 'bar__foo': 1, 'bar__bar__baz': 4, + } + + self.assertEqual( + { + 'foo': {'foo__bar': 2, 'bar': 3, 'baz': 42}, + 'bar': {'foo': 1, 'bar__baz': 4}, + 'baz': {} + }, + utils.multi_extract_dict(['foo', 'bar', 'baz'], d, pop=False)) + self.assertEqual(42, d['foo__baz']) + self.assertEqual(3, d['foo__bar']) + self.assertEqual(2, d['foo__foo__bar']) + self.assertEqual(1, d['bar__foo']) + self.assertEqual(4, d['bar__bar__baz']) + + self.assertEqual( + { + 'foo': {'foo__bar': 2, 'bar': 3, 'baz': 42}, + 'bar': {'foo': 1, 'bar__baz': 4}, + 'baz': {} + }, + utils.multi_extract_dict(['foo', 'bar', 'baz'], d, pop=True)) + self.assertNotIn('foo__baz', d) + self.assertNotIn('foo__bar', d) + self.assertNotIn('foo__foo__bar', d) + self.assertNotIn('bar__foo', d) + self.assertNotIn('bar__bar__baz', d) + + def test_son_in_list(self): + """Make sure that prefixes are used in decreasing match length order.""" + d = { + 'foo': 13, + 'foo__baz': 42, 'foo__foo__bar': 2, 'foo__bar': 3, + 'bar__foo': 1, 'bar__bar__baz': 4, + } + + self.assertEqual( + { + 'foo__foo': {'bar': 2}, + 'foo': {'bar': 3, 'baz': 42}, + 'bar__bar': {'baz': 4}, + 'bar': {'foo': 1}, + 'baz': {} + }, + utils.multi_extract_dict( + ['foo', 'bar', 'baz', 'foo__foo', 'bar__bar'], d, pop=False)) + self.assertEqual(42, d['foo__baz']) + self.assertEqual(3, d['foo__bar']) + self.assertEqual(2, d['foo__foo__bar']) + self.assertEqual(1, d['bar__foo']) + self.assertEqual(4, d['bar__bar__baz']) + + self.assertEqual( + { + 'foo__foo': {'bar': 2}, + 'foo': {'bar': 3, 'baz': 42}, + 'bar__bar': {'baz': 4}, + 'bar': {'foo': 1}, + 'baz': {} + }, + utils.multi_extract_dict( + ['foo', 'bar', 'baz', 'foo__foo', 'bar__bar'], d, pop=True)) + self.assertNotIn('foo__baz', d) + self.assertNotIn('foo__bar', d) + self.assertNotIn('foo__foo__bar', d) + self.assertNotIn('bar__foo', d) + self.assertNotIn('bar__bar__baz', d) + + +class ImportObjectTestCase(unittest.TestCase): + def test_datetime(self): + imported = utils.import_object('datetime', 'date') + import datetime + d = datetime.date + self.assertEqual(d, imported) + + def test_unknown_attribute(self): + self.assertRaises(AttributeError, utils.import_object, + 'datetime', 'foo') + + def test_invalid_module(self): + self.assertRaises(ImportError, utils.import_object, + 'this-is-an-invalid-module', '__name__') |