8OI-528 regression coverage — :func:`oct.diag.oct_diag.set_level` and the
9paired :func:`restore_config` helper must provide safe in-place edits of
10``debug_config.json``. A bad level write can brick diagnostics, so the
11operation is backed by a ``<path>.bk`` sidecar and a ``--dry-run`` flag
12that short-circuits both writes.
16- ``--dry-run`` never writes to the config or creates ``.bk``.
17- A real write creates ``<path>.bk`` containing the original text.
18- :func:`restore_config` round-trips the backup back onto the config.
19- Calling :func:`restore_config` with no backup raises cleanly.
20- Re-running ``set_level`` overwrites ``.bk`` with the pre-edit text.
27 L3 — assertion details
32- All config writes and backups use ``tmp_path``; no real
33 ``debug_config.json`` is modified.
36from __future__
import annotations
39from pathlib
import Path
42from click.testing
import CliRunner
49 "_schema_version":
"2.0",
51 "GENERAL": {
"level": 1,
"color":
"default"},
52 "NET": {
"level": 2,
"color":
"blue"},
54 "global_settings": {
"mode":
"dev"},
59 diag = root /
"oc_diagnostics"
63 (root /
"docs").mkdir()
64 (root /
"tests").mkdir()
65 cfg = diag /
"debug_config.json"
66 cfg.write_text(json.dumps(data, indent=2) +
"\n", encoding=
"utf-8")
72 original_text = cfg.read_text(encoding=
"utf-8")
74 result = set_level(tmp_path,
"GENERAL", 4, dry_run=
True)
76 assert cfg.read_text(encoding=
"utf-8") == original_text
77 assert not cfg.with_suffix(
".json.bk").exists()
78 assert result[
"DEBUG_LEVELS"][
"GENERAL"][
"level"] == 4
83 original_text = cfg.read_text(encoding=
"utf-8")
85 set_level(tmp_path,
"GENERAL", 3)
87 bk = cfg.with_suffix(
".json.bk")
89 assert bk.read_text(encoding=
"utf-8") == original_text
90 reloaded = json.loads(cfg.read_text(encoding=
"utf-8"))
91 assert reloaded[
"DEBUG_LEVELS"][
"GENERAL"][
"level"] == 3
96 original_text = cfg.read_text(encoding=
"utf-8")
97 set_level(tmp_path,
"GENERAL", 4)
98 assert json.loads(cfg.read_text(encoding=
"utf-8"))[
"DEBUG_LEVELS"][
"GENERAL"][
"level"] == 4
100 restored = restore_config(tmp_path)
102 assert restored == cfg
103 assert cfg.read_text(encoding=
"utf-8") == original_text
109 with pytest.raises(FileNotFoundError):
110 restore_config(tmp_path)
115 set_level(tmp_path,
"GENERAL", 3)
116 set_level(tmp_path,
"NET", 0)
118 bk = cfg.with_suffix(
".json.bk")
119 backup_state = json.loads(bk.read_text(encoding=
"utf-8"))
120 assert backup_state[
"DEBUG_LEVELS"][
"GENERAL"][
"level"] == 3
121 assert backup_state[
"DEBUG_LEVELS"][
"NET"][
"level"] == 2
126 original_text = cfg.read_text(encoding=
"utf-8")
127 monkeypatch.chdir(tmp_path)
130 result = runner.invoke(cli, [
"diag",
"set-level",
"GENERAL",
"4",
"--dry-run"])
132 assert result.exit_code == 0, result.output
133 assert "[DRY RUN]" in result.output
134 assert cfg.read_text(encoding=
"utf-8") == original_text
135 assert not cfg.with_suffix(
".json.bk").exists()
140 original_text = cfg.read_text(encoding=
"utf-8")
141 monkeypatch.chdir(tmp_path)
144 runner.invoke(cli, [
"diag",
"set-level",
"GENERAL",
"4"])
145 result = runner.invoke(cli, [
"diag",
"restore"])
147 assert result.exit_code == 0, result.output
148 assert cfg.read_text(encoding=
"utf-8") == original_text
test_dry_run_does_not_write_or_backup(tmp_path)
test_restore_config_without_backup_raises(tmp_path)
test_write_creates_backup_with_original_text(tmp_path)
Path _write_config(Path root, dict data)
test_cli_restore_command_round_trips(tmp_path, monkeypatch)
test_backup_is_overwritten_with_pre_edit_text_on_second_write(tmp_path)
test_cli_set_level_dry_run_does_not_touch_files(tmp_path, monkeypatch)
test_restore_config_round_trips_backup(tmp_path)