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

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package configschema
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/zclconf/go-cty/cty"
    10  )
    11  
    12  func TestAttributeByPath(t *testing.T) {
    13  	schema := &Block{
    14  		Attributes: map[string]*Attribute{
    15  			"a1": {Description: "a1"},
    16  			"a2": {Description: "a2"},
    17  			"a3": {
    18  				Description: "a3",
    19  				NestedType: &Object{
    20  					Nesting: NestingList,
    21  					Attributes: map[string]*Attribute{
    22  						"nt1": {Description: "nt1"},
    23  						"nt2": {
    24  							Description: "nt2",
    25  							NestedType: &Object{
    26  								Nesting: NestingSingle,
    27  								Attributes: map[string]*Attribute{
    28  									"deeply_nested": {Description: "deeply_nested"},
    29  								},
    30  							},
    31  						},
    32  					},
    33  				},
    34  			},
    35  		},
    36  		BlockTypes: map[string]*NestedBlock{
    37  			"b1": {
    38  				Nesting: NestingList,
    39  				Block: Block{
    40  					Attributes: map[string]*Attribute{
    41  						"a3": {Description: "a3"},
    42  						"a4": {Description: "a4"},
    43  					},
    44  					BlockTypes: map[string]*NestedBlock{
    45  						"b2": {
    46  							Nesting: NestingMap,
    47  							Block: Block{
    48  								Attributes: map[string]*Attribute{
    49  									"a5": {Description: "a5"},
    50  									"a6": {Description: "a6"},
    51  								},
    52  							},
    53  						},
    54  					},
    55  				},
    56  			},
    57  			"b3": {
    58  				Nesting: NestingMap,
    59  				Block: Block{
    60  					Attributes: map[string]*Attribute{
    61  						"a7": {Description: "a7"},
    62  						"a8": {Description: "a8"},
    63  					},
    64  					BlockTypes: map[string]*NestedBlock{
    65  						"b4": {
    66  							Nesting: NestingSet,
    67  							Block: Block{
    68  								Attributes: map[string]*Attribute{
    69  									"a9":  {Description: "a9"},
    70  									"a10": {Description: "a10"},
    71  								},
    72  							},
    73  						},
    74  					},
    75  				},
    76  			},
    77  		},
    78  	}
    79  
    80  	for _, tc := range []struct {
    81  		path            cty.Path
    82  		attrDescription string
    83  		exists          bool
    84  	}{
    85  		{
    86  			cty.GetAttrPath("a2"),
    87  			"a2",
    88  			true,
    89  		},
    90  		{
    91  			cty.GetAttrPath("a3").IndexInt(1).GetAttr("nt2"),
    92  			"nt2",
    93  			true,
    94  		},
    95  		{
    96  			cty.GetAttrPath("a3").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("no"),
    97  			"missing",
    98  			false,
    99  		},
   100  		{
   101  			cty.GetAttrPath("b1"),
   102  			"block",
   103  			false,
   104  		},
   105  		{
   106  			cty.GetAttrPath("b1").IndexInt(1).GetAttr("a3"),
   107  			"a3",
   108  			true,
   109  		},
   110  		{
   111  			cty.GetAttrPath("b1").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("a7"),
   112  			"missing",
   113  			false,
   114  		},
   115  		{
   116  			cty.GetAttrPath("b1").IndexInt(1).GetAttr("b2").IndexString("foo").GetAttr("a6"),
   117  			"a6",
   118  			true,
   119  		},
   120  		{
   121  			cty.GetAttrPath("b3").IndexString("foo").GetAttr("b2").IndexString("foo").GetAttr("a7"),
   122  			"missing_block",
   123  			false,
   124  		},
   125  		{
   126  			cty.GetAttrPath("b3").IndexString("foo").GetAttr("a7"),
   127  			"a7",
   128  			true,
   129  		},
   130  		{
   131  			// Index steps don't apply to the schema, so the set Index value doesn't matter.
   132  			cty.GetAttrPath("b3").IndexString("foo").GetAttr("b4").Index(cty.EmptyObjectVal).GetAttr("a9"),
   133  			"a9",
   134  			true,
   135  		},
   136  	} {
   137  		t.Run(tc.attrDescription, func(t *testing.T) {
   138  			attr := schema.AttributeByPath(tc.path)
   139  			if !tc.exists && attr == nil {
   140  				return
   141  			}
   142  
   143  			if attr == nil {
   144  				t.Fatalf("missing attribute from path %#v\n", tc.path)
   145  			}
   146  
   147  			if attr.Description != tc.attrDescription {
   148  				t.Fatalf("expected Attribute for %q, got %#v\n", tc.attrDescription, attr)
   149  			}
   150  		})
   151  	}
   152  }
   153  
   154  func TestObject_AttributeByPath(t *testing.T) {
   155  	obj := &Object{
   156  		Nesting: NestingList,
   157  		Attributes: map[string]*Attribute{
   158  			"a1": {Description: "a1"},
   159  			"a2": {
   160  				Description: "a2",
   161  				NestedType: &Object{
   162  					Nesting: NestingSingle,
   163  					Attributes: map[string]*Attribute{
   164  						"n1": {Description: "n1"},
   165  						"n2": {
   166  							Description: "n2",
   167  							NestedType: &Object{
   168  								Attributes: map[string]*Attribute{
   169  									"dn1": {Description: "dn1"},
   170  								},
   171  							},
   172  						},
   173  					},
   174  				},
   175  			},
   176  		},
   177  	}
   178  
   179  	tests := []struct {
   180  		path            cty.Path
   181  		attrDescription string
   182  		exists          bool
   183  	}{
   184  		{
   185  			cty.GetAttrPath("a2"),
   186  			"a2",
   187  			true,
   188  		},
   189  		{
   190  			cty.GetAttrPath("a3"),
   191  			"missing",
   192  			false,
   193  		},
   194  		{
   195  			cty.GetAttrPath("a2").IndexString("foo").GetAttr("n1"),
   196  			"n1",
   197  			true,
   198  		},
   199  		{
   200  			cty.GetAttrPath("a2").IndexString("foo").GetAttr("n2").IndexInt(11).GetAttr("dn1"),
   201  			"dn1",
   202  			true,
   203  		},
   204  		{
   205  			cty.GetAttrPath("a2").IndexString("foo").GetAttr("n2").IndexInt(11).GetAttr("dn1").IndexString("hello").GetAttr("nope"),
   206  			"missing_nested",
   207  			false,
   208  		},
   209  	}
   210  
   211  	for _, tc := range tests {
   212  		t.Run(tc.attrDescription, func(t *testing.T) {
   213  			attr := obj.AttributeByPath(tc.path)
   214  			if !tc.exists && attr == nil {
   215  				return
   216  			}
   217  
   218  			if !tc.exists && attr != nil {
   219  				t.Fatalf("found Attribute, expected nil from path %#v\n", tc.path)
   220  			}
   221  
   222  			if attr == nil {
   223  				t.Fatalf("missing attribute from path %#v\n", tc.path)
   224  			}
   225  
   226  			if attr.Description != tc.attrDescription {
   227  				t.Fatalf("expected Attribute for %q, got %#v\n", tc.attrDescription, attr)
   228  			}
   229  		})
   230  	}
   231  
   232  }