8Tests for branch naming enforcement and auto-profile selection
9(Phase 4E — G-E3, G-E4, G-E10).
13- Validate ``validate_branch_name`` against default and custom patterns.
14- Validate ``_resolve_auto_profile`` branch-to-profile mapping.
15- Validate ``resolve_effective_profile`` with ``"auto"`` config value.
27- All tests are pure unit tests (no git repo needed).
34 _resolve_auto_profile,
35 resolve_effective_profile,
36 generate_branch_name_from_message,
37 DEFAULT_BRANCH_PATTERNS,
48 """Tests for validate_branch_name()."""
51 valid, msg = validate_branch_name(
"main",
None)
56 valid, msg = validate_branch_name(
"feature/add-auth",
None)
60 valid, msg = validate_branch_name(
"release/v1.0",
None)
64 valid, msg = validate_branch_name(
"hotfix/fix-crash",
None)
68 valid, msg = validate_branch_name(
"my-random-branch",
None)
70 assert "does not match" in msg
73 """Custom patterns from octrc override defaults."""
78 "patterns": [
r"^custom/.+$"],
82 valid, _ = validate_branch_name(
"custom/my-branch", octrc)
85 valid2, _ = validate_branch_name(
"feature/something", octrc)
86 assert valid2
is False
89 """When branch_naming.enabled is false, everything is valid."""
92 "branch_naming": {
"enabled":
False},
95 valid, msg = validate_branch_name(
"anything-goes", octrc)
100 """None branch (detached HEAD) is always valid."""
101 valid, msg = validate_branch_name(
None,
None)
105 """Literal 'HEAD' (detached) is always valid."""
106 valid, msg = validate_branch_name(
"HEAD",
None)
110 """Empty patterns list means everything is valid."""
119 valid, msg = validate_branch_name(
"whatever", octrc)
123 valid, _ = validate_branch_name(
"develop",
None)
127 valid, _ = validate_branch_name(
"docs/update-readme",
None)
131 valid, _ = validate_branch_name(
"bugfix/null-pointer",
None)
135 valid, _ = validate_branch_name(
"chore/deps-update",
None)
145 """Tests for _resolve_auto_profile()."""
148 assert _resolve_auto_profile(
"main") ==
"strict"
151 assert _resolve_auto_profile(
"master") ==
"strict"
154 assert _resolve_auto_profile(
"feature/something") ==
"compact"
157 assert _resolve_auto_profile(
"release/v1.0") ==
"strict"
160 assert _resolve_auto_profile(
"hotfix/urgent") ==
"strict"
163 assert _resolve_auto_profile(
"docs/update") ==
"compact"
166 assert _resolve_auto_profile(
"chore/cleanup") ==
"compact"
169 assert _resolve_auto_profile(
"random-branch") == DEFAULT_PROFILE
172 assert _resolve_auto_profile(
None) == DEFAULT_PROFILE
175 assert _resolve_auto_profile(
"HEAD") == DEFAULT_PROFILE
178 assert _resolve_auto_profile(
"bugfix/fix-it") ==
"compact"
187 """Tests for resolve_effective_profile with auto mode."""
190 """Auto on main resolves to strict (protected branch takes precedence)."""
191 octrc = {
"git": {
"pre_commit_profile":
"auto",
"protected_branches": [
"main"]}}
193 result = resolve_effective_profile(
"main", octrc,
None)
194 assert result ==
"strict"
197 """Auto on feature branch resolves to compact."""
198 octrc = {
"git": {
"pre_commit_profile":
"auto"}}
199 result = resolve_effective_profile(
"feature/thing", octrc,
None)
200 assert result ==
"compact"
203 """CLI --profile overrides auto."""
204 octrc = {
"git": {
"pre_commit_profile":
"auto"}}
205 result = resolve_effective_profile(
"feature/thing", octrc,
"proto")
206 assert result ==
"proto"
209 """Auto on release branch resolves to strict."""
210 octrc = {
"git": {
"pre_commit_profile":
"auto",
"protected_branches": []}}
211 result = resolve_effective_profile(
"release/v1.0", octrc,
None)
212 assert result ==
"strict"
221 """Tests for generate_branch_name_from_message()."""
224 name = generate_branch_name_from_message(
"feat: add login page")
225 assert name
is not None
226 assert name.startswith(
"feature/")
227 assert "add-login-page" in name
230 name = generate_branch_name_from_message(
"feat(auth): add JWT tokens")
231 assert name ==
"feature/auth-add-jwt-tokens"
234 name = generate_branch_name_from_message(
"fix: null pointer in parser")
235 assert name
is not None
236 assert name.startswith(
"bugfix/")
239 name = generate_branch_name_from_message(
"sec: patch CVE-2024-1234")
240 assert name
is not None
241 assert name.startswith(
"hotfix/")
244 name = generate_branch_name_from_message(
"docs: update changelog")
245 assert name ==
"docs/update-changelog"
248 name = generate_branch_name_from_message(
"chore: cleanup deps")
249 assert name
is not None
250 assert name.startswith(
"chore/")
253 name = generate_branch_name_from_message(
"refactor: simplify parser")
254 assert name
is not None
255 assert name.startswith(
"chore/")
258 name = generate_branch_name_from_message(
"feat: add API v2 (beta)")
259 assert name
is not None
261 assert "(" not in name
262 assert " " not in name
265 long_msg =
"feat: " +
"a" * 100
266 name = generate_branch_name_from_message(long_msg)
267 assert name
is not None
269 slug = name.split(
"/", 1)[1]
270 assert len(slug) <= 50
273 assert generate_branch_name_from_message(
"not a valid commit")
is None
274 assert generate_branch_name_from_message(
"")
is None
277 """All commit types produce names that pass validate_branch_name."""
282 "style: fix formatting",
283 "refactor: simplify",
284 "perf: optimise query",
290 name = generate_branch_name_from_message(msg)
291 assert name
is not None, f
"failed for {msg!r}"
292 valid, val_msg = validate_branch_name(name,
None)
293 assert valid, f
"{name!r} from {msg!r}: {val_msg}"
None test_release_strict(self)
None test_unrecognized_default(self)
None test_docs_compact(self)
None test_none_branch_default(self)
None test_chore_compact(self)
None test_feature_compact(self)
None test_hotfix_strict(self)
None test_bugfix_compact(self)
None test_main_strict(self)
None test_master_strict(self)
None test_head_default(self)
None test_bugfix_branch_valid(self)
None test_disabled_always_valid(self)
None test_release_branch_valid(self)
None test_main_valid(self)
None test_feature_branch_valid(self)
None test_docs_branch_valid(self)
None test_custom_patterns_in_octrc(self)
None test_head_branch_valid(self)
None test_empty_patterns_all_valid(self)
None test_chore_branch_valid(self)
None test_invalid_random_name(self)
None test_none_branch_valid(self)
None test_hotfix_branch_valid(self)
None test_develop_valid(self)
None test_refactor_produces_chore_prefix(self)
None test_unparseable_returns_none(self)
None test_long_subject_truncated(self)
None test_feat_with_scope(self)
None test_generated_names_pass_validation(self)
None test_feat_produces_feature_prefix(self)
None test_fix_produces_bugfix_prefix(self)
None test_sec_produces_hotfix_prefix(self)
None test_docs_produces_docs_prefix(self)
None test_special_chars_slugified(self)
None test_chore_produces_chore_prefix(self)
None test_auto_on_main(self)
None test_cli_overrides_auto(self)
None test_auto_on_release(self)
None test_auto_on_feature(self)