Chrono Mock
МоваУкраїнська

Довідник із командного рядка

Усі прапорці обох команд, обидві таблиці кодів завершення й те, як читати те, що повертається. Розповідна версія з обґрунтуваннями — на сторінці «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крок або одиницю не включено в цю збірку, або кроку потрібен календар, який ви не передали. Навмисно відокремлено від помилки використання, щоб скрипт міг відрізнити «ще ні» від «хибно»

Далі