Skip to content

Commit

Permalink
Allow changing oicompare format
Browse files Browse the repository at this point in the history
  • Loading branch information
MasloMaslane committed Sep 15, 2024
1 parent 22cf5c0 commit 8c661ac
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 20 deletions.
1 change: 1 addition & 0 deletions oioioi/contestexcl/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def _modify_contestexcl(
('contestlogo', 0, 0, 0, 1),
('programs_config', 0, 0, 0, 1),
('contestcompiler_set', 0, 0, 0, 1000),
('checkerformatforcontest', 0, 0, 0, 1),
)
data = dict()
for (name, total, initial, min_num, max_num) in formsets:
Expand Down
4 changes: 4 additions & 0 deletions oioioi/problems/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from oioioi.evalmgr.tasks import create_environ, delay_environ
from oioioi.problems.models import ProblemStatistics, UserStatistics
from oioioi.problems.utils import can_admin_problem
from oioioi.programs.utils import get_checker_format

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -156,6 +157,9 @@ def judge(self, submission, extra_args=None, is_rejudge=False):
break
if user_lang:
environ['user_language'] = user_lang
else:
environ['user_language'] = 'english'
environ['checker_format'] = environ['user_language'] + '_' + get_checker_format(submission.problem_instance)
picontroller = submission.problem_instance.controller

picontroller.fill_evaluation_environ(environ, submission)
Expand Down
37 changes: 37 additions & 0 deletions oioioi/programs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
ProgramsConfig,
ReportActionsConfig,
Test,
CheckerFormatForContest,
CheckerFormatForProblem,
)


Expand Down Expand Up @@ -447,3 +449,38 @@ def queryset(self, request, queryset):
return queryset.filter(condition)
else:
return queryset


class CheckerFormatForContestInline(admin.StackedInline):
model = CheckerFormatForContest
category = _("Advanced")


class CheckerFormatForProblemInline(admin.StackedInline):
model = CheckerFormatForProblem
category = _("Advanced")


class CheckerFormatOverrideContestAdminMixin(object):
"""Adds :class:`~oioioi.programs.models.CheckerFormatForContest` to an admin
panel.
"""
def __init__(self, *args, **kwargs):
super(CheckerFormatOverrideContestAdminMixin, self).__init__(*args, **kwargs)
self.inlines = tuple(self.inlines) + (CheckerFormatForContestInline,)


ContestAdmin.mix_in(CheckerFormatOverrideContestAdminMixin)


class CheckerFormatOverrideProblemAdminMixin(object):
"""Adds :class:`~oioioi.programs.models.CheckerFormatForProblem` to an admin
panel.
"""

def __init__(self, *args, **kwargs):
super(CheckerFormatOverrideProblemAdminMixin, self).__init__(*args, **kwargs)
self.inlines = tuple(self.inlines) + (CheckerFormatForProblemInline,)


ProblemInstanceAdmin.mix_in(CheckerFormatOverrideProblemAdminMixin)
2 changes: 1 addition & 1 deletion oioioi/programs/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def run_tests(env, kind=None, **kwargs):
job['check_output'] = env.get('check_outputs', True)
if env.get('checker'):
job['chk_file'] = env['checker']
job['checker_language'] = env.get('user_language', 'polish')
job['checker_format'] = env.get('checker_format', 'english_abbreviated')
if env.get('save_outputs'):
job.setdefault('out_file', _make_filename(env, test_name + '.out'))
job['upload_out'] = True
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 4.2.16 on 2024-09-15 21:27

from django.db import migrations, models
import django.db.models.deletion
import oioioi.base.fields


class Migration(migrations.Migration):

dependencies = [
('contests', '0018_contest_show_contest_rules'),
('programs', '0019_add_limits_override'),
]

operations = [
migrations.AddField(
model_name='programsubmission',
name='user_language_code',
field=models.CharField(blank=True, max_length=6, null=True, verbose_name='User language code'),
),
migrations.CreateModel(
name='CheckerFormatForProblem',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('format', oioioi.base.fields.EnumField(max_length=64, verbose_name='format')),
('problem_instance', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='contests.probleminstance', verbose_name='problem instance')),
],
options={
'verbose_name': 'checker format for problem',
'verbose_name_plural': 'checker formats for problems',
'ordering': ('problem_instance',),
'unique_together': {('problem_instance', 'format')},
},
),
migrations.CreateModel(
name='CheckerFormatForContest',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('format', oioioi.base.fields.EnumField(help_text="Format of the checker output for this contest. Abbreviated describes the output difference, while Terse doesn't give any details.", max_length=64, verbose_name='format')),
('contest', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='contests.contest', verbose_name='contest')),
],
options={
'verbose_name': 'checker format for contest',
'verbose_name_plural': 'checker formats for contests',
'ordering': ('contest',),
'unique_together': {('contest', 'format')},
},
),
]
41 changes: 41 additions & 0 deletions oioioi/programs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,3 +463,44 @@ def check_compilers_config():


check_compilers_config()


CheckerFormat = EnumRegistry()
CheckerFormat.register('terse', _("Terse"))
CheckerFormat.register('abbreviated', _("Abbreviated"))


