xhd2015 / xgo

All-in-one go testing library
MIT License
289 stars 16 forks source link

Testing: add a DiffJSON api #193

Open xhd2015 opened 4 weeks ago

xhd2015 commented 4 weeks ago

It's tempting to embed this function in xgo, though it's just a wrapper around git, but it feels powerful when combining with reflect.DeepEqual():

Usage:

package dosomething

import (
    "reflect"
    "testing"
)

func TestDoSomething(t *testing.T) {
    type args struct {
             ...
    }
    tests := []struct {
        name    string
        args    args
        want    ...
        wantErr bool
    }{
            ...
    }
    for _, tt := range tests {
        tt := tt
        t.Run(tt.name, func(t *testing.T) {
            got, err := DoSomething(tt.args)
            if (err != nil) != tt.wantErr {
                t.Errorf("DoSomething() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if !reflect.DeepEqual(got, tt.want) {
                t.Errorf("DoSomething() = %v, want %v, diff: %s", got, tt.want, DiffJSON(tt.want, got))
            }
        })
    }
}

Assert message:

dosomething_test.go:109: DoSomething() = map[a.go:map[2:4-0:0:0xc0003cee40]], want map[a.go:map[2:4-0:0:0xc0003ced00]], diff: diff --git a/expected b/actual
    index 77721f7..9e95f61 100755
    --- a/expected
    +++ b/actual
    @@ -1,7 +1,7 @@
     {
       "a.go": {
         "2:4-0:0": {
    -      "package": "github.com/xhd2015/xgo",
    +      "package": "github.com/xhd2015/xgo/.",
           "name": "Test",
           "file": "a.go",
           "line": 2,

Implementation:

package assert

import (
    "encoding/json"
    "io/ioutil"
    "os"
    "os/exec"
    "path/filepath"

    "github.com/xhd2015/xgo/support/cmd"
)

func DiffJSON(expected interface{}, actual interface{}) string {
    diff, err := diffJSON(expected, actual)
    if err != nil {
        sep := ""
        if diff != "" {
            sep = ", "
        }
        diff += sep + "err: " + err.Error()
    }
    return diff
}
func diffJSON(expected interface{}, actual interface{}) (string, error) {
    tmpDir, err := os.MkdirTemp("", "diff")
    if err != nil {
        return "", err
    }
    defer os.RemoveAll(tmpDir)

    jsonExpected, err := json.MarshalIndent(expected, "", "  ")
    if err != nil {
        return "", err
    }
    jsonAcutal, err := json.MarshalIndent(actual, "", "  ")
    if err != nil {
        return "", err
    }

    err = ioutil.WriteFile(filepath.Join(tmpDir, "expected"), jsonExpected, 0755)
    if err != nil {
        return "", err
    }
    err = ioutil.WriteFile(filepath.Join(tmpDir, "actual"), jsonAcutal, 0755)
    if err != nil {
        return "", err
    }

    diff, err := cmd.Dir(tmpDir).Output("git", "diff", "--no-index", "--", "expected", "actual")
    if err != nil {
        if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() != 0 {
            err = nil
        }
    }
    return diff, err
}