@@ -10,11 +10,27 @@ import (
1010 "time"
1111
1212 "github.com/pb33f/libopenapi/datamodel"
13+ "github.com/pb33f/libopenapi/datamodel/low"
1314 "github.com/pb33f/libopenapi/orderedmap"
1415 "github.com/pb33f/testify/assert"
1516 "github.com/pb33f/testify/require"
17+ "go.yaml.in/yaml/v4"
1618)
1719
20+ type yamlErrorMarshaler struct {}
21+
22+ func (yamlErrorMarshaler ) MarshalYAML () (interface {}, error ) {
23+ return nil , errors .New ("yaml marshal failed" )
24+ }
25+
26+ type yamlNodeMarshaler struct {
27+ node * yaml.Node
28+ }
29+
30+ func (y yamlNodeMarshaler ) MarshalYAML () (interface {}, error ) {
31+ return y .node , nil
32+ }
33+
1834func TestOrderedMap (t * testing.T ) {
1935 t .Run ("Empty" , func (t * testing.T ) {
2036 m := orderedmap .New [string , int ]()
@@ -265,6 +281,159 @@ func TestMap(t *testing.T) {
265281 })
266282}
267283
284+ func TestMapMarshalYAMLDoesNotMutateYAMLNodeValues (t * testing.T ) {
285+ t .Run ("nil map marshals as null" , func (t * testing.T ) {
286+ var m * orderedmap.Map [string , * yaml.Node ]
287+
288+ node , err := m .MarshalYAML ()
289+ require .NoError (t , err )
290+ require .Nil (t , node )
291+
292+ rendered , err := yaml .Marshal (m )
293+ require .NoError (t , err )
294+ require .Equal (t , "null\n " , string (rendered ))
295+ })
296+
297+ t .Run ("nil value marshals as null" , func (t * testing.T ) {
298+ m := orderedmap .New [string , any ]()
299+ m .Set ("x-null" , nil )
300+
301+ rendered , err := yaml .Marshal (m )
302+ require .NoError (t , err )
303+ require .Equal (t , "x-null: null\n " , string (rendered ))
304+ })
305+
306+ t .Run ("nil pointer value marshals as null" , func (t * testing.T ) {
307+ var value * yamlErrorMarshaler
308+ m := orderedmap .New [string , * yamlErrorMarshaler ]()
309+ m .Set ("x-null" , value )
310+
311+ rendered , err := yaml .Marshal (m )
312+ require .NoError (t , err )
313+ require .Equal (t , "x-null: null\n " , string (rendered ))
314+ })
315+
316+ t .Run ("key marshaler error" , func (t * testing.T ) {
317+ m := orderedmap .New [yamlErrorMarshaler , string ]()
318+ m .Set (yamlErrorMarshaler {}, "value" )
319+
320+ _ , err := m .MarshalYAML ()
321+ require .ErrorContains (t , err , "yaml marshal failed" )
322+ })
323+
324+ t .Run ("value marshaler error" , func (t * testing.T ) {
325+ m := orderedmap .New [string , yamlErrorMarshaler ]()
326+ m .Set ("x-error" , yamlErrorMarshaler {})
327+
328+ _ , err := m .MarshalYAML ()
329+ require .ErrorContains (t , err , "yaml marshal failed" )
330+ })
331+
332+ t .Run ("key encode error" , func (t * testing.T ) {
333+ m := orderedmap .New [chan int , string ]()
334+ m .Set (make (chan int ), "value" )
335+
336+ _ , err := m .MarshalYAML ()
337+ require .Error (t , err )
338+ })
339+
340+ t .Run ("value encode error" , func (t * testing.T ) {
341+ m := orderedmap .New [string , chan int ]()
342+ m .Set ("x-error" , make (chan int ))
343+
344+ _ , err := m .MarshalYAML ()
345+ require .Error (t , err )
346+ })
347+
348+ t .Run ("direct scalar node" , func (t * testing.T ) {
349+ valueNode := & yaml.Node {
350+ Kind : yaml .ScalarNode ,
351+ Tag : "!!bool" ,
352+ Value : "true" ,
353+ }
354+
355+ m := orderedmap .New [string , * yaml.Node ]()
356+ m .Set ("x-custom" , valueNode )
357+
358+ _ , err := m .MarshalYAML ()
359+ require .NoError (t , err )
360+
361+ require .Equal (t , yaml .ScalarNode , valueNode .Kind )
362+ require .Equal (t , "!!bool" , valueNode .Tag )
363+ require .Equal (t , "true" , valueNode .Value )
364+ require .Equal (t , yaml .Style (0 ), valueNode .Style )
365+ })
366+
367+ t .Run ("nested node tree" , func (t * testing.T ) {
368+ valueNode := & yaml.Node {
369+ Kind : yaml .MappingNode ,
370+ Tag : "!!map" ,
371+ Content : []* yaml.Node {
372+ {Kind : yaml .ScalarNode , Tag : "!!str" , Value : "enabled" },
373+ {Kind : yaml .ScalarNode , Tag : "!!bool" , Value : "true" },
374+ {Kind : yaml .ScalarNode , Tag : "!!str" , Value : "levels" },
375+ {
376+ Kind : yaml .SequenceNode ,
377+ Tag : "!!seq" ,
378+ Content : []* yaml.Node {
379+ {Kind : yaml .ScalarNode , Tag : "!!int" , Value : "1" },
380+ {Kind : yaml .ScalarNode , Tag : "!!int" , Value : "2" },
381+ },
382+ },
383+ },
384+ }
385+
386+ m := orderedmap .New [string , * yaml.Node ]()
387+ m .Set ("x-nested" , valueNode )
388+
389+ _ , err := yaml .Marshal (m )
390+ require .NoError (t , err )
391+
392+ require .Equal (t , "!!map" , valueNode .Tag )
393+ require .Equal (t , "!!str" , valueNode .Content [0 ].Tag )
394+ require .Equal (t , "!!bool" , valueNode .Content [1 ].Tag )
395+ require .Equal (t , "!!str" , valueNode .Content [2 ].Tag )
396+ require .Equal (t , "!!seq" , valueNode .Content [3 ].Tag )
397+ require .Equal (t , "!!int" , valueNode .Content [3 ].Content [0 ].Tag )
398+ require .Equal (t , "!!int" , valueNode .Content [3 ].Content [1 ].Tag )
399+ })
400+
401+ t .Run ("marshaler key returning node" , func (t * testing.T ) {
402+ keyNode := & yaml.Node {
403+ Kind : yaml .ScalarNode ,
404+ Tag : "!!str" ,
405+ Value : "x-custom" ,
406+ }
407+ m := orderedmap .New [low.KeyReference [string ], string ]()
408+ m .Set (low.KeyReference [string ]{
409+ Value : "x-custom" ,
410+ KeyNode : keyNode ,
411+ }, "true" )
412+
413+ _ , err := yaml .Marshal (m )
414+ require .NoError (t , err )
415+
416+ require .Equal (t , "!!str" , keyNode .Tag )
417+ require .Equal (t , "x-custom" , keyNode .Value )
418+ })
419+
420+ t .Run ("recursive marshaler returning node" , func (t * testing.T ) {
421+ valueNode := & yaml.Node {
422+ Kind : yaml .ScalarNode ,
423+ Tag : "!!bool" ,
424+ Value : "true" ,
425+ }
426+ m := orderedmap .New [string , yamlNodeMarshaler ]()
427+ m .Set ("x-custom" , yamlNodeMarshaler {node : valueNode })
428+
429+ _ , err := yaml .Marshal (m )
430+ require .NoError (t , err )
431+
432+ require .Equal (t , "!!bool" , valueNode .Tag )
433+ require .Equal (t , "true" , valueNode .Value )
434+ })
435+ }
436+
268437func TestFirst (t * testing.T ) {
269438 t .Run ("Nil" , func (t * testing.T ) {
270439 pair := orderedmap.First [string , int ](nil )
0 commit comments