Skip to content

Commit

Permalink
Improving management command and adding some testing.
Browse files Browse the repository at this point in the history
  • Loading branch information
gregmuellegger committed Mar 5, 2010
1 parent d64af55 commit 5abd0d5
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 16 deletions.
21 changes: 14 additions & 7 deletions src/django_autofixture/autofixture.py
Expand Up @@ -181,14 +181,20 @@ def __init__(self, model,

if follow_m2m is not None:
if not isinstance(follow_m2m, dict):
follow_m2m = Link({'ALL': follow_m2m})
if follow_m2m:
follow_m2m = Link({'ALL': follow_m2m})
else:
follow_m2m = Link(False)
elif not isinstance(follow_m2m, Link):
follow_m2m = Link(follow_m2m)
self.follow_m2m = follow_m2m

if generate_m2m is not None:
if not isinstance(generate_m2m, dict):
generate_m2m = Link({'ALL': generate_m2m})
if generate_m2m:
generate_m2m = Link({'ALL': generate_m2m})
else:
generate_m2m = Link(False)
elif not isinstance(generate_m2m, Link):
generate_m2m = Link(generate_m2m)
self.generate_m2m = generate_m2m
Expand Down Expand Up @@ -243,7 +249,7 @@ def get_generator(self, field):
return generators.InstanceSelector(
field.rel.to,
limit_choices_to=field.rel.limit_choices_to)
if field.null:
if field.blank or field.null:
return generators.NoneGenerator()
raise CreateInstanceError(
u'Cannot resolve ForeignKey "%s" to "%s". Provide either '
Expand All @@ -258,7 +264,9 @@ def get_generator(self, field):
if field.name in self.generate_m2m:
min_count, max_count = self.generate_m2m[field.name]
return generators.MultipleInstanceGenerator(
AutoFixture(field.rel.to),
AutoFixture(
field.rel.to
),
limit_choices_to=field.rel.limit_choices_to,
min_count=min_count,
max_count=max_count,
Expand All @@ -271,12 +279,11 @@ def get_generator(self, field):
min_count=min_count,
max_count=max_count,
**kwargs)
if field.null:
if field.blank or field.null:
return generators.StaticGenerator([])
raise CreateInstanceError(
u'Cannot assign instances of "%s" to ManyToManyField "%s". '
u'Provide either "follow_m2m" or "generate_m2m" '
u'parameters.' % (
u'Provide either "follow_m2m" or "generate_m2m" argument.' % (
'%s.%s' % (
field.rel.to._meta.app_label,
field.rel.to._meta.object_name,
Expand Down
33 changes: 25 additions & 8 deletions src/django_autofixture/management/commands/loadtestdata.py
Expand Up @@ -10,6 +10,9 @@ class Command(BaseCommand):
help = 'Create random model instances for testing purposes.'
args = 'app.Model:# [app.Model:# ...]'

# TODO(gregor@muellegger.de): change descriptions, they are already
# invalid

option_list = BaseCommand.option_list + (
make_option('-d', '--overwrite-defaults', action='store_true',
dest='overwrite_defaults', default=False, help=
Expand All @@ -18,20 +21,20 @@ class Command(BaseCommand):
make_option('--no-follow-fk', action='store_true', dest='no_follow_fk',
default=False, help=
u'Ignore ForeignKey fields while creating model instances.'),
make_option('--generate-fk', action='store_true', dest='generate_fk',
default=False, help=
make_option('--generate-fk', action='store', dest='generate_fk',
default='', help=
u'Do not use already existing instances for ForeignKey '
u'relations. Create new instances instead.'),
make_option('--no-follow-m2m', action='store_true',
dest='no_follow_m2m', default=False, help=
u'Ignore ManyToManyFields while creating model instances.'),
make_option('--follow-m2m', action='store', dest='follow_m2m',
default='1,5', help=
default='1:5', help=
u'Specify minimum and maximum number of instances that are '
u'assigned to a m2m relation. Use two, comma separated '
u'numbers in the form of: min,max. Default is 1,5.'),
make_option('--generate-m2m', action='store', dest='generate_m2m',
default='0,0', help=
default='', help=
u'Specify minimum and maximum number of instances that are '
u'newly created and assigned to a m2m relation. Use two, '
u'comma separated numbers in the form of: min,max. Default is '
Expand Down Expand Up @@ -81,22 +84,36 @@ def handle(self, *attrs, **options):

follow_fk = not options['no_follow_fk']
follow_m2m = not options['no_follow_m2m']
generate_fk = options['generate_fk']
generate_fk = options['generate_fk'].split(',')

error_option = None
try:
if follow_m2m:
follow_m2m = [int(i) for i in options['follow_m2m'].split(',')]
value = [i for i in options['follow_m2m'].split(',')]
if len(value) == 1 and value[0].count(':') == 1:
follow_m2m = [int(i) for i in value[0].split(':')]
else:
follow_m2m = {}
for field in value:
key, minval, maxval = field.split(':')
follow_m2m[key] = int(minval), int(maxval)
except ValueError:
error_option = '--follow-m2m=%s' % options['follow_m2m']
try:
generate_m2m = [int(i) for i in options['generate_m2m'].split(',')]
value = [v for v in options['generate_m2m'].split(',') if v]
if len(value) == 1 and value[0].count(':') == 1:
generate_m2m = [int(i) for i in value[0].split(':')]
else:
generate_m2m = {}
for field in value:
key, minval, maxval = field.split(':')
generate_m2m[key] = int(minval), int(maxval)
except ValueError:
error_option = '--generate-m2m=%s' % options['generate_m2m']
if error_option:
raise CommandError(
u'Invalid option %s\n'
u'Expected: %s=min,max (min and max must be numbers)' % (
u'Expected: %s=field:min:max,field2:min:max... (min and max must be numbers)' % (
error_option,
error_option.split('=', 1)[0]))

Expand Down
101 changes: 100 additions & 1 deletion src/django_autofixture/tests.py
Expand Up @@ -34,6 +34,10 @@ class DeepLinkModel2(models.Model):
related = models.ForeignKey('DeepLinkModel1')


class NullableFKModel(models.Model):
m2m = models.ManyToManyField('SimpleModel', null=True, blank=True)


class BasicModel(models.Model):
chars = models.CharField(max_length=50)
blankchars = models.CharField(max_length=100, blank=True)
Expand Down Expand Up @@ -410,7 +414,7 @@ def test_always_true_link(self):
self.assertTrue('field' in link)
self.assertTrue('any' in link)

link = Link(True)
link = Link(('ALL',))
self.assertTrue('field' in link)
self.assertTrue('any' in link)

Expand All @@ -424,3 +428,98 @@ def test_inherit_always_true_value(self):

sublink = link.get_deep_links('foo')
self.assertEqual(sublink['bar'], 1)


class TestManagementCommand(TestCase):
def setUp(self):
from django_autofixture.management.commands.loadtestdata import Command
self.command = Command()
self.options = {
'overwrite_defaults': False,
'no_follow_fk': False,
'no_follow_m2m': False,
'generate_fk': '',
'follow_m2m': '1:5',
'generate_m2m': '',
'verbosity': '0',
}

def test_basic(self):
models = ()
# empty attributes are allowed
self.command.handle(*models, **self.options)
self.assertEqual(SimpleModel.objects.count(), 0)

models = ('django_autofixture.SimpleModel:1',)
self.command.handle(*models, **self.options)
self.assertEqual(SimpleModel.objects.count(), 1)

models = ('django_autofixture.SimpleModel:5',)
self.command.handle(*models, **self.options)
self.assertEqual(SimpleModel.objects.count(), 6)

def test_generate_fk(self):
models = ('django_autofixture.DeepLinkModel2:1',)
self.options['generate_fk'] = 'related,related__related'
self.command.handle(*models, **self.options)
obj = DeepLinkModel2.objects.get()
self.assertTrue(obj.related)
self.assertTrue(obj.related.related)
self.assertEqual(obj.related.related2, obj.related.related)

def test_generate_fk_with_no_follow(self):
models = ('django_autofixture.DeepLinkModel2:1',)
self.options['generate_fk'] = 'related,related__related'
self.options['no_follow_fk'] = True
self.command.handle(*models, **self.options)
obj = DeepLinkModel2.objects.get()
self.assertTrue(obj.related)
self.assertTrue(obj.related.related)
self.assertEqual(obj.related.related2, None)

def test_generate_fk_with_ALL(self):
models = ('django_autofixture.DeepLinkModel2:1',)
self.options['generate_fk'] = 'ALL'
self.command.handle(*models, **self.options)
obj = DeepLinkModel2.objects.get()
self.assertTrue(obj.related)
self.assertTrue(obj.related.related)
self.assertTrue(obj.related.related2)
self.assertTrue(obj.related.related != obj.related.related2)

def test_no_follow_m2m(self):
AutoFixture(SimpleModel).create(1)

models = ('django_autofixture.NullableFKModel:1',)
self.options['no_follow_m2m'] = True
self.command.handle(*models, **self.options)
obj = NullableFKModel.objects.get()
self.assertEqual(obj.m2m.count(), 0)

def test_follow_m2m(self):
AutoFixture(SimpleModel).create(10)
AutoFixture(OtherSimpleModel).create(10)

models = ('django_autofixture.M2MModel:25',)
self.options['follow_m2m'] = 'm2m:3:3,secondm2m:0:10'
self.command.handle(*models, **self.options)

for obj in M2MModel.objects.all():
self.assertEqual(obj.m2m.count(), 3)
self.assertTrue(0 <= obj.secondm2m.count() <= 10)

def test_generate_m2m(self):
models = ('django_autofixture.M2MModel:10',)
self.options['generate_m2m'] = 'm2m:1:1,secondm2m:2:5'
self.command.handle(*models, **self.options)

all_m2m, all_secondm2m = set(), set()
for obj in M2MModel.objects.all():
self.assertEqual(obj.m2m.count(), 1)
self.assertTrue(
2 <= obj.secondm2m.count() <= 5 or
obj.secondm2m.count() == 0)
all_m2m.update(obj.m2m.all())
all_secondm2m.update(obj.secondm2m.all())
self.assertEqual(all_m2m, set(SimpleModel.objects.all()))
self.assertEqual(all_secondm2m, set(OtherSimpleModel.objects.all()))

0 comments on commit 5abd0d5

Please sign in to comment.