mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
Test almost all commands correctly bubble output errors.
Also make the helper thatOutputErrorIsBubbled more precise by matching for the exact error that is thrown.
This commit is contained in:
parent
20274d3245
commit
82b9bddb15
|
@ -408,9 +408,16 @@ func dissoc(a, k interface{}) (interface{}, error) {
|
|||
//
|
||||
// @cf one
|
||||
|
||||
func all(fm *Frame, inputs Inputs) {
|
||||
func all(fm *Frame, inputs Inputs) error {
|
||||
out := fm.ValueOutput()
|
||||
inputs(func(v interface{}) { out.Put(v) })
|
||||
var errOut error
|
||||
inputs(func(v interface{}) {
|
||||
if errOut != nil {
|
||||
return
|
||||
}
|
||||
errOut = out.Put(v)
|
||||
})
|
||||
return errOut
|
||||
}
|
||||
|
||||
//elvdoc:fn one
|
||||
|
@ -466,15 +473,20 @@ func one(fm *Frame, inputs Inputs) error {
|
|||
//
|
||||
// Etymology: Haskell.
|
||||
|
||||
func take(fm *Frame, n int, inputs Inputs) {
|
||||
func take(fm *Frame, n int, inputs Inputs) error {
|
||||
out := fm.ValueOutput()
|
||||
var errOut error
|
||||
i := 0
|
||||
inputs(func(v interface{}) {
|
||||
if errOut != nil {
|
||||
return
|
||||
}
|
||||
if i < n {
|
||||
out.Put(v)
|
||||
errOut = out.Put(v)
|
||||
}
|
||||
i++
|
||||
})
|
||||
return errOut
|
||||
}
|
||||
|
||||
//elvdoc:fn drop
|
||||
|
@ -504,15 +516,20 @@ func take(fm *Frame, n int, inputs Inputs) {
|
|||
//
|
||||
// @cf take
|
||||
|
||||
func drop(fm *Frame, n int, inputs Inputs) {
|
||||
func drop(fm *Frame, n int, inputs Inputs) error {
|
||||
out := fm.ValueOutput()
|
||||
var errOut error
|
||||
i := 0
|
||||
inputs(func(v interface{}) {
|
||||
if errOut != nil {
|
||||
return
|
||||
}
|
||||
if i >= n {
|
||||
out.Put(v)
|
||||
errOut = out.Put(v)
|
||||
}
|
||||
i++
|
||||
})
|
||||
return errOut
|
||||
}
|
||||
|
||||
//elvdoc:fn has-value
|
||||
|
|
|
@ -59,19 +59,14 @@ func TestRange(t *testing.T) {
|
|||
// non-positive int step
|
||||
That("range &step=0 10").
|
||||
Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "0"}),
|
||||
thatOutputErrorIsBubbled("range 1"),
|
||||
|
||||
That("range 10_000_000_000_000_000_000 10_000_000_000_000_000_003").
|
||||
Puts(
|
||||
vals.ParseNum("10_000_000_000_000_000_000"),
|
||||
vals.ParseNum("10_000_000_000_000_000_001"),
|
||||
vals.ParseNum("10_000_000_000_000_000_002")),
|
||||
That("range 10_000_000_000_000_000_000 10_000_000_000_000_000_003 &step=2").
|
||||
Puts(
|
||||
vals.ParseNum("10_000_000_000_000_000_000"),
|
||||
vals.ParseNum("10_000_000_000_000_000_002")),
|
||||
That("range "+z+" "+z3).Puts(bigInt(z), bigInt(z1), bigInt(z2)),
|
||||
That("range "+z+" "+z3+" &step=2").Puts(bigInt(z), bigInt(z2)),
|
||||
// non-positive bigint step
|
||||
That("range &step=-"+z+" 10").
|
||||
Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "-" + z}),
|
||||
thatOutputErrorIsBubbled("range "+z+" "+z1),
|
||||
|
||||
That("range 23/10").Puts(0, 1, 2),
|
||||
That("range 1/10 23/10").Puts(
|
||||
|
@ -81,6 +76,7 @@ func TestRange(t *testing.T) {
|
|||
// non-positive bigrat step
|
||||
That("range &step=-1/2 10").
|
||||
Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "-1/2"}),
|
||||
thatOutputErrorIsBubbled("range 1/2 3/2"),
|
||||
|
||||
That("range 1.2").Puts(0.0, 1.0),
|
||||
That("range &step=0.5 1 3").Puts(1.0, 1.5, 2.0, 2.5),
|
||||
|
@ -90,12 +86,14 @@ func TestRange(t *testing.T) {
|
|||
// non-positive float64 step
|
||||
That("range &step=-0.5 10").
|
||||
Throws(errs.BadValue{What: "step", Valid: "positive", Actual: "-0.5"}),
|
||||
thatOutputErrorIsBubbled("range 1.2"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestRepeat(t *testing.T) {
|
||||
Test(t,
|
||||
That(`repeat 4 foo`).Puts("foo", "foo", "foo", "foo"),
|
||||
thatOutputErrorIsBubbled("repeat 1 foo"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -118,6 +116,7 @@ func TestAll(t *testing.T) {
|
|||
That(`put foo bar | all`).Puts("foo", "bar"),
|
||||
That(`echo foobar | all`).Puts("foobar"),
|
||||
That(`all [foo bar]`).Puts("foo", "bar"),
|
||||
thatOutputErrorIsBubbled("all [foo]"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -129,18 +128,21 @@ func TestOne(t *testing.T) {
|
|||
That(`one [foo]`).Puts("foo"),
|
||||
That(`one []`).Throws(AnyError),
|
||||
That(`one [foo bar]`).Throws(AnyError),
|
||||
thatOutputErrorIsBubbled("one [foo]"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestTake(t *testing.T) {
|
||||
Test(t,
|
||||
That(`range 100 | take 2`).Puts(0, 1),
|
||||
thatOutputErrorIsBubbled("take 1 [foo]"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestDrop(t *testing.T) {
|
||||
Test(t,
|
||||
That(`range 100 | drop 98`).Puts(98, 99),
|
||||
thatOutputErrorIsBubbled("drop 1 [foo bar]"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -184,6 +186,7 @@ func TestKeys(t *testing.T) {
|
|||
// Windows does not have an external sort command. Disabled until we have a
|
||||
// builtin sort command.
|
||||
That(`keys [&a=foo &b=bar] | order`).Puts("a", "b"),
|
||||
thatOutputErrorIsBubbled("keys [&a=foo]"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -266,5 +269,7 @@ func TestOrder(t *testing.T) {
|
|||
// are equal, an check that the order among them has not changed.
|
||||
That("put l x o x r x e x m | order &less-than=[a b]{ eq $a x }").
|
||||
Puts("x", "x", "x", "x", "l", "o", "r", "e", "m"),
|
||||
|
||||
thatOutputErrorIsBubbled("order [foo]"),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package eval_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"src.elv.sh/pkg/eval"
|
||||
"src.elv.sh/pkg/eval/errs"
|
||||
. "src.elv.sh/pkg/eval/evaltest"
|
||||
"src.elv.sh/pkg/eval/vals"
|
||||
|
@ -204,5 +206,5 @@ func TestPrintf(t *testing.T) {
|
|||
}
|
||||
|
||||
func thatOutputErrorIsBubbled(code string) TestCase {
|
||||
return That(code + " >&-").Throws(AnyError)
|
||||
return That(code + " >&-").Throws(OneOfErrors(os.ErrInvalid, eval.ErrNoValueOutput))
|
||||
}
|
||||
|
|
|
@ -12,9 +12,17 @@ import (
|
|||
"src.elv.sh/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestKindOf(t *testing.T) {
|
||||
Test(t,
|
||||
That("kind-of a []").Puts("string", "list"),
|
||||
thatOutputErrorIsBubbled("kind-of a"),
|
||||
)
|
||||
}
|
||||
|
||||
func TestConstantly(t *testing.T) {
|
||||
Test(t,
|
||||
That(`f = (constantly foo); $f; $f`).Puts("foo", "foo"),
|
||||
thatOutputErrorIsBubbled("(constantly foo)"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -74,6 +82,8 @@ func TestTime(t *testing.T) {
|
|||
|
||||
That("time &on-end=[_]{ fail on-end } { fail body }").Throws(
|
||||
FailError{"body"}),
|
||||
|
||||
thatOutputErrorIsBubbled("time { }"),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ func TestStringComparisonCommands(t *testing.T) {
|
|||
func TestToString(t *testing.T) {
|
||||
Test(t,
|
||||
That(`to-string str (num 1) $true`).Puts("str", "1", "$true"),
|
||||
thatOutputErrorIsBubbled("to-string str"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,7 @@ func TestBase(t *testing.T) {
|
|||
That(`base 16 42 233`).Puts("2a", "e9"),
|
||||
That(`base 1 1`).Throws(AnyError), // no base-1
|
||||
That(`base 37 10`).Throws(AnyError), // no letter for base-37
|
||||
thatOutputErrorIsBubbled("base 2 1"),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -138,6 +138,7 @@ func TestAnd(t *testing.T) {
|
|||
|
||||
// Exception
|
||||
That("and a (fail x)").Throws(FailError{"x"}, "fail x"),
|
||||
thatOutputErrorIsBubbled("and a"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -152,6 +153,7 @@ func TestOr(t *testing.T) {
|
|||
|
||||
// Exception
|
||||
That("or $false (fail x)").Throws(FailError{"x"}, "fail x"),
|
||||
thatOutputErrorIsBubbled("or a"),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -132,3 +132,18 @@ func (e errCmdExit) matchError(gotErr error) bool {
|
|||
ge := gotErr.(eval.ExternalCmdExit)
|
||||
return e.v.CmdName == ge.CmdName && e.v.WaitStatus == ge.WaitStatus
|
||||
}
|
||||
|
||||
type errOneOf struct{ errs []error }
|
||||
|
||||
func OneOfErrors(errs ...error) error { return errOneOf{errs} }
|
||||
|
||||
func (e errOneOf) Error() string { return fmt.Sprint("one of", e.errs) }
|
||||
|
||||
func (e errOneOf) matchError(gotError error) bool {
|
||||
for _, want := range e.errs {
|
||||
if matchErr(want, gotError) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -45,6 +45,9 @@ func TestRe(t *testing.T) {
|
|||
// Basic verification of &posix behavior.
|
||||
That("put (re:find &posix 'a(x|xy)+' AaxyxxxyZ)[text]").Puts("axyxxxy"),
|
||||
|
||||
// re:find bubbles output error
|
||||
That("re:find . ab >&-").Throws(eval.ErrNoValueOutput),
|
||||
|
||||
That("re:replace '(ba|z)sh' '${1}SH' 'bash and zsh'").Puts("baSH and zSH"),
|
||||
That("re:replace &literal '(ba|z)sh' '$sh' 'bash and zsh'").Puts("$sh and $sh"),
|
||||
That("re:replace '(ba|z)sh' [x]{ put [&bash=BaSh &zsh=ZsH][$x] } 'bash and zsh'").Puts("BaSh and ZsH"),
|
||||
|
@ -66,6 +69,9 @@ func TestRe(t *testing.T) {
|
|||
// Invalid pattern in re:split
|
||||
That("re:split '(' x").Throws(AnyError),
|
||||
|
||||
// re:split bubbles output error
|
||||
That("re:split . ab >&-").Throws(eval.ErrNoValueOutput),
|
||||
|
||||
That("re:quote a.txt").Puts(`a\.txt`),
|
||||
That("re:quote '(*)'").Puts(`\(\*\)`),
|
||||
)
|
||||
|
|
|
@ -97,14 +97,17 @@ func TestStr(t *testing.T) {
|
|||
|
||||
That(`str:split : /usr:/bin:/tmp`).Puts("/usr", "/bin", "/tmp"),
|
||||
That(`str:split : /usr:/bin:/tmp &max=2`).Puts("/usr", "/bin:/tmp"),
|
||||
That("str:split : a:b >&-").Throws(eval.ErrNoValueOutput),
|
||||
|
||||
That(`str:to-codepoints a`).Puts("0x61"),
|
||||
That(`str:to-codepoints 你好`).Puts("0x4f60", "0x597d"),
|
||||
That(`str:to-codepoints 你好 | str:from-codepoints (all)`).Puts("你好"),
|
||||
That("str:to-codepoints a >&-").Throws(eval.ErrNoValueOutput),
|
||||
|
||||
That(`str:to-utf8-bytes a`).Puts("0x61"),
|
||||
That(`str:to-utf8-bytes 你好`).Puts("0xe4", "0xbd", "0xa0", "0xe5", "0xa5", "0xbd"),
|
||||
That(`str:to-utf8-bytes 你好 | str:from-utf8-bytes (all)`).Puts("你好"),
|
||||
That("str:to-utf8-bytes a >&-").Throws(eval.ErrNoValueOutput),
|
||||
|
||||
That(`str:title abc`).Puts("Abc"),
|
||||
That(`str:title "abc def"`).Puts("Abc Def"),
|
||||
|
|
Loading…
Reference in New Issue
Block a user