1+ #! /usr/bin/env bash
2+ # Unit tests for generate-summary.sh.
3+ # Usage: test-generate-summary.sh <path-to-generate-summary.sh>
4+ # Exits 0 if all tests pass, 1 on first failure.
5+
6+ set -euo pipefail
7+
8+ _script_arg=" ${1:- $(dirname " $0 " )/ generate-summary.sh} "
9+ SCRIPT=" $( cd " $( dirname " $_script_arg " ) " && pwd) /$( basename " $_script_arg " ) "
10+
11+ pass=0
12+ fail=0
13+
14+ INITIAL_COMMIT_MSG=" initial"
15+ OLD_RULE_CONTENT=' <rule>old</rule>'
16+ NEW_RULE_CONTENT=' <rule>new</rule>'
17+ UPDATED_JSON=' {"updated":true}'
18+
19+ assert_output_contains () {
20+ local test_name=" $1 "
21+ local pattern=" $2 "
22+ local output_file=" $3 "
23+ if grep -q " $pattern " " $output_file " ; then
24+ echo " ✓ $test_name "
25+ pass=$(( pass + 1 ))
26+ else
27+ echo " ✗ $test_name "
28+ echo " Expected pattern: $pattern "
29+ echo " Actual output:"
30+ sed ' s/^/ /' " $output_file "
31+ fail=$(( fail + 1 ))
32+ fi
33+ return 0
34+ }
35+
36+ # ---------------------------------------------------------------------------
37+ # Helper: create an isolated git repo, commit initial files, stage changes,
38+ # write a log file, run the script, and return the output file path.
39+ # ---------------------------------------------------------------------------
40+ run_test () {
41+ local work_dir
42+ work_dir=$( mktemp -d)
43+
44+ # Each test receives the work_dir; caller populates it before calling run_script.
45+ echo " $work_dir "
46+ return 0
47+ }
48+
49+ init_git () {
50+ git init -q
51+ git config user.email " test@test.com"
52+ git config user.name " Test"
53+ return 0
54+ }
55+
56+ run_script () {
57+ local work_dir=" $1 "
58+ local gh_output=" $work_dir /gh_output"
59+ (cd " $work_dir " && GITHUB_OUTPUT=" $gh_output " bash " $SCRIPT " " 2.99.0" ) || true
60+ echo " $gh_output "
61+ return 0
62+ }
63+
64+ # ---------------------------------------------------------------------------
65+ # Test 1: flat structure (sonar-rpg style)
66+ # sonarpedia.json at the repo root — mirrors SonarSource/sonar-rpg.
67+ # ---------------------------------------------------------------------------
68+ echo " --- Test 1: flat structure (sonar-rpg style) ---"
69+ WORK_DIR=$( run_test)
70+ cd " $WORK_DIR "
71+ init_git
72+ mkdir -p rules
73+ echo ' {}' > sonarpedia.json
74+ echo " $OLD_RULE_CONTENT " > rules/S1000.html
75+ echo ' {}' > rules/S1000.json
76+ git add . && git commit -q -m " $INITIAL_COMMIT_MSG "
77+
78+ echo " $NEW_RULE_CONTENT " > rules/S1000.html
79+ echo " $UPDATED_JSON " > rules/S1001.json
80+ git add .
81+
82+ printf ' === PATH:. ===\nRunning rule-api update\nFound 3 rule(s) to update\n' > rule-api-logs.txt
83+
84+ OUTPUT=$( run_script " $WORK_DIR " )
85+ assert_output_contains " flat: row shows 3 to update and 2 updated" \
86+ ' ./sonarpedia.json.*3.*2' " $OUTPUT "
87+ rm -rf " $WORK_DIR "
88+
89+ # ---------------------------------------------------------------------------
90+ # Test 2: 2-level structure (sonar-security frontend/<lang> style)
91+ # ---------------------------------------------------------------------------
92+ echo " --- Test 2: 2-level structure (sonar-security frontend/java style) ---"
93+ WORK_DIR=$( run_test)
94+ cd " $WORK_DIR "
95+ init_git
96+ mkdir -p frontend/java/rules frontend/python/rules
97+ echo ' {}' > frontend/java/sonarpedia.json
98+ echo ' {}' > frontend/python/sonarpedia.json
99+ echo " $OLD_RULE_CONTENT " > frontend/java/rules/S1000.html
100+ echo ' {}' > frontend/java/rules/S1000.json
101+ echo " $OLD_RULE_CONTENT " > frontend/python/rules/S2000.html
102+ git add . && git commit -q -m " $INITIAL_COMMIT_MSG "
103+
104+ # Update java rules only; python unchanged.
105+ echo " $NEW_RULE_CONTENT " > frontend/java/rules/S1000.html
106+ echo " $UPDATED_JSON " > frontend/java/rules/S1001.json
107+ git add .
108+
109+ printf ' === PATH:frontend/java ===\nRunning rule-api update\nFound 5 rule(s) to update\n=== PATH:frontend/python ===\nRunning rule-api update\nFound 2 rule(s) to update\n' > rule-api-logs.txt
110+
111+ OUTPUT=$( run_script " $WORK_DIR " )
112+ assert_output_contains " 2-level: java row shows 5 to update and 2 updated" \
113+ ' frontend/java/sonarpedia.json.*5.*2' " $OUTPUT "
114+ assert_output_contains " 2-level: python row shows 2 to update and 0 updated" \
115+ ' frontend/python/sonarpedia.json.*2.*0' " $OUTPUT "
116+ rm -rf " $WORK_DIR "
117+
118+ # ---------------------------------------------------------------------------
119+ # Test 3: deep 3-level structure (sonar-security dotnet style)
120+ # frontend/dotnet/<plugin>/sonarpedia.json — the path the old bug truncated.
121+ # ---------------------------------------------------------------------------
122+ echo " --- Test 3: deep 3-level structure (sonar-security dotnet style) ---"
123+ WORK_DIR=$( run_test)
124+ cd " $WORK_DIR "
125+ init_git
126+ mkdir -p frontend/dotnet/sonar-security-csharp-frontend-plugin/rules
127+ mkdir -p frontend/dotnet/sonar-security-vbnet-frontend-plugin/rules
128+ echo ' {}' > frontend/dotnet/sonar-security-csharp-frontend-plugin/sonarpedia.json
129+ echo ' {}' > frontend/dotnet/sonar-security-vbnet-frontend-plugin/sonarpedia.json
130+ echo " $OLD_RULE_CONTENT " > frontend/dotnet/sonar-security-csharp-frontend-plugin/rules/S3649.html
131+ echo ' {}' > frontend/dotnet/sonar-security-csharp-frontend-plugin/rules/S3649.json
132+ echo " $OLD_RULE_CONTENT " > frontend/dotnet/sonar-security-vbnet-frontend-plugin/rules/S3649.html
133+ git add . && git commit -q -m " $INITIAL_COMMIT_MSG "
134+
135+ echo " $NEW_RULE_CONTENT " > frontend/dotnet/sonar-security-csharp-frontend-plugin/rules/S3649.html
136+ echo " $UPDATED_JSON " > frontend/dotnet/sonar-security-csharp-frontend-plugin/rules/S3650.json
137+ git add .
138+
139+ printf ' === PATH:frontend/dotnet/sonar-security-csharp-frontend-plugin ===\nRunning rule-api update\nFound 4 rule(s) to update\n=== PATH:frontend/dotnet/sonar-security-vbnet-frontend-plugin ===\nRunning rule-api update\nFound 4 rule(s) to update\n' > rule-api-logs.txt
140+
141+ OUTPUT=$( run_script " $WORK_DIR " )
142+ assert_output_contains " 3-level: csharp row shows 4 to update and 2 updated" \
143+ ' sonar-security-csharp-frontend-plugin/sonarpedia.json.*4.*2' " $OUTPUT "
144+ assert_output_contains " 3-level: vbnet row shows 4 to update and 0 updated" \
145+ ' sonar-security-vbnet-frontend-plugin/sonarpedia.json.*4.*0' " $OUTPUT "
146+ rm -rf " $WORK_DIR "
147+
148+ # ---------------------------------------------------------------------------
149+ # Test 5: deduplication — both .html and .json changed for same rule = 1 rule
150+ # ---------------------------------------------------------------------------
151+ echo " --- Test 5: deduplication (.html + .json same rule counts as 1) ---"
152+ WORK_DIR=$( run_test)
153+ cd " $WORK_DIR "
154+ init_git
155+ mkdir -p rules
156+ echo ' {}' > sonarpedia.json
157+ echo " $OLD_RULE_CONTENT " > rules/S1896.html
158+ echo ' {}' > rules/S1896.json
159+ git add . && git commit -q -m " $INITIAL_COMMIT_MSG "
160+
161+ echo " $NEW_RULE_CONTENT " > rules/S1896.html
162+ echo " $UPDATED_JSON " > rules/S1896.json
163+ git add .
164+
165+ printf ' === PATH:. ===\nRunning rule-api update\nFound 2 rule(s) to update\n' > rule-api-logs.txt
166+
167+ OUTPUT=$( run_script " $WORK_DIR " )
168+ assert_output_contains " dedup: S1896.html+S1896.json counts as 1 rule updated" \
169+ ' ./sonarpedia.json.*2.*1' " $OUTPUT "
170+ rm -rf " $WORK_DIR "
171+
172+ # ---------------------------------------------------------------------------
173+ # Test 4: no rules to update — fallback summary string
174+ # ---------------------------------------------------------------------------
175+ echo " --- Test 4: no rules to update (fallback summary) ---"
176+ WORK_DIR=$( run_test)
177+ cd " $WORK_DIR "
178+ init_git
179+ echo ' {}' > sonarpedia.json
180+ git add . && git commit -q -m " $INITIAL_COMMIT_MSG "
181+
182+ printf ' === PATH:. ===\nRunning rule-api update\nFound 0 rule(s) to update\n' > rule-api-logs.txt
183+
184+ OUTPUT=$( run_script " $WORK_DIR " )
185+ assert_output_contains " zero rules: fallback summary written" \
186+ ' summary=Update rule metadata' " $OUTPUT "
187+ rm -rf " $WORK_DIR "
188+
189+ # ---------------------------------------------------------------------------
190+ # Results
191+ # ---------------------------------------------------------------------------
192+ echo " "
193+ echo " Results: $pass passed, $fail failed"
194+ [[ " $fail " -eq 0 ]]
0 commit comments