package generators import ( "reflect" "testing" "go-common/app/tool/gengo/types" ) func Test_isRootedUnder(t *testing.T) { testCases := []struct { path string roots []string expect bool }{ { path: "/foo/bar", roots: nil, expect: false, }, { path: "/foo/bar", roots: []string{}, expect: false, }, { path: "/foo/bar", roots: []string{ "/bad", }, expect: false, }, { path: "/foo/bar", roots: []string{ "/foo", }, expect: true, }, { path: "/foo/bar", roots: []string{ "/bad", "/foo", }, expect: true, }, { path: "/foo/bar/qux/zorb", roots: []string{ "/foo/bar/qux", }, expect: true, }, { path: "/foo/bar", roots: []string{ "/foo/bar", }, expect: true, }, { path: "/foo/barn", roots: []string{ "/foo/bar", }, expect: false, }, { path: "/foo/bar", roots: []string{ "/foo/barn", }, expect: false, }, { path: "/foo/bar", roots: []string{ "", }, expect: true, }, } for i, tc := range testCases { r := isRootedUnder(tc.path, tc.roots) if r != tc.expect { t.Errorf("case[%d]: expected %t, got %t for %q in %q", i, tc.expect, r, tc.path, tc.roots) } } } func Test_deepCopyMethod(t *testing.T) { testCases := []struct { typ types.Type expect bool error bool }{ { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, // No DeepCopy method. Methods: map[string]*types.Type{}, }, expect: false, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // No DeepCopy method. "method": { Name: types.Name{Package: "pkgname", Name: "func()"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{}, }, }, }, }, expect: false, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (no result). "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func()"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{}, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (wrong result). "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func() int"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{ { Name: types.Name{Name: "int"}, Kind: types.Builtin, }, }, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature with pointer receiver, but non-pointer result. "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{ { Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, }, }, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature with non-pointer receiver, but pointer result. "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, Parameters: []*types.Type{}, Results: []*types.Type{ { Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, }, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Correct signature with non-pointer receiver. "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, Parameters: []*types.Type{}, Results: []*types.Type{ { Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, }, }, }, }, }, }, expect: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Correct signature with pointer receiver. "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{ { Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, }, }, }, }, }, expect: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (has params). "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func(int) pkgname.typename"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{ { Name: types.Name{Name: "int"}, Kind: types.Builtin, }, }, Results: []*types.Type{ { Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, }, }, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (extra results). "DeepCopy": { Name: types.Name{Package: "pkgname", Name: "func() (pkgname.typename, int)"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{ { Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, }, { Name: types.Name{Name: "int"}, Kind: types.Builtin, }, }, }, }, }, }, expect: false, error: true, }, } for i, tc := range testCases { r, err := deepCopyMethod(&tc.typ) if tc.error && err == nil { t.Errorf("case[%d]: expected an error, got none", i) } else if !tc.error && err != nil { t.Errorf("case[%d]: expected no error, got: %v", i, err) } else if !tc.error && (r != nil) != tc.expect { t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) } } } func Test_deepCopyIntoMethod(t *testing.T) { testCases := []struct { typ types.Type expect bool error bool }{ { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, // No DeepCopyInto method. Methods: map[string]*types.Type{}, }, expect: false, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // No DeepCopyInto method. "method": { Name: types.Name{Package: "pkgname", Name: "func()"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{}, }, }, }, }, expect: false, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (no parameter). "DeepCopyInto": { Name: types.Name{Package: "pkgname", Name: "func()"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{}, Results: []*types.Type{}, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (unexpected result). "DeepCopyInto": { Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename) int"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{ { Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, }, Results: []*types.Type{ { Name: types.Name{Name: "int"}, Kind: types.Builtin, }, }, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (non-pointer parameter, pointer receiver). "DeepCopyInto": { Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{ {Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Results: []*types.Type{}, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Wrong signature (non-pointer parameter, non-pointer receiver). "DeepCopyInto": { Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, Parameters: []*types.Type{ {Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Results: []*types.Type{}, }, }, }, }, expect: false, error: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Correct signature with non-pointer receiver. "DeepCopyInto": { Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, Parameters: []*types.Type{ { Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, }, Results: []*types.Type{}, }, }, }, }, expect: true, }, { typ: types.Type{ Name: types.Name{Package: "pkgname", Name: "typename"}, Kind: types.Builtin, Methods: map[string]*types.Type{ // Correct signature with pointer receiver. "DeepCopyInto": { Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, Kind: types.Func, Signature: &types.Signature{ Receiver: &types.Type{ Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, Parameters: []*types.Type{ { Kind: types.Pointer, Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, }, }, Results: []*types.Type{}, }, }, }, }, expect: true, }, } for i, tc := range testCases { r, err := deepCopyIntoMethod(&tc.typ) if tc.error && err == nil { t.Errorf("case[%d]: expected an error, got none", i) } else if !tc.error && err != nil { t.Errorf("case[%d]: expected no error, got: %v", i, err) } else if !tc.error && (r != nil) != tc.expect { t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) } } } func Test_extractTagParams(t *testing.T) { testCases := []struct { comments []string expect *tagValue }{ { comments: []string{ "Human comment", }, expect: nil, }, { comments: []string{ "Human comment", "+bili:deepcopy-gen", }, expect: &tagValue{ value: "", register: false, }, }, { comments: []string{ "Human comment", "+bili:deepcopy-gen=package", }, expect: &tagValue{ value: "package", register: false, }, }, { comments: []string{ "Human comment", "+bili:deepcopy-gen=package,register", }, expect: &tagValue{ value: "package", register: true, }, }, { comments: []string{ "Human comment", "+bili:deepcopy-gen=package,register=true", }, expect: &tagValue{ value: "package", register: true, }, }, { comments: []string{ "Human comment", "+bili:deepcopy-gen=package,register=false", }, expect: &tagValue{ value: "package", register: false, }, }, } for i, tc := range testCases { r := extractTag(tc.comments) if r == nil && tc.expect != nil { t.Errorf("case[%d]: expected non-nil", i) } if r != nil && tc.expect == nil { t.Errorf("case[%d]: expected nil, got %v", i, *r) } if r != nil && *r != *tc.expect { t.Errorf("case[%d]: expected %v, got %v", i, *tc.expect, *r) } } } func Test_extractInterfacesTag(t *testing.T) { testCases := []struct { comments []string expect []string }{ { comments: []string{}, expect: nil, }, { comments: []string{ "+bili:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", }, expect: []string{ "k8s.io/kubernetes/runtime.Object", }, }, { comments: []string{ "+bili:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", "+bili:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.List", }, expect: []string{ "k8s.io/kubernetes/runtime.Object", "k8s.io/kubernetes/runtime.List", }, }, { comments: []string{ "+bili:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", "+bili:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", }, expect: []string{ "k8s.io/kubernetes/runtime.Object", "k8s.io/kubernetes/runtime.Object", }, }, } for i, tc := range testCases { r := extractInterfacesTag(tc.comments) if r == nil && tc.expect != nil { t.Errorf("case[%d]: expected non-nil", i) } if r != nil && tc.expect == nil { t.Errorf("case[%d]: expected nil, got %v", i, r) } if r != nil && !reflect.DeepEqual(r, tc.expect) { t.Errorf("case[%d]: expected %v, got %v", i, tc.expect, r) } } }