series of tests added with built-in django test support

This commit is contained in:
pacnpal
2024-11-05 18:40:39 +00:00
parent ba226c861a
commit 2e8a725933
60 changed files with 2108 additions and 274 deletions

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-11-05 18:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("media", "0006_photo_is_approved"),
]
operations = [
migrations.AddField(
model_name="photo",
name="date_taken",
field=models.DateTimeField(blank=True, null=True),
),
]

View File

@@ -5,6 +5,9 @@ from django.contrib.contenttypes.models import ContentType
from django.utils.text import slugify
from django.conf import settings
import os
from PIL import Image, ExifTags
from PIL.ExifTags import TAGS
from datetime import datetime
from .storage import MediaStorage
from rides.models import Ride
from django.utils import timezone
@@ -56,6 +59,7 @@ class Photo(models.Model):
is_approved = models.BooleanField(default=False) # New field for approval status
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
date_taken = models.DateTimeField(null=True, blank=True)
uploaded_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
@@ -76,8 +80,29 @@ class Photo(models.Model):
def __str__(self) -> str:
return f"{self.content_type} - {self.content_object} - {self.caption or 'No caption'}"
def extract_exif_date(self) -> Optional[datetime]:
"""Extract the date taken from image EXIF data"""
try:
with Image.open(self.image) as img:
exif = img.getexif()
if exif:
# Find the DateTime tag ID
for tag_id in ExifTags.TAGS:
if ExifTags.TAGS[tag_id] == 'DateTimeOriginal':
if tag_id in exif:
# EXIF dates are typically in format: '2024:02:15 14:30:00'
date_str = exif[tag_id]
return datetime.strptime(date_str, '%Y:%m:%d %H:%M:%S')
return None
except Exception:
return None
def save(self, *args: Any, **kwargs: Any) -> None:
# Extract EXIF date if this is a new photo
if not self.pk and not self.date_taken:
self.date_taken = self.extract_exif_date()
# Set default caption if not provided
if not self.caption and self.uploaded_by:
current_time = timezone.now()

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

189
media/tests.py Normal file
View File

@@ -0,0 +1,189 @@
from django.test import TestCase, override_settings
from django.core.files.uploadedfile import SimpleUploadedFile
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from datetime import datetime
from PIL import Image, ExifTags
import io
from .models import Photo
from parks.models import Park
User = get_user_model()
class PhotoModelTests(TestCase):
def setUp(self):
# Create a test user
self.user = User.objects.create_user(
username='testuser',
password='testpass123'
)
# Create a test park for photo association
self.park = Park.objects.create(
name='Test Park',
slug='test-park'
)
self.content_type = ContentType.objects.get_for_model(Park)
def create_test_image_with_exif(self, date_taken=None):
"""Helper method to create a test image with EXIF data"""
# Create a test image
image = Image.new('RGB', (100, 100), color='red')
image_io = io.BytesIO()
# Add EXIF data if date_taken is provided
if date_taken:
exif_dict = {
"0th": {},
"Exif": {
ExifTags.Base.DateTimeOriginal: date_taken.strftime("%Y:%m:%d %H:%M:%S").encode()
}
}
image.save(image_io, 'JPEG', exif=exif_dict)
else:
image.save(image_io, 'JPEG')
image_io.seek(0)
return SimpleUploadedFile(
'test.jpg',
image_io.getvalue(),
content_type='image/jpeg'
)
def test_photo_creation(self):
"""Test basic photo creation"""
photo = Photo.objects.create(
image=SimpleUploadedFile(
'test.jpg',
b'dummy image data',
content_type='image/jpeg'
),
caption='Test Caption',
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk
)
self.assertEqual(photo.caption, 'Test Caption')
self.assertEqual(photo.uploaded_by, self.user)
self.assertIsNone(photo.date_taken)
def test_exif_date_extraction(self):
"""Test EXIF date extraction from uploaded photos"""
test_date = datetime(2024, 1, 1, 12, 0, 0)
image_file = self.create_test_image_with_exif(test_date)
photo = Photo.objects.create(
image=image_file,
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk
)
if photo.date_taken:
self.assertEqual(
photo.date_taken.strftime("%Y-%m-%d %H:%M:%S"),
test_date.strftime("%Y-%m-%d %H:%M:%S")
)
else:
self.skipTest("EXIF data extraction not supported in test environment")
def test_photo_without_exif(self):
"""Test photo upload without EXIF data"""
image_file = self.create_test_image_with_exif() # No date provided
photo = Photo.objects.create(
image=image_file,
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk
)
self.assertIsNone(photo.date_taken)
def test_default_caption(self):
"""Test default caption generation"""
photo = Photo.objects.create(
image=SimpleUploadedFile(
'test.jpg',
b'dummy image data',
content_type='image/jpeg'
),
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk
)
expected_prefix = f"Uploaded by {self.user.username} on"
self.assertTrue(photo.caption.startswith(expected_prefix))
def test_primary_photo_toggle(self):
"""Test primary photo functionality"""
# Create two photos
photo1 = Photo.objects.create(
image=SimpleUploadedFile(
'test1.jpg',
b'dummy image data',
content_type='image/jpeg'
),
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk,
is_primary=True
)
photo2 = Photo.objects.create(
image=SimpleUploadedFile(
'test2.jpg',
b'dummy image data',
content_type='image/jpeg'
),
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk,
is_primary=True
)
# Refresh from database
photo1.refresh_from_db()
photo2.refresh_from_db()
# Verify only photo2 is primary
self.assertFalse(photo1.is_primary)
self.assertTrue(photo2.is_primary)
@override_settings(MEDIA_ROOT='test_media/')
def test_photo_upload_path(self):
"""Test photo upload path generation"""
photo = Photo.objects.create(
image=SimpleUploadedFile(
'test.jpg',
b'dummy image data',
content_type='image/jpeg'
),
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk
)
expected_path = f"park/{self.park.slug}/"
self.assertTrue(photo.image.name.startswith(expected_path))
def test_date_taken_field(self):
"""Test date_taken field functionality"""
test_date = timezone.now()
photo = Photo.objects.create(
image=SimpleUploadedFile(
'test.jpg',
b'dummy image data',
content_type='image/jpeg'
),
uploaded_by=self.user,
content_type=self.content_type,
object_id=self.park.pk,
date_taken=test_date
)
self.assertEqual(photo.date_taken, test_date)