15 Commits

14 changed files with 383 additions and 129 deletions

View File

@@ -11,6 +11,7 @@ pipenv = "*"
wheel = "*"
twine = "*"
pandoc ="*"
pylint-django ="*"
[packages]
django = "*"
@@ -18,6 +19,7 @@ easy-thumbnails = "*"
image = "*"
django-widget-tweaks = "*"
django-taggit = "*"
# Commented out to not explicitly specify Python 3 subversion.
# [requires]
# python_version = "3.8"
[requires]
python_version = "3.7"

View File

@@ -6,15 +6,15 @@
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from .models import *
from lostplaces_app.models import *
from .forms import ExplorerCreationForm, ExplorerChangeForm
from lostplaces_app.forms import ExplorerCreationForm, ExplorerChangeForm
# Register your models here.
class VoucherAdmin(admin.ModelAdmin):
fields = ['code', 'expires', 'created']
readonly_fields = ['created']
fields = ['code', 'expires_when', 'created_when']
readonly_fields = ['created_when']
admin.site.register(Explorer)
admin.site.register(Voucher, VoucherAdmin)

View File

@@ -33,7 +33,7 @@ class Explorer(models.Model):
)
def __str__(self):
return self.user.name
return self.user.username
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
@@ -54,11 +54,11 @@ class Voucher(models.Model):
"""
code = models.CharField(unique=True, max_length=30)
created = models.DateTimeField(auto_now_add=True)
expires = models.DateField()
created_when = models.DateTimeField(auto_now_add=True)
expires_when = models.DateTimeField()
def __str__(self):
return "Voucher " + str(self.pk)
return "Voucher " + str(self.code)
class Place (models.Model):

View File

@@ -1,13 +1,11 @@
from django.db import models as django_models
from django.test import TestCase
from django.contrib.auth.models import User
class BaseData(TestCase):
def mock_user():
explorer_list = User.objects.all()
if len(explorer_list) <= 0:
return User.objects.create_user(
@classmethod
def setUpTestData(cls):
User.objects.create_user(
username='testpeter',
password='Develop123'
)
else:
return explorer_list[0]
).save()

View File

@@ -1,58 +1,106 @@
from django.db import models
from django.contrib.auth.models import User
from django.core.exceptions import FieldDoesNotExist
from django.test import TestCase
class TestModel:
# Creating a test user
class ModelTestCase:
'''
Base class for Lostplaces models
'''
model = None
model_name = None
def _test_field(self, field_name, field_class):
def setUp(self):
self.object = self.model.objects.get(id=1)
self.model_name = type(self.model).__name__
def _test_field(self, field_name, field_class, must_have={}, must_not_have={}):
'''
Tests if a field exists under the given name and
if the field is of the right type
if the field is of the right type.
Also checks if the field has the given must_have attributes
and does not have any of the must_not_have attributes. If you
dont care about the value of the attribute you can just set it to
something that fullfills value == False (i.e. '' or 0)
'''
field = self.object._meta.get_field(field_name)
self.assertTrue(
field,
msg="%s has no field named '%s'" % (
self.model_name,
field_name
try:
field = self.object._meta.get_field(field_name)
except FieldDoesNotExist:
self.fail(
'Expecting %s to have a field named \'%s\'' % (
self.model_name,
field_name
)
)
)
self.assertEqual(
type(field), field_class,
msg='%s.%s name field is no CharField' % (
type(field), field_class,
msg='Expecting type of %s.%s to be %s' % (
self.model_name,
field_name
field_name,
field_class.__name__
)
)
for key, value in must_have.items():
if value:
self.assertEqual(getattr(field, key), value,
msg='Expeting %s.%s.%s to be \'%s\'' % (
self.model_name,
field_name,
key,
value
)
)
else:
self.assertTrue(hasattr(field, key),
msg='Expeting %s.%s to have \'%s\'' % (
self.model_name,
field_name,
key
)
)
for key, value in must_not_have.items():
if value:
self.assertTrue(getattr(field, key) != value,
msg='Expeting %s.%s.%s to not be \'%s\'' % (
self.model_name,
field_name,
key,
value
)
)
else:
self.assertFalse(hasattr(field, value),
msg='Expeting %s.%s to not have \'%s\'' % (
self.model_name,
field_name,
key
)
)
return field
def _test_char_field(self, field_name, min_length, max_length):
def _test_char_field(self, field_name, min_length, max_length, must_have={}, must_hot_have={}):
'''
Tests if the given field is a char field and if its max_length
is in min_length and max_legth
'''
field = self._test_field(field_name, models.CharField)
self.assertEqual(
type(field), models.CharField,
msg='%s.%s name field is no CharField' % (
self.model_name,
field_name
)
)
field = self._test_field(
field_name, models.CharField, must_have, must_hot_have)
self.assertTrue(
field.max_length in range(min_length, max_length),
msg='%s.%s field max_length not in range of %d and %d' % (
msg='Expeting %s.%s field max_length to be in the range of %d and %d' % (
self.model_name,
field_name,
min_length,
max_length
)
)
)
def _test_float_field(self, field_name, min_value=None, max_value=None):
def _test_float_field(self, field_name, min_value=None, max_value=None, must_have={}, must_hot_have={}):
'''
Tests if the field is a floatfield. If min_value and/or max_value are passed,
the validators of the field are also checked. The validator list of the field should
@@ -61,21 +109,23 @@ class TestModel:
[MinValueValidator] if only min_value is passed,
[MaxValueValidator] if only max_value is passed
'''
field = self._test_field(field_name, models.FloatField)
field = self._test_field(
field_name, models.FloatField, must_have, must_hot_have)
if min_value:
self.assertTrue(
len(field.validators) >= 1,
msg='%s.%s first validator should check minimum' % (
msg='Expecting the first valiator of %s.%s to check the minimum' % (
self.model_name,
field_name
)
)
)
self.assertEqual(
field.validators[0].limit_value,
min_value,
msg='%s.%s min value missmatch' % (
msg='Expecting the min value of %s.%s min to be at least %d' % (
self.model_name,
field_name
field_name,
min_value
)
)
if max_value:
@@ -84,38 +134,41 @@ class TestModel:
index += 1
self.assertTrue(
len(field.validators) >= index+1,
msg='%s.%s second validator should check maximum' % (
self.model_name,
field_name
)
)
self.assertEqual(
field.validators[1].limit_value,
max_value,
msg='%s.%s max value missmatch' % (
msg='Expecting the second valiator of %s.%s to check the maximum' % (
self.model_name,
field_name
)
)
self.assertEqual(
field.validators[1].limit_value,
max_value,
msg='Expecting the max value of %s.%s min to be at most %d' % (
self.model_name,
field_name,
max_value
)
)
class TestSubmittable(TestModel):
model_name='<Class>'
class SubmittableTestCase(ModelTestCase):
model_name = '<Class>'
related_name = None
nullable = False
def test_submitted_when(self):
submitted_when = self._test_field('submitted_when', models.DateTimeField)
self.assertTrue(submitted_when.auto_now_add,
msg='%s.submitted_when should be auto_now_add' % (
self.model_name
)
submitted_when = self._test_field(
'submitted_when',
models.DateTimeField,
must_have={'auto_now_add': True}
)
def test_submitted_by(self):
submitted_by = self._test_field('submitted_by',models.ForeignKey)
submitted_by = self._test_field('submitted_by', models.ForeignKey)
if self.related_name:
self.assertEqual(submitted_by.remote_field.related_name, self.related_name)
self.assertEqual(
submitted_by.remote_field.related_name, self.related_name)
if self.nullable:
self.assertTrue(submitted_by.null,)
self.assertTrue(submitted_by.blank)
self.assertEqual(submitted_by.remote_field.on_delete, models.SET_NULL)
self.assertEqual(
submitted_by.remote_field.on_delete, models.SET_NULL)

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -0,0 +1,58 @@
from django.test import TestCase
from django.db import models
from django.contrib.auth.models import User
from lostplaces_app.models import Explorer
class ExplorerTestCase(TestCase):
@classmethod
def setUpTestData(self):
User.objects.create_user(
username='testpeter',
password='Develop123'
)
def test_epxlorer_creation(self):
'''
Tests if the explorer profile will be automticly
created when a user is created
'''
user = User.objects.get(id=1)
explorer_list = Explorer.objects.all()
self.assertTrue(len(explorer_list) > 0,
msg='Expecting at least one Exlorer object, none found'
)
self.assertTrue(hasattr(user, 'explorer'),
msg='''Expecting the User instance to have an \'explorer\' attribute.
Check the Explorer model and the related name.'''
)
explorer = Explorer.objects.get(id=1)
self.assertEqual(explorer, user.explorer,
msg='''The Explorer object of the User did not match.
Expecting User with id 1 to have Explorer with id 1'''
)
explorer = Explorer.objects.get(id=1)
self.assertEqual(explorer.user, user,
msg='''The User object of the Explorer did not match.
Expecting Explorer with id 1 to have User with id 1'''
)
def test_explorer_deletion(self):
'''
Tests if the Explorer objects get's deleted when the User instance is deleted
'''
user = User.objects.get(username='testpeter')
explorer_id = user.explorer.id
user.delete()
with self.assertRaises(models.ObjectDoesNotExist,
msg='Expecting explorer objec to be deleted when the corresponding User object is deleted'
):
Explorer.objects.get(id=explorer_id)

View File

@@ -1,32 +1,56 @@
import datetime
import os
import shutil
from unittest import mock
from django.test import TestCase
from django.db import models
from django.core.files import File
from django.conf import settings
from django.contrib.auth.models import User
from lostplaces_app.models import PlaceImage
from lostplaces_app.tests.models import TestSubmittable
from lostplaces_app.tests import mock_user
from lostplaces_app.tests.models import TestModel
from lostplaces_app.tests.models.test_place_model import mock_place
from lostplaces_app.models import PlaceImage, Place
from lostplaces_app.tests.models import SubmittableTestCase
from lostplaces_app.tests.models.test_place_model import PlaceTestCase
from easy_thumbnails.fields import ThumbnailerImageField
def mock_place_image():
return PlaceImage(
description='Im a description',
filename=mock.MagicMock(spec=File, name='FileMock'),
place=mock_place(),
submitted_when=datetime.datetime.now(),
submitted_by=mock_user().explorer
)
class TestPlaceImage(SubmittableTestCase, TestCase):
model = PlaceImage
class TestPlaceImage(TestSubmittable, TestCase):
model_name = 'PlaceImage'
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=datetime.datetime.now(),
submitted_by=User.objects.get(username='testpeter').explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
place.save()
def setUp(self):
self.object = mock_place_image()
current_dir = os.path.dirname(os.path.abspath(__file__))
if not os.path.isfile(os.path.join(settings.MEDIA_ROOT, 'im_a_image_copy.jpeg')):
shutil.copyfile(
os.path.join(current_dir, 'im_a_image.jpeg'),
os.path.join(settings.MEDIA_ROOT, 'im_a_image_copy.jpeg')
)
PlaceImage.objects.create(
description='Im a description',
filename=os.path.join(settings.MEDIA_ROOT, 'im_a_image_copy.jpeg'),
place=place,
submitted_when=datetime.datetime.now(),
submitted_by=user.explorer
)
def test_description(self):
self._test_field('description', models.TextField)
@@ -51,5 +75,18 @@ class TestPlaceImage(TestSubmittable, TestCase):
)
def test_str(self):
place_image = mock_place_image()
self.assertEqual(str(place_image), ' '.join([place_image.place.name, str(place_image.pk)]))
place_image = self.object
self.assertTrue(place_image.place.name.lower() in str(place_image).lower(),
msg='Expecting %s.__str__ to contain the name of the place' % (
self.model_name
)
)
def test_deletion(self):
# TODO
path = self.object.filename.path
self.object.delete()
self.assertFalse(
os.path.isfile(path),
msg='Expecting the file of an place_image to be deleteed when an place_image is deleted'
)

View File

@@ -3,35 +3,38 @@ import datetime
from django.test import TestCase
from django.db import models
from django.contrib.auth.models import User
from lostplaces_app.models import Place
from lostplaces_app.tests.models import TestSubmittable
from lostplaces_app.tests import mock_user
from lostplaces_app.tests.models import TestModel
from lostplaces_app.tests import BaseData
from lostplaces_app.tests.models import SubmittableTestCase
from taggit.managers import TaggableManager
def mock_place():
place = Place.objects.create(
name='Im a place',
submitted_when=datetime.datetime.now(),
submitted_by=mock_user().explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
return place
class PlaceTestCase(TestSubmittable, TestCase):
model_name = 'Place'
class PlaceTestCase(SubmittableTestCase, TestCase):
model = Place
related_name = 'places'
nullable = True
def setUp(self):
self.place = mock_place()
self.object = self.place
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=datetime.datetime.now(),
submitted_by=user.explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
place.save()
def test_name_field(self):
self._test_char_field(
@@ -74,9 +77,11 @@ class PlaceTestCase(TestSubmittable, TestCase):
'''
place_list = []
for i in range(10):
place = mock_place()
place = Place.objects.get(id=1)
place.id = None
place.latitude = i+1
place.longitude = i+10
place.save()
place_list.append(place)
avg_latlon = Place.average_latlon(place_list)
@@ -96,7 +101,7 @@ class PlaceTestCase(TestSubmittable, TestCase):
Tests the average latitude/longitude calculation of a list
of one place
'''
place = mock_place()
place = Place.objects.get(id=1)
avg_latlon = Place.average_latlon([place])
self.assertEqual(avg_latlon[0], place.latitude,
msg='%s:(one place) average latitude missmatch' % (
@@ -127,10 +132,9 @@ class PlaceTestCase(TestSubmittable, TestCase):
)
def test_str(self):
place = mock_place()
self.assertEqual(str(place), place.name,
msg='%s __str__ should return the name' % (
place = self.object
self.assertTrue(place.name.lower() in str(place).lower(),
msg='Expecting %s.__str__ to contain the name' % (
self.model_name
)
)

View File

@@ -0,0 +1,49 @@
import datetime
from django.test import TestCase
from django.db import models
from django.utils import timezone
from lostplaces_app.models import Voucher
from lostplaces_app.tests.models import ModelTestCase
class VoucheTestCase(ModelTestCase, TestCase):
model = Voucher
@classmethod
def setUpTestData(cls):
Voucher.objects.create(
code='ayDraJCCwfhcFiYmSR5GrcjcchDfcahv',
expires_when=timezone.now() + datetime.timedelta(days=1)
)
def test_voucher_code(self):
self._test_char_field(
'code',
10,
100,
must_have={'unique': True}
)
def test_voucher_created(self):
self._test_field(
'created_when',
models.DateTimeField,
must_have={'auto_now_add': True}
)
def test_voucher_expires(self):
self._test_field(
'expires_when',
models.DateTimeField,
must_not_have={'auto_now_add': True}
)
def test_str(self):
voucher = self.object
self.assertTrue(voucher.code.lower() in str(voucher).lower(),
msg='Expecting %s.__str__ to contain the voucher code' % (
self.model_name
)
)

View File

@@ -1,17 +1,36 @@
import datetime
from django.test import TestCase, Client
from django.urls import reverse_lazy
from django.contrib.auth.models import User
from lostplaces_app.models import Place
from django.contrib.auth.models import User
from lostplaces_app.tests.models.test_place_model import mock_place
from lostplaces_app.tests import mock_user
class TestIsAuthenticated(TestCase):
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=datetime.datetime.now(),
submitted_by=User.objects.get(username='testpeter').explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
place.save()
def setUp(self):
self. client = Client()
mock_place()
mock_user()
def test_logged_in(self):
self.client.login(username='testpeter', password='Develop123')
@@ -36,10 +55,27 @@ class TestIsAuthenticated(TestCase):
class TestIsPlaceSubmitter(TestCase):
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=datetime.datetime.now(),
submitted_by=user.explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
place.save()
def setUp(self):
self. client = Client()
mock_place()
mock_user()
def test_is_submitter(self):
self.client.login(username='testpeter', password='Develop123')

View File

@@ -1,17 +1,34 @@
import datetime
from django.test import TestCase, Client
from django.urls import reverse_lazy
from django.contrib.auth.models import User
from lostplaces_app.models import Place
from lostplaces_app.tests.models.test_place_model import mock_place
from lostplaces_app.tests import mock_user
class TestPlaceCreateView(TestCase):
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=datetime.datetime.now(),
submitted_by=user.explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
place.save()
def setUp(self):
self. client = Client()
mock_place()
mock_user()
def test_url_logged_in(self):
self.client.login(username='testpeter', password='Develop123')

View File

@@ -1,5 +1,5 @@
from django.urls import path
from .views import (
from lostplaces_app.views import (
HomeView,
PlaceDetailView,
PlaceListView,