class CheckerFormatForContest(models.Model):
"""Overrides the default checker's format (abbreviated) for a contest."""

contest = models.OneToOneField(
Contest, verbose_name=_("contest"), on_delete=models.CASCADE
)
format = EnumField(
CheckerFormat,
verbose_name=_("format"),
help_text=_("Format of the checker output for this contest. "
"Abbreviated describes the output difference, while "
"Terse doesn't give any details.")
)

class Meta(object):
verbose_name = _("checker format for contest")
verbose_name_plural = _("checker formats for contests")
ordering = ('contest',)
unique_together = ('contest', 'format')


class CheckerFormatForProblem(models.Model):
"""Overrides the default checker's format (abbreviated) for a problem."""

problem_instance = models.OneToOneField(
ProblemInstance, verbose_name=_("problem instance"), on_delete=models.CASCADE
)
format = EnumField(CheckerFormat, verbose_name=_("format"))

class Meta(object):
verbose_name = _("checker format for problem")
verbose_name_plural = _("checker formats for problems")
ordering = ('problem_instance',)
unique_together = ('problem_instance', 'format')
66 changes: 65 additions & 1 deletion oioioi/programs/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
LanguageOverrideForTest,
TestReport,
check_compilers_config,
CheckerFormatForContest,
CheckerFormatForProblem,
)
from oioioi.programs.problem_instance_utils import get_allowed_languages_dict
from oioioi.programs.utils import form_field_id_for_langs
Expand Down Expand Up @@ -544,7 +546,7 @@ def fake_send_notification(
NotificationHandler.send_notification = fake_send_notification

submission = Submission.objects.get(pk=1)

environ = create_environ()
environ['extra_args'] = {}
environ['is_rejudge'] = False
Expand Down Expand Up @@ -1986,3 +1988,65 @@ def test_proper_env_override(self):
self.assertEqual(
env_with_tests['tests']['1a']['exec_mem_limit'], tests[1].memory_limit
)


class TestOICompare(TestCase):
fixtures = ['test_users', 'test_contest']

def test_format(self):
contest = Contest.objects.get()
filename = get_test_filename('test_simple_package.zip')
self.assertTrue(self.client.login(username='test_admin'))
url = reverse('oioioiadmin:problems_problem_add')
response = self.client.get(url, {'contest_id': contest.id}, follow=True)
url = response.redirect_chain[-1][0]
self.assertEqual(response.status_code, 200)
self.assertIn(
'problems/add-or-update.html',
[getattr(t, 'name', None) for t in response.templates],
)
response = self.client.post(
url,
{
'package_file': open(filename, 'rb'),
'visibility': Problem.VISIBILITY_PRIVATE,
},
follow=True,
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Problem.objects.count(), 1)

pi = ProblemInstance.objects.get(contest=contest)
for lang, terse, abbreviated in [
("pl", "ŹLE", 'ŹLE: wiersz 1: oczekiwano "50000000", otrzymano koniec pliku'),
("en", "WRONG", 'WRONG: line 1: expected "50000000", got end of file'),
]:
terse = terse.replace('"', '"')
abbreviated = abbreviated.replace('"', '"')
for format_contest, format_problem, expected, unexpected in [
(None, None, abbreviated, None),
('terse', None, terse, abbreviated),
('terse', 'abbreviated', abbreviated, None),
(None, 'terse', terse, abbreviated),
]:
CheckerFormatForContest.objects.all().delete()
CheckerFormatForProblem.objects.all().delete()
if format_problem is not None:
CheckerFormatForProblem.objects.create(
problem_instance=pi, format=format_problem
)
if format_contest is not None:
CheckerFormatForContest.objects.create(contest=contest, format=format_contest)

ps = ProgramSubmission.objects.create(
source_file=ContentFile(b'int main(){}', name='a.cpp'),
user_language_code=lang,
problem_instance=pi,
user=User.objects.get(username='test_admin'),
)
pi.controller.judge(ps)
url = reverse('submission', kwargs={'contest_id': contest.id, 'submission_id': ps.id})
response = self.client.get(url)
self.assertContains(response, expected)
if unexpected:
self.assertNotContains(response, unexpected)
15 changes: 15 additions & 0 deletions oioioi/programs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
ModelProgramSubmission,
ProgramSubmission,
ReportActionsConfig,
CheckerFormatForContest,
CheckerFormatForProblem,
)


Expand Down Expand Up @@ -215,3 +217,16 @@ def get_submittable_languages():
for _, lang_config in submittable_languages.items():
lang_config.setdefault('type', 'main')
return submittable_languages


def get_checker_format(problem_instance):
try:
return CheckerFormatForProblem.objects.get(problem_instance=problem_instance).format
except CheckerFormatForProblem.DoesNotExist:
if problem_instance.contest:
try:
return CheckerFormatForContest.objects.get(contest=problem_instance.contest).format
except CheckerFormatForContest.DoesNotExist:
return getattr(settings, 'DEFAULT_CHECKER_FORMAT', 'abbreviated')
else:
return getattr(settings, 'DEFAULT_CHECKER_FORMAT', 'abbreviated')

0 comments on commit 8c661ac

Please sign in to comment.