Skip to content

Commit 1ffc34f

Browse files
committed
remove cycle dependency issue
1 parent 3a55a37 commit 1ffc34f

File tree

4 files changed

+185
-37
lines changed

4 files changed

+185
-37
lines changed

utils/field/fields.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ package field
99
import (
1010
"time"
1111

12-
"github.com/ARM-software/golang-utils/utils/reflection"
12+
"github.com/ARM-software/golang-utils/utils/value"
1313
)
1414

1515
// ToOptionalInt returns a pointer to an int
@@ -216,7 +216,7 @@ func ToOptional[T any](v T) *T {
216216

217217
// ToOptionalOrNilIfEmpty returns a pointer to the given field value unless it is empty and in that case returns nil.
218218
func ToOptionalOrNilIfEmpty[T any](v T) *T {
219-
if reflection.IsEmpty(v) {
219+
if value.IsEmpty(v) {
220220
return nil
221221
}
222222
return ToOptional[T](v)

utils/reflection/reflection.go

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ package reflection
77
import (
88
"fmt"
99
"reflect"
10-
"strings"
1110
"unsafe"
1211

1312
"github.com/ARM-software/golang-utils/utils/commonerrors"
13+
valueUtils "github.com/ARM-software/golang-utils/utils/value"
1414
)
1515

1616
func GetUnexportedStructureField(structure interface{}, fieldName string) interface{} {
@@ -22,8 +22,8 @@ func GetStructureField(field reflect.Value) interface{} {
2222
return nil
2323
}
2424
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())). //nolint:gosec // this conversion is between types recommended by Go https://cs.opensource.google/go/go/+/master:src/reflect/value.go;l=2445
25-
Elem().
26-
Interface()
25+
Elem().
26+
Interface()
2727
}
2828
func SetUnexportedStructureField(structure interface{}, fieldName string, value interface{}) {
2929
SetStructureField(fetchStructureField(structure, fieldName), value)
@@ -33,8 +33,8 @@ func SetStructureField(field reflect.Value, value interface{}) {
3333
return
3434
}
3535
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())). //nolint:gosec // this conversion is between types recommended by Go https://cs.opensource.google/go/go/+/master:src/reflect/value.go;l=2445
36-
Elem().
37-
Set(reflect.ValueOf(value))
36+
Elem().
37+
Set(reflect.ValueOf(value))
3838
}
3939

