Skip to content

Commit

Permalink
Implement Nullable Type Functions and DefaultIfNil Utility (#37)
Browse files Browse the repository at this point in the history
* added pointer utils

* added test cases

* organized related functions in same files

---------

Co-authored-by: Kashif Khan <[email protected]>
  • Loading branch information
shahzadhaider1 and kashifkhan0771 authored Nov 18, 2024
1 parent 62e0ef4 commit 1c951f5
Show file tree
Hide file tree
Showing 6 changed files with 917 additions and 0 deletions.
30 changes: 30 additions & 0 deletions pointers/common.go
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
}
165 changes: 165 additions & 0 deletions pointers/common_test.go
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)
}
})
}
}
127 changes: 127 additions & 0 deletions pointers/numeric.go
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
}
Loading

0 comments on commit 1c951f5

Please sign in to comment.