Skip to content

Commit 6acb8d0

Browse files
kalbasitclaude
andcommitted
test: add TestFixAcronyms with comprehensive test cases
Add unit tests for FixAcronyms function covering: - Basic acronym replacements (Id, Url, Api, Sql, Json) - Words that should NOT be corrupted (Identifier, Curling, XmlParser) - Multiple acronyms in one string - Already-correct acronyms staying unchanged - Empty strings Also export FixAcronyms to make it testable from external test package. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bd74fac commit 6acb8d0

2 files changed

Lines changed: 141 additions & 10 deletions

File tree

generator/helpers.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ func extractBulkFor(comment string) string {
5353

5454
func toSingular(s string) string { return inflection.Singular(s) }
5555

56-
// fixAcronyms corrects common Go acronym casing issues using word-boundary-aware
56+
// FixAcronyms corrects common Go acronym casing issues using word-boundary-aware
5757
// regex replacements to avoid corrupting words that contain acronyms as substrings.
5858
// For example: Id -> ID, Api -> API, Sql -> SQL, Url -> URL.
59-
func fixAcronyms(content []byte) []byte {
59+
func FixAcronyms(content []byte) []byte {
6060
// Common Go acronyms that should be all caps, with their correct form.
6161
acronymReplacements := []struct {
6262
pattern string
@@ -91,13 +91,20 @@ func fixAcronyms(content []byte) []byte {
9191
continue
9292
}
9393

94-
// Match acronym when preceded by a lowercase letter and followed by
95-
// a capital letter or end of string. This prevents replacing "Id" in
96-
// "Identifier" (where it should stay as "Id") but correctly handles
97-
// "userId" -> "userID" and "myId" -> "myID".
98-
regex := regexp.MustCompile(`([a-z])(` + r.pattern + `)([A-Z]|$)`)
99-
repl := "$1" + r.replacement + "$3"
100-
result = regex.ReplaceAllString(result, repl)
94+
// Use three patterns to handle acronym in different positions:
95+
// 1. `([a-z])(Acronym)([A-Z])` - acronym in middle of camelCase, e.g., "JsonM" in "userJsonM"
96+
// 2. `([a-z])(Acronym)$` - acronym at end of identifier, e.g., "Id" in "userId"
97+
// 3. `([a-z])(Acronym)([^A-Za-z])` - acronym followed by non-letter (space, punctuation, etc.)
98+
regexMid := regexp.MustCompile(`([a-z])(` + r.pattern + `)([A-Z])`)
99+
regexEnd := regexp.MustCompile(`([a-z])(` + r.pattern + `)$`)
100+
regexNonLetter := regexp.MustCompile(`([a-z])(` + r.pattern + `)([^A-Za-z])`)
101+
102+
// For middle case: preserve the following uppercase letter via ${3}
103+
result = regexMid.ReplaceAllString(result, "${1}"+r.replacement+"${3}")
104+
// For non-letter case: preserve the following character via ${3}
105+
result = regexNonLetter.ReplaceAllString(result, "${1}"+r.replacement+"${3}")
106+
// For end case: no ${3} since there's no following letter
107+
result = regexEnd.ReplaceAllString(result, "${1}"+r.replacement)
101108
}
102109

103110
return []byte(result)
@@ -122,7 +129,7 @@ func writeFile(dir, filename string, content []byte) {
122129
}
123130

124131
// 3. Fix acronym casing (Api -> API, Id -> ID, etc.)
125-
fixed := fixAcronyms(formatted)
132+
fixed := FixAcronyms(formatted)
126133

127134
if err := os.WriteFile(filepath.Join(dir, filename), fixed, 0o644); err != nil { //nolint:gosec
128135
log.Fatal(err)

generator/helpers_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package generator_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/kalbasit/sqlc-multi-db/generator"
7+
)
8+
9+
func TestFixAcronyms(t *testing.T) {
10+
t.Parallel()
11+
12+
tests := []struct {
13+
name string
14+
input string
15+
expected string
16+
}{
17+
{
18+
name: "Simple Id to ID",
19+
input: "userId",
20+
expected: "userID",
21+
},
22+
{
23+
name: "Url to URL",
24+
input: "profileUrl",
25+
expected: "profileURL",
26+
},
27+
{
28+
name: "Api to API",
29+
input: "fetchApiData",
30+
expected: "fetchAPIData",
31+
},
32+
{
33+
name: "Sql to SQL",
34+
input: "execSqlQuery",
35+
expected: "execSQLQuery",
36+
},
37+
{
38+
name: "Json to JSON",
39+
input: "parseJsonBody",
40+
expected: "parseJSONBody",
41+
},
42+
{
43+
name: "Identifier should not be corrupted",
44+
input: "Identifier",
45+
expected: "Identifier",
46+
},
47+
{
48+
name: "Curling should not be corrupted to CURLing",
49+
input: "Curling",
50+
expected: "Curling",
51+
},
52+
{
53+
name: "XmlParser should not be corrupted",
54+
input: "XmlParser",
55+
expected: "XmlParser",
56+
},
57+
{
58+
name: "HtmlDocument should not be corrupted",
59+
input: "HtmlDocument",
60+
expected: "HtmlDocument",
61+
},
62+
{
63+
name: "Multiple acronyms in one string",
64+
input: "userId and profileUrl",
65+
expected: "userID and profileURL",
66+
},
67+
{
68+
name: "Id at end of string",
69+
input: "GetUserId",
70+
expected: "GetUserID",
71+
},
72+
{
73+
name: "Already correct ID should stay",
74+
input: "GetUserID",
75+
expected: "GetUserID",
76+
},
77+
{
78+
name: "Already correct URL should stay",
79+
input: "profileURL",
80+
expected: "profileURL",
81+
},
82+
{
83+
name: "Tcp connection",
84+
input: "openTcpConnection",
85+
expected: "openTCPConnection",
86+
},
87+
{
88+
name: "Jwt token",
89+
input: "validateJwtToken",
90+
expected: "validateJWTToken",
91+
},
92+
{
93+
name: "Ec2 instance",
94+
input: "launchEc2Instance",
95+
expected: "launchEC2Instance",
96+
},
97+
{
98+
name: "Json web token Jwt",
99+
input: "parseJsonWebToken",
100+
expected: "parseJSONWebToken",
101+
},
102+
{
103+
name: "Uuid should not change (not in our list)",
104+
input: "userUuid",
105+
expected: "userUuid",
106+
},
107+
{
108+
name: "Empty string",
109+
input: "",
110+
expected: "",
111+
},
112+
}
113+
114+
for _, tt := range tests {
115+
t.Run(tt.name, func(t *testing.T) {
116+
t.Parallel()
117+
118+
result := generator.FixAcronyms([]byte(tt.input))
119+
if string(result) != tt.expected {
120+
t.Errorf("FixAcronyms(%q) = %q, want %q", tt.input, string(result), tt.expected)
121+
}
122+
})
123+
}
124+
}

0 commit comments

Comments
 (0)