Files
snotes/tests/test_cli.py
schmeeve 0758095046 CLI
2026-09-26 22:06:28 -07:00

132 lines
3.9 KiB
Python

from __future__ import annotations
import importlib.util
import sys
from datetime import date, datetime, timedelta
from pathlib import Path
import pytest
def _load_cli():
path = Path(__file__).parent.parent / "cli" / "snotes.py"
spec = importlib.util.spec_from_file_location("snotes_cli", path)
mod = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = mod
spec.loader.exec_module(mod)
return mod
cli = _load_cli()
# -- parse_date --------------------------------------------------------------
def test_parse_date_defaults_to_today():
assert cli.parse_date(None) == date.today()
assert cli.parse_date("today") == date.today()
def test_parse_date_relative_words():
assert cli.parse_date("yesterday") == date.today() - timedelta(days=1)
assert cli.parse_date("tomorrow") == date.today() + timedelta(days=1)
def test_parse_date_offsets():
assert cli.parse_date("+3") == date.today() + timedelta(days=3)
assert cli.parse_date("-7") == date.today() - timedelta(days=7)
assert cli.parse_date("0") == date.today()
def test_parse_date_iso():
assert cli.parse_date("2026-09-26") == date(2026, 9, 26)
def test_parse_date_invalid():
with pytest.raises(cli.CliError, match="bad date"):
cli.parse_date("next friday-ish")
# -- render_template ---------------------------------------------------------
def test_render_template_date():
body = "# Journal for %date%\n$journal\n\n- \n"
out = cli.render_template(body, date(2026, 9, 26), "schmeeve")
assert out.startswith("# Journal for 2026-09-26\n")
def test_render_template_strips_marker_lines():
body = "# T\n$journal\nmiddle\n $other \nend\n"
out = cli.render_template(body, date(2026, 1, 1), "u")
assert "$journal" not in out
assert "$other" not in out
assert "middle" in out
assert "end" in out
def test_render_template_keeps_inline_markers():
# only standalone marker lines are stripped
body = "# T\nmentions $journal inline\n"
out = cli.render_template(body, date(2026, 1, 1), "u")
assert "$journal inline" in out
def test_render_template_vars():
now = datetime(2026, 9, 26, 14, 30)
body = "%date% | %time% | %datetime% | %user%"
out = cli.render_template(body, date(2026, 1, 2), "ilya", now=now)
assert out == "2026-01-02 | 14:30 | 2026-01-02 14:30 | ilya\n"
def test_render_template_collapses_blank_edges():
body = "$journal\n\n# Title\n\n"
out = cli.render_template(body, date(2026, 1, 1), "u")
assert out == "# Title\n"
# -- extract_title -----------------------------------------------------------
def test_extract_title_heading():
assert cli.extract_title("# Hello\n\nbody") == "Hello"
def test_extract_title_first_line():
assert cli.extract_title("plain line\nmore") == "plain line"
def test_extract_title_untitled():
assert cli.extract_title(" \n\n") == "Untitled"
# -- config ------------------------------------------------------------------
def test_config_round_trip(tmp_path, monkeypatch):
path = tmp_path / "cfg" / "config.json"
monkeypatch.setattr(cli, "CONFIG_PATH", path)
cfg = cli.Config(url="http://sno.tes/", user="schmeeve", token="tok123")
cli.save_config(cfg)
loaded = cli.load_config()
assert loaded.url == "http://sno.tes" # trailing slash stripped
assert loaded.user == "schmeeve"
assert loaded.token == "tok123"
assert (path.stat().st_mode & 0o777) == 0o600
def test_load_config_missing(tmp_path, monkeypatch):
monkeypatch.setattr(cli, "CONFIG_PATH", tmp_path / "nope.json")
with pytest.raises(cli.CliError, match="no config"):
cli.load_config()
def test_load_config_bad_json(tmp_path, monkeypatch):
path = tmp_path / "config.json"
path.write_text("{not json")
monkeypatch.setattr(cli, "CONFIG_PATH", path)
with pytest.raises(cli.CliError, match="bad config"):
cli.load_config()