From 23be8b41a9e150180d63548347ddd70ebb86a082 Mon Sep 17 00:00:00 2001 From: Iwo Herka Date: Fri, 13 Jul 2018 11:50:50 +0000 Subject: [PATCH] Add tests for forms --- .coveragerc | 1 + eav/admin.py | 19 ++++++------ eav/forms.py | 8 ++--- eav/utils.py | 2 +- runtests | 3 +- tests/attributes.py | 6 +--- tests/forms.py | 71 ++++++++++++++++++++++++++++++++++++++++++++ tests/misc_models.py | 1 - 8 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 tests/forms.py diff --git a/.coveragerc b/.coveragerc index f204218..932c4dd 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,3 +2,4 @@ omit = */migrations/* eav/__init__.py + eav/utils.py diff --git a/eav/admin.py b/eav/admin.py index ea88fc9..bf35bd6 100644 --- a/eav/admin.py +++ b/eav/admin.py @@ -10,11 +10,10 @@ from .models import Attribute, EnumGroup, EnumValue, Value class BaseEntityAdmin(ModelAdmin): - - def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): + def render_change_form(self, request, context, *args, **kwargs): """ - Wrapper for ModelAdmin.render_change_form. Replaces standard static - AdminForm with an EAV-friendly one. The point is that our form generates + Wrapper for `ModelAdmin.render_change_form`. Replaces standard static + `AdminForm` with an EAV-friendly one. The point is that our form generates fields dynamically and fieldsets must be inferred from a prepared and validated form instance, not just the form class. Django does not seem to provide hooks for this purpose, so we simply wrap the view and @@ -22,16 +21,16 @@ class BaseEntityAdmin(ModelAdmin): """ form = context['adminform'].form - # infer correct data from the form + # Infer correct data from the form. fieldsets = self.fieldsets or [(None, {'fields': form.fields.keys()})] - adminform = admin.helpers.AdminForm(form, fieldsets, - self.prepopulated_fields) + adminform = admin.helpers.AdminForm(form, fieldsets, self.prepopulated_fields) media = mark_safe(self.media + adminform.media) context.update(adminform=adminform, media=media) - super_meth = super(BaseEntityAdmin, self).render_change_form - return super_meth(request, context, add, change, form_url, obj) + return super(BaseEntityAdmin, self).render_change_form( + request, context, *args, **kwargs + ) class BaseEntityInlineFormSet(BaseInlineFormSet): @@ -75,10 +74,12 @@ class BaseEntityInline(InlineModelAdmin): return [(None, {'fields': form.fields.keys()})] + class AttributeAdmin(ModelAdmin): list_display = ('name', 'slug', 'datatype', 'description') prepopulated_fields = {'slug': ('name',)} + admin.site.register(Attribute, AttributeAdmin) admin.site.register(Value) admin.site.register(EnumValue) diff --git a/eav/forms.py b/eav/forms.py index eeb1f9b..d9f5b24 100644 --- a/eav/forms.py +++ b/eav/forms.py @@ -18,7 +18,6 @@ class BaseDynamicEntityForm(ModelForm): validation is actually done, all EAV fields are present in it (unless Rubric is not defined). ''' - FIELD_CLASSES = { 'text': CharField, 'float': FloatField, @@ -78,16 +77,15 @@ class BaseDynamicEntityForm(ModelForm): Returns ``instance``. """ - if self.errors: raise ValueError(_(u"The %s could not be saved because the data" u"didn't validate.") % \ self.instance._meta.object_name) - # create entity instance, don't save yet + # Create entity instance, don't save yet. instance = super(BaseDynamicEntityForm, self).save(commit=False) - # assign attributes + # Assign attributes. for attribute in self.entity.get_all_attributes(): value = self.cleaned_data.get(attribute.slug) if attribute.datatype == attribute.TYPE_ENUM: @@ -98,7 +96,7 @@ class BaseDynamicEntityForm(ModelForm): setattr(self.entity, attribute.slug, value) - # save entity and its attributes + # Save entity and its attributes. if commit: instance.save() diff --git a/eav/utils.py b/eav/utils.py index 2b17755..80e8da4 100644 --- a/eav/utils.py +++ b/eav/utils.py @@ -5,7 +5,7 @@ import sys from django.db.models import Q -def print_q_expr(expr, indent="", is_tail=True): # pragma: no cover +def print_q_expr(expr, indent="", is_tail=True): ''' Simple print method for debugging Q-expressions' trees. ''' diff --git a/runtests b/runtests index 4a79792..c71a783 100755 --- a/runtests +++ b/runtests @@ -19,7 +19,8 @@ if __name__ == "__main__": 'tests.data_validation', 'tests.attributes', 'tests.misc_models', - 'tests.set_and_get' + 'tests.set_and_get', + 'tests.forms' ] else: tests = ['tests.{}'.format(arg) for arg in sys.argv[1:]] diff --git a/tests/attributes.py b/tests/attributes.py index d276c67..a306c04 100644 --- a/tests/attributes.py +++ b/tests/attributes.py @@ -2,18 +2,14 @@ from django.core.exceptions import ValidationError from django.test import TestCase import eav +from eav.exceptions import IllegalAssignmentException from eav.models import Attribute, Value from eav.registry import EavConfig -from eav.exceptions import IllegalAssignmentException from .models import Encounter, Patient class Attributes(TestCase): - ''' - TODO: Explain this test. - ''' - def setUp(self): class EncounterEavConfig(EavConfig): manager_attr = 'eav_objects' diff --git a/tests/forms.py b/tests/forms.py new file mode 100644 index 0000000..73734bf --- /dev/null +++ b/tests/forms.py @@ -0,0 +1,71 @@ +from django.test import TestCase +from django.contrib.admin.sites import AdminSite + +import eav +from eav.admin import * +from .models import Patient +from eav.models import Attribute +from eav.forms import BaseDynamicEntityForm +from django.contrib import admin +from django.core.handlers.base import BaseHandler +from django.test.client import RequestFactory +from django.forms import ModelForm + + +class MockRequest(RequestFactory): + def request(self, **request): + "Construct a generic request object." + request = RequestFactory.request(self, **request) + handler = BaseHandler() + handler.load_middleware() + for middleware_method in handler._request_middleware: + if middleware_method(request): + raise Exception("Couldn't create request mock object - " + "request middleware returned a response") + return request + + +class MockSuperUser: + def __init__(self): + self.is_active = True + self.is_staff = True + + def has_perm(self, perm): + return True + + +request = MockRequest().request() +request.user = MockSuperUser() + + +class Forms(TestCase): + def setUp(self): + eav.register(Patient) + Attribute.objects.create(name='weight', datatype=Attribute.TYPE_FLOAT) + Attribute.objects.create(name='color', datatype=Attribute.TYPE_TEXT) + self.instance = Patient.objects.create(name='Jim Morrison') + self.site = AdminSite() + + def test_fields(self): + admin = BaseEntityAdmin(Patient, self.site) + admin.form = BaseDynamicEntityForm + view = admin.change_view(request, str(self.instance.pk)) + + own_fields = 1 + adminform = view.context_data['adminform'] + + self.assertEqual( + len(adminform.form.fields), Attribute.objects.count() + own_fields + ) + + def test_submit(self): + class PatientForm(ModelForm): + class Meta: + model = Patient + fields = '__all__' + + self.instance.eav.color = 'Blue' + form = PatientForm(self.instance.__dict__, instance=self.instance) + jim = form.save() + + self.assertEqual(jim.eav.color, 'Blue') \ No newline at end of file diff --git a/tests/misc_models.py b/tests/misc_models.py index 0c0a02f..6b8deff 100644 --- a/tests/misc_models.py +++ b/tests/misc_models.py @@ -7,7 +7,6 @@ from .models import Patient class MiscModels(TestCase): - def test_enumgroup_str(self): name = 'Yes / No' e = EnumGroup.objects.create(name=name)