@@ -13,38 +13,43 @@ import (
1313
1414func TestImportCache (t * testing.T ) {
1515 tempDir := t .TempDir ()
16-
17- // Create a new cache
1816 cache := NewImportCache (tempDir )
19-
20- // Test Set and Get
17+ const (
18+ owner = "testowner"
19+ repo = "testrepo"
20+ path = "workflows/test.md"
21+ sha = "abc123"
22+ )
2123 testContent := []byte ("# Test Workflow\n \n Test content" )
22- owner := "testowner"
23- repo := "testrepo"
24- path := "workflows/test.md"
25- sha := "abc123"
26-
27- cachedPath , err := cache .Set (owner , repo , path , sha , testContent )
28- require .NoError (t , err , "Set should succeed for valid inputs" )
29-
30- // Verify file was created
31- require .FileExists (t , cachedPath , "cache file should be created at expected path" )
32-
33- // Verify content
34- content , err := os .ReadFile (cachedPath )
35- require .NoError (t , err , "reading cached file should succeed" )
36- assert .Equal (t , string (testContent ), string (content ), "cached content should match original" )
37-
38- // Test Get
39- retrievedPath , found := cache .Get (owner , repo , path , sha )
40- assert .True (t , found , "cache entry should be found after Set" )
41- assert .Equal (t , cachedPath , retrievedPath , "retrieved path from Get should match path returned by Set" )
4224
43- // Test that a new cache instance can find the file
44- cache2 := NewImportCache (tempDir )
45- retrievedPath2 , found := cache2 .Get (owner , repo , path , sha )
46- assert .True (t , found , "cache entry should be found from new cache instance" )
47- assert .Equal (t , cachedPath , retrievedPath2 , "path from new cache instance should match original cached path" )
25+ t .Run ("Set creates file and returns path" , func (t * testing.T ) {
26+ cachedPath , err := cache .Set (owner , repo , path , sha , testContent )
27+ require .NoError (t , err , "Set should succeed for valid inputs" )
28+ require .FileExists (t , cachedPath , "cache file should be created at expected path" )
29+ })
30+
31+ t .Run ("Get returns cached path after Set" , func (t * testing.T ) {
32+ cachedPath , _ := cache .Set (owner , repo , path , sha , testContent )
33+ retrievedPath , found := cache .Get (owner , repo , path , sha )
34+ assert .True (t , found , "cache entry should be found after Set" )
35+ assert .Equal (t , cachedPath , retrievedPath , "retrieved path should match path returned by Set" )
36+ })
37+
38+ t .Run ("Cached file content matches original" , func (t * testing.T ) {
39+ cachedPath , err := cache .Set (owner , repo , path , sha , testContent )
40+ require .NoError (t , err , "Set should succeed" )
41+ content , err := os .ReadFile (cachedPath )
42+ require .NoError (t , err , "reading cached file should succeed" )
43+ assert .Equal (t , string (testContent ), string (content ), "cached content should match original" )
44+ })
45+
46+ t .Run ("New cache instance finds existing entry" , func (t * testing.T ) {
47+ cachedPath , _ := cache .Set (owner , repo , path , sha , testContent )
48+ cache2 := NewImportCache (tempDir )
49+ retrievedPath2 , found := cache2 .Get (owner , repo , path , sha )
50+ assert .True (t , found , "cache entry should be found from new cache instance" )
51+ assert .Equal (t , cachedPath , retrievedPath2 , "path from new instance should match original" )
52+ })
4853}
4954
5055func TestImportCacheDirectory (t * testing.T ) {
@@ -131,6 +136,26 @@ func TestSanitizePath(t *testing.T) {
131136 input : "a/./b/file.md" ,
132137 expected : "a_b_file.md" ,
133138 },
139+ {
140+ name : "empty string" ,
141+ input : "" ,
142+ expected : "." ,
143+ },
144+ {
145+ name : "trailing slash" ,
146+ input : "a/b/" ,
147+ expected : "a_b" ,
148+ },
149+ {
150+ name : "single dot component" ,
151+ input : "a/./b" ,
152+ expected : "a_b" ,
153+ },
154+ {
155+ name : "leading slash becomes root-like" ,
156+ input : "/absolute/path" ,
157+ expected : "_absolute_path" ,
158+ },
134159 }
135160
136161 for _ , tt := range tests {
@@ -204,6 +229,33 @@ func TestValidatePathComponents(t *testing.T) {
204229 shouldErr : true ,
205230 errMsg : "absolute path" ,
206231 },
232+ {
233+ name : "empty repo" ,
234+ owner : "testowner" ,
235+ repo : "" ,
236+ path : "test.md" ,
237+ sha : "abc123" ,
238+ shouldErr : true ,
239+ errMsg : "empty component" ,
240+ },
241+ {
242+ name : "empty path" ,
243+ owner : "testowner" ,
244+ repo : "testrepo" ,
245+ path : "" ,
246+ sha : "abc123" ,
247+ shouldErr : true ,
248+ errMsg : "empty component" ,
249+ },
250+ {
251+ name : "path traversal embedded in sha" ,
252+ owner : "testowner" ,
253+ repo : "testrepo" ,
254+ path : "test.md" ,
255+ sha : "abc..def" ,
256+ shouldErr : true ,
257+ errMsg : ".." ,
258+ },
207259 }
208260
209261 for _ , tt := range tests {
@@ -272,6 +324,15 @@ func TestImportCacheSet_Validation(t *testing.T) {
272324 shouldErr : true ,
273325 errMsg : "invalid path components" ,
274326 },
327+ {
328+ name : "valid inputs succeed" ,
329+ owner : "owner" ,
330+ repo : "repo" ,
331+ path : "workflows/test.md" ,
332+ sha : "abc123def456" ,
333+ content : []byte ("# valid content" ),
334+ shouldErr : false ,
335+ },
275336 }
276337
277338 cache := NewImportCache (tempDir )
@@ -287,3 +348,33 @@ func TestImportCacheSet_Validation(t *testing.T) {
287348 })
288349 }
289350}
351+
352+ func TestImportCacheSetIdempotent (t * testing.T ) {
353+ tempDir := t .TempDir ()
354+ cache := NewImportCache (tempDir )
355+
356+ firstContent := []byte ("first content" )
357+ secondContent := []byte ("second content" )
358+
359+ path1 , err := cache .Set ("owner" , "repo" , "test.md" , "sha1" , firstContent )
360+ require .NoError (t , err , "first Set should succeed" )
361+
362+ path2 , err := cache .Set ("owner" , "repo" , "test.md" , "sha1" , secondContent )
363+ require .NoError (t , err , "second Set with same key should succeed (overwrite)" )
364+ assert .Equal (t , path1 , path2 , "both Set calls should return the same cache path" )
365+
366+ content , err := os .ReadFile (path2 )
367+ require .NoError (t , err , "reading overwritten file should succeed" )
368+ assert .Equal (t , string (secondContent ), string (content ), "file should contain second (latest) content" )
369+ }
370+
371+ func TestImportCacheGetDoesNotValidateComponents (t * testing.T ) {
372+ // Document that Get does not validate components (unlike Set).
373+ // If validation is added in the future, this test should be updated.
374+ tempDir := t .TempDir ()
375+ cache := NewImportCache (tempDir )
376+
377+ // Should return not-found (not panic or error), even with suspicious inputs.
378+ _ , found := cache .Get ("../etc" , "repo" , "test.md" , "sha" )
379+ assert .False (t , found , "Get with path traversal input should return not-found, not panic" )
380+ }
0 commit comments