fix(yaml): эмиттер должен квотить скаляры с YAML-индикаторами в начале (#3273)#3277
fix(yaml): эмиттер должен квотить скаляры с YAML-индикаторами в начале (#3273)#3277kvirund wants to merge 2 commits into
Conversation
Класс перенесён один в один в src/engine/db/koi8r_yaml_emitter.h без изменения поведения, чтобы его можно было покрыть unit-тестами без включения всего yaml_world_data_source.cpp. Preparation для фикса #3273.
#3273) Koi8rYamlEmitter::Value() пропускал `&`, `*`, `!` и `,` в списке символов, требующих квотинга в начале значения. Из-за этого имена объектов и мобов с цветовыми кодами вида `&Yкрепеньки&Wй пенёк&n` сохранялись через OLC без кавычек: nominative: &Yкрепеньки&Wй пенёк&n При следующей загрузке yaml-cpp интерпретировал `&Y`/`&W` как декларации якорей на одном узле и валил boot фатальной ошибкой `cannot assign multiple anchors to the same node`. Объект уходил в error_count, и при первом таком фейле сервер аварийно завершался (`FATAL: 1 object(s) failed to load. Aborting.`). Симптом проявлялся только на ямл-мирах, которые в какой-то момент ретёрнули через C++ OLC-сохранение: исходные ямл-миры, полученные через `tools/converter/convert_to_yaml.py`, выходили без бага, потому что ruamel.yaml автоматически квотит скаляры с лидирующими индикаторами (`preserve_quotes=True`). Поэтому наши прогоны `run_load_tests.sh` на свежесконвертированном мире проходили чисто, а на стрибоговом зеркале `/home/stribog/lib/world` boot падал. Тесты: `tests/koi8r.yaml.emitter.cpp` гоняет save -> reload через yaml-cpp для скаляров, начинающихся с `&`, `*`, `!`, `,` и для исходного кейса `&Yfoo &Wbar&n` из тикета. Без фикса три теста падают, с фиксом — все девять зелёные.
|
Прогнал После ребейза ветка идентична Поверх master ушли ещё 25 коммитов (#3278 / #3279 и др.), в т. ч. дополнительные фиксы литерал-блоков ( @kvirund — предлагаю закрыть PR как obsolete, дублирующая работа в master. Если есть что-то, чего тут было, а в master не доехало (хотел бы знать что — хедер по диффу выглядит более развитой версией твоего), скажи, перенесём отдельным коммитом. |
Диагноз
Прод-мир после OLC-сохранения не грузится с
Корень —
Koi8rYamlEmitter::Value()вsrc/engine/db/yaml_world_data_source.cppпропускал&,*,!,,в списке стартовых символов, требующих квотинга. Имена объектов с цветовыми кодами&Yкрепеньки&Wй пенёк&nложились в ямл без кавычек:При следующем boot'е yaml-cpp видит
&Yкак декларацию якоря и валится сcannot assign multiple anchors to the same node. Объект уходит вerror_count, на первом таком фейле сервер падает.Симптом не воспроизводился у нас при мердже PR'ов, потому что свежесконвертированный мир из
tools/converter/convert_to_yaml.pyчист — ruamel.yaml сам квотит лидирующие индикаторы (preserve_quotes=True). Бьёт только мир, который пересохранил OLC.Что в PR
Koi8rYamlEmitterвsrc/engine/db/koi8r_yaml_emitter.hбез изменения поведения — нужно для unit-тестирования.&,*,!,,в стартовые символы, требующие квотинга. Добавилtests/koi8r.yaml.emitter.cpp— save → reload round-trip через yaml-cpp для всех проблемных индикаторов и для конкретного кейса&Yfoo &Wbar&nиз тикета.Проверил, что без фикса три из новых тестов падают (
ColorCodesAtStartRoundTrip,SingleLeadingAmpersandRoundTripи round-trip с lead-&), с фиксом — все восемь зелёные.Closes #3273
Test plan
ninja tests/testsсобирается с-Dyaml=builtin./tests/tests --gtest_filter='Koi8rYamlEmitter.*'— 9 passed./tests/tests --gtest_filter='YamlSaveEncoding.*'— без регресса, 3 passed/home/stribog/lib/world-аналоге)Не закрыто этим PR
keywords:на exit'ах комнаты пишется напрямую черезout <<безKoi8rYamlEmitter::Value()(yaml_world_data_source.cpp:3097-3142). Если у двери ключевое слово начнётся с&, тот же баг. Маловероятно встретить, но как follow-up — пропустить и эти ветки через эмиттер.