diff --git a/.coveragerc b/.coveragerc index 90c8c7c4..04df1ec9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,5 @@ [run] include = contact/*, content/*, glossary/*, message/*, photograph/*, quiz/*, slideshow/* -omit = *migrations*, */tests/*, .*, *config*, manage.py, some/, dist/, sample_project/ +omit = *migrations*, */tests/*, .*, *config*, manage.py, some/, dist/, sample_project/*, cov_html/* plugins = django_coverage_plugin diff --git a/.travis.yml b/.travis.yml index 5a1f4f17..f3cc0c71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,9 @@ jobs: - stage: "Unit tests and linting" name: "Unit tests with Python 3.7" before_script: - - psql -c "CREATE DATABASE test_db_app;" -U postgres - - psql -c "CREATE USER db_user WITH PASSWORD 'db_pass';" -U postgres + - psql -c "CREATE DATABASE local_db;" -U postgres + - psql -c "CREATE USER localuser WITH PASSWORD 'localpass';" -U postgres + - psql -c "ALTER USER localuser CREATEDB;" script: make ci after_success: codecov - name: "Formatting with black" diff --git a/sample_project/sample_project/settings.py b/sample_project/sample_project/settings.py index 1fe43a83..ae7ffbe6 100644 --- a/sample_project/sample_project/settings.py +++ b/sample_project/sample_project/settings.py @@ -129,6 +129,12 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ +# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root +MEDIA_ROOT = "./media" + +# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url +MEDIA_URL = "/media/" + STATIC_URL = "/static/" PROFILES_SERIALIZER_MODULE, PROFILES_SERIALIZER = ( diff --git a/solid_backend/photograph/forms.py b/solid_backend/photograph/forms.py index e2ea8427..b9fb2f6d 100644 --- a/solid_backend/photograph/forms.py +++ b/solid_backend/photograph/forms.py @@ -1,8 +1,6 @@ from django import forms from mutagen import File -from .models import Photograph - class PhotographForm(forms.ModelForm): """ @@ -41,7 +39,7 @@ def save(self, commit=True): pixel_number = self.cleaned_data.get("pixel_number") instance = super(PhotographForm, self).save(commit=False) - + print(instance.audio) if length_value and pixel_number: instance.img_original_scale = length_value * length_unit / pixel_number diff --git a/solid_backend/photograph/tests/conftest_files/100x100_test_img.jpg b/solid_backend/photograph/tests/conftest_files/100x100_test_img.jpg new file mode 100644 index 00000000..f8be98d1 Binary files /dev/null and b/solid_backend/photograph/tests/conftest_files/100x100_test_img.jpg differ diff --git a/solid_backend/photograph/tests/conftest_files/general_conftest.py b/solid_backend/photograph/tests/conftest_files/general_conftest.py index b4cb7f8f..b77f2dd0 100644 --- a/solid_backend/photograph/tests/conftest_files/general_conftest.py +++ b/solid_backend/photograph/tests/conftest_files/general_conftest.py @@ -1,8 +1,63 @@ import pytest +from django.contrib.admin.sites import AdminSite +from django.core.files.uploadedfile import SimpleUploadedFile +from solid_backend.photograph.admin import PhotographAdmin from solid_backend.photograph.models import Photograph +CURRENT_RELATIVE_PATH = "solid_backend/photograph/tests/conftest_files/" +test_img_filename = "{}100x100_test_img.jpg".format(CURRENT_RELATIVE_PATH) +test_audio_filename = "{}test_mp3_file.mp3".format(CURRENT_RELATIVE_PATH) + @pytest.fixture def photograph_model_class(): return Photograph + + +@pytest.fixture +def photograph_admin_form(): + return PhotographAdmin(Photograph, AdminSite()).get_form(request=None) + + +@pytest.fixture +def valid_photograph_data(): + data = { + "length_value": 5.0, # 5 cm + "length_unit": 0.01, # cm + "pixel_number": 100, # per 100 pixel + "img_alt": "Alternative text to describe the image.", + } + return data + + +@pytest.fixture +def valid_photograph_files(): + files = { + "img": SimpleUploadedFile( + test_img_filename, open(test_img_filename, "rb").read() + ), + "audio": SimpleUploadedFile( + test_audio_filename, open(test_audio_filename, "rb").read() + ), + } + return files + + +@pytest.fixture +def valid_img(): + return { + "img": SimpleUploadedFile( + test_img_filename, open(test_img_filename, "rb").read() + ) + } + + +@pytest.fixture +def photograph_object( + photograph_admin_form, valid_photograph_data, valid_photograph_files +): + form = photograph_admin_form(valid_photograph_data, valid_photograph_files) + form.is_valid() + instance = form.save() + return instance diff --git a/solid_backend/photograph/tests/conftest_files/test_mp3_file.mp3 b/solid_backend/photograph/tests/conftest_files/test_mp3_file.mp3 new file mode 100644 index 00000000..8bbda403 Binary files /dev/null and b/solid_backend/photograph/tests/conftest_files/test_mp3_file.mp3 differ diff --git a/solid_backend/photograph/tests/test_forms.py b/solid_backend/photograph/tests/test_forms.py new file mode 100644 index 00000000..dfaeb3fb --- /dev/null +++ b/solid_backend/photograph/tests/test_forms.py @@ -0,0 +1,66 @@ +import pytest +from django import forms + + +class TestPhotographModelForm: + def test_photograph_admin_form_exists(self): + from solid_backend.photograph.forms import PhotographForm + + def test_form_has_length_value_field(self, photograph_admin_form): + field = photograph_admin_form.base_fields.get("length_value") + assert field + assert isinstance(field, forms.FloatField) + + def test_form_has_length_unit_field(self, photograph_admin_form): + field = photograph_admin_form.base_fields.get("length_unit") + assert field + assert isinstance(field, forms.TypedChoiceField) + + def test_form_has_pixel_number_field(self, photograph_admin_form): + field = photograph_admin_form.base_fields.get("pixel_number") + assert field + assert isinstance(field, forms.IntegerField) + + def test_form_has_unit_choices(self, photograph_admin_form): + assert hasattr(photograph_admin_form, "LENGTH_UNIT_CHOICES") + + choices = [ + (1.00, "m"), + (0.01, "cm"), + (0.001, "mm"), + ] + + assert photograph_admin_form.LENGTH_UNIT_CHOICES == choices + + @pytest.mark.django_db + def test_audio_file_duration(self, photograph_object): + assert photograph_object.audio_duration == 2.0 + + @pytest.mark.django_db + def test_scale_factor_calculation(self, photograph_object): + assert photograph_object.img_original_scale == 5e-4 + + @pytest.mark.django_db + def test_delete_scale_factor( + self, valid_photograph_data, photograph_object, photograph_admin_form + ): + valid_photograph_data["pixel_number"] = 0 + form = photograph_admin_form(valid_photograph_data, instance=photograph_object) + form.is_valid() + instance = form.save() + + assert instance.img_original_scale is None + + @pytest.mark.django_db + def test_audio_duration_without_file( + self, photograph_object, valid_photograph_data, valid_img, photograph_admin_form + ): + + form = photograph_admin_form( + valid_photograph_data, files={"audio": False}, instance=photograph_object + ) + form.is_valid() + instance = form.save() + + assert not instance.audio + assert instance.audio_duration is None diff --git a/test_settings.py b/test_settings.py index 1348dc63..44d58f95 100644 --- a/test_settings.py +++ b/test_settings.py @@ -33,8 +33,9 @@ "solid_backend.message.apps.MessageConfig", "solid_backend.slideshow.apps.SlideshowConfig", "solid_backend.photograph.apps.PhotographConfig", - "django_cleanup.apps.CleanupConfig", # Should be placed last! "django_extensions", + "django_cleanup.apps.CleanupConfig", # Should be placed last! + ] MIDDLEWARE = [ @@ -71,10 +72,14 @@ # ------------------------------------------------------------------------------ # See: https://docs.djangoproject.com/en/dev/ref/settings/#databases DATABASES = { - # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ - "default": env.db( - "DATABASE_URL", default="postgres://postgres@localhost:5432/postgres" - ), + "default": { + "ENGINE": "django.db.backends.postgresql_psycopg2", + "NAME": "local_db", + "USER": "localuser", + "PASSWORD": "localpass", + "HOST": "localhost", + "PORT": "", + } } DATABASES["default"]["ATOMIC_REQUESTS"] = True @@ -106,7 +111,7 @@ # MEDIA CONFIGURATION # ------------------------------------------------------------------------------ # See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root -MEDIA_ROOT = "/media" +MEDIA_ROOT = "./media" # See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url MEDIA_URL = "/media/"