Difference between revisions of "Подготовка задачи tests"

From EjudgeWiki
(Настройка дополнительных параметров для задач на разработку тестов)
 
(24 intermediate revisions by the same user not shown)
Line 14: Line 14:
 
  [[Serve.cfg:problem:test_sfx|test_sfx]] = ".dat"            # Суффикс имен файлов с тестовыми данными
 
  [[Serve.cfg:problem:test_sfx|test_sfx]] = ".dat"            # Суффикс имен файлов с тестовыми данными
 
  [[Serve.cfg:problem:use_corr|use_corr]]                    # Проверка использует файлы с правильными ответами
 
  [[Serve.cfg:problem:use_corr|use_corr]]                    # Проверка использует файлы с правильными ответами
  [[Serve.cfg:problem:corr_dir|corr_dir]] = "%Ps"            # Каталог с файлами с правильными ответами - значение не важно
+
  [[Serve.cfg:problem:corr_dir|corr_dir]] = "[[Форматная подстановка|%Ps]]"            # Каталог с файлами с правильными ответами - значение не важно
 
  [[Serve.cfg:problem:corr_sfx|corr_sfx]] = ".ans"            # Суффикс имен файлов с правильным ответом
 
  [[Serve.cfg:problem:corr_sfx|corr_sfx]] = ".ans"            # Суффикс имен файлов с правильным ответом
 
  [[Serve.cfg:problem:use_stdin|use_stdin]]                    # Программа считывает результат со стандартного потока ввода
 
  [[Serve.cfg:problem:use_stdin|use_stdin]]                    # Программа считывает результат со стандартного потока ввода
Line 32: Line 32:
 
Для задачи на написание тестов должны быть установлены следующие параметры задачи.
 
Для задачи на написание тестов должны быть установлены следующие параметры задачи.
  
  type = "tests"
+
  [[Serve.cfg:problem:type|type]] = "[[Задача:tests|tests]]"
  binary
+
  [[Serve.cfg:problem:binary|binary]]
  enable_language = "application/x-gzip"
+
  [[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:type|<tt>type</tt>]] задает тип задачи как задачу на разработку тестов. Параметр [[Serve.cfg:problem:binary|<tt>binary</tt>]] разрешает прием двоичных файлов в качестве решений. Параметр [[Serve.cfg:problem:enable_language|<tt>enable_language</tt>]] разрешает прием файлов формата <tt>GZIP</tt> в качестве решений.
+
Параметр [[Serve.cfg:problem:type|<tt>type</tt>]] задает тип задачи как задачу на разработку тестов. Параметр [[Serve.cfg:problem:binary|<tt>binary</tt>]] разрешает прием двоичных файлов в качестве решений. Параметр [[Serve.cfg:problem:enable_language|<tt>enable_language</tt>]] разрешает прием архивных файлов в качестве решений.
  
 
=== Настройка проверки правильности сдаваемого архива ===
 
=== Настройка проверки правильности сдаваемого архива ===
Line 44: Line 48:
 
что в архиве отсутствуют лишние файлы. Эта проверка должна быть выполнена без разархивирования архива в файловую систему во избежание потенциальных дыр в безопасности. Такая проверка выполняется программой [[style_archive]], поставляемой в составе ejudge.
 
что в архиве отсутствуют лишние файлы. Эта проверка должна быть выполнена без разархивирования архива в файловую систему во избежание потенциальных дыр в безопасности. Такая проверка выполняется программой [[style_archive]], поставляемой в составе ejudge.
  
Чтобы включить проверку сдаваемых архивов необходимо добавить в раздел описания задачи определение конфигурационной переменной [[Serve.cfg:problem:style_checker|<tt>style_checker</tt>]].
+
Чтобы включить проверку сдаваемых архивов необходимо добавить в раздел описания задачи определение конфигурационной переменной [[Serve.cfg:problem:style_checker_cmd|<tt>style_checker_cmd</tt>]].
  
  style_checker_cmd = "@prefix@/libexec/ejudge/checkers/style_archive"
