Skip to content

Commit

Permalink
update validity/pres fcf signature; add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
JesseCoretta committed Aug 26, 2023
1 parent 624100c commit e80eae4
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 36 deletions.
50 changes: 18 additions & 32 deletions cond.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,22 +161,6 @@ func (r *condition) setExpression(ex any) {
}
}

func (r condition) canAssignNester(x any) (ok bool) {
// if no-nesting bit is enabled ...
if r.positive(nnest) {

// ... and if the input value (x) is a
// Stack or Stack type alias, we'll invert
// the bool (ok) return.
_, ok = stackTypeAliasConverter(x)
return !ok
}

// if no-nesting bit is not enabled,
// assign whatever you want ...
return true
}

/*
assertKeyword returns a valid keyword string value based on the input value.
If the value is a string, it is returned as-is. Else, if a custom type that
Expand Down Expand Up @@ -284,10 +268,22 @@ func (r condition) defaultAssertionExpressionHandler(x any) (X any) {
// was converted back to Stack without
// any issues ...
X = v

} else if meth := getStringer(x); meth != nil {
// whatever it is, it seems to have
// a stringer method, at least ...
X = x

} else if isNumberPrimitive(x) {
// value is one of go's builtin
// numerical primitives, which
// are string represented using
// sprintf.
X = numberStringer(x)

} else if isStringPrimitive(x) {
// value is a simple string
X = x.(string)
}

return
Expand Down Expand Up @@ -407,7 +403,7 @@ func (r Condition) Valid() (err error) {

// if a validitypolicy was provided, use it
if r.condition.cfg.vpf != nil {
err = r.condition.cfg.vpf()
err = r.condition.cfg.vpf(r)
return
}

Expand Down Expand Up @@ -524,19 +520,9 @@ func (r *condition) getEncap() [][]string {
/*
NoNesting sets the no-nesting bit within the receiver. If
set to true, the receiver shall ignore any Stack or Stack
type alias instance when pushed using the Push method. In
such a case, only primitives, Conditions, etc., shall be
honored during the Push operation.
Note this will only have an effect when not using a custom
PushPolicy. When using a custom PushPolicy, the user has
total control -- and full responsibility -- in deciding
what may or may not be pushed.
Also note that setting or unsetting this bit shall not, in
any way, have an impact on pre-existing Stack or Stack type
alias instances within the receiver. This bit only has an
influence on the Push method and only when set to true.
type alias instance when assigned using the SetExpression
method. In such a case, only primitives, etc., shall be
honored during the SetExpression operation.
A Boolean input value explicitly sets the bit as intended.
Execution without a Boolean input value will *TOGGLE* the
Expand Down Expand Up @@ -712,7 +698,7 @@ func (r Condition) IsPadded() bool {
return false
}

return !r.cfg.positive(nspad)
return !r.condition.positive(nspad)
}

/*
Expand Down Expand Up @@ -788,7 +774,7 @@ of the receiver instance.
*/
func (r condition) string() string {
if r.cfg.rpf != nil {
return r.cfg.rpf()
return r.cfg.rpf(r)
}

// begin default presentation
Expand Down
68 changes: 68 additions & 0 deletions cond_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,45 @@ import (
"testing"
)

type customTestValue struct {
Type string
Value string
}

func (r customTestValue) String() string {
return sprintf("TYPE: %s; VALUE: %s", r.Type, r.Value)
}

type customTestKeyword uint8

const (
testKeyword01 customTestKeyword = 1 << iota
testKeyword02
testKeyword03
testKeyword04
testKeyword05
testKeyword06
)

func (r customTestKeyword) String() string {
switch r {
case testKeyword01:
return `keyword_01`
case testKeyword02:
return `keyword_02`
case testKeyword03:
return `keyword_03`
case testKeyword04:
return `keyword_04`
case testKeyword05:
return `keyword_05`
case testKeyword06:
return `keyword_06`
}

return `<unknown_keyword>`
}

func TestCondition_001(t *testing.T) {
c := Cond(`person`, Eq, `Jesse`)
want := `person = Jesse`
Expand All @@ -14,6 +53,35 @@ func TestCondition_001(t *testing.T) {
}
}

func TestCondition_customKeyword(t *testing.T) {
var c Condition
c.SetKeyword(testKeyword05)
c.SetOperator(Gt)
c.SetExpression(complex(2, 3))
if c.Keyword() != testKeyword05.String() {
t.Errorf("%s failed: want '%s', got '%s'", t.Name(), testKeyword05, c.Keyword())
}

want := `keyword_05 > (2+3i)`
if got := c.String(); got != want {
t.Errorf("%s failed: want '%s', got '%s'", t.Name(), want, got)
}
}

func TestCondition_customType(t *testing.T) {
cv := customTestValue{Type: `Color`, Value: `Red`}

var c Condition
c.SetKeyword(testKeyword05)
c.SetOperator(Ne)
c.SetExpression(cv)

want := `keyword_05 != TYPE: Color; VALUE: Red`
if got := c.String(); got != want {
t.Errorf("%s failed: want '%s', got '%s'", t.Name(), want, got)
}
}

func TestCondition_002(t *testing.T) {
st := List().Paren().Push(
Cond(`person`, Eq, `Jesse`),
Expand Down
4 changes: 2 additions & 2 deletions fcf.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ validity of a stack based on its configuration and/or values.
A ValidityPolicy function or method is executed via the Stack
method Valid.
*/
type ValidityPolicy func() error
type ValidityPolicy func(any) error

/*
PresentationPolicy is a first-class (closure) function signature
Expand All @@ -59,4 +59,4 @@ String method(s).
Note that basic Stack instances are ineligible for the process of
string representation, thus no PresentationPolicy may be set.
*/
type PresentationPolicy func() string
type PresentationPolicy func(any) string
85 changes: 85 additions & 0 deletions misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,88 @@ func foldValue(do bool, value string) string {
func isPtr(x any) bool {
return typOf(x).Kind() == reflect.Ptr
}

func isNumberPrimitive(x any) bool {
switch x.(type) {
case int, int8, int16, int32, int64,
float32, float64, complex64, complex128,
uint, uint8, uint16, uint32, uint64, uintptr:
return true
}

return false
}

func isStringPrimitive(x any) bool {
switch x.(type) {
case string:
return true
}

return false
}

func numberStringer(x any) string {
switch tv := x.(type) {
case float32, float64:
return floatStringer(tv)
case complex64, complex128:
return complexStringer(tv)
case int, int8, int16, int32, int64:
return intStringer(tv)
case uint, uint8, uint16, uint32, uint64, uintptr:
return uintStringer(tv)
}

return `<invalid_number>`
}

func floatStringer(x any) string {
switch tv := x.(type) {
case float64:
return sprintf("%.02f", tv)
}

return sprintf("%.02f", x.(float32))
}

func complexStringer(x any) string {
switch tv := x.(type) {
case complex128:
return sprintf("%v", tv)
}

return sprintf("%v", x.(complex64))
}

func uintStringer(x any) string {
switch tv := x.(type) {
case uint8:
return sprintf("%d", tv)
case uint16:
return sprintf("%d", tv)
case uint32:
return sprintf("%d", tv)
case uint64:
return sprintf("%d", tv)
case uintptr:
return sprintf("%d", tv)
}

return sprintf("%d", x.(uint))
}

func intStringer(x any) string {
switch tv := x.(type) {
case int8:
return sprintf("%d", tv)
case int16:
return sprintf("%d", tv)
case int32:
return sprintf("%d", tv)
case int64:
return sprintf("%d", tv)
}

return sprintf("%d", x.(int))
}
4 changes: 2 additions & 2 deletions stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (r Stack) Valid() (err error) {
// try to see if the user provided a
// validity function
if meth := r.getValidityPolicy(); meth != nil {
err = meth()
err = meth(r)
}

return
Expand Down Expand Up @@ -1442,7 +1442,7 @@ func (r stack) string() string {
// policy, if defined, instead of going any
// further.
if ppol := r.getPresentationPolicy(); ppol != nil {
return ppol()
return ppol(r)
}

// Scan each slice and attempt stringification
Expand Down

0 comments on commit e80eae4

Please sign in to comment.