132 lines
3.9 KiB
Python
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()
|