Use go-cmp instead of reflect.DeepEqual to compare unit test results (#6343)

This commit is contained in:
Armel Soro
2022-11-24 13:24:32 +01:00
committed by GitHub
parent 1bfb116b74
commit 5660093167
73 changed files with 1198 additions and 1554 deletions

7
go.mod
View File

@@ -17,11 +17,13 @@ require (
github.com/fsnotify/fsnotify v1.5.1
github.com/ghodss/yaml v1.0.0
github.com/go-git/go-git/v5 v5.3.0
github.com/go-openapi/jsonpointer v0.19.5
github.com/go-openapi/jsonreference v0.19.5
github.com/go-openapi/spec v0.19.5
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.9
github.com/jedib0t/go-pretty/v6 v6.3.5
github.com/kubernetes-sigs/service-catalog v0.3.1
github.com/kylelemons/godebug v1.1.0
github.com/mattn/go-colorable v0.1.13
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5
@@ -106,8 +108,6 @@ require (
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.1.0 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
@@ -117,7 +117,6 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/licensecheck v0.3.1 // indirect
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect

5
go.sum
View File

@@ -609,8 +609,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@@ -784,7 +784,6 @@ github.com/kubernetes-sigs/service-catalog v0.3.1 h1:jgE7b16OqBjxG3BScxqQYl5zkx7
github.com/kubernetes-sigs/service-catalog v0.3.1/go.mod h1:MUAf+rdT06kiNpLXRAIqtPHC3Kgkw63YziVj1VMu3HM=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=

View File

@@ -2,14 +2,15 @@ package binding
import (
"fmt"
"reflect"
"testing"
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/pkg/devfile/parser"
devfileCtx "github.com/devfile/library/pkg/devfile/parser/context"
"github.com/devfile/library/pkg/testingutil/filesystem"
"github.com/golang/mock/gomock"
"github.com/kylelemons/godebug/pretty"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -65,8 +66,9 @@ func TestBindingClient_GetFlags(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &BindingClient{}
if got := o.GetFlags(tt.args.flags); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetFlags() = %v, want %v", got, tt.want)
got := o.GetFlags(tt.args.flags)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("BindingClient.GetFlags() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -209,8 +211,8 @@ func TestBindingClient_GetServiceInstances(t *testing.T) {
t.Errorf("GetServiceInstances() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetServiceInstances() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("BindingClient.GetServiceInstances() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -408,8 +410,10 @@ func TestBindingClient_AddBindingToDevfile(t *testing.T) {
t.Errorf("AddBindingToDevfile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, *tt.want) {
t.Errorf("AddBindingToDevfile(): %v", pretty.Compare(got, tt.want))
if diff := cmp.Diff(*tt.want, got,
cmp.AllowUnexported(devfileCtx.DevfileCtx{}),
cmpopts.IgnoreInterfaces(struct{ filesystem.Filesystem }{})); diff != "" {
t.Errorf("BindingClient.AddBindingToDevfile() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,12 +1,11 @@
package binding
import (
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/parser"
"github.com/golang/mock/gomock"
"github.com/kylelemons/godebug/pretty"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/kclient"
@@ -226,11 +225,11 @@ func TestBindingClient_ListAllBindings(t *testing.T) {
t.Errorf("BindingClient.ListAllBindings() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("BindingClient.ListAllBindings(): %v ", pretty.Compare(got, tt.want))
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("BindingClient.ListAllBindings() mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(gotInDevfile, tt.wantInDevfile) {
t.Errorf("BindingClient.ListAllBindings(): %v", pretty.Compare(gotInDevfile, tt.wantInDevfile))
if diff := cmp.Diff(tt.wantInDevfile, gotInDevfile); diff != "" {
t.Errorf("BindingClient.ListAllBindings() wantInDevfile mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,10 +1,11 @@
package binding
import (
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/parser"
devfileCtx "github.com/devfile/library/pkg/devfile/parser/context"
"github.com/google/go-cmp/cmp"
odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil"
)
@@ -95,8 +96,8 @@ func TestBindingClient_RemoveBinding(t *testing.T) {
t.Errorf("RemoveBinding() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("RemoveBinding() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got, cmp.AllowUnexported(devfileCtx.DevfileCtx{})); diff != "" {
t.Errorf("BindingClient.RemoveBinding() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -6,7 +6,6 @@ import (
"os"
"path"
"path/filepath"
"reflect"
"testing"
devfilepkg "github.com/devfile/api/v2/pkg/devfile"
@@ -17,7 +16,7 @@ import (
"github.com/devfile/library/pkg/testingutil/filesystem"
dfutil "github.com/devfile/library/pkg/util"
"github.com/golang/mock/gomock"
"github.com/kylelemons/godebug/pretty"
"github.com/google/go-cmp/cmp"
v12 "github.com/openshift/api/route/v1"
v1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -170,8 +169,8 @@ func TestListAllClusterComponents(t *testing.T) {
t.Errorf("ListAllClusterComponents error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ListAllClusterComponents got = %+v\nwant = %+v\ncomparison:\n %v", got, tt.want, pretty.Compare(got, tt.want))
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("ListAllClusterComponents() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -361,8 +360,8 @@ func TestGetRunningModes(t *testing.T) {
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetRunningModes() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetRunningModes() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -488,8 +487,8 @@ func TestGatherName(t *testing.T) {
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
}
want := tt.want(dir, d)
if !reflect.DeepEqual(got, want) {
t.Errorf("GatherName() = %q, want = %q", got, want)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("GatherName() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -673,11 +672,11 @@ func TestListRoutesAndIngresses(t *testing.T) {
t.Errorf("ListRoutesAndIngresses() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotIngs, tt.wantIngs) {
t.Errorf("ListRoutesAndIngresses() gotIngs = %v, want %v", gotIngs, tt.wantIngs)
if diff := cmp.Diff(tt.wantIngs, gotIngs); diff != "" {
t.Errorf("ListRoutesAndIngresses() wantIngs mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(gotRoutes, tt.wantRoutes) {
t.Errorf("ListRoutesAndIngresses() gotRoutes = %v, want %v", gotRoutes, tt.wantRoutes)
if diff := cmp.Diff(tt.wantRoutes, gotRoutes); diff != "" {
t.Errorf("ListRoutesAndIngresses() wantRoutes mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -3,12 +3,12 @@ package delete
import (
"context"
"errors"
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/parser"
"github.com/devfile/library/pkg/testingutil/filesystem"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -123,8 +123,8 @@ func TestDeleteComponentClient_ListClusterResourcesToDelete(t *testing.T) {
t.Errorf("DeleteComponentClient.ListResourcesToDelete() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("DeleteComponentClient.ListResourcesToDelete() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("DeleteComponentClient.ListClusterResourcesToDelete() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -234,8 +234,9 @@ func TestDeleteComponentClient_DeleteResources(t *testing.T) {
kubeClient := tt.fields.kubeClient(ctrl)
execClient := exec.NewExecClient(kubeClient)
do := NewDeleteComponentClient(kubeClient, execClient)
if got := do.DeleteResources(tt.args.resources, false); !reflect.DeepEqual(got, tt.want) {
t.Errorf("DeleteComponentClient.DeleteResources() = %v, want %v", got, tt.want)
got := do.DeleteResources(tt.args.resources, false)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("DeleteComponentClient.DeleteResources() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -557,8 +558,8 @@ func TestDeleteComponentClient_ListResourcesToDeleteFromDevfile(t *testing.T) {
if gotIsInnerLoopDeployed != tt.wantIsInnerLoopDeployed {
t.Errorf("ListResourcesToDeleteFromDevfile() gotIsInnerLoopDeployed = %v, want %v", gotIsInnerLoopDeployed, tt.wantIsInnerLoopDeployed)
}
if !reflect.DeepEqual(gotResources, tt.wantResources) {
t.Errorf("ListResourcesToDeleteFromDevfile() gotResources = %v, want %v", gotResources, tt.wantResources)
if diff := cmp.Diff(tt.wantResources, gotResources); diff != "" {
t.Errorf("DeleteComponentClient.ListResourcesToDeleteFromDevfile() wantResources mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -6,7 +6,8 @@ import (
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/pkg/devfile/parser"
"github.com/devfile/library/pkg/devfile/parser/data"
"github.com/kylelemons/godebug/pretty"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/labels"
@@ -14,7 +15,6 @@ import (
"github.com/redhat-developer/odo/pkg/version"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/resource"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
@@ -336,12 +336,12 @@ func Test_createPodFromComponent(t *testing.T) {
t.Errorf("createPodFromComponent() error = %v, wantErr %v", err, tt.wantErr)
return
}
want := tt.wantPod()
if !equality.Semantic.DeepEqual(got, want) {
t.Errorf("createPodFromComponent() pod: %s", pretty.Compare(want, got))
if diff := cmp.Diff(tt.wantPod(), got, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("createPodFromComponent() pod mismatch (-want +got):\n%s", diff)
}
if !equality.Semantic.DeepEqual(gotFwPorts, tt.wantFwPorts) {
t.Errorf("createPodFromComponent() fwPorts: %s", pretty.Compare(tt.wantFwPorts, gotFwPorts))
if diff := cmp.Diff(tt.wantFwPorts, gotFwPorts, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("createPodFromComponent() fwPorts mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,12 +1,12 @@
package component
import (
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/generator"
"github.com/devfile/library/pkg/devfile/parser/data"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/libdevfile"
"github.com/redhat-developer/odo/pkg/preference"
@@ -238,8 +238,8 @@ func TestAdapter_generateDeploymentObjectMeta(t *testing.T) {
t.Errorf("generateDeploymentObjectMeta() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("generateDeploymentObjectMeta() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Adapter.generateDeploymentObjectMeta() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,7 +1,6 @@
package storage
import (
"reflect"
"testing"
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
@@ -10,10 +9,12 @@ import (
devfileParser "github.com/devfile/library/pkg/devfile/parser"
"github.com/devfile/library/pkg/devfile/parser/data"
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
"github.com/redhat-developer/odo/pkg/testingutil"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/redhat-developer/odo/pkg/testingutil"
)
func TestGetPVC(t *testing.T) {
@@ -138,12 +139,11 @@ func TestGetVolumeInfos(t *testing.T) {
if err != nil {
return
}
if odoSourcePVCName != tt.wantOdoSourcePVCName {
t.Errorf("Got odoSource PVC name %v, expected %v", odoSourcePVCName, tt.wantOdoSourcePVCName)
if diff := cmp.Diff(tt.wantOdoSourcePVCName, odoSourcePVCName); diff != "" {
t.Errorf("GetVolumeInfos() wantOdoSourcePVCName mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(infos, tt.wantInfos) {
t.Errorf("Got infos %v, expected %v", infos, tt.wantInfos)
if diff := cmp.Diff(tt.wantInfos, infos); diff != "" {
t.Errorf("GetVolumeInfos() wantInfos mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,10 +1,10 @@
package utils
import (
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/parser/data"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/storage"
"github.com/redhat-developer/odo/pkg/util"
@@ -472,13 +472,11 @@ func TestUpdateContainersEntrypointsIfNeeded(t *testing.T) {
t.Errorf("empty command for container %q", c.Args)
}
if !reflect.DeepEqual(tt.expectedContainerCommand[c.Name], c.Command) {
t.Errorf("unexpected command for container %q, expected=%v, got %v",
c.Name, tt.expectedContainerCommand[c.Name], c.Command)
if diff := cmp.Diff(tt.expectedContainerCommand[c.Name], c.Command); diff != "" {
t.Errorf("UpdateContainersEntrypointsIfNeeded() expectedContainerCommand[%s] mismatch (-want +got):\n%s", c.Name, diff)
}
if !reflect.DeepEqual(tt.expectedContainerArgs[c.Name], c.Args) {
t.Errorf("unexpected args for container %q, expected=%v, got %v",
c.Name, tt.expectedContainerArgs[c.Name], c.Args)
if diff := cmp.Diff(tt.expectedContainerArgs[c.Name], c.Args); diff != "" {
t.Errorf("UpdateContainersEntrypointsIfNeeded() expectedContainerArgs[%s] mismatch (-want +got):\n%s", c.Name, diff)
}
}

View File

@@ -1,10 +1,11 @@
package devfile
import (
"reflect"
"sort"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
devfiletesting "github.com/redhat-developer/odo/pkg/devfile/testing"
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
@@ -161,28 +162,24 @@ func TestGetKubernetesComponentsToPush(t *testing.T) {
},
}
sorterFuncProvider := func(x []devfilev1.Component) func(i, j int) bool {
return func(i, j int) bool {
return x[i].Name < x[j].Name
}
lessFunc := func(x, y devfilev1.Component) bool {
return x.Name < y.Name
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetKubernetesComponentsToPush(tt.devfileObj, tt.allowApply)
gotErr := err != nil
if gotErr != tt.wantErr {
t.Errorf("Got error %v, expected %v\n", err, tt.wantErr)
}
if len(got) != len(tt.want) {
t.Errorf("Got %d components, expected %d\n", len(got), len(tt.want))
}
sort.Slice(tt.want, sorterFuncProvider(tt.want))
sort.Slice(got, sorterFuncProvider(got))
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("\nGot %+v\nExpected %+v\n", got, tt.want)
}
if gotErr != tt.wantErr {
t.Errorf("Got error %v, expected %v\n", err, tt.wantErr)
if diff := cmp.Diff(tt.want, got, cmpopts.SortSlices(lessFunc)); diff != "" {
t.Errorf("GetKubernetesComponentsToPush() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -5,11 +5,11 @@ import (
"net/http"
"net/http/httptest"
"path/filepath"
"reflect"
"strings"
"testing"
devfile "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
)
@@ -138,8 +138,8 @@ func TestGetShellCommand(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getShellCommand(tt.cmdName, tt.image, tt.devfilePath, tt.image.Dockerfile.Uri)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%s:\n Expected %v,\n got %v", tt.name, tt.want, got)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("getShellCommand() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,10 +1,10 @@
package validate
import (
"reflect"
"testing"
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/google/go-cmp/cmp"
)
func TestValidateComponents(t *testing.T) {
@@ -17,8 +17,8 @@ func TestValidateComponents(t *testing.T) {
got := validateComponents(components)
want := &NoComponentsError{}
if !reflect.DeepEqual(got, want) {
t.Errorf("TestValidateComponents error - got: '%v', want: '%v'", got, want)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("validateComponents() mismatch (-want +got):\n%s", diff)
}
})

View File

@@ -3,9 +3,9 @@ package exec
import (
"errors"
"io"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
@@ -87,11 +87,11 @@ func TestExecuteCommand(t *testing.T) {
t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(tt.wantStdout, stdout) {
t.Errorf("expected %+q for stdout, got %+q", tt.wantStdout, stdout)
if diff := cmp.Diff(tt.wantStdout, stdout); diff != "" {
t.Errorf("ExecClient.ExecuteCommand() wantStdout mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(tt.wantStderr, stderr) {
t.Errorf("expected %+q for stderr, got %+q", tt.wantStderr, stderr)
if diff := cmp.Diff(tt.wantStderr, stderr); diff != "" {
t.Errorf("ExecClient.ExecuteCommand() wantStderr mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,8 +1,9 @@
package asker
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
)
func Test_buildPersonalizedConfigurationOptions(t *testing.T) {
@@ -86,11 +87,12 @@ func Test_buildPersonalizedConfigurationOptions(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotOptions, gotTracker := buildPersonalizedConfigurationOptions(tt.args.configuration)
if !reflect.DeepEqual(gotOptions, tt.wantOptions) {
t.Errorf("buildPersonalizedConfigurationOptions() gotOptions = %v, want %v", gotOptions, tt.wantOptions)
if diff := cmp.Diff(tt.wantOptions, gotOptions); diff != "" {
t.Errorf("buildPersonalizedConfigurationOptions() wantOptions mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(gotTracker, tt.wantTracker) {
t.Errorf("buildPersonalizedConfigurationOptions() gotTracker = %v, want %v", gotTracker, tt.wantTracker)
if diff := cmp.Diff(tt.wantTracker, gotTracker); diff != "" {
t.Errorf("buildPersonalizedConfigurationOptions() wantTracker mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -3,11 +3,12 @@ package backend
import (
"context"
"path/filepath"
"reflect"
"runtime"
"testing"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/alizer/go/pkg/apis/recognizer"
"github.com/redhat-developer/odo/pkg/alizer"
"github.com/redhat-developer/odo/pkg/api"
@@ -102,8 +103,8 @@ func TestAlizerBackend_SelectDevfile(t *testing.T) {
t.Errorf("AlizerBackend.SelectDevfile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotLocation, tt.wantLocation) {
t.Errorf("AlizerBackend.SelectDevfile() = %v, want %v", gotLocation, tt.wantLocation)
if diff := cmp.Diff(tt.wantLocation, gotLocation); diff != "" {
t.Errorf("AlizerBackend.SelectDevfile() wantLocation mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -2,10 +2,10 @@ package backend
import (
"context"
"reflect"
"testing"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/pkg/devfile/parser"
@@ -54,8 +54,8 @@ func TestFlagsBackend_SelectDevfile(t *testing.T) {
t.Errorf("FlagsBackend.SelectDevfile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("FlagsBackend.SelectDevfile() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("FlagsBackend.SelectDevfile() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -381,8 +381,8 @@ func TestFlagsBackend_SelectStarterProject(t *testing.T) {
t.Errorf("FlagsBackend.SelectStarterProject() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got1, tt.want) {
t.Errorf("FlagsBackend.SelectStarterProject() got1 = %v, want %v", got1, tt.want)
if diff := cmp.Diff(tt.want, got1); diff != "" {
t.Errorf("FlagsBackend.SelectStarterProject() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -2,10 +2,10 @@ package backend
import (
"context"
"reflect"
"testing"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/alizer"
"github.com/redhat-developer/odo/pkg/api"
@@ -94,11 +94,11 @@ func TestInteractiveBackend_SelectDevfile(t *testing.T) {
ctx := context.Background()
got, err := o.SelectDevfile(ctx, map[string]string{}, nil, "")
if (err != nil) != tt.wantErr {
t.Errorf("InteractiveBuilder.ParamsBuild() error = %v, wantErr %v", err, tt.wantErr)
t.Errorf("InteractiveBackend.SelectDevfile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("InteractiveBuilder.ParamsBuild() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("InteractiveBackend.SelectDevfile() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -194,8 +194,8 @@ func TestInteractiveBackend_SelectStarterProject(t *testing.T) {
return
}
if !reflect.DeepEqual(got1, tt.want) {
t.Errorf("InteractiveBackend.SelectStarterProject() got1 = %v, want %v", got1, tt.want)
if diff := cmp.Diff(tt.want, got1); diff != "" {
t.Errorf("InteractiveBackend.SelectStarterProject() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -510,7 +510,7 @@ func TestInteractiveBackend_PersonalizeDevfileconfig(t *testing.T) {
Ports: []string{"7000", "8000"},
Envs: map[string]string{"env1": "val1", "env2": "val2"},
}
return reflect.DeepEqual(config, checkConfig)
return cmp.Diff(checkConfig, config) == ""
},
},
}
@@ -614,8 +614,8 @@ func Test_getPortsAndEnvVar(t *testing.T) {
t.Errorf("getPortsAndEnvVar() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getPortsAndEnvVar() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("getPortsAndEnvVar mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,10 +1,12 @@
package kclient
import (
"reflect"
"testing"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/jsonreference"
"github.com/go-openapi/spec"
"github.com/google/go-cmp/cmp"
olm "github.com/operator-framework/api/pkg/operators/v1alpha1"
)
@@ -85,8 +87,8 @@ func TestGetResourceSpecDefinitionFromSwagger(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, gotErr := getResourceSpecDefinitionFromSwagger(tt.swagger, tt.group, tt.version, tt.kind)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("expected %+v\n\ngot %+v", tt.want, got)
if diff := cmp.Diff(tt.want, got, cmp.AllowUnexported(jsonreference.Ref{}, jsonpointer.Pointer{})); diff != "" {
t.Errorf("getResourceSpecDefinitionFromSwagger mismatch (-want +got):\n%s", diff)
}
if (gotErr != nil) != tt.wantErr {
t.Errorf("Expected error %v, got %v", tt.wantErr, gotErr)
@@ -203,8 +205,8 @@ func TestToOpenAPISpec(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := toOpenAPISpec(&tt.repr)
if !reflect.DeepEqual(*result, tt.want) {
t.Errorf("Failed %s:\n\ngot: %+v\n\nwant: %+v", t.Name(), result, tt.want)
if diff := cmp.Diff(tt.want, *result, cmp.AllowUnexported(jsonreference.Ref{}, jsonpointer.Pointer{})); diff != "" {
t.Errorf("toOpenAPISpec mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -2,11 +2,11 @@ package kclient
import (
"fmt"
"reflect"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -100,8 +100,8 @@ func TestGetOnePodFromSelector(t *testing.T) {
} else if tt.wantErr && err != nil {
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetOnePodFromSelector() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Client.GetRunningPodFromSelector() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -149,8 +149,8 @@ func TestGetPodUsingComponentName(t *testing.T) {
t.Errorf("GetPodUsingComponentName() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetPodUsingComponentName() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Client.GetPodUsingComponentName() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -2,16 +2,17 @@ package kclient
import (
"fmt"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
projectv1 "github.com/openshift/api/project/v1"
"github.com/redhat-developer/odo/pkg/testingutil"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
ktesting "k8s.io/client-go/testing"
"github.com/redhat-developer/odo/pkg/testingutil"
)
func TestCreateNewProject(t *testing.T) {
@@ -90,10 +91,13 @@ func TestCreateNewProject(t *testing.T) {
if tt.wait {
expectedFields := fields.OneTermEqualSelector("metadata.name", tt.projName)
gotFields := actions[0].(ktesting.WatchAction).GetWatchRestrictions().Fields
expectedFieldsReq := expectedFields.Requirements()
if !reflect.DeepEqual(expectedFields, gotFields) {
t.Errorf("Fields not matching: expected: %s, got %s", expectedFields, gotFields)
gotFields := actions[0].(ktesting.WatchAction).GetWatchRestrictions().Fields
gotFieldsReq := gotFields.Requirements()
if diff := cmp.Diff(expectedFieldsReq, gotFieldsReq); diff != "" {
t.Errorf("OneTermEqualSelector() fieldsReq mismatch (-want +got):\n%s", diff)
}
}
}
@@ -136,8 +140,8 @@ func TestListProjects(t *testing.T) {
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ListProjects() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Client.ListProjects() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -176,8 +180,8 @@ func TestListProjectNames(t *testing.T) {
t.Errorf("ListProjectNames() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ListProjectNames() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Client.ListProjectNames() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -2,9 +2,9 @@ package kclient
import (
"fmt"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/watch"
corev1 "k8s.io/api/core/v1"
@@ -221,8 +221,8 @@ func TestListSecrets(t *testing.T) {
secretsList, err := client.ListSecrets("")
if !reflect.DeepEqual(tt.output, secretsList) {
t.Errorf("expected output: %#v,got: %#v", tt.secretList, secretsList)
if diff := cmp.Diff(tt.output, secretsList); diff != "" {
t.Errorf("Client.ListSecrets() secretsList mismatch (-want +got):\n%s", diff)
}
if err == nil && !tt.wantErr {

View File

@@ -2,10 +2,10 @@ package kclient
import (
"fmt"
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/parser/data"
"github.com/google/go-cmp/cmp"
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/pkg/devfile/generator"
@@ -245,8 +245,8 @@ func TestListServices(t *testing.T) {
t.Errorf("ListServices() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ListServices() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Client.ListServices() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -314,8 +314,8 @@ func TestClient_GetOneServiceFromSelector(t *testing.T) {
t.Errorf("GetOneServiceFromSelector() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetOneServiceFromSelector() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Client.GetOneServiceFromSelector() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,10 +1,10 @@
package kclient
import (
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
)
@@ -92,8 +92,8 @@ func TestGetInputEnvVarsFromStrings(t *testing.T) {
envVars, err := GetInputEnvVarsFromStrings(tt.envVars)
if err == nil && !tt.wantErr {
if !reflect.DeepEqual(tt.wantedEnvVars, envVars) {
t.Errorf("corev1.Env values are not matching with expected values, expected: %v, got %v", tt.wantedEnvVars, envVars)
if diff := cmp.Diff(tt.wantedEnvVars, envVars); diff != "" {
t.Errorf("GetInputEnvVarsFromStrings() wantedEnvVars mismatch (-want +got):\n%s", diff)
}
} else if err == nil && tt.wantErr {
t.Error("error was expected, but no error was returned")

View File

@@ -3,9 +3,10 @@ package kclient
import (
"errors"
"fmt"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/testingutil"
corev1 "k8s.io/api/core/v1"
@@ -234,8 +235,8 @@ func TestListPVCs(t *testing.T) {
if PVC.Name != tt.pvcName {
t.Errorf("TestGetPVCsFromSelector: PVC found with incorrect name, expected: %s actual: %s", tt.pvcName, PVC.Name)
}
if !reflect.DeepEqual(PVC.Labels, tt.labels) {
t.Errorf("TestGetPVCsFromSelector: Labels do not match with expected labels, expected: %s, got %s", tt.labels, PVC.Labels)
if diff := cmp.Diff(tt.labels, PVC.Labels); diff != "" {
t.Errorf("Client.ListPVCs() labels mismatch (-want +got):\n%s", diff)
}
}
}
@@ -342,8 +343,8 @@ func TestListPVCNames(t *testing.T) {
t.Errorf("ListPVCNames() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ListPVCNames() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Client.ListPVCNames() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,10 +1,10 @@
package labels
import (
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/validation"
@@ -70,8 +70,9 @@ func Test_getLabels(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getLabels(tt.args.componentName, tt.args.applicationName, ComponentDevMode, tt.args.additional, tt.args.isPartOfComponent); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetLabels() = %v, want %v", got, tt.want)
got := getLabels(tt.args.componentName, tt.args.applicationName, ComponentDevMode, tt.args.additional, tt.args.isPartOfComponent)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("getLabels() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -3,7 +3,6 @@ package libdevfile
import (
"fmt"
"os"
"reflect"
"testing"
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
@@ -13,6 +12,7 @@ import (
devfileFileSystem "github.com/devfile/library/pkg/testingutil/filesystem"
dfutil "github.com/devfile/library/pkg/util"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"k8s.io/utils/pointer"
"github.com/redhat-developer/odo/pkg/libdevfile/generator"
@@ -696,8 +696,8 @@ func TestGetContainerEndpointMapping(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
got := GetContainerEndpointMapping(tt.args.containers)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetContainerEndpointMapping() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetContainerEndpointMapping() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -800,8 +800,8 @@ func TestGetEndpointsFromDevfile(t *testing.T) {
t.Errorf("GetEndpointsFromDevfile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetEndpointsFromDevfile() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetEndpointsFromDevfile() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -1779,8 +1779,8 @@ func TestGetContainerComponentsForCommand(t *testing.T) {
if tt.wantErr != (err != nil) {
t.Errorf("unexpected error, wantErr: %v, err: %v", tt.wantErr, err)
}
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("want: %v, got %v", tt.want, got)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetContainerComponentsForCommand() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,7 +1,6 @@
package libdevfile
import (
"reflect"
"testing"
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
@@ -12,6 +11,7 @@ import (
context "github.com/devfile/library/pkg/devfile/parser/context"
"github.com/devfile/library/pkg/devfile/parser/data"
"github.com/devfile/library/pkg/testingutil/filesystem"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/libdevfile/generator"
@@ -357,8 +357,8 @@ func TestGetReferencedLocalFiles(t *testing.T) {
t.Errorf("GetReferencedLocalFiles() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotResult, tt.wantResult) {
t.Errorf("GetReferencedLocalFiles() = %v, want %v", gotResult, tt.wantResult)
if diff := cmp.Diff(tt.wantResult, gotResult); diff != "" {
t.Errorf("GetReferencedLocalFiles() wantResult mismatch (-want +got):\n%s", diff)
}
})
}
@@ -412,8 +412,8 @@ func Test_appendUriIfFile(t *testing.T) {
t.Errorf("appendUriIfFile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("appendUriIfFile() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("appendUriIfFile() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -519,8 +519,8 @@ func Test_getFromAttributes(t *testing.T) {
t.Errorf("getFromAttributes() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getFromAttributes() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("getFromAttributes() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -6,12 +6,12 @@ import (
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/parser"
"github.com/devfile/library/pkg/testingutil/filesystem"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -304,8 +304,9 @@ func Test_listResourcesMissingFromDevfilePresentOnCluster(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := listResourcesMissingFromDevfilePresentOnCluster(tt.args.componentName, tt.args.devfileResources, tt.args.clusterResources); !reflect.DeepEqual(got, tt.want) {
t.Errorf("listResourcesMissingFromDevfilePresentOnCluster() = %v, want %v", got, tt.want)
got := listResourcesMissingFromDevfilePresentOnCluster(tt.args.componentName, tt.args.devfileResources, tt.args.clusterResources)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("listResourcesMissingFromDevfilePresentOnCluster() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -6,10 +6,11 @@ import (
"io/fs"
"os"
"path/filepath"
"reflect"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
"github.com/redhat-developer/odo/pkg/util"
)
@@ -151,8 +152,8 @@ func TestGetFilesGeneratedByOdo(t *testing.T) {
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("expected %+q for stdout, got %+q", tt.want, got)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetFilesGeneratedByOdo() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,9 +1,10 @@
package portForward
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/api"
)
@@ -55,8 +56,8 @@ func Test_getForwardedPort(t *testing.T) {
t.Errorf("getForwardedPort() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getForwardedPort() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("getForwardedPort() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -5,11 +5,12 @@ import (
"fmt"
"io/ioutil"
"os"
"reflect"
"strconv"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/config"
envcontext "github.com/redhat-developer/odo/pkg/config/context"
@@ -71,9 +72,8 @@ func TestNew(t *testing.T) {
t.Errorf("expected test to fail, but it passed!")
}
}
if !reflect.DeepEqual(test.output, cfi) {
t.Errorf("expected output: %#v", test.output)
t.Errorf("actual output: %#v", cfi)
if diff := cmp.Diff(test.output, cfi); diff != "" {
t.Errorf("newPreferenceInfo() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -614,8 +614,8 @@ func TestHandleWithoutRegistryExist(t *testing.T) {
t.Logf("Error message is %v", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("handleWithoutRegistryExist() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -667,8 +667,8 @@ func TestHandleWithRegistryExist(t *testing.T) {
t.Logf("Error message is %v", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %v, want: %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("handleWithRegistryExist() mismatch (-want +got):\n%s", diff)
}
}
}

View File

@@ -1,12 +1,13 @@
package project
import (
"reflect"
"testing"
"github.com/golang/mock/gomock"
"github.com/redhat-developer/odo/pkg/kclient"
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/redhat-developer/odo/pkg/kclient"
)
func TestCreate(t *testing.T) {
@@ -236,8 +237,8 @@ func TestList(t *testing.T) {
return
}
if !reflect.DeepEqual(list, tt.expectedList) {
t.Errorf("Expected value:\n%+v\ngot:\n%+v", tt.expectedList, list)
if diff := cmp.Diff(tt.expectedList, list); diff != "" {
t.Errorf("Client.List() expectedList mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,9 +1,10 @@
package registry
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/api"
)
@@ -66,8 +67,9 @@ func TestDevfileStackList_GetLanguages(t *testing.T) {
o := &DevfileStackList{
Items: tt.fields.Items,
}
if got := o.GetLanguages(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("DevfileStackList.GetLanguages() = %v, want %v", got, tt.want)
got := o.GetLanguages()
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("DevfileStackList.GetLanguages() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -176,8 +178,9 @@ func TestDevfileStackList_GetProjectTypes(t *testing.T) {
o := &DevfileStackList{
Items: tt.fields.Items,
}
if got := o.GetProjectTypes(tt.args.language); !reflect.DeepEqual(got, tt.want) {
t.Errorf("DevfileStackList.GetProjectTypes() = \n%+v, want \n%+v", got, tt.want)
got := o.GetProjectTypes(tt.args.language)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("DevfileStackList.GetProjectTypes() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -6,11 +6,11 @@ import (
"net/http"
"net/http/httptest"
"os"
"reflect"
"testing"
"github.com/golang/mock/gomock"
"github.com/kylelemons/godebug/pretty"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/config"
@@ -88,8 +88,8 @@ OdoSettings:
t.Errorf("Error message is %v", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %v, want: %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("RegistryClient.GetDevfileRegistries() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -246,13 +246,7 @@ func TestListDevfileStacks(t *testing.T) {
{
name: "Case 4: Expect nothing back if registry is not found",
registryName: "Foobar",
want: DevfileStackList{
// We use "nil" here as reflect.DeepEqual() returns false if one slice is nil,
// and the other is a non-nil slice with 0 length.
// So we simply just say 'nil'
DevfileRegistries: nil,
Items: nil,
},
want: DevfileStackList{},
},
}
@@ -274,10 +268,8 @@ func TestListDevfileStacks(t *testing.T) {
t.Error(err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %+v \n\n Want: %+v", got, tt.want)
t.Errorf("Comparison: %v", pretty.Compare(got, tt.want))
t.Logf("Error message is: %v", err)
if diff := cmp.Diff(tt.want, got, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("RegistryClient.ListDevfileStacks() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -349,8 +341,8 @@ func TestGetRegistryDevfiles(t *testing.T) {
ctx = envcontext.WithEnvConfig(ctx, config.Configuration{})
got, err := getRegistryStacks(ctx, prefClient, tt.registry)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %v, want: %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("getRegistryStacks() mismatch (-want +got):\n%s", diff)
t.Logf("Error message is: %v", err)
}
})

View File

@@ -1,9 +1,10 @@
package registry
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/api"
)
@@ -48,8 +49,9 @@ func TestTypesWithDetails_GetOrderedLabels(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.types.GetOrderedLabels(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("TypesWithDetails.GetOrderedLabels() = %v, want %v", got, tt.want)
got := tt.types.GetOrderedLabels()
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetOrderedLabels() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -216,8 +218,8 @@ func TestTypesWithDetails_GetAtOrderedPosition(t *testing.T) {
t.Errorf("TypesWithDetails.GetAtOrderedPosition() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("TypesWithDetails.GetAtOrderedPosition() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetAtOrderedPosition() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -3,9 +3,10 @@ package registry
import (
"context"
"io/ioutil"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/config"
envcontext "github.com/redhat-developer/odo/pkg/config/context"
"github.com/redhat-developer/odo/pkg/preference"
@@ -64,8 +65,8 @@ func TestIsSecure(t *testing.T) {
}
got := IsSecure(cfg, tt.registryName)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %t, want %t", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("IsSecure() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -4,12 +4,12 @@ import (
"errors"
"fmt"
"io"
"reflect"
"sync"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/exec"
"github.com/redhat-developer/odo/pkg/kclient"
@@ -156,8 +156,8 @@ func TestKubeExecProcessHandler_GetProcessInfoForCommand(t *testing.T) {
if tt.wantErr != (err != nil) {
t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("expected %v, got %v", tt.want, got)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("kubeExecProcessHandler.GetProcessInfoForCommand() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -281,8 +281,8 @@ func TestKubeExecProcessHandler_StartProcessForCommand(t *testing.T) {
return
}
if !reflect.DeepEqual(tt.expectedStatuses, statusesReported) {
t.Errorf("expected %v, got %v", tt.expectedStatuses, statusesReported)
if diff := cmp.Diff(tt.expectedStatuses, statusesReported); diff != "" {
t.Errorf("kubeExecProcessHandler.StartProcessForCommand() expectedStatuses mismatch (-want +got):\n%s", diff)
}
})
}
@@ -566,8 +566,8 @@ func Test_getProcessInfoFromPid(t *testing.T) {
if tt.wantErr != (err != nil) {
t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("expected %v, got %v", tt.want, got)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("kubeExecProcessHandler.getProcessInfoFromPid() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -716,11 +716,11 @@ func Test_getRemoteProcessPID(t *testing.T) {
if tt.wantErr != (err != nil) {
t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(tt.wantPid, got) {
t.Errorf("expected PID %v, got %v", tt.wantPid, got)
if diff := cmp.Diff(tt.wantPid, got); diff != "" {
t.Errorf("kubeExecProcessHandler.getRemoteProcessPID() wantPid mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(tt.wantLastKnownExitCode, lastKnownExitStatus) {
t.Errorf("expected recorded exit code %v, got %v", tt.wantLastKnownExitCode, lastKnownExitStatus)
if diff := cmp.Diff(tt.wantLastKnownExitCode, lastKnownExitStatus); diff != "" {
t.Errorf("kubeExecProcessHandler.getRemoteProcessPID() wantLastKnownExitCode mismatch (-want +got):\n%s", diff)
}
})
}
@@ -944,10 +944,9 @@ func Test_getProcessChildren(t *testing.T) {
if tt.wantErr != (err != nil) {
t.Errorf("unexpected error %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("expected %v, got %v", tt.want, got)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("kubeExecProcessHandler.getProcessChildren() mismatch (-want +got):\n%s", diff)
}
})
}
}

View File

@@ -3,10 +3,10 @@ package context
import (
"context"
"fmt"
"reflect"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/spf13/pflag"
)
@@ -18,8 +18,8 @@ func TestGetContextProperties(t *testing.T) {
got := GetContextProperties(ctx)
want := map[string]interface{}{ckey: value}
if !reflect.DeepEqual(got, want) {
t.Errorf("want: %q got: %q", want, got)
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("GetContextProperties() mismatch (-want +got):\n%s", diff)
}
}

View File

@@ -2,10 +2,10 @@ package service
import (
"encoding/json"
"reflect"
"testing"
"github.com/go-openapi/spec"
"github.com/google/go-cmp/cmp"
)
func TestBuildCRDFromParams(t *testing.T) {
@@ -174,7 +174,8 @@ func TestBuildCRDFromParams(t *testing.T) {
t.Errorf("got err: %v, expected err: %v\n", gotErr != nil, tt.wantErr)
}
if gotErr == nil {
if !reflect.DeepEqual(got["spec"], tt.want) {
if diff := cmp.Diff(tt.want, got["spec"]); diff != "" {
t.Errorf("BuildCRDFromParams() mismatch (-want +got):\n%s", diff)
jsonGot, _ := json.Marshal(got["spec"])
jsonWant, _ := json.Marshal(tt.want)
t.Errorf("\ngot: %+v\n\nwant: %v\n", string(jsonGot), string(jsonWant))

View File

@@ -3,9 +3,10 @@ package service
import (
"os"
"path/filepath"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/devfile/consts"
devfiletesting "github.com/redhat-developer/odo/pkg/devfile/testing"
@@ -115,8 +116,8 @@ spec:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, gotErr := listDevfileLinks(tt.devfileObj, testFolderName, fs)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%s: got %v, expect %v", t.Name(), got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("listDevfileLinks() mismatch (-want +got):\n%s", diff)
}
if gotErr != tt.wantErr {
t.Errorf("%s: got %v, expect %v", t.Name(), gotErr, tt.wantErr)

View File

@@ -3,9 +3,10 @@ package state
import (
"encoding/json"
"fmt"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
)
@@ -63,8 +64,8 @@ func TestState_SetForwardedPorts(t *testing.T) {
return err
}
expected := []api.ForwardedPort{forwardedPort1}
if !reflect.DeepEqual(content.ForwardedPorts, expected) {
return fmt.Errorf("Forwarded ports is %+v, should be %+v", content.ForwardedPorts, expected)
if diff := cmp.Diff(expected, content.ForwardedPorts); diff != "" {
return fmt.Errorf("forwarded ports is %+v, should be %+v, diff: %s", content.ForwardedPorts, expected, diff)
}
return nil
},
@@ -198,8 +199,8 @@ func TestState_GetForwardedPorts(t *testing.T) {
t.Errorf("State.GetForwardedPorts() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("State.GetForwardedPorts() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("State.GetForwardedPorts() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,11 +1,11 @@
package storage
import (
"reflect"
"strings"
"testing"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
@@ -337,8 +337,8 @@ func Test_kubernetesClient_List(t *testing.T) {
t.Errorf("List() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("List() got = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("kubernetesClient.List() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -427,20 +427,20 @@ func Test_kubernetesClient_Create(t *testing.T) {
odolabels.AddStorageInfo(wantLabels, tt.args.storage.Name, strings.Contains(tt.args.storage.Name, OdoSourceVolume))
// created PVC should be labeled with labels passed to CreatePVC
if !reflect.DeepEqual(createdPVC.Labels, wantLabels) {
t.Errorf("labels in created pvc is not matching expected labels, expected: %v, got: %v", wantLabels, createdPVC.Labels)
if diff := cmp.Diff(wantLabels, createdPVC.Labels); diff != "" {
t.Errorf("kubernetesClient.Create() wantLabels mismatch (-want +got):\n%s", diff)
}
// name, size of createdPVC should be matching to size, name passed to CreatePVC
if !reflect.DeepEqual(createdPVC.Spec.Resources.Requests["storage"], quantity) {
t.Errorf("size of PVC is not matching to expected size, expected: %v, got %v", quantity, createdPVC.Spec.Resources.Requests["storage"])
if diff := cmp.Diff(quantity, createdPVC.Spec.Resources.Requests["storage"]); diff != "" {
t.Errorf("kubernetesClient.Create() quantity mismatch (-want +got):\n%s", diff)
}
wantedPVCName, err := generatePVCName(tt.args.storage.Name, tt.fields.generic.componentName, tt.fields.generic.appName)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if !reflect.DeepEqual(createdPVC.Name, wantedPVCName) {
t.Errorf("name of the PVC is not matching to expected name, expected: %v, got %v", wantedPVCName, createdPVC.Name)
if diff := cmp.Diff(wantedPVCName, createdPVC.Name); diff != "" {
t.Errorf("kubernetesClient.Create() wantedPVCName mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,12 +1,13 @@
package storage
import (
"reflect"
"testing"
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/pkg/devfile/parser"
"github.com/devfile/library/pkg/devfile/parser/data"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/testingutil"
)
@@ -228,8 +229,8 @@ func TestEnvInfo_ListStorage(t *testing.T) {
if (err != nil) != tt.wantErr {
t.Errorf("ListStorage() error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ListStorage() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("ListStorage() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -253,8 +253,8 @@ func TestPush(t *testing.T) {
for k := range ephemerals {
ephemeralKeys = append(ephemeralKeys, k)
}
if !reflect.DeepEqual(tt.wantEphemeralNames, ephemeralKeys) {
t.Errorf("Expected ephemeral names are %v, got %v\n", tt.wantEphemeralNames, ephemeralKeys)
if diff := cmp.Diff(tt.wantEphemeralNames, ephemeralKeys); diff != "" {
t.Errorf("Push() ephemeral names mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,9 +1,9 @@
package storage
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -51,8 +51,8 @@ func TestNewStorage(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotStorage := NewStorage(tt.storageName, tt.storageSize, tt.mountedPath, nil)
if !reflect.DeepEqual(tt.want, gotStorage) {
t.Errorf("the returned storage is different, expected: %v, got: %v", tt.want, gotStorage)
if diff := cmp.Diff(tt.want, gotStorage); diff != "" {
t.Errorf("NewStorage() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -175,8 +175,8 @@ func TestNewStorageList(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotStorage := NewStorageList(tt.inputStorage)
if !reflect.DeepEqual(tt.want, gotStorage) {
t.Errorf("the returned storage is different, expected: %v, got: %v", tt.want, gotStorage)
if diff := cmp.Diff(tt.want, gotStorage); diff != "" {
t.Errorf("NewStorageList() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -7,11 +7,11 @@ import (
"os"
"path"
"path/filepath"
"reflect"
"testing"
"github.com/devfile/library/pkg/devfile/generator"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/exec"
"github.com/redhat-developer/odo/pkg/kclient"
@@ -38,8 +38,8 @@ func TestGetCmdToCreateSyncFolder(t *testing.T) {
}
for _, tt := range tests {
cmdArr := getCmdToCreateSyncFolder(tt.syncFolder)
if !reflect.DeepEqual(tt.want, cmdArr) {
t.Errorf("Expected %s, got %s", tt.want, cmdArr)
if diff := cmp.Diff(tt.want, cmdArr); diff != "" {
t.Errorf("getCmdToCreateSyncFolder() mismatch (-want +got):\n%s", diff)
}
}
}
@@ -74,8 +74,8 @@ func TestGetCmdToDeleteFiles(t *testing.T) {
}
for _, tt := range tests {
cmdArr := getCmdToDeleteFiles(tt.delFiles, tt.syncFolder)
if !reflect.DeepEqual(tt.want, cmdArr) {
t.Errorf("Expected %s, got %s", tt.want, cmdArr)
if diff := cmp.Diff(tt.want, cmdArr); diff != "" {
t.Errorf("getCmdToDeleteFiles() mismatch (-want +got):\n%s", diff)
}
}
}

View File

@@ -4,12 +4,11 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
"testing"
"github.com/kylelemons/godebug/pretty"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
)
@@ -1097,23 +1096,23 @@ func Test_recursiveChecker(t *testing.T) {
return
}
sort.Strings(got.FilesDeleted)
sort.Strings(got.FilesChanged)
sort.Strings(got.RemoteDeleted)
if !reflect.DeepEqual(got.FilesChanged, tt.want.FilesChanged) {
t.Errorf("recursiveChecker() FilesChanged got = %v, want %v", got.FilesChanged, tt.want.FilesChanged)
sortOpt := cmpopts.SortSlices(func(x, y string) bool {
return x < y
})
if diff := cmp.Diff(tt.want.FilesChanged, got.FilesChanged, sortOpt); diff != "" {
t.Errorf("recursiveChecker() FilesChanged mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(got.FilesDeleted, tt.want.FilesDeleted) {
t.Errorf("recursiveChecker() FilesDeleted got = %v, want %v", got.FilesDeleted, tt.want.FilesDeleted)
if diff := cmp.Diff(tt.want.FilesDeleted, got.FilesDeleted, sortOpt); diff != "" {
t.Errorf("recursiveChecker() FilesDeleted mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(got.RemoteDeleted, tt.want.RemoteDeleted) {
t.Errorf("recursiveChecker() RemoteDeleted got = %v, want %v", got.RemoteDeleted, tt.want.RemoteDeleted)
if diff := cmp.Diff(tt.want.RemoteDeleted, got.RemoteDeleted, sortOpt); diff != "" {
t.Errorf("recursiveChecker() RemoteDeleted mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(tt.want.NewFileMap, got.NewFileMap) {
t.Errorf("recursiveChecker() new file map is different, difference = %v", pretty.Compare(got.NewFileMap, tt.want.NewFileMap))
if diff := cmp.Diff(tt.want.NewFileMap, got.NewFileMap); diff != "" {
t.Errorf("recursiveChecker() NewFileMap mismatch (-want +got):\n%s", diff)
}
})
}
@@ -1604,23 +1603,22 @@ func Test_runIndexerWithExistingFileIndex(t *testing.T) {
return
}
sort.Strings(gotRet.FilesDeleted)
sort.Strings(gotRet.FilesChanged)
sort.Strings(gotRet.RemoteDeleted)
if !reflect.DeepEqual(gotRet.FilesChanged, tt.wantRet.FilesChanged) {
t.Errorf("runIndexerWithExistingFileIndex() fileChanged gotRet = %v, want %v", gotRet.FilesChanged, tt.wantRet.FilesChanged)
sortOpt := cmpopts.SortSlices(func(x, y string) bool {
return x < y
})
if diff := cmp.Diff(tt.wantRet.FilesChanged, gotRet.FilesChanged, sortOpt); diff != "" {
t.Errorf("runIndexerWithExistingFileIndex() FilesChanged mismatch (-want +got):\n%s", diff)
}
if diff := cmp.Diff(tt.wantRet.NewFileMap, gotRet.NewFileMap); diff != "" {
t.Errorf("runIndexerWithExistingFileIndex() NewFileMap mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(gotRet.NewFileMap, tt.wantRet.NewFileMap) {
t.Errorf("runIndexerWithExistingFileIndex() new file map is different = %v", pretty.Compare(gotRet.NewFileMap, tt.wantRet.NewFileMap))
if diff := cmp.Diff(tt.wantRet.FilesDeleted, gotRet.FilesDeleted, sortOpt); diff != "" {
t.Errorf("runIndexerWithExistingFileIndex() FilesDeleted mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(gotRet.FilesDeleted, tt.wantRet.FilesDeleted) {
t.Errorf("runIndexerWithExistingFileIndex() files deleted gotRet = %v, want %v", gotRet.FilesDeleted, tt.wantRet.FilesDeleted)
}
if !reflect.DeepEqual(gotRet.RemoteDeleted, tt.wantRet.RemoteDeleted) {
t.Errorf("runIndexerWithExistingFileIndex() files remote changed gotRet = %v, want %v", gotRet.RemoteDeleted, tt.wantRet.RemoteDeleted)
if diff := cmp.Diff(tt.wantRet.RemoteDeleted, gotRet.RemoteDeleted, sortOpt); diff != "" {
t.Errorf("runIndexerWithExistingFileIndex() RemoteDeleted mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -12,7 +12,6 @@ import (
"os"
"os/user"
"path/filepath"
"reflect"
"regexp"
"runtime"
"strconv"
@@ -21,6 +20,7 @@ import (
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/google/go-cmp/cmp"
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
dfutil "github.com/devfile/library/pkg/util"
@@ -625,8 +625,8 @@ func TestGetIgnoreRulesFromDirectory(t *testing.T) {
gotRules, err := dfutil.GetIgnoreRulesFromDirectory(testDir)
if err == nil && !tt.wantErr {
if !reflect.DeepEqual(gotRules, tt.wantRules) {
t.Errorf("the expected value of rules are different, excepted: %v, got: %v", tt.wantRules, gotRules)
if diff := cmp.Diff(tt.wantRules, gotRules); diff != "" {
t.Errorf("dfutil.GetIgnoreRulesFromDirectory() wantRules mismatch (-want +got):\n%s", diff)
}
} else if err == nil && tt.wantErr {
t.Error("error was expected, but no error was returned")
@@ -678,8 +678,8 @@ func TestGetAbsGlobExps(t *testing.T) {
}
}
if !reflect.DeepEqual(resultExps, tt.expectedGlobExps) {
t.Errorf("expected %v, got %v", tt.expectedGlobExps, resultExps)
if diff := cmp.Diff(tt.expectedGlobExps, resultExps); diff != "" {
t.Errorf("dfutil.GetAbsGlobExps() expectedGlobExps mismatch (-want +got):\n%s", diff)
}
})
}
@@ -702,8 +702,8 @@ func TestGetSortedKeys(t *testing.T) {
t.Log("Running test: ", tt.testName)
t.Run(tt.testName, func(t *testing.T) {
actual := dfutil.GetSortedKeys(tt.input)
if !reflect.DeepEqual(tt.expected, actual) {
t.Errorf("expected: %+v, got: %+v", tt.expected, actual)
if diff := cmp.Diff(tt.expected, actual); diff != "" {
t.Errorf("dfutil.GetSortedKeys() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -736,8 +736,8 @@ func TestGetSplitValuesFromStr(t *testing.T) {
t.Log("Running test: ", tt.testName)
t.Run(tt.testName, func(t *testing.T) {
actual := dfutil.GetSplitValuesFromStr(tt.input)
if !reflect.DeepEqual(tt.expected, actual) {
t.Errorf("expected: %+v, got: %+v", tt.expected, actual)
if diff := cmp.Diff(tt.expected, actual); diff != "" {
t.Errorf("dfutil.GetSplitValuesFromStr() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -821,8 +821,8 @@ func TestGetContainerPortsFromStrings(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
ports, err := dfutil.GetContainerPortsFromStrings(tt.ports)
if err == nil && !tt.wantErr {
if !reflect.DeepEqual(tt.containerPorts, ports) {
t.Errorf("the ports are not matching, expected %#v, got %#v", tt.containerPorts, ports)
if diff := cmp.Diff(tt.containerPorts, ports); diff != "" {
t.Errorf("dfutil.GetContainerPortsFromStrings() containerPorts mismatch (-want +got):\n%s", diff)
}
} else if err == nil && tt.wantErr {
t.Error("error was expected, but no error was returned")
@@ -956,8 +956,8 @@ func TestRemoveRelativePathFromFiles(t *testing.T) {
return
}
if !(reflect.DeepEqual(output, tt.args.output)) {
t.Errorf("expected %v, got %v", tt.args.output, output)
if diff := cmp.Diff(tt.args.output, output); diff != "" {
t.Errorf("dfutil.RemoveRelativePathFromFiles() output mismatch (-want +got):\n%s", diff)
}
})
@@ -1027,8 +1027,8 @@ func TestGetRemoteFilesMarkedForDeletion(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
remoteFiles := dfutil.GetRemoteFilesMarkedForDeletion(tt.files, tt.remotePath)
if !reflect.DeepEqual(tt.want, remoteFiles) {
t.Errorf("Expected %s, got %s", tt.want, remoteFiles)
if diff := cmp.Diff(tt.want, remoteFiles); diff != "" {
t.Errorf("dfutil.GetRemoteFilesMarkedForDeletion() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -1072,8 +1072,8 @@ func TestHTTPGetRequest(t *testing.T) {
}
got, err := dfutil.HTTPGetRequest(request, 0)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %v, want: %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("dfutil.HTTPGetRequest() mismatch (-want +got):\n%s", diff)
t.Logf("Error message is: %v", err)
}
})
@@ -1127,12 +1127,12 @@ func TestFilterIgnores(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
filterChanged, filterDeleted := dfutil.FilterIgnores(tt.changedFiles, tt.deletedFiles, tt.ignoredFiles)
if !reflect.DeepEqual(tt.wantChangedFiles, filterChanged) {
t.Errorf("Expected %s, got %s", tt.wantChangedFiles, filterChanged)
if diff := cmp.Diff(tt.wantChangedFiles, filterChanged); diff != "" {
t.Errorf("dfutil.FilterIgnores() wantChangedFiles mismatch (-want +got):\n%s", diff)
}
if !reflect.DeepEqual(tt.wantDeletedFiles, filterDeleted) {
t.Errorf("Expected %s, got %s", tt.wantDeletedFiles, filterDeleted)
if diff := cmp.Diff(tt.wantDeletedFiles, filterDeleted); diff != "" {
t.Errorf("dfutil.FilterIgnores() wantDeletedFiles mismatch (-want +got):\n%s", diff)
}
})
}
@@ -1195,8 +1195,8 @@ func TestDownloadFile(t *testing.T) {
if err != nil {
gotErr = true
}
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Error("Failed to get expected error")
if gotErr != tt.wantErr {
t.Errorf("Failed to get expected error: %v", err)
}
if !tt.wantErr {
@@ -1209,8 +1209,8 @@ func TestDownloadFile(t *testing.T) {
t.Errorf("Failed to read file with error %s", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %v, want: %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("dfutil.DownloadFile() mismatch (-want +got):\n%s", diff)
}
// Clean up the file that downloaded in this test case
@@ -1254,8 +1254,8 @@ func TestValidateK8sResourceName(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
err := dfutil.ValidateK8sResourceName(tt.key, tt.value)
got := err == nil
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got %t, want %t", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("dfutil.ValidateK8sResourceName() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -1426,8 +1426,10 @@ func TestIsValidProjectDir(t *testing.T) {
expectedError = fmt.Sprintf(expectedError, tmpDir)
}
if err != nil && !reflect.DeepEqual(err.Error(), expectedError) {
t.Errorf("Got err: %s, expected err %s", err.Error(), expectedError)
if err != nil {
if diff := cmp.Diff(expectedError, err.Error()); diff != "" {
t.Errorf("IsValidProjectDir() mismatch (-want +got):\n%s", diff)
}
}
})
}
@@ -1469,8 +1471,8 @@ func TestDownloadFileInMemory(t *testing.T) {
t.Errorf("Failed to download file with error %s", err)
}
if !reflect.DeepEqual(data, tt.want) {
t.Errorf("Got: %v, want: %v", data, tt.want)
if diff := cmp.Diff(tt.want, data); diff != "" {
t.Errorf("DownloadFileInMemory() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -1565,7 +1567,7 @@ func TestValidateURL(t *testing.T) {
gotErr = true
}
if !reflect.DeepEqual(gotErr, tt.wantErr) {
if gotErr != tt.wantErr {
t.Errorf("Got %v, want %v", got, tt.wantErr)
}
})
@@ -1608,8 +1610,8 @@ func TestValidateFile(t *testing.T) {
if err != nil {
gotErr = true
}
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Errorf("Got error: %t, want error: %t", gotErr, tt.wantErr)
if gotErr != tt.wantErr {
t.Errorf("Got error: %v, want error: %t", err, tt.wantErr)
}
})
}
@@ -1668,8 +1670,8 @@ func TestCopyFile(t *testing.T) {
gotErr = true
}
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Errorf("Got error: %t, want error: %t", gotErr, tt.wantErr)
if gotErr != tt.wantErr {
t.Errorf("Got error: %v, want error: %t", err, tt.wantErr)
}
})
}
@@ -1712,8 +1714,8 @@ func TestPathEqual(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := dfutil.PathEqual(tt.firstPath, tt.secondPath)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Got: %t, want %t", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("dfutil.PathEqual() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -1750,8 +1752,8 @@ func TestSliceContainsString(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
gotVal := sliceContainsString(tt.stringVal, tt.slice)
if !reflect.DeepEqual(gotVal, tt.wantVal) {
t.Errorf("Got %v, want %v", gotVal, tt.wantVal)
if diff := cmp.Diff(tt.wantVal, gotVal); diff != "" {
t.Errorf("sliceContainsString() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -2692,8 +2694,8 @@ func TestDisplayLog(t *testing.T) {
}
lines = append(lines, line)
}
if !reflect.DeepEqual(lines, tt.want) {
t.Errorf("expected %v, got %v", tt.want, lines)
if diff := cmp.Diff(tt.want, lines); diff != "" {
t.Errorf("DisplayLog() mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -1,9 +1,10 @@
package vars
import (
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
)
@@ -92,8 +93,8 @@ G
t.Errorf("parseKeyValueFile() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseKeyValueFile() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("parseKeyValueFile() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -164,8 +165,8 @@ func Test_parseKeyValueStrings(t *testing.T) {
t.Errorf("parseKeyValueStrings() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseKeyValueStrings() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("parseKeyValueStrings() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -311,8 +312,8 @@ func TestGetVariables(t *testing.T) {
t.Errorf("GetVariables() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetVariables() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetVariables() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -355,8 +356,8 @@ func TestGetVariablesEmptyFilename(t *testing.T) {
t.Errorf("GetVariables() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetVariables() = %v, want %v", got, tt.want)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("GetVariables() mismatch (-want +got):\n%s", diff)
}
})
}

156
vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go generated vendored Normal file
View File

@@ -0,0 +1,156 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package cmpopts provides common options for the cmp package.
package cmpopts
import (
"errors"
"math"
"reflect"
"time"
"github.com/google/go-cmp/cmp"
)
func equateAlways(_, _ interface{}) bool { return true }
// EquateEmpty returns a Comparer option that determines all maps and slices
// with a length of zero to be equal, regardless of whether they are nil.
//
// EquateEmpty can be used in conjunction with SortSlices and SortMaps.
func EquateEmpty() cmp.Option {
return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways))
}
func isEmpty(x, y interface{}) bool {
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
return (x != nil && y != nil && vx.Type() == vy.Type()) &&
(vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) &&
(vx.Len() == 0 && vy.Len() == 0)
}
// EquateApprox returns a Comparer option that determines float32 or float64
// values to be equal if they are within a relative fraction or absolute margin.
// This option is not used when either x or y is NaN or infinite.
//
// The fraction determines that the difference of two values must be within the
// smaller fraction of the two values, while the margin determines that the two
// values must be within some absolute margin.
// To express only a fraction or only a margin, use 0 for the other parameter.
// The fraction and margin must be non-negative.
//
// The mathematical expression used is equivalent to:
//
// |x-y| ≤ max(fraction*min(|x|, |y|), margin)
//
// EquateApprox can be used in conjunction with EquateNaNs.
func EquateApprox(fraction, margin float64) cmp.Option {
if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) {
panic("margin or fraction must be a non-negative number")
}
a := approximator{fraction, margin}
return cmp.Options{
cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)),
cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)),
}
}
type approximator struct{ frac, marg float64 }
func areRealF64s(x, y float64) bool {
return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0)
}
func areRealF32s(x, y float32) bool {
return areRealF64s(float64(x), float64(y))
}
func (a approximator) compareF64(x, y float64) bool {
relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y))
return math.Abs(x-y) <= math.Max(a.marg, relMarg)
}
func (a approximator) compareF32(x, y float32) bool {
return a.compareF64(float64(x), float64(y))
}
// EquateNaNs returns a Comparer option that determines float32 and float64
// NaN values to be equal.
//
// EquateNaNs can be used in conjunction with EquateApprox.
func EquateNaNs() cmp.Option {
return cmp.Options{
cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)),
cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)),
}
}
func areNaNsF64s(x, y float64) bool {
return math.IsNaN(x) && math.IsNaN(y)
}
func areNaNsF32s(x, y float32) bool {
return areNaNsF64s(float64(x), float64(y))
}
// EquateApproxTime returns a Comparer option that determines two non-zero
// time.Time values to be equal if they are within some margin of one another.
// If both times have a monotonic clock reading, then the monotonic time
// difference will be used. The margin must be non-negative.
func EquateApproxTime(margin time.Duration) cmp.Option {
if margin < 0 {
panic("margin must be a non-negative number")
}
a := timeApproximator{margin}
return cmp.FilterValues(areNonZeroTimes, cmp.Comparer(a.compare))
}
func areNonZeroTimes(x, y time.Time) bool {
return !x.IsZero() && !y.IsZero()
}
type timeApproximator struct {
margin time.Duration
}
func (a timeApproximator) compare(x, y time.Time) bool {
// Avoid subtracting times to avoid overflow when the
// difference is larger than the largest representable duration.
if x.After(y) {
// Ensure x is always before y
x, y = y, x
}
// We're within the margin if x+margin >= y.
// Note: time.Time doesn't have AfterOrEqual method hence the negation.
return !x.Add(a.margin).Before(y)
}
// AnyError is an error that matches any non-nil error.
var AnyError anyError
type anyError struct{}
func (anyError) Error() string { return "any error" }
func (anyError) Is(err error) bool { return err != nil }
// EquateErrors returns a Comparer option that determines errors to be equal
// if errors.Is reports them to match. The AnyError error can be used to
// match any non-nil error.
func EquateErrors() cmp.Option {
return cmp.FilterValues(areConcreteErrors, cmp.Comparer(compareErrors))
}
// areConcreteErrors reports whether x and y are types that implement error.
// The input types are deliberately of the interface{} type rather than the
// error type so that we can handle situations where the current type is an
// interface{}, but the underlying concrete types both happen to implement
// the error interface.
func areConcreteErrors(x, y interface{}) bool {
_, ok1 := x.(error)
_, ok2 := y.(error)
return ok1 && ok2
}
func compareErrors(x, y interface{}) bool {
xe := x.(error)
ye := y.(error)
return errors.Is(xe, ye) || errors.Is(ye, xe)
}

206
vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go generated vendored Normal file
View File

@@ -0,0 +1,206 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"fmt"
"reflect"
"unicode"
"unicode/utf8"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/internal/function"
)
// IgnoreFields returns an Option that ignores fields of the
// given names on a single struct type. It respects the names of exported fields
// that are forwarded due to struct embedding.
// The struct type is specified by passing in a value of that type.
//
// The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a
// specific sub-field that is embedded or nested within the parent struct.
func IgnoreFields(typ interface{}, names ...string) cmp.Option {
sf := newStructFilter(typ, names...)
return cmp.FilterPath(sf.filter, cmp.Ignore())
}
// IgnoreTypes returns an Option that ignores all values assignable to
// certain types, which are specified by passing in a value of each type.
func IgnoreTypes(typs ...interface{}) cmp.Option {
tf := newTypeFilter(typs...)
return cmp.FilterPath(tf.filter, cmp.Ignore())
}
type typeFilter []reflect.Type
func newTypeFilter(typs ...interface{}) (tf typeFilter) {
for _, typ := range typs {
t := reflect.TypeOf(typ)
if t == nil {
// This occurs if someone tries to pass in sync.Locker(nil)
panic("cannot determine type; consider using IgnoreInterfaces")
}
tf = append(tf, t)
}
return tf
}
func (tf typeFilter) filter(p cmp.Path) bool {
if len(p) < 1 {
return false
}
t := p.Last().Type()
for _, ti := range tf {
if t.AssignableTo(ti) {
return true
}
}
return false
}
// IgnoreInterfaces returns an Option that ignores all values or references of
// values assignable to certain interface types. These interfaces are specified
// by passing in an anonymous struct with the interface types embedded in it.
// For example, to ignore sync.Locker, pass in struct{sync.Locker}{}.
func IgnoreInterfaces(ifaces interface{}) cmp.Option {
tf := newIfaceFilter(ifaces)
return cmp.FilterPath(tf.filter, cmp.Ignore())
}
type ifaceFilter []reflect.Type
func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) {
t := reflect.TypeOf(ifaces)
if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct {
panic("input must be an anonymous struct")
}
for i := 0; i < t.NumField(); i++ {
fi := t.Field(i)
switch {
case !fi.Anonymous:
panic("struct cannot have named fields")
case fi.Type.Kind() != reflect.Interface:
panic("embedded field must be an interface type")
case fi.Type.NumMethod() == 0:
// This matches everything; why would you ever want this?
panic("cannot ignore empty interface")
default:
tf = append(tf, fi.Type)
}
}
return tf
}
func (tf ifaceFilter) filter(p cmp.Path) bool {
if len(p) < 1 {
return false
}
t := p.Last().Type()
for _, ti := range tf {
if t.AssignableTo(ti) {
return true
}
if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) {
return true
}
}
return false
}
// IgnoreUnexported returns an Option that only ignores the immediate unexported
// fields of a struct, including anonymous fields of unexported types.
// In particular, unexported fields within the struct's exported fields
// of struct types, including anonymous fields, will not be ignored unless the
// type of the field itself is also passed to IgnoreUnexported.
//
// Avoid ignoring unexported fields of a type which you do not control (i.e. a
// type from another repository), as changes to the implementation of such types
// may change how the comparison behaves. Prefer a custom Comparer instead.
func IgnoreUnexported(typs ...interface{}) cmp.Option {
ux := newUnexportedFilter(typs...)
return cmp.FilterPath(ux.filter, cmp.Ignore())
}
type unexportedFilter struct{ m map[reflect.Type]bool }
func newUnexportedFilter(typs ...interface{}) unexportedFilter {
ux := unexportedFilter{m: make(map[reflect.Type]bool)}
for _, typ := range typs {
t := reflect.TypeOf(typ)
if t == nil || t.Kind() != reflect.Struct {
panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
}
ux.m[t] = true
}
return ux
}
func (xf unexportedFilter) filter(p cmp.Path) bool {
sf, ok := p.Index(-1).(cmp.StructField)
if !ok {
return false
}
return xf.m[p.Index(-2).Type()] && !isExported(sf.Name())
}
// isExported reports whether the identifier is exported.
func isExported(id string) bool {
r, _ := utf8.DecodeRuneInString(id)
return unicode.IsUpper(r)
}
// IgnoreSliceElements returns an Option that ignores elements of []V.
// The discard function must be of the form "func(T) bool" which is used to
// ignore slice elements of type V, where V is assignable to T.
// Elements are ignored if the function reports true.
func IgnoreSliceElements(discardFunc interface{}) cmp.Option {
vf := reflect.ValueOf(discardFunc)
if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() {
panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
}
return cmp.FilterPath(func(p cmp.Path) bool {
si, ok := p.Index(-1).(cmp.SliceIndex)
if !ok {
return false
}
if !si.Type().AssignableTo(vf.Type().In(0)) {
return false
}
vx, vy := si.Values()
if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() {
return true
}
if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() {
return true
}
return false
}, cmp.Ignore())
}
// IgnoreMapEntries returns an Option that ignores entries of map[K]V.
// The discard function must be of the form "func(T, R) bool" which is used to
// ignore map entries of type K and V, where K and V are assignable to T and R.
// Entries are ignored if the function reports true.
func IgnoreMapEntries(discardFunc interface{}) cmp.Option {
vf := reflect.ValueOf(discardFunc)
if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() {
panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
}
return cmp.FilterPath(func(p cmp.Path) bool {
mi, ok := p.Index(-1).(cmp.MapIndex)
if !ok {
return false
}
if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) {
return false
}
k := mi.Key()
vx, vy := mi.Values()
if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() {
return true
}
if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() {
return true
}
return false
}, cmp.Ignore())
}

147
vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go generated vendored Normal file
View File

@@ -0,0 +1,147 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"fmt"
"reflect"
"sort"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/internal/function"
)
// SortSlices returns a Transformer option that sorts all []V.
// The less function must be of the form "func(T, T) bool" which is used to
// sort any slice with element type V that is assignable to T.
//
// The less function must be:
// - Deterministic: less(x, y) == less(x, y)
// - Irreflexive: !less(x, x)
// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
//
// The less function does not have to be "total". That is, if !less(x, y) and
// !less(y, x) for two elements x and y, their relative order is maintained.
//
// SortSlices can be used in conjunction with EquateEmpty.
func SortSlices(lessFunc interface{}) cmp.Option {
vf := reflect.ValueOf(lessFunc)
if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
panic(fmt.Sprintf("invalid less function: %T", lessFunc))
}
ss := sliceSorter{vf.Type().In(0), vf}
return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort))
}
type sliceSorter struct {
in reflect.Type // T
fnc reflect.Value // func(T, T) bool
}
func (ss sliceSorter) filter(x, y interface{}) bool {
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
if !(x != nil && y != nil && vx.Type() == vy.Type()) ||
!(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) ||
(vx.Len() <= 1 && vy.Len() <= 1) {
return false
}
// Check whether the slices are already sorted to avoid an infinite
// recursion cycle applying the same transform to itself.
ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) })
ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) })
return !ok1 || !ok2
}
func (ss sliceSorter) sort(x interface{}) interface{} {
src := reflect.ValueOf(x)
dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len())
for i := 0; i < src.Len(); i++ {
dst.Index(i).Set(src.Index(i))
}
sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) })
ss.checkSort(dst)
return dst.Interface()
}
func (ss sliceSorter) checkSort(v reflect.Value) {
start := -1 // Start of a sequence of equal elements.
for i := 1; i < v.Len(); i++ {
if ss.less(v, i-1, i) {
// Check that first and last elements in v[start:i] are equal.
if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) {
panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i)))
}
start = -1
} else if start == -1 {
start = i
}
}
}
func (ss sliceSorter) less(v reflect.Value, i, j int) bool {
vx, vy := v.Index(i), v.Index(j)
return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
}
// SortMaps returns a Transformer option that flattens map[K]V types to be a
// sorted []struct{K, V}. The less function must be of the form
// "func(T, T) bool" which is used to sort any map with key K that is
// assignable to T.
//
// Flattening the map into a slice has the property that cmp.Equal is able to
// use Comparers on K or the K.Equal method if it exists.
//
// The less function must be:
// - Deterministic: less(x, y) == less(x, y)
// - Irreflexive: !less(x, x)
// - Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
// - Total: if x != y, then either less(x, y) or less(y, x)
//
// SortMaps can be used in conjunction with EquateEmpty.
func SortMaps(lessFunc interface{}) cmp.Option {
vf := reflect.ValueOf(lessFunc)
if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
panic(fmt.Sprintf("invalid less function: %T", lessFunc))
}
ms := mapSorter{vf.Type().In(0), vf}
return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort))
}
type mapSorter struct {
in reflect.Type // T
fnc reflect.Value // func(T, T) bool
}
func (ms mapSorter) filter(x, y interface{}) bool {
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
return (x != nil && y != nil && vx.Type() == vy.Type()) &&
(vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) &&
(vx.Len() != 0 || vy.Len() != 0)
}
func (ms mapSorter) sort(x interface{}) interface{} {
src := reflect.ValueOf(x)
outType := reflect.StructOf([]reflect.StructField{
{Name: "K", Type: src.Type().Key()},
{Name: "V", Type: src.Type().Elem()},
})
dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len())
for i, k := range src.MapKeys() {
v := reflect.New(outType).Elem()
v.Field(0).Set(k)
v.Field(1).Set(src.MapIndex(k))
dst.Index(i).Set(v)
}
sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) })
ms.checkSort(dst)
return dst.Interface()
}
func (ms mapSorter) checkSort(v reflect.Value) {
for i := 1; i < v.Len(); i++ {
if !ms.less(v, i-1, i) {
panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i)))
}
}
}
func (ms mapSorter) less(v reflect.Value, i, j int) bool {
vx, vy := v.Index(i).Field(0), v.Index(j).Field(0)
return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
}

View File

@@ -0,0 +1,189 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"fmt"
"reflect"
"strings"
"github.com/google/go-cmp/cmp"
)
// filterField returns a new Option where opt is only evaluated on paths that
// include a specific exported field on a single struct type.
// The struct type is specified by passing in a value of that type.
//
// The name may be a dot-delimited string (e.g., "Foo.Bar") to select a
// specific sub-field that is embedded or nested within the parent struct.
func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option {
// TODO: This is currently unexported over concerns of how helper filters
// can be composed together easily.
// TODO: Add tests for FilterField.
sf := newStructFilter(typ, name)
return cmp.FilterPath(sf.filter, opt)
}
type structFilter struct {
t reflect.Type // The root struct type to match on
ft fieldTree // Tree of fields to match on
}
func newStructFilter(typ interface{}, names ...string) structFilter {
// TODO: Perhaps allow * as a special identifier to allow ignoring any
// number of path steps until the next field match?
// This could be useful when a concrete struct gets transformed into
// an anonymous struct where it is not possible to specify that by type,
// but the transformer happens to provide guarantees about the names of
// the transformed fields.
t := reflect.TypeOf(typ)
if t == nil || t.Kind() != reflect.Struct {
panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
}
var ft fieldTree
for _, name := range names {
cname, err := canonicalName(t, name)
if err != nil {
panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err))
}
ft.insert(cname)
}
return structFilter{t, ft}
}
func (sf structFilter) filter(p cmp.Path) bool {
for i, ps := range p {
if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) {
return true
}
}
return false
}
// fieldTree represents a set of dot-separated identifiers.
//
// For example, inserting the following selectors:
//
// Foo
// Foo.Bar.Baz
// Foo.Buzz
// Nuka.Cola.Quantum
//
// Results in a tree of the form:
//
// {sub: {
// "Foo": {ok: true, sub: {
// "Bar": {sub: {
// "Baz": {ok: true},
// }},
// "Buzz": {ok: true},
// }},
// "Nuka": {sub: {
// "Cola": {sub: {
// "Quantum": {ok: true},
// }},
// }},
// }}
type fieldTree struct {
ok bool // Whether this is a specified node
sub map[string]fieldTree // The sub-tree of fields under this node
}
// insert inserts a sequence of field accesses into the tree.
func (ft *fieldTree) insert(cname []string) {
if ft.sub == nil {
ft.sub = make(map[string]fieldTree)
}
if len(cname) == 0 {
ft.ok = true
return
}
sub := ft.sub[cname[0]]
sub.insert(cname[1:])
ft.sub[cname[0]] = sub
}
// matchPrefix reports whether any selector in the fieldTree matches
// the start of path p.
func (ft fieldTree) matchPrefix(p cmp.Path) bool {
for _, ps := range p {
switch ps := ps.(type) {
case cmp.StructField:
ft = ft.sub[ps.Name()]
if ft.ok {
return true
}
if len(ft.sub) == 0 {
return false
}
case cmp.Indirect:
default:
return false
}
}
return false
}
// canonicalName returns a list of identifiers where any struct field access
// through an embedded field is expanded to include the names of the embedded
// types themselves.
//
// For example, suppose field "Foo" is not directly in the parent struct,
// but actually from an embedded struct of type "Bar". Then, the canonical name
// of "Foo" is actually "Bar.Foo".
//
// Suppose field "Foo" is not directly in the parent struct, but actually
// a field in two different embedded structs of types "Bar" and "Baz".
// Then the selector "Foo" causes a panic since it is ambiguous which one it
// refers to. The user must specify either "Bar.Foo" or "Baz.Foo".
func canonicalName(t reflect.Type, sel string) ([]string, error) {
var name string
sel = strings.TrimPrefix(sel, ".")
if sel == "" {
return nil, fmt.Errorf("name must not be empty")
}
if i := strings.IndexByte(sel, '.'); i < 0 {
name, sel = sel, ""
} else {
name, sel = sel[:i], sel[i:]
}
// Type must be a struct or pointer to struct.
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("%v must be a struct", t)
}
// Find the canonical name for this current field name.
// If the field exists in an embedded struct, then it will be expanded.
sf, _ := t.FieldByName(name)
if !isExported(name) {
// Avoid using reflect.Type.FieldByName for unexported fields due to
// buggy behavior with regard to embeddeding and unexported fields.
// See https://golang.org/issue/4876 for details.
sf = reflect.StructField{}
for i := 0; i < t.NumField() && sf.Name == ""; i++ {
if t.Field(i).Name == name {
sf = t.Field(i)
}
}
}
if sf.Name == "" {
return []string{name}, fmt.Errorf("does not exist")
}
var ss []string
for i := range sf.Index {
ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name)
}
if sel == "" {
return ss, nil
}
ssPost, err := canonicalName(sf.Type, sel)
return append(ss, ssPost...), err
}

36
vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
// Copyright 2018, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmpopts
import (
"github.com/google/go-cmp/cmp"
)
type xformFilter struct{ xform cmp.Option }
func (xf xformFilter) filter(p cmp.Path) bool {
for _, ps := range p {
if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform {
return false
}
}
return true
}
// AcyclicTransformer returns a Transformer with a filter applied that ensures
// that the transformer cannot be recursively applied upon its own output.
//
// An example use case is a transformer that splits a string by lines:
//
// AcyclicTransformer("SplitLines", func(s string) []string{
// return strings.Split(s, "\n")
// })
//
// Had this been an unfiltered Transformer instead, this would result in an
// infinite cycle converting a string to []string to [][]string and so on.
func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option {
xf := xformFilter{cmp.Transformer(name, xformFunc)}
return cmp.FilterPath(xf.filter, xf.xform)
}

View File

@@ -13,21 +13,21 @@
//
// The primary features of cmp are:
//
// When the default behavior of equality does not suit the needs of the test,
// custom equality functions can override the equality operation.
// For example, an equality function may report floats as equal so long as they
// are within some tolerance of each other.
// - When the default behavior of equality does not suit the test's needs,
// custom equality functions can override the equality operation.
// For example, an equality function may report floats as equal so long as
// they are within some tolerance of each other.
//
// Types that have an Equal method may use that method to determine equality.
// This allows package authors to determine the equality operation for the types
// that they define.
// - Types with an Equal method may use that method to determine equality.
// This allows package authors to determine the equality operation
// for the types that they define.
//
// If no custom equality functions are used and no Equal method is defined,
// equality is determined by recursively comparing the primitive kinds on both
// values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
// fields are not compared by default; they result in panics unless suppressed
// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly
// compared using the Exporter option.
// - If no custom equality functions are used and no Equal method is defined,
// equality is determined by recursively comparing the primitive kinds on
// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual,
// unexported fields are not compared by default; they result in panics
// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported)
// or explicitly compared using the Exporter option.
package cmp
import (
@@ -45,25 +45,25 @@ import (
// Equal reports whether x and y are equal by recursively applying the
// following rules in the given order to x and y and all of their sub-values:
//
// Let S be the set of all Ignore, Transformer, and Comparer options that
// remain after applying all path filters, value filters, and type filters.
// If at least one Ignore exists in S, then the comparison is ignored.
// If the number of Transformer and Comparer options in S is greater than one,
// then Equal panics because it is ambiguous which option to use.
// If S contains a single Transformer, then use that to transform the current
// values and recursively call Equal on the output values.
// If S contains a single Comparer, then use that to compare the current values.
// Otherwise, evaluation proceeds to the next rule.
// - Let S be the set of all Ignore, Transformer, and Comparer options that
// remain after applying all path filters, value filters, and type filters.
// If at least one Ignore exists in S, then the comparison is ignored.
// If the number of Transformer and Comparer options in S is non-zero,
// then Equal panics because it is ambiguous which option to use.
// If S contains a single Transformer, then use that to transform
// the current values and recursively call Equal on the output values.
// If S contains a single Comparer, then use that to compare the current values.
// Otherwise, evaluation proceeds to the next rule.
//
// If the values have an Equal method of the form "(T) Equal(T) bool" or
// "(T) Equal(I) bool" where T is assignable to I, then use the result of
// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
// evaluation proceeds to the next rule.
// - If the values have an Equal method of the form "(T) Equal(T) bool" or
// "(T) Equal(I) bool" where T is assignable to I, then use the result of
// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and
// evaluation proceeds to the next rule.
//
// Lastly, try to compare x and y based on their basic kinds.
// Simple kinds like booleans, integers, floats, complex numbers, strings, and
// channels are compared using the equivalent of the == operator in Go.
// Functions are only equal if they are both nil, otherwise they are unequal.
// - Lastly, try to compare x and y based on their basic kinds.
// Simple kinds like booleans, integers, floats, complex numbers, strings,
// and channels are compared using the equivalent of the == operator in Go.
// Functions are only equal if they are both nil, otherwise they are unequal.
//
// Structs are equal if recursively calling Equal on all fields report equal.
// If a struct contains unexported fields, Equal panics unless an Ignore option
@@ -144,7 +144,7 @@ func rootStep(x, y interface{}) PathStep {
// so that they have the same parent type.
var t reflect.Type
if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() {
t = reflect.TypeOf((*interface{})(nil)).Elem()
t = anyType
if vx.IsValid() {
vvx := reflect.New(t).Elem()
vvx.Set(vx)
@@ -639,7 +639,9 @@ type dynChecker struct{ curr, next int }
// Next increments the state and reports whether a check should be performed.
//
// Checks occur every Nth function call, where N is a triangular number:
//
// 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ...
//
// See https://en.wikipedia.org/wiki/Triangular_number
//
// This sequence ensures that the cost of checks drops significantly as

View File

@@ -127,9 +127,9 @@ var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
// This function returns an edit-script, which is a sequence of operations
// needed to convert one list into the other. The following invariants for
// the edit-script are maintained:
// eq == (es.Dist()==0)
// nx == es.LenX()
// ny == es.LenY()
// - eq == (es.Dist()==0)
// - nx == es.LenX()
// - ny == es.LenY()
//
// This algorithm is not guaranteed to be an optimal solution (i.e., one that
// produces an edit-script with a minimal Levenshtein distance). This algorithm
@@ -169,12 +169,13 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
// A diagonal edge is equivalent to a matching symbol between both X and Y.
// Invariants:
// 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx
// 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny
// - 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx
// - 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny
//
// In general:
// fwdFrontier.X < revFrontier.X
// fwdFrontier.Y < revFrontier.Y
// - fwdFrontier.X < revFrontier.X
// - fwdFrontier.Y < revFrontier.Y
//
// Unless, it is time for the algorithm to terminate.
fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)}
revPath := path{-1, point{nx, ny}, make(EditScript, 0)}
@@ -195,19 +196,21 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
// computing sub-optimal edit-scripts between two lists.
//
// The algorithm is approximately as follows:
// Searching for differences switches back-and-forth between
// a search that starts at the beginning (the top-left corner), and
// a search that starts at the end (the bottom-right corner). The goal of
// the search is connect with the search from the opposite corner.
// • As we search, we build a path in a greedy manner, where the first
// match seen is added to the path (this is sub-optimal, but provides a
// decent result in practice). When matches are found, we try the next pair
// of symbols in the lists and follow all matches as far as possible.
// • When searching for matches, we search along a diagonal going through
// through the "frontier" point. If no matches are found, we advance the
// frontier towards the opposite corner.
// • This algorithm terminates when either the X coordinates or the
// Y coordinates of the forward and reverse frontier points ever intersect.
// - Searching for differences switches back-and-forth between
// a search that starts at the beginning (the top-left corner), and
// a search that starts at the end (the bottom-right corner).
// The goal of the search is connect with the search
// from the opposite corner.
// - As we search, we build a path in a greedy manner,
// where the first match seen is added to the path (this is sub-optimal,
// but provides a decent result in practice). When matches are found,
// we try the next pair of symbols in the lists and follow all matches
// as far as possible.
// - When searching for matches, we search along a diagonal going through
// through the "frontier" point. If no matches are found,
// we advance the frontier towards the opposite corner.
// - This algorithm terminates when either the X coordinates or the
// Y coordinates of the forward and reverse frontier points ever intersect.
// This algorithm is correct even if searching only in the forward direction
// or in the reverse direction. We do both because it is commonly observed
@@ -389,6 +392,7 @@ type point struct{ X, Y int }
func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy }
// zigzag maps a consecutive sequence of integers to a zig-zag sequence.
//
// [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...]
func zigzag(x int) int {
if x&1 != 0 {

View File

@@ -1,48 +0,0 @@
// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package value
import (
"math"
"reflect"
)
// IsZero reports whether v is the zero value.
// This does not rely on Interface and so can be used on unexported fields.
func IsZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return v.Bool() == false
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return math.Float64bits(v.Float()) == 0
case reflect.Complex64, reflect.Complex128:
return math.Float64bits(real(v.Complex())) == 0 && math.Float64bits(imag(v.Complex())) == 0
case reflect.String:
return v.String() == ""
case reflect.UnsafePointer:
return v.Pointer() == 0
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
return v.IsNil()
case reflect.Array:
for i := 0; i < v.Len(); i++ {
if !IsZero(v.Index(i)) {
return false
}
}
return true
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
if !IsZero(v.Field(i)) {
return false
}
}
return true
}
return false
}

View File

@@ -33,6 +33,7 @@ type Option interface {
}
// applicableOption represents the following types:
//
// Fundamental: ignore | validator | *comparer | *transformer
// Grouping: Options
type applicableOption interface {
@@ -43,6 +44,7 @@ type applicableOption interface {
}
// coreOption represents the following types:
//
// Fundamental: ignore | validator | *comparer | *transformer
// Filters: *pathFilter | *valuesFilter
type coreOption interface {
@@ -336,9 +338,9 @@ func (tr transformer) String() string {
// both implement T.
//
// The equality function must be:
// Symmetric: equal(x, y) == equal(y, x)
// Deterministic: equal(x, y) == equal(x, y)
// Pure: equal(x, y) does not modify x or y
// - Symmetric: equal(x, y) == equal(y, x)
// - Deterministic: equal(x, y) == equal(x, y)
// - Pure: equal(x, y) does not modify x or y
func Comparer(f interface{}) Option {
v := reflect.ValueOf(f)
if !function.IsType(v.Type(), function.Equal) || v.IsNil() {
@@ -430,7 +432,7 @@ func AllowUnexported(types ...interface{}) Option {
}
// Result represents the comparison result for a single node and
// is provided by cmp when calling Result (see Reporter).
// is provided by cmp when calling Report (see Reporter).
type Result struct {
_ [0]func() // Make Result incomparable
flags resultFlags

View File

@@ -41,13 +41,13 @@ type PathStep interface {
// The type of each valid value is guaranteed to be identical to Type.
//
// In some cases, one or both may be invalid or have restrictions:
// For StructField, both are not interface-able if the current field
// is unexported and the struct type is not explicitly permitted by
// an Exporter to traverse unexported fields.
// For SliceIndex, one may be invalid if an element is missing from
// either the x or y slice.
// For MapIndex, one may be invalid if an entry is missing from
// either the x or y map.
// - For StructField, both are not interface-able if the current field
// is unexported and the struct type is not explicitly permitted by
// an Exporter to traverse unexported fields.
// - For SliceIndex, one may be invalid if an element is missing from
// either the x or y slice.
// - For MapIndex, one may be invalid if an entry is missing from
// either the x or y map.
//
// The provided values must not be mutated.
Values() (vx, vy reflect.Value)
@@ -94,6 +94,7 @@ func (pa Path) Index(i int) PathStep {
// The simplified path only contains struct field accesses.
//
// For example:
//
// MyMap.MySlices.MyField
func (pa Path) String() string {
var ss []string
@@ -108,6 +109,7 @@ func (pa Path) String() string {
// GoString returns the path to a specific node using Go syntax.
//
// For example:
//
// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
func (pa Path) GoString() string {
var ssPre, ssPost []string
@@ -159,7 +161,7 @@ func (ps pathStep) String() string {
if ps.typ == nil {
return "<nil>"
}
s := ps.typ.String()
s := value.TypeString(ps.typ, false)
if s == "" || strings.ContainsAny(s, "{}\n") {
return "root" // Type too simple or complex to print
}
@@ -282,7 +284,7 @@ type typeAssertion struct {
func (ta TypeAssertion) Type() reflect.Type { return ta.typ }
func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", ta.typ) }
func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) }
// Transform is a transformation from the parent type to the current type.
type Transform struct{ *transform }

View File

@@ -7,8 +7,6 @@ package cmp
import (
"fmt"
"reflect"
"github.com/google/go-cmp/cmp/internal/value"
)
// numContextRecords is the number of surrounding equal records to print.
@@ -117,7 +115,7 @@ func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out
// For leaf nodes, format the value based on the reflect.Values alone.
// As a special case, treat equal []byte as a leaf nodes.
isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == reflect.TypeOf(byte(0))
isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == byteType
isEqualBytes := isBytes && v.NumDiff+v.NumIgnored+v.NumTransformed == 0
if v.MaxDepth == 0 || isEqualBytes {
switch opts.DiffMode {
@@ -248,11 +246,11 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, pt
var isZero bool
switch opts.DiffMode {
case diffIdentical:
isZero = value.IsZero(r.Value.ValueX) || value.IsZero(r.Value.ValueY)
isZero = r.Value.ValueX.IsZero() || r.Value.ValueY.IsZero()
case diffRemoved:
isZero = value.IsZero(r.Value.ValueX)
isZero = r.Value.ValueX.IsZero()
case diffInserted:
isZero = value.IsZero(r.Value.ValueY)
isZero = r.Value.ValueY.IsZero()
}
if isZero {
continue

View File

@@ -16,6 +16,13 @@ import (
"github.com/google/go-cmp/cmp/internal/value"
)
var (
anyType = reflect.TypeOf((*interface{})(nil)).Elem()
stringType = reflect.TypeOf((*string)(nil)).Elem()
bytesType = reflect.TypeOf((*[]byte)(nil)).Elem()
byteType = reflect.TypeOf((*byte)(nil)).Elem()
)
type formatValueOptions struct {
// AvoidStringer controls whether to avoid calling custom stringer
// methods like error.Error or fmt.Stringer.String.
@@ -184,7 +191,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind,
}
for i := 0; i < v.NumField(); i++ {
vv := v.Field(i)
if value.IsZero(vv) {
if vv.IsZero() {
continue // Elide fields with zero values
}
if len(list) == maxLen {
@@ -205,7 +212,7 @@ func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind,
}
// Check whether this is a []byte of text data.
if t.Elem() == reflect.TypeOf(byte(0)) {
if t.Elem() == byteType {
b := v.Bytes()
isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) || unicode.IsSpace(r) }
if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 {

View File

@@ -104,7 +104,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
case t.Kind() == reflect.String:
sx, sy = vx.String(), vy.String()
isString = true
case t.Kind() == reflect.Slice && t.Elem() == reflect.TypeOf(byte(0)):
case t.Kind() == reflect.Slice && t.Elem() == byteType:
sx, sy = string(vx.Bytes()), string(vy.Bytes())
isString = true
case t.Kind() == reflect.Array:
@@ -147,7 +147,10 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
})
efficiencyLines := float64(esLines.Dist()) / float64(len(esLines))
efficiencyBytes := float64(esBytes.Dist()) / float64(len(esBytes))
isPureLinedText = efficiencyLines < 4*efficiencyBytes
quotedLength := len(strconv.Quote(sx + sy))
unquotedLength := len(sx) + len(sy)
escapeExpansionRatio := float64(quotedLength) / float64(unquotedLength)
isPureLinedText = efficiencyLines < 4*efficiencyBytes || escapeExpansionRatio > 1.1
}
}
@@ -171,12 +174,13 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
// differences in a string literal. This format is more readable,
// but has edge-cases where differences are visually indistinguishable.
// This format is avoided under the following conditions:
// A line starts with `"""`
// A line starts with "..."
// A line contains non-printable characters
// Adjacent different lines differ only by whitespace
// - A line starts with `"""`
// - A line starts with "..."
// - A line contains non-printable characters
// - Adjacent different lines differ only by whitespace
//
// For example:
//
// """
// ... // 3 identical lines
// foo
@@ -231,7 +235,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"}
switch t.Kind() {
case reflect.String:
if t != reflect.TypeOf(string("")) {
if t != stringType {
out = opts.FormatType(t, out)
}
case reflect.Slice:
@@ -326,12 +330,12 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
switch t.Kind() {
case reflect.String:
out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
if t != reflect.TypeOf(string("")) {
if t != stringType {
out = opts.FormatType(t, out)
}
case reflect.Slice:
out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
if t != reflect.TypeOf([]byte(nil)) {
if t != bytesType {
out = opts.FormatType(t, out)
}
}
@@ -446,7 +450,6 @@ func (opts formatOptions) formatDiffSlice(
// {NumIdentical: 3},
// {NumInserted: 1},
// ]
//
func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) {
var prevMode byte
lastStats := func(mode byte) *diffStats {
@@ -503,7 +506,6 @@ func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats)
// {NumIdentical: 8, NumRemoved: 12, NumInserted: 3},
// {NumIdentical: 63},
// ]
//
func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats {
groups, groupsOrig := groups[:0], groups
for i, ds := range groupsOrig {
@@ -548,7 +550,6 @@ func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStat
// {NumRemoved: 9},
// {NumIdentical: 64}, // incremented by 10
// ]
//
func cleanupSurroundingIdentical(groups []diffStats, eq func(i, j int) bool) []diffStats {
var ix, iy int // indexes into sequence x and y
for i, ds := range groups {

View File

@@ -393,6 +393,7 @@ func (s diffStats) Append(ds diffStats) diffStats {
// String prints a humanly-readable summary of coalesced records.
//
// Example:
//
// diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields"
func (s diffStats) String() string {
var ss []string

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,186 +0,0 @@
// Copyright 2013 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package diff implements a linewise diff algorithm.
package diff
import (
"bytes"
"fmt"
"strings"
)
// Chunk represents a piece of the diff. A chunk will not have both added and
// deleted lines. Equal lines are always after any added or deleted lines.
// A Chunk may or may not have any lines in it, especially for the first or last
// chunk in a computation.
type Chunk struct {
Added []string
Deleted []string
Equal []string
}
func (c *Chunk) empty() bool {
return len(c.Added) == 0 && len(c.Deleted) == 0 && len(c.Equal) == 0
}
// Diff returns a string containing a line-by-line unified diff of the linewise
// changes required to make A into B. Each line is prefixed with '+', '-', or
// ' ' to indicate if it should be added, removed, or is correct respectively.
func Diff(A, B string) string {
aLines := strings.Split(A, "\n")
bLines := strings.Split(B, "\n")
chunks := DiffChunks(aLines, bLines)
buf := new(bytes.Buffer)
for _, c := range chunks {
for _, line := range c.Added {
fmt.Fprintf(buf, "+%s\n", line)
}
for _, line := range c.Deleted {
fmt.Fprintf(buf, "-%s\n", line)
}
for _, line := range c.Equal {
fmt.Fprintf(buf, " %s\n", line)
}
}
return strings.TrimRight(buf.String(), "\n")
}
// DiffChunks uses an O(D(N+M)) shortest-edit-script algorithm
// to compute the edits required from A to B and returns the
// edit chunks.
func DiffChunks(a, b []string) []Chunk {
// algorithm: http://www.xmailserver.org/diff2.pdf
// We'll need these quantities a lot.
alen, blen := len(a), len(b) // M, N
// At most, it will require len(a) deletions and len(b) additions
// to transform a into b.
maxPath := alen + blen // MAX
if maxPath == 0 {
// degenerate case: two empty lists are the same
return nil
}
// Store the endpoint of the path for diagonals.
// We store only the a index, because the b index on any diagonal
// (which we know during the loop below) is aidx-diag.
// endpoint[maxPath] represents the 0 diagonal.
//
// Stated differently:
// endpoint[d] contains the aidx of a furthest reaching path in diagonal d
endpoint := make([]int, 2*maxPath+1) // V
saved := make([][]int, 0, 8) // Vs
save := func() {
dup := make([]int, len(endpoint))
copy(dup, endpoint)
saved = append(saved, dup)
}
var editDistance int // D
dLoop:
for editDistance = 0; editDistance <= maxPath; editDistance++ {
// The 0 diag(onal) represents equality of a and b. Each diagonal to
// the left is numbered one lower, to the right is one higher, from
// -alen to +blen. Negative diagonals favor differences from a,
// positive diagonals favor differences from b. The edit distance to a
// diagonal d cannot be shorter than d itself.
//
// The iterations of this loop cover either odds or evens, but not both,
// If odd indices are inputs, even indices are outputs and vice versa.
for diag := -editDistance; diag <= editDistance; diag += 2 { // k
var aidx int // x
switch {
case diag == -editDistance:
// This is a new diagonal; copy from previous iter
aidx = endpoint[maxPath-editDistance+1] + 0
case diag == editDistance:
// This is a new diagonal; copy from previous iter
aidx = endpoint[maxPath+editDistance-1] + 1
case endpoint[maxPath+diag+1] > endpoint[maxPath+diag-1]:
// diagonal d+1 was farther along, so use that
aidx = endpoint[maxPath+diag+1] + 0
default:
// diagonal d-1 was farther (or the same), so use that
aidx = endpoint[maxPath+diag-1] + 1
}
// On diagonal d, we can compute bidx from aidx.
bidx := aidx - diag // y
// See how far we can go on this diagonal before we find a difference.
for aidx < alen && bidx < blen && a[aidx] == b[bidx] {
aidx++
bidx++
}
// Store the end of the current edit chain.
endpoint[maxPath+diag] = aidx
// If we've found the end of both inputs, we're done!
if aidx >= alen && bidx >= blen {
save() // save the final path
break dLoop
}
}
save() // save the current path
}
if editDistance == 0 {
return nil
}
chunks := make([]Chunk, editDistance+1)
x, y := alen, blen
for d := editDistance; d > 0; d-- {
endpoint := saved[d]
diag := x - y
insert := diag == -d || (diag != d && endpoint[maxPath+diag-1] < endpoint[maxPath+diag+1])
x1 := endpoint[maxPath+diag]
var x0, xM, kk int
if insert {
kk = diag + 1
x0 = endpoint[maxPath+kk]
xM = x0
} else {
kk = diag - 1
x0 = endpoint[maxPath+kk]
xM = x0 + 1
}
y0 := x0 - kk
var c Chunk
if insert {
c.Added = b[y0:][:1]
} else {
c.Deleted = a[x0:][:1]
}
if xM < x1 {
c.Equal = a[xM:][:x1-xM]
}
x, y = x0, y0
chunks[d] = c
}
if x > 0 {
chunks[0].Equal = a[:x]
}
if chunks[0].empty() {
chunks = chunks[1:]
}
if len(chunks) == 0 {
return nil
}
return chunks
}

View File

@@ -1,5 +0,0 @@
*.test
*.bench
*.golden
*.txt
*.prof

View File

@@ -1,25 +0,0 @@
// Copyright 2013 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package pretty pretty-prints Go structures.
//
// This package uses reflection to examine a Go value and can
// print out in a nice, aligned fashion. It supports three
// modes (normal, compact, and extended) for advanced use.
//
// See the Reflect and Print examples for what the output looks like.
package pretty
// TODO:
// - Catch cycles

View File

@@ -1,188 +0,0 @@
// Copyright 2013 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pretty
import (
"bytes"
"fmt"
"io"
"net"
"reflect"
"time"
"github.com/kylelemons/godebug/diff"
)
// A Config represents optional configuration parameters for formatting.
//
// Some options, notably ShortList, dramatically increase the overhead
// of pretty-printing a value.
type Config struct {
// Verbosity options
Compact bool // One-line output. Overrides Diffable.
Diffable bool // Adds extra newlines for more easily diffable output.
// Field and value options
IncludeUnexported bool // Include unexported fields in output
PrintStringers bool // Call String on a fmt.Stringer
PrintTextMarshalers bool // Call MarshalText on an encoding.TextMarshaler
SkipZeroFields bool // Skip struct fields that have a zero value.
// Output transforms
ShortList int // Maximum character length for short lists if nonzero.
// Type-specific overrides
//
// Formatter maps a type to a function that will provide a one-line string
// representation of the input value. Conceptually:
// Formatter[reflect.TypeOf(v)](v) = "v as a string"
//
// Note that the first argument need not explicitly match the type, it must
// merely be callable with it.
//
// When processing an input value, if its type exists as a key in Formatter:
// 1) If the value is nil, no stringification is performed.
// This allows overriding of PrintStringers and PrintTextMarshalers.
// 2) The value will be called with the input as its only argument.
// The function must return a string as its first return value.
//
// In addition to func literals, two common values for this will be:
// fmt.Sprint (function) func Sprint(...interface{}) string
// Type.String (method) func (Type) String() string
//
// Note that neither of these work if the String method is a pointer
// method and the input will be provided as a value. In that case,
// use a function that calls .String on the formal value parameter.
Formatter map[reflect.Type]interface{}
// If TrackCycles is enabled, pretty will detect and track
// self-referential structures. If a self-referential structure (aka a
// "recursive" value) is detected, numbered placeholders will be emitted.
//
// Pointer tracking is disabled by default for performance reasons.
TrackCycles bool
}
// Default Config objects
var (
// DefaultFormatter is the default set of overrides for stringification.
DefaultFormatter = map[reflect.Type]interface{}{
reflect.TypeOf(time.Time{}): fmt.Sprint,
reflect.TypeOf(net.IP{}): fmt.Sprint,
reflect.TypeOf((*error)(nil)).Elem(): fmt.Sprint,
}
// CompareConfig is the default configuration used for Compare.
CompareConfig = &Config{
Diffable: true,
IncludeUnexported: true,
Formatter: DefaultFormatter,
}
// DefaultConfig is the default configuration used for all other top-level functions.
DefaultConfig = &Config{
Formatter: DefaultFormatter,
}
// CycleTracker is a convenience config for formatting and comparing recursive structures.
CycleTracker = &Config{
Diffable: true,
Formatter: DefaultFormatter,
TrackCycles: true,
}
)
func (cfg *Config) fprint(buf *bytes.Buffer, vals ...interface{}) {
ref := &reflector{
Config: cfg,
}
if cfg.TrackCycles {
ref.pointerTracker = new(pointerTracker)
}
for i, val := range vals {
if i > 0 {
buf.WriteByte('\n')
}
newFormatter(cfg, buf).write(ref.val2node(reflect.ValueOf(val)))
}
}
// Print writes the DefaultConfig representation of the given values to standard output.
func Print(vals ...interface{}) {
DefaultConfig.Print(vals...)
}
// Print writes the configured presentation of the given values to standard output.
func (cfg *Config) Print(vals ...interface{}) {
fmt.Println(cfg.Sprint(vals...))
}
// Sprint returns a string representation of the given value according to the DefaultConfig.
func Sprint(vals ...interface{}) string {
return DefaultConfig.Sprint(vals...)
}
// Sprint returns a string representation of the given value according to cfg.
func (cfg *Config) Sprint(vals ...interface{}) string {
buf := new(bytes.Buffer)
cfg.fprint(buf, vals...)
return buf.String()
}
// Fprint writes the representation of the given value to the writer according to the DefaultConfig.
func Fprint(w io.Writer, vals ...interface{}) (n int64, err error) {
return DefaultConfig.Fprint(w, vals...)
}
// Fprint writes the representation of the given value to the writer according to the cfg.
func (cfg *Config) Fprint(w io.Writer, vals ...interface{}) (n int64, err error) {
buf := new(bytes.Buffer)
cfg.fprint(buf, vals...)
return buf.WriteTo(w)
}
// Compare returns a string containing a line-by-line unified diff of the
// values in a and b, using the CompareConfig.
//
// Each line in the output is prefixed with '+', '-', or ' ' to indicate which
// side it's from. Lines from the a side are marked with '-', lines from the
// b side are marked with '+' and lines that are the same on both sides are
// marked with ' '.
//
// The comparison is based on the intentionally-untyped output of Print, and as
// such this comparison is pretty forviving. In particular, if the types of or
// types within in a and b are different but have the same representation,
// Compare will not indicate any differences between them.
func Compare(a, b interface{}) string {
return CompareConfig.Compare(a, b)
}
// Compare returns a string containing a line-by-line unified diff of the
// values in got and want according to the cfg.
//
// Each line in the output is prefixed with '+', '-', or ' ' to indicate which
// side it's from. Lines from the a side are marked with '-', lines from the
// b side are marked with '+' and lines that are the same on both sides are
// marked with ' '.
//
// The comparison is based on the intentionally-untyped output of Print, and as
// such this comparison is pretty forviving. In particular, if the types of or
// types within in a and b are different but have the same representation,
// Compare will not indicate any differences between them.
func (cfg *Config) Compare(a, b interface{}) string {
diffCfg := *cfg
diffCfg.Diffable = true
return diff.Diff(cfg.Sprint(a), cfg.Sprint(b))
}

View File

@@ -1,241 +0,0 @@
// Copyright 2013 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pretty
import (
"encoding"
"fmt"
"reflect"
"sort"
)
func isZeroVal(val reflect.Value) bool {
if !val.CanInterface() {
return false
}
z := reflect.Zero(val.Type()).Interface()
return reflect.DeepEqual(val.Interface(), z)
}
// pointerTracker is a helper for tracking pointer chasing to detect cycles.
type pointerTracker struct {
addrs map[uintptr]int // addr[address] = seen count
lastID int
ids map[uintptr]int // ids[address] = id
}
// track tracks following a reference (pointer, slice, map, etc). Every call to
// track should be paired with a call to untrack.
func (p *pointerTracker) track(ptr uintptr) {
if p.addrs == nil {
p.addrs = make(map[uintptr]int)
}
p.addrs[ptr]++
}
// untrack registers that we have backtracked over the reference to the pointer.
func (p *pointerTracker) untrack(ptr uintptr) {
p.addrs[ptr]--
if p.addrs[ptr] == 0 {
delete(p.addrs, ptr)
}
}
// seen returns whether the pointer was previously seen along this path.
func (p *pointerTracker) seen(ptr uintptr) bool {
_, ok := p.addrs[ptr]
return ok
}
// keep allocates an ID for the given address and returns it.
func (p *pointerTracker) keep(ptr uintptr) int {
if p.ids == nil {
p.ids = make(map[uintptr]int)
}
if _, ok := p.ids[ptr]; !ok {
p.lastID++
p.ids[ptr] = p.lastID
}
return p.ids[ptr]
}
// id returns the ID for the given address.
func (p *pointerTracker) id(ptr uintptr) (int, bool) {
if p.ids == nil {
p.ids = make(map[uintptr]int)
}
id, ok := p.ids[ptr]
return id, ok
}
// reflector adds local state to the recursive reflection logic.
type reflector struct {
*Config
*pointerTracker
}
// follow handles following a possiblly-recursive reference to the given value
// from the given ptr address.
func (r *reflector) follow(ptr uintptr, val reflect.Value) node {
if r.pointerTracker == nil {
// Tracking disabled
return r.val2node(val)
}
// If a parent already followed this, emit a reference marker
if r.seen(ptr) {
id := r.keep(ptr)
return ref{id}
}
// Track the pointer we're following while on this recursive branch
r.track(ptr)
defer r.untrack(ptr)
n := r.val2node(val)
// If the recursion used this ptr, wrap it with a target marker
if id, ok := r.id(ptr); ok {
return target{id, n}
}
// Otherwise, return the node unadulterated
return n
}
func (r *reflector) val2node(val reflect.Value) node {
if !val.IsValid() {
return rawVal("nil")
}
if val.CanInterface() {
v := val.Interface()
if formatter, ok := r.Formatter[val.Type()]; ok {
if formatter != nil {
res := reflect.ValueOf(formatter).Call([]reflect.Value{val})
return rawVal(res[0].Interface().(string))
}
} else {
if s, ok := v.(fmt.Stringer); ok && r.PrintStringers {
return stringVal(s.String())
}
if t, ok := v.(encoding.TextMarshaler); ok && r.PrintTextMarshalers {
if raw, err := t.MarshalText(); err == nil { // if NOT an error
return stringVal(string(raw))
}
}
}
}
switch kind := val.Kind(); kind {
case reflect.Ptr:
if val.IsNil() {
return rawVal("nil")
}
return r.follow(val.Pointer(), val.Elem())
case reflect.Interface:
if val.IsNil() {
return rawVal("nil")
}
return r.val2node(val.Elem())
case reflect.String:
return stringVal(val.String())
case reflect.Slice:
n := list{}
length := val.Len()
ptr := val.Pointer()
for i := 0; i < length; i++ {
n = append(n, r.follow(ptr, val.Index(i)))
}
return n
case reflect.Array:
n := list{}
length := val.Len()
for i := 0; i < length; i++ {
n = append(n, r.val2node(val.Index(i)))
}
return n
case reflect.Map:
// Extract the keys and sort them for stable iteration
keys := val.MapKeys()
pairs := make([]mapPair, 0, len(keys))
for _, key := range keys {
pairs = append(pairs, mapPair{
key: new(formatter).compactString(r.val2node(key)), // can't be cyclic
value: val.MapIndex(key),
})
}
sort.Sort(byKey(pairs))
// Process the keys into the final representation
ptr, n := val.Pointer(), keyvals{}
for _, pair := range pairs {
n = append(n, keyval{
key: pair.key,
val: r.follow(ptr, pair.value),
})
}
return n
case reflect.Struct:
n := keyvals{}
typ := val.Type()
fields := typ.NumField()
for i := 0; i < fields; i++ {
sf := typ.Field(i)
if !r.IncludeUnexported && sf.PkgPath != "" {
continue
}
field := val.Field(i)
if r.SkipZeroFields && isZeroVal(field) {
continue
}
n = append(n, keyval{sf.Name, r.val2node(field)})
}
return n
case reflect.Bool:
if val.Bool() {
return rawVal("true")
}
return rawVal("false")
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rawVal(fmt.Sprintf("%d", val.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return rawVal(fmt.Sprintf("%d", val.Uint()))
case reflect.Uintptr:
return rawVal(fmt.Sprintf("0x%X", val.Uint()))
case reflect.Float32, reflect.Float64:
return rawVal(fmt.Sprintf("%v", val.Float()))
case reflect.Complex64, reflect.Complex128:
return rawVal(fmt.Sprintf("%v", val.Complex()))
}
// Fall back to the default %#v if we can
if val.CanInterface() {
return rawVal(fmt.Sprintf("%#v", val.Interface()))
}
return rawVal(val.String())
}
type mapPair struct {
key string
value reflect.Value
}
type byKey []mapPair
func (v byKey) Len() int { return len(v) }
func (v byKey) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v byKey) Less(i, j int) bool { return v[i].key < v[j].key }

View File

@@ -1,223 +0,0 @@
// Copyright 2013 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pretty
import (
"bufio"
"bytes"
"fmt"
"io"
"strconv"
"strings"
)
// a formatter stores stateful formatting information as well as being
// an io.Writer for simplicity.
type formatter struct {
*bufio.Writer
*Config
// Self-referential structure tracking
tagNumbers map[int]int // tagNumbers[id] = <#n>
}
// newFormatter creates a new buffered formatter. For the output to be written
// to the given writer, this must be accompanied by a call to write (or Flush).
func newFormatter(cfg *Config, w io.Writer) *formatter {
return &formatter{
Writer: bufio.NewWriter(w),
Config: cfg,
tagNumbers: make(map[int]int),
}
}
func (f *formatter) write(n node) {
defer f.Flush()
n.format(f, "")
}
func (f *formatter) tagFor(id int) int {
if tag, ok := f.tagNumbers[id]; ok {
return tag
}
if f.tagNumbers == nil {
return 0
}
tag := len(f.tagNumbers) + 1
f.tagNumbers[id] = tag
return tag
}
type node interface {
format(f *formatter, indent string)
}
func (f *formatter) compactString(n node) string {
switch k := n.(type) {
case stringVal:
return string(k)
case rawVal:
return string(k)
}
buf := new(bytes.Buffer)
f2 := newFormatter(&Config{Compact: true}, buf)
f2.tagNumbers = f.tagNumbers // reuse tagNumbers just in case
f2.write(n)
return buf.String()
}
type stringVal string
func (str stringVal) format(f *formatter, indent string) {
f.WriteString(strconv.Quote(string(str)))
}
type rawVal string
func (r rawVal) format(f *formatter, indent string) {
f.WriteString(string(r))
}
type keyval struct {
key string
val node
}
type keyvals []keyval
func (l keyvals) format(f *formatter, indent string) {
f.WriteByte('{')
switch {
case f.Compact:
// All on one line:
for i, kv := range l {
if i > 0 {
f.WriteByte(',')
}
f.WriteString(kv.key)
f.WriteByte(':')
kv.val.format(f, indent)
}
case f.Diffable:
f.WriteByte('\n')
inner := indent + " "
// Each value gets its own line:
for _, kv := range l {
f.WriteString(inner)
f.WriteString(kv.key)
f.WriteString(": ")
kv.val.format(f, inner)
f.WriteString(",\n")
}
f.WriteString(indent)
default:
keyWidth := 0
for _, kv := range l {
if kw := len(kv.key); kw > keyWidth {
keyWidth = kw
}
}
alignKey := indent + " "
alignValue := strings.Repeat(" ", keyWidth)
inner := alignKey + alignValue + " "
// First and last line shared with bracket:
for i, kv := range l {
if i > 0 {
f.WriteString(",\n")
f.WriteString(alignKey)
}
f.WriteString(kv.key)
f.WriteString(": ")
f.WriteString(alignValue[len(kv.key):])
kv.val.format(f, inner)
}
}
f.WriteByte('}')
}
type list []node
func (l list) format(f *formatter, indent string) {
if max := f.ShortList; max > 0 {
short := f.compactString(l)
if len(short) <= max {
f.WriteString(short)
return
}
}
f.WriteByte('[')
switch {
case f.Compact:
// All on one line:
for i, v := range l {
if i > 0 {
f.WriteByte(',')
}
v.format(f, indent)
}
case f.Diffable:
f.WriteByte('\n')
inner := indent + " "
// Each value gets its own line:
for _, v := range l {
f.WriteString(inner)
v.format(f, inner)
f.WriteString(",\n")
}
f.WriteString(indent)
default:
inner := indent + " "
// First and last line shared with bracket:
for i, v := range l {
if i > 0 {
f.WriteString(",\n")
f.WriteString(inner)
}
v.format(f, inner)
}
}
f.WriteByte(']')
}
type ref struct {
id int
}
func (r ref) format(f *formatter, indent string) {
fmt.Fprintf(f, "<see #%d>", f.tagFor(r.id))
}
type target struct {
id int
value node
}
func (t target) format(f *formatter, indent string) {
tag := fmt.Sprintf("<#%d> ", f.tagFor(t.id))
switch {
case f.Diffable, f.Compact:
// no indent changes
default:
indent += strings.Repeat(" ", len(tag))
}
f.WriteString(tag)
t.value.format(f, indent)
}

7
vendor/modules.txt vendored
View File

@@ -343,9 +343,10 @@ github.com/google/gnostic/extensions
github.com/google/gnostic/jsonschema
github.com/google/gnostic/openapiv2
github.com/google/gnostic/openapiv3
# github.com/google/go-cmp v0.5.8
# github.com/google/go-cmp v0.5.9
## explicit; go 1.13
github.com/google/go-cmp/cmp
github.com/google/go-cmp/cmp/cmpopts
github.com/google/go-cmp/cmp/internal/diff
github.com/google/go-cmp/cmp/internal/flags
github.com/google/go-cmp/cmp/internal/function
@@ -436,10 +437,6 @@ github.com/kubernetes-sigs/service-catalog/pkg/client/clientset_generated/client
github.com/kubernetes-sigs/service-catalog/pkg/client/clientset_generated/clientset/typed/settings/v1alpha1
github.com/kubernetes-sigs/service-catalog/pkg/client/clientset_generated/clientset/typed/settings/v1alpha1/fake
github.com/kubernetes-sigs/service-catalog/pkg/filter
# github.com/kylelemons/godebug v1.1.0
## explicit; go 1.11
github.com/kylelemons/godebug/diff
github.com/kylelemons/godebug/pretty
# github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
## explicit
github.com/liggitt/tabwriter