1+ import os
2+ import re
3+ from pathlib import Path
4+
5+ README_CANDIDATES = [
6+ Path ("README.md" ),
7+ * Path ("." ).glob ("README.*" ),
8+ ]
9+
10+
11+ def load_readme_text () -> str :
12+ for p in README_CANDIDATES :
13+ if p .exists () and p .is_file ():
14+ return p .read_text (encoding = "utf-8" )
15+ raise FileNotFoundError ()
16+
17+
18+ def test_readme_exists_and_non_empty ():
19+ text = load_readme_text ()
20+ assert isinstance (text , str )
21+ assert len (text .strip ()) > 0 , "README should not be empty"
22+
23+
24+ def test_title_and_intro_present ():
25+ text = load_readme_text ()
26+ assert re .search (r"^#\s+Commit-Check GitHub Action\s*$" , text , re .M ), "Missing H1 title"
27+ assert "A GitHub Action for checking commit message" in text , "Missing introductory sentence"
28+
29+
30+ def test_badges_section_contains_expected_badges ():
31+ text = load_readme_text ()
32+ # Key badges/links in the diff
33+ assert "actions/workflow/status/commit-check/commit-check-action/commit-check.yml" in text
34+ assert "shields.io/github/v/release/commit-check/commit-check-action" in text
35+ assert "Used%20by" in text and "network/dependents" in text
36+ assert "marketplace/actions/commit-check-action" in text
37+ assert "slsa-badge" in text or "slsa.dev/images/gh-badge" in text
38+
39+
40+ def test_table_of_contents_includes_expected_sections ():
41+ text = load_readme_text ()
42+ sections = [
43+ "Usage" ,
44+ "Optional Inputs" ,
45+ "GitHub Action Job Summary" ,
46+ "GitHub Pull Request Comments" ,
47+ "Badging Your Repository" ,
48+ "Versioning" ,
49+ ]
50+ for sec in sections :
51+ assert re .search (rf"^\*\s+\[{ re .escape (sec )} \]\(#" , text , re .M ), f"Missing ToC entry: { sec } "
52+
53+
54+ def test_usage_block_contains_required_yaml_fields ():
55+ text = load_readme_text ()
56+ # Ensure the YAML block exists
57+ assert "```yaml" in text and "```" in text , "Usage YAML code fence missing"
58+ # Critical lines in example workflow
59+ required_lines = [
60+ "name: Commit Check" ,
61+ "on:" ,
62+ "push:" ,
63+ "pull_request:" ,
64+ "branches: 'main'" ,
65+ "- uses: actions/checkout@v5" ,
66+ "fetch-depth: 0" ,
67+ "- uses: commit-check/commit-check-action@v1" ,
68+ "GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}" ,
69+ "with:" ,
70+ "message: true" ,
71+ "branch: true" ,
72+ "author-name: true" ,
73+ "author-email: true" ,
74+ "commit-signoff: true" ,
75+ "merge-base: false" ,
76+ "imperative: false" ,
77+ "job-summary: true" ,
78+ "pr-comments: ${{ github.event_name == 'pull_request' }}" ,
79+ ]
80+ for line in required_lines :
81+ assert line in text , f"Missing line in usage YAML: { line } "
82+
83+
84+ def test_used_by_gallery_contains_key_orgs ():
85+ text = load_readme_text ()
86+ # The gallery is HTML-based; check representative orgs to avoid brittleness
87+ for org in ["Apache" , "Texas Instruments" , "Mila" ]:
88+ assert org in text , f"Expected org '{ org } ' not found in Used By section"
89+ # Ensure the "many more" dependents link exists
90+ assert "network/dependents" in text , "Missing 'many more' dependents link"
91+
92+
93+ def test_optional_inputs_section_and_defaults ():
94+ text = load_readme_text ()
95+ # Sub-headings for inputs
96+ inputs = [
97+ "message" , "branch" , "author-name" , "author-email" ,
98+ "commit-signoff" , "merge-base" , "imperative" ,
99+ "dry-run" , "job-summary" , "pr-comments" ,
100+ ]
101+ for name in inputs :
102+ assert re .search (rf"^###\s+`{ re .escape (name )} `\s*$" , text , re .M ), f"Missing input heading for `{ name } `"
103+
104+ # Representative default assertions (avoid overfitting to formatting)
105+ defaults = {
106+ "message" : "Default: `true`" ,
107+ "branch" : "Default: `true`" ,
108+ "author-name" : "Default: `true`" ,
109+ "author-email" : "Default: `true`" ,
110+ "commit-signoff" : "Default: `true`" ,
111+ "merge-base" : "Default: `false`" ,
112+ "imperative" : "Default: `false`" ,
113+ "dry-run" : "Default: `false`" ,
114+ "job-summary" : "Default: `true`" ,
115+ "pr-comments" : "Default: `false`" ,
116+ }
117+ for key , default_line in defaults .items ():
118+ assert default_line in text , f"Missing default line for `{ key } `"
119+
120+
121+ def test_merge_base_and_pr_comments_important_notes_present ():
122+ text = load_readme_text ()
123+ # merge-base important note about fetch-depth: 0
124+ assert "merge-base" in text and "experimental" in text
125+ assert "fetch-depth: 0" in text , "merge-base note should mention fetch-depth: 0"
126+ # pr-comments important note and forked repos limitation with issue #77
127+ assert "pr-comments" in text and "experimental" in text
128+ assert "#77" in text , "pr-comments note should reference issue #77"
129+
130+
131+ def test_job_summary_and_pr_comment_screenshots_present ():
132+ text = load_readme_text ()
133+ # Two sections each with an image
134+ assert "Success job summary" in text and "Failure job summary" in text
135+ assert "screenshot/success-job-summary.png" in text
136+ assert "screenshot/failure-job-summary.png" in text
137+ assert "Success pull request comment" in text and "Failure pull request comment" in text
138+ assert "screenshot/success-pr-comments.png" in text
139+ assert "screenshot/failure-pr-comments.png" in text
140+
141+
142+ def test_badging_section_contains_markdown_and_rst_examples ():
143+ text = load_readme_text ()
144+ # Heading and primary badge
145+ assert "## Badging Your Repository" in text
146+ assert "badge.svg" in text
147+ # Markdown example fenced block
148+ md_block = re .search (r"(?s)Markdown\s+```[\s\S]*?```" , text )
149+ assert md_block , "Missing Markdown badging example fenced block"
150+ assert "actions/workflows/commit-check.yml/badge.svg" in md_block .group (0 )
151+ # reStructuredText example fenced block
152+ rst_block = re .search (r"(?s)reStructuredText\s+```[\s\S]*?```" , text )
153+ assert rst_block , "Missing reStructuredText badging example fenced block"
154+ assert ".. image:: https://github.com/commit-check/commit-check-action/actions/workflows/commit-check.yml/badge.svg" in rst_block .group (0 )
155+
156+
157+ def test_versioning_and_feedback_sections_present ():
158+ text = load_readme_text ()
159+ assert "Versioning follows [Semantic Versioning]" in text
160+ assert re .search (r"\[issues\]\(https://github\.com/commit-check/commit-check/issues\)" , text ), "Missing issues link"
161+
162+
163+ def test_top_badges_appear_near_top_of_file ():
164+ text = load_readme_text ()
165+ # Check first ~20 lines contain multiple badge URLs
166+ top = "\n " .join (text .splitlines ()[:25 ])
167+ urls = [
168+ "img.shields.io/github/actions/workflow/status/commit-check/commit-check-action/commit-check.yml" ,
169+ "img.shields.io/github/v/release/commit-check/commit-check-action" ,
170+ "img.shields.io/static/v1?label=Used%20by" ,
171+ "github.com/marketplace/actions/commit-check-action" ,
172+ ]
173+ missing = [u for u in urls if u not in top ]
174+ assert not missing , f"Expected top badges missing: { missing } "
175+
176+
177+ # The tests above intentionally avoid asserting volatile values (like exact counts)
178+ # while thoroughly validating structure and key content introduced/changed in the diff.
0 commit comments