report/diff_message.go (120 lines of code) (raw):

package report import ( "encoding/json" "fmt" "strings" "github.com/azure/armstrong/types" "github.com/nsf/jsondiff" ) func DiffMessageTerraform(diff types.Change) string { option := jsondiff.DefaultConsoleOptions() _, msg := jsondiff.Compare([]byte(diff.Before), []byte(diff.After), &option) return msg } func DiffMessageReadable(diff types.Change) string { option := jsondiff.Options{ Added: jsondiff.Tag{Begin: "\033[0;32m", End: " is not returned from response, if it's on purpose, please follow https://github.com/Azure/armstrong?tab=readme-ov-file#troubleshooting\033[0m"}, Removed: jsondiff.Tag{Begin: "\033[0;31m", End: "\033[0m"}, Changed: jsondiff.Tag{Begin: "\033[0;33m Got ", End: "\033[0m"}, Skipped: jsondiff.Tag{Begin: "\033[0;90m", End: "\033[0m"}, SkippedArrayElement: jsondiff.SkippedArrayElement, SkippedObjectProperty: jsondiff.SkippedObjectProperty, ChangedSeparator: " in response, expect ", Indent: " ", } _, msg := jsondiff.Compare([]byte(diff.Before), []byte(diff.After), &option) return msg } func DiffMessageMarkdown(diff types.Change) string { option := jsondiff.Options{ Added: jsondiff.Tag{Begin: "", End: " is not returned from response, if it's on purpose, please follow https://github.com/Azure/armstrong?tab=readme-ov-file#troubleshooting"}, Removed: jsondiff.Tag{Begin: "", End: ""}, Changed: jsondiff.Tag{Begin: "Got ", End: ""}, Skipped: jsondiff.Tag{Begin: "", End: ""}, SkippedArrayElement: jsondiff.SkippedArrayElement, SkippedObjectProperty: jsondiff.SkippedObjectProperty, ChangedSeparator: " in response, expect ", Indent: " ", } _, msg := jsondiff.Compare([]byte(diff.Before), []byte(diff.After), &option) return msg } func DiffMessageDescription(diff types.Change) string { var before, after interface{} _ = json.Unmarshal([]byte(diff.Before), &before) _ = json.Unmarshal([]byte(diff.After), &after) diffs := compare(before, after, "- ") return strings.Join(diffs, "\n") } // compare two json objects, return the difference in string array // path is the path of the json object // got is the value returned from the api // expect is the expected value which is defined in the config file func compare(got interface{}, expect interface{}, path string) []string { if expect == nil && got == nil { return []string{} } if expect == nil { return []string{fmt.Sprintf("%s: expect null, but got %v", path, got)} } if got == nil { return []string{fmt.Sprintf("%s = %v: not returned from response", path, expect)} } switch expectValue := expect.(type) { case map[string]interface{}: if gotMap, ok := got.(map[string]interface{}); ok { res := make([]string, 0) for key, value := range expectValue { res = append(res, compare(gotMap[key], value, fmt.Sprintf("%s.%s", path, key))...) } return res } else { return []string{fmt.Sprintf("%s: expect %v which is a map, but got %v", path, expect, got)} } case []interface{}: if gotArr, ok := got.([]interface{}); ok { if len(gotArr) != len(expectValue) { return []string{fmt.Sprintf("%s: expect %d in length, but got %d", path, len(expectValue), len(gotArr))} } res := make([]string, 0) for index := range expectValue { res = append(res, compare(gotArr[index], expectValue[index], fmt.Sprintf("%s.%d", path, index))...) } return res } else { return []string{fmt.Sprintf("%s: expect %v which is an array, but got %v", path, expect, got)} } case bool: if gotBool, ok := got.(bool); ok { if gotBool != expectValue { return []string{fmt.Sprintf("%s: expect %v, but got %v", path, expect, got)} } } else { return []string{fmt.Sprintf("%s: expect %v which is a bool, but got %v", path, expect, got)} } case string: if gotString, ok := got.(string); ok { if gotString != expectValue { if strings.EqualFold(gotString, expectValue) { return []string{fmt.Sprintf("%s: the values are not equal case-sensitively, expect %v, but got %v", path, expect, got)} } return []string{fmt.Sprintf("%s: expect %v, but got %v", path, expect, got)} } } else { return []string{fmt.Sprintf("%s: expect %v which is a string, but got %v", path, expect, got)} } case float64: if gotFloat, ok := got.(float64); ok { if gotFloat != expectValue { return []string{fmt.Sprintf("%s: expect %v, but got %v", path, expect, got)} } } else { return []string{fmt.Sprintf("%s: expect %v which is a number, but got %v", path, expect, got)} } case int64: if gotInt, ok := got.(int64); ok { if gotInt != expectValue { return []string{fmt.Sprintf("%s: expect %v, but got %v", path, expect, got)} } } else { return []string{fmt.Sprintf("%s: expect %v which is a number, but got %v", path, expect, got)} } } return nil }