8FS-539 regression tests — :mod:`oct.core.option_c_dir` resolves paths
9to the canonical ``.option_c/`` project dotdir with a legacy fallback
10so in-flight migrations keep working for one release.
14- ``option_c_dir(root)`` returns ``root/.option_c``.
15- ``resolve_octrc`` prefers ``.option_c/octrc.json``, falling back to
17- ``resolve_debug_config`` prefers ``.option_c/debug_config.json``,
18 then ``oc_diagnostics/debug_config.json``, then legacy
19 ``diagnostics/debug_config.json``.
20- ``resolve_logs_dir`` prefers ``.option_c/logs``, falls back to
22- ``load_oc_status`` returns ``None`` when the file is missing and an
23 :class:`OcStatus` dataclass when present.
30 L3 — assertion details
35- All path-resolution tests use ``tmp_path`` as the project root.
38from __future__
import annotations
41from pathlib
import Path
45from oct.core.option_c_dir
import (
64 assert OPTION_C_DIRNAME ==
".option_c"
68 assert OC_STATUS_FILENAME ==
"oc_status.json"
82 (tmp_path /
".option_c").mkdir()
83 modern = tmp_path /
".option_c" /
"octrc.json"
84 modern.write_text(
"{}", encoding=
"utf-8")
85 legacy = tmp_path /
".octrc.json"
86 legacy.write_text(
"{}", encoding=
"utf-8")
88 assert resolve_octrc(tmp_path) == modern
91 legacy = tmp_path /
".octrc.json"
92 legacy.write_text(
"{}", encoding=
"utf-8")
94 assert resolve_octrc(tmp_path) == legacy
101 result = resolve_octrc(tmp_path)
102 assert result == tmp_path /
".octrc.json"
112 (tmp_path /
".option_c").mkdir()
113 modern = tmp_path /
".option_c" /
"debug_config.json"
114 modern.write_text(
"{}", encoding=
"utf-8")
115 (tmp_path /
"oc_diagnostics").mkdir()
116 (tmp_path /
"oc_diagnostics" /
"debug_config.json").write_text(
117 "{}", encoding=
"utf-8",
120 assert resolve_debug_config(tmp_path) == modern
123 (tmp_path /
"oc_diagnostics").mkdir()
124 legacy = tmp_path /
"oc_diagnostics" /
"debug_config.json"
125 legacy.write_text(
"{}", encoding=
"utf-8")
127 assert resolve_debug_config(tmp_path) == legacy
130 (tmp_path /
"diagnostics").mkdir()
131 very_legacy = tmp_path /
"diagnostics" /
"debug_config.json"
132 very_legacy.write_text(
"{}", encoding=
"utf-8")
134 assert resolve_debug_config(tmp_path) == very_legacy
144 modern = tmp_path /
".option_c" /
"logs"
145 modern.mkdir(parents=
True)
146 (tmp_path /
"logs").mkdir()
148 assert resolve_logs_dir(tmp_path) == modern
151 legacy = tmp_path /
"logs"
154 assert resolve_logs_dir(tmp_path) == legacy
161 result = resolve_logs_dir(tmp_path)
162 assert result == tmp_path /
"logs"
168 (tmp_path /
".option_c").mkdir()
169 result = resolve_logs_dir(tmp_path)
170 assert result == tmp_path /
".option_c" /
"logs"
180 assert load_oc_status(tmp_path)
is None
183 (tmp_path /
".option_c").mkdir()
184 (tmp_path /
".option_c" /
"oc_status.json").write_text(
185 "{ not json", encoding=
"utf-8",
187 assert load_oc_status(tmp_path)
is None
193 "linter": {
"enabled":
True,
"since":
"2026-04-16"},
194 "diagnostics": {
"enabled":
True,
"since":
"2026-04-16"},
195 "git": {
"enabled":
False,
"since":
None},
196 "docs": {
"enabled":
True,
"since":
"2026-04-16"},
197 "tests": {
"enabled":
True,
"since":
"2026-04-16"},
198 "scaffold": {
"enabled":
True,
"since":
"2026-04-16"},
201 oct_version_at_migration=
"0.19.0",
203 write_oc_status(tmp_path, status)
205 path = tmp_path /
".option_c" /
"oc_status.json"
206 assert path.is_file()
208 loaded = load_oc_status(tmp_path)
209 assert loaded
is not None
210 assert loaded.stage ==
"compliant"
211 assert loaded.pillars[
"git"][
"enabled"]
is False
212 assert loaded.oct_version_at_migration ==
"0.19.0"
219 oct_version_at_migration=
"0.19.0",
221 write_oc_status(tmp_path, status)
223 assert (tmp_path /
".option_c").is_dir()
224 assert (tmp_path /
".option_c" /
"oc_status.json").is_file()
231 oct_version_at_migration=
"0.19.0",
233 write_oc_status(tmp_path, status)
236 (tmp_path /
".option_c" /
"oc_status.json").read_text(
240 assert raw[
"_schema_version"] ==
"1.0"
243 with pytest.raises(ValueError):
248 oct_version_at_migration=
"0.19.0",
test_load_returns_none_when_missing(self, Path tmp_path)
test_write_creates_option_c_dir_if_missing(self, Path tmp_path)
test_write_emits_schema_version(self, Path tmp_path)
test_invalid_stage_rejected(self)
test_load_returns_none_when_invalid_json(self, Path tmp_path)
test_write_and_round_trip(self, Path tmp_path)
test_falls_back_to_oc_diagnostics(self, Path tmp_path)
test_prefers_option_c_dir(self, Path tmp_path)
test_falls_back_to_very_old_diagnostics(self, Path tmp_path)
test_falls_back_to_root_logs(self, Path tmp_path)
test_returns_legacy_on_unmigrated_project(self, Path tmp_path)
test_returns_option_c_path_when_dotdir_exists(self, Path tmp_path)
test_prefers_option_c_logs(self, Path tmp_path)
test_prefers_option_c_when_present(self, Path tmp_path)
test_returns_legacy_path_when_nothing_exists(self, Path tmp_path)
test_falls_back_to_legacy_when_modern_absent(self, Path tmp_path)
test_oc_status_filename_is_json()
test_option_c_dir_joins_root(Path tmp_path)
test_option_c_dirname_is_lowercase_dotdir()