diff --git a/.gitignore b/.gitignore index 2bdfe29..c1f58df 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ tests/db.sqlite* .DS_Store .pytest_cache /tests/local.db +/.venv diff --git a/advanced_filters/form_helpers.py b/advanced_filters/form_helpers.py index 7bb405b..2523e52 100644 --- a/advanced_filters/form_helpers.py +++ b/advanced_filters/form_helpers.py @@ -7,7 +7,7 @@ logger = logging.getLogger('advanced_filters.form_helpers') -extra_spaces_pattern = re.compile('\s+') +extra_spaces_pattern = re.compile(r'\s+') class VaryingTypeCharField(forms.CharField): diff --git a/advanced_filters/forms.py b/advanced_filters/forms.py index 9068f74..ce1adc1 100644 --- a/advanced_filters/forms.py +++ b/advanced_filters/forms.py @@ -253,17 +253,18 @@ def get_fields_from_model(self, model, fields): """ model_fields = {} for field in fields: - if isinstance(field, tuple) and len(field) == 2: - field, verbose_name = field[0], field[1] - else: - try: - model_field = get_fields_from_path(model, field)[-1] - verbose_name = model_field.verbose_name - except (FieldDoesNotExist, IndexError, TypeError) as e: - logger.warn("AdvancedFilterForm: skip invalid field " - "- %s", e) - continue - model_fields[field] = verbose_name + if isinstance(field, tuple) and len(field) == 2: + field, verbose_name = field[0], field[1] + else: + try: + model_field = get_fields_from_path(model, field)[-1] + verbose_name = model_field.verbose_name + except (FieldDoesNotExist, IndexError, TypeError) as e: + logger.warning( + "AdvancedFilterForm: skip invalid field - %s", e + ) + continue + model_fields[field] = verbose_name return model_fields def __init__(self, *args, **kwargs): diff --git a/advanced_filters/tests/__init__.py b/advanced_filters/tests/__init__.py index 8d26a51..e69de29 100644 --- a/advanced_filters/tests/__init__.py +++ b/advanced_filters/tests/__init__.py @@ -1,3 +0,0 @@ -from .test_models import * -from .test_q_serializer import * -from .test_views import * diff --git a/advanced_filters/tests/conftest.py b/advanced_filters/tests/conftest.py new file mode 100644 index 0000000..6db2510 --- /dev/null +++ b/advanced_filters/tests/conftest.py @@ -0,0 +1,13 @@ +import pytest +from tests.factories import SalesRepFactory + + +@pytest.fixture +def user(db): + return SalesRepFactory() + + +@pytest.fixture() +def client(client, user): + client.force_login(user) + return client diff --git a/advanced_filters/tests/factories.py b/advanced_filters/tests/factories.py new file mode 100644 index 0000000..f551702 --- /dev/null +++ b/advanced_filters/tests/factories.py @@ -0,0 +1,10 @@ +import factory + +from tests.factories import SalesRepFactory + + +class AdvancedFilterFactory(factory.django.DjangoModelFactory): + model = 'customers.Client' + + class Meta: + model = 'advanced_filters.AdvancedFilter' diff --git a/advanced_filters/tests/test_admin.py b/advanced_filters/tests/test_admin.py deleted file mode 100644 index 320d5ff..0000000 --- a/advanced_filters/tests/test_admin.py +++ /dev/null @@ -1,176 +0,0 @@ -try: - from django.urls import reverse -except ImportError: # Django < 2.0 - from django.core.urlresolvers import reverse -from django.contrib.auth.models import Permission -from django.db.models import Q -from django.test import TestCase - -from ..models import AdvancedFilter -from ..admin import AdvancedListFilters -from tests import factories - - -class ChageFormAdminTest(TestCase): - """ Test the AdvancedFilter admin change page """ - def setUp(self): - self.user = factories.SalesRep() - assert self.client.login(username='user', password='test') - self.a = AdvancedFilter(title='test', url='test', created_by=self.user, - model='customers.Client') - self.a.query = Q(email__iexact='a@a.com') - self.a.save() - - def test_change_page_requires_perms(self): - url = reverse('admin:advanced_filters_advancedfilter_change', - args=(self.a.pk,)) - res = self.client.get(url) - assert res.status_code == 403 - - def test_change_page_renders(self): - self.user.user_permissions.add(Permission.objects.get( - codename='change_advancedfilter')) - url = reverse('admin:advanced_filters_advancedfilter_change', - args=(self.a.pk,)) - - with self.settings(ADVANCED_FILTER_EDIT_BY_USER=False): - res = self.client.get(url) - assert res.status_code == 200 - - def test_change_and_goto(self): - self.user.user_permissions.add(Permission.objects.get( - codename='change_advancedfilter')) - url = reverse('admin:advanced_filters_advancedfilter_change', - args=(self.a.pk,)) - form_data = {'form-TOTAL_FORMS': 1, 'form-INITIAL_FORMS': 0, - '_save_goto': 1} - with self.settings(ADVANCED_FILTER_EDIT_BY_USER=False): - res = self.client.post(url, data=form_data) - assert res.status_code == 302 - url = res['location'] - assert url.endswith('admin/customers/client/?_afilter=1') - - def test_create_page_disabled(self): - self.user.user_permissions.add(Permission.objects.get( - codename='add_advancedfilter')) - url = reverse('admin:advanced_filters_advancedfilter_add') - res = self.client.get(url) - assert res.status_code == 403 - - -class AdvancedFilterCreationTest(TestCase): - """ Test creation of AdvancedFilter in target model changelist """ - form_data = {'form-TOTAL_FORMS': 1, 'form-INITIAL_FORMS': 0, - 'action': 'advanced_filters'} - good_data = {'title': 'Test title', 'form-0-field': 'language', - 'form-0-operator': 'iexact', 'form-0-value': 'ru', } - query = ['language__iexact', 'ru'] - - def setUp(self): - self.user = factories.SalesRep() - assert self.client.login(username='user', password='test') - - def test_changelist_includes_form(self): - self.user.user_permissions.add(Permission.objects.get( - codename='change_client')) - url = reverse('admin:customers_client_changelist') - with self.settings(ADVANCED_FILTER_EDIT_BY_USER=False): - res = self.client.get(url) - assert res.status_code == 200 - title = ['Create advanced filter'] - fields = ['First name', 'Language', 'Sales Rep'] - # python >= 3.3 support - response_content = res.content.decode('utf-8') - for part in title + fields: - assert part in response_content - - def test_create_form_validation(self): - self.user.user_permissions.add(Permission.objects.get( - codename='change_client')) - url = reverse('admin:customers_client_changelist') - form_data = self.form_data.copy() - res = self.client.post(url, data=form_data) - assert res.status_code == 200 - form = res.context_data['advanced_filters'] - assert 'title' in form.errors - assert '__all__' in form.errors - assert form.errors['title'] == ['This field is required.'] - assert form.errors['__all__'] == ['Error validating filter forms'] - - def test_create_form_valid(self): - self.user.user_permissions.add(Permission.objects.get( - codename='change_client')) - url = reverse('admin:customers_client_changelist') - form_data = self.form_data.copy() - form_data.update(self.good_data) - res = self.client.post(url, data=form_data) - assert res.status_code == 200 - form = res.context_data['advanced_filters'] - assert form.is_valid() - assert AdvancedFilter.objects.count() == 1 - - created_filter = AdvancedFilter.objects.order_by('-pk')[0] - - assert created_filter.title == self.good_data['title'] - assert list(created_filter.query.children[0]) == self.query - - # save with redirect to filter - form_data['_save_goto'] = 1 - res = self.client.post(url, data=form_data) - assert res.status_code == 302 - assert AdvancedFilter.objects.count() == 2 - - created_filter = AdvancedFilter.objects.order_by('-pk')[0] - url = res['location'] - assert url.endswith('admin/customers/client/?_afilter=%s' % - created_filter.pk) - - assert list(created_filter.query.children[0]) == self.query - - -class AdvancedFilterUsageTest(TestCase): - """ Test filter visibility and actual filtering of a changelist """ - def setUp(self): - self.user = factories.SalesRep() - assert self.client.login(username='user', password='test') - factories.Client.create_batch(8, assigned_to=self.user, language='en') - factories.Client.create_batch(2, assigned_to=self.user, language='ru') - self.user.user_permissions.add(Permission.objects.get( - codename='change_client')) - self.a = AdvancedFilter(title='Russian speakers', url='foo', - created_by=self.user, model='customers.Client') - self.a.query = Q(language='ru') - self.a.save() - - def test_filters_not_available(self): - url = reverse('admin:customers_client_changelist') - res = self.client.get(url, data={'_afilter': self.a.pk}) - assert res.status_code == 200 - cl = res.context_data['cl'] - assert not any(isinstance(f, AdvancedListFilters) - for f in cl.filter_specs) - # filter not applied due to user not being in list - if hasattr(cl, 'queryset'): - assert cl.queryset.count() == 10 - - def test_filters_available_to_users(self): - self.a.users.add(self.user) - url = reverse('admin:customers_client_changelist') - res = self.client.get(url, data={'_afilter': self.a.pk}) - assert res.status_code == 200 - cl = res.context_data['cl'] - assert any(isinstance(f, AdvancedListFilters) - for f in cl.filter_specs) - if hasattr(cl, 'queryset'): - assert cl.queryset.count() == 2 - - def test_filters_available_to_groups(self): - group = self.user.groups.create() - self.a.groups.add(group) - url = reverse('admin:customers_client_changelist') - res = self.client.get(url, data={'_afilter': self.a.pk}) - assert res.status_code == 200 - cl = res.context_data['cl'] - assert cl.filter_specs - if hasattr(cl, 'queryset'): - assert cl.queryset.count() == 2 diff --git a/advanced_filters/tests/test_admin_change_form.py b/advanced_filters/tests/test_admin_change_form.py new file mode 100644 index 0000000..540376e --- /dev/null +++ b/advanced_filters/tests/test_admin_change_form.py @@ -0,0 +1,57 @@ +import pytest +from django.contrib.auth.models import Permission +from django.db.models import Q + +from ..models import AdvancedFilter +from .factories import AdvancedFilterFactory + +try: + from django.urls import reverse +except ImportError: # Django < 2.0 + from django.core.urlresolvers import reverse + +URL_NAME_CHANGE = "admin:advanced_filters_advancedfilter_change" +URL_NAME_ADD = "admin:advanced_filters_advancedfilter_add" +URL_NAME_CLIENT_CHANGELIST = "admin:customers_client_changelist" + + +@pytest.fixture +def advanced_filter(user): + af = AdvancedFilterFactory.build(created_by=user) + af.query = Q(email__iexact="a@a.com") + af.save() + return af + + +def test_change_page_requires_perms(client, advanced_filter): + url = reverse(URL_NAME_CHANGE, args=(advanced_filter.pk,)) + res = client.get(url) + assert res.status_code == 403 + + +def test_change_page_renders(client, user, settings, advanced_filter): + user.user_permissions.add(Permission.objects.get(codename="change_advancedfilter")) + url = reverse(URL_NAME_CHANGE, args=(advanced_filter.pk,)) + + settings.ADVANCED_FILTER_EDIT_BY_USER = False + res = client.get(url) + assert res.status_code == 200 + + +def test_change_and_goto(client, user, settings, advanced_filter): + user.user_permissions.add(Permission.objects.get(codename="change_advancedfilter")) + url = reverse(URL_NAME_CHANGE, args=(advanced_filter.pk,)) + form_data = {"form-TOTAL_FORMS": 1, "form-INITIAL_FORMS": 0, "_save_goto": 1} + settings.ADVANCED_FILTER_EDIT_BY_USER = False + res = client.post(url, data=form_data) + assert res.status_code == 302 + url = res["location"] + assert url.endswith("%s?_afilter=1" % reverse(URL_NAME_CLIENT_CHANGELIST)) + + +def test_create_page_disabled(client, user): + user.user_permissions.add(Permission.objects.get(codename="add_advancedfilter")) + url = reverse(URL_NAME_ADD) + res = client.get(url) + assert res.status_code == 403 + assert AdvancedFilter.objects.count() == 0 diff --git a/advanced_filters/tests/test_creation.py b/advanced_filters/tests/test_creation.py new file mode 100644 index 0000000..de3cab0 --- /dev/null +++ b/advanced_filters/tests/test_creation.py @@ -0,0 +1,88 @@ +import pytest +from django.contrib.auth.models import Permission + +from ..models import AdvancedFilter + +try: + from django.urls import reverse_lazy +except ImportError: # Django < 2.0 + from django.core.urlresolvers import reverse_lazy + +URL_CLIENT_CHANGELIST = reverse_lazy("admin:customers_client_changelist") + + +def test_changelist_includes_form(user, settings, client): + user.user_permissions.add(Permission.objects.get(codename="change_client")) + settings.ADVANCED_FILTER_EDIT_BY_USER = False + res = client.get(URL_CLIENT_CHANGELIST) + assert res.status_code == 200 + title = ["Create advanced filter"] + fields = ["First name", "Language", "Sales Rep"] + response_content = res.content.decode("utf-8") + for part in title + fields: + assert part in response_content + + +@pytest.fixture +def form_data(): + return { + "form-TOTAL_FORMS": 1, + "form-INITIAL_FORMS": 0, + "action": "advanced_filters", + } + + +def test_create_form_validation(user, client, form_data): + user.user_permissions.add(Permission.objects.get(codename="change_client")) + res = client.post(URL_CLIENT_CHANGELIST, data=form_data) + assert res.status_code == 200 + form = res.context_data["advanced_filters"] + assert "title" in form.errors + assert "__all__" in form.errors + assert form.errors["title"] == ["This field is required."] + assert form.errors["__all__"] == ["Error validating filter forms"] + + +@pytest.fixture() +def good_data(form_data): + form_data.update( + { + "title": "Test title", + "form-0-field": "language", + "form-0-operator": "iexact", + "form-0-value": "ru", + } + ) + return form_data + + +@pytest.fixture() +def query(): + return ["language__iexact", "ru"] + + +def test_create_form_valid(user, client, good_data, query): + assert AdvancedFilter.objects.count() == 0 + user.user_permissions.add(Permission.objects.get(codename="change_client")) + res = client.post(URL_CLIENT_CHANGELIST, data=good_data) + assert res.status_code == 200 + form = res.context_data["advanced_filters"] + assert form.is_valid() + assert AdvancedFilter.objects.count() == 1 + + created_filter = AdvancedFilter.objects.order_by("pk").last() + + assert created_filter.title == good_data["title"] + assert list(created_filter.query.children[0]) == query + + # save with redirect to filter + good_data["_save_goto"] = 1 + res = client.post(URL_CLIENT_CHANGELIST, data=good_data) + assert res.status_code == 302 + assert AdvancedFilter.objects.count() == 2 + + created_filter = AdvancedFilter.objects.order_by("pk").last() + url = res["location"] + assert url.endswith("%s?_afilter=%s" % (URL_CLIENT_CHANGELIST, created_filter.pk)) + + assert list(created_filter.query.children[0]) == query diff --git a/advanced_filters/tests/test_get_field_choices_view.py b/advanced_filters/tests/test_get_field_choices_view.py new file mode 100644 index 0000000..ceda1d0 --- /dev/null +++ b/advanced_filters/tests/test_get_field_choices_view.py @@ -0,0 +1,136 @@ +import json +import sys + +import django +import pytest +from django.utils.encoding import force_text +from tests.factories import ClientFactory + +try: + from django.urls import reverse +except ImportError: # Django < 2.0 + from django.core.urlresolvers import reverse + + +URL_NAME = "afilters_get_field_choices" + + +def assert_json(content, expect): + assert json.loads(force_text(content)) == expect + + +def assert_view_error(client, error, exception=None, **view_kwargs): + """ Ensure view either raises exception or returns a 400 json error """ + view_url = reverse(URL_NAME, kwargs=view_kwargs) + + if exception is not None: + with pytest.raises(exception) as excinfo: + client.get(view_url) + assert error == str(excinfo.value) + return + + response = client.get(view_url) + assert response.status_code == 400 + assert_json(response.content, dict(error=error)) + + +if django.VERSION < (1, 7): + NO_APP_INSTALLED_ERROR = "No installed app/model: foo.test" + NO_MODEL_ERROR = "No installed app/model: reps.Foo" +else: + NO_APP_INSTALLED_ERROR = "No installed app with label 'foo'." + NO_MODEL_ERROR = "App 'reps' doesn't have a 'Foo' model." + + +if "PyPy" in getattr(sys, "subversion", ()): + ARGUMENT_LENGTH_ERROR = "expected length 2, got 1" +elif sys.version_info >= (3, 5): + ARGUMENT_LENGTH_ERROR = "not enough values to unpack (expected 2, got 1)" +else: + ARGUMENT_LENGTH_ERROR = "need more than 1 value to unpack" + +MISSING_FIELD_ERROR = "SalesRep has no field named 'baz'" + + +def test_invalid_view_kwargs(client): + assert_view_error(client, "GetFieldChoices view requires 2 arguments") + assert_view_error( + client, ARGUMENT_LENGTH_ERROR, model="a", field_name="b", exception=ValueError + ) + assert_view_error( + client, NO_APP_INSTALLED_ERROR, model="foo.test", field_name="baz" + ) + assert_view_error(client, NO_MODEL_ERROR, model="reps.Foo", field_name="b") + assert_view_error( + client, MISSING_FIELD_ERROR, model="reps.SalesRep", field_name="baz" + ) + + +def test_field_with_choices(client): + view_url = reverse( + URL_NAME, kwargs=dict(model="customers.Client", field_name="language") + ) + response = client.get(view_url) + assert_json( + response.content, + { + "results": [ + {"id": "en", "text": "English"}, + {"id": "it", "text": "Italian"}, + {"id": "sp", "text": "Spanish"}, + ] + }, + ) + + +@pytest.fixture +def three_clients(user): + return ClientFactory.create_batch(3, assigned_to=user) + + +def test_disabled_field(three_clients, client, settings): + settings.ADVANCED_FILTERS_DISABLE_FOR_FIELDS = ("email",) + view_url = reverse( + URL_NAME, kwargs=dict(model="customers.Client", field_name="email") + ) + response = client.get(view_url) + assert_json(response.content, {"results": []}) + + +def test_disabled_field_types(three_clients, client): + view_url = reverse( + URL_NAME, kwargs=dict(model="customers.Client", field_name="is_active") + ) + response = client.get(view_url) + assert_json(response.content, {"results": []}) + + +def test_database_choices(three_clients, client): + view_url = reverse( + URL_NAME, kwargs=dict(model="customers.Client", field_name="email") + ) + response = client.get(view_url) + assert_json( + response.content, + {"results": [dict(id=e.email, text=e.email) for e in three_clients]}, + ) + + +def test_more_than_max_database_choices(user, client, settings): + settings.ADVANCED_FILTERS_MAX_CHOICES = 4 + ClientFactory.create_batch(5, assigned_to=user) + view_url = reverse(URL_NAME, kwargs=dict(model="customers.Client", field_name="id")) + response = client.get(view_url) + assert_json(response.content, {"results": []}) + + +def test_distinct_database_choices(user, client, settings): + settings.ADVANCED_FILTERS_MAX_CHOICES = 4 + ClientFactory.create_batch(5, assigned_to=user, email="foo@bar.com") + view_url = reverse( + URL_NAME, kwargs=dict(model="customers.Client", field_name="email") + ) + response = client.get(view_url) + assert_json( + response.content, {"results": [{"id": "foo@bar.com", "text": "foo@bar.com"}]} + ) diff --git a/advanced_filters/tests/test_models.py b/advanced_filters/tests/test_models.py index 955cb16..f6c777d 100644 --- a/advanced_filters/tests/test_models.py +++ b/advanced_filters/tests/test_models.py @@ -25,21 +25,21 @@ def setUp(self): def test_filter_by_user_empty(self): qs = AdvancedFilter.objects.filter_by_user(user=self.user) - self.assertEquals(qs.count(), 0) + self.assertEqual(qs.count(), 0) def test_filter_by_user_users(self): self.advancedfilter.users.add(self.user) qs = AdvancedFilter.objects.filter_by_user(user=self.user) - self.assertEquals(qs.count(), 1) + self.assertEqual(qs.count(), 1) def test_filter_by_user_groups(self): self.advancedfilter.groups.add(self.group) qs = AdvancedFilter.objects.filter_by_user(user=self.user) - self.assertEquals(qs.count(), 1) + self.assertEqual(qs.count(), 1) def test_list_fields(self): self.advancedfilter.query = Q(some_field__iexact='some_value') diff --git a/advanced_filters/tests/test_q_serializer.py b/advanced_filters/tests/test_q_serializer.py index a098e8d..41bae32 100644 --- a/advanced_filters/tests/test_q_serializer.py +++ b/advanced_filters/tests/test_q_serializer.py @@ -19,7 +19,7 @@ def setUp(self): def test_serialize_q(self): res = self.s.serialize(self.query_a) - self.assertEquals(res, self.correct_query) + self.assertEqual(res, self.correct_query) def test_jsondump_q(self): jres = self.s.dumps(self.query_a) diff --git a/advanced_filters/tests/test_usage.py b/advanced_filters/tests/test_usage.py new file mode 100644 index 0000000..0155093 --- /dev/null +++ b/advanced_filters/tests/test_usage.py @@ -0,0 +1,79 @@ +import pytest +from django.contrib.auth.models import Permission +from django.db.models import Q +from tests.factories import ClientFactory, SalesRepFactory + +from ..admin import AdvancedListFilters +from ..models import AdvancedFilter +from .factories import AdvancedFilterFactory + +try: + from django.urls import reverse +except ImportError: # Django < 2.0 + from django.core.urlresolvers import reverse + + +URL_NAME_CLIENT_CHANGELIST = "admin:customers_client_changelist" + + +@pytest.fixture +def user(db): + user = SalesRepFactory() + user.user_permissions.add(Permission.objects.get(codename="change_client")) + return user + + +@pytest.fixture() +def client(client, user): + client.force_login(user) + return client + + +@pytest.fixture +def advanced_filter(user): + af = AdvancedFilterFactory.build( + title="Russian speakers", url="foo", model="customers.Client", created_by=user + ) + af.query = Q(language="ru") + af.save() + return af + + +@pytest.fixture(autouse=True) +def clients(user): + ClientFactory.create_batch(8, assigned_to=user, language="en") + ClientFactory.create_batch(2, assigned_to=user, language="ru") + + +def test_filters_not_available(client, advanced_filter): + url = reverse(URL_NAME_CLIENT_CHANGELIST) + res = client.get(url, data={"_afilter": advanced_filter.pk}) + assert res.status_code == 200 + cl = res.context_data["cl"] + assert not any(isinstance(f, AdvancedListFilters) for f in cl.filter_specs) + # filter not applied due to user not being in list + if hasattr(cl, "queryset"): + assert cl.queryset.count() == 10 + + +def test_filters_available_to_users(client, user, advanced_filter): + advanced_filter.users.add(user) + url = reverse(URL_NAME_CLIENT_CHANGELIST) + res = client.get(url, data={"_afilter": advanced_filter.pk}) + assert res.status_code == 200 + cl = res.context_data["cl"] + assert any(isinstance(f, AdvancedListFilters) for f in cl.filter_specs) + if hasattr(cl, "queryset"): + assert cl.queryset.count() == 2 + + +def test_filters_available_to_groups(client, user, advanced_filter): + group = user.groups.create() + advanced_filter.groups.add(group) + url = reverse(URL_NAME_CLIENT_CHANGELIST) + res = client.get(url, data={"_afilter": advanced_filter.pk}) + assert res.status_code == 200 + cl = res.context_data["cl"] + assert cl.filter_specs + if hasattr(cl, "queryset"): + assert cl.queryset.count() == 2 diff --git a/advanced_filters/tests/test_views.py b/advanced_filters/tests/test_views.py deleted file mode 100644 index f264a59..0000000 --- a/advanced_filters/tests/test_views.py +++ /dev/null @@ -1,125 +0,0 @@ -import sys - -from django.test import TestCase -try: - from django.test import override_settings -except ImportError: - from django.test.utils import override_settings -from django.utils.encoding import force_text -try: - from django.urls import reverse -except ImportError: # Django < 2.0 - from django.core.urlresolvers import reverse -import django - -from tests import factories - - -class TestGetFieldChoicesView(TestCase): - url_name = 'afilters_get_field_choices' - - def setUp(self): - self.user = factories.SalesRep() - assert self.client.login(username='user', password='test') - - def assert_json(self, response, expect): - self.assertJSONEqual(force_text(response.content), expect) - - def assert_view_error(self, error, exception=None, **view_kwargs): - """ Ensure view either raises exception or returns a 400 json error """ - view_url = reverse(self.url_name, kwargs=view_kwargs) - if exception is not None: - self.assertRaisesMessage( - exception, error, self.client.get, view_url) - return - res = self.client.get(view_url) - assert res.status_code == 400 - self.assert_json(res, dict(error=error)) - - def test_invalid_args(self): - self.assert_view_error("GetFieldChoices view requires 2 arguments") - if 'PyPy' in getattr(sys, 'subversion', ()): - self.assert_view_error( - 'expected length 2, got 1', - model='a', field_name='b', exception=ValueError) - elif sys.version_info >= (3, 5): - self.assert_view_error( - 'not enough values to unpack (expected 2, got 1)', model='a', - field_name='b', exception=ValueError) - else: - self.assert_view_error( - 'need more than 1 value to unpack', model='a', - field_name='b', exception=ValueError) - if django.VERSION >= (1, 11): - self.assert_view_error("No installed app with label 'Foo'.", - model='Foo.test', field_name='baz') - self.assert_view_error("App 'reps' doesn't have a 'Foo' model.", - model='reps.Foo', field_name='b') - elif django.VERSION >= (1, 7): - self.assert_view_error("No installed app with label 'foo'.", - model='foo.test', field_name='baz') - self.assert_view_error("App 'reps' doesn't have a 'foo' model.", - model='reps.Foo', field_name='b') - else: - self.assert_view_error("No installed app/model: foo.test", - model='foo.test', field_name='baz') - self.assert_view_error("No installed app/model: reps.Foo", - model='reps.Foo', field_name='b') - if sys.version_info >= (3, 3) or django.VERSION >= (1, 11): - expected_exception = "SalesRep has no field named 'baz'" - else: - expected_exception = "SalesRep has no field named u'baz'" - self.assert_view_error(expected_exception, - model='reps.SalesRep', field_name='baz') - - def test_field_with_choices(self): - view_url = reverse(self.url_name, kwargs=dict( - model='customers.Client', field_name='language')) - res = self.client.get(view_url) - self.assert_json(res, { - 'results': [ - {'id': 'en', 'text': 'English'}, - {'id': 'it', 'text': 'Italian'}, - {'id': 'sp', 'text': 'Spanish'} - ] - }) - - @override_settings(ADVANCED_FILTERS_DISABLE_FOR_FIELDS=('email',)) - def test_disabled_field(self): - factories.Client.create_batch(3, assigned_to=self.user) - view_url = reverse(self.url_name, kwargs=dict( - model='customers.Client', field_name='email')) - res = self.client.get(view_url) - self.assert_json(res, {'results': []}) - - def test_disabled_field_types(self): - factories.Client.create_batch(3, assigned_to=self.user) - view_url = reverse(self.url_name, kwargs=dict( - model='customers.Client', field_name='is_active')) - res = self.client.get(view_url) - self.assert_json(res, {'results': []}) - - def test_database_choices(self): - clients = factories.Client.create_batch(3, assigned_to=self.user) - view_url = reverse(self.url_name, kwargs=dict( - model='customers.Client', field_name='email')) - res = self.client.get(view_url) - self.assert_json(res, { - 'results': [dict(id=e.email, text=e.email) for e in clients] - }) - - @override_settings(ADVANCED_FILTERS_MAX_CHOICES=4) - def test_more_than_max_database_choices(self): - factories.Client.create_batch(5, assigned_to=self.user) - view_url = reverse(self.url_name, kwargs=dict( - model='customers.Client', field_name='id')) - res = self.client.get(view_url) - self.assert_json(res, {'results': []}) - - @override_settings(ADVANCED_FILTERS_MAX_CHOICES=4) - def test_distinct_database_choices(self): - factories.Client.create_batch(5, assigned_to=self.user, email="foo@bar.com") - view_url = reverse(self.url_name, kwargs=dict( - model='customers.Client', field_name='email')) - res = self.client.get(view_url) - self.assert_json(res, {'results': [{'id': 'foo@bar.com', 'text': 'foo@bar.com'}]}) diff --git a/test-reqs.txt b/test-reqs.txt index 05f2926..e11e70d 100644 --- a/test-reqs.txt +++ b/test-reqs.txt @@ -1,3 +1,4 @@ -coveralls==0.5 -factory-boy==2.5.2 -pep8==1.6.2 +coveralls +factory-boy==2.12.0 +pycodestyle==2.5.0 +pytest-django==3.9.0 diff --git a/tests/factories.py b/tests/factories.py index b977a14..81f5ff3 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -1,7 +1,7 @@ import factory -class SalesRep(factory.django.DjangoModelFactory): +class SalesRepFactory(factory.django.DjangoModelFactory): class Meta: model = 'reps.SalesRep' django_get_or_create = ('username',) @@ -15,7 +15,7 @@ class Meta: @classmethod def _prepare(cls, create, **kwargs): password = kwargs.pop('password', None) - user = super(SalesRep, cls)._prepare(create, **kwargs) + user = super(SalesRepFactory, cls)._prepare(create, **kwargs) if password: user.set_password(password) if create: @@ -23,7 +23,7 @@ def _prepare(cls, create, **kwargs): return user -class Client(factory.django.DjangoModelFactory): +class ClientFactory(factory.django.DjangoModelFactory): class Meta: model = 'customers.Client' diff --git a/tox.ini b/tox.ini index 58d2dc5..675e98d 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ envlist = py37-d{20,21} pypy-d{17,18,19,110,111} -[pep8] +[pycodestyle] max-line-length = 120 [testenv] @@ -26,4 +26,4 @@ deps = commands = pip install -e . coverage run -m py.test advanced_filters - pep8 --exclude=urls.py,migrations,.ropeproject -v advanced_filters + pycodestyle --exclude=urls.py,migrations,.ropeproject -v advanced_filters