Skip to content

Commit 7e96a41

Browse files
author
Paddy
authored
Implement unit tests (#32)
* Test marshaling msgpack. Test that the bytes produced from msgpack marshaling match the bytes cty produces for equivalent msgpack marshaling. This hardcodes the bytes so we don't have a dependency on cty. * Fix dynamic tests. * Make tests parallel. * Test behavior of Value.As. Add tests that assert we get the results we expect for given inputs of the tftypes.Value.As method. * Add tests for encoding and decoding types with JSON. Add a test that will decode JSON from a hard-coded string and assert that the type that was parsed is correct, then will encode the type and ensure that the generated JSON is correct. * Test Value.IsKnown() and Value.IsFullyKnown() * Test WalkAttributePath. * Move msgpack tests to tfprotov5, implement parsing. Move our msgpack encoding tests to the tfprotov5 package, which led to some unfortunate exports needing to be added to the tftypes package, mostly the ValueComparer function. But this lets us quickly and easily reuse those tests in the tfprotov5 package to test that our parsing of msgpack values is correct. We now mimic the cty tests incredibly closely. * Add tests for parsing JSON from DynamicValues.
1 parent 958fd96 commit 7e96a41

12 files changed

+1716
-23
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ go 1.14
44

55
require (
66
github.com/golang/protobuf v1.4.2
7+
github.com/google/go-cmp v0.5.2
78
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd
89
github.com/hashicorp/go-plugin v1.3.0
910
github.com/kr/pretty v0.1.0 // indirect
11+
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce
1012
github.com/vmihailenco/msgpack v4.0.4+incompatible
1113
golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
1214
google.golang.org/appengine v1.6.5 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
2828
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
2929
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
3030
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
31+
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
32+
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
3133
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
3234
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
3335
github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8=
@@ -43,6 +45,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
4345
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
4446
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
4547
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
48+
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758=
49+
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs=
4650
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
4751
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
4852
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

tfprotov5/dynamic_value.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ var ErrUnknownDynamicValueType = errors.New("DynamicValue had no JSON or msgpack
2727
// Type of the Value, but it can also be the DynamicPseudoType.
2828
func NewDynamicValue(t tftypes.Type, v tftypes.Value) (DynamicValue, error) {
2929
b, err := v.MarshalMsgPack(t) //nolint:staticcheck
30-
//
31-
// Deprecated: this is not meant to be called by third-party code.
3230
if err != nil {
3331
return DynamicValue{}, err
3432
}

tfprotov5/dynamic_value_json.go

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package tfprotov5
33
import (
44
"bytes"
55
"encoding/json"
6+
"math/big"
7+
"strings"
68

79
"github.com/hashicorp/terraform-plugin-go/tfprotov5/tftypes"
810
)
@@ -63,8 +65,10 @@ func jsonUnmarshalString(buf []byte, typ tftypes.Type, p tftypes.AttributePath)
6365
case json.Number:
6466
return tftypes.NewValue(tftypes.String, string(v)), nil
6567
case bool:
66-
// TODO: convert boolean to a string
67-
// not really sure why, but... compatibility!
68+
if v {
69+
return tftypes.NewValue(tftypes.String, "true"), nil
70+
}
71+
return tftypes.NewValue(tftypes.String, "false"), nil
6872
}
6973
return tftypes.Value{}, p.NewErrorf("unsupported type %T sent as %s", tok, tftypes.String)
7074
}
@@ -76,12 +80,21 @@ func jsonUnmarshalNumber(buf []byte, typ tftypes.Type, p tftypes.AttributePath)
7680
if err != nil {
7781
return tftypes.Value{}, p.NewErrorf("error reading token: %w", err)
7882
}
79-
numTok, ok := tok.(json.Number)
80-
if !ok {
81-
return tftypes.Value{}, p.NewErrorf("unsupported type %T sent as %s", tok, tftypes.Number)
83+
switch numTok := tok.(type) {
84+
case json.Number:
85+
f, _, err := big.ParseFloat(string(numTok), 10, 512, big.ToNearestEven)
86+
if err != nil {
87+
return tftypes.Value{}, p.NewErrorf("error parsing number: %w", err)
88+
}
89+
return tftypes.NewValue(typ, f), nil
90+
case string:
91+
f, _, err := big.ParseFloat(string(numTok), 10, 512, big.ToNearestEven)
92+
if err != nil {
93+
return tftypes.Value{}, p.NewErrorf("error parsing number: %w", err)
94+
}
95+
return tftypes.NewValue(typ, f), nil
8296
}
83-
// TODO: convert numTok to big.Float
84-
return tftypes.NewValue(typ, numTok), nil
97+
return tftypes.Value{}, p.NewErrorf("unsupported type %T sent as %s", tok, tftypes.Number)
8598
}
8699

87100
func jsonUnmarshalBool(buf []byte, typ tftypes.Type, p tftypes.AttributePath) (tftypes.Value, error) {
@@ -94,7 +107,25 @@ func jsonUnmarshalBool(buf []byte, typ tftypes.Type, p tftypes.AttributePath) (t
94107
case bool:
95108
return tftypes.NewValue(tftypes.Bool, v), nil
96109
case string:
97-
// TODO: convert string to boolean
110+
switch v {
111+
case "true", "1":
112+
return tftypes.NewValue(tftypes.Bool, true), nil
113+
case "false", "0":
114+
return tftypes.NewValue(tftypes.Bool, false), nil
115+
}
116+
switch strings.ToLower(string(v)) {
117+
case "true":
118+
return tftypes.Value{}, p.NewErrorf("to convert from string, use lowercase \"true\"")
119+
case "false":
120+
return tftypes.Value{}, p.NewErrorf("to convert from string, use lowercase \"false\"")
121+
}
122+
case json.Number:
123+
switch v {
124+
case "1":
125+
return tftypes.NewValue(tftypes.Bool, true), nil
126+
case "0":
127+
return tftypes.NewValue(tftypes.Bool, false), nil
128+
}
98129
}
99130
return tftypes.Value{}, p.NewErrorf("unsupported type %T sent as %s", tok, tftypes.Bool)
100131
}
@@ -201,8 +232,16 @@ func jsonUnmarshalList(buf []byte, elementType tftypes.Type, p tftypes.Attribute
201232
if tok != json.Delim(']') {
202233
return tftypes.Value{}, p.NewErrorf("invalid JSON, expected %q, got %q", json.Delim(']'), tok)
203234
}
235+
236+
elTyp := elementType
237+
if elTyp == tftypes.DynamicPseudoType {
238+
elTyp, err = tftypes.TypeFromElements(vals)
239+
if err != nil {
240+
return tftypes.Value{}, p.NewErrorf("invalid elements for list: %w", err)
241+
}
242+
}
204243
return tftypes.NewValue(tftypes.List{
205-
ElementType: elementType,
244+
ElementType: elTyp,
206245
}, vals), nil
207246
}
208247

@@ -250,8 +289,16 @@ func jsonUnmarshalSet(buf []byte, elementType tftypes.Type, p tftypes.AttributeP
250289
if tok != json.Delim(']') {
251290
return tftypes.Value{}, p.NewErrorf("invalid JSON, expected %q, got %q", json.Delim(']'), tok)
252291
}
292+
293+
elTyp := elementType
294+
if elTyp == tftypes.DynamicPseudoType {
295+
elTyp, err = tftypes.TypeFromElements(vals)
296+
if err != nil {
297+
return tftypes.Value{}, p.NewErrorf("invalid elements for list: %w", err)
298+
}
299+
}
253300
return tftypes.NewValue(tftypes.Set{
254-
ElementType: elementType,
301+
ElementType: elTyp,
255302
}, vals), nil
256303
}
257304

0 commit comments

Comments
 (0)