From d8fbaa79248a92e5c3919a1c7e90f6e5b7c09c7e Mon Sep 17 00:00:00 2001 From: James Bardin Date: Thu, 9 Jun 2016 13:02:30 -0400 Subject: [PATCH 1/2] Serialization for hash panics on TypeMap The serializeCollectionMemberForHash helper can't be called for the MapType values, because MapType doesn't have a schema.Elem. Instead, we can write the key/value pairs directly to the buffer. This still doesn't allow for nested maps or lists, but we need to define that use case before committing to it here. --- helper/schema/serialize.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/helper/schema/serialize.go b/helper/schema/serialize.go index 78f5bfbd6..3eb2d0075 100644 --- a/helper/schema/serialize.go +++ b/helper/schema/serialize.go @@ -2,6 +2,7 @@ package schema import ( "bytes" + "fmt" "sort" "strconv" ) @@ -33,6 +34,7 @@ func SerializeValueForHash(buf *bytes.Buffer, val interface{}, schema *Schema) { } buf.WriteRune(')') case TypeMap: + m := val.(map[string]interface{}) var keys []string for k := range m { @@ -42,9 +44,24 @@ func SerializeValueForHash(buf *bytes.Buffer, val interface{}, schema *Schema) { buf.WriteRune('[') for _, k := range keys { innerVal := m[k] + if innerVal == nil { + continue + } buf.WriteString(k) buf.WriteRune(':') - serializeCollectionMemberForHash(buf, innerVal, schema.Elem) + + switch innerVal := innerVal.(type) { + case int: + buf.WriteString(strconv.Itoa(innerVal)) + case float64: + buf.WriteString(strconv.FormatFloat(innerVal, 'g', -1, 64)) + case string: + buf.WriteString(innerVal) + default: + panic(fmt.Sprintf("unknown value type in TypeMap %T", innerVal)) + } + + buf.WriteRune(';') } buf.WriteRune(']') case TypeSet: @@ -100,6 +117,6 @@ func serializeCollectionMemberForHash(buf *bytes.Buffer, val interface{}, elem i SerializeResourceForHash(buf, val, tElem) buf.WriteString(">;") default: - panic("invalid element type") + panic(fmt.Sprintf("invalid element type: %T", tElem)) } } From bab031aac5a4a7da1af3566702f177031d1a1d3c Mon Sep 17 00:00:00 2001 From: James Bardin Date: Thu, 9 Jun 2016 16:00:33 -0400 Subject: [PATCH 2/2] Add test for TypeMap in a Schema --- helper/schema/serialize_test.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/helper/schema/serialize_test.go b/helper/schema/serialize_test.go index 7fe9e20bf..55afb1528 100644 --- a/helper/schema/serialize_test.go +++ b/helper/schema/serialize_test.go @@ -13,7 +13,6 @@ func TestSerializeForHash(t *testing.T) { } tests := []testCase{ - testCase{ Schema: &Schema{ Type: TypeInt, @@ -193,6 +192,31 @@ func TestSerializeForHash(t *testing.T) { }, Expected: "green:1;name:my-fun-database;size:12;", }, + + // test TypeMap nested in Schema: GH-7091 + testCase{ + Schema: &Resource{ + Schema: map[string]*Schema{ + "outer": &Schema{ + Type: TypeSet, + Required: true, + Elem: &Schema{ + Type: TypeMap, + Optional: true, + }, + }, + }, + }, + Value: map[string]interface{}{ + "outer": NewSet(func(i interface{}) int { return 42 }, []interface{}{ + map[string]interface{}{ + "foo": "bar", + "baz": "foo", + }, + }), + }, + Expected: "outer:{[baz:foo;foo:bar;];};", + }, } for _, test := range tests {