Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Merge pull request #76 from unb-mds/feature/validators-forms
Browse files Browse the repository at this point in the history
[feature request] Adicionar validadores em todas as páginas de admin
  • Loading branch information
bitterteriyaki authored Nov 15, 2023
2 parents 250519f + 1d1de6d commit b65835f
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 21 deletions.
40 changes: 38 additions & 2 deletions apps/contests/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.core.exceptions import ValidationError
from django.db.models import (
BooleanField,
CharField,
Expand Down Expand Up @@ -33,12 +34,47 @@ def __str__(self) -> str:

@property
def status(self) -> ContestStatus:
"""
Retorna o status atual do contest baseado no horário atual.
.. list-table:: Status do contest
:header-rows: 1
* - Status
- Descrição
* - :attr:`ContestStatus.PENDING`
- Quando o contest ainda não começou.
* - :attr:`ContestStatus.RUNNING`
- Quando o contest está acontecendo.
* - :attr:`ContestStatus.FINISHED`
- Quando o contest já terminou.
* - :attr:`ContestStatus.CANCELLED`
- Quando o contest foi cancelado.
Returns
-------
:class:`ContestStatus`
O status atual do contest.
"""
if self.cancelled:
return ContestStatus.CANCELLED

if self.start_time > now():
elif self.start_time > now():
return ContestStatus.PENDING
elif self.end_time < now():
return ContestStatus.FINISHED
else:
return ContestStatus.RUNNING

def clean(self) -> None:
"""
Validação do contest. Verifica se o :attr:`start_time` é menor
que o :attr:`end_time`, ou seja, se o contest começa antes de
terminar. Se não for, lança um :class:`ValidationError`.
Raises
------
:class:`ValidationError`
Se o :attr:`start_time` for maior que o :attr:`end_time`.
"""
if self.start_time > self.end_time:
raise ValidationError("Start time must be before end time.")
49 changes: 34 additions & 15 deletions apps/contests/tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import timedelta

from django.contrib.admin import AdminSite
from django.core.exceptions import ValidationError
from django.forms import CharField, Textarea
from django.test import TestCase
from django.urls import resolve, reverse
Expand All @@ -11,13 +12,9 @@
from apps.contests.models import Contest


class ContestTestCase(TestCase):
class ContestModelTestCase(TestCase):
def setUp(self) -> None:
self.contest = Contest(
title="Test Contest",
description="This is a test contest",
cancelled=False,
)
self.contest = Contest(title="Test", description="Test contest")

def test_status_pending(self) -> None:
self.contest.start_time = timezone.now() + timedelta(hours=1)
Expand All @@ -38,19 +35,41 @@ def test_status_cancelled(self) -> None:
self.contest.cancelled = True
self.assertEqual(self.contest.status, ContestStatus.CANCELLED)

def test_start_time_before_end_time(self) -> None:
self.contest.start_time = timezone.now()
self.contest.end_time = timezone.now() + timedelta(hours=1)

class ContestStatusTestCase(TestCase):
def test_pending(self) -> None:
self.assertEqual(ContestStatus.PENDING, "Pending")
try:
self.contest.clean()
except ValidationError:
self.fail("ValidationError raised unexpectedly.")

def test_running(self) -> None:
self.assertEqual(ContestStatus.RUNNING, "Running")
def test_start_time_after_end_time(self) -> None:
self.contest.start_time = timezone.now() + timedelta(hours=1)
self.contest.end_time = timezone.now()

expected = ["Start time must be before end time."]

with self.assertRaises(ValidationError) as context:
self.contest.clean()

def test_finished(self) -> None:
self.assertEqual(ContestStatus.FINISHED, "Finished")
self.assertEqual(context.exception.messages, expected)

def test_cancelled(self) -> None:
self.assertEqual(ContestStatus.CANCELLED, "Cancelled")

class ContestStatusTestCase(TestCase):
def test_statuses_values(self) -> None:
self.assertEqual(ContestStatus.PENDING.value, "Pending")
self.assertEqual(ContestStatus.RUNNING.value, "Running")
self.assertEqual(ContestStatus.FINISHED.value, "Finished")
self.assertEqual(ContestStatus.CANCELLED.value, "Cancelled")

def test_statuses_choices_length(self) -> None:
"""
Devemos ter 4 opções de status de contests: Pending, Running,
Finished, Cancelled. Qualquer mudança nesse número deve ser
refletida aqui.
"""
self.assertEqual(len(ContestStatus), 4)


class ContestModelFormTestCase(TestCase):
Expand Down
11 changes: 7 additions & 4 deletions apps/contests/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Dict

from django.db.models.query import QuerySet
from django.views import generic
Expand All @@ -19,12 +19,15 @@ class IndexView(IndexViewBase):
context_object_name = "contests"

def get_queryset(self) -> QuerySet[Contest]:
return Contest._default_manager.order_by("start_time")[:5]
return Contest._default_manager.order_by("-start_time")[:5]

def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
ctx = super().get_context_data(**kwargs)
# Serve para separar os concursos que estão com status pendente
# ou em andamento dos concursos que já aconteceram ou que foram
# cancelados. Precisamos separar para que o template possa
# exibir os contests de forma diferente.
ctx["valid_statuses"] = (ContestStatus.PENDING, ContestStatus.RUNNING)

return ctx


Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ max-complexity = 5
# These files can't be tested, so we exclude them from coverage.
# We also exclude the manage.py file, since it's not a part of the app.
omit =
apps/*/tests.py
server/asgi.py
server/wsgi.py
server/settings/__init__.py
Expand Down

0 comments on commit b65835f

Please sign in to comment.