@@ -92,6 +92,94 @@ func TestPrepareFinalInputVariableValue(t *testing.T) {
9292 })
9393 })
9494 }
95+ // https://github.com/hashicorp/terraform/issues/32152
96+ // This variable was originally added to test that optional attribute
97+ // metadata is stripped from empty default collections. Essentially, you
98+ // should be able to mix and match custom and default values for the
99+ // optional_list attribute.
100+ variable "complex_type_with_empty_default_and_nested_optional" {
101+ type = list(object({
102+ name = string
103+ optional_list = optional(list(object({
104+ string = string
105+ optional_string = optional(string)
106+ })), [])
107+ }))
108+ }
109+ // https://github.com/hashicorp/terraform/issues/32160#issuecomment-1302783910
110+ // These variables were added to test the specific use case from this
111+ // GitHub comment.
112+ variable "empty_object_with_optional_nested_object_with_optional_bool" {
113+ type = object({
114+ thing = optional(object({
115+ flag = optional(bool, false)
116+ }))
117+ })
118+ default = {}
119+ }
120+ variable "populated_object_with_optional_nested_object_with_optional_bool" {
121+ type = object({
122+ thing = optional(object({
123+ flag = optional(bool, false)
124+ }))
125+ })
126+ default = {
127+ thing = {}
128+ }
129+ }
130+ variable "empty_object_with_default_nested_object_with_optional_bool" {
131+ type = object({
132+ thing = optional(object({
133+ flag = optional(bool, false)
134+ }), {})
135+ })
136+ default = {}
137+ }
138+ // https://github.com/hashicorp/terraform/issues/32160
139+ // This variable was originally added to test that optional objects do
140+ // get created containing only their defaults. Instead they should be
141+ // left empty. We do not expect nested_object to be created just because
142+ // optional_string has a default value.
143+ variable "object_with_nested_object_with_required_and_optional_attributes" {
144+ type = object({
145+ nested_object = optional(object({
146+ string = string
147+ optional_string = optional(string, "optional")
148+ }))
149+ })
150+ }
151+ // https://github.com/hashicorp/terraform/issues/32157
152+ // Similar to above, we want to see that merging combinations of the
153+ // nested_object into a single collection doesn't crash because of
154+ // inconsistent elements.
155+ variable "list_with_nested_object_with_required_and_optional_attributes" {
156+ type = list(object({
157+ nested_object = optional(object({
158+ string = string
159+ optional_string = optional(string, "optional")
160+ }))
161+ }))
162+ }
163+ // https://github.com/hashicorp/terraform/issues/32109
164+ // This variable was originally introduced to test the behaviour of
165+ // the dynamic type constraint. You should be able to use the 'any'
166+ // constraint and introduce empty, null, and populated values into the
167+ // list.
168+ variable "list_with_nested_list_of_any" {
169+ type = list(object({
170+ a = string
171+ b = optional(list(any))
172+ }))
173+ default = [
174+ {
175+ a = "a"
176+ },
177+ {
178+ a = "b"
179+ b = [1]
180+ }
181+ ]
182+ }
95183 `
96184 cfg := testModuleInline (t , map [string ]string {
97185 "main.tf" : cfgSrc ,
@@ -496,6 +584,136 @@ func TestPrepareFinalInputVariableValue(t *testing.T) {
496584 }),
497585 `` ,
498586 },
587+ {
588+ "complex_type_with_empty_default_and_nested_optional" ,
589+ cty .ListVal ([]cty.Value {
590+ cty .ObjectVal (map [string ]cty.Value {
591+ "name" : cty .StringVal ("abc" ),
592+ "optional_list" : cty .ListVal ([]cty.Value {
593+ cty .ObjectVal (map [string ]cty.Value {
594+ "string" : cty .StringVal ("child" ),
595+ "optional_string" : cty .NullVal (cty .String ),
596+ }),
597+ }),
598+ }),
599+ cty .ObjectVal (map [string ]cty.Value {
600+ "name" : cty .StringVal ("def" ),
601+ "optional_list" : cty .NullVal (cty .List (cty .Object (map [string ]cty.Type {
602+ "string" : cty .String ,
603+ "optional_string" : cty .String ,
604+ }))),
605+ }),
606+ }),
607+ cty .ListVal ([]cty.Value {
608+ cty .ObjectVal (map [string ]cty.Value {
609+ "name" : cty .StringVal ("abc" ),
610+ "optional_list" : cty .ListVal ([]cty.Value {
611+ cty .ObjectVal (map [string ]cty.Value {
612+ "string" : cty .StringVal ("child" ),
613+ "optional_string" : cty .NullVal (cty .String ),
614+ }),
615+ }),
616+ }),
617+ cty .ObjectVal (map [string ]cty.Value {
618+ "name" : cty .StringVal ("def" ),
619+ "optional_list" : cty .ListValEmpty (cty .Object (map [string ]cty.Type {
620+ "string" : cty .String ,
621+ "optional_string" : cty .String ,
622+ })),
623+ }),
624+ }),
625+ `` ,
626+ },
627+ {
628+ "object_with_nested_object_with_required_and_optional_attributes" ,
629+ cty .EmptyObjectVal ,
630+ cty .ObjectVal (map [string ]cty.Value {
631+ "nested_object" : cty .NullVal (cty .Object (map [string ]cty.Type {
632+ "string" : cty .String ,
633+ "optional_string" : cty .String ,
634+ })),
635+ }),
636+ `` ,
637+ },
638+ {
639+ "empty_object_with_optional_nested_object_with_optional_bool" ,
640+ cty .NilVal ,
641+ cty .ObjectVal (map [string ]cty.Value {
642+ "thing" : cty .NullVal (cty .Object (map [string ]cty.Type {
643+ "flag" : cty .Bool ,
644+ })),
645+ }),
646+ `` ,
647+ },
648+ {
649+ "populated_object_with_optional_nested_object_with_optional_bool" ,
650+ cty .NilVal ,
651+ cty .ObjectVal (map [string ]cty.Value {
652+ "thing" : cty .ObjectVal (map [string ]cty.Value {
653+ "flag" : cty .False ,
654+ }),
655+ }),
656+ `` ,
657+ },
658+ {
659+ "empty_object_with_default_nested_object_with_optional_bool" ,
660+ cty .NilVal ,
661+ cty .ObjectVal (map [string ]cty.Value {
662+ "thing" : cty .ObjectVal (map [string ]cty.Value {
663+ "flag" : cty .False ,
664+ }),
665+ }),
666+ `` ,
667+ },
668+ {
669+ "list_with_nested_object_with_required_and_optional_attributes" ,
670+ cty .ListVal ([]cty.Value {
671+ cty .ObjectVal (map [string ]cty.Value {
672+ "nested_object" : cty .ObjectVal (map [string ]cty.Value {
673+ "string" : cty .StringVal ("string" ),
674+ "optional_string" : cty .NullVal (cty .String ),
675+ }),
676+ }),
677+ cty .ObjectVal (map [string ]cty.Value {
678+ "nested_object" : cty .NullVal (cty .Object (map [string ]cty.Type {
679+ "string" : cty .String ,
680+ "optional_string" : cty .String ,
681+ })),
682+ }),
683+ }),
684+ cty .ListVal ([]cty.Value {
685+ cty .ObjectVal (map [string ]cty.Value {
686+ "nested_object" : cty .ObjectVal (map [string ]cty.Value {
687+ "string" : cty .StringVal ("string" ),
688+ "optional_string" : cty .StringVal ("optional" ),
689+ }),
690+ }),
691+ cty .ObjectVal (map [string ]cty.Value {
692+ "nested_object" : cty .NullVal (cty .Object (map [string ]cty.Type {
693+ "string" : cty .String ,
694+ "optional_string" : cty .String ,
695+ })),
696+ }),
697+ }),
698+ `` ,
699+ },
700+ {
701+ "list_with_nested_list_of_any" ,
702+ cty .NilVal ,
703+ cty .ListVal ([]cty.Value {
704+ cty .ObjectVal (map [string ]cty.Value {
705+ "a" : cty .StringVal ("a" ),
706+ "b" : cty .NullVal (cty .List (cty .Number )),
707+ }),
708+ cty .ObjectVal (map [string ]cty.Value {
709+ "a" : cty .StringVal ("b" ),
710+ "b" : cty .ListVal ([]cty.Value {
711+ cty .NumberIntVal (1 ),
712+ }),
713+ }),
714+ }),
715+ `` ,
716+ },
499717
500718 // sensitive
501719 {
0 commit comments