Option C Tools
Loading...
Searching...
No Matches
test_git_commit_msg.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# tests/tests_git/test_git_commit_msg.py
4
5"""
6Purpose
7-------
8OI-503 regression tests — verify ``oct git commit-msg <file>`` exists and
9validates Conventional Commit messages correctly. Without this command, every
10``oct git hooks install`` produces a broken commit-msg hook (the hook template
11already references this entry, but the command was missing in v0.16.0).
12
13Responsibilities
14----------------
15- Valid Conventional Commit → exit 0.
16- Invalid (no type) → exit 1 + error on stderr.
17- --json on valid → exit 0 + JSON with ``"valid": true``.
18- --json on invalid → exit 1 + JSON with ``"valid": false`` and errors.
19- Scoped breaking-change (``feat!: ...``) is accepted.
20- Missing file → Click exits 2 (argument validation).
21
22Diagnostics
23-----------
24Domain: GIT-TESTS
25Levels:
26 L2 — test lifecycle
27 L3 — assertion details
28 L4 — deep tracing
29
30Contracts
31---------
32- The command must never raise; it must always exit with a numeric code.
33"""
34
35import json
36import sys
37import subprocess
38from pathlib import Path
39
40import pytest
41from click.testing import CliRunner
42
43from oct.git.oct_git import git_commit_msg_cmd
44
45
46def _run(tmp_path: Path, message: str, *extra: str):
47 msg_file = tmp_path / "COMMIT_EDITMSG"
48 msg_file.write_text(message, encoding="utf-8")
49 runner = CliRunner()
50 return runner.invoke(
51 git_commit_msg_cmd, [str(msg_file), *extra], catch_exceptions=False
52 )
53
54
56 result = _run(tmp_path, "feat(core): add widget\n")
57 assert result.exit_code == 0
58 assert "OK" in result.output
59
60
62 result = _run(tmp_path, "broken commit without a type\n")
63 assert result.exit_code == 1
64 # Error message rendered in combined output.
65 assert (
66 "Conventional Commits" in result.output
67 or "validation" in result.output.lower()
68 )
69
70
72 result = _run(tmp_path, "fix(git): redact tokens\n", "--json")
73 assert result.exit_code == 0
74 data = json.loads(result.output)
75 assert data["valid"] is True
76 assert data["errors"] == []
77
78
80 result = _run(tmp_path, "no type here\n", "--json")
81 assert result.exit_code == 1
82 data = json.loads(result.output)
83 assert data["valid"] is False
84 assert len(data["errors"]) >= 1
85
86
88 result = _run(tmp_path, "feat!: drop legacy flag\n")
89 assert result.exit_code == 0
90
91
93 # Click's type=Path(exists=True) should reject a missing file via usage error.
94 runner = CliRunner()
95 missing = tmp_path / "does_not_exist"
96 result = runner.invoke(
97 git_commit_msg_cmd, [str(missing)], catch_exceptions=False
98 )
99 assert result.exit_code != 0
100
101
102def test_subprocess_roundtrip(tmp_path: Path):
103 """Smoke test via ``python -m oct.cli git commit-msg`` as pre-commit would run it."""
104 msg_file = tmp_path / "COMMIT_EDITMSG"
105 msg_file.write_text("feat: end-to-end test\n", encoding="utf-8")
106 proc = subprocess.run(
107 [sys.executable, "-m", "oct.cli", "git", "commit-msg", str(msg_file)],
108 capture_output=True,
109 text=True,
110 )
111 assert proc.returncode == 0, proc.stderr
test_invalid_commit_no_type_exits_1(Path tmp_path)
test_invalid_with_json_emits_valid_false(Path tmp_path)
test_valid_with_json_emits_valid_true(Path tmp_path)
test_valid_conventional_commit_exits_0(Path tmp_path)
_run(Path tmp_path, str message, *str extra)
test_breaking_change_marker_accepted(Path tmp_path)