4040
func fetchStructureField(structure interface{}, fieldName string) reflect.Value {
@@ -198,36 +198,7 @@ func InheritsFrom(object interface{}, parentType reflect.Type) bool {
198198
// IsEmpty checks whether a value is empty i.e. "", nil, 0, [], {}, false, etc.
199199
// For Strings, a string is considered empty if it is "" or if it only contains whitespaces
200200
func IsEmpty(value any) bool {
201-
if value == nil {
202-
return true
203-
}
204-
if valueStr, ok := value.(string); ok {
205-
return len(strings.TrimSpace(valueStr)) == 0
206-
}
207-
if valueStrPtr, ok := value.(*string); ok {
208-
if valueStrPtr == nil {
209-
return true
210-
}
211-
return len(strings.TrimSpace(*valueStrPtr)) == 0
212-
}
213-
if valueBool, ok := value.(bool); ok {
214-
// if set to true, then value is not empty
215-
return !valueBool
216-
}
217-
objValue := reflect.ValueOf(value)
218-
switch objValue.Kind() {
219-
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
220-
return objValue.Len() == 0
221-
case reflect.Ptr:
222-
if objValue.IsNil() {
223-
return true
224-
}
225-
deref := objValue.Elem().Interface()
226-
return IsEmpty(deref)
227-
default:
228-
zero := reflect.Zero(objValue.Type())
229-
return reflect.DeepEqual(value, zero.Interface())
230-
}
201+
return valueUtils.IsEmpty(value)
231202
}
232203

233204
// ToStructPtr returns an instance of the pointer (interface) to the object obj.

utils/value/empty.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package value
2+
3+
import (
4+
"reflect"
5+
"strings"
6+
)
7+
8+
// IsEmpty checks whether a value is empty i.e. "", nil, 0, [], {}, false, etc.
9+
// For Strings, a string is considered empty if it is "" or if it only contains whitespaces
10+
func IsEmpty(value any) bool {
11+
if value == nil {
12+
return true
13+
}
14+
if valueStr, ok := value.(string); ok {
15+
return len(strings.TrimSpace(valueStr)) == 0
16+
}
17+
if valueStrPtr, ok := value.(*string); ok {
18+
if valueStrPtr == nil {
19+
return true
20+
}
21+
return len(strings.TrimSpace(*valueStrPtr)) == 0
22+
}
23+
if valueBool, ok := value.(bool); ok {
24+
// if set to true, then value is not empty
25+
return !valueBool
26+
}
27+
objValue := reflect.ValueOf(value)
28+
switch objValue.Kind() {
29+
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
30+
return objValue.Len() == 0
31+
case reflect.Ptr:
32+
if objValue.IsNil() {
33+
return true
34+
}
35+
deref := objValue.Elem().Interface()
36+
return IsEmpty(deref)
37+
default:
38+
zero := reflect.Zero(objValue.Type())
39+
return reflect.DeepEqual(value, zero.Interface())
40+
}
41+
}

utils/value/empty_test.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package value
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestIsEmpty(t *testing.T) {
12+
type testInterface interface {
13+
}
14+
var testEmptyPtr testInterface
15+
emptyStr := ""
16+
whiteSpace := " "
17+
18+
aFilledChannel := make(chan struct{}, 1)
19+
aFilledChannel <- struct{}{}
20+
tests := []struct {
21+
value interface{}
22+
isEmpty bool
23+
differsFromAssertEmpty bool
24+
}{
25+
{
26+
value: nil,
27+
isEmpty: true,
28+
},
29+
{
30+
value: 0,
31+
isEmpty: true,
32+
},
33+
{
34+
value: uint(0),
35+
isEmpty: true,
36+
},
37+
{
38+
value: float64(0),
39+
isEmpty: true,
40+
},
41+
{
42+
value: "",
43+
isEmpty: true,
44+
},
45+
{
46+
value: " ",
47+
isEmpty: true,
48+
differsFromAssertEmpty: true,
49+
},
50+
{
51+
value: (*string)(nil),
52+
isEmpty: true,
53+
},
54+
{
55+
value: &emptyStr,
56+
isEmpty: true,
57+
},
58+
{
59+
value: &whiteSpace,
60+
isEmpty: true,
61+
differsFromAssertEmpty: true,
62+
},
63+
{
64+
value: false,
65+
isEmpty: true,
66+
},
67+
{
68+
value: []string{},
69+
isEmpty: true,
70+
},
71+
{
72+
value: []int64{},
73+
isEmpty: true,
74+
},
75+
{
76+
value: []int64{int64(0)},
77+
isEmpty: false,
78+
},
79+
{
80+
value: "blah",
81+
isEmpty: false,
82+
},
83+
{
84+
value: 1,
85+
isEmpty: false,
86+
},
87+
{
88+
value: true,
89+
isEmpty: false,
90+
},
91+
{
92+
value: testEmptyPtr,
93+
isEmpty: true,
94+
},
95+
{
96+
value: map[string]string{},
97+
isEmpty: true,
98+
},
99+
{
100+
value: map[string]interface{}{},
101+
isEmpty: true,
102+
},
103+
{
104+
value: map[string]interface{}{"foo": "bar"},
105+
isEmpty: false,
106+
},
107+
{
108+
value: time.Time{},
109+
isEmpty: true,
110+
},
111+
{
112+
value: time.Now(),
113+
isEmpty: false,
114+
},
115+
{
116+
value: make(chan struct{}),
117+
isEmpty: true,
118+
},
119+
{
120+
value: aFilledChannel,
121+
isEmpty: false,
122+
},
123+
}
124+
125+
for i := range tests {
126+
test := tests[i]
127+
t.Run(fmt.Sprintf("subtest #%v (%v)", i, test.value), func(t *testing.T) {
128+
assert.Equal(t, test.isEmpty, IsEmpty(test.value))
129+
if test.isEmpty && !test.differsFromAssertEmpty {
130+
assert.Empty(t, test.value)
131+
} else {
132+
assert.NotEmpty(t, test.value)
133+
}
134+
})
135+
}
136+
}

0 commit comments

Comments
 (0)