diff

package
v2.10.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2025 License: Apache-2.0 Imports: 23 Imported by: 0

README

Diff Package

The diff package provides utilities for generating, comparing, and visualizing differences between expected and actual values in various formats. This package is designed to be used in testing scenarios but can be used in any context where difference visualization is needed.

Features

  • Generic type comparisons using go-cmp
  • String-based diffing with unified diff format
  • Character-level diffing for detailed text comparison
  • Rich formatting with color and whitespace visualization
  • Support for various Go types including structs, maps, and primitive types
  • Reflection-based comparison for complex types

Architecture

The package is organized into several modules:

  1. Core Diff Logic (diff.go): Main interfaces and type-specific diff generation
  2. Unified Diff (udiff.go): Implementation of unified diff parsing and formatting
  3. Output Enrichment (enrich.go): Enhances diff output with colors and formatting
  4. Type & Value Formatting (convoluted.go): Formats Go types and values for comparison
  5. Testing Utilities (testing.go): Functions for using diffs in testing

Usage Examples

Basic Comparison
package main

import (
    "fmt"
    "github.com/walteh/cloudstack-mcp/pkg/diff"
)

func main() {
    expected := "Hello, World!"
    actual := "Hello, Universe!"

    // Generate a diff between two strings
    result := diff.TypedDiff(expected, actual)

    // Print the diff
    fmt.Println(result)
}
Using in Tests
package mypackage_test

import (
    "testing"
    "github.com/walteh/cloudstack-mcp/pkg/diff"
)

func TestSomething(t *testing.T) {
    expected := map[string]int{"a": 1, "b": 2}
    actual := map[string]int{"a": 1, "b": 3}

    // Compare values and fail if they don't match
    diff.RequireEqual(t, expected, actual)
}
Comparing Complex Types
package mypackage_test

import (
    "reflect"
    "testing"
    "github.com/walteh/cloudstack-mcp/pkg/diff"
)

type MyStruct struct {
    Name string
    Age  int
    private string
}

func TestStructComparison(t *testing.T) {
    s1 := MyStruct{Name: "Alice", Age: 30, private: "secret"}
    s2 := MyStruct{Name: "Alice", Age: 31, private: "secret"}

    // Compare with unexported fields
    diff.RequireEqual(t, s1, s2, diff.WithUnexportedType[MyStruct]())
}
Character-Level Diffing
package main

import (
    "fmt"
    "github.com/walteh/cloudstack-mcp/pkg/diff"
)

func main() {
    str1 := "The quick brown fox jumps over the lazy dog"
    str2 := "The quick brown fox jumps over the lazy cat"

    // Get character-level differences
    result := diff.SingleLineStringDiff(str1, str2)

    fmt.Println(result)
}

Extension Points

The package is designed to be extensible:

  1. Create custom formatters by implementing the DiffFormatter interface
  2. Create custom diff generators by implementing the Differ interface
  3. Add options to modify behavior via the various ...Opts structs

Best Practices

  1. Use TypedDiff for comparing values of the same type
  2. Use TypedDiffExportedOnly when comparing structs where unexported fields should be ignored
  3. Use RequireEqual and similar functions in tests for clean assertion code
  4. Consider using WithUnexportedType when comparing structs with private fields in tests
  5. For long diffs, the output is automatically shortened to make it more readable

Legacy Support

The package maintains backward compatibility with older functions like:

  • RequireUnknownTypeEqual
  • RequireUnknownValueEqualAsJSON
  • RequireKnownValueEqual

However, it's recommended to use the newer, more consistently named functions instead.

Documentation

Overview

Package diff - Type and Value Formatting This file contains functions for formatting Go types and values for better diff representation

Package diff provides utilities for generating, comparing, and visualizing differences between expected and actual values in various formats.

The package offers multiple ways to compare values: - Generic type comparisons using go-cmp - String-based diffing with unified diff format - Character-level diffing for detailed text comparison

It's designed to be used in testing scenarios but can be used in any context where difference visualization is needed.

Package diff - Diff Output Enrichment This file contains functions to enhance and format diff outputs

Package diff - Testing Utilities This file contains testing utilities for comparing values and generating diff reports

Package diff - UnifiedDiff implementation This file contains the functionality for parsing and formatting unified diffs

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AltEnrichUnifiedDiff

func AltEnrichUnifiedDiff(diff string) string

AltEnrichUnifiedDiff provides an alternative implementation of UnifiedDiff enrichment This uses the structured diff parser and renderer

func ConvertToRawUnifiedDiffString

func ConvertToRawUnifiedDiffString(want string, got string) string

