From a527fa1a964787537b2fd71b67523b8386ec915f Mon Sep 17 00:00:00 2001 From: akshat99812 <138353837+akshat99812@users.noreply.github.com> Date: Sun, 20 Oct 2024 19:54:00 +0530 Subject: [PATCH 1/4] feature/disable-color Signed-off-by: akshat99812 <138353837+akshat99812@users.noreply.github.com> --- jsondiff.go | 63 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/jsondiff.go b/jsondiff.go index d913425..44d7846 100644 --- a/jsondiff.go +++ b/jsondiff.go @@ -25,6 +25,7 @@ type Diff struct { Actual string } +//function func CompareJSON(expectedJSON []byte, actualJSON []byte, noise map[string][]string, disableColor bool) (Diff, error) { color.NoColor = disableColor // Calculate the differences between the two JSON objects. @@ -58,17 +59,26 @@ func CompareJSON(expectedJSON []byte, actualJSON []byte, noise map[string][]stri // expectedJSON: The JSON string containing the expected values. // actualJSON: The JSON string containing the actual values. // Returns a Diff struct containing the colorized differences for the expected and actual JSON responses. -func Compare(expectedJSON, actualJSON string) Diff { +func Compare(expectedJSON, actualJSON string, disableColor bool) Diff { // Calculate the ranges for differences between the expected and actual JSON strings. - offsetExpected, offsetActual, _ := diffArrayRange(expectedJSON, actualJSON) - - // Define colors for highlighting differences. - highlightExpected := color.FgHiRed - highlightActual := color.FgHiGreen + offsetExpected, offsetActual, _ := diffArrayRange(expectedJSON, actualJSON) + + // Define variables for the colorized strings + var colorizedExpected, colorizedActual string + + if disableColor { + // If color is disabled, return the JSON strings as they are + colorizedExpected = expectedJSON + colorizedActual = actualJSON + } else { + // Define colors for highlighting differences. + highlightExpected := color.FgHiRed + highlightActual := color.FgHiGreen - // Colorize the differences in the expected and actual JSON strings. - colorizedExpected := breakSliceWithColor(expectedJSON, &highlightExpected, offsetExpected) - colorizedActual := breakSliceWithColor(actualJSON, &highlightActual, offsetActual) + // Colorize the differences in the expected and actual JSON strings. + colorizedExpected = breakSliceWithColor(expectedJSON, &highlightExpected, offsetExpected) + colorizedActual = breakSliceWithColor(actualJSON, &highlightActual, offsetActual) + } // Return the colorized differences in a Diff struct. return Diff{ @@ -725,29 +735,30 @@ func compareAndColorizeMaps(a, b map[string]interface{}, indent string, red, gre // expect: The map containing the expected header values. // actual: The map containing the actual header values. // Returns a ColorizedResponse containing the colorized differences for the expected and actual headers. -func CompareHeaders(expectedHeaders, actualHeaders map[string]string) Diff { - var expectAll, actualAll strings.Builder // Builders for the resulting strings. +func CompareHeaders(expectedHeaders, actualHeaders map[string]string, options ...bool) Diff { + disableColor := false + if len(options) > 0 { + disableColor = options[0] + } - // Iterate over each key-value pair in the expected map. + var expectAll, actualAll strings.Builder for key, expValue := range expectedHeaders { - actValue := actualHeaders[key] // Get the corresponding value from the actual map. - - // Calculate the offsets of the differences between the expected and actual values. + actValue := actualHeaders[key] offsetsStr1, offsetsStr2, _ := diffArrayRange(string(expValue), string(actValue)) - - // Define colors for highlighting differences. - cE, cA := color.FgHiRed, color.FgHiGreen - - // Colorize the differences in the expected and actual values. - expectDiff := key + ": " + breakSliceWithColor(string(expValue), &cE, offsetsStr1) - actualDiff := key + ": " + breakSliceWithColor(string(actValue), &cA, offsetsStr2) - - // Add the colorized differences to the builders. + + var expectDiff, actualDiff string + if disableColor { + expectDiff = key + ": " + string(expValue) + actualDiff = key + ": " + string(actValue) + } else { + cE, cA := color.FgHiRed, color.FgHiGreen + expectDiff = key + ": " + breakSliceWithColor(string(expValue), &cE, offsetsStr1) + actualDiff = key + ": " + breakSliceWithColor(string(actValue), &cA, offsetsStr2) + } + expectAll.WriteString(breakLines(expectDiff) + "\n") actualAll.WriteString(breakLines(actualDiff) + "\n") } - - // Return the resulting strings. return Diff{Expected: expectAll.String(), Actual: actualAll.String()} } From d423b8c1bac6609b18e5800d432767718c4c5a70 Mon Sep 17 00:00:00 2001 From: akshat99812 <138353837+akshat99812@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:33:55 +0530 Subject: [PATCH 2/4] comments-added Signed-off-by: akshat99812 <138353837+akshat99812@users.noreply.github.com> --- jsondiff.go | 148 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 55 deletions(-) diff --git a/jsondiff.go b/jsondiff.go index 44d7846..8f42b68 100644 --- a/jsondiff.go +++ b/jsondiff.go @@ -25,36 +25,47 @@ type Diff struct { Actual string } -//function +// CompareJSON compares two JSON objects (expectedJSON and actualJSON) and returns a Diff structure. +// It takes into account specific keys that are noisy or irrelevant, specified in the 'noise' parameter. +// If 'disableColor' is true, the colorization of the output will be disabled. +// The function calculates the differences between the JSON objects, and if modified keys exist in the provided maps, +// it adds additional context to the diff. It then separates and optionally colorizes the diff output into expected and actual parts. +// Returns a Diff struct containing the expected and actual differences, or an error if any issue arises. func CompareJSON(expectedJSON []byte, actualJSON []byte, noise map[string][]string, disableColor bool) (Diff, error) { - color.NoColor = disableColor - // Calculate the differences between the two JSON objects. - diffString, err := calculateJSONDiffs(expectedJSON, actualJSON) - if err != nil || diffString == "" { - return Diff{}, err - } - // Extract the modified keys from the diff string. - modifiedKeys := extractKey(diffString) - - // Check if the modified keys exist in the provided maps and add additional context if they do. - contextInfo, exists, error := checkKeyInMaps(expectedJSON, actualJSON, modifiedKeys) - - if error != nil { - return Diff{}, error - } - - if exists { - diffString = contextInfo + "\n" + diffString - } - // Separate and colorize the diff string into expected and actual outputs. - expect, actual := separateAndColorize(diffString, noise) - - return Diff{ - Expected: expect, - Actual: actual, - }, nil + // Disable or enable colorization of output based on 'disableColor' parameter. + color.NoColor = disableColor + + // Calculate the differences between the two JSON objects. + diffString, err := calculateJSONDiffs(expectedJSON, actualJSON) + if err != nil || diffString == "" { + return Diff{}, err + } + + // Extract the modified keys from the generated diff string. + modifiedKeys := extractKey(diffString) + + // Check if the modified keys exist in the provided maps and add additional context if they do. + contextInfo, exists, error := checkKeyInMaps(expectedJSON, actualJSON, modifiedKeys) + if error != nil { + return Diff{}, error + } + + // If relevant keys exist, prepend the context information to the diff string. + if exists { + diffString = contextInfo + "\n" + diffString + } + + // Separate and optionally colorize the diff string into expected and actual outputs. + expect, actual := separateAndColorize(diffString, noise) + + // Return a Diff struct containing the expected and actual differences. + return Diff{ + Expected: expect, + Actual: actual, + }, nil } + // Compare takes expected and actual JSON strings and returns the colorized differences. // expectedJSON: The JSON string containing the expected values. // actualJSON: The JSON string containing the actual values. @@ -732,36 +743,63 @@ func compareAndColorizeMaps(a, b map[string]interface{}, indent string, red, gre } // CompareHeaders compares the headers of the expected and actual maps and returns the differences as colorized strings. -// expect: The map containing the expected header values. -// actual: The map containing the actual header values. -// Returns a ColorizedResponse containing the colorized differences for the expected and actual headers. -func CompareHeaders(expectedHeaders, actualHeaders map[string]string, options ...bool) Diff { - disableColor := false - if len(options) > 0 { - disableColor = options[0] - } - - var expectAll, actualAll strings.Builder - for key, expValue := range expectedHeaders { - actValue := actualHeaders[key] - offsetsStr1, offsetsStr2, _ := diffArrayRange(string(expValue), string(actValue)) - - var expectDiff, actualDiff string - if disableColor { - expectDiff = key + ": " + string(expValue) - actualDiff = key + ": " + string(actValue) - } else { - cE, cA := color.FgHiRed, color.FgHiGreen - expectDiff = key + ": " + breakSliceWithColor(string(expValue), &cE, offsetsStr1) - actualDiff = key + ": " + breakSliceWithColor(string(actValue), &cA, offsetsStr2) - } - - expectAll.WriteString(breakLines(expectDiff) + "\n") - actualAll.WriteString(breakLines(actualDiff) + "\n") - } - return Diff{Expected: expectAll.String(), Actual: actualAll.String()} +// It compares the values of the headers with the same keys from both maps and highlights the differences. +// - expectedHeaders: A map containing the expected header values. +// - actualHeaders: A map containing the actual header values. +// - options: A variadic array of interfaces to pass additional parameters (e.g., disableColor as a bool). +// - If a bool is passed, it will determine whether to disable colorization (true means colorization is disabled). +// - Additional parameters could be added in the future without changing the function signature. +// Returns a Diff struct containing colorized (or plain) differences in the expected and actual headers. +func CompareHeaders(expectedHeaders, actualHeaders map[string]string, options ...interface{}) Diff { + // Default value for disabling colorization (false means colorization is enabled). + disableColor := false + + // Parse options: currently, we only handle disabling colorization. + for _, option := range options { + switch v := option.(type) { + case bool: + disableColor = v // If a boolean is passed, treat it as a flag to disable colorization. + // Additional option types can be handled here in the future. + } + } + + // Initialize string builders to store the final expected and actual header strings. + var expectAll, actualAll strings.Builder + + // Iterate over each key-value pair in the expected headers map. + for key, expValue := range expectedHeaders { + // Retrieve the corresponding actual value from the actual headers map. + actValue := actualHeaders[key] + + // Calculate the differences (ranges of mismatches) between the expected and actual header values. + offsetsStr1, offsetsStr2, _ := diffArrayRange(string(expValue), string(actValue)) + + var expectDiff, actualDiff string + + // If colorization is disabled, simply concatenate the key and its corresponding header value. + if disableColor { + expectDiff = key + ": " + string(expValue) + actualDiff = key + ": " + string(actValue) + } else { + // Colorize the differences using different colors for expected (red) and actual (green) values. + cE, cA := color.FgHiRed, color.FgHiGreen + expectDiff = key + ": " + breakSliceWithColor(string(expValue), &cE, offsetsStr1) + actualDiff = key + ": " + breakSliceWithColor(string(actValue), &cA, offsetsStr2) + } + + // Break the differences into lines and append them to the string builders. + expectAll.WriteString(breakLines(expectDiff) + "\n") + actualAll.WriteString(breakLines(actualDiff) + "\n") + } + + // Return the Diff struct containing the final strings of expected and actual header differences. + return Diff{ + Expected: expectAll.String(), + Actual: actualAll.String(), + } } + // breakSliceWithColor breaks the input string into slices and applies color to specified offsets. // s: The input string to be processed. // c: The color attribute to apply to the specified offsets. From 9a6409e63d98ef46d3ef8bb3ce6c9f4e1274c549 Mon Sep 17 00:00:00 2001 From: akshat99812 <138353837+akshat99812@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:19:01 +0530 Subject: [PATCH 3/4] bug/compareHeadersFixed Signed-off-by: akshat99812 <138353837+akshat99812@users.noreply.github.com> --- jsondiff.go | 104 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 21 deletions(-) diff --git a/jsondiff.go b/jsondiff.go index 8f42b68..a8316f3 100644 --- a/jsondiff.go +++ b/jsondiff.go @@ -753,13 +753,12 @@ func compareAndColorizeMaps(a, b map[string]interface{}, indent string, red, gre func CompareHeaders(expectedHeaders, actualHeaders map[string]string, options ...interface{}) Diff { // Default value for disabling colorization (false means colorization is enabled). disableColor := false - + // Parse options: currently, we only handle disabling colorization. for _, option := range options { switch v := option.(type) { case bool: disableColor = v // If a boolean is passed, treat it as a flag to disable colorization. - // Additional option types can be handled here in the future. } } @@ -768,37 +767,100 @@ func CompareHeaders(expectedHeaders, actualHeaders map[string]string, options .. // Iterate over each key-value pair in the expected headers map. for key, expValue := range expectedHeaders { - // Retrieve the corresponding actual value from the actual headers map. - actValue := actualHeaders[key] - - // Calculate the differences (ranges of mismatches) between the expected and actual header values. - offsetsStr1, offsetsStr2, _ := diffArrayRange(string(expValue), string(actValue)) - - var expectDiff, actualDiff string + actValue, exists := actualHeaders[key] + + if !exists { + // Handle missing headers + if disableColor { + expectAll.WriteString(fmt.Sprintf("%s: %s\n", key, expValue)) + actualAll.WriteString(fmt.Sprintf("%s: \n", key)) + } else { + // Use direct ANSI color codes for missing headers + expectAll.WriteString(fmt.Sprintf("%s: \033[91m%s\033[0m\n", key, expValue)) // Red + actualAll.WriteString(fmt.Sprintf("%s: \n", key)) + } + continue + } - // If colorization is disabled, simply concatenate the key and its corresponding header value. - if disableColor { - expectDiff = key + ": " + string(expValue) - actualDiff = key + ": " + string(actValue) + if expValue != actValue { + if disableColor { + expectAll.WriteString(fmt.Sprintf("%s: %s\n", key, expValue)) + actualAll.WriteString(fmt.Sprintf("%s: %s\n", key, actValue)) + } else { + // Calculate diffs only if values are different + offsetsStr1, offsetsStr2, _ := diffArrayRange(expValue, actValue) + + // Use direct color initialization + redColor := color.New(color.FgHiRed).SprintFunc() + greenColor := color.New(color.FgHiGreen).SprintFunc() + + // Apply colors to the differences + expectDiff := applyColorToRanges(expValue, offsetsStr1, redColor) + actualDiff := applyColorToRanges(actValue, offsetsStr2, greenColor) + + expectAll.WriteString(fmt.Sprintf("%s: %s\n", key, expectDiff)) + actualAll.WriteString(fmt.Sprintf("%s: %s\n", key, actualDiff)) + } } else { - // Colorize the differences using different colors for expected (red) and actual (green) values. - cE, cA := color.FgHiRed, color.FgHiGreen - expectDiff = key + ": " + breakSliceWithColor(string(expValue), &cE, offsetsStr1) - actualDiff = key + ": " + breakSliceWithColor(string(actValue), &cA, offsetsStr2) + // If values are the same, no need for coloring + expectAll.WriteString(fmt.Sprintf("%s: %s\n", key, expValue)) + actualAll.WriteString(fmt.Sprintf("%s: %s\n", key, actValue)) } + } - // Break the differences into lines and append them to the string builders. - expectAll.WriteString(breakLines(expectDiff) + "\n") - actualAll.WriteString(breakLines(actualDiff) + "\n") + // Check for additional headers in actual that weren't in expected + for key, actValue := range actualHeaders { + if _, exists := expectedHeaders[key]; !exists { + if disableColor { + expectAll.WriteString(fmt.Sprintf("%s: \n", key)) + actualAll.WriteString(fmt.Sprintf("%s: %s\n", key, actValue)) + } else { + expectAll.WriteString(fmt.Sprintf("%s: \n", key)) + actualAll.WriteString(fmt.Sprintf("%s: \033[92m%s\033[0m\n", key, actValue)) // Green + } + } } - // Return the Diff struct containing the final strings of expected and actual header differences. return Diff{ Expected: expectAll.String(), Actual: actualAll.String(), } } +// Helper function to apply color to specific ranges of text +func applyColorToRanges(text string, ranges []int, colorFunc func(...interface{}) string) string { + if len(ranges) == 0 { + return text + } + + var result strings.Builder + lastIdx := 0 + + for i := 0; i < len(ranges); i += 2 { + start := ranges[i] + end := ranges[i+1] + + // Add uncolored text before the range + if start > lastIdx { + result.WriteString(text[lastIdx:start]) + } + + // Add colored text for the range + if end > start { + result.WriteString(colorFunc(text[start:end])) + } + + lastIdx = end + } + + // Add any remaining uncolored text + if lastIdx < len(text) { + result.WriteString(text[lastIdx:]) + } + + return result.String() +} + // breakSliceWithColor breaks the input string into slices and applies color to specified offsets. // s: The input string to be processed. From dd79d6073be2c98c3d59a96a62f7f43858dd309a Mon Sep 17 00:00:00 2001 From: akshat99812 <138353837+akshat99812@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:00:05 +0530 Subject: [PATCH 4/4] compareHeadersFixed Signed-off-by: akshat99812 <138353837+akshat99812@users.noreply.github.com> --- jsondiff.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsondiff.go b/jsondiff.go index a8316f3..c7777b7 100644 --- a/jsondiff.go +++ b/jsondiff.go @@ -807,7 +807,7 @@ func CompareHeaders(expectedHeaders, actualHeaders map[string]string, options .. actualAll.WriteString(fmt.Sprintf("%s: %s\n", key, actValue)) } } - + // Check for additional headers in actual that weren't in expected for key, actValue := range actualHeaders { if _, exists := expectedHeaders[key]; !exists {