"""Tests for the standard JSON envelope utility (muse.core.envelope).""" from __future__ import annotations import time from typing import get_type_hints import pytest from muse.core.envelope import EnvelopeJson from muse.core.timing import start_timer class TestMakeEnvelope: """make_envelope() must return all six standard fields.""" def _call(self, **kwargs: str) -> "EnvelopeJson": from muse.core.envelope import make_envelope elapsed = start_timer() return make_envelope(elapsed, **kwargs) def test_has_muse_version(self) -> None: assert "muse_version" in self._call() def test_has_schema(self) -> None: assert "schema" in self._call() def test_has_exit_code(self) -> None: assert "exit_code" in self._call() def test_has_duration_ms(self) -> None: assert "duration_ms" in self._call() def test_has_timestamp(self) -> None: assert "timestamp" in self._call() def test_has_warnings(self) -> None: assert "warnings" in self._call() def test_muse_version_is_str(self) -> None: v = self._call()["muse_version"] assert isinstance(v, str) and v def test_schema_defaults_to_1(self) -> None: assert self._call()["schema"] == 1 def test_schema_custom(self) -> None: assert self._call(schema=2)["schema"] == 2 def test_exit_code_defaults_to_0(self) -> None: assert self._call()["exit_code"] == 0 def test_exit_code_custom(self) -> None: assert self._call(exit_code=1)["exit_code"] == 1 def test_duration_ms_is_float(self) -> None: assert isinstance(self._call()["duration_ms"], float) def test_duration_ms_nonnegative(self) -> None: assert self._call()["duration_ms"] >= 0.0 def test_warnings_defaults_to_empty_list(self) -> None: assert self._call()["warnings"] == [] def test_warnings_custom(self) -> None: w = self._call(warnings=["watch out"])["warnings"] assert w == ["watch out"] def test_timestamp_is_iso8601_z(self) -> None: ts = self._call()["timestamp"] assert isinstance(ts, str) assert ts.endswith("Z") assert "T" in ts def test_timestamp_is_utc(self) -> None: import datetime ts = self._call()["timestamp"] # Must parse without error datetime.datetime.fromisoformat(ts.replace("Z", "+00:00")) def test_duration_ms_increases_with_time(self) -> None: from muse.core.envelope import make_envelope elapsed = start_timer() time.sleep(0.01) ms = make_envelope(elapsed)["duration_ms"] assert ms >= 10.0 def test_no_schema_version_key(self) -> None: """The old name must not appear in the envelope.""" assert "schema_version" not in self._call()