test: fix tests that failed on Windows and macOS (#1506, #1485, #1541)

- the module-help subprocess is read as UTF-8 under a cp1252 locale
- the yfinance cache check names the suite's directory, which may sit under the home on Windows
- POSIX file modes and shell upgrade commands are checked only off Windows
- file locking names errno.EDEADLK, which macOS also defines
This commit is contained in:
Yijia-Xiao
2026-10-27 08:01:08 +00:00
parent ec4e2c8e5a
commit d46c052278
6 changed files with 20 additions and 8 deletions
+1 -1
View File
@@ -106,7 +106,7 @@ def test_on_windows_the_lock_is_waited_for_while_another_writer_holds_it(tmp_pat
import errno
import sys
fake, calls = _fake_msvcrt([OSError(errno.EDEADLOCK, "held"), None])
fake, calls = _fake_msvcrt([OSError(errno.EDEADLK, "held"), None])
monkeypatch.setitem(sys.modules, "msvcrt", fake)
with open(tmp_path / "log.md.lock", "a+b") as handle, files._hold_windows(handle):
+5 -2
View File
@@ -6,6 +6,7 @@ check of the sign-in (signature, issuer, audience, nonce, plan scope) runs for r
import base64
import json
import os
import socket
import stat
import threading
@@ -165,7 +166,8 @@ def test_a_token_near_expiry_is_renewed_with_the_stored_refresh_token(home, open
assert url == auth.TOKEN_URL and sent["refresh_token"] == "r1" and sent["client_id"] == CLIENT
stored = json.loads(auth.AUTH_FILE.read_text())
assert stored["tokens"]["refresh_token"] == "r2" and stored["account"]["subject"] == SUBJECT
assert stat.S_IMODE(auth.AUTH_FILE.stat().st_mode) == 0o600
if os.name != "nt": # Windows keeps no POSIX mode; the profile's ACL guards it
assert stat.S_IMODE(auth.AUTH_FILE.stat().st_mode) == 0o600
@pytest.mark.unit
@@ -245,7 +247,8 @@ def test_signing_in_by_pasting_the_redirect_saves_a_private_sign_in(home, openai
stored = json.loads(auth.AUTH_FILE.read_text())
assert stored["account"] == {"client_id": CLIENT, "email": "a@example.com", "subject": SUBJECT}
assert stored["host_id"].startswith("urn:uuid:")
assert stat.S_IMODE(auth.AUTH_FILE.stat().st_mode) == 0o600
if os.name != "nt": # Windows keeps no POSIX mode; the profile's ACL guards it
assert stat.S_IMODE(auth.AUTH_FILE.stat().st_mode) == 0o600
asked = dict(urllib.parse.parse_qsl(urllib.parse.urlparse(printed[1]).query))
assert asked["client_id"] == auth.DYNAMIC_CLIENT_ID and asked["agent_name_hint"] == "TradingAgents"
assert asked["code_challenge_method"] == "S256" and asked["redirect_uri"].startswith("http://127.0.0.1:")
+4 -1
View File
@@ -83,12 +83,15 @@ class _Summary:
def test_every_command_is_registered_when_run_as_a_module():
"""README documents `python -m cli.main`, which executes the file top to
bottom, so a command defined after the __main__ block would not exist."""
import os
import re
import subprocess
import sys
# Help draws boxes in UTF-8; read it as such whatever the locale (cp1252 on Windows).
out = subprocess.run([sys.executable, "-m", "cli.main", "backtest", "--help"],
capture_output=True, text=True, timeout=120)
capture_output=True, text=True, encoding="utf-8", errors="replace",
env={**os.environ, "PYTHONIOENCODING": "utf-8"}, timeout=120)
assert out.returncode == 0, out.stderr[-400:]
# Where the terminal takes colour, help styles each option and splits
# "--start" across escape sequences, so read the text without them.
+2
View File
@@ -242,6 +242,7 @@ def _dist(direct=None, installer="pip"):
@pytest.mark.unit
@pytest.mark.skipif(os.name == "nt", reason="the upgrade commands are POSIX shell")
def test_the_upgrade_command_follows_the_install(tmp_path, monkeypatch):
clone = tmp_path / "TradingAgents"
(clone / ".git").mkdir(parents=True)
@@ -314,6 +315,7 @@ def test_remote_text_cannot_carry_c1_or_direction_controls():
@pytest.mark.unit
@pytest.mark.skipif(os.name == "nt", reason="the upgrade commands are POSIX shell")
def test_a_uv_git_install_is_upgraded_with_uv(monkeypatch):
monkeypatch.delenv("TRADINGAGENTS_IN_DOCKER", raising=False)
monkeypatch.setattr(updates.sys, "executable", "/venv/bin/python")
+6 -2
View File
@@ -34,12 +34,16 @@ def test_a_test_saves_cli_selections_to_its_own_directory(tmp_path):
@pytest.mark.unit
def test_yfinance_keeps_its_cache_out_of_the_users_home():
"""yfinance caches each symbol's time zone on disk, in the home directory by default."""
"""yfinance caches each symbol's time zone on disk, in the home directory by default.
The suite's own temporary directory may itself sit under the home (``%TEMP%``
on Windows), so the check is that the cache is the suite's, not where it is.
"""
from pathlib import Path
from yfinance.cache import _TzDBManager
assert not Path(_TzDBManager.get_location()).is_relative_to(Path.home())
assert Path(_TzDBManager.get_location()).name.startswith("tradingagents-tests-yf-")
@pytest.mark.unit
+2 -2
View File
@@ -74,12 +74,12 @@ def _hold_windows(handle, wait: bool = True) -> Iterator[bool]:
msvcrt.locking(handle.fileno(), msvcrt.LK_LOCK if wait else msvcrt.LK_NBLCK, 1)
break
except OSError as exc:
if not wait and exc.errno in (errno.EACCES, errno.EDEADLOCK):
if not wait and exc.errno in (errno.EACCES, errno.EDEADLK):
yield False # another writer holds it
return
# LK_LOCK gives up after about ten seconds of another writer's hold;
# any other failure is not a wait.
if exc.errno != errno.EDEADLOCK:
if exc.errno != errno.EDEADLK:
raise
try:
yield True