No shims, one marker system. The full mechanical sweep:
- 165 test files converted: every @pytest.mark.<os>_only decorator and
pytestmark assignment is now platforms("<os>"). Docstring/comment
prose mentioning the trio rewritten to the platforms() vocabulary.
- conftest: _OS_MARKS, the legacy skip loop, the double-mark reject for
the trio, and the selector-tagging shim are deleted. The single
platforms() gate does all host gating; _reject_contradictory_platform_
marks replaces the old reject (one platforms() marker per test — a
module-level pytestmark stacked on a per-test marker is the historic
skipped-everywhere-green-everywhere failure and stays a hard error).
- pyproject: only the platforms marker is registered.
- list_os_marked_tests.py: rewritten for the single vocabulary — takes
a platform name (linux/macos/windows), matches quoted platforms(...)
specs including negated and any-of forms, exits nonzero on empty
selection. Its test file rewritten to match (bare identifiers must
not match; the spec must appear inside the string literal).
- tests.yml macOS lane: marker: macos feeds the lister; the pytest
selection is -m "platforms and not integration" — the marker name is
the selector, the conftest's per-test host skips are the gate.
- test_os_marker_gating.py rewritten for the new reject (the old file
tested deleted machinery).
- AGENTS.md / CONTRIBUTING.md updated to the single vocabulary.
Verified: full-tree compile; marker unit tests (36); lister tests;
macOS-lane simulation (21 files, 180 collected / 429 deselected on a
windows host); broad xdist slices through scripts/run_tests.sh
(367 + 1674 passed, zero refactor-attributable failures — the 6 red
tests in the second slice fail identically with the changes stashed).
78 lines
3.1 KiB
Python
78 lines
3.1 KiB
Python
"""Tests for the terminal result cwd echo (feat/terminal-cwd-echo).
|
|
|
|
When a command changes the session working directory, the tool result
|
|
gains a "cwd" field so the model stops prefixing every command with
|
|
'cd X && ' (60% of production terminal calls) and stops running pwd
|
|
diagnostics after directory changes.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import tempfile
|
|
|
|
import pytest
|
|
|
|
from tools.terminal_tool import terminal_tool
|
|
|
|
|
|
@pytest.fixture
|
|
def isolated_home(tmp_path, monkeypatch):
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path / ".hermes"))
|
|
return tmp_path
|
|
|
|
|
|
class TestCwdEcho:
|
|
# `cd` with a *native* Windows path (``str(Path)`` → ``C:\\Users\\...``)
|
|
# doesn't survive the terminal's ``eval '<command>'`` wrapper on Windows —
|
|
# bash re-parses the command and eats the backslash separators, so the
|
|
# ``cd`` no-ops and the cwd never changes. Native-path handling in the
|
|
# terminal is a separate Windows workstream; the echo feature itself is
|
|
# covered by the Linux lane here.
|
|
@pytest.mark.platforms("linux")
|
|
def test_cd_reports_new_cwd(self, isolated_home, tmp_path):
|
|
target = tmp_path / "projdir"
|
|
target.mkdir()
|
|
r = json.loads(terminal_tool(f"cd {target}", task_id="t-cwd-1"))
|
|
assert r["exit_code"] == 0
|
|
assert "cwd" in r
|
|
assert os.path.realpath(r["cwd"]) == os.path.realpath(str(target))
|
|
|
|
def test_non_cd_command_has_no_cwd_field(self, isolated_home):
|
|
r = json.loads(terminal_tool("echo hello", task_id="t-cwd-2"))
|
|
assert r["exit_code"] == 0
|
|
assert "cwd" not in r
|
|
|
|
@pytest.mark.platforms("linux")
|
|
def test_cwd_persists_and_stops_reporting_when_stable(self, isolated_home, tmp_path):
|
|
target = tmp_path / "stable"
|
|
target.mkdir()
|
|
r1 = json.loads(terminal_tool(f"cd {target}", task_id="t-cwd-3"))
|
|
assert "cwd" in r1
|
|
# Next command runs IN the new cwd without changing it: no echo.
|
|
r2 = json.loads(terminal_tool("pwd", task_id="t-cwd-3"))
|
|
assert "cwd" not in r2
|
|
assert os.path.realpath(r2["output"].strip()) == os.path.realpath(str(target))
|
|
|
|
@pytest.mark.platforms("linux")
|
|
def test_cd_within_chain_reports_final_dir(self, isolated_home, tmp_path):
|
|
a = tmp_path / "a"
|
|
b = tmp_path / "b"
|
|
a.mkdir(); b.mkdir()
|
|
r = json.loads(terminal_tool(f"cd {a} && cd {b} && echo done", task_id="t-cwd-4"))
|
|
assert r["exit_code"] == 0
|
|
assert os.path.realpath(r.get("cwd", "")) == os.path.realpath(str(b))
|
|
|
|
def test_workdir_override_does_not_echo(self, isolated_home, tmp_path):
|
|
# Per-command workdir is transient by contract; it must not surface
|
|
# a cwd field (the session cwd did not change).
|
|
sub = tmp_path / "transient"
|
|
sub.mkdir()
|
|
r = json.loads(terminal_tool("echo hi", workdir=str(sub), task_id="t-cwd-5"))
|
|
assert r["exit_code"] == 0
|
|
assert "cwd" not in r
|
|
|
|
def test_failed_cd_no_echo(self, isolated_home):
|
|
r = json.loads(terminal_tool("cd /nonexistent_dir_zzz_42", task_id="t-cwd-6"))
|
|
assert r["exit_code"] != 0
|
|
assert "cwd" not in r
|