Skip to content

Commit 576f540

Browse files
authored
test: 100% coverage for cache, client, grouper (#52)
## Summary - **cache.go**: 95.7% → 100% (ReadFile error path) - **grouper.go**: 0%/96% → 100% (added "sses" singularize test, removed dead code branch in DeriveVerb Case 2) - **client.go**: 81.6% → 98% (30+ new tests covering OAuth2 edge cases, pagination auth/connection errors, Fetch error paths, dry-run with non-JSON body, URL construction edge cases; remaining 2% is structurally unreachable defensive code) ## Test plan - [x] `make test` passes - [x] `make lint` passes - [x] Coverage verified with `go tool cover`
1 parent 1524ed8 commit 576f540

4 files changed

Lines changed: 820 additions & 4 deletions

File tree

gen/grouper.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,9 @@ func DeriveVerb(operationID, method, path, resource string) string {
8181
// Case 2: rest ENDS with resource name → strip it, keep verb + prefix
8282
// e.g., "getAllProjects" → rest=["All","Projects"], resource="project"
8383
// → strip "Projects" → prefix = ["All"] → "get-all"
84-
if singularize(restSingular[len(rest)-1]) == resourceSingular || restSingular[len(rest)-1] == resourceSingular {
84+
// len(rest)==1 is already handled by Case 1, so prefix is never empty here.
85+
if len(rest) > 1 && (singularize(restSingular[len(rest)-1]) == resourceSingular || restSingular[len(rest)-1] == resourceSingular) {
8586
prefix := restLower[:len(rest)-1]
86-
if len(prefix) == 0 {
87-
return verb
88-
}
8987
return verb + "-" + strings.Join(prefix, "-")
9088
}
9189

gen/grouper_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ func TestSingularizeEdgeCases(t *testing.T) {
136136
{"categories", "category"},
137137
{"values", "value"},
138138
{"project", "project"},
139+
// sses suffix branch: strip last 2 chars (e.g. "dresses" → "dress")
140+
{"dresses", "dress"},
139141
}
140142
for _, tt := range tests {
141143
t.Run(tt.input, func(t *testing.T) {

internal/cache/cache_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,40 @@ func TestCacheKeyBackwardCompatible(t *testing.T) {
174174
}
175175
}
176176

177+
// TestGetReadFileError verifies that Get returns (nil, false) when the cache
178+
// file exists and is fresh but cannot be read (e.g. permissions set to 000).
179+
// This exercises the os.ReadFile error path in Get (lines 50-53 of cache.go).
180+
func TestGetReadFileError(t *testing.T) {
181+
key := cache.Key("GET", "https://test.example.com/unreadable-"+t.Name())
182+
183+
// Write a valid cache entry.
184+
if err := cache.Set(key, []byte(`{"ok":true}`)); err != nil {
185+
t.Fatalf("Set failed: %v", err)
186+
}
187+
188+
// Locate the file and make it unreadable.
189+
dir := cache.Dir()
190+
path := dir + "/" + key
191+
if err := os.Chmod(path, 0o000); err != nil {
192+
t.Fatalf("Chmod failed: %v", err)
193+
}
194+
195+
// Restore permissions after the test so cleanup can delete the file.
196+
t.Cleanup(func() {
197+
_ = os.Chmod(path, 0o600)
198+
_ = os.Remove(path)
199+
})
200+
201+
// Get must report a miss because ReadFile fails.
202+
data, ok := cache.Get(key, time.Minute)
203+
if ok {
204+
t.Error("expected cache miss when file is unreadable")
205+
}
206+
if data != nil {
207+
t.Errorf("expected nil data, got %s", data)
208+
}
209+
}
210+
177211
// TestCacheKeyAuthContextIsolation verifies that cached data from one profile
178212
// is not returned for a different profile.
179213
func TestCacheKeyAuthContextIsolation(t *testing.T) {

0 commit comments

Comments
 (0)