kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/configs/configschema/validate_traversal_test.go (about) 1 package configschema 2 3 import ( 4 "testing" 5 6 "github.com/hashicorp/hcl/v2" 7 "github.com/hashicorp/hcl/v2/hclsyntax" 8 "github.com/zclconf/go-cty/cty" 9 ) 10 11 func TestStaticValidateTraversal(t *testing.T) { 12 attrs := map[string]*Attribute{ 13 "str": {Type: cty.String, Optional: true}, 14 "list": {Type: cty.List(cty.String), Optional: true}, 15 "dyn": {Type: cty.DynamicPseudoType, Optional: true}, 16 } 17 schema := &Block{ 18 Attributes: attrs, 19 BlockTypes: map[string]*NestedBlock{ 20 "single_block": { 21 Nesting: NestingSingle, 22 Block: Block{ 23 Attributes: attrs, 24 }, 25 }, 26 "list_block": { 27 Nesting: NestingList, 28 Block: Block{ 29 Attributes: attrs, 30 }, 31 }, 32 "set_block": { 33 Nesting: NestingSet, 34 Block: Block{ 35 Attributes: attrs, 36 }, 37 }, 38 "map_block": { 39 Nesting: NestingMap, 40 Block: Block{ 41 Attributes: attrs, 42 }, 43 }, 44 }, 45 } 46 47 tests := []struct { 48 Traversal string 49 WantError string 50 }{ 51 { 52 `obj`, 53 ``, 54 }, 55 { 56 `obj.str`, 57 ``, 58 }, 59 { 60 `obj.str.nonexist`, 61 `Unsupported attribute: Can't access attributes on a primitive-typed value (string).`, 62 }, 63 { 64 `obj.list`, 65 ``, 66 }, 67 { 68 `obj.list[0]`, 69 ``, 70 }, 71 { 72 `obj.list.nonexist`, 73 `Unsupported attribute: This value does not have any attributes.`, 74 }, 75 { 76 `obj.dyn`, 77 ``, 78 }, 79 { 80 `obj.dyn.anything_goes`, 81 ``, 82 }, 83 { 84 `obj.dyn[0]`, 85 ``, 86 }, 87 { 88 `obj.nonexist`, 89 `Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`, 90 }, 91 { 92 `obj[1]`, 93 `Invalid index operation: Only attribute access is allowed here, using the dot operator.`, 94 }, 95 { 96 `obj["str"]`, // we require attribute access for the first step to avoid ambiguity with resource instance indices 97 `Invalid index operation: Only attribute access is allowed here. Did you mean to access attribute "str" using the dot operator?`, 98 }, 99 { 100 `obj.atr`, 101 `Unsupported attribute: This object has no argument, nested block, or exported attribute named "atr". Did you mean "str"?`, 102 }, 103 { 104 `obj.single_block`, 105 ``, 106 }, 107 { 108 `obj.single_block.str`, 109 ``, 110 }, 111 { 112 `obj.single_block.nonexist`, 113 `Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`, 114 }, 115 { 116 `obj.list_block`, 117 ``, 118 }, 119 { 120 `obj.list_block[0]`, 121 ``, 122 }, 123 { 124 `obj.list_block[0].str`, 125 ``, 126 }, 127 { 128 `obj.list_block[0].nonexist`, 129 `Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`, 130 }, 131 { 132 `obj.list_block.str`, 133 `Invalid operation: Block type "list_block" is represented by a list of objects, so it must be indexed using a numeric key, like .list_block[0].`, 134 }, 135 { 136 `obj.set_block`, 137 ``, 138 }, 139 { 140 `obj.set_block[0]`, 141 `Cannot index a set value: Block type "set_block" is represented by a set of objects, and set elements do not have addressable keys. To find elements matching specific criteria, use a "for" expression with an "if" clause.`, 142 }, 143 { 144 `obj.set_block.str`, 145 `Cannot index a set value: Block type "set_block" is represented by a set of objects, and set elements do not have addressable keys. To find elements matching specific criteria, use a "for" expression with an "if" clause.`, 146 }, 147 { 148 `obj.map_block`, 149 ``, 150 }, 151 { 152 `obj.map_block.anything`, 153 ``, 154 }, 155 { 156 `obj.map_block["anything"]`, 157 ``, 158 }, 159 { 160 `obj.map_block.anything.str`, 161 ``, 162 }, 163 { 164 `obj.map_block["anything"].str`, 165 ``, 166 }, 167 { 168 `obj.map_block.anything.nonexist`, 169 `Unsupported attribute: This object has no argument, nested block, or exported attribute named "nonexist".`, 170 }, 171 } 172 173 for _, test := range tests { 174 t.Run(test.Traversal, func(t *testing.T) { 175 traversal, parseDiags := hclsyntax.ParseTraversalAbs([]byte(test.Traversal), "", hcl.Pos{Line: 1, Column: 1}) 176 for _, diag := range parseDiags { 177 t.Error(diag.Error()) 178 } 179 180 // We trim the "obj." portion from the front since StaticValidateTraversal 181 // only works with relative traversals. 182 traversal = traversal[1:] 183 184 diags := schema.StaticValidateTraversal(traversal) 185 if test.WantError == "" { 186 if diags.HasErrors() { 187 t.Errorf("unexpected error: %s", diags.Err().Error()) 188 } 189 } else { 190 if diags.HasErrors() { 191 if got := diags.Err().Error(); got != test.WantError { 192 t.Errorf("wrong error\ngot: %s\nwant: %s", got, test.WantError) 193 } 194 } else { 195 t.Errorf("wrong error\ngot: <no error>\nwant: %s", test.WantError) 196 } 197 } 198 }) 199 } 200 }