Skip to content

Commit 6db874c

Browse files
committed
test: improve test coverage
1 parent 59c90ae commit 6db874c

3 files changed

Lines changed: 160 additions & 123 deletions

File tree

tag.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func parseOptions(opts string, structPtr reflect.Value) error {
131131
return fmt.Errorf("missing option key")
132132
}
133133

134-
opt := val
134+
optName := val
135135
opts = opts[valLen:]
136136
skip = skipSpaces(opts)
137137
opts = opts[skip:]
@@ -142,21 +142,21 @@ func parseOptions(opts string, structPtr reflect.Value) error {
142142
opts = opts[skip:]
143143

144144
if len(opts) == 0 {
145-
return fmt.Errorf("missing value for option %q", opt)
145+
return fmt.Errorf("missing value for option %q", optName)
146146
}
147147

148-
val, valLen, err = scanOptValue(opts)
148+
val, valLen, err = scanOptValue(optName, opts, structPtr)
149149
if err != nil {
150150
return err
151151
}
152152

153-
if err = setOption(opt, val, structPtr); err != nil {
153+
if err = setOption(optName, val, structPtr); err != nil {
154154
return err
155155
}
156156

157157
opts = opts[valLen:]
158158
} else if len(opts) == 0 {
159-
if err = setFlagOption(opt, structPtr); err != nil {
159+
if err = setFlagOption(optName, structPtr); err != nil {
160160
return err
161161
}
162162

@@ -171,7 +171,7 @@ func parseOptions(opts string, structPtr reflect.Value) error {
171171
}
172172

173173
if opts[0] != ',' {
174-
return fmt.Errorf("missing comma after option %q", opt)
174+
return fmt.Errorf("missing comma after option %q", optName)
175175
} else {
176176
opts = opts[1:]
177177
}

tag_test.go

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ package tag
1717
import (
1818
"errors"
1919
"fmt"
20-
"testing"
21-
2220
"github.com/stretchr/testify/assert"
21+
"testing"
2322
)
2423

2524
type CustomType struct {
@@ -620,20 +619,14 @@ func TestParse(t *testing.T) {
620619
name: "invalid slice positional option missing closing bracket",
621620
rawTags: `test:"[11,41"`,
622621
tagStruct: &TestTag[[]int]{},
623-
wantErr: errors.New(`tag: failed to parse 'test' options "[11,41": unterminated slice, missing closing ']'`),
622+
wantErr: errors.New(`tag: failed to parse 'test' options "[11,41": unterminated value, missing closing ']'`),
624623
},
625624
{
626625
name: "invalid map positional option missing opening brace",
627626
rawTags: `test:"'key':'val'}"`,
628627
tagStruct: &TestTag[map[string]any]{},
629628
wantErr: errors.New(`tag: failed to parse 'test' options "'key':'val'}": expected { at the beginning of map value 'key'`),
630629
},
631-
{
632-
name: "invalid map positional option missing closing brace",
633-
rawTags: `test:"{'key':'val'"`,
634-
tagStruct: &TestTag[map[string]any]{},
635-
wantErr: errors.New(`tag: failed to parse 'test' options "{'key':'val'": unterminated map, missing closing '}'`),
636-
},
637630
{
638631
name: "full options",
639632
rawTags: `test:"any,int=1141,float=11.41,bool=true,slice=['a','b'],map={'key':'val'},stringSlice=['str1','str2'],intSlice=[11,22],floatSlice=[1.1,2.2],mapSlice=[{'key1':'val1'},{'key2':'val2'}]"`,
@@ -659,7 +652,7 @@ func TestParse(t *testing.T) {
659652
name: "slice option with missing opening bracket",
660653
rawTags: `test:"any,slice=['a','b'"`,
661654
tagStruct: &TestTag[any]{},
662-
wantErr: errors.New(`tag: failed to parse 'test' options "any,slice=['a','b'": unterminated slice, missing closing ']'`),
655+
wantErr: errors.New(`tag: failed to parse 'test' options "any,slice=['a','b'": unterminated value, missing closing ']'`),
663656
},
664657
{
665658
name: "nested slice positional option",
@@ -709,7 +702,110 @@ func TestParse(t *testing.T) {
709702
name: "invalid struct option",
710703
rawTags: `test:"any,struct='string':'value','int':1141,'float':11.41,'bool':true,'slice':['a','b'],'map':{'key':'val'}}"`,
711704
tagStruct: &TestTag[any]{},
712-
wantErr: errors.New(`tag: failed to parse 'test' options "any,struct='string':'value','int':1141,'float':11.41,'bool':true,'slice':['a','b'],'map':{'key':'val'}}": failed to set option "struct": expected {, but got 'string'`),
705+
wantErr: errors.New(`tag: failed to parse 'test' options "any,struct='string':'value','int':1141,'float':11.41,'bool':true,'slice':['a','b'],'map':{'key':'val'}}": value must start with '{'`),
706+
},
707+
{
708+
name: "invalid bool option with non-bool value",
709+
rawTags: `test:"any,bool=non-bool"`,
710+
tagStruct: &TestTag[any]{},
711+
wantErr: errors.New(`tag: failed to parse 'test' options "any,bool=non-bool": invalid bool value "non-bool"`),
712+
},
713+
{
714+
name: "invalid bool option with empty value",
715+
rawTags: `test:"any,bool=[]"`,
716+
tagStruct: &TestTag[any]{},
717+
wantErr: errors.New(`tag: failed to parse 'test' options "any,bool=[]": invalid bool value`),
718+
},
719+
{
720+
name: "invalid integer option value",
721+
rawTags: `test:"any,int=non-int"`,
722+
tagStruct: &TestTag[any]{},
723+
wantErr: errors.New(`tag: failed to parse 'test' options "any,int=non-int": invalid integer value`),
724+
},
725+
{
726+
name: "invalid float option value",
727+
rawTags: `test:"any,float=non-float"`,
728+
tagStruct: &TestTag[any]{},
729+
wantErr: errors.New(`tag: failed to parse 'test' options "any,float=non-float": invalid float value`),
730+
},
731+
{
732+
name: "string option with escape characters",
733+
rawTags: `test:"any,string='line1\nline2\tTabbed'"`,
734+
tagStruct: &TestTag[any]{
735+
String: "line1\nline2\tTabbed",
736+
},
737+
},
738+
{
739+
name: "unsupported field type",
740+
rawTags: `test:"any"`,
741+
wantErr: errors.New(`tag: failed to parse 'test' options "any": unsupported field type: "chan bool"`),
742+
tagStruct: &TestTag[chan bool]{},
743+
},
744+
{
745+
name: "empty positional option value",
746+
rawTags: `test:","`,
747+
tagStruct: &TestTag[any]{},
748+
wantErr: errors.New(`tag: failed to parse 'test' options ",": cannot infer type from empty value`),
749+
},
750+
{
751+
name: "invalid map positional option with missing colon separator",
752+
rawTags: `test:"{'key'}"`,
753+
tagStruct: &TestTag[map[string]any]{},
754+
wantErr: errors.New(`tag: failed to parse 'test' options "{'key'}": invalid map item format, missing ':' separator`),
755+
},
756+
{
757+
name: "invalid custom type with missing colon separator",
758+
rawTags: `test:"{'key'}"`,
759+
tagStruct: &TestTag[CustomType]{},
760+
wantErr: errors.New(`tag: failed to parse 'test' options "{'key'}": invalid struct item format, missing ':' separator`),
761+
},
762+
{
763+
name: "invalid custom type positional option missing opening brace",
764+
rawTags: `test:"'key':'val'}"`,
765+
tagStruct: &TestTag[CustomType]{},
766+
wantErr: errors.New(`tag: failed to parse 'test' options "'key':'val'}": expected { at the beginning of value 'key'`),
767+
},
768+
{
769+
name: "expected , separator in slice",
770+
rawTags: `test:"['a' 'b']"`,
771+
tagStruct: &TestTag[[]string]{},
772+
wantErr: errors.New(`tag: failed to parse 'test' options "['a' 'b']": expected ',' between slice items in ''b']'`),
773+
},
774+
{
775+
name: "expected , separator in map",
776+
rawTags: `test:"{'key1':'val1' 'key2':'val2'}"`,
777+
tagStruct: &TestTag[map[string]string]{},
778+
wantErr: errors.New(`tag: failed to parse 'test' options "{'key1':'val1' 'key2':'val2'}": expected ',' between map items in ''key2':'val2'}'`),
779+
},
780+
{
781+
name: "expected , separator in custom type properties",
782+
rawTags: `test:"{'string':'value' 'int':1141}"`,
783+
tagStruct: &TestTag[CustomType]{},
784+
wantErr: errors.New(`tag: failed to parse 'test' options "{'string':'value' 'int':1141}": expected ',' between fields in ''int':1141}'`),
785+
},
786+
{
787+
name: "invalid map positional option with invalid key",
788+
rawTags: `test:"{: 'val'}"`,
789+
tagStruct: &TestTag[map[string]string]{},
790+
wantErr: errors.New(`tag: failed to parse 'test' options "{: 'val'}": invalid key: must start with '`),
791+
},
792+
{
793+
name: "invalid map positional option with invalid value",
794+
rawTags: `test:"{'key':}"`,
795+
tagStruct: &TestTag[map[string]any]{},
796+
wantErr: errors.New(`tag: failed to parse 'test' options "{'key':}": invalid value: must start with '`),
797+
},
798+
{
799+
name: "invalid custom type positional option with invalid field key",
800+
rawTags: `test:"{: 'value'}"`,
801+
tagStruct: &TestTag[CustomType]{},
802+
wantErr: errors.New(`tag: failed to parse 'test' options "{: 'value'}": invalid field name: must start with '`),
803+
},
804+
{
805+
name: "invalid custom type positional option with invalid field value",
806+
rawTags: `test:"{'string':}"`,
807+
tagStruct: &TestTag[CustomType]{},
808+
wantErr: errors.New(`tag: failed to parse 'test' options "{'string':}": invalid field value: must start with '`),
713809
},
714810
}
715811

0 commit comments

Comments
 (0)