From d961fe384602034ce1a344d9492dea5ee3d65ba2 Mon Sep 17 00:00:00 2001 From: George Kozakjian Date: Thu, 1 Sep 2022 18:04:01 +0000 Subject: [PATCH] Add getEncodedJson and getEncodedEscapedJson functions (#1159) * Add getEncodedJson which takes a map and returns a JSON encoded string * Add getEncodedEscapedJson which takes a map and returns a JSON encoded, escaped string * Update unit tests --- internal/template/funcmap.go | 61 +++++++++++++++++++++------ internal/template/template_test.go | 66 ++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 13 deletions(-) diff --git a/internal/template/funcmap.go b/internal/template/funcmap.go index 39ed13a76..a803c049f 100644 --- a/internal/template/funcmap.go +++ b/internal/template/funcmap.go @@ -15,6 +15,7 @@ package template import ( + "encoding/json" "fmt" "regexp" "strings" @@ -24,19 +25,21 @@ import ( ) var funcMap = map[string]interface{}{ - "get": get, - "has": has, - "hcl": hcl, - "hclField": hclField, - "merge": merge, - "replace": replace, - "resourceName": resourceName, - "now": time.Now, - "trimSpace": strings.TrimSpace, - "regexReplaceAll": regexReplaceAll, - "makeSlice": makeSlice, - "schemaDescription": schemaDescription, - "substr": substr, + "get": get, + "has": has, + "hcl": hcl, + "hclField": hclField, + "merge": merge, + "replace": replace, + "resourceName": resourceName, + "now": time.Now, + "trimSpace": strings.TrimSpace, + "regexReplaceAll": regexReplaceAll, + "makeSlice": makeSlice, + "schemaDescription": schemaDescription, + "substr": substr, + "getEncodedJSON": getEncodedJSON, + "getEncodedEscapedJSON": getEncodedEscapedJSON, } // invalidIDRE defines the invalid characters not allowed in terraform resource names. @@ -173,3 +176,35 @@ func substr(s string, start int, length int) (string, error) { } return s[start : start+length], nil } + +// getEncodedJSON returns an encoded JSON string from a given map +func getEncodedJSON(m map[string]interface{}) (string, error) { + jsonStr, err := json.Marshal(m) + if err != nil { + return "", fmt.Errorf("JSON marshalling failed due to %w", err) + } + return string(jsonStr), nil +} + +// getEncodedEscapedJSON returns an encoded, escaped JSON string from a given map +func getEncodedEscapedJSON(m map[string]interface{}) (string, error) { + jsonStr, err := json.Marshal(m) + if err != nil { + return "", fmt.Errorf("JSON marshalling failed due to %w", err) + } + escapedJSONStr, err := jsonEscape(string(jsonStr)) + if err != nil { + return "", fmt.Errorf("JSON escaping failed due to %w", err) + } + return escapedJSONStr, nil +} + +// jsonEscape return an escaped JSON string +func jsonEscape(i string) (string, error) { + jsonStr, err := json.Marshal(i) + if err != nil { + return "", fmt.Errorf("JSON marshalling failed due to %w", err) + } + str := string(jsonStr) + return str[1 : len(str)-1], nil +} diff --git a/internal/template/template_test.go b/internal/template/template_test.go index 3fa594b8d..48ba1c2d1 100644 --- a/internal/template/template_test.go +++ b/internal/template/template_test.go @@ -332,3 +332,69 @@ func TestSubstr(t *testing.T) { } } } + +func TestGetEncodedJSON(t *testing.T) { + tests := []struct { + input map[string]interface{} + want string + }{ + {map[string]interface{}{ + "testboolfalse": false, + "testbooltrue": true, + "testint": 1, + "teststring": "test", + "testmap": map[string]interface{}{ + "testmapstring": "test", + "testmapint": 1, + "testmapboolean": true, + }, + }, "{\"testboolfalse\":false,\"testbooltrue\":true,\"testint\":1,\"testmap\":{\"testmapboolean\":true,\"testmapint\":1,\"testmapstring\":\"test\"},\"teststring\":\"test\"}"}, + {map[string]interface{}{}, "{}"}, + } + + for _, tc := range tests { + got, err := getEncodedJSON(tc.input) + + if err != nil { + t.Fatalf("received error for valid input:\"%s\", got:%s, "+ + ", error received:\n%v", tc.input, got, err) + } + if diff := cmp.Diff(got, tc.want); diff != "" { + t.Errorf("getEncodedJSON results differ for input:\"%s\", want:%s, got:%s, "+ + "and diff(-want +got):\n%v", tc.input, tc.want, got, diff) + } + } +} + +func TestGetEncodedEscapedJSON(t *testing.T) { + tests := []struct { + input map[string]interface{} + want string + }{ + {map[string]interface{}{ + "testboolfalse": false, + "testbooltrue": true, + "testint": 1, + "teststring": "test", + "testmap": map[string]interface{}{ + "testmapstring": "test", + "testmapint": 1, + "testmapboolean": true, + }, + }, "{\\\"testboolfalse\\\":false,\\\"testbooltrue\\\":true,\\\"testint\\\":1,\\\"testmap\\\":{\\\"testmapboolean\\\":true,\\\"testmapint\\\":1,\\\"testmapstring\\\":\\\"test\\\"},\\\"teststring\\\":\\\"test\\\"}"}, + {map[string]interface{}{}, "{}"}, + } + + for _, tc := range tests { + got, err := getEncodedEscapedJSON(tc.input) + + if err != nil { + t.Fatalf("received error for valid input:\"%s\", got:%s, "+ + ", error received:\n%v", tc.input, got, err) + } + if diff := cmp.Diff(got, tc.want); diff != "" { + t.Errorf("getEncodedEscapedJSON results differ for input:\"%s\", want:%s, got:%s, "+ + "and diff(-want +got):\n%v", tc.input, tc.want, got, diff) + } + } +}