Справочник по командной строке
Все флаги обеих команд, обе таблицы кодов завершения и как читать то, что возвращается. Повествовательная версия с обоснованиями — на странице «CLI и CI».
Две команды
chrono run запускает приложение с другими датой и временем.
chrono calc вычисляет дату и говорит, чем она интересна.
У них общая грамматика шагов, поэтому сдвиг, записанный для одной команды, значит то же самое
в другой.
chrono version отвечает на третий, куда более скромный вопрос: что это за сборка,
какое из двух ядер представляет исполняемый файл и какую версию протокола он использует.
Одна строка в stdout, чтобы скрипт мог её перехватить.
chrono license отвечает на четвёртый: на каких условиях лицензии
распространяется эта сборка, отказ от гарантий и сторонние компоненты, влинкованные в неё.
Она также сообщает, где на диске лежат полный текст лицензии и уведомления о сторонних
компонентах, или признаётся, что у запущенной вами копии их рядом нет.
--components выводит каждый включённый компонент с его версией вместо краткой
сводки.
chrono presets выводит каталог сценариев так, как его читает
--preset: каждый сценарий из папки, записанный словами, которые читает
грамматика калькулятора, и каждый файл, который был бы отклонён, с причиной.
--json выводит chronomock.presets/1, а --dir
указывает другую папку.
chrono run <target> [options] chrono calc [options] chrono version # chrono 0.4.0 (x64, protocol 1) chrono license # GPL-3.0-only и что в комплекте chrono presets # каталог так, как его читает --preset chrono --help # справка по всем командам
chrono run — параметры
| Флаг | Что делает |
|---|---|
--at <moment> |
Момент начала в поясе сессии. Абсолютный
(2038-01-19T03:14:07) или относительный с ведущим знаком
(+1d, -2h). Единицы: s m h d w mo q y —
m — минуты, а mo — месяцы. Без этого флага часы
сессии стартуют с настоящего текущего времени, так что один --mode xN просто
запускает цель быстрее. |
--zone +HH:MM |
Пояс сессии: пояс, в котором записан момент и который сообщают вызовы местного времени в цели. Фиксированное смещение, без перехода на летнее время. Без флага — собственный пояс хоста. |
--mode flow|frozen|xN |
flow идёт с настоящей скоростью, frozen удерживает часы на
месте, xN запускает их в N раз быстрее (x60 превращает час в
минуту, x1440 — сутки). |
--scale-duration |
Ускорить также ось прошедшего времени: счётчики тиков, время прерываний, задержки сна и таймеры. Ожидания объектов считаются и сохраняют реальную длительность. По умолчанию выключено, потому что настенные часы и секундомер - разные вопросы. Таймер или задержка, заведённые на конкретные дату и время, следуют за часами сессии с этим флагом и без него. |
--scale-qpc |
Масштабирует и высокоточный счётчик, с которого читают прошедшее время monotonic
в Python 3.13+, Stopwatch в .NET и nanoTime в Java. По умолчанию
выключено: приложение, которое измеряет время отрисовки по этому счётчику, может выглядеть
искажённым. |
--ticks N |
Завершает сессию после N тактов, по одной настоящей секунде каждый, и сообщает результат. Без него инструмент остаётся подключённым, пока не завершатся цель и каждая запущенная ею программа, работающая на часах сессии, — лаунчер, который сразу завершается, оставляет сессию приложению, которое он запустил. |
--timeout <s> |
Сдаётся через столько секунд и завершается с кодом 6 — для конвейера, который не должен зависать. Независимо от этого флага ядро, молчащее 15 секунд, останавливается и тоже завершается с кодом 6 — в обоих случаях запуск оборван, поэтому вердикта у него нет. |
--args "..." |
Аргументы для цели одной строкой, разбираемые по тому же правилу, что и в Windows, — так
что аргумент с пробелами сохраняется. Для цели на Chromium --user-data-dir и
--remote-debugging-port отклоняются, а не переопределяются: сессии нужен
собственный изолированный профиль, а тихая работа на вашем настоящем профиле браузера —
единственное, чего допускать нельзя. |
--cwd <dir> |
Запускает цель в этом каталоге. Без флага цель наследует наш каталог, как делал каждый запуск
до появления этого флага. Пустое значение — это ошибка использования, а не «нет каталога»:
отсутствие и пустота — разные вещи, и Windows можно передать только отсутствие. Каталог,
которого не существует, останавливает сессию с target.cwd_missing до того, как
что-либо запущено, вместо того чтобы позже проявиться как цель, которая не стартует. |
--preset <id> |
Берёт момент и скорость из presets/<id>.json. Несовместим с
--at, --mode и --scale-duration, так как сценарий
тогда становится единственным источником и того и другого. |
--param id=value |
Заполняет параметр сценария. Можно повторять, требует --preset. Только в
run дата начала пробного периода по умолчанию равна дате создания самого
исполняемого файла цели, так что сценарий пробного периода отсчитывает от дня установки
приложения, и вам не нужно вводить её вручную. |
--set-after T:M |
На такте T меняет скорость на M. В полёте множитель не меньше 1 — остановка посреди сессии здесь не предусмотрена. |
--jump-after T:moment |
На такте T перебрасывает часы на этот момент, абсолютный или относительный, в поясе сессии. |
--force |
Сохраняет сессию, даже если начальный вердикт говорит, что подмена не сработала, — по умолчанию цель в этом случае останавливается, потому что сессия, которая ничего не доказала, хуже, чем отсутствие сессии. Вердикт не меняется, как и код завершения. Флаг лишь решает, продолжит ли цель работать. |
--no-embedded |
Оставляет веб-страницы внутри приложения (WebView2, Qt WebEngine) на реальных часах и не открывает порт отладки. Без флага сессия просит такой движок открыть локальный порт и переводит его страницы на часы сессии через него - пока порт открыт, любая другая программа на этом компьютере может использовать его, чтобы добраться до этих страниц. |
--elevated-embedded |
Для приложения, запущенного от имени администратора, из Chrono Mock, который тоже
запущен от имени администратора. Для такого приложения WebView2 игнорирует настройку,
через которую сессия добирается до его страниц, поэтому сессия на время своей работы
записывает одно значение в реестр машины (HKLM, названное по .exe приложения) и в
конце удаляет его. Пока приложение работает, любая другая программа на этом компьютере
может добраться до его страниц через порт, а приложение имеет права администратора. Не
вместе с --no-embedded. |
--keep-background-timers |
Запускает веб-движок - браузер приложения Chromium или Electron либо движок внутри
приложения - с отключённым замедлением таймеров в скрытых окнах, чтобы свёрнутое окно
сохраняло скорость сессии. Тогда приложение работает в полную силу и пока скрыто.
Приложение, запущенное от имени администратора через --elevated-embedded,
её не получает. |
--dry-run |
Печатает, какой была бы сессия, и ничего не запускает: определённые момент и пояс и
откуда они взялись, чем сценарий заполнил каждый параметр, аргументы после разбора и
какой из двух механизмов выберет цель. Ни один процесс не запускается и ни один файл
не пишется, включая тот, что назван в --report. Завершается с кодом 0 для
выполнимого плана и 2 для цели, которой нет, — это тот же код, что даёт настоящий
запуск в том же случае. У плана нет вердикта, и он об этом говорит — вердикт есть
только у настоящей сессии. С --json план выводится как данные, включая
session.elevated_embedded и session.elevated_embedded_value
- имя файла, по которому назвали бы значение в реестре, когда опция относится к цели
.exe, иначе null. Имя там не обещает запись: сессия записывает значение,
только когда сам Chrono Mock запущен от имени администратора. |
--report <path> |
Записывает отчёт для людей в файл. Вердикт, отличный от работает, открывает файл баннером о ненадёжных доказательствах, потому что доказательство, скрывающее собственные сомнения, хуже, чем его отсутствие. Этот баннер получает и сессия с вердиктом работает, если приложение не прочитало ни одних часов, которые подменяет сессия, или если это программа на Go, до настенных часов которой Chrono Mock не дотягивается. Файл также называет сам запуск: версию, время начала, цель, её папку и флаги. |
--report-args |
Вместе с --report записывает в этот файл и аргументы цели, дословно. По умолчанию выключено, потому что аргумент может содержать пароль - тогда файл сообщает только их количество. |
--json |
Выдаёт сессию в виде машиночитаемых записей вместо отчёта — тот же поток, который потребляет само окно. Собственный вывод консольного приложения идёт в стандартный поток ошибок, так что стандартный вывод содержит записи и ничего больше. Приложение, всё ещё работающее на момент конца сессии, продолжает писать туда, поэтому всё, что читает стандартный поток ошибок до конца, ждёт его, и запуск об этом сообщает. |
chrono run — коды завершения
Код завершения — это вердикт сессии, а не то, что вернуло приложение. Собственный код завершения приложения сообщается отдельно, в отчёте и в данных сессии, — почему так сделано, объясняет страница «CLI и CI».
| Код | Значение |
|---|---|
| 0 | работает — каждый процесс, читавший время, видел часы сессии |
| 10 | работает частично — часть каналов покрыта, часть нет |
| 11 | не работает — подмена не дошла до ключевых каналов |
| 4 | не определено — покрытие установить не удалось. Честное «не могу сказать», а не притворный успех |
| 12 | цель исчезла сразу после внедрения и ничего не оставила работать на часах сессии, что указывает на приложение с единственным экземпляром, передающее управление уже запущенной копии, или на передачу программе, в которую сессия не смогла войти, обычно другой разрядности. Цель, которая запускает приложение и завершается, — это лаунчер, и сессия продолжается для приложения |
| 1 | ошибка использования — неверный флаг, неверное выражение или сценарий, который эта команда не принимает |
| 2 | цель не удалось запустить или внедриться в неё |
| 3 | внутренняя ошибка — ядро не смогло запуститься, столкнулось с неожиданным состоянием или остановилось до закрытия сессии (каким бы ни был его собственный код завершения). У такого запуска нет вердикта |
| 5 | операция не включена в эту сборку — например, сценарий, момент которого требует календаря, а run пока не умеет его загружать. Намеренно отличается от ошибки использования: вы попросили то, чего пока нет, а не то, что неверно |
| 6 | запуск оборван — истёк --timeout или ядро перестало отвечать на 15 секунд и было остановлено. Это не вердикт: сессия прервана, поэтому она не доказывает о цели ничего ни в ту, ни в другую сторону |
| 7 | уже идёт другая сессия - одновременно только одна сессия. Достаточно повторить попытку, когда она закончится |
| 8 | сессия пришла к вердикту, но её доказательства нет в файле, указанном в --report - диск был заполнен или другая программа держала старый файл открытым, и он остаётся без изменений. Вердикт по-прежнему есть в отчёте, который выводит команда |
Как читать отчёт
Без --json сессия заканчивается обычным отчётом. Каждая строка — это либо факт,
который сессия наблюдала, либо её нет: ничто не подставляется правдоподобным значением по
умолчанию.
Chrono Mock - session report
target: .\build\test.exe
verdict: WORKS - time substitution took effect (processes: 1)
every process that read time saw the session clock
session: fake clock reached 2038-01-19T03:14:08
real elapsed 1.3s, fake elapsed 1.3s
exited: the target closed itself with code 3
covered channels (substituted, with call counts, 10 calls in all):
- pid 21240: GetSystemTimeAsFileTime (5 calls)
- pid 21240: GetLocalTime (5 calls)
observed channels (hooked but left real):
- pid 21240: NtCreateUserProcess (0 calls)
warnings:
- the target opened a network connection ...
- verdict — вердикт по всей семье процессов: родитель и все дочерние, с числом процессов. Именно это число несёт код завершения.
- exited — собственный код завершения приложения, и только если оно
закрылось само. Запуск, ограниченный
--ticks, оставляет цель работать, сессию Chromium инструмент закрывает сам, а у сессии, которая так и не началась, такого кода нет — тогда строка отсутствует, а не показывает выдуманный ноль. Код аварии приходит большим отрицательным числом, поэтому к нему добавляется и шестнадцатеричная форма. - covered — каналы, до которых дошла подмена, с количеством реальных вызовов каждого, по процессам. Счётчики никогда не суммируются между процессами: аудит одного процесса не должен заимствовать числа другого. Счётчик останавливается на 1048576 и тогда показывает не менее этого числа.
- observed — каналы, перехваченные, но намеренно оставленные настоящими, например ожидания объектов и мультимедийные таймеры. У них своя корзина, чтобы их никогда не принимали за подменённые.
- uncovered — каналы, которые запрашивало приложение и которые сессия не покрыла. Именно это превращает вердикт в частичный.
- not fully cleaned up — всё, что завершение не смогло убрать. При чистом конце, то есть в нормальном случае, строки нет.
chrono calc — параметры
Никакого естественного языка: каждый флаг — это один шаг, а порядок флагов — порядок шагов. Результат после каждого шага печатается, поэтому неверный шаг виден, а не погребён.
| Флаг | Что делает |
|---|---|
--base today|now|<moment> |
Откуда начинать, по умолчанию today. Определяется в поясе сессии. Невозможный
день вроде 2025-02-31 отклоняется, а не тихо переносится на следующий месяц. |
--base-utc <moment> |
Как --base, но начало задаётся моментом в UTC, с необязательной
Z в конце, а не показанием настенных часов в поясе сессии. |
--shift ±N<unit> |
Можно повторять. Знак обязателен. Единицы: s m h d w mo q y bd или их полные
названия. m — минуты, mo — месяцы. Месяцы,
кварталы и годы сворачиваются на календарную дату с ограничением, так что месяц после
31 января — это конец февраля, а не фиксированное число тиков. bd (рабочие
дни) требует --calendar. |
--set-time HH:MM:SS | Задаёт время суток в текущем результате. |
--snap <target> |
Перескакивает на границу периода: som eom soq eoq soy eoy (начало или конец
месяца, квартала, года). Начало — первый день в 00:00:00, конец — последний день в
23:59:59. |
--nearest nbd|pbd |
Ближайший рабочий день вперёд или назад, включая текущий, если он уже рабочий. Требует
--calendar. |
--to-zone +HH:MM |
Шаг: выражает тот же момент в другом фиксированном смещении. Момент сохраняется,
поэтому значение epoch не меняется, а меняются только гражданские поля. Не путать с
--zone. |
--zone +HH:MM |
Пояс сессии, используемый для определения today и now и для
отображения результата. Без него — пояс хоста. |
--calendar us-banking|us-federal|pl |
Загружает календарь праздников. Добавляет в метаданные рабочий день и праздник и
включает bd и --nearest. Два американских календаря
различаются тем, как они переносят праздник, выпавший на выходной, — а это ровно тот
сдвиг на один день, который тест призван найти. Каждый календарь отвечает за свой
диапазон лет: pl с 2002, us-federal с 1960 и
us-banking с 2008. Шаг в рабочих днях, который доходит до дня раньше
этого диапазона, отклоняется с кодом 1, а дата раньше диапазона показывается как не
оценённая. Если праздники календаря сверяли с законом более года назад, более поздний
день, который он оценил, получает отметку calendar_outdated, потому что
новый праздник мог не попасть в календарь. |
--preset <id> --param id=value |
Именованный момент из presets/<id>.json с заполненными параметрами.
Несовместим с флагами шагов и с --analyze, а с --calendar,
--zone и --format сочетается. |
--analyze <date> |
Читает вставленную дату обратно и говорит, что это такое. Неоднозначное 04/08
показывается в обоих прочтениях, американском и польском, а не угадывается —
эта неоднозначность настоящий источник ошибочных отчётов о багах. |
--format <mask> |
Печатает результат ещё и по вашей маске, чтобы он совпадал с форматом тестируемого
приложения: yyyy-MM-dd HH:mm:ss. Токены чувствительны к регистру в смысле .NET и
Java — M — месяц, m — минута. |
--json |
Машинный вывод (chronomock.calc/1) для любого из перечисленного, чтобы
конвейер мог вычислить дату и сразу подать её обратно в chrono run. |
# Последний рабочий день квартала, американский банковский календарь chrono calc --base today --snap eoq --nearest pbd --calendar us-banking
chrono calc — коды завершения
Отдельная, меньшая таблица: у калькулятора нет вердикта о покрытии, о котором нужно сообщать.
| Код | Значение |
|---|---|
| 0 | вычислено |
| 1 | ошибка использования — неверный флаг, невозможная дата, переполнение диапазона или файл календаря, в котором нет ни одного рабочего дня |
| 5 | шаг или единица не включены в эту сборку, либо шагу нужен календарь, который вы не передали. Намеренно отделено от ошибки использования, чтобы скрипт мог отличить «ещё нет» от «неверно» |