# ~*~ encoding: utf-8 ~*~
import re
from datetime import datetime, timezone # pylint: disable=E0611
from django.core.cache import cache
from django.urls import reverse
from oioioi.base.tests import TestCase, fake_time, fake_timezone_now
from oioioi.contests.models import Contest, Submission
from oioioi.oi.controllers import OIContestController
from oioioi.programs.controllers import ProgrammingContestController
[docs]class TSolutionOIContestController(OIContestController):
[docs] def can_see_publicsolutions(self, request, round):
r_times = super(TSolutionOIContestController, self).get_round_times(
request, round
)
return r_times.show_results <= request.timestamp
[docs] def solutions_must_be_public(self, qs):
return qs.exclude(problem_instance=4)
[docs] def solutions_may_be_published(self, qs):
return qs
[docs]class TSolutionSimpleContestController(ProgrammingContestController):
[docs] def can_see_publicsolutions(self, request, round):
r_times = super(TSolutionSimpleContestController, self).get_round_times(
request, round
)
return r_times.show_results <= request.timestamp
[docs] def solutions_must_be_public(self, qs):
return qs.exclude(problem_instance=4)
[docs] def solutions_may_be_published(self, qs):
return qs
[docs]class TestPublicSolutions(TestCase):
[docs] fixtures = [
'test_users',
'test_contest',
'test_full_package',
'test_problem_instance',
'test_submission',
'test_extra_rounds',
]
[docs] def setUp(self):
contest = Contest.objects.get()
contest.controller_name = (
'oioioi.publicsolutions.tests.TSolutionOIContestController'
)
contest.save()
[docs] def _href(self, url):
return 'href="' + url + '"'
[docs] def _no_public_rounds(self):
return datetime(2010, 6, 25, tzinfo=timezone.utc)
[docs] def _rounds_14(self):
return datetime(2013, 4, 4, tzinfo=timezone.utc)
[docs] def _all_rounds(self):
return datetime(2016, 1, 1, tzinfo=timezone.utc)
[docs] def assertUserSubmissionHTMLDataCount(self, html, username, count):
actual = len(
re.findall((r'username.*"' + username + r'"').encode('utf-8'), html)
)
self.assertEqual(
actual, count, "Expected %d html data, got %d in %s" % (count, actual, html)
)
[docs] def test_public_solutions_list(self):
contest = Contest.objects.get()
solutions_url = reverse('list_solutions', kwargs={'contest_id': contest.id})
def show_source_url(sub_id):
return reverse(
'show_submission_source',
kwargs={'contest_id': contest.id, 'submission_id': sub_id},
)
def change_publication_url(way, sub_id):
return reverse(
'publish_solution' if way else 'unpublish_solution',
kwargs={'contest_id': contest.id, 'submission_id': sub_id},
)
def check_categories_forbidden(cats, user):
self.assertTrue(self.client.login(username=user))
for cat in cats:
r = self.client.get(solutions_url, {'category': cat})
self.assertContains(r, "Select a valid choice.")
self.client.logout()
# Checks categories and solutions
# pylint: disable=dangerous-default-value
def check_visibility(good_ids, category='', users=['test_user', 'test_user2']):
for user in users:
self.assertTrue(self.client.login(username=user))
r = self.client.get(solutions_url, {'category': category})
self.assertEqual(200, r.status_code)
for id in range(1, 5):
sb = Submission.objects.all().select_related().get(pk=id)
if id in good_ids:
self.assertContains(r, str(sb.problem_instance))
self.assertContains(r, str(sb.user.get_full_name()))
self.assertContains(r, self._href(show_source_url(id)))
else:
self.assertNotContains(r, self._href(show_source_url(id)))
if not category:
self.assertNotContains(r, str(sb.problem_instance))
self.client.logout()
def check_sources_access(good_ids, bad_ids, user):
self.assertTrue(self.client.login(username=user))
for id in good_ids:
response = self.client.get(show_source_url(id))
self.assertEqual(200, response.status_code)
for id in bad_ids:
response = self.client.get(show_source_url(id))
self.assertEqual(403, response.status_code)
self.client.logout()
def change_publication(way, sub_id, user='test_user'):
self.assertTrue(self.client.login(username=user))
response = self.client.post(change_publication_url(way, sub_id))
self.assertEqual(302, response.status_code)
self.client.logout()
# 'test_user' doesn't see submissions from rounds that start in future,
# that's the way controller.filter_visible_sources works.
with fake_time(self._no_public_rounds()):
check_sources_access([], [1], 'test_user')
with fake_time(self._rounds_14()):
check_visibility([1])
check_visibility([1], "1", users=['test_user'])
change_publication(True, 4)
check_visibility([1, 4])
check_sources_access([1, 4], [], 'test_user2')
change_publication(False, 4)
check_visibility([1])
check_sources_access([1], [4], 'test_user2')
check_categories_forbidden([2, 4], 'test_user2')
with fake_time(self._all_rounds()):
check_visibility([1, 2, 3], users=['test_user2'])
[docs] def test_publish_solutions(self):
contest = Contest.objects.get()
publish_url = reverse('publish_solutions', kwargs={'contest_id': contest.id})
def submission_url(sub_id):
return reverse(
'submission', kwargs={'contest_id': contest.id, 'submission_id': sub_id}
)
def show_source_url(sub_id):
return reverse(
'show_submission_source',
kwargs={'contest_id': contest.id, 'submission_id': sub_id},
)
def change_publication_url(way, sub_id):
return reverse(
'publish_solution' if way else 'unpublish_solution',
kwargs={'contest_id': contest.id, 'submission_id': sub_id},
)
def change_publication(way, sub_id):
r = self.client.post(change_publication_url(way, sub_id))
self.assertEqual(302, r.status_code)
def check_access_forbidden(sub_ids):
for id in sub_ids:
r = self.client.post(change_publication_url(id % 2, id))
self.assertEqual(403, r.status_code)
def check_visibility(good_ids, way):
r = self.client.get(publish_url)
self.assertEqual(200, r.status_code)
for id in range(1, 5):
sb = Submission.objects.get(pk=id)
if id in good_ids:
self.assertContains(r, sb.get_date_display())
self.assertContains(r, self._href(show_source_url(id)))
self.assertContains(r, change_publication_url(way, id))
self.assertContains(r, self._href(submission_url(id)))
else:
self.assertNotContains(r, sb.get_date_display())
with fake_time(self._no_public_rounds()):
self.assertTrue(self.client.login(username='test_user'))
r = self.client.get(publish_url)
self.assertEqual(403, r.status_code)
check_access_forbidden([4])
with fake_time(self._rounds_14()):
check_visibility([4], True)
change_publication(True, 4)
check_visibility([4], False)
check_access_forbidden([1, 2])
self.client.logout()
self.assertTrue(self.client.login(username='test_user2'))
check_visibility([], True)
check_access_forbidden([3, 4])
self.client.logout()
self.assertTrue(self.client.login(username='test_user'))
change_publication(False, 4)
check_visibility([4], True)
self.client.logout()
[docs] def test_ranking(self):
def change_publication_url(way, sub_id):
return reverse(
'publish_solution' if way else 'unpublish_solution',
kwargs={'contest_id': contest.id, 'submission_id': sub_id},
)
with fake_timezone_now(self._rounds_14()):
contest = Contest.objects.get()
contest.controller_name = (
'oioioi.publicsolutions.tests.TSolutionSimpleContestController'
)
contest.save()
self.assertTrue(self.client.login(username='test_user'))
url = reverse('default_ranking', kwargs={'contest_id': contest.id})
response = self.client.get(url)
self.assertUserSubmissionHTMLDataCount(response.content, 'test_user', 2)
self.assertTrue(self.client.login(username='test_user2'))
cache.clear()
response = self.client.get(url)
self.assertUserSubmissionHTMLDataCount(response.content, 'test_user2', 0)
self.assertTrue(self.client.login(username='test_user'))
request = self.client.post(change_publication_url(True, 4))
self.assertEqual(302, request.status_code)
cache.clear()
response = self.client.get(url)
self.assertUserSubmissionHTMLDataCount(response.content, 'test_user', 2)
self.assertTrue(self.client.login(username='test_user2'))
cache.clear()
response = self.client.get(url)
self.assertUserSubmissionHTMLDataCount(response.content, 'test_user2', 0)