@@ -3,6 +3,7 @@ package testutil
33import (
44 "encoding/json"
55 "fmt"
6+ "maps"
67 "os"
78 "os/exec"
89 "path/filepath"
@@ -12,6 +13,7 @@ import (
1213 "testing"
1314
1415 "github.com/arm/topo/internal/template"
16+ "github.com/stretchr/testify/assert"
1517 "github.com/stretchr/testify/require"
1618)
1719
@@ -110,10 +112,10 @@ func AssertFileContents(t *testing.T, wantContents string, path string) {
110112
111113func AssertJsonGoldenFile (t * testing.T , got string , goldenPath string ) {
112114 t .Helper ()
113- AssertJsonGoldenFileWithOverrides (t , got , goldenPath , map [ string ] any {} )
115+ AssertJsonGoldenFileWithOverrides (t , got , goldenPath , nil )
114116}
115117
116- func AssertJsonGoldenFileWithOverrides (t * testing.T , got string , goldenPath string , overrides map [ string ] any ) {
118+ func AssertJsonGoldenFileWithOverrides (t * testing.T , got string , goldenPath string , overrides any ) {
117119 t .Helper ()
118120
119121 if os .Getenv ("UPDATE_GOLDEN" ) == "1" {
@@ -122,37 +124,75 @@ func AssertJsonGoldenFileWithOverrides(t *testing.T, got string, goldenPath stri
122124 t .Skipf ("Updated golden file: %s" , goldenPath )
123125 }
124126
125- gotObj := make (map [string ]any )
126- err := json .Unmarshal ([]byte (got ), & gotObj )
127+ wantBytes , err := os .ReadFile (goldenPath )
127128 require .NoError (t , err )
128129
129- wantBytes , err := os .ReadFile (goldenPath )
130+ var wantValue any
131+ err = json .Unmarshal (wantBytes , & wantValue )
130132 require .NoError (t , err )
131133
132- wantObj := make (map [string ]any )
133- err = json .Unmarshal (wantBytes , & wantObj )
134+ if hasJSONOverrides (overrides ) {
135+ wantValue = MergeJSONValues (wantValue , overrides )
136+ }
137+
138+ wantWithOverrides , err := json .Marshal (wantValue )
134139 require .NoError (t , err )
135140
136- deepMergeMaps (wantObj , overrides )
141+ assert .JSONEq (t , string (wantWithOverrides ), got , "output did not match golden file %s" , goldenPath )
142+ }
137143
138- require .Equal (t , wantObj , gotObj , "output did not match golden file %s" , goldenPath )
144+ func hasJSONOverrides (value any ) bool {
145+ switch typedValue := value .(type ) {
146+ case nil :
147+ return false
148+ case map [string ]any :
149+ return len (typedValue ) > 0
150+ case []any :
151+ return len (typedValue ) > 0
152+ default :
153+ return true
154+ }
139155}
140156
141- func deepMergeMaps (base , override map [string ]any ) {
157+ func MergeJSONValues (base , override any ) any {
158+ baseObj , baseIsObj := base .(map [string ]any )
159+ overrideObj , overrideIsObj := override .(map [string ]any )
160+ if baseIsObj && overrideIsObj {
161+ return mergeJSONMaps (baseObj , overrideObj )
162+ }
163+
164+ baseArray , baseIsArray := base .([]any )
165+ overrideArray , overrideIsArray := override .([]any )
166+ if baseIsArray && overrideIsArray {
167+ return mergeJSONArrays (baseArray , overrideArray )
168+ }
169+
170+ return override
171+ }
172+
173+ func mergeJSONMaps (base , override map [string ]any ) map [string ]any {
174+ merged := maps .Clone (base )
142175 for key , overrideValue := range override {
143- baseValue , ok := base [key ]
176+ baseValue , ok := merged [key ]
144177 if ! ok {
145- base [key ] = overrideValue
178+ merged [key ] = overrideValue
146179 continue
147180 }
148181
149- baseObj , baseIsObj := baseValue .(map [string ]any )
150- overrideObj , overrideIsObj := overrideValue .(map [string ]any )
151- if baseIsObj && overrideIsObj {
152- deepMergeMaps (baseObj , overrideObj )
182+ merged [key ] = MergeJSONValues (baseValue , overrideValue )
183+ }
184+ return merged
185+ }
186+
187+ func mergeJSONArrays (base , override []any ) []any {
188+ merged := slices .Clone (base )
189+ for index , overrideValue := range override {
190+ if index >= len (merged ) {
191+ merged = append (merged , overrideValue )
153192 continue
154193 }
155194
156- base [ key ] = overrideValue
195+ merged [ index ] = MergeJSONValues ( merged [ index ], overrideValue )
157196 }
197+ return merged
158198}
0 commit comments