increased test coverage (83.9%)

This commit is contained in:
2026-05-21 03:06:52 +02:00
parent 1055569dd6
commit a62f27b104
10 changed files with 190 additions and 45 deletions
+9 -11
View File
@@ -42,12 +42,16 @@ func ImportInContextByGlobPattern(ctx kern.ExprContext, pattern string) (count i
return return
} }
func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValue any) { func fixCtrlVar(name string) string {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
if !strings.HasPrefix(name, "_") { if !strings.HasPrefix(name, "_") {
name = "_" + name name = "_" + name
} }
return name
}
func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValue any) {
if globalCtx := ctx.GetGlobal(); globalCtx != nil {
name = fixCtrlVar(name)
currentValue, _ = globalCtx.GetVar(name) currentValue, _ = globalCtx.GetVar(name)
globalCtx.SetVar(name, newValue) globalCtx.SetVar(name, newValue)
} }
@@ -56,18 +60,14 @@ func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValu
func GlobalCtrlGet(ctx kern.ExprContext, name string) (currentValue any) { func GlobalCtrlGet(ctx kern.ExprContext, name string) (currentValue any) {
if globalCtx := ctx.GetGlobal(); globalCtx != nil { if globalCtx := ctx.GetGlobal(); globalCtx != nil {
if !strings.HasPrefix(name, "_") { name = fixCtrlVar(name)
name = "_" + name
}
currentValue, _ = globalCtx.GetVar(name) currentValue, _ = globalCtx.GetVar(name)
} }
return currentValue return currentValue
} }
func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) { func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
if !strings.HasPrefix(name, "_") { name = fixCtrlVar(name)
name = "_" + name
}
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) { if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
currentStatus, _ = v.(bool) currentStatus, _ = v.(bool)
} }
@@ -77,9 +77,7 @@ func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) {
} }
func CtrlDisable(ctx kern.ExprContext, name string) (currentStatus bool) { func CtrlDisable(ctx kern.ExprContext, name string) (currentStatus bool) {
if !strings.HasPrefix(name, "_") { name = fixCtrlVar(name)
name = "_" + name
}
if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) { if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) {
currentStatus, _ = v.(bool) currentStatus, _ = v.(bool)
} }
+4
View File
@@ -20,6 +20,10 @@ type IntIterator struct {
step int64 step int64
} }
func NewIntIteratorA(args ...any) (it *IntIterator, err error) {
return NewIntIterator(args)
}
func NewIntIterator(args []any) (it *IntIterator, err error) { func NewIntIterator(args []any) (it *IntIterator, err error) {
var argc int = 0 var argc int = 0
if args != nil { if args != nil {
+6 -6
View File
@@ -38,9 +38,9 @@ func HasIterStandardOperations(name string) bool {
return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name) return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name)
} }
func HasIterOperations(name string, ops ...string) bool { // func HasIterOperations(name string, ops ...string) bool {
return slices.Contains([]string{ // return slices.Contains([]string{
kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName, // kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName,
}, name) || // }, name) ||
slices.Contains(ops, name) // slices.Contains(ops, name)
} // }
+23 -21
View File
@@ -40,23 +40,7 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
} }
if sourceCtx != nil { if sourceCtx != nil {
if formatter, ok := sourceCtx.(kern.DictFormat); ok { v = contextToDict(sourceCtx)
v = formatter.ToDict()
} else if formatter, ok := sourceCtx.(kern.Formatter); ok {
v = formatter.ToString(0)
} else {
// keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
keys := sourceCtx.EnumVars(nil)
d := make(map[string]any)
for _, key := range keys {
d[key], _ = sourceCtx.GetVar(key)
}
keys = sourceCtx.EnumFuncs(func(name string) bool { return true })
for _, key := range keys {
d[key], _ = sourceCtx.GetFuncInfo(key)
}
v = d
}
} else if childValue != nil { } else if childValue != nil {
it, ok := childValue.(kern.Iterator) it, ok := childValue.(kern.Iterator)
if !ok { if !ok {
@@ -64,18 +48,14 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
} }
if err == nil { if err == nil {
var item any var item any
// values := kern.NewListA()
values := kern.NewLinkedListA() values := kern.NewLinkedListA()
for item, err = it.Next(); err == nil; item, err = it.Next() { for item, err = it.Next(); err == nil; item, err = it.Next() {
// values.AppendItem(item)
values.PushBack(item) values.PushBack(item)
} }
if err == io.EOF { if err == io.EOF {
err = nil err = nil
v = values v = values
} }
// } else {
// err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
} }
} else { } else {
err = opTerm.ErrIncompatiblePrefixPostfixType(childValue) err = opTerm.ErrIncompatiblePrefixPostfixType(childValue)
@@ -83,6 +63,28 @@ func evalContextValue(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error
return return
} }
func contextToDict(ctx kern.ExprContext) (dict *kern.DictType) {
// Variables
keys := ctx.EnumVars(nil)
vars := kern.MakeDict()
for _, key := range keys {
value, _ := ctx.GetVar(key)
vars.SetItem(key, value)
}
// Functions
keys = ctx.EnumFuncs(func(name string) bool { return true })
funcs := kern.MakeDict()
for _, key := range keys {
funcInfo, _ := ctx.GetFuncInfo(key)
funcs.SetItem(key, funcInfo)
}
dict = kern.MakeDict()
dict.SetItem("vars", vars)
dict.SetItem("funcs", funcs)
return
}
// init // init
func init() { func init() {
scan.RegisterTermConstructor(scan.SymDoubleDollar, newContextTerm) scan.RegisterTermConstructor(scan.SymDoubleDollar, newContextTerm)
+24
View File
@@ -121,3 +121,27 @@ func logTest(t *testing.T, n int, section, source string, wantResult any, wantEr
t.Logf("[-]%s nr %3d -- `%s` --> %v", section, n, source, wantErr) t.Logf("[-]%s nr %3d -- `%s` --> %v", section, n, source, wantErr)
} }
} }
func testIteratorCallOp(t *testing.T, section string, it kern.Iterator) {
if _, err := it.CallOperation("next", map[string]any{}); err != nil {
t.Errorf(`%s -- CallOperation("next") failed: %v`, section, err)
}
if _, err := it.CallOperation("current", map[string]any{}); err != nil {
t.Errorf(`%s -- CallOperation("current") failed: %v`, section, err)
}
if _, err := it.CallOperation("clean", map[string]any{}); err != nil {
t.Errorf(`%s -- CallOperation("clean") failed: %v`, section, err)
}
if _, err := it.CallOperation("index", map[string]any{}); err != nil {
t.Errorf(`%s -- CallOperation("index") failed: %v`, section, err)
}
if _, err := it.CallOperation("count", map[string]any{}); err != nil {
t.Errorf(`%s -- CallOperation("count") failed: %v`, section, err)
}
if _, err := it.CallOperation("reset", map[string]any{}); err != nil {
t.Errorf(`%s -- CallOperation("reset") failed: %v`, section, err)
}
if _, err := it.CallOperation("fake", map[string]any{}); err == nil {
t.Errorf(`%s -- CallOperation("fake") should return error`, section)
}
}
+34
View File
@@ -6,6 +6,8 @@ package expr
import ( import (
"testing" "testing"
"git.portale-stac.it/go-pkg/expr/kern"
) )
func TestCtrlSet(t *testing.T) { func TestCtrlSet(t *testing.T) {
@@ -58,3 +60,35 @@ func TestCtrlGetNotDefined(t *testing.T) {
t.Errorf(`%s -- CtrlGet(%q) should have returned nil, got %v`, section, varName, v) t.Errorf(`%s -- CtrlGet(%q) should have returned nil, got %v`, section, varName, v)
} }
} }
func TestCtrlEnable(t *testing.T) {
section := "Context"
varName := "test_var"
varValue := true
ctx := NewSimpleStore()
GlobalCtrlSet(ctx, varName, varValue)
if !CtrlEnable(ctx, varName) {
t.Errorf(`%s -- CtrlEnable(ctx, %q) should have returned 'true', got 'false'`, section, varName)
}
if !CtrlDisable(ctx, varName) {
t.Errorf(`%s -- CtrlEnable(ctx, %q) should have returned 'true', got 'false'`, section, varName)
// t.Errorf(`%s -- CtrlEnable(ctx, %q) should have returned 'false', got 'true'`, section, varName)
}
}
func TestList(t *testing.T) {
section := "Context"
inputs := []inputType{
/* 1 */ {`$$(5)`, kern.NewLinkedListA(5), nil},
/* 2 */ {`$$($(2))`, kern.NewLinkedListA(0, 1), nil},
/* 3 */ {`string(($$global).funcs.bool)`, `bool(value):boolean{}`, nil},
}
runTestSuiteSpec(t, section, inputs, 3)
// runTestSuite(t, section, inputs)
}
+2 -2
View File
@@ -47,8 +47,8 @@ func TestDictParser(t *testing.T) {
/* 24 */ {`f=func(n){"x"+n}; d={f(5) but "z":10}`, kern.NewDict(map[any]any{"z": int64(10)}), nil}, /* 24 */ {`f=func(n){"x"+n}; d={f(5) but "z":10}`, kern.NewDict(map[any]any{"z": int64(10)}), nil},
} }
runTestSuiteSpec(t, section, inputs, 1, 23, 24) // runTestSuiteSpec(t, section, inputs, 23, 24)
// runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }
func TestAccessSubFields(t *testing.T) { func TestAccessSubFields(t *testing.T) {
+1 -2
View File
@@ -31,8 +31,7 @@ func TestExpr(t *testing.T) {
/* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`}, /* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`},
/* 16 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil}, /* 16 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil},
/* 17 */ {`true ? {"a"} :: {"b"}`, "a", nil}, /* 17 */ {`true ? {"a"} :: {"b"}`, "a", nil},
/* 18 */ {`$$`, kern.NewDict(map[any]any{"variables": kern.NewDict(nil), "functions": kern.NewDict(nil)}), nil}, /* 18 */ {`$$`, kern.NewDict(map[any]any{"vars": kern.NewDict(nil), "funcs": kern.NewDict(nil)}), nil},
///* 19 */ {`$$global`, NewDict(map[any]any{"variables": NewDict(nil), "functions": NewDict(nil)}), nil},
/* 19 */ {` /* 19 */ {`
ds={ ds={
"init":func(@end){@current=0 but true}, "init":func(@end){@current=0 but true},
+79 -1
View File
@@ -8,6 +8,7 @@ import (
"testing" "testing"
"git.portale-stac.it/go-pkg/expr/kern" "git.portale-stac.it/go-pkg/expr/kern"
"git.portale-stac.it/go-pkg/expr/scan"
) )
func TestIteratorParser(t *testing.T) { func TestIteratorParser(t *testing.T) {
@@ -35,12 +36,89 @@ func TestIteratorParser(t *testing.T) {
/* 20 */ {`it=$({1:"one",2:"two",3:"three"}, "default", "value"); it++`, "one", nil}, /* 20 */ {`it=$({1:"one",2:"two",3:"three"}, "default", "value"); it++`, "one", nil},
/* 21 */ {`it=$({1:"one",2:"two",3:"three"}, "desc", "key"); it++`, int64(3), nil}, /* 21 */ {`it=$({1:"one",2:"two",3:"three"}, "desc", "key"); it++`, int64(3), nil},
/* 22 */ {`it=$({1:"one",2:"two",3:"three"}, "asc", "item"); it++`, kern.NewList([]any{int64(1), "one"}), nil}, /* 22 */ {`it=$({1:"one",2:"two",3:"three"}, "asc", "item"); it++`, kern.NewList([]any{int64(1), "one"}), nil},
/* 23 */ {`$$($(1,4,0))`, nil, `step cannot be zero`},
/* 24 */ {`$$($(1,4,-1))`, nil, `step cannot be negative when start < stop`},
/* 25 */ {`$$($(4,1,1))`, nil, `step cannot be positive when start > stop`},
} }
// runTestSuiteSpec(t, section, inputs, 1) // runTestSuiteSpec(t, section, inputs, 25)
runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }
func TestCallOpIntIter(t *testing.T) {
section := "IntIterator-CallOp"
if it, err := NewIntIteratorA(int64(1), int64(4), int64(1)); err != nil {
t.Errorf(`%s -- NewIntIteratorA() failed: %v`, section, err)
} else {
testIteratorCallOp(t, section, it)
testIterAttrs(t, section, it, "IntIterator", "$(1..4..1)")
}
}
func TestCallOpIterIter(t *testing.T) {
section := "IterIterator-CallOp"
ctx := NewSimpleStore()
if inner, err := NewIntIteratorA(int64(1), int64(4), int64(1)); err == nil {
if it, err := NewIterIter(inner, ctx, []*scan.Term{}); err != nil {
t.Errorf(`%s -- NewIterIter() failed: %v`, section, err)
} else {
testIteratorCallOp(t, section, it)
testIterAttrs(t, section, it, "IterIter", "$($(1..4..1))")
}
} else {
t.Errorf(`%s -- can't create inner iterator: %v`, section, err)
}
}
func TestCallOpDictIter(t *testing.T) {
section := "DictIterator-CallOp"
inner := kern.NewDict(map[any]any{"a": 1})
if it, err := NewDictIterator(inner, nil); err != nil {
t.Errorf(`%s -- NewIterIter() failed: %v`, section, err)
} else {
testIteratorCallOp(t, section, it)
testIterAttrs(t, section, it, "DictIterator", "$({#1})")
}
}
func TestCallOpLinkedListIter(t *testing.T) {
section := "LinkedListIterator-CallOp"
inner := kern.NewLinkedListA(1, 2, 3)
it := NewLinkedListIterator(inner, nil)
testIteratorCallOp(t, section, it)
// wanted := "$([<#3>])"
// got := it.String()
// if wanted != got {
// t.Errorf(`%s -- LinkedListIterator.String() failed: expected %q, got %q`, section, wanted, got)
// }
// wanted = "LinkedListIterator"
// got = it.TypeName()
// if wanted != got {
// t.Errorf(`%s -- LinkedListIterator.TypeName() failed: expected %q, got %q`, section, wanted, got)
// }
testIterAttrs(t, section, it, "LinkedListIterator", "$([<#3>])")
}
func testIterAttrs(t *testing.T, section string, it kern.Iterator, name, repr string) {
wanted := repr
got := it.String()
if wanted != got {
t.Errorf(`%s -- %s.String() failed: expected %q, got %q`, section, name, wanted, got)
}
wanted = name
got = it.TypeName()
if wanted != got {
t.Errorf(`%s -- %s.TypeName() failed: expected %q, got %q`, section, name, wanted, got)
}
}
func TestFilterIterator(t *testing.T) { func TestFilterIterator(t *testing.T) {
section := "Iterator-Filter" section := "Iterator-Filter"
inputs := []inputType{ inputs := []inputType{
+6
View File
@@ -35,6 +35,12 @@ func TestOperator(t *testing.T) {
/* 20 */ {`a=1; a^=2`, int64(3), nil}, /* 20 */ {`a=1; a^=2`, int64(3), nil},
/* 21 */ {`a=1; ++a`, int64(2), nil}, /* 21 */ {`a=1; ++a`, int64(2), nil},
/* 22 */ {`a=1; --a`, int64(0), nil}, /* 22 */ {`a=1; --a`, int64(0), nil},
/* 23 */ {`a=1; a++`, int64(1), nil},
/* 24 */ {`a=1; a--`, int64(1), nil},
/* 25 */ {`a="1"; ++a`, nil, `[1:9] prefix/postfix operator "++" does not support operand '1' [string]`},
/* 26 */ {`a="1"; --a`, nil, `[1:9] prefix/postfix operator "--" does not support operand '1' [string]`},
/* 27 */ {`a="1"; a++`, nil, `[1:10] prefix/postfix operator "++" does not support operand '1' [string]`},
/* 28 */ {`a="1"; a--`, nil, `[1:10] prefix/postfix operator "--" does not support operand '1' [string]`},
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")