github.com/KevinKlinger/open_terraform@v0.11.12-beta1/config/configschema/internal_validate_test.go (about) 1 package configschema 2 3 import ( 4 "testing" 5 6 "github.com/zclconf/go-cty/cty" 7 8 multierror "github.com/hashicorp/go-multierror" 9 ) 10 11 func TestBlockInternalValidate(t *testing.T) { 12 tests := map[string]struct { 13 Block *Block 14 ErrCount int 15 }{ 16 "empty": { 17 &Block{}, 18 0, 19 }, 20 "valid": { 21 &Block{ 22 Attributes: map[string]*Attribute{ 23 "foo": &Attribute{ 24 Type: cty.String, 25 Required: true, 26 }, 27 "bar": &Attribute{ 28 Type: cty.String, 29 Optional: true, 30 }, 31 "baz": &Attribute{ 32 Type: cty.String, 33 Computed: true, 34 }, 35 "baz_maybe": &Attribute{ 36 Type: cty.String, 37 Optional: true, 38 Computed: true, 39 }, 40 }, 41 BlockTypes: map[string]*NestedBlock{ 42 "single": &NestedBlock{ 43 Nesting: NestingSingle, 44 Block: Block{}, 45 }, 46 "single_required": &NestedBlock{ 47 Nesting: NestingSingle, 48 Block: Block{}, 49 MinItems: 1, 50 MaxItems: 1, 51 }, 52 "list": &NestedBlock{ 53 Nesting: NestingList, 54 Block: Block{}, 55 }, 56 "list_required": &NestedBlock{ 57 Nesting: NestingList, 58 Block: Block{}, 59 MinItems: 1, 60 }, 61 "set": &NestedBlock{ 62 Nesting: NestingSet, 63 Block: Block{}, 64 }, 65 "set_required": &NestedBlock{ 66 Nesting: NestingSet, 67 Block: Block{}, 68 MinItems: 1, 69 }, 70 "map": &NestedBlock{ 71 Nesting: NestingMap, 72 Block: Block{}, 73 }, 74 }, 75 }, 76 0, 77 }, 78 "attribute with no flags set": { 79 &Block{ 80 Attributes: map[string]*Attribute{ 81 "foo": &Attribute{ 82 Type: cty.String, 83 }, 84 }, 85 }, 86 1, // must set one of the flags 87 }, 88 "attribute required and optional": { 89 &Block{ 90 Attributes: map[string]*Attribute{ 91 "foo": &Attribute{ 92 Type: cty.String, 93 Required: true, 94 Optional: true, 95 }, 96 }, 97 }, 98 1, // both required and optional 99 }, 100 "attribute required and computed": { 101 &Block{ 102 Attributes: map[string]*Attribute{ 103 "foo": &Attribute{ 104 Type: cty.String, 105 Required: true, 106 Computed: true, 107 }, 108 }, 109 }, 110 1, // both required and computed 111 }, 112 "attribute optional and computed": { 113 &Block{ 114 Attributes: map[string]*Attribute{ 115 "foo": &Attribute{ 116 Type: cty.String, 117 Optional: true, 118 Computed: true, 119 }, 120 }, 121 }, 122 0, 123 }, 124 "attribute with missing type": { 125 &Block{ 126 Attributes: map[string]*Attribute{ 127 "foo": &Attribute{ 128 Optional: true, 129 }, 130 }, 131 }, 132 1, // Type must be set 133 }, 134 "attribute with invalid name": { 135 &Block{ 136 Attributes: map[string]*Attribute{ 137 "fooBar": &Attribute{ 138 Type: cty.String, 139 Optional: true, 140 }, 141 }, 142 }, 143 1, // name may not contain uppercase letters 144 }, 145 "block type with invalid name": { 146 &Block{ 147 BlockTypes: map[string]*NestedBlock{ 148 "fooBar": &NestedBlock{ 149 Nesting: NestingSingle, 150 }, 151 }, 152 }, 153 1, // name may not contain uppercase letters 154 }, 155 "colliding names": { 156 &Block{ 157 Attributes: map[string]*Attribute{ 158 "foo": &Attribute{ 159 Type: cty.String, 160 Optional: true, 161 }, 162 }, 163 BlockTypes: map[string]*NestedBlock{ 164 "foo": &NestedBlock{ 165 Nesting: NestingSingle, 166 }, 167 }, 168 }, 169 1, // "foo" is defined as both attribute and block type 170 }, 171 "nested block with badness": { 172 &Block{ 173 BlockTypes: map[string]*NestedBlock{ 174 "bad": &NestedBlock{ 175 Nesting: NestingSingle, 176 Block: Block{ 177 Attributes: map[string]*Attribute{ 178 "nested_bad": &Attribute{ 179 Type: cty.String, 180 Required: true, 181 Optional: true, 182 }, 183 }, 184 }, 185 }, 186 }, 187 }, 188 1, // nested_bad is both required and optional 189 }, 190 "nil": { 191 nil, 192 1, // block is nil 193 }, 194 "nil attr": { 195 &Block{ 196 Attributes: map[string]*Attribute{ 197 "bad": nil, 198 }, 199 }, 200 1, // attribute schema is nil 201 }, 202 "nil block type": { 203 &Block{ 204 BlockTypes: map[string]*NestedBlock{ 205 "bad": nil, 206 }, 207 }, 208 1, // block schema is nil 209 }, 210 } 211 212 for name, test := range tests { 213 t.Run(name, func(t *testing.T) { 214 errs := multierrorErrors(test.Block.InternalValidate()) 215 if got, want := len(errs), test.ErrCount; got != want { 216 t.Errorf("wrong number of errors %d; want %d", got, want) 217 for _, err := range errs { 218 t.Logf("- %s", err.Error()) 219 } 220 } 221 }) 222 } 223 } 224 225 func multierrorErrors(err error) []error { 226 // A function like this should really be part of the multierror package... 227 228 if err == nil { 229 return nil 230 } 231 232 switch terr := err.(type) { 233 case *multierror.Error: 234 return terr.Errors 235 default: 236 return []error{err} 237 } 238 }