Pylint happiness!

This commit is contained in:
Gergely Polonkai 2015-10-20 16:26:25 +02:00
parent 2db6e2dd24
commit d3ec0e8998
15 changed files with 548 additions and 173 deletions

View File

@ -1,22 +1,37 @@
# -*- coding: utf-8
"""
Account management module for the Duck Booking Tool backend
"""
from django.test import TestCase, Client
from django_webtest import WebTest
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class FrontTest(TestCase):
"""
Test front-end capabilities of the accounts module
"""
def setUp(self):
self.client = Client()
self.admin = User.objects.create_user(
username = 'admin',
password = 'password')
self.admin.save()
self.admin = User.objects.create_user(username='admin',
password='password')
def test_login_page(self):
"""
Test for the existence of the login page
"""
response = self.client.get('/accounts/login')
self.assertEqual(response.status_code, 200)
def test_login(self):
"""
Test login functionality
"""
response = self.client.post('/accounts/login', {
'next': '/',
'username': 'admin',
@ -25,17 +40,33 @@ class FrontTest(TestCase):
self.assertRedirects(response, '/')
def test_logout(self):
self.client.login(username = 'admin', password = 'aeou')
"""
Test the logout page
"""
self.client.login(username='admin', password='aeou')
response = self.client.get('/accounts/logout')
self.assertRedirects(response, '/')
def test_registration_page(self):
"""
Test for existence of the registration page
"""
response = self.client.get('/accounts/register')
self.assertEqual(response.status_code, 200)
class RegFormTest(WebTest):
"""
Test case for the registration form
"""
def test_valid_data(self):
"""
Test valid registration without actual HTTP requests
"""
form_data = {
'username': 'test',
'password1': 'password',
@ -51,6 +82,10 @@ class RegFormTest(WebTest):
self.assertNotEqual(user.password, 'password')
def test_empty(self):
"""
Test empty registration form
"""
form_data = {}
form = UserCreationForm(form_data)
self.assertFalse(form.is_valid())
@ -61,11 +96,19 @@ class RegFormTest(WebTest):
})
def test_form_error(self):
"""
Test incomplete registration
"""
page = self.app.get('/accounts/register')
page = page.form.submit()
self.assertContains(page, "This field is required.")
def test_form_success(self):
"""
Test for successful registrations
"""
page = self.app.get('/accounts/register')
page.form['username'] = 'test'
page.form['password1'] = 'password'

View File

@ -1,24 +1,28 @@
from django.conf.urls import patterns, url
# -*- coding: utf-8
"""
URL patterns for the accounts module
"""
from django.conf.urls import url
from .views import RegistrationFormView
urlpatterns = patterns(
'',
urlpatterns = [
url(
r'^register$',
RegistrationFormView.as_view(),
name = 'register'
name='register'
),
url(
r'^login$',
'django.contrib.auth.views.login',
{'template_name': 'accounts/login.html'},
name = 'login'
name='login'
),
url(
r'^logout$',
'django.contrib.auth.views.logout',
{'next_page': 'booking:list'},
name = 'logout'
name='logout'
),
)
]

View File

@ -1,3 +1,8 @@
# -*- coding: utf-8
"""
Views for the accounts module
"""
from django.shortcuts import render
from django.views import generic
from django.http import HttpResponseRedirect
@ -5,14 +10,26 @@ from django.core.urlresolvers import reverse
from django.contrib.auth.forms import UserCreationForm
class RegistrationFormView(generic.View):
"""
Class to display the registration form
"""
form_class = UserCreationForm
template_name = 'accounts/registration.html'
def get(self, request):
"""
Implementation of the GET method
"""
form = self.form_class()
return render(request, self.template_name, { 'form': form })
return render(request, self.template_name, {'form': form})
def post(self, request):
"""
Implementation of the POST method
"""
form = self.form_class(request.POST)
if form.is_valid():

View File

@ -1,10 +1,18 @@
# -*- coding: utf-8 -*-
"""
Serializers for the Duck Booking Tool API
"""
from django.core.exceptions import ImproperlyConfigured
from rest_framework import serializers
from booking.models import Duck, Competence, DuckCompetence
class NamespacedSerializer(serializers.HyperlinkedModelSerializer):
"""
HyperlinkedModelSerializer with URL namespace support
"""
def __init__(self, *args, **kwargs):
if not hasattr(self.Meta, 'url_namespace') or self.Meta.url_namespace is None:
raise ImproperlyConfigured("namespace must be set!")
@ -17,7 +25,7 @@ class NamespacedSerializer(serializers.HyperlinkedModelSerializer):
if not self.url_namespace.endswith(':'):
self.url_namespace += ':'
return super(NamespacedSerializer, self).__init__(*args, **kwargs)
super(NamespacedSerializer, self).__init__(*args, **kwargs)
def build_url_field(self, field_name, model_class):
field_class, field_kwargs = super(NamespacedSerializer, self) \
@ -32,12 +40,20 @@ class NamespacedSerializer(serializers.HyperlinkedModelSerializer):
return field_class, field_kwargs
class CompetenceSerializer(NamespacedSerializer):
"""
Serializer for Competence objects
"""
class Meta:
url_namespace = 'api'
model = Competence
fields = ('url', 'name',)
class DuckCompetenceSerializer(NamespacedSerializer):
"""
Serializer for DuckCompetence objects
"""
comp = CompetenceSerializer()
class Meta:
@ -46,6 +62,10 @@ class DuckCompetenceSerializer(NamespacedSerializer):
fields = ('comp', 'up_minutes', 'down_minutes',)
class DuckSerializer(NamespacedSerializer):
"""
Serializer for Duck objects
"""
competences = DuckCompetenceSerializer(many=True)
class Meta:

View File

@ -1,5 +1,8 @@
# -*- coding: utf-8
from django.test import TestCase, Client
"""
Test cases for API calls
"""
from django.contrib.auth.models import User
from django.conf import settings
from django_webtest import WebTest
@ -10,6 +13,10 @@ from booking.ducklevel import level_to_up_minutes
from booking.models import Species, Location, Duck, Competence, DuckCompetence
class DuckClassTest(WebTest):
"""
Test case for duck related API calls
"""
csrf_checks = False
def setUp(self):
@ -46,10 +53,18 @@ class DuckClassTest(WebTest):
down_minutes=0)
def test_book_nonlogged(self):
"""
Test booking without logging in
"""
page = self.app.post('/api/v1/ducks/1/book/', expect_errors=True)
self.assertEqual(page.status_code, 403)
def test_book_nonexist(self):
"""
Test booking a non-existing duck
"""
# Try to book a non-existing duck
page = self.app.post(
'/api/v1/ducks/9999/book/',
@ -71,6 +86,10 @@ class DuckClassTest(WebTest):
self.assertEqual(404, page.status_code)
def test_book_warn(self):
"""
Test duck booking for a competence the duck is not good at
"""
url = '/api/v1/ducks/%d/book/' % self.duck.pk
comp_none = Competence.objects.create(name='test3',
added_by=self.user)
@ -107,6 +126,10 @@ class DuckClassTest(WebTest):
self.assertEquals(page_json['status'], 'ok')
def test_book_good(self):
"""
Test duck booking for a competence the duck is good at
"""
test_data = {
"competence": self.comp_good.pk
}
@ -127,6 +150,10 @@ class DuckClassTest(WebTest):
self.assertEqual('already-booked', page_json['status'])
def test_duck_donation(self):
"""
Test duck donating functionality
"""
# Duck donation should not be allowed without logging in
page = self.app.get('/api/v1/ducks/donate/', expect_errors=True)
self.assertEquals(page.status_code, 403)
@ -135,16 +162,19 @@ class DuckClassTest(WebTest):
page = self.app.post('/api/v1/ducks/donate/', expect_errors=True)
self.assertEquals(page.status_code, 403)
page = self.app.post(
self.app.post(
'/api/v1/ducks/donate/',
params={
'species': 1,
'color': '123456',
},
user=self.user)
page_json = json.loads(page.content)
def test_duck_details(self):
"""
Test duck details view
"""
url = '/api/v1/ducks/%d/' % self.duck.pk
page = self.app.get(url)
self.assertEqual(200, page.status_code)

View File

@ -1,4 +1,7 @@
from django.conf.urls import patterns, url, include
# -*- coding: utf-8
"""
URL definitions for version 1 of the Duck Booking Tool API
"""
from rest_framework import routers

View File

@ -1,22 +1,32 @@
# -*- coding: utf-8 -*-
"""
Views for the Duck Booking Tool API
"""
from django.conf import settings
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.decorators import detail_route, list_route
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .serializers import DuckSerializer, CompetenceSerializer, \
DuckCompetenceSerializer
from booking.models import Duck, Competence, Booking, DuckCompetence
from .serializers import DuckSerializer, CompetenceSerializer
from booking.models import Duck, Competence, Booking
class DuckViewSet(viewsets.ModelViewSet):
"""
View set for duck handling
"""
serializer_class = DuckSerializer
queryset = Duck.objects.all()
@detail_route(methods=['post'], permission_classes=[IsAuthenticated])
def book(self, request, pk=None):
"""
API call to book a duck
"""
duck = self.get_object()
competence = get_object_or_404(Competence, pk=request.data['competence'])
force = request.data.get('force', False)
@ -54,8 +64,16 @@ class DuckViewSet(viewsets.ModelViewSet):
@list_route(methods=['post'], permission_classes=[IsAuthenticated])
def donate(self, request):
"""
API call to donate a new duck
"""
return Response({'Woot!'})
class CompetenceViewSet(viewsets.ModelViewSet):
"""
View set for competence handling
"""
serializer_class = CompetenceSerializer
queryset = Competence.objects.all()

View File

@ -1,5 +1,12 @@
# -*- coding: utf-8
"""
Administration site definition for the Duck Booking Tool
"""
from django.contrib import admin
from booking.models import Species, Location, Competence, Duck, Booking, DuckCompetence, DuckName, DuckNameVote
from booking.models import Species, Location, Competence, Duck, \
Booking, DuckCompetence, DuckName, \
DuckNameVote
admin.site.register(Species)
admin.site.register(Location)

View File

@ -1,19 +1,35 @@
# -*- coding: utf-8
"""
Duck level calculations
"""
from django.conf import settings
import math
def level_to_up_minutes(level):
"""
Convert duck level to up minutes
"""
if level == 0:
return 0
return 2 * pow(10, level)
def level_to_down_minutes(level):
"""
Convert duck level to down minutes
"""
if level == 0:
return 0
return 20 * pow(10, level)
def minutes_to_level(up_minutes, down_minutes):
"""
Convert booking minutes to duck level
"""
minutes = up_minutes + down_minutes / 10
level = 0 if minutes <= 0 else min(settings.MAX_DUCK_LEVEL, math.floor(math.log10(minutes)))

View File

@ -1,32 +1,45 @@
# -*- coding: utf-8 -*-
"""
Models for the Duck Booking Tool
"""
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone
from django.utils.encoding import python_2_unicode_compatible
from fuzzywuzzy import fuzz
from .ducklevel import minutes_to_level
@python_2_unicode_compatible
class Species(models.Model):
"""Model to hold the Ducks species"""
"""
Model to hold the Ducks species
"""
name = models.CharField(max_length=40, unique=True)
def __str__(self):
return self.name
@python_2_unicode_compatible
class Location(models.Model):
"""Model to hold the possible locations of the Ducks"""
"""
Model to hold the possible locations of the Ducks
"""
name = models.CharField(max_length=50)
def __str__(self):
return self.name
@python_2_unicode_compatible
class Competence(models.Model):
"""Model to hold Duck competences"""
"""
Model to hold Duck competences
"""
name = models.CharField(max_length=255, unique=True)
added_at = models.DateTimeField(default=timezone.now)
@ -37,20 +50,27 @@ class Competence(models.Model):
@classmethod
def get_similar_comps(cls, name):
"""
Get competence names similar to name
"""
comps = cls.objects.values_list('name', flat=True)
ret = ()
for c in comps:
r = fuzz.ratio(name.lower(), c.lower())
for competence in comps:
similarity = fuzz.ratio(name.lower(), competence.lower())
# This ratio is subject to change
if r > settings.MIN_FUZZY_SIMILARITY:
ret = ret + (c,)
if similarity > settings.MIN_FUZZY_SIMILARITY:
ret = ret + (competence,)
return ret
@python_2_unicode_compatible
class Duck(models.Model):
"""Model to hold Duck data"""
"""
Model to hold Duck data
"""
name = models.CharField(max_length=80, null=True, blank=True)
color = models.CharField(max_length=6)
@ -72,6 +92,11 @@ class Duck(models.Model):
return self.name
def age(self):
"""
Get the age of the duck (time since the duck has been registered
in the tool)
"""
seconds_d = timezone.now() - self.donated_at
seconds = seconds_d.total_seconds()
@ -81,6 +106,10 @@ class Duck(models.Model):
return seconds
def dpx(self):
"""
Get the Duck Popularity indeX for this duck
"""
all_time = Booking.total_booking_time()
duck_time = Booking.duck_booking_time(self)
@ -90,18 +119,25 @@ class Duck(models.Model):
return Booking.duck_booking_time(self) / Booking.total_booking_time()
def booked_by(self):
l = self.booking_set.filter(end_ts=None)
"""
Get the user who is currently using the duck
"""
if len(l) == 0:
booking_list = self.booking_set.filter(end_ts=None)
if len(booking_list) == 0:
return None
if len(l) > 1:
if len(booking_list) > 1:
raise RuntimeError(u"Duck is booked more than once!")
return l[0].user
return booking_list[0].user
@python_2_unicode_compatible
class DuckName(models.Model):
"""Model to hold name suggestions for Ducks"""
"""
Model to hold name suggestions for Ducks
"""
duck = models.ForeignKey(Duck)
name = models.CharField(max_length=60)
@ -110,16 +146,31 @@ class DuckName(models.Model):
closed_by = models.ForeignKey(User, related_name='+')
closed_at = models.DateTimeField(null=True)
def __str__(self):
return "{0}, suggested by {1}".format(self.name,
self.suggested_by)
@python_2_unicode_compatible
class DuckNameVote(models.Model):
"""Model to hold votes to Duck names"""
"""
Model to hold votes to Duck names
"""
duck_name = models.ForeignKey(DuckName)
vote_timestamp = models.DateTimeField(default=timezone.now)
voter = models.ForeignKey(User)
upvote = models.BooleanField(default=True)
def __str__(self):
return "{0} voted {1} for {2}".format(self.voter,
"up" if upvote else "down",
self.duck_name)
@python_2_unicode_compatible
class DuckCompetence(models.Model):
"""Duck competence governor table"""
"""
Duck competence governor table
"""
duck = models.ForeignKey(Duck, related_name='competences')
comp = models.ForeignKey(Competence, related_name='ducks')
@ -127,13 +178,26 @@ class DuckCompetence(models.Model):
down_minutes = models.IntegerField(default=0)
def level(self):
"""
Return the actual level of a duck
"""
return minutes_to_level(self.up_minutes, self.down_minutes)
def __str__(self):
return "{0} with +{1}/-{2} minutes in {3}".format(self.duck,
self.up_minutes,
self.down_minutes,
self.comp)
class Meta:
unique_together = ('duck', 'comp')
@python_2_unicode_compatible
class Booking(models.Model):
"""Duck booking governor table"""
"""
Duck booking governor table
"""
duck = models.ForeignKey(Duck)
user = models.ForeignKey(User)
@ -144,6 +208,10 @@ class Booking(models.Model):
@classmethod
def total_booking_time(cls):
"""
Get the sum of booked hours for all ducks
"""
return cls.objects.filter(
start_ts__isnull=False,
end_ts__isnull=False).extra(
@ -154,10 +222,19 @@ class Booking(models.Model):
@classmethod
def duck_booking_time(cls, duck):
"""
Get the sum of booked hours of a duck
"""
return cls.objects.filter(
start_ts__isnull=False,
end_ts__isnull=False, duck = duck).extra(
end_ts__isnull=False, duck=duck).extra(
select={
'amount': 'sum(strftime(%s, end_ts) - strftime(%s, start_ts))'
},
select_params=('%s', '%s'))[0].amount
def __str__(self):
return "{0} booked by {1} since {2}".format(self.duck,
self.user,
self.start_ts)

View File

@ -1,17 +1,31 @@
# -*- coding: utf-8
"""
Template tags for the booking templates
"""
from django import template
import math
register = template.Library()
def is_number(s):
def is_number(string):
"""
Check if s is a number in string representation
"""
try:
float(s)
float(string)
return True
except ValueError:
return False
@register.filter
def age_format(value, arg = None):
def age_format(value, arg=None):
"""
Create human readable string from the duck age
"""
if not is_number(value):
return value
@ -30,7 +44,7 @@ def age_format(value, arg = None):
remainder = remainder % 2592000
if months > 0:
if (ret != ""):
if ret != "":
ret += " "
ret += u"%d month%s" % (months, "" if months == 1 else "s")
@ -45,7 +59,7 @@ def age_format(value, arg = None):
days = 1
if days > 0:
if (ret != ""):
if ret != "":
ret += " "
ret += u"%d day%s" % (days, "" if days == 1 else "s")
@ -60,7 +74,7 @@ def age_format(value, arg = None):
remainder = remainder % 3600
if hours > 0:
if (ret != ""):
if ret != "":
ret += " "
ret += u"%d hour%s" % (hours, "" if hours == 1 else "s")
@ -68,7 +82,7 @@ def age_format(value, arg = None):
minutes = math.floor(remainder / 60)
if minutes > 0:
if (ret != ""):
if ret != "":
ret += " "
ret += u"%d minute%s" % (minutes, "" if minutes == 1 else "s")
@ -76,7 +90,7 @@ def age_format(value, arg = None):
seconds = round(remainder % 60)
if seconds > 0:
if (ret != ""):
if ret != "":
ret += " "
ret += u"%d second%s" % (seconds, "" if seconds == 1 else "s")

View File

@ -1,70 +1,96 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.test import TestCase, Client
from django.utils import timezone
"""
Tests for the Duck Booking Tool frontend
"""
import datetime
from django.conf import settings
from django.contrib.auth.models import User
from django.test import TestCase, Client
from django.utils import timezone
from .ducklevel import level_to_up_minutes, level_to_down_minutes, minutes_to_level
from .templatetags import booking_tags
from .models import Duck, Competence, DuckCompetence, Species, Location, Booking
class FrontTest(TestCase):
"""
Test case for the front end
"""
def setUp(self):
self.client = Client()
def test_index_page(self):
"""
Test for the existence of the main page
"""
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
def test_vocabulary_page(self):
"""
Test for the existence of the vocabulary page
"""
response = self.client.get('/vocabulary.html')
self.assertEqual(response.status_code, 200)
def test_terms_page(self):
"""
Test for the existence of the terms page
"""
response = self.client.get('/terms.html')
self.assertEqual(response.status_code, 200)
def test_disclaimer_page(self):
"""
Test for the existence of the disclaimer page
"""
response = self.client.get('/disclaimer.html')
self.assertEqual(response.status_code, 200)
class DuckCompLevelTest(TestCase):
"""
Test case for competence level calculation
"""
def setUp(self):
user = User.objects.create_user(username='test', password='test')
species = Species(name='test species')
species.save()
species = Species.objects.create(name='test species')
location = Location(name='test location')
location.save()
location = Location.objects.create(name='test location')
duck = Duck(
species=species,
duck = Duck.objects.create(species=species,
location=location,
donated_by=user)
duck.save()
comp = Competence(
name='testing',
comp = Competence.objects.create(name='testing',
added_by=user)
comp.save()
self.duckcomp = DuckCompetence(
duck = duck,
comp = comp,
up_minutes = 0,
down_minutes =0)
self.duckcomp = DuckCompetence.objects.create(duck=duck,
comp=comp,
up_minutes=0,
down_minutes=0)
def test_sane_max(self):
"""
Test if the MAX_DUCK_LEVEL setting has a sane value
"""
self.assertGreater(
settings.MAX_DUCK_LEVEL, 0,
msg = "MAX_DUCK_LEVEL must be greater than zero!")
msg="MAX_DUCK_LEVEL must be greater than zero!")
def test_max_minutes(self):
"""Test if level can not go above settings.MAX_DUCK_LEVEL)"""
"""
Test if level can not go above settings.MAX_DUCK_LEVEL)
"""
max_up_minutes = level_to_up_minutes(settings.MAX_DUCK_LEVEL)
double_minutes = level_to_up_minutes(settings.MAX_DUCK_LEVEL * 2)
@ -86,6 +112,10 @@ class DuckCompLevelTest(TestCase):
self.assertEqual(level, settings.MAX_DUCK_LEVEL)
def test_conversions(self):
"""
Test minutes to level conversations
"""
for i in range(1, settings.MAX_DUCK_LEVEL):
up_minutes = level_to_up_minutes(i)
down_minutes = level_to_down_minutes(i)
@ -93,12 +123,16 @@ class DuckCompLevelTest(TestCase):
up_level = minutes_to_level(up_minutes, 0)
down_level = minutes_to_level(0, down_minutes)
self.assertEqual(up_level, i, msg = "Test failed for value %d" % i)
self.assertEqual(up_level, i, msg="Test failed for value %d" % i)
self.assertEqual(
down_level, i,
msg = "Test failed for value %d" % i)
msg="Test failed for value %d" % i)
def test_level_to_minutes(self):
"""
Test level to minutes conversations
"""
self.assertEqual(level_to_up_minutes(0), 0)
self.assertEqual(level_to_up_minutes(1), 20)
self.assertEqual(level_to_up_minutes(2), 200)
@ -114,11 +148,19 @@ class DuckCompLevelTest(TestCase):
self.assertEqual(level_to_down_minutes(5), 2000000)
def test_no_comp(self):
"""
Test if level equals 0 if minutes count is 0
"""
self.duckcomp.up_minutes = 0
self.duckcomp.down_minutes = 0
self.assertEquals(self.duckcomp.level(), 0)
def test_comp_levels(self):
"""
Test competence level calculation
"""
self.duckcomp.down_minutes = 0
for lvl in range(1, settings.MAX_DUCK_LEVEL):
@ -127,16 +169,33 @@ class DuckCompLevelTest(TestCase):
self.assertEqual(self.duckcomp.level(), lvl)
def test_high_minutes(self):
"""
Test duck level calculation with a very high amount of minutes
"""
self.duckcomp.up_minutes = level_to_up_minutes(settings.MAX_DUCK_LEVEL)
self.duckcomp.down_minutes = level_to_down_minutes(settings.MAX_DUCK_LEVEL)
self.assertEqual(self.duckcomp.level(), settings.MAX_DUCK_LEVEL)
class DuckAgeTest(TestCase):
"""
Tests related to duck age
"""
def test_duck_is_from_the_future(self):
future_duck = Duck(donated_at = timezone.now() + datetime.timedelta(days = 2))
"""
Test if the duck came from the future (ie. donation time is in
the future)
"""
future_duck = Duck(donated_at=timezone.now() + datetime.timedelta(days=2))
self.assertEqual(future_duck.age(), -1)
def test_duck_age_formatter(self):
"""
Test duck age formatter
"""
self.assertEqual(booking_tags.age_format("aoeu"), "aoeu")
self.assertEqual(booking_tags.age_format(0), "a few moments")
self.assertEqual(booking_tags.age_format(1), "1 second")
@ -173,75 +232,105 @@ class DuckAgeTest(TestCase):
self.assertEqual(booking_tags.age_format(63072000), "2 years")
class BookingTimeTest(TestCase):
duck1 = None
duck2 = None
"""
Test case for calculating booking time and popularity
"""
def setUp(self):
user = User()
user.save()
species = Species(name = 'duck')
species.save()
species = Species.objects.create(name='duck')
location = Location.objects.create(name='start')
location = Location(name = 'start')
location.save()
self.duck1 = Duck.objects.create(species=species,
location=location,
donated_by=user)
self.duck1 = Duck(species = species, location = location, donated_by = user)
self.duck1.save()
competence = Competence(name = 'test', added_by = user)
competence.save()
competence = Competence.objects.create(name='test',
added_by=user)
now = timezone.now()
booking = Booking(duck = self.duck1, start_ts = now - datetime.timedelta(days = 2), end_ts = now - datetime.timedelta(days = 1), user = user, comp_req = competence)
booking.save()
Booking.objects.create(duck=self.duck1,
start_ts=now - datetime.timedelta(days=2),
end_ts=now - datetime.timedelta(days=1),
user=user,
comp_req=competence)
self.duck2 = Duck(species = species, location = location, donated_by = user)
self.duck2.save()
self.duck2 = Duck.objects.create(species=species,
location=location,
donated_by=user)
booking = Booking(duck = self.duck2, start_ts = now - datetime.timedelta(days = 3), end_ts = now - datetime.timedelta(days = 2), user = user, comp_req = competence)
booking.save()
Booking.objects.create(duck=self.duck2,
start_ts=now - datetime.timedelta(days=3),
end_ts=now - datetime.timedelta(days=2),
user=user,
comp_req=competence)
booking = Booking(duck = self.duck2, start_ts = now - datetime.timedelta(days = 2), end_ts = now - datetime.timedelta(days = 1), user = user, comp_req = competence)
booking.save()
Booking.objects.create(duck=self.duck2,
start_ts=now - datetime.timedelta(days=2),
end_ts=now - datetime.timedelta(days=1),
user=user,
comp_req=competence)
def test_total_booking_time(self):
self.assertEqual(Booking.total_booking_time(), 259200)
"""
Test total booking time
"""
self.assertEqual(259200, Booking.total_booking_time())
def test_duck_booking_time(self):
self.assertEqual(Booking.duck_booking_time(self.duck1), 86400)
self.assertEqual(Booking.duck_booking_time(self.duck2), 172800)
"""
Test duck booking time
"""
self.assertEqual(86400, Booking.duck_booking_time(self.duck1))
self.assertEqual(172800, Booking.duck_booking_time(self.duck2))
def test_dpx(self):
self.assertEqual(self.duck1.dpx(), 1/3)
self.assertEqual(self.duck2.dpx(), 2/3)
"""
Test Duck Popularity indeX calculation
"""
self.assertEqual(1/3, self.duck1.dpx())
self.assertEqual(2/3, self.duck2.dpx())
class TestListing(TestCase):
"""
Test case for duck listing
"""
def setUp(self):
self.client = Client()
species = Species()
species.save()
species = Species.objects.create()
loc = Location.objects.create()
user = User.objects.create_user(username='test',
password='test')
loc = Location()
loc.save()
user = User()
user.save()
self.duck = Duck(species = species, location = loc, donated_by = user)
self.duck.save()
self.duck = Duck.objects.create(species=species,
location=loc,
donated_by=user)
def test_front_page(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
"""
Test existence of the front page
"""
self.assertEqual(len(response.context['duck_list']), 1)
response = self.client.get('/')
self.assertEqual(200, response.status_code)
self.assertEqual(1, len(response.context['duck_list']))
class SimilarCompTest(TestCase):
"""
Test case for competence name fuzzy search
"""
def setUp(self):
admin = User(username = 'admin')
admin.save()
admin = User.objects.create_user(username='admin',
password='test')
competence_list = (
'Creativity',
@ -251,54 +340,75 @@ class SimilarCompTest(TestCase):
'TCSH',
)
for c in competence_list:
comp = Competence(name = c, added_by = admin)
comp.save()
for competence in competence_list:
Competence.objects.create(name=competence,
added_by=admin)
def test_good_similar_competences(self):
l = Competence.get_similar_comps('perl')
self.assertEquals(len(l), 1)
"""
Test similar competence list with different inputs
"""
l = Competence.get_similar_comps('pzthon')
self.assertEquals(len(l), 1)
comp_list = Competence.get_similar_comps('perl')
self.assertEquals(1, len(comp_list))
l = Competence.get_similar_comps(u'kreativitás')
self.assertEqual(len(l), 1)
comp_list = Competence.get_similar_comps('pzthon')
self.assertEquals(1, len(comp_list))
comp_list = Competence.get_similar_comps(u'kreativitás')
self.assertEqual(1, len(comp_list))
def test_bad_similar_competence(self):
l = Competence.get_similar_comps('development')
self.assertEqual(len(l), 0)
"""
Test similar competence list with a totally new and unmatching
competence name
"""
comp_list = Competence.get_similar_comps('development')
self.assertEqual(0, len(comp_list))
class BookingTest(TestCase):
"""
Test duck booking functionality
"""
def setUp(self):
spec = Species.objects.create(name='test')
loc = Location.objects.create(name='test')
self.spec = Species.objects.create(name='test')
self.loc = Location.objects.create(name='test')
self.user = User.objects.create_user(username='test')
self.booked_duck = Duck.objects.create(species=spec,
location=loc,
self.booked_duck = Duck.objects.create(species=self.spec,
location=self.loc,
donated_by=self.user)
self.comp = Competence.objects.create(name='test',
added_by=self.user)
booking = Booking.objects.create(duck=self.booked_duck,
Booking.objects.create(duck=self.booked_duck,
user=self.user,
comp_req=self.comp)
self.unbooked_duck = Duck.objects.create(species=spec,
location=loc,
donated_by=self.user)
def test_booked_duck(self):
"""
Test if booked duck returns the booking user from booked_by()
"""
self.assertNotEqual(self.booked_duck.booked_by(), None)
def test_unbooked_duck(self):
self.assertEqual(self.unbooked_duck.booked_by(), None)
"""
Test if unbooked duck returns None from booked_by()
"""
unbooked_duck = Duck.objects.create(species=self.spec,
location=self.loc,
donated_by=self.user)
self.assertEqual(unbooked_duck.booked_by(), None)
def test_multiple_booking(self):
"""
Test error presence in case of multiple bookings for the same
duck
"""
Booking.objects.create(duck=self.booked_duck,
user=self.user,
comp_req=self.comp)

View File

@ -1,24 +1,28 @@
from django.conf.urls import patterns, url
# -*- coding: utf-8
"""
URL definitions for the Duck Booking Tool frontend
"""
from django.conf.urls import url
from django.views.generic.base import TemplateView
from .views import DuckListView
urlpatterns = patterns(
'',
url(r'^$', DuckListView.as_view(), name = 'list'),
urlpatterns = [
url(r'^$', DuckListView.as_view(), name='list'),
url(
r'^vocabulary.html$',
TemplateView.as_view(template_name = 'booking/vocabulary.html'),
name = 'vocabulary'
TemplateView.as_view(template_name='booking/vocabulary.html'),
name='vocabulary'
),
url(
r'^terms.html$',
TemplateView.as_view(template_name = 'booking/terms.html'),
name = 'terms'
TemplateView.as_view(template_name='booking/terms.html'),
name='terms'
),
url(
r'^disclaimer.html$',
TemplateView.as_view(template_name = 'booking/disclaimer.html'),
name = 'disclaimer'
TemplateView.as_view(template_name='booking/disclaimer.html'),
name='disclaimer'
),
)
]

View File

@ -1,9 +1,17 @@
from django.shortcuts import render
# -*- coding: utf-8
"""
Views for the Duck Booking Tool frontend
"""
from django.views import generic
from .models import Duck
class DuckListView(generic.ListView):
"""
View for duck listing (the main page)
"""
template_name = 'booking/duck_list.html'
context_object_name = 'duck_list'

View File

@ -1,26 +1,30 @@
from django.conf import settings
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.views.decorators.cache import cache_page
# -*- coding: utf-8
"""
Main URL definitions file
"""
from django_js_reverse.views import urls_js
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns(
'',
urlpatterns = [
url(
r'^static/(?P<path>.*)$',
'django.views.static.serve',
{'document_root': settings.STATIC_ROOT}
),
url(
r'^reverse.js$',
cache_page(3600)(urls_js),
name = 'js_reverse'
),
url(r'^admin/', include(admin.site.urls)),
url(r'^accounts/', include('accounts.urls', namespace = 'accounts')),
url(r'^api/v1/', include('api.urls', namespace = 'api')),
url('', include('booking.urls', namespace = 'booking')),
)
r'^admin/',
include(admin.site.urls)),
url(
r'^accounts/',
include('accounts.urls', namespace='accounts')),
url(
r'^api/v1/',
include('api.urls', namespace='api')),
url(
'',
include('booking.urls', namespace='booking')),
]