Change:
The commands under will benefit of a batter unit test coverage as seen in Originally posted by in
/sig api-machinery /assign
GitHub didn't allow me to assign the following users: damiansawicki. Note that only with read permissions, repo collaborators and people who have commented on this issue/PR can be assigned. Additionally, issues/PRs can only have 10 assignees at the same time. For more information please see <detailsIn response to : /sig api-machinery Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/triage accepted
Hi I would like to work on this issue. Could you tell me how many test files are needed per PR under this issue?
Hi the issue is already assigned to me. Would you consider contributing to other issues to avoid duplication?
Hi do you mind if I work on this issue along with you? I would only like to write tests on limited number of files, if that's okay with you...
Hi thanks for your engagement! If you also want to work on this particular issue, we should coordinate. Are you working on something other than ?
Hey currently I'm thinking of shifting to Do let me know if you are already working on that particular directory. Also I could assist you in any of your work on this issue as I'm not preoccupied at the moment.

Discussion:
package prereleaselifecyclegenerators import ( <ins> "fmt" </ins> "reflect" <ins> "strconv" </ins> "testing" "k8s.io/gengo/types" <ins> "k8s.io/klog/v2" </ins> ) var mockType = &types.Type{

} func Test_extractKubeVersionTag(t *testing.T) { <ins> oldKlogOsExit := klog.OsExit defer func() { klog.OsExit = oldKlogOsExit }() klog.OsExit = customExit </ins> tests := []struct { name        string tagName     string

wantMajor   int wantMinor   int wantErr     bool <ins> wantFatal   bool </ins> }{ { name:    "not found tag should generate an error",

wantMinor: 5, wantErr:   false, }, <del> /*{ </del> <ins> { </ins> name:    "multiple declarations of same tag should return an error", tagName: "someVersionTag:version", tagComments: []string{

"+someVersionTag:version=v1.7", }, wantValue: nil, <del> wantErr:   true, // TODO: Today it is klog.Fatal, check how to capture it </del> <ins> wantFatal: true, </ins> }, { name:    "multiple values on same tag should return an error",

"+someVersionTag:version=1.5,something", }, wantValue: nil, <del> wantErr:   true, // TODO: Today it is klog.Fatal, check how to capture it },*/ </del> <ins> wantFatal: true, }, </ins> { name:    "wrong tag major value should return an error", tagName: "someVersionTag:version",

for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockType.SecondClosestCommentLines = tt.tagComments <del> gotTag, gotMajor, gotMinor, err := extractKubeVersionTag(tt.tagName, mockType) </del> <ins> gotTag, gotMajor, gotMinor, err, fatalErr := safeExtractKubeVersionTag(tt.tagName, mockType) if (fatalErr != nil) != tt.wantFatal { t.Errorf("extractKubeVersionTag() fatalErr = %v, wantFatal %v", fatalErr, tt.wantFatal) return } if tt.wantFatal { return } </ins> if (err != nil) != tt.wantErr { t.Errorf("extractKubeVersionTag() error = %v, wantErr %v", err, tt.wantErr) return

}) } } <ins> func customExit(exitCode int) { panic(strconv.Itoa(exitCode)) } func safeExtractKubeVersionTag(tagName string, t *types.Type) (value *tagValue, major int, minor int, err error, localErr error) { defer func() { if e := recover(); e != nil { localErr = fmt.Errorf("extractKubeVersionTag returned error: %v", e) } }() value, major, minor, err = extractKubeVersionTag(tagName, t) return } func safeExtractTag(t *testing.T, tagName string, comments []string) (value *tagValue, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("extractTag returned error: %v", e) } }() value = extractTag(tagName, comments) return } func Test_extractTag(t *testing.T) { oldKlogOsExit := klog.OsExit defer func() { klog.OsExit = oldKlogOsExit }() klog.OsExit = customExit comments := []string{ "+variable=7", "+anotherVariable=8", "+yetAnotherVariable=9", "variableWithoutMarker=10", "+variableWithoutValue", "+variable=11", "+multi-valuedVariable=12,13,14", "+strangeVariable=15,=16", } tests := []struct { name         string tagComments  []string variableName string wantError    bool wantValue    *tagValue }{ { name:         "variable with explicit value", tagComments:  comments, variableName: "anotherVariable", wantValue:    &tagValue{value: "8"}, }, { name:         "variable without explicit value", tagComments:  comments, variableName: "variableWithoutValue", wantValue:    &tagValue{value: ""}, }, { name:         "variable not present in comments", tagComments:  comments, variableName: "variableOutOfNowhere", wantValue:    nil, }, { name:         "variable without marker test", tagComments:  comments, variableName: "variableWithoutMarker", wantValue:    nil, }, { name:         "abort duplicated variable", tagComments:  comments, variableName: "variable", wantError:    true, wantValue:    nil, }, { name:         "abort variable with multiple values", tagComments:  comments, variableName: "multi-valuedVariable", wantError:    true, wantValue:    nil, }, { name:         "this test documents strange behaviour", // TODO: Is this behaviour intended? tagComments:  comments, variableName: "strangeVariable", wantValue:    &tagValue{value: "15"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotTag, err := safeExtractTag(t, tt.variableName, tt.tagComments) if (err != nil) != tt.wantError { t.Errorf("extractTag() err = %v, wantError = %v.", gotTag, tt.wantError) return } if tt.wantError { return } if !reflect.DeepEqual(gotTag, tt.wantValue) { t.Errorf("extractTag() got = %v, want %v", gotTag, tt.wantValue) } }) } } func Test_extractEnabledTypeTag(t *testing.T) { someComments := []string{ "+variable=7", "+k8s:prerelease-lifecycle-gen=8", } moreComments := []string{ "+yetAnotherVariable=9", "variableWithoutMarker=10", "+variableWithoutValue", "+variable=11", "+multi-valuedVariable=12,13,14", } tests := []struct { name      string mockType  *types.Type wantValue *tagValue }{ { name:      "desired info in main comments", mockType:  &types.Type{CommentLines: someComments, SecondClosestCommentLines: moreComments}, wantValue: &tagValue{value: "8"}, }, { name:      "secondary comments empty", mockType:  &types.Type{CommentLines: someComments}, wantValue: &tagValue{value: "8"}, }, { name:      "main comments empty", mockType:  &types.Type{SecondClosestCommentLines: someComments}, wantValue: &tagValue{value: "8"}, }, { name:      "lack of desired info, empty secondary comments", mockType:  &types.Type{CommentLines: moreComments}, wantValue: nil, }, { name:      "lack of desired info, empty main comments", mockType:  &types.Type{SecondClosestCommentLines: moreComments}, wantValue: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotTag := extractEnabledTypeTag(tt.mockType) if !reflect.DeepEqual(gotTag, tt.wantValue) { t.Errorf("extractEnabledTypeTag() got = %v, want %v", gotTag, tt.wantValue) } }) } } func Test_extractReplacementTag(t *testing.T) { replacementTag := "+k8s:prerelease-lifecycle-gen:replacement" tests := []struct { name               string mainComments       []string secondaryComments  []string wantGroup          string wantVersion        string wantKind           string wantHasReplacement bool wantErr            bool }{ { name:               "no replacement tag", mainComments:       []string{"randomText=7"}, secondaryComments:  []string{"importantFlag=8.8.8.8"}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            false, }, { name:               "replacement tag correct", mainComments:       []string{fmt.Sprintf("%v=my_group,v1,KindOf", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "my_group", wantVersion:        "v1", wantKind:           "KindOf", wantHasReplacement: true, wantErr:            false, }, { name:               "correct replacement tag in secondary comments", mainComments:       []string{}, secondaryComments:  []string{fmt.Sprintf("%v=my_group,v1,KindOf", replacementTag)}, wantGroup:          "my_group", wantVersion:        "v1", wantKind:           "KindOf", wantHasReplacement: true, wantErr:            false, }, { name:               "4 values instead of 3", mainComments:       []string{fmt.Sprintf("%v=my_group,v1,KindOf,subKind", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, { name:               "4 values instead of 3 in secondary comments", mainComments:       []string{}, secondaryComments:  []string{fmt.Sprintf("%v=my_group,v1,KindOf,subKind", replacementTag)}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, { name:               "2 values instead of 3", mainComments:       []string{fmt.Sprintf("%v=my_group,v1", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, { name:               "group name not all upper", mainComments:       []string{fmt.Sprintf("%v=myGroup,v1,KindOf", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, { name:               "version name does not start with v", mainComments:       []string{fmt.Sprintf("%v=my_group,bestVersion,KindOf", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, { name:               "kind name does not start with capital", mainComments:       []string{fmt.Sprintf("%v=my_group,v1,kindOf", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, { name:               "empty group name", // TODO: is it a valid input or a bug? mainComments:       []string{fmt.Sprintf("%v=,v1,KindOf", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "v1", wantKind:           "KindOf", wantHasReplacement: true, wantErr:            false, }, { name:               "empty version", mainComments:       []string{fmt.Sprintf("%v=my_group,,KindOf", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, { name:               "empty kind", mainComments:       []string{fmt.Sprintf("%v=my_group,v1,", replacementTag)}, secondaryComments:  []string{}, wantGroup:          "", wantVersion:        "", wantKind:           "", wantHasReplacement: false, wantErr:            true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { replacementGroup, replacementVersion, replacementKind, hasReplacement, err := extractReplacementTag(&types.Type{ CommentLines:              tt.mainComments, SecondClosestCommentLines: tt.secondaryComments, }) if replacementGroup != tt.wantGroup { t.Errorf("extractReplacementTag() group got = %v, want %v", replacementGroup, tt.wantGroup) } if replacementVersion != tt.wantVersion { t.Errorf("extractReplacementTag() version got = %v, want %v", replacementVersion, tt.wantVersion) } if replacementKind != tt.wantKind { t.Errorf("extractReplacementTag() kind got = %v, want %v", replacementKind, tt.wantKind) } if hasReplacement != tt.wantHasReplacement { t.Errorf("extractReplacementTag() hasReplacement got = %v, want %v", hasReplacement, tt.wantHasReplacement) } if (err != nil) != tt.wantErr { t.Errorf("extractReplacementTag() err got = %v, want %v", err, tt.wantErr) } }) } } func Test_isAPIType(t *testing.T) { tests := []struct { name string t    *types.Type want bool }{ { name: "private name is not apitype", want: false, t: &types.Type{ Name: types.Name{ Name: "notpublic", }, }, }, { name: "non struct is not apitype", want: false, t: &types.Type{ Name: types.Name{ Name: "Public", }, Kind: types.Slice, }, }, { name: "contains member type", want: true, t: &types.Type{ Name: types.Name{ Name: "Public", }, Kind: types.Struct, Members: []types.Member{ { Embedded: true, Name:     "TypeMeta", }, }, }, }, { name: "contains no type", want: false, t: &types.Type{ Name: types.Name{ Name: "Public", }, Kind: types.Struct, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := isAPIType(tt.t); got != tt.want { t.Errorf("isAPIType() = %v, want %v", got, tt.want) } }) } } </ins>