diff --git a/condition/condition.go b/condition/condition.go index f1b3b7e..abc5259 100644 --- a/condition/condition.go +++ b/condition/condition.go @@ -2,8 +2,37 @@ // Use of this source code is governed by MIT license // Package condition contains some functions for conditional judgment. eg. And, Or, TernaryOperator ... +// The implementation of this package refers to the implementation of carlmjohnson's truthy package, you may find more +// useful information in truthy(https://github.com/carlmjohnson/truthy), thanks carlmjohnson. package condition +import "reflect" + +// Bool returns the truthy value of anything. +// If the value's type has a Bool() bool method, the method is called and returned. +// If the type has an IsZero() bool method, the opposite value is returned. +// Slices and maps are truthy if they have a length greater than zero. +// All other types are truthy if they are not their zero value. +func Bool[T any](value T) bool { + switch m := any(value).(type) { + case interface{ Bool() bool }: + return m.Bool() + case interface{ IsZero() bool }: + return !m.IsZero() + } + return reflectValue(&value) +} + +func reflectValue(vp any) bool { + switch rv := reflect.ValueOf(vp).Elem(); rv.Kind() { + case reflect.Map, reflect.Slice: + return rv.Len() != 0 + default: + is := rv.IsZero() + return !is + } +} + // TernaryOperator if true return trueValue else return falseValue func TernaryOperator[T any](isTrue bool, trueValue T, falseValue T) T { if isTrue { diff --git a/condition/condition_test.go b/condition/condition_test.go index 50b454b..9ee4f77 100644 --- a/condition/condition_test.go +++ b/condition/condition_test.go @@ -1,11 +1,67 @@ package condition import ( + "errors" "testing" + "time" "github.com/duke-git/lancet/v2/internal" ) +type TestStruct struct{} + +func TestBool(t *testing.T) { + assert := internal.NewAssert(t, "TestBool") + + // bool + assert.Equal(false, Bool(false)) + assert.Equal(true, Bool(true)) + + // integer + assert.Equal(false, Bool(0)) + assert.Equal(true, Bool(1)) + + // float + assert.Equal(false, Bool(0.0)) + assert.Equal(true, Bool(0.1)) + + // string + assert.Equal(false, Bool("")) + assert.Equal(true, Bool(" ")) + assert.Equal(true, Bool("0")) + + // slice + var nums [2]int + assert.Equal(false, Bool(nums)) + nums = [2]int{0, 1} + assert.Equal(true, Bool(nums)) + + // map + assert.Equal(false, Bool(map[string]string{})) + assert.Equal(true, Bool(map[string]string{"a": "a"})) + + // channel + var ch chan int + assert.Equal(false, Bool(ch)) + ch = make(chan int) + assert.Equal(true, Bool(ch)) + + // interface + var err error + assert.Equal(false, Bool(err)) + err = errors.New("error message") + assert.Equal(true, Bool(err)) + + // struct + assert.Equal(false, Bool(struct{}{})) + assert.Equal(true, Bool(time.Now())) + + // struct pointer + ts := TestStruct{} + assert.Equal(false, Bool(ts)) + assert.Equal(true, Bool(&ts)) +} + func TestTernaryOperator(t *testing.T) { assert := internal.NewAssert(t, "TernaryOperator") trueValue := "1"