From 7907497c478a106c734d68da6857cf339a0b93ae Mon Sep 17 00:00:00 2001 From: Vasil Slavov Date: Thu, 20 Jun 2019 15:00:54 +0300 Subject: [PATCH] Add test configuration and method tests --- django_enum_choices/__init__.py | 1 - django_enum_choices/fields.py | 2 +- django_enum_choices/requirements.txt | 5 + django_enum_choices/tests/__init__.py | 0 django_enum_choices/tests/settings.py | 16 ++ django_enum_choices/tests/test_fields.py | 208 ++++++++++++++++++ django_enum_choices/tests/testapp/apps.py | 6 + .../tests/testapp/enumerations.py | 13 ++ django_enum_choices/tests/testapp/models.py | 13 ++ pytest.ini | 4 + setup.cfg | 2 + 11 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 django_enum_choices/requirements.txt create mode 100644 django_enum_choices/tests/__init__.py create mode 100644 django_enum_choices/tests/settings.py create mode 100644 django_enum_choices/tests/test_fields.py create mode 100644 django_enum_choices/tests/testapp/apps.py create mode 100644 django_enum_choices/tests/testapp/enumerations.py create mode 100644 django_enum_choices/tests/testapp/models.py create mode 100644 pytest.ini create mode 100644 setup.cfg diff --git a/django_enum_choices/__init__.py b/django_enum_choices/__init__.py index a6630ed..e69de29 100644 --- a/django_enum_choices/__init__.py +++ b/django_enum_choices/__init__.py @@ -1 +0,0 @@ -name = 'django_enum_choices' diff --git a/django_enum_choices/fields.py b/django_enum_choices/fields.py index a694fd0..d559a57 100644 --- a/django_enum_choices/fields.py +++ b/django_enum_choices/fields.py @@ -75,7 +75,7 @@ def get_swapped_instance(self, base, **kwargs): ) if base is EnumCharField: - max_length = self._calculate_max_length() + max_length = self._calculate_max_length(**kwargs) # Removing `max_length` as it is calculated explicitly. kwargs.pop('max_length', None) diff --git a/django_enum_choices/requirements.txt b/django_enum_choices/requirements.txt new file mode 100644 index 0000000..1ad0032 --- /dev/null +++ b/django_enum_choices/requirements.txt @@ -0,0 +1,5 @@ +Django==2.2.2 +djangorestframework==3.9.4 +flake8==3.7.7 +pytest==4.6.3 +pytest-django==3.5.0 diff --git a/django_enum_choices/tests/__init__.py b/django_enum_choices/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_enum_choices/tests/settings.py b/django_enum_choices/tests/settings.py new file mode 100644 index 0000000..db09828 --- /dev/null +++ b/django_enum_choices/tests/settings.py @@ -0,0 +1,16 @@ +from __future__ import unicode_literals + +DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}} + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.sites", + "tests.testapp.apps.TestAppConfig" +] + +SITE_ID = 1 + +SECRET_KEY = "test" diff --git a/django_enum_choices/tests/test_fields.py b/django_enum_choices/tests/test_fields.py new file mode 100644 index 0000000..f1d2ac8 --- /dev/null +++ b/django_enum_choices/tests/test_fields.py @@ -0,0 +1,208 @@ +from enum import Enum + +from django.test import TestCase + +from django_enum_choices.fields import EnumChoiceFieldBuilder, EnumIntegerField, EnumCharField, EnumChoiceField +from django_enum_choices.exceptions import EnumChoiceFieldException +from .testapp.enumerations import CharTestEnum, IntTestEnum + + +class EnumChoiceFieldBuilderTests(TestCase): + def test_builder_initializes_string_choice_values(self): + builder = EnumChoiceFieldBuilder(enum_class=CharTestEnum) + + self.assertEqual( + builder.enum_class, + CharTestEnum + ) + self.assertEqual( + builder._choices, + ['first', 'second', 'third'] + ) + + def test_builder_initializes_int_choice_values(self): + builder = EnumChoiceFieldBuilder(enum_class=IntTestEnum) + + self.assertEqual( + builder.enum_class, + IntTestEnum + ) + self.assertEqual( + builder._choices, + [1, 2, 3] + ) + + def test_builder_packs_string_choices_correctly(self): + builder = EnumChoiceFieldBuilder(enum_class=CharTestEnum) + + packed = builder._pack_choices() + + self.assertEqual( + list(packed), + [ + ('first', 'first'), + ('second', 'second'), + ('third', 'third') + ] + ) + + def test_builder_packs_int_choices_correctly(self): + builder = EnumChoiceFieldBuilder(enum_class=IntTestEnum) + + packed = builder._pack_choices() + + self.assertEqual( + list(packed), + [ + (1, 1), + (2, 2), + (3, 3) + ] + ) + + def test_get_inferred_base_returns_intfield_instance_when_all_choice_types_are_int(self): + builder = EnumChoiceFieldBuilder(enum_class=IntTestEnum) + + base = builder.get_inferred_base() + + self.assertIs(base, EnumIntegerField) + + def test_get_inferred_base_returns_charfield_instance_when_all_choice_types_are_str(self): + builder = EnumChoiceFieldBuilder(enum_class=CharTestEnum) + + base = builder.get_inferred_base() + + self.assertIs(base, EnumCharField) + + def test_get_inferred_base_raises_exception_when_choice_types_differ(self): + class FailingEnum(Enum): + FOO = 1 + BAR = '2' + + builder = EnumChoiceFieldBuilder(enum_class=FailingEnum) + + with self.assertRaisesMessage( + EnumChoiceFieldException, + 'All choices in provided enum class must be of the same type' + ): + + builder.get_inferred_base() + + def test_calculate_max_length_returns_longest_choice_length_if_max_length_not_in_kwargs_and_longer_than_255( + self + ): + class LongStringEnum(Enum): + FOO = 'foo' + BAR = 'A' * 256 + + builder = EnumChoiceFieldBuilder(enum_class=LongStringEnum) + + result = builder._calculate_max_length() + + self.assertEqual(result, 256) + + def test_calculate_max_length_returns_255_when_longest_choice_is_less_than_255_and_max_length_not_in_kwargs( + self + ): + class ShortStringEnum(Enum): + FOO = 'foo' + BAR = 'bar' + + builder = EnumChoiceFieldBuilder(enum_class=ShortStringEnum) + + result = builder._calculate_max_length() + + self.assertEqual(result, 255) + + def test_calculate_max_length_returns_255_when_max_length_in_kwargs_and_less_than_255(self): + builder = EnumChoiceFieldBuilder(enum_class=CharTestEnum) + + result = builder._calculate_max_length(max_length=50) + + self.assertEqual(result, 255) + + def test_calculate_max_length_returns_max_length_from_kwargs_more_than_255(self): + builder = EnumChoiceFieldBuilder(enum_class=CharTestEnum) + + result = builder._calculate_max_length(max_length=256) + + self.assertEqual(result, 256) + + def test_get_swapped_instance_returns_correct_model_field_instance(self): + with self.subTest('When base is `EnumIntegerField`'): + builder = EnumChoiceFieldBuilder(enum_class=IntTestEnum) + + instance = builder.get_swapped_instance(base=EnumIntegerField) + + self.assertIsInstance(instance, EnumIntegerField) + + with self.subTest('When base is `EnumCharField`'): + builder = EnumChoiceFieldBuilder(enum_class=CharTestEnum) + + instance = builder.get_swapped_instance(base=EnumCharField) + + self.assertIsInstance(instance, EnumCharField) + + +class EnumChoiceFieldTests(TestCase): + def test_raises_exception_when_enum_class_is_not_enumeration(self): + class FailingEnum: + FOO = 'foo' + BAR = 'bar' + + with self.assertRaisesMessage( + EnumChoiceFieldException, + '`enum_class` argument must be a child of `Enum`' + ): + EnumChoiceField(enum_class=FailingEnum) + + def test_instance_returns_EnumCharField_when_choices_are_strings(self): + instance = EnumChoiceField(enum_class=CharTestEnum) + + self.assertIsInstance(instance, EnumCharField) + + def test_instance_returns_EnumIntegerField_when_choices_are_integers(self): + instance = EnumChoiceField(enum_class=IntTestEnum) + + self.assertIsInstance(instance, EnumIntegerField) + + def test_get_prep_value_returns_primitive_value_when_base_is_integer(self): + instance = EnumChoiceField(enum_class=IntTestEnum) + + result = instance.get_prep_value(IntTestEnum.FIRST) + + self.assertEqual(result, 1) + + def test_get_prep_value_returns_primitive_value_when_base_is_string(self): + instance = EnumChoiceField(enum_class=CharTestEnum) + + result = instance.get_prep_value(CharTestEnum.FIRST) + + self.assertEqual(result, 'first') + + def test_from_db_value_returns_None_when_value_is_none(self): + instance = EnumChoiceField(enum_class=IntTestEnum) + + result = instance.from_db_value(None, None, None) + + self.assertIsNone(result) + + def test_from_db_value_returns_enum_value_when_base_is_integer(self): + instance = EnumChoiceField(enum_class=IntTestEnum) + + result = instance.from_db_value(1, None, None) + + self.assertEqual(result, IntTestEnum.FIRST) + + def test_from_db_value_returns_enum_value_when_base_is_string(self): + instance = EnumChoiceField(enum_class=CharTestEnum) + + result = instance.from_db_value('first', None, None) + + self.assertEqual(result, CharTestEnum.FIRST) + + def test_from_db_value_raises_exception_when_int_value_not_contained_in_enum_class(self): + instance = EnumChoiceField(enum_class=IntTestEnum) + + with self.assertRaises(EnumChoiceFieldException): + instance.from_db_value(7, None, None) diff --git a/django_enum_choices/tests/testapp/apps.py b/django_enum_choices/tests/testapp/apps.py new file mode 100644 index 0000000..039067d --- /dev/null +++ b/django_enum_choices/tests/testapp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TestAppConfig(AppConfig): + name = 'django_enum_choices.tests.testapp' + verbose_name = 'TestApp' diff --git a/django_enum_choices/tests/testapp/enumerations.py b/django_enum_choices/tests/testapp/enumerations.py new file mode 100644 index 0000000..db5f77f --- /dev/null +++ b/django_enum_choices/tests/testapp/enumerations.py @@ -0,0 +1,13 @@ +from enum import Enum + + +class CharTestEnum(Enum): + FIRST = 'first' + SECOND = 'second' + THIRD = 'third' + + +class IntTestEnum(Enum): + FIRST = 1 + SECOND = 2 + THIRD = 3 diff --git a/django_enum_choices/tests/testapp/models.py b/django_enum_choices/tests/testapp/models.py new file mode 100644 index 0000000..798f94b --- /dev/null +++ b/django_enum_choices/tests/testapp/models.py @@ -0,0 +1,13 @@ +from django.db import models + +from django_enum_choices.fields import EnumChoiceField + +from .enumerations import CharTestEnum, IntTestEnum + + +class IntegerEnumeratedModel(models.Model): + enumeration = EnumChoiceField(enum_class=IntTestEnum) + + +class StringEnumeratedModel(models.Model): + enumeration = EnumChoiceField(enum_class=CharTestEnum) diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..ced018a --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +DJANGO_SETTINGS_MODULE=tests.settings +django_find_project = false +python_paths = django_enum_choices diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..6deafc2 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 120