Validators withВалидаторы и testlib.h
Разница между en16 и ru1, 7,940 символ(ов) изменены
If you have written some programming problems, and have prepared test cases, you will probably experience the terrible feeling that some test cases may be invalid (meaning it does not agree with the constraints in problem statement): upper bound can be violated, your graph not satisfied connectivity requirements or is not at tree... It is reasonable to feel that way. Even experienced problem setters make mistakes sometimes (for example, in the prestigious ACM ICPC World final 2007).↵

It is strictly recommended to write a special program (called _validator_) to formally check each test to satisfy all requirements from problem statements. Validators are strictly required for problems on Codeforces. [Polygon](https://polygon.codeforces.com) has built-in support of validators.↵

It is really easy to write a validator using testlib.h.↵

## Example↵

Following is the validator was written for the problem [problem:100541A]:↵

~~~~~↵
#include "testlib.h"↵
#include <bits/stdc++.h>↵
using namespace std;↵

int main() {↵
    registerValidation();↵
    int testCount = inf.readInt(1, 10, "testCount");↵
    inf.readEoln();↵
    ↵
    for (int i = 0; i < testCount; i++) {↵
        int n = inf.readInt(1, 100, "n");↵
        inf.readChar(' ');↵
        inf.readInt(1, 1000000, "w");↵
        inf.readEoln();↵

        for(int i = 0; i < n; ++i) {↵
            inf.readInt(1, 1000, "p_i");↵
            if (i < n-1) inf.readChar(' ');↵
        }↵
        inf.readEoln();↵
    }↵

    inf.readEof();↵
}↵

~~~~~↵

The wonderful thing about this validator is that it is very simple and it is very difficult to write something incorrect.↵

More examples can be found at [the Github repo](https://github.com/MikeMirzayanov/testlib/tree/master/validators)↵

## Available methods↵

The first line of your code should be `registerValidation()` which does some magic in the background, so that you can use the necessary methods.↵

[cut]↵

Most methods for validators start with prefix "read" and it does the same thing: moves input stream pointer to next suitable place after reading something. It also detect violations (input does not match what you are trying to read), and then throw error.↵

**Notes**:↵

- Validator is strict. It cares about correct placing of spaces. For example, when you're trying to read an integer and the next character is a space (and then an integer), the validator will throw error.↵
- Some method has "regex" feature. It is not a full-featured regex as you may have used in many programming languages. It is a very simple version, which supports the following:↵
    - **Set** of character, e.g: `[a-z]` is a lowercase latin letter, `[^a-z]` matches anything but a lowercase latin letter.↵
    - **Range**, e.g. `[a-z]{1,5}` is a string of length 1 to 5 consists of only lowercase latin letter.↵
    - **Or** operator, e.g. `mike|john` is either `mike` or `john`.↵
    - **Optional** character, e.g. `-?[1-9][0-9]{0,3}` will match non-zero integers from -9999 to 9999 (note the optional minus sign).↵
    - **Repetition**, e.g. `[0-9]*` will match sequences (empty or non-empty) of digits, and `[0-9]+` will match non-empty sequences of digits.↵
- Also regarding regex, very simple greedy algorithm is used. For example, pattern `[0-9]?1` will not match `1`, because of greedy nature of matching.↵

Following is full list of methods available:↵

|Method|What it does|↵
|-|-|↵
|void registerValidation()| This method must be called at the beginning of your code in order to use validator. <br> After calling this method, you can access input stream by variable named `inf`. |↵
|char readChar()| Returns current character and moves pointer one character forward.|↵
|char readChar(char c)| Same as `readChar()` but ensures that the readCharacter is 'c'.|↵
|char readSpace()| Same as `readChar(' ')`.|↵
|void unreadChar(char c)| Puts back character c to input stream.|↵
|string readToken()|Reads a new token.|↵
|string readToken(string regex)|Same as `readToken()` but ensures that it matches given regex.|↵
|long long readLong()|Reads a long (long long in C/C++ and long in Java)|↵
|long long readLong(int L, int R)|Same as `readLong()` but ensures that the value is in range $[L, R]$ (inclusively)|↵
|int readInt(), <br> int readInteger()|Reads an integer (int type in both Java and C/C++)|↵
|int readInt(int L, int R), <br> int readInteger(L, R)|Same as `readInt()` but ensures that the value is in range $[L, R]$ (inclusively)|↵
|double readReal(), <br> double readDouble()|Reads a double.|↵
|double readReal(double L, double R), <br> double readDouble(double L, double R)|Same as `readReal()`, `readDouble()` but ensures that the value is in range $[L, R]$.|↵
|double readStrictReal(double L, double R, int minPrecision, int maxPrecision), <br> double readStrictDouble(double L, double R, int minPrecision, int maxPrecision)|Same as `readReal(L, R)`, `readDouble(L, R)`, but additionally ensures that the number of digits after decimal point is between $[minPrecision, maxPrecision]$. Doesn't allow exponential or any other non-standard form.|↵
|string readString(), <br> string readLine()|Reads a line from current position to EOLN. Moves input stream pointer to first character of new line (if exists).|↵
|string readString(string regex), <br> string readLine(string regex)|Same as `readString()` and `readLine()`, but ensures that the string matches given regex.|↵
|void readEoln()|Reads EOLN or fails. Note that this method magically works on both Windows and Linux. On Windows it reads #13#10 and on Linux it reads #10.|↵
|void readEof()|Reads EOF or fails.|↵


#### Parameter _variableName_↵
It is recommended to insert last string parameter to readInt/readInteger/readLong/readDouble/readWord/readToken/readString/readLine called _variableName_ to make error message be human-readable. So it is preffered to use `inf.readInt(1, 100, n)` instead of `inf.readInt(1, 100)`. The first statement will fail with human-readable message like `FAIL Integer parameter [name=n] equals to 0, violates the range [1, 100]`.↵

#### Using ensure/ensuref↵

To check a requirement (like a graph doesn't contain loops, i.e. $x_i \ne y_i$) use `ensuref(x_i != y_i, "Graph can't contain loops")`. It is allowed to use C-language format specifiers like `ensuref(s.length() % 2 == 0, "String 's' should have even length, but s.length()=%d", int(s.length()))`. Also you can use simple form like `ensure(x > y)`, it will print failed condition if it doesn't hold in form `FAIL Condition failed: "x > y"`.↵


Reference: [Github page of testlib.h
Если вы написали несколько задач и подготовили для них тесты, вероятно, вы будете крайне неприятно себя чувствовать, если какие-то из тестов окажутся некорректными (в том смысле, что они не будут согласованы с условием задачи): значение какой-то величины будет больше допустимой верхней границы для нее, граф не будет удовлетворять требованиям связности или же не будет являться деревом...↵
Это естественно, что вы будете себя так чувствовать. Даже опытные авторы задач не застрахованы от ошибок (это случается даже на самых престижных соревнованиях: пример тому &mdash; финал чемпионата мира ACM ICPC 2007 г.)↵

Настоятельно рекомендуется писать специальную программу (называемую валидатором), чтобы формально проверить каждый тест на соответствие всем требованиям условия задачи.↵
Валидаторы обязательны для задач, которые готовятся для Codeforces. [Polygon](https://polygon.codeforces.com) имеет встроенную поддержку валидаторов.↵

Написать валидатор с помощью testlib.h на самом деле очень легко. ↵

## Пример↵

Ниже приводится валидатор, который была написан для задачи [problem:100541A]:↵

~~~~~↵
#include "testlib.h"↵
#include <bits/stdc++.h>↵
using namespace std;↵

int main() {↵
    registerValidation();↵
    int testCount = inf.readInt(1, 10, "testCount");↵
    inf.readEoln();↵
    ↵
    for (int i = 0; i < testCount; i++) {↵
        int n = inf.readInt(1, 100, "n");↵
        inf.readChar(' ');↵
        inf.readInt(1, 1000000, "w");↵
        inf.readEoln();↵

        for(int i = 0; i < n; ++i) {↵
            inf.readInt(1, 1000, "p_i");↵
            if (i < n-1) inf.readChar(' ');↵
        }↵
        inf.readEoln();↵
    }↵

    inf.readEof();↵
}↵

~~~~~↵

Самое замечательное в этом валидаторе то, что он очень простой, и в нем очень трудно написать что-то неправильно.↵

В репозитории Github можно найти другие [примеры валидаторов](https://github.com/MikeMirzayanov/testlib/tree/master/validators).↵

## Функции и методы↵

Первая строка вашего кода должна содержать вызов `registerValidation()`: немного магии, и вы можете использовать необходимые методы. ↵

[cut]↵

Большинство методов для валидатора начинаются с префикса _read_  и именно выполняют чтение: перемещают указатель во входном потоке на следующую позицию после прочтения чего-либо. В процессе чтения обнаруживаются нарушения (входные данные не соответствуют тому, что вы пытаетесь прочитать: например, вы предпринимаете попытку прочитать целое число, а во входных данных встречается строка) и выбрасывается ошибка.↵

**Замечания**:↵

- Валидатор строг. Он проверяет корректное расположение пробелов. Например, последовательность вызовов вида _прочесть число_, _прочесть пробел_, _прочесть число_ гарантирует наличие ровно одного пробела между числами; в противном случае валидатор сообщит об ошибке.↵
- Некоторые методы частично поддерживают синтаксис регулярных выражений. Конечно, это не полноценные регулярные выражения, которые вы можете использовать во многих языках программирования. Это очень простая версия, в которой поддерживается следующее:↵
    - **Множество** символов: например, `[a-z]` &mdash; любые строчные латинские буквы, `[^a-z]` &mdash;  любые символы за исключением строчных латинских букв.↵
    - **Диапазон**, например, шаблон `[a-z]{1,5}` описывает строки длиной от 1 до 5 символов, содержащие только строчные латинские буквы.↵
    - Оператор **Или**,  например, шаблон `mike|john` &mdash; это или строка `mike`, или строка `john`.↵
    - **Необязательные** символы, например, шаблон `-?[1-9][0-9]{0,3}` допускает ненулевые целые числа от -9999 до 9999 (обратите внимание на необязательный знак "минус").↵
    - **Повторения**, например, шаблон `[0-9]*` допускает последовательности (как пустые, так и непустые) цифр, а шаблон  `[0-9]+` только непустые последовательности цифр.↵
- Также заметим, что при распознавании регулярных выражений используется очень простой жадный алгоритм. Например, шаблон `[0-9]?1` не допускает `1` в силу жадного поведения распознавателя.↵

Ниже представлен полный список функций и методов↵

|Метод / функция|Что делает|↵
|-|-|↵
|void registerValidation()| Эта функция должна быть вызвана в начале вашего кода, чтобы использовать валидатор. После вызова этой функции вы получаете доступ к входному потоку посредством переменной `inf`. |↵
|char readChar()| Этот метод возвращает текущий символ и перемещает указатель на один символ вперед.|↵
|char readChar(char c)| Аналогичен `readChar()`, но обеспечивает проверку, что прочитанный символ именно `c`.|↵
|char readSpace()| Аналогичен `readChar(' ')`.|↵
|void unreadChar(char c)| Возвращает символ `c` во входной поток.|↵
|string readToken()|Читает и возвращает очередную лексему (токен).|↵
|string readToken(string regex)|Аналогичен `readToken()`, но выполняет проверку соответствия лексемы (токена) указанному регулярному выражению `regex`.|↵
|long long readLong()|Читает и возвращает длинное целое (`long long` в C/C++ и `long` в Java)|↵
|long long readLong(int L, int R)|Аналогичен `readLong()`, но выполняет проверку, что значение находится в диапазоне $[L, R]$ (включительно)|↵
|int readInt(), <br> int readInteger()|Читает и возвращает целое число (тип `int` как в Java, так и в C/C++)|↵
|int readInt(int L, int R), <br> int readInteger(L, R)|Аналогичны `readInt()`, но выполняет проверку, что значение находится в диапазоне $[L, R]$ (включительно)|↵
|double readReal(), <br> double readDouble()|Читают и возвращают вещественное число (`double`).|↵
|double readReal(double L, double R), <br> double readDouble(double L, double R)|Аналогичны `readReal()`, `readDouble()`, но выполняют проверку, что значение находится в диапазоне $[L, R]$.|↵
|double readStrictReal(double L, double R, int minPrecision, int maxPrecision), <br> double readStrictDouble(double L, double R, int minPrecision, int maxPrecision)|Аналогичны `readReal(L, R)`, `readDouble(L, R)`, но выполняют дополнительную проверку, что количество цифр после десятичной точки находится в диапазоне $[minPrecision, maxPrecision]$. Экспоненциальная запись числа или другие нестандартные формы записи не допускаются.|↵
|string readString(), <br> string readLine()|Прочитывают строку, начиная с текущей позиции до EOLN.  Перемещают указатель во входном потоке на первый символ следующей строки (если она существует).|↵
|string readString(string regex), <br> string readLine(string regex)|Аналогичны `readString()` and `readLine()`, но выполняют проверку, что строка соответствует указанному регулярному выражению `regex`.|↵
|void readEoln()|Читает EOLN или завершает работу с ошибкой. Заметим, что этот метод чудесным образом работает как для Windows, так и для Linux. В Windows он прочитывает #13#10, а в Linux #10.|↵
|void readEof()|Читает EOF или завершает работу с ошибкой.|↵


#### Параметр _variableName_↵

Рекомендуется использовать последний строковый параметр _variableName_ в методах readInt/readInteger/readLong/readDouble/readWord/readToken/readString/readLine, чтобы сделать сообщение об ошибке более удобным для чтения. Т.е. предпочтительнее использовать `inf.readInt(1, 100, n)` вместо `inf.readInt(1, 100)`. При возникновении ошибки в первом случае будет выводиться сообщение вида  `FAIL Integer parameter [name=n] equals to 0, violates the range [1, 100]`.↵

#### Использование _ensure/ensuref_↵

Чтобы проверить некоторые требования (например, то, что граф не содержит петель, т.е. что $x_i \ne y_i$), используйте `ensuref(x_i != y_i, "Graph can't contain loops")`.  Допускается использование спецификаторов формата языка C, подобных `ensuref(s.length() % 2 == 0, "String 's' should have even length, but s.length()=%d", int(s.length()))`.↵
Также вы можете использовать более простую форму `ensure(x > y)`, в этом случае будет печататься нарушенное условие, если оно не выполняется: `FAIL Condition failed: "x > y"`.↵

Ссылки: [страница testlib.h на Github
](https://github.com/MikeMirzayanov/testlib/blob/master/testlib.h)↵

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
ru11 Русский KAN 2022-07-07 20:21:26 2128
en24 Английский KAN 2022-07-07 20:16:48 4201 Tiny change: 'alidation()` which d' -> 'alidation(argc, argv)` which d'
ru10 Русский KAN 2022-07-07 19:00:36 2066 added global methods
ru9 Русский KAN 2022-07-07 18:43:02 2171 updated functions
ru8 Русский MikeMirzayanov 2018-12-29 14:28:59 20 Мелкая правка: ' readLong(int L, int R)|Аналог' -> ' readLong(long long L, long long R)|Аналог'
ru7 Русский arsijo 2018-11-02 01:08:48 527
en23 Английский arsijo 2018-11-02 01:01:28 400
ru6 Русский Zlobober 2016-10-01 20:36:24 32
en22 Английский Zlobober 2016-02-24 02:54:05 32
en21 Английский I_love_Hoang_Yen 2015-06-18 14:09:58 20 Tiny change: ' readLong(int L, int R)|Same a' -> ' readLong(long long L, long long R)|Same a'
ru5 Русский riadwaw 2015-06-10 22:35:00 20
en20 Английский I_love_Hoang_Yen 2015-06-10 21:00:28 20
ru4 Русский MikeMirzayanov 2015-06-10 12:29:16 118
en19 Английский MikeMirzayanov 2015-06-10 12:27:46 410
en18 Английский PrinceOfPersia 2015-06-10 08:57:32 218
ru3 Русский MikeMirzayanov 2015-06-10 02:25:07 67
en17 Английский MikeMirzayanov 2015-06-10 02:24:34 67
ru2 Русский MikeMirzayanov 2015-06-10 02:20:24 3
ru1 Русский elena 2015-06-10 02:18:13 7940 Первая редакция перевода на Русский
en16 Английский elena 2015-06-10 01:13:44 30 Tiny change: 'inus sign), note that it will match '-0'.\n - *' -> 'inus sign).\n - *'
en15 Английский MikeMirzayanov 2015-06-09 17:33:29 1546
en14 Английский PrinceOfPersia 2015-06-09 17:16:10 56
en13 Английский I_love_Hoang_Yen 2015-06-09 14:08:48 125
en12 Английский I_love_Hoang_Yen 2015-06-09 14:06:24 246 Tiny change: '| Same as readChar(' ').|\n|void ' -> '| Same as `readChar(' ')`.|\n|void '
en11 Английский I_love_Hoang_Yen 2015-06-09 13:56:28 86 Update styling
en10 Английский I_love_Hoang_Yen 2015-06-09 13:53:23 1840 (published)
en9 Английский I_love_Hoang_Yen 2015-06-09 13:38:13 291
en8 Английский I_love_Hoang_Yen 2015-06-09 13:34:33 28 Tiny change: ' C/C++)|\n\n|readInt' -
en7 Английский I_love_Hoang_Yen 2015-06-09 13:01:14 3 Tiny change: 'readInt(), readIntege' -> 'readInt(),\nreadIntege'
en6 Английский I_love_Hoang_Yen 2015-06-09 12:54:26 2 Tiny change: ' in range [L, R].|\n|readS' -> ' in range $[L, R]$.|\n|readS'
en5 Английский I_love_Hoang_Yen 2015-06-09 12:54:01 60
en4 Английский I_love_Hoang_Yen 2015-06-09 12:52:57 1888
en3 Английский I_love_Hoang_Yen 2015-06-09 12:34:31 206
en2 Английский I_love_Hoang_Yen 2015-06-09 12:04:31 331
en1 Английский I_love_Hoang_Yen 2015-06-09 12:01:01 1478 Initial revision (saved to drafts)