From dacae83dc611776795cf9fc81618ec6fcab2afb4 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilovich Date: Sat, 11 Apr 2026 09:28:53 +0300 Subject: [PATCH] add some dsl examples --- example/showcase/01-minimal.jdg | 23 +++++++ example/showcase/02-structured-build.jdg | 72 ++++++++++++++++++++ example/showcase/03-matchers.jdg | 69 +++++++++++++++++++ example/showcase/04-limits-scoring-env.jdg | 77 ++++++++++++++++++++++ example/showcase/05-pattern-expansion.jdg | 52 +++++++++++++++ example/showcase/06-files.jdg | 59 +++++++++++++++++ 6 files changed, 352 insertions(+) create mode 100644 example/showcase/01-minimal.jdg create mode 100644 example/showcase/02-structured-build.jdg create mode 100644 example/showcase/03-matchers.jdg create mode 100644 example/showcase/04-limits-scoring-env.jdg create mode 100644 example/showcase/05-pattern-expansion.jdg create mode 100644 example/showcase/06-files.jdg diff --git a/example/showcase/01-minimal.jdg b/example/showcase/01-minimal.jdg new file mode 100644 index 0000000..a39b0c4 --- /dev/null +++ b/example/showcase/01-minimal.jdg @@ -0,0 +1,23 @@ +// Минимальный рабочий suite на structured DSL. +// Декларируем один toolchain, один build, одну группу с одним тестом. +// С этого можно копипастить для новых задач. + +toolchains { + gcc { platforms = "linux" } +} + +build "release" { + language = "c" + standard = "c11" + sources = "solution.c" + output = "solution" + profile = release +} + +group("basic") { + weight = 1.0 + + test("hello") { + stdout = "Hello, World!\n" + } +} diff --git a/example/showcase/02-structured-build.jdg b/example/showcase/02-structured-build.jdg new file mode 100644 index 0000000..5763250 --- /dev/null +++ b/example/showcase/02-structured-build.jdg @@ -0,0 +1,72 @@ +// Полный showcase возможностей build-блока. +// Показывает: toolchains c платформами / переопределением binary / явным class, +// build_defaults как общая основа, три профиля (release/debug/sanitized), +// фильтры platforms и compilers, OS-оверрайды, wrapper, sanitize, define, +// includes, link, extra, а также build-level `wrapper` для valgrind. + +toolchains { + gcc { platforms = "linux" } + clang { + platforms = "linux" "windows" + binary = "clang-17" // конкретная версия в PATH + class = gnu // явный class если имя нестандартное + } + msvc { platforms = "windows" } + nvcc { + platforms = "linux" + class = gnu // nvcc принимает gnu-like флаги + } +} + +build_defaults { + language = "c" + standard = "c11" + sources = "src/*.c" // glob, раскрывается относительно work dir + output = "solution" // на Windows автоматически станет solution.exe + includes = "include" "vendor/include" + link = "m" "pthread" + warnings = strict // → -Wall -Wextra / /W4 + define("BUILD_ID") = "42" +} + +build "release" { + profile = release // → -O2 / /O2 + + // OS-специфичные правки поверх defaults. Скаляры переопределяются, + // списки (extra, sanitize, sources, includes) аккумулируются. + linux { extra = "-fPIC" } + windows { extra = "/bigobj" } + darwin { extra = "-mmacosx-version-min=11" } +} + +build "debug" { + profile = debug // → -O0 -g / /Od /Zi + warnings = pedantic // → добавляет -Wpedantic / /permissive- + define("DEBUG") = "1" +} + +build "sanitized" { + profile = sanitized + sanitize = "address" "undefined" "leak" + platforms = "linux" // UBSan не работает на MSVC + compilers = "gcc" "clang" // и только gnu-like + extra = "-fno-sanitize-recover=all" +} + +build "debug-valgrind" { + profile = debug + wrapper = "valgrind --error-exitcode=99 --leak-check=full -q" + platforms = "linux" + compilers = "gcc" +} + +timeout 10s +memory_limit = 256M + +group("basic") { + weight = 1.0 + + test("smoke") { + stdout = "ok\n" + } +} diff --git a/example/showcase/03-matchers.jdg b/example/showcase/03-matchers.jdg new file mode 100644 index 0000000..ae79ba4 --- /dev/null +++ b/example/showcase/03-matchers.jdg @@ -0,0 +1,69 @@ +// Все способы сматчить stdout/stderr: exact, contains, regex, anyOrder, +// numeric-eps. Плюс случай, когда сравнение вывода вообще не нужно +// (достаточно exitCode). + +toolchains { + gcc { platforms = "linux" } +} + +build "release" { + language = "c" + standard = "c11" + sources = "solution.c" + output = "solution" + profile = release +} + +group("matchers") { + weight = 1.0 + + // Точное совпадение (по умолчанию). Пробелы, переводы строк и + // регистр важны. Нормализация CRLF / trim_ws настраивается на + // уровне файла. + test("exact") { + stdin = "42\n" + stdout = "42\n" + } + + // Подстрока в любом месте вывода. + test("contains") { + stdin = "log me\n" + stdout contains "log me" + } + + // Регулярное выражение (Go regexp syntax). + test("regex") { + stdin = "7\n" + stdout matches "^result:\\s+[0-9]+\\s*$" + } + + // Лайны могут прийти в любом порядке — полезно для stress-тестов + // с параллельным выводом. + test("any-order") { + stdin = "start\n" + stdout anyOrder { + "alpha" + "beta" + "gamma" + } + } + + // Числовое сравнение с epsilon — для задач с плавающей точкой. + // Синтаксис: ~ of "<ожидаемое значение как строка>" + test("numeric") { + stdin = "3.14159\n" + stdout ~ 0.0001 of "3.14159\n" + } + + // Проверяем только stderr; stdout не трогаем вообще (NoMatcher). + test("stderr-only") { + args = "--version" + stderr contains "version 1." + } + + // Никакого матчинга вывода — нас интересует только exit code. + test("exit-code-only") { + args = "--help" + exitCode = 0 + } +} diff --git a/example/showcase/04-limits-scoring-env.jdg b/example/showcase/04-limits-scoring-env.jdg new file mode 100644 index 0000000..447a1fe --- /dev/null +++ b/example/showcase/04-limits-scoring-env.jdg @@ -0,0 +1,77 @@ +// Тонкая настройка: timeout и memory_limit на разных уровнях (file → group +// → test), режимы скоринга (partial / all_or_none), переменные окружения, +// проверка exit code, передача аргументов. + +toolchains { + gcc { platforms = "linux" } +} + +build "release" { + language = "c" + standard = "c11" + sources = "solution.c" + output = "solution" + profile = release +} + +// Глобальные дефолты. Применяются к каждому тесту, если тот не +// переопределит у себя или на уровне группы. +timeout 5s +memory_limit = 256M +normalize_crlf = true // стрип \r перед сравнением — полезно на Windows +trim_trailing_ws = true // trim trailing space/tab на каждой строке + +group("strict-subset") { + weight = 0.4 + scoring = all_or_none // группа даёт weight или 0 — без частичного + + // Эти дефолты применятся к каждому тесту группы. + timeout = 2s + memory_limit = 64M + env("LC_ALL") = "C" + env("LANG") = "C" + + test("fast") { + args = "--mode" "fast" + stdout = "ok\n" + } + + test("strict-timeout") { + timeout = 500ms // переопределяет group timeout + stdout = "ok\n" + } + + test("high-memory") { + memory_limit = 128M // переопределяет group memory_limit + stdout = "ok\n" + } + + test("own-env") { + env("FOO") = "bar" // добавляется к group env + stdout = "ok\n" + } +} + +group("partial-credit") { + weight = 0.6 + scoring = partial // default: weight * passed/total + + test("case-1") { + stdin = "1\n" + stdout = "1\n" + exitCode = 0 + } + + test("case-2") { + stdin = "2\n" + stdout = "4\n" + exitCode = 0 + } + + test("case-error") { + // Программа ДОЛЖНА выйти с кодом 1 на плохом вводе. + stdin = "abc\n" + exitCode = 1 + stderr contains "invalid input" + } +} diff --git a/example/showcase/05-pattern-expansion.jdg b/example/showcase/05-pattern-expansion.jdg new file mode 100644 index 0000000..6d14e48 --- /dev/null +++ b/example/showcase/05-pattern-expansion.jdg @@ -0,0 +1,52 @@ +// Автогенерация тестов из папки с файлами. Удобно когда тестов много и +// вручную выписывать каждый через test("...") { stdin = ... stdout = ... } +// будет слишком громоздко. +// +// Два режима: +// 1) file-glob — пары .in/.ans файлов +// 2) dir-mode — каждый тест лежит в своей подпапке с фиксированными +// именами input/output файлов + +toolchains { + gcc { platforms = "linux" } +} + +build "release" { + language = "c" + standard = "c11" + sources = "solution.c" + output = "solution" + profile = release +} + +// Режим 1: глобы на input и output файлы. +// Тестом становится каждая пара (tests/*.in, tests/*.ans) с совпадающим +// базовым именем. Имя теста — имя файла без расширения. +group("from-files") { + weight = 0.5 + + pattern { + input = "tests/*.in" + output = "tests/*.ans" + } +} + +// Режим 2: каждый тест — подкаталог с фиксированным layout'ом. +// Ожидается структура: +// cases/ +// 01-basic/ +// input.txt +// expected.txt +// 02-edge/ +// input.txt +// expected.txt +// Имя теста — имя подкаталога. +group("from-dirs") { + weight = 0.5 + + pattern { + dirs = "cases/*" + input = "input.txt" + output = "expected.txt" + } +} diff --git a/example/showcase/06-files.jdg b/example/showcase/06-files.jdg new file mode 100644 index 0000000..9516bbb --- /dev/null +++ b/example/showcase/06-files.jdg @@ -0,0 +1,59 @@ +// Тесты, которые общаются через файлы, а не через stdin/stdout. +// file("name") = "content" — файл кладётся в рабочую директорию теста +// перед запуском программы. +// outFile("name") = "content" — после запуска содержимое файла сравнивается +// с ожидаемым (точное совпадение с учётом +// normalize_crlf / trim_trailing_ws). + +toolchains { + gcc { platforms = "linux" } +} + +build "release" { + language = "c" + standard = "c11" + sources = "solution.c" + output = "solution" + profile = release +} + +normalize_crlf = true +trim_trailing_ws = true + +group("io") { + weight = 1.0 + + // Программа читает input.txt, пишет output.txt. + test("copy") { + args = "input.txt" "output.txt" + file("input.txt") = "hello world\n" + outFile("output.txt") = "hello world\n" + } + + // Несколько входных и выходных файлов сразу — удобно для задач + // вроде «посчитать сумму по каждой строке и записать в отдельный + // файл». + test("multi-file") { + args = "a.txt" "b.txt" "result.txt" + file("a.txt") = "1 2 3\n" + file("b.txt") = "10 20 30\n" + outFile("result.txt") = "11 22 33\n" + } + + // Вложенные пути тоже работают — создаются автоматически. + test("nested") { + args = "data/in.txt" "data/out.txt" + file("data/in.txt") = "payload\n" + outFile("data/out.txt") = "PAYLOAD\n" + } + + // Можно комбинировать с stdin/stdout и переменными окружения. + test("combined") { + stdin = "42\n" + args = "config.ini" + env("MODE") = "strict" + file("config.ini") = "threshold=10\n" + stdout = "ok\n" + outFile("log.txt") = "processed 42\n" + } +}