Skip to content

Commit f007577

Browse files
author
Paddy Carver
committed
Write good error messages.
Add good error messages to our type conversion code that will make it easier to diagnose where things are going wrong. Also, make sure that all typecasts are conditional, to return pretty errors instead of panics.
1 parent 607334f commit f007577

File tree

3 files changed

+96
-56
lines changed

3 files changed

+96
-56
lines changed

tfprotov5/internal/fromproto/types.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ func typeFromValue(in interface{}) (tftypes.Type, error) {
114114
return tftypes.Bool, nil
115115
case []interface{}:
116116
var types []tftypes.Type
117-
for _, val := range v {
117+
for pos, val := range v {
118118
typ, err := typeFromValue(val)
119119
if err != nil {
120-
// TODO: return error
120+
return nil, fmt.Errorf("error choosing default tftypes.Type for value %d of type %T: %w", pos, in, err)
121121
}
122122
types = append(types, typ)
123123
}
@@ -129,7 +129,7 @@ func typeFromValue(in interface{}) (tftypes.Type, error) {
129129
for k, val := range v {
130130
typ, err := typeFromValue(val)
131131
if err != nil {
132-
// TODO: return error
132+
return nil, fmt.Errorf("error choosing default tftypes.Type for attribute %q of type %T: %w", k, in, err)
133133
}
134134
types[k] = typ
135135
}

tfprotov5/tftypes/raw_value.go

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ func (r RawValue) Unmarshal(dst interface{}) error {
145145
case *[]interface{}:
146146
*(dst.(*[]interface{})) = r.Value.([]interface{})
147147
default:
148-
// TODO: return error
148+
return fmt.Errorf("can't unmarshal %s into %T", r.Type, dst)
149149
}
150150
case r.Type.Is(Set{}):
151151
// this can't be a value with the cty information included; we
@@ -155,7 +155,7 @@ func (r RawValue) Unmarshal(dst interface{}) error {
155155
case *[]interface{}:
156156
*(dst.(*[]interface{})) = r.Value.([]interface{})
157157
default:
158-
// TODO: return error
158+
return fmt.Errorf("can't unmarshal %s into %T", r.Type, dst)
159159
}
160160
case r.Type.Is(Tuple{}):
161161
// this could be an actual, honest-to-goodness Tuple, or it
@@ -168,23 +168,33 @@ func (r RawValue) Unmarshal(dst interface{}) error {
168168
case *[]interface{}:
169169
*(dst.(*[]interface{})) = r.Value.([]interface{})
170170
case *RawValue:
171-
val := r.Value.([]interface{})
171+
val, ok := r.Value.([]interface{})
172+
if !ok {
173+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. Intermediary type is %T, not %T", r.Value, []interface{}{})
174+
}
172175
if len(val) != 2 {
173-
// TODO: return error
176+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. Expected %d items, got %d.", 2, len(val))
174177
}
175178
var typ interface{}
176-
err := json.Unmarshal([]byte(val[0].(string)), &typ)
179+
str, ok := val[0].(string)
180+
if !ok {
181+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. Expected %T for first value, got %T", str, val[0])
182+
}
183+
err := json.Unmarshal([]byte(str), &typ)
177184
if err != nil {
178-
// TODO: return error
185+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. First value %q isn't valid JSON: %w", str, err)
179186
}
180187
parsedType, err := parseType(typ)
188+
if err != nil {
189+
return fmt.Errorf("error parsing type: %w", err)
190+
}
181191
rv, err := rawValueFromComplexType(parsedType, val[1])
182192
if err != nil {
183193
return err
184194
}
185195
*(dst.(*RawValue)) = rv
186196
default:
187-
// TODO: return error
197+
return fmt.Errorf("can't unmarshal %s into %T", r.Type, dst)
188198
}
189199
case r.Type.Is(Map{}):
190200
// this can't be a value with the cty information included; we
@@ -194,7 +204,7 @@ func (r RawValue) Unmarshal(dst interface{}) error {
194204
case *map[string]interface{}:
195205
*(dst.(*map[string]interface{})) = r.Value.(map[string]interface{})
196206
default:
197-
// TODO: return error
207+
return fmt.Errorf("can't unmarshal %s into %T", r.Type, dst)
198208
}
199209
case r.Type.Is(Object{}):
200210
// this could be an actual, honest-to-goodness Object, or it
@@ -207,23 +217,38 @@ func (r RawValue) Unmarshal(dst interface{}) error {
207217
case *map[string]interface{}:
208218
*(dst.(*map[string]interface{})) = r.Value.(map[string]interface{})
209219
case *RawValue:
210-
val := r.Value.(map[string]interface{})
220+
val, ok := r.Value.(map[string]interface{})
221+
if !ok {
222+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. Intermediary type is %T, not %T", r.Value, map[string]interface{}{})
223+
}
211224
var typ interface{}
212-
err := json.Unmarshal([]byte(val["type"].(string)), &typ)
225+
typeInterface, ok := val["type"]
226+
if !ok {
227+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. No \"type\" key found.")
228+
}
229+
typeStr, ok := typeInterface.(string)
230+
if !ok {
231+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. Expected %T for \"type\" key, got %T", typeStr, typeInterface)
232+
}
233+
err := json.Unmarshal([]byte(typeStr), &typ)
213234
if err != nil {
214-
// TODO: return error
235+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; invalid type information. \"type\" key's value %q isn't valid JSON: %w", typeStr, err)
215236
}
216237
parsedType, err := parseType(typ)
217238
if err != nil {
218-
// TODO: return error
239+
return fmt.Errorf("error parsing type: %w", err)
219240
}
220-
rv, err := rawValueFromComplexType(parsedType, val["value"])
241+
valueInterface, ok := val["value"]
242+
if !ok {
243+
return fmt.Errorf("can't unmarshal into tftypes.RawValue; no \"value\" key found")
244+
}
245+
rv, err := rawValueFromComplexType(parsedType, valueInterface)
221246
if err != nil {
222-
return err
247+
return fmt.Errorf("error parsing value: %w", err)
223248
}
224249
*(dst.(*RawValue)) = rv
225250
default:
226-
// TODO: return error
251+
return fmt.Errorf("can't unmarshal %s into %T", r.Type, dst)
227252
}
228253
default:
229254
return ErrUnhandledType(r.Type.String())
@@ -246,13 +271,17 @@ func rawValueFromComplexType(typ Type, val interface{}) (RawValue, error) {
246271
} else if s, ok := typ.(Set); ok {
247272
elementType = s.ElementType
248273
} else {
249-
// TODO: throw an error, this should never happen
274+
return RawValue{}, fmt.Errorf("type is %T, not %T or %T. This shouldn't be possible", typ, Set{}, List{})
250275
}
251-
values := make([]RawValue, len(val.([]interface{})))
252-
for pos, v := range val.([]interface{}) {
276+
interfaceValues, ok := val.([]interface{})
277+
if !ok {
278+
return RawValue{}, fmt.Errorf("unexpected intermediary type %T, expected %T", val, interfaceValues)
279+
}
280+
values := make([]RawValue, len(interfaceValues))
281+
for pos, v := range interfaceValues {
253282
value, err := rawValueFromComplexType(elementType, v)
254283
if err != nil {
255-
// TODO: return error
284+
return RawValue{}, fmt.Errorf("error converting element %d of %T to a tftypes.RawValue: %w", pos, typ, err)
256285
}
257286
values[pos] = value
258287
}
@@ -262,14 +291,18 @@ func rawValueFromComplexType(typ Type, val interface{}) (RawValue, error) {
262291
}, nil
263292
case typ.Is(Tuple{}):
264293
elementTypes := typ.(Tuple).ElementTypes
265-
if len(elementTypes) != len(val.([]interface{})) {
266-
// TODO: return error
294+
interfaceValues, ok := val.([]interface{})
295+
if !ok {
296+
return RawValue{}, fmt.Errorf("unexpected intermediary type %T, expected %T", val, interfaceValues)
297+
}
298+
if len(elementTypes) != len(interfaceValues) {
299+
return RawValue{}, fmt.Errorf("expected %d element types in %T, got %d", len(interfaceValues), typ, len(elementTypes))
267300
}
268-
elements := make([]RawValue, len(val.([]interface{})))
269-
for pos, v := range val.([]interface{}) {
301+
elements := make([]RawValue, len(interfaceValues))
302+
for pos, v := range interfaceValues {
270303
value, err := rawValueFromComplexType(elementTypes[pos], v)
271304
if err != nil {
272-
// TODO: return error
305+
return RawValue{}, fmt.Errorf("error converting element %d of %T to a tftypes.RawValue: %w", pos, typ, err)
273306
}
274307
elements[pos] = value
275308
}
@@ -279,11 +312,15 @@ func rawValueFromComplexType(typ Type, val interface{}) (RawValue, error) {
279312
}, nil
280313
case typ.Is(Map{}):
281314
attributeType := typ.(Map).AttributeType
282-
values := make(map[string]RawValue, len(val.(map[string]interface{})))
283-
for key, v := range val.(map[string]interface{}) {
315+
msiValues, ok := val.(map[string]interface{})
316+
if !ok {
317+
return RawValue{}, fmt.Errorf("unexpected intermediary type %T, expected %T", val, msiValues)
318+
}
319+
values := make(map[string]RawValue, len(msiValues))
320+
for key, v := range msiValues {
284321
value, err := rawValueFromComplexType(attributeType, v)
285322
if err != nil {
286-
// TODO: return error
323+
return RawValue{}, fmt.Errorf("error converting attribute %q of %T to a tftypes.RawValue: %w", key, typ, err)
287324
}
288325
values[key] = value
289326
}
@@ -293,18 +330,22 @@ func rawValueFromComplexType(typ Type, val interface{}) (RawValue, error) {
293330
}, nil
294331
case typ.Is(Object{}):
295332
attributeTypes := typ.(Object).AttributeTypes
296-
values := make(map[string]RawValue, len(val.(map[string]interface{})))
297-
if len(attributeTypes) != len(val.(map[string]interface{})) {
298-
// TODO: return error
333+
msiValues, ok := val.(map[string]interface{})
334+
if !ok {
335+
return RawValue{}, fmt.Errorf("unexpected intermediary type %T, expected %T", val, msiValues)
336+
}
337+
values := make(map[string]RawValue, len(msiValues))
338+
if len(attributeTypes) != len(msiValues) {
339+
return RawValue{}, fmt.Errorf("expected %d attribute types in %T, got %d", len(msiValues), typ, len(attributeTypes))
299340
}
300-
for key, v := range val.(map[string]interface{}) {
341+
for key, v := range msiValues {
301342
attributeType, ok := attributeTypes[key]
302343
if !ok {
303-
// TODO: return error
344+
return RawValue{}, fmt.Errorf("expected type for attribute %q of %T, but didn't get one", key, typ)
304345
}
305346
value, err := rawValueFromComplexType(attributeType, v)
306347
if err != nil {
307-
// TODO: return error
348+
return RawValue{}, fmt.Errorf("error converting attribute %q of %T to a tftypes.RawValue: %w", key, typ, err)
308349
}
309350
values[key] = value
310351
}
@@ -313,6 +354,5 @@ func rawValueFromComplexType(typ Type, val interface{}) (RawValue, error) {
313354
Value: values,
314355
}, nil
315356
}
316-
// TODO: return error
317-
return RawValue{}, nil
357+
return RawValue{}, fmt.Errorf("unrecognized type %T can't be converted to a tftypes.RawValue", typ)
318358
}

tfprotov5/tftypes/type.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package tftypes
22

3+
import "fmt"
4+
35
type Type interface {
46
Is(Type) bool
57
String() string
@@ -19,47 +21,47 @@ func parseType(in interface{}) (Type, error) {
1921
case "bool":
2022
return Bool, nil
2123
default:
22-
// TODO: return an error
24+
return nil, fmt.Errorf("unknown type %q", v)
2325
}
2426
case []interface{}:
2527
// sets, lists, tuples, maps, and objects are
2628
// represented as slices, recursive iterations of this
2729
// type/value syntax
2830
if len(v) < 1 {
29-
// TODO: return an error
31+
return nil, fmt.Errorf("improperly formatted type information; need at least %d elements, got %d", 1, len(v))
3032
}
3133
switch v[0] {
3234
case "set":
3335
if len(v) != 2 {
34-
// TODO: return an error
36+
return nil, fmt.Errorf("improperly formatted type information; need %d elements, got %d", 2, len(v))
3537
}
3638
subType, err := parseType(v[1])
3739
if err != nil {
38-
// TODO: return an error
40+
return nil, fmt.Errorf("error parsing element type for tftypes.Set: %w", err)
3941
}
4042
return Set{
4143
ElementType: subType,
4244
}, nil
4345
case "list":
4446
if len(v) != 2 {
45-
// TODO: return an error
47+
return nil, fmt.Errorf("improperly formatted type information; need %d elements, got %d", 2, len(v))
4648
}
4749
subType, err := parseType(v[1])
4850
if err != nil {
49-
// TODO: return an error
51+
return nil, fmt.Errorf("error parsing element type for tftypes.List: %w", err)
5052
}
5153
return List{
5254
ElementType: subType,
5355
}, nil
5456
case "tuple":
5557
if len(v) < 2 {
56-
// TODO: return an error
58+
return nil, fmt.Errorf("improperly formatted type information; need at least %d elements, got %d", 2, len(v))
5759
}
5860
var types []Type
59-
for _, typ := range v {
61+
for pos, typ := range v {
6062
subType, err := parseType(typ)
6163
if err != nil {
62-
// TODO: return an error
64+
return nil, fmt.Errorf("error parsing type of element %d for tftypes.Tuple: %w", pos, err)
6365
}
6466
types = append(types, subType)
6567
}
@@ -68,36 +70,34 @@ func parseType(in interface{}) (Type, error) {
6870
}, nil
6971
case "map":
7072
if len(v) != 2 {
71-
// TODO: return an error
73+
return nil, fmt.Errorf("improperly formatted type information; need %d elements, got %d", 2, len(v))
7274
}
7375
subType, err := parseType(v[1])
7476
if err != nil {
75-
// TODO: return an error
77+
return nil, fmt.Errorf("error parsing attribute type for tftypes.Map: %w", err)
7678
}
7779
return Map{
7880
AttributeType: subType,
7981
}, nil
8082
case "object":
81-
if len(v) < 2 {
82-
// TODO: return an error
83+
if len(v) != 2 {
84+
return nil, fmt.Errorf("improperly formatted type information; need %d elements, got %d", 2, len(v))
8385
}
8486
types := map[string]Type{}
8587
valTypes := v[1].(map[string]interface{})
8688
for key, typ := range valTypes {
8789
subType, err := parseType(typ)
8890
if err != nil {
89-
// TODO: return an error
91+
return nil, fmt.Errorf("error parsing type of attribute %q for tftypes.Object: %w", key, err)
9092
}
9193
types[key] = subType
9294
}
9395
return Object{
9496
AttributeTypes: types,
9597
}, nil
9698
default:
97-
// TODO: return an error
98-
return nil, nil
99+
return nil, fmt.Errorf("unknown type %q", v[0])
99100
}
100101
}
101-
// TODO: return an error
102-
return nil, nil
102+
return nil, fmt.Errorf("unhandled intermediary type %T", in)
103103
}

0 commit comments

Comments
 (0)