diff --git a/decoder/decoder_test.go b/decoder/decoder_test.go index fa97881..6a0c4f6 100644 --- a/decoder/decoder_test.go +++ b/decoder/decoder_test.go @@ -101,8 +101,8 @@ func Test_Decode(t *testing.T) { options: decoder.DecoderOptions{Rules: []decoder.SchemaValidationRule{decoder.INVALID_TYPE, decoder.REQUIRED_ATTRIBUTE}}, }, want: map[string][]string{ - "id": {"decoder.REQUIRED_ATTRIBUTE_MISSING"}, - "name": {"decoder.REQUIRED_ATTRIBUTE_MISSING"}, + "id": {"REQUIRED_ATTRIBUTE_MISSING"}, + "name": {"REQUIRED_ATTRIBUTE_MISSING"}, }, }, { @@ -125,8 +125,8 @@ func Test_Decode(t *testing.T) { options: decoder.DecoderOptions{Rules: []decoder.SchemaValidationRule{decoder.INVALID_TYPE, decoder.REQUIRED_ATTRIBUTE}}, }, want: map[string][]string{ - "id": {"decoder.REQUIRED_ATTRIBUTE_MISSING"}, - "name": {"decoder.REQUIRED_ATTRIBUTE_MISSING"}, + "id": {"REQUIRED_ATTRIBUTE_MISSING"}, + "name": {"REQUIRED_ATTRIBUTE_MISSING"}, }, }, { diff --git a/decoder/parser.go b/decoder/parser.go index 84dd5c6..125b5d4 100644 --- a/decoder/parser.go +++ b/decoder/parser.go @@ -304,12 +304,12 @@ func getAttributes(rv reflect.Value, parents []StructAttribute, filterTags, igno // Struct field definition rsf := rv.Type().Field(position) - sa := StructAttribute{ + sa := *NewStructAttribute(NewStructAttributeFields{ Value: value, Field: rsf, Parents: parents, ListPosition: currentIndex, - } + }) // Do not include an anonymous field at the top level. // Only include its inner fields. @@ -356,12 +356,12 @@ func getAttributes(rv reflect.Value, parents []StructAttribute, filterTags, igno el := value.Index(l) if isListOfPrimitives { - child := StructAttribute{ + child := *NewStructAttribute(NewStructAttributeFields{ Value: el, Parents: newParents, ListPosition: l, - isPrimitive: true, - } + IsPrimitive: true, + }) // Copy information from parent StructField child.Field = reflect.StructField{ diff --git a/decoder/parser_test.go b/decoder/parser_test.go index 7da9b94..5f0539a 100644 --- a/decoder/parser_test.go +++ b/decoder/parser_test.go @@ -315,7 +315,7 @@ func Test_GetAllAttributes(t *testing.T) { } } -func TestGetAttributes_WithSpecificTags(t *testing.T) { +func Test_GetAttributes_WithSpecificTags(t *testing.T) { type Expectation struct { Name string Model any @@ -387,7 +387,7 @@ func TestGetAttributes_WithSpecificTags(t *testing.T) { } } -func TestGetTagValues(t *testing.T) { +func Test_GetTagValues(t *testing.T) { var field reflect.StructField = reflect.StructField{ Tag: `json:"id,omitempty" db:"_id"`, } @@ -410,7 +410,7 @@ func TestGetTagValues(t *testing.T) { } } -func TestGetTag(t *testing.T) { +func Test_GetTag(t *testing.T) { var field reflect.StructField = reflect.StructField{ Tag: `json:"id,omitempty" db:"_id" validate:"min=1,max=255,required"`, } @@ -432,7 +432,7 @@ func TestGetTag(t *testing.T) { } } -func TestGetTags(t *testing.T) { +func Test_GetTags(t *testing.T) { var field reflect.StructField = reflect.StructField{ Tag: `json:"id,omitempty" db:"_id"`, } @@ -448,7 +448,7 @@ func TestGetTags(t *testing.T) { } } -func TestTagContainsValues(t *testing.T) { +func Test_TagContainsValues(t *testing.T) { type Expectation struct { Name string Field reflect.StructField @@ -527,7 +527,7 @@ func TestTagContainsValues(t *testing.T) { } } -func TestMatchingFields(t *testing.T) { +func Test_MatchingFields(t *testing.T) { type Expectation struct { Name string Model any @@ -619,7 +619,7 @@ func TestMatchingFields(t *testing.T) { } } -func TestSetValuesFromMap(t *testing.T) { +func Test_SetValuesFromMap(t *testing.T) { type args struct { model any values map[string]any @@ -667,7 +667,7 @@ func TestSetValuesFromMap(t *testing.T) { } } -func TestSetValuesFromBytes(t *testing.T) { +func Test_SetValuesFromBytes(t *testing.T) { type args struct { model any values []byte @@ -715,7 +715,7 @@ func TestSetValuesFromBytes(t *testing.T) { } } -func TestRemoveValuesFromTag(t *testing.T) { +func Test_RemoveValuesFromTag(t *testing.T) { type args struct { tag string removeList []string diff --git a/decoder/struct.go b/decoder/struct.go index 2648c7d..1ce79e2 100644 --- a/decoder/struct.go +++ b/decoder/struct.go @@ -4,16 +4,19 @@ import ( "fmt" "reflect" "strings" + + "github.com/oleoneto/go-toolkit/helpers" ) // This type abstracts both `reflect.Value` and `reflect.StructField` types. type StructAttribute struct { Value reflect.Value Field reflect.StructField - Parents []StructAttribute Children []StructAttribute ListPosition int isPrimitive bool + + name *string } type NewStructAttributeFields struct { @@ -26,7 +29,7 @@ type NewStructAttributeFields struct { type StructAttributes []StructAttribute -// Returns the name of the field properly scoped under its parents. +// Sets and returns the name of the field properly scoped under its parents. // // Usage: // @@ -40,13 +43,14 @@ type StructAttributes []StructAttribute // } // } // -// sa.FullName() // -> "parentA.listB[i].attribute_name" -func (sa *StructAttribute) FullName() (name string) { - if len(sa.Parents) == 0 { - return GetJSONTagValue(sa.Field) +// sa.assignName(parents...) // -> "parentA.listB[i].attribute_name" +func (sa *StructAttribute) assignName(parents ...StructAttribute) string { + if len(parents) < 1 { + sa.name = helpers.PointerTo(GetJSONTagValue(sa.Field)) + return *sa.name } - scope := sa.Parents[len(sa.Parents)-1].FullName() + scope := parents[len(parents)-1].FullName() // Adds the array notation to the slice/array field if sa.ListPosition >= 0 { @@ -54,15 +58,20 @@ func (sa *StructAttribute) FullName() (name string) { } if sa.isPrimitive { - return scope + sa.name = helpers.PointerTo(scope) + return *sa.name } fullName := strings.Join([]string{scope, GetJSONTagValue(sa.Field)}, ".") - // Ensures field name is never prefixed by a dot (.) - return strings.TrimSuffix(strings.TrimPrefix(fullName, "."), ".") + // Ensures field name is never prefixed or suffixed by a dot (.) + sa.name = helpers.PointerTo(strings.TrimSuffix(strings.TrimPrefix(fullName, "."), ".")) + + return *sa.name } +func (sa *StructAttribute) FullName() string { return *sa.name } + func (sa *StructAttribute) SkipsPastLastChild() int { if len(sa.Children) == 0 { return 0 @@ -77,12 +86,15 @@ func (sa *StructAttribute) SkipsPastLastChild() int { } func NewStructAttribute(args NewStructAttributeFields) *StructAttribute { - return &StructAttribute{ + sa := &StructAttribute{ Value: args.Value, Field: args.Field, - Parents: args.Parents, Children: args.Children, ListPosition: args.ListPosition, isPrimitive: args.IsPrimitive, } + + sa.assignName(args.Parents...) + + return sa } diff --git a/decoder/struct_test.go b/decoder/struct_test.go index 944d8e1..cf30fa3 100644 --- a/decoder/struct_test.go +++ b/decoder/struct_test.go @@ -7,13 +7,13 @@ import ( "github.com/oleoneto/go-toolkit/decoder" ) -func TestStructAttribute_SkipsPastLastChild(t *testing.T) { +func Test_StructAttribute_SkipsPastLastChild(t *testing.T) { type fields struct { - Value reflect.Value - Field reflect.StructField - Parents []decoder.StructAttribute - Children []decoder.StructAttribute - ListPosition int + value reflect.Value + field reflect.StructField + parents []decoder.StructAttribute + children []decoder.StructAttribute + listPosition int isPrimitive bool } tests := []struct { @@ -24,14 +24,14 @@ func TestStructAttribute_SkipsPastLastChild(t *testing.T) { { name: "test - 1", fields: fields{ - Children: []decoder.StructAttribute{}, + children: []decoder.StructAttribute{}, }, want: 0, }, { name: "test - 2", fields: fields{ - Children: []decoder.StructAttribute{{}}, + children: []decoder.StructAttribute{{}}, }, want: 3, }, @@ -39,11 +39,11 @@ func TestStructAttribute_SkipsPastLastChild(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sa := decoder.NewStructAttribute(decoder.NewStructAttributeFields{ - Value: tt.fields.Value, - Field: tt.fields.Field, - Parents: tt.fields.Parents, - Children: tt.fields.Children, - ListPosition: tt.fields.ListPosition, + Value: tt.fields.value, + Field: tt.fields.field, + Parents: tt.fields.parents, + Children: tt.fields.children, + ListPosition: tt.fields.listPosition, IsPrimitive: tt.fields.isPrimitive, }) diff --git a/validator/validator_test.go b/validator/validator_test.go index 211e965..410d5d8 100644 --- a/validator/validator_test.go +++ b/validator/validator_test.go @@ -539,61 +539,61 @@ func Test_PassesRegex(t *testing.T) { str string } tests := []struct { - name string - args args - want bool + name string + args args + passes bool }{ { - name: "numeric - 0", - want: false, + name: "numeric - 0", + passes: false, args: args{ pattern: `\d+`, str: "leonardo", }, }, { - name: "numeric - 1", - want: true, + name: "numeric - 1", + passes: true, args: args{ pattern: `\d+`, str: "299", }, }, { - name: "numeric - 2", - want: true, + name: "numeric - 2", + passes: true, args: args{ pattern: `\d{3}$`, str: "299", }, }, { - name: "numeric - 3", - want: false, + name: "numeric - 3", + passes: false, args: args{ pattern: `^\d{2}$`, str: "299", }, }, { - name: "US phone number - 1", - want: false, + name: "US phone number - 1", + passes: false, args: args{ pattern: `^\d{3}-\d{3}-\d{4}$`, str: "55-5-5555-5555", }, }, { - name: "US phone number - 2", - want: true, + name: "US phone number - 2", + passes: true, args: args{ pattern: `^\d{3}-\d{3}-\d{4}$`, str: "555-555-5555", }, }, { - name: "invalid - 1", - want: false, + name: "invalid - 1", + passes: false, args: args{ pattern: `/\`, str: "#FBA", @@ -603,8 +603,8 @@ func Test_PassesRegex(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := validator.PassesRegex(tt.args.pattern, tt.args.str); got != tt.want { - t.Errorf("PassesRegex() = %v, want %v", got, tt.want) + if got := validator.PassesRegex(tt.args.pattern, tt.args.str); got != tt.passes { + t.Errorf("PassesRegex() = %v, want %v", got, tt.passes) } }) }