diff --git a/go.mod b/go.mod index 9b4f8aa36..8006ceb7b 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 2060f5e53..32fef4ed7 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/pkg/binding/binding_test.go b/pkg/binding/binding_test.go index e08268f2c..e7076772e 100644 --- a/pkg/binding/binding_test.go +++ b/pkg/binding/binding_test.go @@ -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) } }) } diff --git a/pkg/binding/list_test.go b/pkg/binding/list_test.go index 4803c9e0e..0ea534ce1 100644 --- a/pkg/binding/list_test.go +++ b/pkg/binding/list_test.go @@ -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) } }) } diff --git a/pkg/binding/remove_binding_test.go b/pkg/binding/remove_binding_test.go index 7bb229751..d6e10c657 100644 --- a/pkg/binding/remove_binding_test.go +++ b/pkg/binding/remove_binding_test.go @@ -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) } }) } diff --git a/pkg/component/component_test.go b/pkg/component/component_test.go index 786ad3e96..897805191 100644 --- a/pkg/component/component_test.go +++ b/pkg/component/component_test.go @@ -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) } }) } diff --git a/pkg/component/delete/delete_test.go b/pkg/component/delete/delete_test.go index 033abbf12..aa295e770 100644 --- a/pkg/component/delete/delete_test.go +++ b/pkg/component/delete/delete_test.go @@ -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) } }) } diff --git a/pkg/dev/podmandev/pod_test.go b/pkg/dev/podmandev/pod_test.go index f50a9774e..9bb70fffa 100644 --- a/pkg/dev/podmandev/pod_test.go +++ b/pkg/dev/podmandev/pod_test.go @@ -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) } }) } diff --git a/pkg/devfile/adapters/kubernetes/component/adapter_test.go b/pkg/devfile/adapters/kubernetes/component/adapter_test.go index d83c14d98..abc79b12d 100644 --- a/pkg/devfile/adapters/kubernetes/component/adapter_test.go +++ b/pkg/devfile/adapters/kubernetes/component/adapter_test.go @@ -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) } }) } diff --git a/pkg/devfile/adapters/kubernetes/storage/utils_test.go b/pkg/devfile/adapters/kubernetes/storage/utils_test.go index 41abd849b..3eaaaf2a6 100644 --- a/pkg/devfile/adapters/kubernetes/storage/utils_test.go +++ b/pkg/devfile/adapters/kubernetes/storage/utils_test.go @@ -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) } }) } diff --git a/pkg/devfile/adapters/kubernetes/utils/utils_test.go b/pkg/devfile/adapters/kubernetes/utils/utils_test.go index bd3b9079a..825e48654 100644 --- a/pkg/devfile/adapters/kubernetes/utils/utils_test.go +++ b/pkg/devfile/adapters/kubernetes/utils/utils_test.go @@ -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) } } diff --git a/pkg/devfile/components_test.go b/pkg/devfile/components_test.go index 11a3ce810..889181c87 100644 --- a/pkg/devfile/components_test.go +++ b/pkg/devfile/components_test.go @@ -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) } }) } diff --git a/pkg/devfile/image/docker_compatible_test.go b/pkg/devfile/image/docker_compatible_test.go index 61cec44b8..9c8950e48 100644 --- a/pkg/devfile/image/docker_compatible_test.go +++ b/pkg/devfile/image/docker_compatible_test.go @@ -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) } }) } diff --git a/pkg/devfile/validate/components_test.go b/pkg/devfile/validate/components_test.go index 552e9824e..71a08d3bc 100644 --- a/pkg/devfile/validate/components_test.go +++ b/pkg/devfile/validate/components_test.go @@ -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) } }) diff --git a/pkg/exec/exec_test.go b/pkg/exec/exec_test.go index b60529429..44ef00647 100644 --- a/pkg/exec/exec_test.go +++ b/pkg/exec/exec_test.go @@ -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) } }) } diff --git a/pkg/init/asker/asker_test.go b/pkg/init/asker/asker_test.go index 2afe9ff55..8273da128 100644 --- a/pkg/init/asker/asker_test.go +++ b/pkg/init/asker/asker_test.go @@ -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) } }) } diff --git a/pkg/init/backend/alizer_test.go b/pkg/init/backend/alizer_test.go index 563c454b5..3afb3e155 100644 --- a/pkg/init/backend/alizer_test.go +++ b/pkg/init/backend/alizer_test.go @@ -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) } }) } diff --git a/pkg/init/backend/flags_test.go b/pkg/init/backend/flags_test.go index 4d23d2621..b2474c0de 100644 --- a/pkg/init/backend/flags_test.go +++ b/pkg/init/backend/flags_test.go @@ -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) } }) } diff --git a/pkg/init/backend/interactive_test.go b/pkg/init/backend/interactive_test.go index 176074bc5..67c27d77c 100644 --- a/pkg/init/backend/interactive_test.go +++ b/pkg/init/backend/interactive_test.go @@ -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) } }) } diff --git a/pkg/kclient/operators_test.go b/pkg/kclient/operators_test.go index bbcc10a9b..77735b975 100644 --- a/pkg/kclient/operators_test.go +++ b/pkg/kclient/operators_test.go @@ -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) } }) } diff --git a/pkg/kclient/pods_test.go b/pkg/kclient/pods_test.go index 6499bd3a4..2bcaaf93e 100644 --- a/pkg/kclient/pods_test.go +++ b/pkg/kclient/pods_test.go @@ -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) } }) } diff --git a/pkg/kclient/projects_test.go b/pkg/kclient/projects_test.go index 7d3062d0b..8ab526c88 100644 --- a/pkg/kclient/projects_test.go +++ b/pkg/kclient/projects_test.go @@ -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) } }) } diff --git a/pkg/kclient/secrets_test.go b/pkg/kclient/secrets_test.go index 33aae6ecb..f42659214 100644 --- a/pkg/kclient/secrets_test.go +++ b/pkg/kclient/secrets_test.go @@ -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 { diff --git a/pkg/kclient/services_test.go b/pkg/kclient/services_test.go index 00599f3dc..901eb49cf 100644 --- a/pkg/kclient/services_test.go +++ b/pkg/kclient/services_test.go @@ -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) } }) } diff --git a/pkg/kclient/utils_test.go b/pkg/kclient/utils_test.go index 88b4fce69..242953624 100644 --- a/pkg/kclient/utils_test.go +++ b/pkg/kclient/utils_test.go @@ -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") diff --git a/pkg/kclient/volumes_test.go b/pkg/kclient/volumes_test.go index 058fa7c35..b3e189c8c 100644 --- a/pkg/kclient/volumes_test.go +++ b/pkg/kclient/volumes_test.go @@ -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) } }) } diff --git a/pkg/labels/labels_test.go b/pkg/labels/labels_test.go index 7e7536f9b..d10fcf446 100644 --- a/pkg/labels/labels_test.go +++ b/pkg/labels/labels_test.go @@ -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) } }) } diff --git a/pkg/libdevfile/libdevfile_test.go b/pkg/libdevfile/libdevfile_test.go index b2c3a30fd..4c37f4d29 100644 --- a/pkg/libdevfile/libdevfile_test.go +++ b/pkg/libdevfile/libdevfile_test.go @@ -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) } }) } diff --git a/pkg/libdevfile/uris_test.go b/pkg/libdevfile/uris_test.go index ac90b3e37..2cf1eb763 100644 --- a/pkg/libdevfile/uris_test.go +++ b/pkg/libdevfile/uris_test.go @@ -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) } }) } diff --git a/pkg/odo/cli/delete/component/component_test.go b/pkg/odo/cli/delete/component/component_test.go index 7d41a73c6..08269fe16 100644 --- a/pkg/odo/cli/delete/component/component_test.go +++ b/pkg/odo/cli/delete/component/component_test.go @@ -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) } }) } diff --git a/pkg/odo/cli/files/files_test.go b/pkg/odo/cli/files/files_test.go index 5cdece0a7..1a4d4b656 100644 --- a/pkg/odo/cli/files/files_test.go +++ b/pkg/odo/cli/files/files_test.go @@ -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) } }) } diff --git a/pkg/portForward/writer_test.go b/pkg/portForward/writer_test.go index f4d64a25f..11ffdfe0e 100644 --- a/pkg/portForward/writer_test.go +++ b/pkg/portForward/writer_test.go @@ -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) } }) } diff --git a/pkg/preference/implem_test.go b/pkg/preference/implem_test.go index 1467f99f9..9f211b742 100644 --- a/pkg/preference/implem_test.go +++ b/pkg/preference/implem_test.go @@ -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) } } } diff --git a/pkg/project/kubernetes_test.go b/pkg/project/kubernetes_test.go index 18fb4b955..e73b0dcdc 100644 --- a/pkg/project/kubernetes_test.go +++ b/pkg/project/kubernetes_test.go @@ -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) } }) } diff --git a/pkg/registry/devfile_component_type_list_test.go b/pkg/registry/devfile_component_type_list_test.go index acdaf0670..39d27f7cf 100644 --- a/pkg/registry/devfile_component_type_list_test.go +++ b/pkg/registry/devfile_component_type_list_test.go @@ -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) } }) } diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index feb2ed47d..c4bfcee2e 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -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) } }) diff --git a/pkg/registry/types_with_details_test.go b/pkg/registry/types_with_details_test.go index bc100e677..23c097a3c 100644 --- a/pkg/registry/types_with_details_test.go +++ b/pkg/registry/types_with_details_test.go @@ -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) } }) } diff --git a/pkg/registry/utils_test.go b/pkg/registry/utils_test.go index b3b851851..c989c9a33 100644 --- a/pkg/registry/utils_test.go +++ b/pkg/registry/utils_test.go @@ -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) } }) } diff --git a/pkg/remotecmd/kubexec_test.go b/pkg/remotecmd/kubexec_test.go index 4ee471e5d..a7f9780e0 100644 --- a/pkg/remotecmd/kubexec_test.go +++ b/pkg/remotecmd/kubexec_test.go @@ -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) } - }) } } diff --git a/pkg/segment/context/context_test.go b/pkg/segment/context/context_test.go index e365d1fe3..3004b754b 100644 --- a/pkg/segment/context/context_test.go +++ b/pkg/segment/context/context_test.go @@ -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) } } diff --git a/pkg/service/crd_builder_test.go b/pkg/service/crd_builder_test.go index 674f4459a..3053ea3a3 100644 --- a/pkg/service/crd_builder_test.go +++ b/pkg/service/crd_builder_test.go @@ -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)) diff --git a/pkg/service/service_test.go b/pkg/service/service_test.go index 4fd54ae2a..152e3ec1e 100644 --- a/pkg/service/service_test.go +++ b/pkg/service/service_test.go @@ -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) diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 6bad4fe97..c9dacde3b 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -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) } }) } diff --git a/pkg/storage/kubernetes_test.go b/pkg/storage/kubernetes_test.go index cb26ad5ad..de68e1fa9 100644 --- a/pkg/storage/kubernetes_test.go +++ b/pkg/storage/kubernetes_test.go @@ -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) } }) } diff --git a/pkg/storage/list_test.go b/pkg/storage/list_test.go index 41a1ee281..5c1dcd954 100644 --- a/pkg/storage/list_test.go +++ b/pkg/storage/list_test.go @@ -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) } }) } diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index e5dda7733..1fd9bdc2e 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -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) } }) } diff --git a/pkg/storage/types_test.go b/pkg/storage/types_test.go index 6c23f4fad..0a4998fe8 100644 --- a/pkg/storage/types_test.go +++ b/pkg/storage/types_test.go @@ -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) } }) } diff --git a/pkg/sync/sync_test.go b/pkg/sync/sync_test.go index f9d9deb3d..fb3a88ef3 100644 --- a/pkg/sync/sync_test.go +++ b/pkg/sync/sync_test.go @@ -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) } } } diff --git a/pkg/util/file_indexer_test.go b/pkg/util/file_indexer_test.go index e70e9b106..c1ffbdad1 100644 --- a/pkg/util/file_indexer_test.go +++ b/pkg/util/file_indexer_test.go @@ -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) } }) } diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 3be284706..385b0dde7 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -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) } }) } diff --git a/pkg/vars/vars_test.go b/pkg/vars/vars_test.go index e59113e1f..20ba9cf0e 100644 --- a/pkg/vars/vars_test.go +++ b/pkg/vars/vars_test.go @@ -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) } }) } diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go new file mode 100644 index 000000000..e54a76c7e --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go @@ -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) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go new file mode 100644 index 000000000..80c60617e --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go @@ -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()) +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go new file mode 100644 index 000000000..0eb2a758c --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go @@ -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() +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go new file mode 100644 index 000000000..ca11a4024 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go @@ -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 +} diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go new file mode 100644 index 000000000..8812443a2 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go @@ -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) +} diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go index fd2b3a42b..087320da7 100644 --- a/vendor/github.com/google/go-cmp/cmp/compare.go +++ b/vendor/github.com/google/go-cmp/cmp/compare.go @@ -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 diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go index bc196b16c..a248e5436 100644 --- a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go @@ -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 { diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go b/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go deleted file mode 100644 index 9147a2997..000000000 --- a/vendor/github.com/google/go-cmp/cmp/internal/value/zero.go +++ /dev/null @@ -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 -} diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go index e57b9eb53..1f9ca9c48 100644 --- a/vendor/github.com/google/go-cmp/cmp/options.go +++ b/vendor/github.com/google/go-cmp/cmp/options.go @@ -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 diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go index c71003463..a0a588502 100644 --- a/vendor/github.com/google/go-cmp/cmp/path.go +++ b/vendor/github.com/google/go-cmp/cmp/path.go @@ -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 "" } - 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 } diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go index 1ef65ac1d..2050bf6b4 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_compare.go +++ b/vendor/github.com/google/go-cmp/cmp/report_compare.go @@ -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 diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go index 287b89358..2ab41fad3 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_reflect.go +++ b/vendor/github.com/google/go-cmp/cmp/report_reflect.go @@ -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 { diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go index 68b5c1ae1..23e444f62 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_slices.go +++ b/vendor/github.com/google/go-cmp/cmp/report_slices.go @@ -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 { diff --git a/vendor/github.com/google/go-cmp/cmp/report_text.go b/vendor/github.com/google/go-cmp/cmp/report_text.go index 0fd46d7ff..388fcf571 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_text.go +++ b/vendor/github.com/google/go-cmp/cmp/report_text.go @@ -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 diff --git a/vendor/github.com/kylelemons/godebug/LICENSE b/vendor/github.com/kylelemons/godebug/LICENSE deleted file mode 100644 index d64569567..000000000 --- a/vendor/github.com/kylelemons/godebug/LICENSE +++ /dev/null @@ -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. diff --git a/vendor/github.com/kylelemons/godebug/diff/diff.go b/vendor/github.com/kylelemons/godebug/diff/diff.go deleted file mode 100644 index 200e596c6..000000000 --- a/vendor/github.com/kylelemons/godebug/diff/diff.go +++ /dev/null @@ -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 -} diff --git a/vendor/github.com/kylelemons/godebug/pretty/.gitignore b/vendor/github.com/kylelemons/godebug/pretty/.gitignore deleted file mode 100644 index fa9a735da..000000000 --- a/vendor/github.com/kylelemons/godebug/pretty/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.test -*.bench -*.golden -*.txt -*.prof diff --git a/vendor/github.com/kylelemons/godebug/pretty/doc.go b/vendor/github.com/kylelemons/godebug/pretty/doc.go deleted file mode 100644 index 03b5718a7..000000000 --- a/vendor/github.com/kylelemons/godebug/pretty/doc.go +++ /dev/null @@ -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 diff --git a/vendor/github.com/kylelemons/godebug/pretty/public.go b/vendor/github.com/kylelemons/godebug/pretty/public.go deleted file mode 100644 index fbc5d7abb..000000000 --- a/vendor/github.com/kylelemons/godebug/pretty/public.go +++ /dev/null @@ -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)) -} diff --git a/vendor/github.com/kylelemons/godebug/pretty/reflect.go b/vendor/github.com/kylelemons/godebug/pretty/reflect.go deleted file mode 100644 index 5cd30b7f0..000000000 --- a/vendor/github.com/kylelemons/godebug/pretty/reflect.go +++ /dev/null @@ -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 } diff --git a/vendor/github.com/kylelemons/godebug/pretty/structure.go b/vendor/github.com/kylelemons/godebug/pretty/structure.go deleted file mode 100644 index d876f60ca..000000000 --- a/vendor/github.com/kylelemons/godebug/pretty/structure.go +++ /dev/null @@ -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, "", 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) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 63f3d237e..3f658ef56 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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