+
  [[Serve.cfg:problem:style_checker_cmd|style_checker_cmd]] = "[[Подстановка параметров configure|@prefix@]]/libexec/ejudge/checkers/style_archive"
  
 
Здесь <tt>@prefix@</tt> будет автоматически заменен на каталог, в который проинсталлирована система ejudge. Параметры проверки архива на целостность программе [[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>.
 
Чтобы установить максимальный размер файла в архиве равным 1 килобайт необходимо задать переменную окружения <tt>EJ_MAX_FILE_SIZE</tt>.
  
  style_checker_env = "EJ_MAX_FILE_SIZE=1K"
+
  [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_MAX_FILE_SIZE=1K"
  
 
Чтобы установить максимальное количество тестов (то есть пар файлов c входными данными и с правильным ответом) равным 10 необходимо задать переменую окружения <tt>EJ_MAX_TEST_COUNT</tt>.
 
Чтобы установить максимальное количество тестов (то есть пар файлов c входными данными и с правильным ответом) равным 10 необходимо задать переменую окружения <tt>EJ_MAX_TEST_COUNT</tt>.
  
  style_checker_env = "EJ_MAX_TEST_COUNT=10"
+
  [[Serve.cfg:problem:style_checker_env|style_checker_env]] = "EJ_MAX_TEST_COUNT=10"
  
 
Параметр <tt>style_checker_env</tt> может повторяться в разделе описания задачи несколько раз. Для полного описания поддерживаемых программой [[style_archive]] переменных окружения смотрите [[style_archive|ее описание]].
 
Параметр <tt>style_checker_env</tt> может повторяться в разделе описания задачи несколько раз. Для полного описания поддерживаемых программой [[style_archive]] переменных окружения смотрите [[style_archive|ее описание]].
Line 66: Line 74:
 
Имя проверяющей программы для тестов задается с помощью конфигурационной переменной [[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|<tt>test_checker_cmd</tt>]]. При необходимости дополнительные переменные окружения могут задаваться с помощью конфигурационной переменной [[Serve.cfg:problem:test_checker_env|<tt>test_checker_env</tt>]].
  
  test_checker_cmd = "testcheck"
+
  [[Serve.cfg:problem:test_checker_cmd|test_checker_cmd]] = "testcheck"
  
 
В этом примере имя проверяющей программы &mdash; <tt>testcheck</tt>.
 
В этом примере имя проверяющей программы &mdash; <tt>testcheck</tt>.
Line 74: Line 82:
 
С учетом всего вышесказанного, раздел конфигурации задачи может выглядеть следующим образом.
 
С учетом всего вышесказанного, раздел конфигурации задачи может выглядеть следующим образом.
  
  id = ...
+
  [[Serve.cfg:problem:id|id]] = ...
  short_name = ...
+
  [[Serve.cfg:problem:short_name|short_name]] = ...
  long_name = ...
+
  [[Serve.cfg:problem:long_name|long_name]] = ...
  type = "tests"
+
  [[Serve.cfg:problem:type|type]] = "[[Задача:tests|tests]]"
  test_sfx = ".dat"
+
  [[Serve.cfg:problem:test_sfx|test_sfx]] = ".dat"
  use_corr
+
  [[Serve.cfg:problem:use_corr|use_corr]]
  corr_dir = "%Ps"
+
  [[Serve.cfg:problem:corr_dir|corr_dir]] = "[[Форматная подстановка|%Ps]]"
  corr_sfx = ".ans"
+
  [[Serve.cfg:problem:corr_sfx|corr_sfx]] = ".ans"
  use_stdin
+
  [[Serve.cfg:problem:use_stdin|use_stdin]]
  use_stdout
+
  [[Serve.cfg:problem:use_stdout|use_stdout]]
  standard_checker = "cmp_int"
+
  [[Serve.cfg:problem:standard_checker|standard_checker]] = "[[cmp_int]]"
  time_limit = 1
+
  [[Serve.cfg:problem:time_limit|time_limit]] = 1
  real_time_limit = 5
+
  [[Serve.cfg:problem:real_time_limit|real_time_limit]] = 5
  max_stack_size = 8M
+
  [[Serve.cfg:problem:max_stack_size|max_stack_size]] = 8M
  max_vm_size = 64M
+
  [[Serve.cfg:problem:max_vm_size|max_vm_size]] = 64M
  binary
+
  [[Serve.cfg:problem:binary|binary]]
  enable_language = "application/x-gzip"
+
  [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-gzip"
  style_checker_cmd = "@prefix@/libexec/ejudge/checkers/style_archive"
+
  [[Serve.cfg:problem:enable_language|enable_language]] = "application/x-compress"
  style_checker_env = "EJ_MAX_FILE_SIZE=1K"
+
[[Serve.cfg:problem:enable_language|enable_language]] = "application/x-bzip2"
  style_checker_env = "EJ_MAX_TEST_COUNT=10"
+
[[Serve.cfg:problem:enable_language|enable_language]] = "application/x-tar"
  test_checker_cmd = "testcheck"
+
[[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"
  
 
Часть этих параметров можно перенести в раздел абстрактной задачи.
 
Часть этих параметров можно перенести в раздел абстрактной задачи.
Line 107: Line 120:
 
Программу проверки корректности тестов можно писать на любом языке (в том числе и скриптовом). В нашем случае эта программа будет написана на языке Си с использованием библиотеки [[libchecker]].
 
Программу проверки корректности тестов можно писать на любом языке (в том числе и скриптовом). В нашем случае эта программа будет написана на языке Си с использованием библиотеки [[libchecker]].
  
  #include "[[libchecker:checkutils.h|checkutils.h]]"
+
  #include "[[Libchecker:Заголовочные файлы|checkutils.h]]"
 
   
 
   
 
  #include <limits.h>
 
  #include <limits.h>
Line 116: Line 129:
 
   int x, y, z;
 
   int x, y, z;
 
   
 
   
   if (argc != 3) fatal_CF("wrong number of arguments");
+
  /* проверить, что передано правильное число аргументов командной строки */
 +
   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]]();
 
   
 
   
   [[libchecker:checker_in_open|checker_in_open]](argv[1]);
+
   /* проверить ограничения на входные данные */
   [[libchecker:checker_read_int_ex|checker_read_int_ex]](f_arr[0], fatal_PE, "x", 1, &x);
+
   if (x < SHRT_MIN || x > SHRT_MAX)
  [[libchecker:checker_read_int_ex|checker_read_int_ex]](f_arr[0], fatal_PE, "y", 1, &y);
+
    [[libchecker:fatal_PE|fatal_PE]]("first value is out of range");
  [[libchecker:checker_eof|checker_eof]](f_arr[0], fatal_PE, "test input");
+
  if (y < SHRT_MIN || y > SHRT_MAX)
  [[libchecker:checker_in_close|checker_in_close]]();
+
    [[libchecker:fatal_PE|fatal_PE]]("second value is out of range");
  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);
+
  [[libchecker:checker_SRC_open|checker_out_open]](argv[2]);
   checker_eof(f_arr[1], fatal_PE, "test answer");
+
   [[libchecker:checker_read_TYPE_ex|checker_read_int_ex]]([[libchecker:Глобальные переменные|f_arr[1]]], [[libchecker:fatal_PE|fatal_PE]], "z", 1, &z);
   checker_out_close();
+
   [[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)
 
   if (z != x + y)
     fatal_WA("wrong answer");
+
     [[libchecker:fatal_WA|fatal_WA]]("wrong answer");
 
   
 
   
 
   return 0;
 
   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/Использование/Виды задач/Задача на написание тестов/Подготовка задачи

Задачи этого типа являются самыми сложными для подготовки. При описании подготовки таких задач будет предполагаться, что турнир настраивается в альтернативной раскладке файлов, то есть все файлы, относящиеся к задаче, размещаются в одном каталоге.

Настройка основных параметров задачи

Поскольку задача на написание тестов предполагает запуск программ на тестовых данных аналогично стандартной задаче, в разделе конфигурации задачи должны быть установлены параметры, относящиеся к тестированию задач. Например:

# Идентификационные параметры задачи
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}