@@ -218,3 +218,179 @@ func TestShimMapCacheOnlyLoadsOnce(t *testing.T) {
218218 t .Errorf ("Cache should not have reloaded - 'new' entry should not exist" )
219219 }
220220}
221+
222+ func TestMergeShimMap_CreatesWhenNoExistingCache (t * testing.T ) {
223+ tempDir := t .TempDir ()
224+
225+ originalRoot := os .Getenv ("DTVEM_ROOT" )
226+ _ = os .Setenv ("DTVEM_ROOT" , tempDir )
227+ defer func () { _ = os .Setenv ("DTVEM_ROOT" , originalRoot ) }()
228+
229+ config .ResetPathsCache ()
230+ defer config .ResetPathsCache ()
231+
232+ ResetShimMapCache ()
233+ defer ResetShimMapCache ()
234+
235+ // No cache directory pre-existing — MergeShimMap must create it from scratch.
236+ entries := ShimMap {
237+ "node" : "node" ,
238+ "npm" : "node" ,
239+ "npx" : "node" ,
240+ }
241+
242+ if err := MergeShimMap (entries ); err != nil {
243+ t .Fatalf ("MergeShimMap returned error on fresh install: %v" , err )
244+ }
245+
246+ loaded , err := LoadShimMap ()
247+ if err != nil {
248+ t .Fatalf ("LoadShimMap after MergeShimMap failed: %v" , err )
249+ }
250+
251+ if len (loaded ) != len (entries ) {
252+ t .Errorf ("expected %d entries, got %d (%v)" , len (entries ), len (loaded ), loaded )
253+ }
254+ for shim , runtime := range entries {
255+ if got := loaded [shim ]; got != runtime {
256+ t .Errorf ("entry %q: expected runtime %q, got %q" , shim , runtime , got )
257+ }
258+ }
259+ }
260+
261+ func TestMergeShimMap_MergesIntoExistingCache (t * testing.T ) {
262+ tempDir := t .TempDir ()
263+
264+ originalRoot := os .Getenv ("DTVEM_ROOT" )
265+ _ = os .Setenv ("DTVEM_ROOT" , tempDir )
266+ defer func () { _ = os .Setenv ("DTVEM_ROOT" , originalRoot ) }()
267+
268+ config .ResetPathsCache ()
269+ defer config .ResetPathsCache ()
270+
271+ ResetShimMapCache ()
272+ defer ResetShimMapCache ()
273+
274+ cacheDir := filepath .Join (tempDir , "cache" )
275+ if err := os .MkdirAll (cacheDir , 0755 ); err != nil {
276+ t .Fatalf ("Failed to create cache directory: %v" , err )
277+ }
278+
279+ // Seed an existing cache (simulates a prior install).
280+ initial := ShimMap {
281+ "python" : "python" ,
282+ "pip" : "python" ,
283+ }
284+ if err := SaveShimMap (initial ); err != nil {
285+ t .Fatalf ("seed SaveShimMap failed: %v" , err )
286+ }
287+
288+ // Merge in a disjoint set of entries (simulates installing a second runtime).
289+ added := ShimMap {
290+ "node" : "node" ,
291+ "npm" : "node" ,
292+ }
293+ if err := MergeShimMap (added ); err != nil {
294+ t .Fatalf ("MergeShimMap failed: %v" , err )
295+ }
296+
297+ loaded , err := LoadShimMap ()
298+ if err != nil {
299+ t .Fatalf ("LoadShimMap failed: %v" , err )
300+ }
301+
302+ // All four entries should now be present.
303+ wantAll := ShimMap {
304+ "python" : "python" ,
305+ "pip" : "python" ,
306+ "node" : "node" ,
307+ "npm" : "node" ,
308+ }
309+ for shim , runtime := range wantAll {
310+ if got := loaded [shim ]; got != runtime {
311+ t .Errorf ("entry %q: expected runtime %q, got %q" , shim , runtime , got )
312+ }
313+ }
314+ }
315+
316+ func TestMergeShimMap_OverwritesExistingKeys (t * testing.T ) {
317+ tempDir := t .TempDir ()
318+
319+ originalRoot := os .Getenv ("DTVEM_ROOT" )
320+ _ = os .Setenv ("DTVEM_ROOT" , tempDir )
321+ defer func () { _ = os .Setenv ("DTVEM_ROOT" , originalRoot ) }()
322+
323+ config .ResetPathsCache ()
324+ defer config .ResetPathsCache ()
325+
326+ ResetShimMapCache ()
327+ defer ResetShimMapCache ()
328+
329+ cacheDir := filepath .Join (tempDir , "cache" )
330+ if err := os .MkdirAll (cacheDir , 0755 ); err != nil {
331+ t .Fatalf ("Failed to create cache directory: %v" , err )
332+ }
333+
334+ // Seed with a stale mapping (e.g., a shim that was previously attributed
335+ // to the wrong runtime by some prior state).
336+ stale := ShimMap {"corepack" : "wrong" }
337+ if err := SaveShimMap (stale ); err != nil {
338+ t .Fatalf ("seed SaveShimMap failed: %v" , err )
339+ }
340+
341+ // Merge should overwrite with the correct runtime.
342+ if err := MergeShimMap (ShimMap {"corepack" : "node" }); err != nil {
343+ t .Fatalf ("MergeShimMap failed: %v" , err )
344+ }
345+
346+ loaded , err := LoadShimMap ()
347+ if err != nil {
348+ t .Fatalf ("LoadShimMap failed: %v" , err )
349+ }
350+
351+ if got := loaded ["corepack" ]; got != "node" {
352+ t .Errorf ("expected corepack remapped to node, got %q" , got )
353+ }
354+ }
355+
356+ func TestMergeShimMap_ResetsInMemoryCache (t * testing.T ) {
357+ tempDir := t .TempDir ()
358+
359+ originalRoot := os .Getenv ("DTVEM_ROOT" )
360+ _ = os .Setenv ("DTVEM_ROOT" , tempDir )
361+ defer func () { _ = os .Setenv ("DTVEM_ROOT" , originalRoot ) }()
362+
363+ config .ResetPathsCache ()
364+ defer config .ResetPathsCache ()
365+
366+ ResetShimMapCache ()
367+ defer ResetShimMapCache ()
368+
369+ cacheDir := filepath .Join (tempDir , "cache" )
370+ if err := os .MkdirAll (cacheDir , 0755 ); err != nil {
371+ t .Fatalf ("Failed to create cache directory: %v" , err )
372+ }
373+
374+ // Prime the in-memory cache with an initial map.
375+ if err := SaveShimMap (ShimMap {"node" : "node" }); err != nil {
376+ t .Fatalf ("SaveShimMap failed: %v" , err )
377+ }
378+ if _ , err := LoadShimMap (); err != nil {
379+ t .Fatalf ("initial LoadShimMap failed: %v" , err )
380+ }
381+
382+ // Without ResetShimMapCache, the next Load would return the cached copy.
383+ // MergeShimMap is supposed to reset it so callers see merged state.
384+ if err := MergeShimMap (ShimMap {"npm" : "node" }); err != nil {
385+ t .Fatalf ("MergeShimMap failed: %v" , err )
386+ }
387+
388+ loaded , err := LoadShimMap ()
389+ if err != nil {
390+ t .Fatalf ("post-merge LoadShimMap failed: %v" , err )
391+ }
392+
393+ if _ , ok := loaded ["npm" ]; ! ok {
394+ t .Error ("expected in-memory cache to be reset so the merged 'npm' entry is visible" )
395+ }
396+ }
0 commit comments