diff --git a/helper/structure/expand_json.go b/helper/structure/expand_json.go new file mode 100644 index 000000000..b3eb90fdf --- /dev/null +++ b/helper/structure/expand_json.go @@ -0,0 +1,11 @@ +package structure + +import "encoding/json" + +func ExpandJsonFromString(jsonString string) (map[string]interface{}, error) { + var result map[string]interface{} + + err := json.Unmarshal([]byte(jsonString), &result) + + return result, err +} diff --git a/helper/structure/expand_json_test.go b/helper/structure/expand_json_test.go new file mode 100644 index 000000000..431cd19e0 --- /dev/null +++ b/helper/structure/expand_json_test.go @@ -0,0 +1,48 @@ +package structure + +import ( + "reflect" + "testing" +) + +func TestExpandJson_emptyString(t *testing.T) { + _, err := ExpandJsonFromString("") + if err == nil { + t.Fatal("Expected to throw an error while Expanding JSON") + } +} + +func TestExpandJson_singleItem(t *testing.T) { + input := `{ + "foo": "bar" + }` + expected := make(map[string]interface{}, 1) + expected["foo"] = "bar" + actual, err := ExpandJsonFromString(input) + if err != nil { + t.Fatalf("Expected not to throw an error while Expanding JSON, but got: %s", err) + } + + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("Got:\n\n%+v\n\nExpected:\n\n%+v\n", actual, expected) + } +} + +func TestExpandJson_multipleItems(t *testing.T) { + input := `{ + "foo": "bar", + "hello": "world" + }` + expected := make(map[string]interface{}, 1) + expected["foo"] = "bar" + expected["hello"] = "world" + + actual, err := ExpandJsonFromString(input) + if err != nil { + t.Fatalf("Expected not to throw an error while Expanding JSON, but got: %s", err) + } + + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("Got:\n\n%+v\n\nExpected:\n\n%+v\n", actual, expected) + } +} diff --git a/helper/structure/flatten_json.go b/helper/structure/flatten_json.go new file mode 100644 index 000000000..578ad2ead --- /dev/null +++ b/helper/structure/flatten_json.go @@ -0,0 +1,16 @@ +package structure + +import "encoding/json" + +func FlattenJsonToString(input map[string]interface{}) (string, error) { + if len(input) == 0 { + return "", nil + } + + result, err := json.Marshal(input) + if err != nil { + return "", err + } + + return string(result), nil +} diff --git a/helper/structure/flatten_json_test.go b/helper/structure/flatten_json_test.go new file mode 100644 index 000000000..fe131a9dc --- /dev/null +++ b/helper/structure/flatten_json_test.go @@ -0,0 +1,47 @@ +package structure + +import ( + "testing" +) + +func TestFlattenJson_empty(t *testing.T) { + input := make(map[string]interface{}, 0) + expected := "" + actual, err := FlattenJsonToString(input) + if err != nil { + t.Fatalf("Expected not to throw an error while Flattening JSON, but got: %s", err) + } + + if expected != actual { + t.Fatalf("Got: `%+v`. Expected: `%+v`", actual, expected) + } +} + +func TestFlattenJson_singleItem(t *testing.T) { + input := make(map[string]interface{}, 1) + input["foo"] = "bar" + expected := `{"foo":"bar"}` + actual, err := FlattenJsonToString(input) + if err != nil { + t.Fatalf("Expected not to throw an error while Flattening JSON, but got: %s", err) + } + + if expected != actual { + t.Fatalf("Got: `%+v`. Expected: `%+v`", actual, expected) + } +} + +func TestFlattenJson_multipleItems(t *testing.T) { + input := make(map[string]interface{}, 1) + input["foo"] = "bar" + input["bar"] = "foo" + expected := `{"bar":"foo","foo":"bar"}` + actual, err := FlattenJsonToString(input) + if err != nil { + t.Fatalf("Expected not to throw an error while Flattening JSON, but got: %s", err) + } + + if expected != actual { + t.Fatalf("Got: `%+v`. Expected: `%+v`", actual, expected) + } +} diff --git a/helper/structure/normalize_json.go b/helper/structure/normalize_json.go new file mode 100644 index 000000000..3256b476d --- /dev/null +++ b/helper/structure/normalize_json.go @@ -0,0 +1,24 @@ +package structure + +import "encoding/json" + +// Takes a value containing JSON string and passes it through +// the JSON parser to normalize it, returns either a parsing +// error or normalized JSON string. +func NormalizeJsonString(jsonString interface{}) (string, error) { + var j interface{} + + if jsonString == nil || jsonString.(string) == "" { + return "", nil + } + + s := jsonString.(string) + + err := json.Unmarshal([]byte(s), &j) + if err != nil { + return s, err + } + + bytes, _ := json.Marshal(j) + return string(bytes[:]), nil +} diff --git a/helper/structure/structure_test.go b/helper/structure/normalize_json_test.go similarity index 100% rename from helper/structure/structure_test.go rename to helper/structure/normalize_json_test.go diff --git a/helper/structure/structure.go b/helper/structure/structure.go deleted file mode 100644 index 6ad12de62..000000000 --- a/helper/structure/structure.go +++ /dev/null @@ -1,65 +0,0 @@ -package structure - -import ( - "encoding/json" - "reflect" - - "github.com/hashicorp/terraform/helper/schema" -) - -// Takes a value containing JSON string and passes it through -// the JSON parser to normalize it, returns either a parsing -// error or normalized JSON string. -func NormalizeJsonString(jsonString interface{}) (string, error) { - var j interface{} - - if jsonString == nil || jsonString.(string) == "" { - return "", nil - } - - s := jsonString.(string) - - err := json.Unmarshal([]byte(s), &j) - if err != nil { - return s, err - } - - bytes, _ := json.Marshal(j) - return string(bytes[:]), nil -} - -func ExpandJsonFromString(jsonString string) (map[string]interface{}, error) { - var result map[string]interface{} - - err := json.Unmarshal([]byte(jsonString), &result) - - return result, err -} - -func FlattenJsonToString(input map[string]interface{}) (string, error) { - - if len(input) == 0 { - return "", nil - } - - result, err := json.Marshal(input) - if err != nil { - return "", err - } - - return string(result), nil -} - -func SuppressJsonDiff(k, old, new string, d *schema.ResourceData) bool { - oldMap, err := ExpandJsonFromString(old) - if err != nil { - return false - } - - newMap, err := ExpandJsonFromString(new) - if err != nil { - return false - } - - return reflect.DeepEqual(oldMap, newMap) -} diff --git a/helper/structure/suppress_json_diff.go b/helper/structure/suppress_json_diff.go new file mode 100644 index 000000000..46f794a71 --- /dev/null +++ b/helper/structure/suppress_json_diff.go @@ -0,0 +1,21 @@ +package structure + +import ( + "reflect" + + "github.com/hashicorp/terraform/helper/schema" +) + +func SuppressJsonDiff(k, old, new string, d *schema.ResourceData) bool { + oldMap, err := ExpandJsonFromString(old) + if err != nil { + return false + } + + newMap, err := ExpandJsonFromString(new) + if err != nil { + return false + } + + return reflect.DeepEqual(oldMap, newMap) +} diff --git a/helper/structure/suppress_json_diff_test.go b/helper/structure/suppress_json_diff_test.go new file mode 100644 index 000000000..c017981bc --- /dev/null +++ b/helper/structure/suppress_json_diff_test.go @@ -0,0 +1,51 @@ +package structure + +import ( + "testing" +) + +func TestSuppressJsonDiff_same(t *testing.T) { + original := `{ "enabled": true }` + new := `{ "enabled": true }` + expected := true + + actual := SuppressJsonDiff("test", original, new, nil) + if actual != expected { + t.Fatal("[ERROR] Identical JSON values shouldn't cause a diff") + } +} + +func TestSuppressJsonDiff_sameWithWhitespace(t *testing.T) { + original := `{ + "enabled": true + }` + new := `{ "enabled": true }` + expected := true + + actual := SuppressJsonDiff("test", original, new, nil) + if actual != expected { + t.Fatal("[ERROR] Identical JSON values shouldn't cause a diff") + } +} + +func TestSuppressJsonDiff_differentValue(t *testing.T) { + original := `{ "enabled": true }` + new := `{ "enabled": false }` + expected := false + + actual := SuppressJsonDiff("test", original, new, nil) + if actual != expected { + t.Fatal("[ERROR] Different JSON values should cause a diff") + } +} + +func TestSuppressJsonDiff_newValue(t *testing.T) { + original := `{ "enabled": true }` + new := `{ "enabled": false, "world": "round" }` + expected := false + + actual := SuppressJsonDiff("test", original, new, nil) + if actual != expected { + t.Fatal("[ERROR] Different JSON values should cause a diff") + } +}