@@ -91,6 +91,16 @@ type testNonUniqueSectionsStruct struct {
9191 Interface testInterface
9292 Peer []testPeer `ini:",nonunique"`
9393}
94+ type testPeerPtr struct {
95+ PublicKey string
96+ PresharedKey string
97+ AllowedIPs []* string `delim:","`
98+ }
99+
100+ type testNonUniqueSectionsPtr struct {
101+ Interface testInterface
102+ Peer []* testPeerPtr `ini:",nonunique"`
103+ }
94104
95105type BaseStruct struct {
96106 Base bool
@@ -291,6 +301,15 @@ func Test_MapToStruct(t *testing.T) {
291301 assert .Error (t , f .MapTo (testStruct {}))
292302 })
293303
304+ t .Run ("map to nil target pointer" , func (t * testing.T ) {
305+ f , err := Load ([]byte (confDataStruct ))
306+ require .NoError (t , err )
307+ require .NotNil (t , f )
308+
309+ var ts * testStruct // nil pointer
310+ assert .Error (t , f .MapTo (ts ))
311+ })
312+
294313 t .Run ("map to unsupported type" , func (t * testing.T ) {
295314 f , err := Load ([]byte (confDataStruct ))
296315 require .NoError (t , err )
@@ -481,6 +500,102 @@ FieldInSection = 6
481500 })
482501 })
483502}
503+ func Test_MapToStructNonUniquePtr (t * testing.T ) {
504+ t .Run ("map to struct non unique" , func (t * testing.T ) {
505+ t .Run ("map file to struct non unique" , func (t * testing.T ) {
506+ f , err := LoadSources (LoadOptions {AllowNonUniqueSections : true }, []byte (confNonUniqueSectionDataStruct ))
507+ require .NoError (t , err )
508+ ts := new (testNonUniqueSectionsPtr )
509+
510+ assert .NoError (t , f .MapTo (ts ))
511+
512+ assert .Equal (t , "10.2.0.1/24" , ts .Interface .Address )
513+ assert .Equal (t , 34777 , ts .Interface .ListenPort )
514+ assert .Equal (t , "privServerKey" , ts .Interface .PrivateKey )
515+
516+ assert .Equal (t , "pubClientKey" , ts .Peer [0 ].PublicKey )
517+ assert .Equal (t , "psKey" , ts .Peer [0 ].PresharedKey )
518+ assert .Equal (t , "10.2.0.2/32" , ts .Peer [0 ].AllowedIPs [0 ])
519+ assert .Equal (t , "fd00:2::2/128" , ts .Peer [0 ].AllowedIPs [1 ])
520+
521+ assert .Equal (t , "pubClientKey2" , ts .Peer [1 ].PublicKey )
522+ assert .Equal (t , "psKey2" , ts .Peer [1 ].PresharedKey )
523+ assert .Equal (t , "10.2.0.3/32" , ts .Peer [1 ].AllowedIPs [0 ])
524+ assert .Equal (t , "fd00:2::3/128" , ts .Peer [1 ].AllowedIPs [1 ])
525+ })
526+
527+ t .Run ("map non unique section to struct" , func (t * testing.T ) {
528+ newPeer := new (testPeerPtr )
529+ newPeerSlice := make ([]testPeerPtr , 0 )
530+
531+ f , err := LoadSources (LoadOptions {AllowNonUniqueSections : true }, []byte (confNonUniqueSectionDataStruct ))
532+ require .NoError (t , err )
533+
534+ // try only first one
535+ assert .NoError (t , f .Section ("Peer" ).MapTo (newPeer ))
536+ assert .Equal (t , "pubClientKey" , newPeer .PublicKey )
537+ assert .Equal (t , "psKey" , newPeer .PresharedKey )
538+ assert .Equal (t , "10.2.0.2/32" , newPeer .AllowedIPs [0 ])
539+ assert .Equal (t , "fd00:2::2/128" , newPeer .AllowedIPs [1 ])
540+
541+ // try all
542+ assert .NoError (t , f .Section ("Peer" ).MapTo (& newPeerSlice ))
543+ assert .Equal (t , "pubClientKey" , newPeerSlice [0 ].PublicKey )
544+ assert .Equal (t , "psKey" , newPeerSlice [0 ].PresharedKey )
545+ assert .Equal (t , "10.2.0.2/32" , newPeerSlice [0 ].AllowedIPs [0 ])
546+ assert .Equal (t , "fd00:2::2/128" , newPeerSlice [0 ].AllowedIPs [1 ])
547+
548+ assert .Equal (t , "pubClientKey2" , newPeerSlice [1 ].PublicKey )
549+ assert .Equal (t , "psKey2" , newPeerSlice [1 ].PresharedKey )
550+ assert .Equal (t , "10.2.0.3/32" , newPeerSlice [1 ].AllowedIPs [0 ])
551+ assert .Equal (t , "fd00:2::3/128" , newPeerSlice [1 ].AllowedIPs [1 ])
552+ })
553+
554+ t .Run ("map non unique sections with subsections to struct" , func (t * testing.T ) {
555+ iniFile , err := LoadSources (LoadOptions {AllowNonUniqueSections : true }, strings .NewReader (`
556+ [Section]
557+ FieldInSubSection = 1
558+ FieldInSubSection2 = 2
559+ FieldInSection = 3
560+
561+ [Section]
562+ FieldInSubSection = 4
563+ FieldInSubSection2 = 5
564+ FieldInSection = 6
565+ ` ))
566+ require .NoError (t , err )
567+
568+ type SubSection struct {
569+ FieldInSubSection string `ini:"FieldInSubSection"`
570+ }
571+ type SubSection2 struct {
572+ FieldInSubSection2 string `ini:"FieldInSubSection2"`
573+ }
574+
575+ type Section struct {
576+ SubSection `ini:"Section"`
577+ SubSection2 `ini:"Section"`
578+ FieldInSection string `ini:"FieldInSection"`
579+ }
580+
581+ type File struct {
582+ Sections []* Section `ini:"Section,nonunique"`
583+ }
584+
585+ f := new (File )
586+ err = iniFile .MapTo (f )
587+ require .NoError (t , err )
588+
589+ assert .Equal (t , "1" , f .Sections [0 ].FieldInSubSection )
590+ assert .Equal (t , "2" , f .Sections [0 ].FieldInSubSection2 )
591+ assert .Equal (t , "3" , f .Sections [0 ].FieldInSection )
592+
593+ assert .Equal (t , "4" , f .Sections [1 ].FieldInSubSection )
594+ assert .Equal (t , "5" , f .Sections [1 ].FieldInSubSection2 )
595+ assert .Equal (t , "6" , f .Sections [1 ].FieldInSection )
596+ })
597+ })
598+ }
484599
485600func Test_ReflectFromStruct (t * testing.T ) {
486601 t .Run ("reflect from struct" , func (t * testing.T ) {
0 commit comments