@@ -471,6 +471,143 @@ func TestNullableRequired_UnmarshalJSON(t *testing.T) {
471471 }
472472}
473473
474+ type ComplexNullable struct {
475+ Config nullable.Nullable [Config ] `json:"config,omitempty"`
476+ Location nullable.Nullable [string ] `json:"location"`
477+ NodeCount nullable.Nullable [int ] `json:"node_count,omitempty"`
478+ }
479+
480+ type Config struct {
481+ CPU nullable.Nullable [string ] `json:"cpu,omitempty"`
482+ RAM nullable.Nullable [string ] `json:"ram,omitempty"`
483+ }
484+
485+ func TestComplexNullable (t * testing.T ) {
486+ type testCase struct {
487+ name string
488+ jsonInput []byte
489+ assert func (obj ComplexNullable , t * testing.T )
490+ wantNull bool
491+ wantSpecified bool
492+ }
493+ tests := []testCase {
494+ {
495+ name : "complex object: empty value" ,
496+ jsonInput : []byte (`{}` ),
497+ assert : func (obj ComplexNullable , t * testing.T ) {
498+ t .Helper ()
499+
500+ assert .Equalf (t , false , obj .Config .IsSpecified (), "config should not be set" )
501+ assert .Equalf (t , false , obj .Config .IsNull (), "config should not be null" )
502+
503+ assert .Equalf (t , false , obj .NodeCount .IsSpecified (), "node count should not be set" )
504+ assert .Equalf (t , false , obj .NodeCount .IsNull (), "node count should not be null" )
505+
506+ assert .Equalf (t , false , obj .Location .IsSpecified (), "location should not be set" )
507+ assert .Equalf (t , false , obj .Location .IsNull (), "location should not be null" )
508+ },
509+ },
510+ {
511+ name : "complex object: empty config value" ,
512+ jsonInput : []byte (`{"config":{}}` ),
513+ assert : func (obj ComplexNullable , t * testing.T ) {
514+ t .Helper ()
515+
516+ assert .Equalf (t , true , obj .Config .IsSpecified (), "config should be set" )
517+ assert .Equalf (t , false , obj .Config .IsNull (), "config should not be null" )
518+
519+ gotConfig , err := obj .Config .Get ()
520+ require .NoError (t , err )
521+
522+ assert .Equalf (t , false , gotConfig .CPU .IsSpecified (), "cpu should not be set" )
523+ assert .Equalf (t , false , gotConfig .CPU .IsNull (), "cpu should not be null" )
524+
525+ assert .Equalf (t , false , gotConfig .RAM .IsSpecified (), "ram should not be set" )
526+ assert .Equalf (t , false , gotConfig .RAM .IsNull (), "ram should not be null" )
527+ },
528+ },
529+
530+ {
531+ name : "complex object: setting only cpu config value" ,
532+ jsonInput : []byte (`{"config":{"cpu":"500"}}` ),
533+ assert : func (obj ComplexNullable , t * testing.T ) {
534+ t .Helper ()
535+
536+ assert .Equalf (t , true , obj .Config .IsSpecified (), "config should be set" )
537+ assert .Equalf (t , false , obj .Config .IsNull (), "config should not be null" )
538+
539+ gotConfig , err := obj .Config .Get ()
540+ require .NoError (t , err )
541+
542+ assert .Equalf (t , true , gotConfig .CPU .IsSpecified (), "cpu should be set" )
543+ assert .Equalf (t , false , gotConfig .CPU .IsNull (), "cpu should not be null" )
544+
545+ assert .Equalf (t , false , gotConfig .RAM .IsSpecified (), "ram should not be set" )
546+ assert .Equalf (t , false , gotConfig .RAM .IsNull (), "ram should not be null" )
547+ },
548+ },
549+
550+ {
551+ name : "complex object: setting only ram config value" ,
552+ jsonInput : []byte (`{"config":{"ram":"1024"}}` ),
553+ assert : func (obj ComplexNullable , t * testing.T ) {
554+ t .Helper ()
555+
556+ assert .Equalf (t , true , obj .Config .IsSpecified (), "config should be set" )
557+ assert .Equalf (t , false , obj .Config .IsNull (), "config should not be null" )
558+
559+ gotConfig , err := obj .Config .Get ()
560+ require .NoError (t , err )
561+
562+ assert .Equalf (t , false , gotConfig .CPU .IsSpecified (), "cpu should not be set" )
563+ assert .Equalf (t , false , gotConfig .CPU .IsNull (), "cpu should not be null" )
564+
565+ assert .Equalf (t , true , gotConfig .RAM .IsSpecified (), "ram should be set" )
566+ assert .Equalf (t , false , gotConfig .RAM .IsNull (), "ram should not be null" )
567+ },
568+ },
569+
570+ {
571+ name : "complex object: setting config to null" ,
572+ jsonInput : []byte (`{"config":null}` ),
573+ assert : func (obj ComplexNullable , t * testing.T ) {
574+ t .Helper ()
575+
576+ assert .Equalf (t , true , obj .Config .IsSpecified (), "config should be set" )
577+ assert .Equalf (t , true , obj .Config .IsNull (), "config should not be null" )
578+ },
579+ },
580+
581+ {
582+ name : "complex object: setting only cpu config to null" ,
583+ jsonInput : []byte (`{"config":{"cpu":null}}` ),
584+ assert : func (obj ComplexNullable , t * testing.T ) {
585+ t .Helper ()
586+
587+ assert .Equalf (t , true , obj .Config .IsSpecified (), "config should be set" )
588+ assert .Equalf (t , false , obj .Config .IsNull (), "config should not be null" )
589+
590+ gotConfig , err := obj .Config .Get ()
591+ require .NoError (t , err )
592+
593+ assert .Equalf (t , true , gotConfig .CPU .IsSpecified (), "cpu should be set" )
594+ assert .Equalf (t , true , gotConfig .CPU .IsNull (), "cpu should be null" )
595+
596+ assert .Equalf (t , false , gotConfig .RAM .IsSpecified (), "ram should not be set" )
597+ assert .Equalf (t , false , gotConfig .RAM .IsNull (), "ram should not be null" )
598+ },
599+ },
600+ }
601+ for _ , tt := range tests {
602+ t .Run (tt .name , func (t * testing.T ) {
603+ var obj ComplexNullable
604+ err := json .Unmarshal (tt .jsonInput , & obj )
605+ require .NoError (t , err )
606+ tt .assert (obj , t )
607+ })
608+ }
609+ }
610+
474611// Idempotency tests for nullable and optional
475612type StringNullableOptional struct {
476613 ID nullable.Nullable [string ] `json:"id,omitempty"`
0 commit comments