From c030148259c60eac9243bee7491673fa7d553246 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 2 Mar 2015 21:06:14 -0800 Subject: [PATCH 1/2] helper/schema: allow pointer values to ResourceData.Set --- helper/schema/resource_data.go | 12 +++++ helper/schema/resource_data_test.go | 70 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/helper/schema/resource_data.go b/helper/schema/resource_data.go index 615038d2d..119c37907 100644 --- a/helper/schema/resource_data.go +++ b/helper/schema/resource_data.go @@ -137,6 +137,18 @@ func (d *ResourceData) Partial(on bool) { // will be returned. func (d *ResourceData) Set(key string, value interface{}) error { d.once.Do(d.init) + + // If the value is a pointer to a non-struct, get its value and + // use that. This allows Set to take a pointer to primitives to + // simplify the interface. + reflectVal := reflect.ValueOf(value) + if reflectVal.Kind() == reflect.Ptr { + reflectVal = reflect.Indirect(reflectVal) + if reflectVal.Kind() != reflect.Struct { + value = reflectVal.Interface() + } + } + return d.setWriter.WriteField(strings.Split(key, "."), value) } diff --git a/helper/schema/resource_data_test.go b/helper/schema/resource_data_test.go index 90aa6a9d9..92c4bfd85 100644 --- a/helper/schema/resource_data_test.go +++ b/helper/schema/resource_data_test.go @@ -1588,6 +1588,72 @@ func TestResourceDataSet(t *testing.T) { GetKey: "ratios", GetValue: []interface{}{1.0, 2.2, 5.5}, }, + + // #13: Basic pointer + { + Schema: map[string]*Schema{ + "availability_zone": &Schema{ + Type: TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + + State: nil, + + Diff: nil, + + Key: "availability_zone", + Value: testPtrTo("foo"), + + GetKey: "availability_zone", + GetValue: "foo", + }, + + // #14: Basic nil value + { + Schema: map[string]*Schema{ + "availability_zone": &Schema{ + Type: TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + + State: nil, + + Diff: nil, + + Key: "availability_zone", + Value: testPtrTo(nil), + + GetKey: "availability_zone", + GetValue: "", + }, + + // #15: Basic nil pointer + { + Schema: map[string]*Schema{ + "availability_zone": &Schema{ + Type: TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + + State: nil, + + Diff: nil, + + Key: "availability_zone", + Value: nil, + + GetKey: "availability_zone", + GetValue: "", + }, } for i, tc := range cases { @@ -2788,3 +2854,7 @@ func TestResourceDataSetId_override(t *testing.T) { t.Fatalf("bad: %#v", actual) } } + +func testPtrTo(raw interface{}) interface{} { + return &raw +} From 58a8776c4173563a05a4c32f6ea9deeed6d0cb10 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 2 Mar 2015 23:37:43 -0800 Subject: [PATCH 2/2] helper/schema: test real nil pointer to ResourceData.Set --- helper/schema/resource_data.go | 13 ++++++++++--- helper/schema/resource_data_test.go | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/helper/schema/resource_data.go b/helper/schema/resource_data.go index 119c37907..af48481d3 100644 --- a/helper/schema/resource_data.go +++ b/helper/schema/resource_data.go @@ -143,9 +143,16 @@ func (d *ResourceData) Set(key string, value interface{}) error { // simplify the interface. reflectVal := reflect.ValueOf(value) if reflectVal.Kind() == reflect.Ptr { - reflectVal = reflect.Indirect(reflectVal) - if reflectVal.Kind() != reflect.Struct { - value = reflectVal.Interface() + if reflectVal.IsNil() { + // If the pointer is nil, then the value is just nil + value = nil + } else { + // Otherwise, we dereference the pointer as long as its not + // a pointer to a struct, since struct pointers are allowed. + reflectVal = reflect.Indirect(reflectVal) + if reflectVal.Kind() != reflect.Struct { + value = reflectVal.Interface() + } } } diff --git a/helper/schema/resource_data_test.go b/helper/schema/resource_data_test.go index 92c4bfd85..d73a33833 100644 --- a/helper/schema/resource_data_test.go +++ b/helper/schema/resource_data_test.go @@ -1178,6 +1178,8 @@ func TestResourceDataHasChange(t *testing.T) { } func TestResourceDataSet(t *testing.T) { + var testNilPtr *string + cases := []struct { Schema map[string]*Schema State *terraform.InstanceState @@ -1649,7 +1651,7 @@ func TestResourceDataSet(t *testing.T) { Diff: nil, Key: "availability_zone", - Value: nil, + Value: testNilPtr, GetKey: "availability_zone", GetValue: "",