GenerateUnifiedDiff creates a unified diff between two strings. It formats the output as a standard unified diff with context.

func ConvolutedFormatReflectType

func ConvolutedFormatReflectType(s reflect.Type) string

ConvolutedFormatReflectType formats a reflect.Type into a standardized string representation. It handles struct types specially, formatting them with consistent field ordering and indentation for better readability.

func ConvolutedFormatReflectValueAsJSON

func ConvolutedFormatReflectValueAsJSON(s reflect.Value) any

ConvolutedFormatReflectValue formats a reflect.Value into a standardized string representation suitable for comparison. It converts the value to JSON and then uses a stable ordering to ensure consistent output.

func EnrichCmpDiff

func EnrichCmpDiff(diff string) string

EnrichCmpDiff enhances a diff produced by cmp.Diff with colors and formatting to make it more readable.

func EnrichUnifiedDiff

func EnrichUnifiedDiff(diff string) string

EnrichUnifiedDiff enhances a unified diff with colors and formatting to make it more readable.

func Equal

func Equal[T any](t *testing.T, want, got T, opts ...OptTestingOptsSetter) bool

Equal compares two values of the same type and returns true if they are equal

func FormatDiff

func FormatDiff(diff *ProcessedDiff) string

FormatDiff applies color formatting to a ProcessedDiff

func RequireEqual

func RequireEqual[T any](t *testing.T, want, got T, opts ...OptTestingOptsSetter)

RequireEqual compares two values and fails the test if they are not equal

func RequireKnownValueEqual

func RequireKnownValueEqual[T any](t *testing.T, want, got T, opts ...OptTestingOptsSetter)

RequireKnownValueEqual compares two values of the same type and fails the test if they are not equal This is maintained for backward compatibility

func RequireTypeEqual

func RequireTypeEqual(t *testing.T, want, got reflect.Type, opts ...OptTestingOptsSetter)

RequireTypeEqual compares two reflect.Type values and fails the test if they are not equal

func RequireUnknownTypeEqual

func RequireUnknownTypeEqual(t *testing.T, want, got reflect.Type, opts ...OptTestingOptsSetter)

RequireUnknownTypeEqual compares two reflect.Type values and fails the test if they are not equal This is maintained for backward compatibility

func RequireUnknownValueEqualAsJSON

func RequireUnknownValueEqualAsJSON(t *testing.T, want, got reflect.Value)

RequireUnknownValueEqualAsJSON compares two reflect.Value values and fails the test if they are not equal This is maintained for backward compatibility

func RequireValueEqual

func RequireValueEqual(t *testing.T, want, got reflect.Value)

RequireValueEqual compares two reflect.Value values and fails the test if they are not equal

func SingleLineStringDiff

func SingleLineStringDiff(want string, got string) string

SingleLineStringDiff performs character-level diffing between two strings. It highlights specific characters that differ, which is useful for single-line string comparisons.

func Strip

func Strip(str string) string

Strip removes ANSI color codes from a string

func TypeEqual

func TypeEqual(t *testing.T, want, got reflect.Type, opts ...OptTestingOptsSetter) bool

TypeEqual compares two reflect.Type values and returns true if they are equal

func TypedDiff

func TypedDiff[T any](want T, got T, opts ...OptTestingOptsSetter) string

func ValueEqual

func ValueEqual(t *testing.T, want, got reflect.Value) bool

ValueEqual compares two reflect.Value values and returns true if they are equal

Types

type ColoredRune

type ColoredRune struct {
	Rune      rune
	Suffix    string
	Color     *color.Color
	IsSpecial bool
}

func (*ColoredRune) Add

func (cr *ColoredRune) Add(c ...color.Attribute)

func (*ColoredRune) MarkIsSpecial

func (cr *ColoredRune) MarkIsSpecial()

type ColoredString

type ColoredString struct {
	// contains filtered or unexported fields
}

func NewColoredString

func NewColoredString(s string) *ColoredString

func (*ColoredString) Annotate

func (s *ColoredString) Annotate(colord *color.Color)

func (*ColoredString) AppendToEnd

func (cs *ColoredString) AppendToEnd(r rune, c ...color.Attribute)

func (*ColoredString) AppendToStart

func (cs *ColoredString) AppendToStart(r rune, c ...color.Attribute)

func (*ColoredString) ColoredString

func (cs *ColoredString) ColoredString() string

func (*ColoredString) MultiAppendToEnd

func (cs *ColoredString) MultiAppendToEnd(rs ...*ColoredRune)

func (*ColoredString) MultiAppendToStart

