Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f100adead3 | |||
| 7d2cf1e687 | |||
| 49728307f3 | |||
| 20dc502438 | |||
| ce7bfc5e3f | |||
| 6e98bdd16b |
+1
-1
@@ -134,7 +134,7 @@ func (ls1 *ListType) Equals(ls2 ListType) (answer bool) {
|
|||||||
answer = true
|
answer = true
|
||||||
for index, i1 := range *ls1 {
|
for index, i1 := range *ls1 {
|
||||||
// if i1 != (ls2)[index] {
|
// if i1 != (ls2)[index] {
|
||||||
if reflect.DeepEqual(i1, ls2[index]) {
|
if !reflect.DeepEqual(i1, ls2[index]) {
|
||||||
answer = false
|
answer = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-digest.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-------- digest term
|
||||||
|
|
||||||
|
func newDigestTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priIterOp,
|
||||||
|
evalFunc: evalDigest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalDigest(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
var it Iterator
|
||||||
|
var item, lastValue any
|
||||||
|
|
||||||
|
if err = opTerm.checkOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if leftValue, err = opTerm.children[0].compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if it, err = NewIterator(leftValue); err != nil {
|
||||||
|
return nil, fmt.Errorf("left operand of DIGEST must be an iterable data-source; got %s", TypeName(leftValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
lastValue = nil
|
||||||
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
|
ctx.SetVar("_", item)
|
||||||
|
ctx.SetVar("_index", it.Index())
|
||||||
|
ctx.SetVar("_count", it.Count())
|
||||||
|
if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
|
||||||
|
if rightValue == nil {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
lastValue = rightValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.DeleteVar("_count")
|
||||||
|
ctx.DeleteVar("_index")
|
||||||
|
ctx.DeleteVar("_")
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
v = lastValue
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymKwDigest, newDigestTerm)
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-filter.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-------- map term
|
||||||
|
|
||||||
|
func newFilterTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priIterOp,
|
||||||
|
evalFunc: evalFilter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalFilter(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
var it Iterator
|
||||||
|
var item any
|
||||||
|
|
||||||
|
if err = opTerm.checkOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if leftValue, err = opTerm.children[0].compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if it, err = NewIterator(leftValue); err != nil {
|
||||||
|
return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", TypeName(leftValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
values := newListA()
|
||||||
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
|
ctx.SetVar("_", item)
|
||||||
|
ctx.SetVar("_index", it.Index())
|
||||||
|
ctx.SetVar("_count", it.Count())
|
||||||
|
if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
|
||||||
|
if success, valid := ToBool(rightValue); valid {
|
||||||
|
if success {
|
||||||
|
values.appendItem(item)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("filter expression must return a boolean or a castable to boolean, got %v [%T]", rightValue, rightValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.DeleteVar("_count")
|
||||||
|
ctx.DeleteVar("_index")
|
||||||
|
ctx.DeleteVar("_")
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
v = values
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymKwFilter, newFilterTerm)
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// operator-join.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
//-------- join term
|
||||||
|
|
||||||
|
func newJoinTerm(tk *Token) (inst *term) {
|
||||||
|
return &term{
|
||||||
|
tk: *tk,
|
||||||
|
children: make([]*term, 0, 2),
|
||||||
|
position: posInfix,
|
||||||
|
priority: priIterOp,
|
||||||
|
evalFunc: evalJoin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalJoin(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
var itLeft, itRight Iterator
|
||||||
|
var item any
|
||||||
|
|
||||||
|
if err = opTerm.checkOperands(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if leftValue, err = opTerm.children[0].compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rightValue, err = opTerm.children[1].compute(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if itLeft, err = NewIterator(leftValue); err != nil {
|
||||||
|
return nil, fmt.Errorf("left operand of JOIN must be an iterable data-source; got %s", TypeName(leftValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
if itRight, err = NewIterator(rightValue); err != nil {
|
||||||
|
return nil, fmt.Errorf("right operand of JOIN must be an iterable data-source; got %s", TypeName(rightValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
values := newListA()
|
||||||
|
for _, it := range []Iterator{itLeft, itRight} {
|
||||||
|
for item, err = it.Next(); err == nil; item, err = it.Next() {
|
||||||
|
values.appendItem(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
v = values
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
func init() {
|
||||||
|
registerTermConstructor(SymKwJoin, newJoinTerm)
|
||||||
|
}
|
||||||
@@ -46,6 +46,8 @@ func evalMap(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
|
if rightValue, err = opTerm.children[1].compute(ctx); err == nil {
|
||||||
values.appendItem(rightValue)
|
values.appendItem(rightValue)
|
||||||
}
|
}
|
||||||
|
ctx.DeleteVar("_count")
|
||||||
|
ctx.DeleteVar("_index")
|
||||||
ctx.DeleteVar("_")
|
ctx.DeleteVar("_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -135,6 +135,10 @@ func init() {
|
|||||||
SymKwNot: {"not", symClassOperator, posInfix},
|
SymKwNot: {"not", symClassOperator, posInfix},
|
||||||
SymKwOr: {"or", symClassOperator, posInfix},
|
SymKwOr: {"or", symClassOperator, posInfix},
|
||||||
SymKwBut: {"but", symClassOperator, posInfix},
|
SymKwBut: {"but", symClassOperator, posInfix},
|
||||||
|
SymKwMap: {"map", symClassOperator, posInfix},
|
||||||
|
SymKwFilter: {"filter", symClassOperator, posInfix},
|
||||||
|
SymKwDigest: {"digest", symClassOperator, posInfix},
|
||||||
|
SymKwJoin: {"join", symClassOperator, posInfix},
|
||||||
SymKwFunc: {"func(", symClassDeclaration, posPrefix},
|
SymKwFunc: {"func(", symClassDeclaration, posPrefix},
|
||||||
SymKwBuiltin: {"builtin", symClassOperator, posPrefix},
|
SymKwBuiltin: {"builtin", symClassOperator, posPrefix},
|
||||||
SymKwPlugin: {"plugin", symClassOperator, posPrefix},
|
SymKwPlugin: {"plugin", symClassOperator, posPrefix},
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ const (
|
|||||||
SymKwIn
|
SymKwIn
|
||||||
SymKwInclude
|
SymKwInclude
|
||||||
SymKwMap
|
SymKwMap
|
||||||
|
SymKwFilter
|
||||||
|
SymKwDigest
|
||||||
|
SymKwJoin
|
||||||
SymKwNil
|
SymKwNil
|
||||||
SymKwUnset
|
SymKwUnset
|
||||||
)
|
)
|
||||||
@@ -137,9 +140,12 @@ func init() {
|
|||||||
"IN": SymKwIn,
|
"IN": SymKwIn,
|
||||||
"INCLUDE": SymKwInclude,
|
"INCLUDE": SymKwInclude,
|
||||||
"MAP": SymKwMap,
|
"MAP": SymKwMap,
|
||||||
|
"FILTER": SymKwFilter,
|
||||||
"NOT": SymKwNot,
|
"NOT": SymKwNot,
|
||||||
"OR": SymKwOr,
|
"OR": SymKwOr,
|
||||||
"NIL": SymKwNil,
|
"NIL": SymKwNil,
|
||||||
"UNSET": SymKwUnset,
|
"UNSET": SymKwUnset,
|
||||||
|
"DIGEST": SymKwDigest,
|
||||||
|
"JOIN": SymKwJoin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,13 @@ func TestFuncOs(t *testing.T) {
|
|||||||
/* 16 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it++`, "uno", nil},
|
/* 16 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it++`, "uno", nil},
|
||||||
/* 17 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it++;it++;it++`, nil, io.EOF.Error()},
|
/* 17 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it++;it++;it++`, nil, io.EOF.Error()},
|
||||||
/* 18 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it.clean`, nil, nil},
|
/* 18 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); it.clean`, nil, nil},
|
||||||
|
/* 19 */ {`builtin "os.file"; it=fileReadIterator("test-file.txt"); string(it)`, `$(fileReadTextIterator@"test-file.txt")`, nil},
|
||||||
|
/* 20 */ {`builtin "os.file"; handle=fileOpen("/etc/hosts"); fileClose(handle); string(handle)`, `reader`, nil},
|
||||||
|
/* 21 */ {`builtin "os.file"; handle=fileCreate("/tmp/dummy"); fileClose(handle); string(handle)`, `writer`, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
runTestSuiteSpec(t, section, inputs, 18)
|
// runTestSuiteSpec(t, section, inputs, 19)
|
||||||
// runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -32,8 +32,10 @@ func TestIteratorParser(t *testing.T) {
|
|||||||
/* 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++`, NewList([]any{int64(1), "one"}), nil},
|
/* 22 */ {`it=$({1:"one",2:"two",3:"three"}, "asc", "item"); it++`, NewList([]any{int64(1), "one"}), nil},
|
||||||
/* 23 */ {`builtin "os.file"; fileReadIterator("test-file.txt") map ${_index}`, NewList([]any{int64(0), int64(1)}), nil},
|
/* 23 */ {`builtin "os.file"; fileReadIterator("test-file.txt") map ${_index}`, NewList([]any{int64(0), int64(1)}), nil},
|
||||||
|
/* 24 */ {`builtin "os.file"; #(fileReadIterator("test-file.txt") filter (#${_} == 2))`, int64(0), nil},
|
||||||
|
/* 25 */ {`builtin "os.file"; #(fileReadIterator("test-file.txt") filter (#${_} == 3))`, int64(2), nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
runTestSuiteSpec(t, section, inputs, 23)
|
// runTestSuiteSpec(t, section, inputs, 23)
|
||||||
// runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -33,12 +33,16 @@ 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 */ {`[1,2,3] map var("_")`, []any{1, 2, 3}, nil},
|
/* 23 */ {`[1,2,3] map var("_")`, newList([]any{int64(1), int64(2), int64(3)}), nil},
|
||||||
/* 24 */ {`[1,2,3] map $_`, newList([]any{1, 2, 3}), nil},
|
/* 24 */ {`[1,2,3] map $_`, newList([]any{int64(1), int64(2), int64(3)}), nil},
|
||||||
|
/* 25 */ {`[1,2,3,4] filter ($_ % 2 == 0)`, newList([]any{int64(2), int64(4)}), nil},
|
||||||
|
/* 26 */ {`max=0; [2,3,1] digest max=(($_ > max) ? {$_} :: {max})`, int64(3), nil},
|
||||||
|
/* 27 */ {`["a","b"] join ["x"]`, newList([]any{"a", "b", "x"}), nil},
|
||||||
|
/* 28 */ {`["a","b"] join ["x"-true]`, nil, `[1:21] left operand 'x' [string] and right operand 'true' [bool] are not compatible with operator "-"`},
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
runTestSuiteSpec(t, section, inputs, 24)
|
// runTestSuiteSpec(t, section, inputs, 28)
|
||||||
// runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
//go:build unix
|
||||||
|
|
||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// t_utils_test.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os/user"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExpandPathRootOk(t *testing.T) {
|
||||||
|
source := "~root"
|
||||||
|
wantValue := "/root"
|
||||||
|
// wantErr := errors.New(`test expected string, got list ([])`)
|
||||||
|
wantErr := error(nil)
|
||||||
|
|
||||||
|
gotValue, gotErr := ExpandPath(source)
|
||||||
|
|
||||||
|
if gotErr != nil && gotErr.Error() != wantErr.Error() {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandPathRootSubDirOk(t *testing.T) {
|
||||||
|
source := "~root/test"
|
||||||
|
wantValue := "/root/test"
|
||||||
|
// wantErr := errors.New(`test expected string, got list ([])`)
|
||||||
|
wantErr := error(nil)
|
||||||
|
|
||||||
|
gotValue, gotErr := ExpandPath(source)
|
||||||
|
|
||||||
|
if gotErr != nil && gotErr.Error() != wantErr.Error() {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandPathUser(t *testing.T) {
|
||||||
|
u, _ := user.Current()
|
||||||
|
source := "~"
|
||||||
|
wantValue := path.Join("/home", u.Username)
|
||||||
|
// wantErr := errors.New(`test expected string, got list ([])`)
|
||||||
|
wantErr := error(nil)
|
||||||
|
|
||||||
|
gotValue, gotErr := ExpandPath(source)
|
||||||
|
|
||||||
|
if gotErr != nil {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandPathEnv(t *testing.T) {
|
||||||
|
u, _ := user.Current()
|
||||||
|
source := "$HOME"
|
||||||
|
wantValue := path.Join("/home", u.Username)
|
||||||
|
// wantErr := errors.New(`test expected string, got list ([])`)
|
||||||
|
wantErr := error(nil)
|
||||||
|
|
||||||
|
gotValue, gotErr := ExpandPath(source)
|
||||||
|
|
||||||
|
if gotErr != nil {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandPathErr(t *testing.T) {
|
||||||
|
source := "~fake-user/test"
|
||||||
|
wantValue := "~fake-user/test"
|
||||||
|
wantErr := errors.New(`user: unknown user fake-user`)
|
||||||
|
|
||||||
|
gotValue, gotErr := ExpandPath(source)
|
||||||
|
|
||||||
|
if gotErr != nil && gotErr.Error() != wantErr.Error() {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandPathUserErr(t *testing.T) {
|
||||||
|
u, _ := user.Current()
|
||||||
|
source := "~"
|
||||||
|
wantValue := path.Join("/home", u.Username)
|
||||||
|
// wantErr := errors.New(`test expected string, got list ([])`)
|
||||||
|
wantErr := error(nil)
|
||||||
|
|
||||||
|
gotValue, gotErr := ExpandPath(source)
|
||||||
|
|
||||||
|
if gotErr != nil {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -164,3 +164,48 @@ func TestCopyMap(t *testing.T) {
|
|||||||
t.Errorf("utils.CopyMap() failed")
|
t.Errorf("utils.CopyMap() failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToStringOk(t *testing.T) {
|
||||||
|
source := "ciao"
|
||||||
|
wantValue := "ciao"
|
||||||
|
wantErr := error(nil)
|
||||||
|
|
||||||
|
gotValue, gotErr := ToGoString(source, "test")
|
||||||
|
|
||||||
|
if gotErr != nil {
|
||||||
|
t.Error(gotErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf("toGoString(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v",
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToStringErr(t *testing.T) {
|
||||||
|
source := newListA()
|
||||||
|
wantValue := ""
|
||||||
|
wantErr := errors.New(`test expected string, got list ([])`)
|
||||||
|
|
||||||
|
gotValue, gotErr := ToGoString(source, "test")
|
||||||
|
|
||||||
|
if gotErr != nil && gotErr.Error() != wantErr.Error() {
|
||||||
|
t.Errorf(`ToGoString(%v, "test") gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
} else if gotValue != wantValue {
|
||||||
|
t.Errorf(`ToString(%v, "test") gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`,
|
||||||
|
source, gotValue, gotErr, wantValue, wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsFunctorSucc(t *testing.T) {
|
||||||
|
f := NewGolangFunctor(isNilFunc)
|
||||||
|
if !isFunctor(f) {
|
||||||
|
t.Errorf("isNilFunc() evalued as not a functor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsFunctorFail(t *testing.T) {
|
||||||
|
f := int64(1)
|
||||||
|
if isFunctor(f) {
|
||||||
|
t.Errorf("int evalued as a functor")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
//go:build unix
|
||||||
|
|
||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// utils-unix.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExpandPath(sourcePath string) (expandedPath string, err error) {
|
||||||
|
for expandedPath = os.ExpandEnv(sourcePath); expandedPath != sourcePath; expandedPath = os.ExpandEnv(sourcePath) {
|
||||||
|
sourcePath = expandedPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(sourcePath, "~") {
|
||||||
|
var home, userName, remainder string
|
||||||
|
|
||||||
|
slashPos := strings.IndexRune(sourcePath, '/')
|
||||||
|
if slashPos > 0 {
|
||||||
|
userName = sourcePath[1:slashPos]
|
||||||
|
remainder = sourcePath[slashPos:]
|
||||||
|
} else {
|
||||||
|
userName = sourcePath[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(userName) == 0 {
|
||||||
|
home, err = os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var userInfo *user.User
|
||||||
|
userInfo, err = user.Lookup(userName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
home = userInfo.HomeDir
|
||||||
|
}
|
||||||
|
expandedPath = path.Join(home, remainder)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// utils-unix.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExpandPath(sourcePath string) (expandedPath string, err error) {
|
||||||
|
for expandedPath = os.ExpandEnv(sourcePath); expandedPath != sourcePath; expandedPath = os.ExpandEnv(sourcePath) {
|
||||||
|
sourcePath = expandedPath
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -6,11 +6,7 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"os/user"
|
|
||||||
"path"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsString(v any) (ok bool) {
|
func IsString(v any) (ok bool) {
|
||||||
@@ -234,37 +230,3 @@ func ForAll[T, V any](ts []T, fn func(T) V) []V {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExpandPath(sourcePath string) (expandedPath string, err error) {
|
|
||||||
for expandedPath = os.ExpandEnv(sourcePath); expandedPath != sourcePath; expandedPath = os.ExpandEnv(sourcePath) {
|
|
||||||
sourcePath = expandedPath
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(sourcePath, "~") {
|
|
||||||
var home, userName, remainder string
|
|
||||||
|
|
||||||
slashPos := strings.IndexRune(sourcePath, '/')
|
|
||||||
if slashPos > 0 {
|
|
||||||
userName = sourcePath[1:slashPos]
|
|
||||||
remainder = sourcePath[slashPos:]
|
|
||||||
} else {
|
|
||||||
userName = sourcePath[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(userName) == 0 {
|
|
||||||
home, err = os.UserHomeDir()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var userInfo *user.User
|
|
||||||
userInfo, err = user.Lookup(userName)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
home = userInfo.HomeDir
|
|
||||||
}
|
|
||||||
expandedPath = path.Join(home, remainder)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user