Difference between revisions of "Подготовка задачи tests"
(→Настройка дополнительных параметров для задач на разработку тестов) |
|||
| (30 intermediate revisions by the same user not shown) | |||
| Line 3: | Line 3: | ||
Задачи этого типа являются самыми сложными для подготовки. При описании подготовки таких задач будет предполагаться, что турнир настраивается в [[Альтернативная раскладка файлов|альтернативной раскладке файлов]], то есть все файлы, относящиеся к задаче, размещаются в одном каталоге. | Задачи этого типа являются самыми сложными для подготовки. При описании подготовки таких задач будет предполагаться, что турнир настраивается в [[Альтернативная раскладка файлов|альтернативной раскладке файлов]], то есть все файлы, относящиеся к задаче, размещаются в одном каталоге. | ||
| − | === | + | === Настройка основных параметров задачи === |
| + | |||
| + | Поскольку задача на написание тестов предполагает запуск программ на тестовых данных аналогично стандартной задаче, в разделе конфигурации задачи должны быть установлены параметры, относящиеся к тестированию задач. Например: | ||
| + | |||
| + | # Идентификационные параметры задачи | ||
| + | [[Serve.cfg:problem:id|id]] = ... | ||
| + | [[Serve.cfg:problem:short_name|short_name]] = ... | ||
| + | [[Serve.cfg:problem:long_name|long_name]] = ... | ||
| + | # Основные параметры задачи | ||
| + | [[Serve.cfg:problem:test_sfx|test_sfx]] = ".dat" # Суффикс имен файлов с тестовыми данными | ||
| + | [[Serve.cfg:problem:use_corr|use_corr]] # Проверка использует файлы с правильными ответами | ||
| + | [[Serve.cfg:problem:corr_dir|corr_dir]] = "[[Форматная подстановка|%Ps]]" # Каталог с файлами с правильными ответами - значение не важно | ||
| + | [[Serve.cfg:problem:corr_sfx|corr_sfx]] = ".ans" # Суффикс имен файлов с правильным ответом | ||
| + | [[Serve.cfg:problem:use_stdin|use_stdin]] # Программа считывает результат со стандартного потока ввода | ||
| + | [[Serve.cfg:problem:use_stdout|use_stdout]] # Программа выводит результат на стандартный поток вывода | ||
| + | [[Serve.cfg:problem:standard_checker|standard_checker]] = "[[cmp_int]]" # Проверка - сравнение двух целых чисел | ||
| + | [[Serve.cfg:problem:time_limit|time_limit]] = 1 # Ограничение времени ЦП - 1 секунда | ||
| + | [[Serve.cfg:problem:real_time_limit|real_time_limit]] = 5 # Ограничение реального времени - 5 секунд | ||
| + | [[Serve.cfg:problem:max_stack_size|max_stack_size]] = 8M # Ограничение размера стека - 8 мегабайт | ||
| + | [[Serve.cfg:problem:max_vm_size|max_vm_size]] = 64M # Ограничение общего размера вирт. памяти - 64 мегабайта | ||
| + | |||
| + | Идентификационные параметры задачи — это идентификатор задачи [[Serve.cfg:problem:id|<tt>id</tt>]], короткое название [[Serve.cfg:problem:short_name|<tt>short_name</tt>]], полное название [[Serve.cfg:problem:long_name|<tt>long_name</tt>]] и, возможно, внутреннее название задачи [[Serve.cfg:problem:internal_name|<tt>internal_name</tt>]]. | ||
| + | |||
| + | Значение параметра [[Serve.cfg:problem:corr_dir|<tt>corr_dir</tt>]] несущественно, так как предполагается что турнир настраивается в альтернативной раскладке файлов. Тем не менее, параметр <tt>corr_dir</tt> должен быть установлен в некоторое непустое значение. | ||
| + | |||
| + | === Настройка дополнительных параметров для задач на разработку тестов === | ||
Для задачи на написание тестов должны быть установлены следующие параметры задачи. | Для задачи на написание тестов должны быть установлены следующие параметры задачи. | ||
| − | [problem] | + | [[Serve.cfg:problem:type|type]] = "[[Задача:tests|tests]]" |
| − | + | [[Serve.cfg:problem:binary|binary]] | |
| − | type = "tests" | + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-gzip" |
| − | binary | + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-compress" |
| − | enable_language = "application/x-gzip" | + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-bzip2" |
| + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-tar" | ||
| + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/zip" | ||
| + | |||
| + | Параметр [[Serve.cfg:problem:type|<tt>type</tt>]] задает тип задачи как задачу на разработку тестов. Параметр [[Serve.cfg:problem:binary|<tt>binary</tt>]] разрешает прием двоичных файлов в качестве решений. Параметр [[Serve.cfg:problem:enable_language|<tt>enable_language</tt>]] разрешает прием архивных файлов в качестве решений. | ||
| + | |||
| + | === Настройка проверки правильности сдаваемого архива === | ||
| + | |||
| + | Архив, сдаваемый участником на проверку, должен быть проверен на корректность. Необходимо проверить, что файлы в архиве | ||
| + | по отдельности и все в целом удовлетворяют ограничениям на размер и количество файлов, что имена всех файлов заданы корректно, | ||
| + | что в архиве отсутствуют лишние файлы. Эта проверка должна быть выполнена без разархивирования архива в файловую систему во избежание потенциальных дыр в безопасности. Такая проверка выполняется программой [[style_archive]], поставляемой в составе ejudge. | ||
| + | |||
| + | Чтобы включить проверку сдаваемых архивов необходимо добавить в раздел описания задачи определение конфигурационной переменной [[Serve.cfg:problem:style_checker_cmd|<tt>style_checker_cmd</tt>]]. | ||
| + | |||
| + | [[Serve.cfg:problem:style_checker_cmd|style_checker_cmd]] = "[[Подстановка параметров configure|@prefix@]]/libexec/ejudge/checkers/style_archive" | ||
| + | |||
| + | Здесь <tt>@prefix@</tt> будет автоматически заменен на каталог, в который проинсталлирована система ejudge. Параметры проверки архива на целостность программе [[style_archive]] можно передавать либо с помощью командной строки, либо с помощью переменных окружения. В разделе конфигурации задачи можно воспользоваться механизмом передачи параметров с помощью переменных окружения. | ||
| + | |||
| + | Чтобы включить режим проверки тестов необходимо задать переменную окружения <tt>EJ_TESTS_MODE</tt>. | ||
| + | |||
| + | [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_TESTS_MODE=1" | ||
| + | |||
| + | Чтобы установить максимальный размер файла в архиве равным 1 килобайт необходимо задать переменную окружения <tt>EJ_MAX_FILE_SIZE</tt>. | ||
| + | |||
| + | [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_MAX_FILE_SIZE=1K" | ||
| + | |||
| + | Чтобы установить максимальное количество тестов (то есть пар файлов c входными данными и с правильным ответом) равным 10 необходимо задать переменую окружения <tt>EJ_MAX_TEST_COUNT</tt>. | ||
| + | |||
| + | [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_MAX_TEST_COUNT=10" | ||
| + | |||
| + | Параметр <tt>style_checker_env</tt> может повторяться в разделе описания задачи несколько раз. Для полного описания поддерживаемых программой [[style_archive]] переменных окружения смотрите [[style_archive|ее описание]]. | ||
| + | |||
| + | === Настройка проверки тестов === | ||
| + | |||
| + | Файлы с тестовыми данными, сданные на проверку, должны быть предварительно проверены на корректность [[Test checkers|проверяющей программой для тестов]]. Провеяющая программа для тестов должна проверить входной и выходной форматы файлов, ограничения на входные данные. Кроме того, программа может проверить соответствие входных данных и ответа. | ||
| + | |||
| + | Имя проверяющей программы для тестов задается с помощью конфигурационной переменной [[Serve.cfg:problem:test_checker_cmd|<tt>test_checker_cmd</tt>]]. При необходимости дополнительные переменные окружения могут задаваться с помощью конфигурационной переменной [[Serve.cfg:problem:test_checker_env|<tt>test_checker_env</tt>]]. | ||
| + | |||
| + | [[Serve.cfg:problem:test_checker_cmd|test_checker_cmd]] = "testcheck" | ||
| + | |||
| + | В этом примере имя проверяющей программы — <tt>testcheck</tt>. | ||
| + | |||
| + | === Итоговая конфигурация задачи === | ||
| + | |||
| + | С учетом всего вышесказанного, раздел конфигурации задачи может выглядеть следующим образом. | ||
| + | |||
| + | [[Serve.cfg:problem:id|id]] = ... | ||
| + | [[Serve.cfg:problem:short_name|short_name]] = ... | ||
| + | [[Serve.cfg:problem:long_name|long_name]] = ... | ||
| + | [[Serve.cfg:problem:type|type]] = "[[Задача:tests|tests]]" | ||
| + | [[Serve.cfg:problem:test_sfx|test_sfx]] = ".dat" | ||
| + | [[Serve.cfg:problem:use_corr|use_corr]] | ||
| + | [[Serve.cfg:problem:corr_dir|corr_dir]] = "[[Форматная подстановка|%Ps]]" | ||
| + | [[Serve.cfg:problem:corr_sfx|corr_sfx]] = ".ans" | ||
| + | [[Serve.cfg:problem:use_stdin|use_stdin]] | ||
| + | [[Serve.cfg:problem:use_stdout|use_stdout]] | ||
| + | [[Serve.cfg:problem:standard_checker|standard_checker]] = "[[cmp_int]]" | ||
| + | [[Serve.cfg:problem:time_limit|time_limit]] = 1 | ||
| + | [[Serve.cfg:problem:real_time_limit|real_time_limit]] = 5 | ||
| + | [[Serve.cfg:problem:max_stack_size|max_stack_size]] = 8M | ||
| + | [[Serve.cfg:problem:max_vm_size|max_vm_size]] = 64M | ||
| + | [[Serve.cfg:problem:binary|binary]] | ||
| + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-gzip" | ||
| + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-compress" | ||
| + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-bzip2" | ||
| + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-tar" | ||
| + | [[Serve.cfg:problem:enable_language|enable_language]] = "application/zip" | ||
| + | [[Serve.cfg:problem:style_checker_cmd|style_checker_cmd]] = "[[Подстановка параметров configure|@prefix@]]/libexec/ejudge/checkers/style_archive" | ||
| + | [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_TESTS_MODE=1" | ||
| + | [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_MAX_FILE_SIZE=1K" | ||
| + | [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_MAX_TEST_COUNT=10" | ||
| + | [[Serve.cfg:problem:test_checker_cmd|test_checker_cmd]] = "testcheck" | ||
| + | |||
| + | Часть этих параметров можно перенести в раздел абстрактной задачи. | ||
| + | |||
| + | === Написание проверяющей программы для тестов === | ||
| + | |||
| + | Следующий шаг — написание программы для проверки корректности тестов. Эта программа получает два аргумента | ||
| + | командной строки: имя файла с тестовыми данными и имя файла с правильным результатом работы. Программа проверки корректности тестов может, в принципе, модифицировать и первый, и второй файл. Для последующего тестирования будут передаваться уже модифицированные файлы. | ||
| + | |||
| + | Рассмотрим программу для проверки корректности тестов для задачи сложения двух целых чисел. На стандартном потоке ввода задаются два целых числа в диапазоне [-32768;32767]. На стандартный поток вывода необходимо напечатать сумму этих чисел. | ||
| + | |||
| + | Программу проверки корректности тестов можно писать на любом языке (в том числе и скриптовом). В нашем случае эта программа будет написана на языке Си с использованием библиотеки [[libchecker]]. | ||
| + | |||
| + | #include "[[Libchecker:Заголовочные файлы|checkutils.h]]" | ||
| + | |||
| + | #include <limits.h> | ||
| + | |||
| + | int | ||
| + | main(int argc, char **argv) | ||
| + | { | ||
| + | int x, y, z; | ||
| + | |||
| + | /* проверить, что передано правильное число аргументов командной строки */ | ||
| + | if (argc != 3) [[libchecker:fatal_CF|fatal_CF]]("wrong number of arguments"); | ||
| + | |||
| + | /* открыть файл с тестовыми данными и прочитать два числа */ | ||
| + | [[libchecker:checker_SRC_open|checker_in_open]](argv[1]); | ||
| + | [[libchecker:checker_read_TYPE_ex|checker_read_int_ex]]([[libchecker:Глобальные переменные|f_arr]][0], [[libchecker:fatal_PE|fatal_PE]], "x", 1, &x); | ||
| + | [[libchecker:checker_read_TYPE_ex|checker_read_int_ex]]([[libchecker:Глобальные переменные|f_arr[0]]], [[libchecker:fatal_PE|fatal_PE]], "y", 1, &y); | ||
| + | [[libchecker:checker_eof|checker_eof]]([[libchecker:Глобальные переменные|f_arr[0]]], [[libchecker:fatal_PE|fatal_PE]], "test input"); | ||
| + | [[libchecker:checker_SRC_close|checker_in_close]](); | ||
| + | |||
| + | /* проверить ограничения на входные данные */ | ||
| + | if (x < SHRT_MIN || x > SHRT_MAX) | ||
| + | [[libchecker:fatal_PE|fatal_PE]]("first value is out of range"); | ||
| + | if (y < SHRT_MIN || y > SHRT_MAX) | ||
| + | [[libchecker:fatal_PE|fatal_PE]]("second value is out of range"); | ||
| + | |||
| + | /* открыть файл с правильным ответом и прочитать число */ | ||
| + | [[libchecker:checker_SRC_open|checker_out_open]](argv[2]); | ||
| + | [[libchecker:checker_read_TYPE_ex|checker_read_int_ex]]([[libchecker:Глобальные переменные|f_arr[1]]], [[libchecker:fatal_PE|fatal_PE]], "z", 1, &z); | ||
| + | [[libchecker:checker_eof|checker_eof]]([[libchecker:Глобальные переменные|f_arr[1]]], [[libchecker:fatal_PE|fatal_PE]], "test answer"); | ||
| + | [[libchecker:checker_SRC_close|checker_out_close]](); | ||
| + | |||
| + | /* проверить правильность ответа */ | ||
| + | if (z != x + y) | ||
| + | [[libchecker:fatal_WA|fatal_WA]]("wrong answer"); | ||
| + | |||
| + | return 0; | ||
| + | } | ||
| + | |||
| + | Эту программу назовем <tt>testcheck.c</tt> и поместим в каталог с файлами задачи. Обратите внимание, что [[внутренняя ошибка проверки]] выдается в случае неправильного использования самой программы проверки тестов. Если входной файл или файл правильного ответа не соответствуют ограничениям задачи, выдается [[ошибка неправильного формата результата]]. | ||
| + | |||
| + | Если в файле правильного ответа на самом деле записан неправильный ответ, программа проверки тестов выдает ошибку [[неправильный ответ]]. Это не обязательно. Неправильные ответы можно и не выявлять на стадии проверки тестов, тогда на стадии запуска тестовых программ корректные программы не пройдут эти тесты, что тоже будет диагностировано как ошибка в тестах, предъявленных на проверку. | ||
| + | |||
| + | === Подготовка тестовых программ === | ||
| + | |||
| + | При работе турнира в альтернативной раскладке файлов тесты к задачам размещаются в каталоге tests каталога задачи. В случае задачи на написание тестов в каталоге tests должны находиться два каталога: <tt>good</tt>, в который помещаются программы, правильно решающие задачу, которые должны проходить все тесты, и <tt>fail</tt>, в который помещаются программы, содержащие ошибку, которые не должны проходить все тесты. | ||
| + | |||
| + | Каталоги <tt>good</tt> и <tt>fail</tt> могут иметь произвольную структуру. Для запуска на выполнение при проверке тестов будут выбираться только регулярные файлы, размещенные непосредственно в этих каталогах (то есть рекурсивный обход подкаталогов не выполняется). Из регулярных файлов выбираются только файлы, у которых установлен бит выполнения <tt>x</tt>. Все прочие файлы игнорируются. Таким образом, в этих каталогах могут находится исходные тексты программ <tt>.c</tt>, <tt>.cpp</tt> и прочие файлы, при условии, что у исходных текстов программ не установлен бит <tt>x</tt>. | ||
| + | |||
| + | Файлы, запускаемые на выполнение, могут быть произвольными файлами, исполнение которых поддерживается в данной операционной системе, например, бинарными исполняемымы файлами, скриптами на языках perl, python и т. д. Система ejudge не поддерживает автоматическую компиляцию файлов, аналогичную автоматической компиляции проверяющих программ, но поддерживается запуск make в каталоге задачи, с помощью которого можно компилировать и тестовые программы. | ||
| + | |||
| + | Обратите внимание, что тестовые программы запускаются в обычном (незащищенном) режиме, поэтому рекомендуется аудит тестовых программ с целью предотвращения потенциальных нарушений безопасности. | ||
| + | |||
| + | === Написание Makefile === | ||
| + | |||
| + | Для перекомпиляции программы проверки тестов, проверяющей программы и тестовых программ необходимо написать <tt>Makefile</tt>. | ||
| + | Этот файл должен располагаться в каталоге задачи (там где располагаются исходники программы проверки тестов и каталог <tt>tests</tt>). | ||
| + | Система ejudge вызывает программу make каждый раз, когда выполняется операция "Check contests settings". | ||
| − | + | Файл <tt>Makefile</tt> может быть примерно таким: | |
| − | + | # Переменная окружения EJUDGE_PREFIX_DIR передается в make при выполнении Check contests settings автоматически | |
| + | # но если ее нет (например, make вызывается из командной строки), то установим вручную | ||
| + | ifndef EJUDGE_PREFIX_DIR | ||
| + | EJUDGE_PREFIX_DIR = /opt/ejudge | ||
| + | endif | ||
| + | |||
| + | # Установка опций компилятора gcc для использования libchecker | ||
| + | EJUDGE_CONFIG = ${EJUDGE_PREFIX_DIR}/bin/ejudge-config | ||
| + | LIBCHECKER_CFLAGS = $(shell ${EJUDGE_CONFIG} --cflags) | ||
| + | LIBCHECKER_LDFLAGS = $(shell ${EJUDGE_CONFIG} --ldflags) | ||
| + | LIBCHECKER_LIBS = $(shell ${EJUDGE_CONFIG} --libs) | ||
| + | |||
| + | CC = gcc | ||
| + | CFLAGS = -Wall -Werror -O2 -std=gnu99 -Wno-pointer-sign ${LIBCHECKER_CFLAGS} ${LIBCHECKER_LDFLAGS} | ||
| + | LD = gcc | ||
| + | LDLIBS = ${LIBCHECKER_LIBS} | ||
| + | |||
| + | # Берем все файлы, которые необходимо скомпилировать | ||
| + | GOOD_CFILES = $(wildcard tests/good/*.c) | ||
| + | GOOD_XFILES = $(GOOD_CFILES:.c=) | ||
| + | |||
| + | FAIL_CFILES = $(wildcard tests/fail/*.c) | ||
| + | FAIL_XFILES = $(FAIL_CFILES:.c=) | ||
| + | |||
| + | all : ejudge_make_problem | ||
| + | |||
| + | # При запуске из ejudge утилита make вызывается с целью ejudge_make_problems | ||
| + | ejudge_make_problem : testcheck ${GOOD_XFILES} ${FAIL_XFILES} | ||
| + | |||
| + | clean: | ||
| + | -rm -f testcheck ${GOOD_XFILES} ${FAIL_XFILES} | ||
Latest revision as of 20:11, 6 July 2010
Навигация: Главная страница/Система ejudge/Использование/Виды задач/Задача на написание тестов/Подготовка задачи
Задачи этого типа являются самыми сложными для подготовки. При описании подготовки таких задач будет предполагаться, что турнир настраивается в альтернативной раскладке файлов, то есть все файлы, относящиеся к задаче, размещаются в одном каталоге.
Contents
- 1 Настройка основных параметров задачи
- 2 Настройка дополнительных параметров для задач на разработку тестов
- 3 Настройка проверки правильности сдаваемого архива
- 4 Настройка проверки тестов
- 5 Итоговая конфигурация задачи
- 6 Написание проверяющей программы для тестов
- 7 Подготовка тестовых программ
- 8 Написание Makefile
Настройка основных параметров задачи
Поскольку задача на написание тестов предполагает запуск программ на тестовых данных аналогично стандартной задаче, в разделе конфигурации задачи должны быть установлены параметры, относящиеся к тестированию задач. Например:
# Идентификационные параметры задачи id = ... short_name = ... long_name = ... # Основные параметры задачи test_sfx = ".dat" # Суффикс имен файлов с тестовыми данными use_corr # Проверка использует файлы с правильными ответами corr_dir = "%Ps" # Каталог с файлами с правильными ответами - значение не важно corr_sfx = ".ans" # Суффикс имен файлов с правильным ответом use_stdin # Программа считывает результат со стандартного потока ввода use_stdout # Программа выводит результат на стандартный поток вывода standard_checker = "cmp_int" # Проверка - сравнение двух целых чисел time_limit = 1 # Ограничение времени ЦП - 1 секунда real_time_limit = 5 # Ограничение реального времени - 5 секунд max_stack_size = 8M # Ограничение размера стека - 8 мегабайт max_vm_size = 64M # Ограничение общего размера вирт. памяти - 64 мегабайта
Идентификационные параметры задачи — это идентификатор задачи id, короткое название short_name, полное название long_name и, возможно, внутреннее название задачи internal_name.
Значение параметра corr_dir несущественно, так как предполагается что турнир настраивается в альтернативной раскладке файлов. Тем не менее, параметр corr_dir должен быть установлен в некоторое непустое значение.
Настройка дополнительных параметров для задач на разработку тестов
Для задачи на написание тестов должны быть установлены следующие параметры задачи.
type = "tests" binary enable_language = "application/x-gzip" enable_language = "application/x-compress" enable_language = "application/x-bzip2" enable_language = "application/x-tar" enable_language = "application/zip"
Параметр type задает тип задачи как задачу на разработку тестов. Параметр binary разрешает прием двоичных файлов в качестве решений. Параметр enable_language разрешает прием архивных файлов в качестве решений.
Настройка проверки правильности сдаваемого архива
Архив, сдаваемый участником на проверку, должен быть проверен на корректность. Необходимо проверить, что файлы в архиве по отдельности и все в целом удовлетворяют ограничениям на размер и количество файлов, что имена всех файлов заданы корректно, что в архиве отсутствуют лишние файлы. Эта проверка должна быть выполнена без разархивирования архива в файловую систему во избежание потенциальных дыр в безопасности. Такая проверка выполняется программой style_archive, поставляемой в составе ejudge.
Чтобы включить проверку сдаваемых архивов необходимо добавить в раздел описания задачи определение конфигурационной переменной style_checker_cmd.
style_checker_cmd = "@prefix@/libexec/ejudge/checkers/style_archive"
Здесь @prefix@ будет автоматически заменен на каталог, в который проинсталлирована система ejudge. Параметры проверки архива на целостность программе style_archive можно передавать либо с помощью командной строки, либо с помощью переменных окружения. В разделе конфигурации задачи можно воспользоваться механизмом передачи параметров с помощью переменных окружения.
Чтобы включить режим проверки тестов необходимо задать переменную окружения EJ_TESTS_MODE.
style_checker_env = "EJ_TESTS_MODE=1"
Чтобы установить максимальный размер файла в архиве равным 1 килобайт необходимо задать переменную окружения EJ_MAX_FILE_SIZE.
style_checker_env = "EJ_MAX_FILE_SIZE=1K"
Чтобы установить максимальное количество тестов (то есть пар файлов c входными данными и с правильным ответом) равным 10 необходимо задать переменую окружения EJ_MAX_TEST_COUNT.
style_checker_env = "EJ_MAX_TEST_COUNT=10"
Параметр style_checker_env может повторяться в разделе описания задачи несколько раз. Для полного описания поддерживаемых программой style_archive переменных окружения смотрите ее описание.
Настройка проверки тестов
Файлы с тестовыми данными, сданные на проверку, должны быть предварительно проверены на корректность проверяющей программой для тестов. Провеяющая программа для тестов должна проверить входной и выходной форматы файлов, ограничения на входные данные. Кроме того, программа может проверить соответствие входных данных и ответа.
Имя проверяющей программы для тестов задается с помощью конфигурационной переменной test_checker_cmd. При необходимости дополнительные переменные окружения могут задаваться с помощью конфигурационной переменной test_checker_env.
test_checker_cmd = "testcheck"
В этом примере имя проверяющей программы — testcheck.
Итоговая конфигурация задачи
С учетом всего вышесказанного, раздел конфигурации задачи может выглядеть следующим образом.
id = ... short_name = ... long_name = ... type = "tests" test_sfx = ".dat" use_corr corr_dir = "%Ps" corr_sfx = ".ans" use_stdin use_stdout standard_checker = "cmp_int" time_limit = 1 real_time_limit = 5 max_stack_size = 8M max_vm_size = 64M binary enable_language = "application/x-gzip" enable_language = "application/x-compress" enable_language = "application/x-bzip2" enable_language = "application/x-tar" enable_language = "application/zip" style_checker_cmd = "@prefix@/libexec/ejudge/checkers/style_archive" style_checker_env = "EJ_TESTS_MODE=1" style_checker_env = "EJ_MAX_FILE_SIZE=1K" style_checker_env = "EJ_MAX_TEST_COUNT=10" test_checker_cmd = "testcheck"
Часть этих параметров можно перенести в раздел абстрактной задачи.
Написание проверяющей программы для тестов
Следующий шаг — написание программы для проверки корректности тестов. Эта программа получает два аргумента командной строки: имя файла с тестовыми данными и имя файла с правильным результатом работы. Программа проверки корректности тестов может, в принципе, модифицировать и первый, и второй файл. Для последующего тестирования будут передаваться уже модифицированные файлы.
Рассмотрим программу для проверки корректности тестов для задачи сложения двух целых чисел. На стандартном потоке ввода задаются два целых числа в диапазоне [-32768;32767]. На стандартный поток вывода необходимо напечатать сумму этих чисел.
Программу проверки корректности тестов можно писать на любом языке (в том числе и скриптовом). В нашем случае эта программа будет написана на языке Си с использованием библиотеки libchecker.
#include "checkutils.h" #include <limits.h> int main(int argc, char **argv) { int x, y, z; /* проверить, что передано правильное число аргументов командной строки */ if (argc != 3) fatal_CF("wrong number of arguments"); /* открыть файл с тестовыми данными и прочитать два числа */ checker_in_open(argv[1]); checker_read_int_ex(f_arr[0], fatal_PE, "x", 1, &x); checker_read_int_ex(f_arr[0], fatal_PE, "y", 1, &y); checker_eof(f_arr[0], fatal_PE, "test input"); checker_in_close(); /* проверить ограничения на входные данные */ if (x < SHRT_MIN || x > SHRT_MAX) fatal_PE("first value is out of range"); if (y < SHRT_MIN || y > SHRT_MAX) fatal_PE("second value is out of range"); /* открыть файл с правильным ответом и прочитать число */ checker_out_open(argv[2]); checker_read_int_ex(f_arr[1], fatal_PE, "z", 1, &z); checker_eof(f_arr[1], fatal_PE, "test answer"); checker_out_close(); /* проверить правильность ответа */ if (z != x + y) fatal_WA("wrong answer"); return 0; }
Эту программу назовем testcheck.c и поместим в каталог с файлами задачи. Обратите внимание, что внутренняя ошибка проверки выдается в случае неправильного использования самой программы проверки тестов. Если входной файл или файл правильного ответа не соответствуют ограничениям задачи, выдается ошибка неправильного формата результата.
Если в файле правильного ответа на самом деле записан неправильный ответ, программа проверки тестов выдает ошибку неправильный ответ. Это не обязательно. Неправильные ответы можно и не выявлять на стадии проверки тестов, тогда на стадии запуска тестовых программ корректные программы не пройдут эти тесты, что тоже будет диагностировано как ошибка в тестах, предъявленных на проверку.
Подготовка тестовых программ
При работе турнира в альтернативной раскладке файлов тесты к задачам размещаются в каталоге tests каталога задачи. В случае задачи на написание тестов в каталоге tests должны находиться два каталога: good, в который помещаются программы, правильно решающие задачу, которые должны проходить все тесты, и fail, в который помещаются программы, содержащие ошибку, которые не должны проходить все тесты.
Каталоги good и fail могут иметь произвольную структуру. Для запуска на выполнение при проверке тестов будут выбираться только регулярные файлы, размещенные непосредственно в этих каталогах (то есть рекурсивный обход подкаталогов не выполняется). Из регулярных файлов выбираются только файлы, у которых установлен бит выполнения x. Все прочие файлы игнорируются. Таким образом, в этих каталогах могут находится исходные тексты программ .c, .cpp и прочие файлы, при условии, что у исходных текстов программ не установлен бит x.
Файлы, запускаемые на выполнение, могут быть произвольными файлами, исполнение которых поддерживается в данной операционной системе, например, бинарными исполняемымы файлами, скриптами на языках perl, python и т. д. Система ejudge не поддерживает автоматическую компиляцию файлов, аналогичную автоматической компиляции проверяющих программ, но поддерживается запуск make в каталоге задачи, с помощью которого можно компилировать и тестовые программы.
Обратите внимание, что тестовые программы запускаются в обычном (незащищенном) режиме, поэтому рекомендуется аудит тестовых программ с целью предотвращения потенциальных нарушений безопасности.
Написание Makefile
Для перекомпиляции программы проверки тестов, проверяющей программы и тестовых программ необходимо написать Makefile. Этот файл должен располагаться в каталоге задачи (там где располагаются исходники программы проверки тестов и каталог tests). Система ejudge вызывает программу make каждый раз, когда выполняется операция "Check contests settings".
Файл Makefile может быть примерно таким:
# Переменная окружения EJUDGE_PREFIX_DIR передается в make при выполнении Check contests settings автоматически
# но если ее нет (например, make вызывается из командной строки), то установим вручную
ifndef EJUDGE_PREFIX_DIR
EJUDGE_PREFIX_DIR = /opt/ejudge
endif
# Установка опций компилятора gcc для использования libchecker
EJUDGE_CONFIG = ${EJUDGE_PREFIX_DIR}/bin/ejudge-config
LIBCHECKER_CFLAGS = $(shell ${EJUDGE_CONFIG} --cflags)
LIBCHECKER_LDFLAGS = $(shell ${EJUDGE_CONFIG} --ldflags)
LIBCHECKER_LIBS = $(shell ${EJUDGE_CONFIG} --libs)
CC = gcc
CFLAGS = -Wall -Werror -O2 -std=gnu99 -Wno-pointer-sign ${LIBCHECKER_CFLAGS} ${LIBCHECKER_LDFLAGS}
LD = gcc
LDLIBS = ${LIBCHECKER_LIBS}
# Берем все файлы, которые необходимо скомпилировать
GOOD_CFILES = $(wildcard tests/good/*.c)
GOOD_XFILES = $(GOOD_CFILES:.c=)
FAIL_CFILES = $(wildcard tests/fail/*.c)
FAIL_XFILES = $(FAIL_CFILES:.c=)
all : ejudge_make_problem
# При запуске из ejudge утилита make вызывается с целью ejudge_make_problems
ejudge_make_problem : testcheck ${GOOD_XFILES} ${FAIL_XFILES}
clean:
-rm -f testcheck ${GOOD_XFILES} ${FAIL_XFILES}