func (cs *ColoredString) MultiAppendToStart(rs ...*ColoredRune)

type DiffChange

type DiffChange struct {
	Text string
	Type DiffChangeType
}

DiffChange represents a character-level change in a line

type DiffChangeType

type DiffChangeType string

DiffChangeType indicates whether a change is an addition, removal, or unchanged text

const (
	// DiffChangeUnchanged represents text that is the same in both versions
	DiffChangeUnchanged DiffChangeType = "unchanged"
	// DiffChangeAdded represents text that was added
	DiffChangeAdded DiffChangeType = "added"
	// DiffChangeRemoved represents text that was removed
	DiffChangeRemoved DiffChangeType = "removed"
)

type DiffFormatter

type DiffFormatter interface {
	// Format formats a diff string with visual enhancements
	Format(diff string) string
}

DiffFormatter defines the interface for formatters that can render diffs

type DiffHunk

type DiffHunk struct {
	Header string
	Lines  []DiffLine
}

DiffHunk represents a hunk in a unified diff (a group of changes)

type DiffLine

type DiffLine struct {
	Content string
	Applied string
	Type    DiffLineType
	Changes []DiffChange // Character-level changes within the line
}

DiffLine represents a line in the unified diff with metadata

type DiffLineType

type DiffLineType string

DiffLineType indicates whether a line is context, addition, or removal

const (
	// DiffLineContext represents an unchanged line shown for context
	DiffLineContext DiffLineType = "context"
	// DiffLineAdded represents a line that was added
	DiffLineAdded DiffLineType = "added"
	// DiffLineRemoved represents a line that was removed
	DiffLineRemoved DiffLineType = "removed"
)

type DiffResult

type DiffResult struct {
	// Content is the formatted diff content
	Content string
	// IsEqual is true if there is no difference
	IsEqual bool
}

DiffResult represents the output of a diff operation

type Differ

type Differ interface {
	// Diff generates a diff between two values
	Diff(want, got interface{}) DiffResult
}

Differ defines the interface for types that can generate diffs

type OptTestingOptsSetter

type OptTestingOptsSetter func(o *TestingOpts)

func WithCmpOpts

func WithCmpOpts(opt []cmp.Option) OptTestingOptsSetter

func WithLogRawDiffOnFail

func WithLogRawDiffOnFail(opt bool) OptTestingOptsSetter

func WithUnexportedType

func WithUnexportedType[T any]() OptTestingOptsSetter

WithUnexportedType adds an option to allow comparing unexported fields in a type This is useful when testing struct values with private fields

type ProcessedDiff

type ProcessedDiff struct {
	OrigFile string
	NewFile  string
	Hunks    []DiffHunk
}

ProcessedDiff represents a fully processed diff with all metadata

type Req

type Req struct {
	// contains filtered or unexported fields
}

func Require

func Require(t *testing.T) *Req

func (*Req) Equals

func (r *Req) Equals()

func (*Req) Got

func (r *Req) Got(got any) *Req

func (*Req) Opts

func (r *Req) Opts(opts ...OptTestingOptsSetter) *Req

func (*Req) Want

func (r *Req) Want(want any) *Req

type TestingOpts

type TestingOpts struct {
	// contains filtered or unexported fields
}

TestingOpts contains options for diff testing functionality

func NewTestingOpts

func NewTestingOpts(
	options ...OptTestingOptsSetter,
) TestingOpts

func (*TestingOpts) Validate

func (o *TestingOpts) Validate() error

type UnifiedDiff

type UnifiedDiff struct {
	FileDiff *diff.FileDiff
}

UnifiedDiff represents a parsed unified diff with methods to process and format it

func ParseUnifiedDiff

func ParseUnifiedDiff(diffStr string) (*UnifiedDiff, error)

ParseUnifiedDiff parses a unified diff string into a structured format It normalizes the input and uses go-diff to parse the unified diff format

func (*UnifiedDiff) PrettyPrint

func (ud *UnifiedDiff) PrettyPrint() string

PrettyPrint formats the unified diff with colors

func (*UnifiedDiff) ProcessDiff

func (ud *UnifiedDiff) ProcessDiff() (*ProcessedDiff, error)

ProcessDiff converts a UnifiedDiff into a ProcessedDiff This is the core logic that can be tested separately from color formatting

type ValueComparison

type ValueComparison struct {
	// contains filtered or unexported fields
}

ValueComparison provides methods for comparing different types of values

func NewValueComparison

func NewValueComparison(t *testing.T) *ValueComparison

NewValueComparison creates a new value comparison helper for testing

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL