github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/configs/configschema/empty_value_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package configschema
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  
    10  	"github.com/apparentlymart/go-dump/dump"
    11  	"github.com/davecgh/go-spew/spew"
    12  	"github.com/zclconf/go-cty/cty"
    13  )
    14  
    15  func TestBlockEmptyValue(t *testing.T) {
    16  	tests := []struct {
    17  		Schema *Block
    18  		Want   cty.Value
    19  	}{
    20  		{
    21  			&Block{},
    22  			cty.EmptyObjectVal,
    23  		},
    24  		{
    25  			&Block{
    26  				Attributes: map[string]*Attribute{
    27  					"str": {Type: cty.String, Required: true},
    28  				},
    29  			},
    30  			cty.ObjectVal(map[string]cty.Value{
    31  				"str": cty.NullVal(cty.String),
    32  			}),
    33  		},
    34  		{
    35  			&Block{
    36  				BlockTypes: map[string]*NestedBlock{
    37  					"single": {
    38  						Nesting: NestingSingle,
    39  						Block: Block{
    40  							Attributes: map[string]*Attribute{
    41  								"str": {Type: cty.String, Required: true},
    42  							},
    43  						},
    44  					},
    45  				},
    46  			},
    47  			cty.ObjectVal(map[string]cty.Value{
    48  				"single": cty.NullVal(cty.Object(map[string]cty.Type{
    49  					"str": cty.String,
    50  				})),
    51  			}),
    52  		},
    53  		{
    54  			&Block{
    55  				BlockTypes: map[string]*NestedBlock{
    56  					"group": {
    57  						Nesting: NestingGroup,
    58  						Block: Block{
    59  							Attributes: map[string]*Attribute{
    60  								"str": {Type: cty.String, Required: true},
    61  							},
    62  						},
    63  					},
    64  				},
    65  			},
    66  			cty.ObjectVal(map[string]cty.Value{
    67  				"group": cty.ObjectVal(map[string]cty.Value{
    68  					"str": cty.NullVal(cty.String),
    69  				}),
    70  			}),
    71  		},
    72  		{
    73  			&Block{
    74  				BlockTypes: map[string]*NestedBlock{
    75  					"list": {
    76  						Nesting: NestingList,
    77  						Block: Block{
    78  							Attributes: map[string]*Attribute{
    79  								"str": {Type: cty.String, Required: true},
    80  							},
    81  						},
    82  					},
    83  				},
    84  			},
    85  			cty.ObjectVal(map[string]cty.Value{
    86  				"list": cty.ListValEmpty(cty.Object(map[string]cty.Type{
    87  					"str": cty.String,
    88  				})),
    89  			}),
    90  		},
    91  		{
    92  			&Block{
    93  				BlockTypes: map[string]*NestedBlock{
    94  					"list_dynamic": {
    95  						Nesting: NestingList,
    96  						Block: Block{
    97  							Attributes: map[string]*Attribute{
    98  								"str": {Type: cty.DynamicPseudoType, Required: true},
    99  							},
   100  						},
   101  					},
   102  				},
   103  			},
   104  			cty.ObjectVal(map[string]cty.Value{
   105  				"list_dynamic": cty.EmptyTupleVal,
   106  			}),
   107  		},
   108  		{
   109  			&Block{
   110  				BlockTypes: map[string]*NestedBlock{
   111  					"map": {
   112  						Nesting: NestingMap,
   113  						Block: Block{
   114  							Attributes: map[string]*Attribute{
   115  								"str": {Type: cty.String, Required: true},
   116  							},
   117  						},
   118  					},
   119  				},
   120  			},
   121  			cty.ObjectVal(map[string]cty.Value{
   122  				"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{
   123  					"str": cty.String,
   124  				})),
   125  			}),
   126  		},
   127  		{
   128  			&Block{
   129  				BlockTypes: map[string]*NestedBlock{
   130  					"map_dynamic": {
   131  						Nesting: NestingMap,
   132  						Block: Block{
   133  							Attributes: map[string]*Attribute{
   134  								"str": {Type: cty.DynamicPseudoType, Required: true},
   135  							},
   136  						},
   137  					},
   138  				},
   139  			},
   140  			cty.ObjectVal(map[string]cty.Value{
   141  				"map_dynamic": cty.EmptyObjectVal,
   142  			}),
   143  		},
   144  		{
   145  			&Block{
   146  				BlockTypes: map[string]*NestedBlock{
   147  					"set": {
   148  						Nesting: NestingSet,
   149  						Block: Block{
   150  							Attributes: map[string]*Attribute{
   151  								"str": {Type: cty.String, Required: true},
   152  							},
   153  						},
   154  					},
   155  				},
   156  			},
   157  			cty.ObjectVal(map[string]cty.Value{
   158  				"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{
   159  					"str": cty.String,
   160  				})),
   161  			}),
   162  		},
   163  	}
   164  
   165  	for _, test := range tests {
   166  		t.Run(fmt.Sprintf("%#v", test.Schema), func(t *testing.T) {
   167  			got := test.Schema.EmptyValue()
   168  			if !test.Want.RawEquals(got) {
   169  				t.Errorf("wrong result\nschema: %s\ngot: %s\nwant: %s", spew.Sdump(test.Schema), dump.Value(got), dump.Value(test.Want))
   170  			}
   171  		})
   172  	}
   173  }
   174  
   175  // Attribute EmptyValue() is well covered by the Block tests above; these tests
   176  // focus on the behavior with NestedType field inside an Attribute
   177  func TestAttributeEmptyValue(t *testing.T) {
   178  	tests := []struct {
   179  		Schema *Attribute
   180  		Want   cty.Value
   181  	}{
   182  		{
   183  			&Attribute{},
   184  			cty.NilVal,
   185  		},
   186  		{
   187  			&Attribute{
   188  				Type: cty.String,
   189  			},
   190  			cty.NullVal(cty.String),
   191  		},
   192  		{
   193  			&Attribute{
   194  				NestedType: &Object{
   195  					Nesting: NestingSingle,
   196  					Attributes: map[string]*Attribute{
   197  						"str": {Type: cty.String, Required: true},
   198  					},
   199  				},
   200  			},
   201  			cty.NullVal(cty.Object(map[string]cty.Type{
   202  				"str": cty.String,
   203  			})),
   204  		},
   205  		{
   206  			&Attribute{
   207  				NestedType: &Object{
   208  					Nesting: NestingList,
   209  					Attributes: map[string]*Attribute{
   210  						"str": {Type: cty.String, Required: true},
   211  					},
   212  				},
   213  			},
   214  			cty.NullVal(cty.List(
   215  				cty.Object(map[string]cty.Type{
   216  					"str": cty.String,
   217  				}),
   218  			)),
   219  		},
   220  		{
   221  			&Attribute{
   222  				NestedType: &Object{
   223  					Nesting: NestingMap,
   224  					Attributes: map[string]*Attribute{
   225  						"str": {Type: cty.String, Required: true},
   226  					},
   227  				},
   228  			},
   229  			cty.NullVal(cty.Map(
   230  				cty.Object(map[string]cty.Type{
   231  					"str": cty.String,
   232  				}),
   233  			)),
   234  		},
   235  		{
   236  			&Attribute{
   237  				NestedType: &Object{
   238  					Nesting: NestingSet,
   239  					Attributes: map[string]*Attribute{
   240  						"str": {Type: cty.String, Required: true},
   241  					},
   242  				},
   243  			},
   244  			cty.NullVal(cty.Set(
   245  				cty.Object(map[string]cty.Type{
   246  					"str": cty.String,
   247  				}),
   248  			)),
   249  		},
   250  	}
   251  
   252  	for _, test := range tests {
   253  		t.Run(fmt.Sprintf("%#v", test.Schema), func(t *testing.T) {
   254  			got := test.Schema.EmptyValue()
   255  			if !test.Want.RawEquals(got) {
   256  				t.Errorf("wrong result\nschema: %s\ngot: %s\nwant: %s", spew.Sdump(test.Schema), dump.Value(got), dump.Value(test.Want))
   257  			}
   258  		})
   259  	}
   260  }