Корпус регрессий
Задайте PROPERTY_DB как каталог, и каждое фальсифицированное свойство записывает туда своё падение. При следующем запуске записанные падения проигрываются первыми (если только атрибут не фиксирует свой seed): то, что всё ещё падает, сообщается немедленно для быстрой обратной связи; то, что больше не падает — или что свойство теперь отбрасывает через Assume::that() — удаляется из корпуса. Свойство накапливает несколько прошлых падений, поэтому починка самого свежего не теряет более старые.
Падение записывается одним из двух способов:
| Запись | Когда | Replay | Сообщается как |
|---|---|---|---|
| Values | Каждый минимизированный аргумент представим как данные: null, скаляры, массивы, case'ы enum, байтовые строки | Один прогон с точным записанным входом | RegressionViolationException |
| Seed | Всё остальное — объекты, замыкания или значения in-body Gen::draw() в контрпримере | Вся случайная фаза, перезапущенная с этим seed | PropertyViolationException |
Записи values предпочтительнее: они стоят один прогон и продолжают работать при сдвиге последовательности генерации, потому что несут сам вход, а не рецепт его регенерации. Записи seed — fallback; они удаляются при изменении последовательности генерации пакета (иначе они проиграли бы другой вход под видом регрессии). Запись values также удаляется, когда сигнатура свойства больше не совпадает с записанными именами аргументов — переименованный или добавленный параметр делает сохранённый вход другим входом.
Хранилище — один небольшой JSON-файл на свойство (<sha1(id)>.json, не более 8 записей values и 2 записей seed, самые старые вытесняются первыми); добавьте каталог в .gitignore.