sendmsg/TESTING.md
2026-07-15 11:41:58 -07:00

98 lines
3.7 KiB
Markdown

# Testing sendmsg
The test suite lives in `tests/test_sendmsg.py` and covers phone/group
detection, path expansion, attachment validation, Signal payload
construction, CSV parsing and dispatch (BOM handling, comma repair, blank
rows, skips, dry run, `--json` output), and CLI argument validation.
## Requirements
- Python 3.10 or newer
- `pytest` (the only test dependency — sendmsg itself is stdlib-only)
```bash
pip install pytest
# or on a system where pip refuses to touch system packages (Homebrew, Debian):
pip install pytest --break-system-packages
# or keep it isolated:
python3 -m venv .venv && source .venv/bin/activate && pip install pytest
```
## Running the tests
Run from the repository root (the tests locate the `sendmsg` script
relative to their own path, so the working directory doesn't actually
matter — but the root is the natural place):
```bash
python3 -m pytest tests/
```
Expected output looks like:
```
..................................................................... [100%]
69 passed in 0.14s
```
### Useful variations
```bash
python3 -m pytest tests/ -v # one line per test, with names
python3 -m pytest tests/ -q # terse summary only
python3 -m pytest tests/ -k csv # only tests matching "csv"
python3 -m pytest tests/ -k "bom or comma" # match multiple keywords
python3 -m pytest tests/test_sendmsg.py::TestPhoneNumbers # one test class
python3 -m pytest tests/test_sendmsg.py::TestCsv::test_quoted_commas_in_message # one test
python3 -m pytest tests/ -x # stop at the first failure
python3 -m pytest tests/ --lf # re-run only what failed last time
```
## What the tests do NOT need
- **No running signal-cli-rest-api container.** All network calls
(`signal_rest_post`, `signal_rest_get`) are replaced with fakes; the
suite asserts on the payloads sendmsg *would* send.
- **No macOS / no `imsg`.** SMS sends are stubbed the same way, so the
suite runs identically on Linux and macOS.
- **No real config.** The suite pins `SIGNAL_REST_URL` and
`SIGNAL_ACCOUNT` environment variables *before* importing the script,
so your real `~/.sendmsg.conf` and shell environment can't leak into
(or be touched by) test runs. Nothing is ever actually sent.
## How the script gets imported
`sendmsg` has no `.py` extension, so the suite loads it with
`importlib`'s `SourceFileLoader` (see the top of `tests/test_sendmsg.py`).
The loaded module is a normal Python module — tests call its functions
(`normalize_account`, `send_one_signal`, `cmd_csv` via `main()`, ...)
directly and monkeypatch its globals.
Two consequences worth knowing:
1. Module-level code (config loading) runs at import time — that's why
the env vars are pinned first.
2. If you rename or move the `sendmsg` script, update `SCRIPT_PATH` at
the top of the test file.
## Continuous integration
`.github/workflows/ci.yml` runs on every push and pull request:
a compile check (`python -m py_compile sendmsg`) followed by the full
suite on Python 3.10, 3.11, 3.12, and 3.13. A green run on your branch
means the same command that CI uses passed:
```bash
python -m py_compile sendmsg && python3 -m pytest tests/ -v
```
## Adding tests
- Pure helpers (parsing, normalization, validation) get direct
parametrized tests — see `TestPhoneNumbers` for the pattern.
- Anything that would send goes through the stubbing helpers:
`run_csv()` for CSV behavior (returns exit code, stdout, stderr, and
the captured Signal/SMS calls) and the `captured_posts` fixture for
payload-level assertions.
- When fixing a bug, add a test that fails on the old behavior first —
most tests in the suite carry a comment naming the bug they pin down.