-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Nullable Type Functions and DefaultIfNil Utility (#37)
* added pointer utils * added test cases * organized related functions in same files --------- Co-authored-by: Kashif Khan <[email protected]>
- Loading branch information
1 parent
62e0ef4
commit 1c951f5
Showing
6 changed files
with
917 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package pointers | ||
|
||
import "time" | ||
|
||
// DefaultIfNil returns the value of the pointer if it is not nil, | ||
// or the default value if the pointer is nil | ||
func DefaultIfNil[T any](ptr *T, defaultVal T) T { | ||
if ptr == nil { | ||
return defaultVal | ||
} | ||
return *ptr | ||
} | ||
|
||
// NullableBool returns the value of the bool pointer | ||
// or false if the pointer is nil | ||
func NullableBool(b *bool) bool { | ||
if b == nil { | ||
return false | ||
} | ||
return *b | ||
} | ||
|
||
// NullableTime returns the dereferenced value of *time.Time if not nil, | ||
// or a zero time.Time otherwise. | ||
func NullableTime(t *time.Time) time.Time { | ||
if t == nil { | ||
return time.Time{} | ||
} | ||
return *t | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
package pointers | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestDefaultIfNil(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
ptr interface{} | ||
defaultVal interface{} | ||
want interface{} | ||
}{ | ||
{ | ||
name: "success - ptr is nil with int", | ||
ptr: (*int)(nil), // explicitly passing a nil *int pointer | ||
defaultVal: 42, | ||
want: 42, | ||
}, | ||
{ | ||
name: "success - ptr is not nil with int", | ||
ptr: new(int), | ||
defaultVal: 42, | ||
want: 0, // default int value | ||
}, | ||
{ | ||
name: "success - ptr is not nil with int and custom value", | ||
ptr: func() *int { x := 100; return &x }(), | ||
defaultVal: 42, | ||
want: 100, | ||
}, | ||
{ | ||
name: "success - ptr is nil with string", | ||
ptr: (*string)(nil), // explicitly passing a nil *string pointer | ||
defaultVal: "default value", | ||
want: "default value", | ||
}, | ||
{ | ||
name: "success - ptr is not nil with string", | ||
ptr: new(string), | ||
defaultVal: "default value", | ||
want: "", | ||
}, | ||
{ | ||
name: "success - ptr is not nil with string and custom value", | ||
ptr: func() *string { s := "hello"; return &s }(), | ||
defaultVal: "default value", | ||
want: "hello", | ||
}, | ||
{ | ||
name: "success - ptr is nil with bool", | ||
ptr: (*bool)(nil), // explicitly passing a nil *bool pointer | ||
defaultVal: false, | ||
want: false, | ||
}, | ||
{ | ||
name: "success - ptr is not nil with bool", | ||
ptr: func() *bool { b := true; return &b }(), | ||
defaultVal: false, | ||
want: true, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
// Use type assertion to call DefaultIfNil correctly | ||
switch v := tt.ptr.(type) { | ||
case *int: | ||
got := DefaultIfNil(v, tt.defaultVal.(int)) | ||
if got != tt.want.(int) { | ||
t.Errorf("DefaultIfNil() = %v, want %v", got, tt.want) | ||
} | ||
case *string: | ||
got := DefaultIfNil(v, tt.defaultVal.(string)) | ||
if got != tt.want.(string) { | ||
t.Errorf("DefaultIfNil() = %v, want %v", got, tt.want) | ||
} | ||
case *bool: | ||
got := DefaultIfNil(v, tt.defaultVal.(bool)) | ||
if got != tt.want.(bool) { | ||
t.Errorf("DefaultIfNil() = %v, want %v", got, tt.want) | ||
} | ||
default: | ||
t.Errorf("Unsupported type %T", v) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestNullableBool(t *testing.T) { | ||
type args struct { | ||
b *bool | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want bool | ||
}{ | ||
{ | ||
name: "success - b is nil", | ||
args: args{ | ||
b: nil, | ||
}, | ||
want: false, | ||
}, | ||
{ | ||
name: "success - b is not nil and is false", | ||
args: args{ | ||
b: new(bool), // new(bool) initializes to false | ||
}, | ||
want: false, | ||
}, | ||
{ | ||
name: "success - b is not nil and is true", | ||
args: args{ | ||
b: func() *bool { v := true; return &v }(), | ||
}, | ||
want: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := NullableBool(tt.args.b); got != tt.want { | ||
t.Errorf("NullableBool() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestNullableTime(t *testing.T) { | ||
now := time.Now() | ||
type args struct { | ||
t *time.Time | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want time.Time | ||
}{ | ||
{ | ||
name: "success - t is nil", | ||
args: args{ | ||
t: nil, | ||
}, | ||
want: time.Time{}, | ||
}, | ||
{ | ||
name: "success - t has a value", | ||
args: args{ | ||
t: func() *time.Time { | ||
return &now | ||
}(), | ||
}, | ||
want: now, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := NullableTime(tt.args.t); got != tt.want { | ||
t.Errorf("NullableTime() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package pointers | ||
|
||
// NullableInt returns the dereferenced value of the int pointer | ||
// or 0 if the pointer is nil | ||
func NullableInt(i *int) int { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableInt8 returns the dereferenced value of *int8 if not nil, | ||
// or 0 otherwise. | ||
func NullableInt8(i *int8) int8 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableInt16 returns the dereferenced value of *int16 if not nil, | ||
// or 0 otherwise. | ||
func NullableInt16(i *int16) int16 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableInt32 returns the dereferenced value of *int32 if not nil, | ||
// or 0 otherwise. | ||
func NullableInt32(i *int32) int32 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableInt64 returns the dereferenced value of *int64 if not nil, | ||
// or 0 otherwise. | ||
func NullableInt64(i *int64) int64 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableUint returns the dereferenced value of *uint if not nil, | ||
// or 0 otherwise. | ||
func NullableUint(i *uint) uint { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableUint8 returns the dereferenced value of *uint8 if not nil, | ||
// or 0 otherwise. | ||
func NullableUint8(i *uint8) uint8 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableUint16 returns the dereferenced value of *uint16 if not nil, | ||
// or 0 otherwise. | ||
func NullableUint16(i *uint16) uint16 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableUint32 returns the dereferenced value of *uint32 if not nil, | ||
// or 0 otherwise. | ||
func NullableUint32(i *uint32) uint32 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableUint64 returns the dereferenced value of *uint64 if not nil, | ||
// or 0 otherwise. | ||
func NullableUint64(i *uint64) uint64 { | ||
if i == nil { | ||
return 0 | ||
} | ||
return *i | ||
} | ||
|
||
// NullableFloat32 returns the dereferenced value of *float32 if not nil, | ||
// or 0.0 otherwise. | ||
func NullableFloat32(f *float32) float32 { | ||
if f == nil { | ||
return 0.0 | ||
} | ||
return *f | ||
} | ||
|
||
// NullableFloat64 returns the dereferenced value of *float64 if not nil, | ||
// or 0.0 otherwise. | ||
func NullableFloat64(f *float64) float64 { | ||
if f == nil { | ||
return 0.0 | ||
} | ||
return *f | ||
} | ||
|
||
// NullableComplex64 returns the dereferenced value of *complex64 if not nil, | ||
// or 0+0i otherwise. | ||
func NullableComplex64(c *complex64) complex64 { | ||
if c == nil { | ||
return 0 + 0i | ||
} | ||
return *c | ||
} | ||
|
||
// NullableComplex128 returns the dereferenced value of *complex128 if not nil, | ||
// or 0+0i otherwise. | ||
func NullableComplex128(c *complex128) complex128 { | ||
if c == nil { | ||
return 0 + 0i | ||
} | ||
return *c | ||
} |
Oops, something went wrong.