pkg/eval: Split test functions.

This commit is contained in:
Qi Xiao 2021-01-10 14:48:21 +00:00
parent c67677fd8f
commit 50c971e5dd
13 changed files with 412 additions and 129 deletions

View File

@ -11,14 +11,18 @@ import (
"github.com/elves/elvish/pkg/eval/vals"
)
func TestBuiltinFnContainer(t *testing.T) {
func TestNsCmd(t *testing.T) {
Test(t,
That("put (ns [&name=value])[name]").Puts("value"),
That("n: = (ns [&name=value]); put $n:name").Puts("value"),
That("ns [&[]=[]]").Throws(errs.BadValue{
What: `key of argument of "ns"`,
Valid: "string", Actual: "list"}),
)
}
func TestMakeMap(t *testing.T) {
Test(t,
That("make-map []").Puts(vals.EmptyMap),
That("make-map [[k v]]").Puts(vals.MakeMap("k", "v")),
That("make-map [[k v] [k v2]]").Puts(vals.MakeMap("k", "v2")),
@ -36,43 +40,91 @@ func TestBuiltinFnContainer(t *testing.T) {
What: "input to make-map", Valid: "iterable with 2 elements",
Actual: "list with 1 elements"},
"make-map [[k]]"),
)
}
func TestRange(t *testing.T) {
Test(t,
That(`range 3`).Puts(0.0, 1.0, 2.0),
That(`range 1 3`).Puts(1.0, 2.0),
That(`range 0 10 &step=3`).Puts(0.0, 3.0, 6.0, 9.0),
)
}
func TestRepeat(t *testing.T) {
Test(t,
That(`repeat 4 foo`).Puts("foo", "foo", "foo", "foo"),
)
}
func TestAssoc(t *testing.T) {
Test(t,
That(`put (assoc [0] 0 zero)[0]`).Puts("zero"),
That(`put (assoc [&] k v)[k]`).Puts("v"),
That(`put (assoc [&k=v] k v2)[k]`).Puts("v2"),
That(`has-key (dissoc [&k=v] k) k`).Puts(false),
)
}
func TestDissoc(t *testing.T) {
Test(t,
That(`has-key (dissoc [&k=v] k) k`).Puts(false),
)
}
func TestAll(t *testing.T) {
Test(t,
That(`put foo bar | all`).Puts("foo", "bar"),
That(`echo foobar | all`).Puts("foobar"),
That(`all [foo bar]`).Puts("foo", "bar"),
)
}
func TestOne(t *testing.T) {
Test(t,
That(`put foo | one`).Puts("foo"),
That(`put | one`).Throws(AnyError),
That(`put foo bar | one`).Throws(AnyError),
That(`one [foo]`).Puts("foo"),
That(`one []`).Throws(AnyError),
That(`one [foo bar]`).Throws(AnyError),
)
}
func TestTake(t *testing.T) {
Test(t,
That(`range 100 | take 2`).Puts(0.0, 1.0),
That(`range 100 | drop 98`).Puts(98.0, 99.0),
)
}
func TestDrop(t *testing.T) {
Test(t,
That(`range 100 | drop 98`).Puts(98.0, 99.0),
)
}
func TestHasKey(t *testing.T) {
Test(t,
That(`has-key [foo bar] 0`).Puts(true),
That(`has-key [foo bar] 0:1`).Puts(true),
That(`has-key [foo bar] 0:20`).Puts(false),
That(`has-key [&lorem=ipsum &foo=bar] lorem`).Puts(true),
That(`has-key [&lorem=ipsum &foo=bar] loremwsq`).Puts(false),
)
}
func TestHasValue(t *testing.T) {
Test(t,
That(`has-value [&lorem=ipsum &foo=bar] lorem`).Puts(false),
That(`has-value [&lorem=ipsum &foo=bar] bar`).Puts(true),
That(`has-value [foo bar] bar`).Puts(true),
That(`has-value [foo bar] badehose`).Puts(false),
That(`has-value "foo" o`).Puts(true),
That(`has-value "foo" d`).Puts(false),
)
}
func TestCount(t *testing.T) {
Test(t,
That(`range 100 | count`).Puts("100"),
That(`count [(range 100)]`).Puts("100"),
That(`count 123`).Puts("3"),
@ -81,13 +133,21 @@ func TestBuiltinFnContainer(t *testing.T) {
What: "arguments here", ValidLow: 0, ValidHigh: 1, Actual: 3},
"count 1 2 3"),
That(`count $true`).Throws(ErrorWithMessage("cannot get length of a bool")),
)
}
func TestKeys(t *testing.T) {
Test(t,
That(`keys [&]`).DoesNothing(),
That(`keys [&a=foo]`).Puts("a"),
// 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"),
)
}
func TestOrder(t *testing.T) {
Test(t,
// Ordering strings
That("put foo bar ipsum | order").Puts("bar", "foo", "ipsum"),
That("put foo bar bar | order").Puts("bar", "bar", "foo"),
@ -143,8 +203,8 @@ func TestBuiltinFnContainer(t *testing.T) {
// &less-than and &reverse
That("put 1 10 2 5 | order &reverse &less-than=[a b]{ < $a $b }").
Puts("10", "5", "2", "1"),
// Sort should be stable - test by pretending that all values but one d
// are equal, an check that the order among them has not change d
// Sort should be stable - test by pretending that all values but one
// 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"),
)

View File

@ -4,34 +4,71 @@ import (
"os"
"testing"
"github.com/elves/elvish/pkg/env"
"github.com/elves/elvish/pkg/eval"
. "github.com/elves/elvish/pkg/eval/evaltest"
"github.com/elves/elvish/pkg/eval/vals"
)
func TestBuiltinFnEnv(t *testing.T) {
oldpath := os.Getenv(env.PATH)
listSep := string(os.PathListSeparator)
func TestGetEnv(t *testing.T) {
restore := saveEnv("var")
defer restore()
os.Unsetenv("var")
Test(t, That(`get-env var`).Throws(eval.ErrNonExistentEnvVar))
os.Setenv("var", "test1")
Test(t,
That(`get-env var`).Throws(eval.ErrNonExistentEnvVar),
That(`set-env var test1`),
That(`get-env var`).Puts("test1"),
That(`put $E:var`).Puts("test1"),
)
That(`set-env var test2`),
os.Setenv("var", "test2")
Test(t,
That(`get-env var`).Puts("test2"),
That(`put $E:var`).Puts("test2"),
)
}
That(`has-env var`).Puts(true),
That(`unset-env var`),
That(`has-env var`).Puts(false),
func TestHasEnv(t *testing.T) {
restore := saveEnv("var")
defer restore()
os.Setenv("var", "test1")
Test(t, That(`has-env var`).Puts(true))
os.Unsetenv("var")
Test(t, That(`has-env var`).Puts(false))
}
func TestSetEnv(t *testing.T) {
restore := saveEnv("var")
defer restore()
Test(t, That("set-env var test1").DoesNothing())
if envVal := os.Getenv("var"); envVal != "test1" {
t.Errorf("got $E:var = %q, want 'test1'", envVal)
}
}
func TestSetEnv_PATH(t *testing.T) {
restore := saveEnv("PATH")
defer restore()
listSep := string(os.PathListSeparator)
Test(t,
That(`set-env PATH /test-path`),
That(`put $paths`).Puts(vals.MakeList("/test-path")),
That(`paths = [/test-path2 $@paths]`),
That(`get-env PATH`).Puts("/test-path2"+listSep+"/test-path"),
)
os.Setenv(env.PATH, oldpath)
}
func saveEnv(name string) func() {
oldValue, ok := os.LookupEnv(name)
return func() {
if ok {
os.Setenv(name, oldValue)
}
}
}

View File

@ -9,11 +9,15 @@ import (
"github.com/elves/elvish/pkg/eval/vals"
)
func TestBuiltinFnFlow(t *testing.T) {
func TestRunParallel(t *testing.T) {
Test(t,
That(`run-parallel { put lorem } { echo ipsum }`).
Puts("lorem").Prints("ipsum\n"),
)
}
func TestEach(t *testing.T) {
Test(t,
That(`put 1 233 | each $put~`).Puts("1", "233"),
That(`echo "1\n233" | each $put~`).Puts("1", "233"),
That(`echo "1\r\n233" | each $put~`).Puts("1", "233"),
@ -23,8 +27,13 @@ func TestBuiltinFnFlow(t *testing.T) {
That(`range 10 | each [x]{ if (== $x 4) { fail haha }; put $x }`).
Puts(0.0, 1.0, 2.0, 3.0).Throws(AnyError),
// TODO(xiaq): Test that "each" does not close the stdin.
// TODO: test peach
)
}
// TODO: test peach
func TestFail(t *testing.T) {
Test(t,
That("fail haha").Throws(FailError{"haha"}, "fail haha"),
That("fn f { fail haha }", "fail ?(f)").Throws(
FailError{"haha"}, "fail haha ", "f"),
@ -32,7 +41,12 @@ func TestBuiltinFnFlow(t *testing.T) {
FailError{vals.EmptyList}, "fail []"),
That("put ?(fail 1)[reason][type]").Puts("fail"),
That("put ?(fail 1)[reason][content]").Puts("1"),
That(`return`).Throws(Return),
)
}
func TestReturn(t *testing.T) {
Test(t,
That("return").Throws(Return),
// Use of return inside fn is tested in TestFn
)
}

View File

@ -7,47 +7,105 @@ import (
"github.com/elves/elvish/pkg/eval/vals"
)
func TestBuiltinFnIO(t *testing.T) {
func TestPut(t *testing.T) {
Test(t,
That(`put foo bar`).Puts("foo", "bar"),
That(`put $nil`).Puts(nil),
)
}
func TestReadUpto(t *testing.T) {
Test(t,
That("print abcd | read-upto c").Puts("abc"),
// read-upto does not consume more than needed
That("print abcd | { read-upto c; slurp }").Puts("abc", "d"),
// read-upto reads up to EOF
That("print abcd | read-upto z").Puts("abcd"),
)
}
func TestReadLine(t *testing.T) {
Test(t,
That(`print eof-ending | read-line`).Puts("eof-ending"),
That(`print "lf-ending\n" | read-line`).Puts("lf-ending"),
That(`print "crlf-ending\r\n" | read-line`).Puts("crlf-ending"),
That(`print "extra-cr\r\r\n" | read-line`).Puts("extra-cr\r"),
)
}
func TestPrint(t *testing.T) {
Test(t,
That(`print [foo bar]`).Prints("[foo bar]"),
That(`print foo bar &sep=,`).Prints("foo,bar"),
That(`echo [foo bar]`).Prints("[foo bar]\n"),
That(`pprint [foo bar]`).Prints("[\n foo\n bar\n]\n"),
That(`repr foo bar ['foo bar']`).Prints("foo bar ['foo bar']\n"),
)
}
func TestEcho(t *testing.T) {
Test(t,
That(`echo [foo bar]`).Prints("[foo bar]\n"),
)
}
func TestPprint(t *testing.T) {
Test(t,
That(`pprint [foo bar]`).Prints("[\n foo\n bar\n]\n"),
)
}
func TestReprCmd(t *testing.T) {
Test(t,
That(`repr foo bar ['foo bar']`).Prints("foo bar ['foo bar']\n"),
)
}
func TestShow(t *testing.T) {
Test(t,
// A sanity test that show writes something.
That(`show ?(fail foo) | !=s (slurp) ''`).Puts(true),
)
}
func TestOnlyBytesAndOnlyValues(t *testing.T) {
Test(t,
// Baseline for only-{bytes,values}
That(`{ print bytes; put values }`).Prints("bytes").Puts("values"),
That(`{ print bytes; put values } | only-bytes`).Prints("bytes").Puts(),
That(`{ print bytes; put values } | only-values`).Prints("").Puts("values"),
)
}
func TestSlurp(t *testing.T) {
Test(t,
That(`print "a\nb" | slurp`).Puts("a\nb"),
)
}
func TestFromLines(t *testing.T) {
Test(t,
That(`print "a\nb" | from-lines`).Puts("a", "b"),
That(`print "a\nb\n" | from-lines`).Puts("a", "b"),
)
}
func TestFromJson(t *testing.T) {
Test(t,
That(`echo '{"k": "v", "a": [1, 2]}' '"foo"' | from-json`).
Puts(vals.MakeMap("k", "v", "a", vals.MakeList(1.0, 2.0)),
"foo"),
That(`echo '[null, "foo"]' | from-json`).Puts(
vals.MakeList(nil, "foo")),
That(`echo 'invalid' | from-json`).Throws(AnyError),
)
}
func TestToLines(t *testing.T) {
Test(t,
That(`put "l\norem" ipsum | to-lines`).Prints("l\norem\nipsum\n"),
)
}
func TestToJson(t *testing.T) {
Test(t,
That(`put [&k=v &a=[1 2]] foo | to-json`).
Prints(`{"a":["1","2"],"k":"v"}
"foo"

View File

@ -12,12 +12,14 @@ import (
"github.com/elves/elvish/pkg/testutil"
)
func TestBuiltinFnMisc(t *testing.T) {
func TestConstantly(t *testing.T) {
Test(t,
That(`f = (constantly foo); $f; $f`).Puts("foo", "foo"),
)
}
// eval
// ====
func TestEval(t *testing.T) {
Test(t,
That("eval 'put x'").Puts("x"),
// Using variable from the local scope.
That("x = foo; eval 'put $x'").Puts("foo"),
@ -43,9 +45,11 @@ func TestBuiltinFnMisc(t *testing.T) {
That("eval 'put $x'").Throws(AnyError),
// Exception.
That("eval 'fail x'").Throws(FailError{"x"}),
)
}
// Test the "time" builtin.
//
func TestTime(t *testing.T) {
Test(t,
// Since runtime duration is non-deterministic, we only have some sanity
// checks here.
That("time { echo foo } | a _ = (all)", "put $a").Puts("foo"),

View File

@ -10,11 +10,15 @@ import (
. "github.com/elves/elvish/pkg/eval/evaltest"
)
func TestBuiltinFnNum(t *testing.T) {
func TestFloat64(t *testing.T) {
Test(t,
That("float64 1").Puts(1.0),
That("float64 (float64 1)").Puts(1.0),
)
}
func TestNumberComparisonCommands(t *testing.T) {
Test(t,
That("< 1 2 3").Puts(true),
That("< 1 3 2").Puts(false),
That("<= 1 1 2").Puts(true),
@ -27,7 +31,11 @@ func TestBuiltinFnNum(t *testing.T) {
That("> 3 1 2").Puts(false),
That(">= 3 3 2").Puts(true),
That(">= 3 2 3").Puts(false),
)
}
func TestArithmeticCommands(t *testing.T) {
Test(t,
// TODO test more edge cases
That("+ 233100 233").Puts(233333.0),
That("- 233333 233100").Puts(233.0),
@ -37,7 +45,11 @@ func TestBuiltinFnNum(t *testing.T) {
That("/ 1 0").Puts(math.Inf(1)),
That("% 23 7").Puts("2"),
That("% 1 0").Throws(AnyError),
)
}
func TestRandint(t *testing.T) {
Test(t,
That("randint 1 2").Puts("1"),
That("i = (randint 10 100); >= $i 10; < $i 100").Puts(true, true),
That("randint 2 1").Throws(ErrArgs, "randint 2 1"),

View File

@ -19,23 +19,39 @@ func TestBool(t *testing.T) {
// Only errors and $false are false
That(`bool ?(fail x)`).Puts(false),
That(`bool $false`).Puts(false),
)
}
func TestNot(t *testing.T) {
Test(t,
That(`not $false`).Puts(true),
That(`not ?(fail x)`).Puts(true),
That(`not $true`).Puts(false),
That(`not 0`).Puts(false),
)
}
func TestIs(t *testing.T) {
Test(t,
That(`is 1 1`).Puts(true),
That(`is a b`).Puts(false),
That(`is [] []`).Puts(true),
That(`is [1] [1]`).Puts(false),
)
}
func TestEq(t *testing.T) {
Test(t,
That(`eq 1 1`).Puts(true),
That(`eq a b`).Puts(false),
That(`eq [] []`).Puts(true),
That(`eq [1] [1]`).Puts(true),
That(`eq 1 1 2`).Puts(false),
)
}
func TestNotEq(t *testing.T) {
Test(t,
That(`not-eq a b`).Puts(true),
That(`not-eq a a`).Puts(false),
// not-eq is true as long as each adjacent pair is not equal.

View File

@ -6,7 +6,7 @@ import (
. "github.com/elves/elvish/pkg/eval/evaltest"
)
func TestBuiltinFnStr(t *testing.T) {
func TestStringComparisonCommands(t *testing.T) {
Test(t,
That(`<s a b`).Puts(true),
That(`<s 2 10`).Puts(false),
@ -22,28 +22,62 @@ func TestBuiltinFnStr(t *testing.T) {
That(`>=s a a`).Puts(true),
That(`>=s a b`).Puts(false),
That(`>=s b a`).Puts(true),
)
}
func TestToString(t *testing.T) {
Test(t,
That(`to-string str (float64 1) $true`).Puts("str", "1", "$true"),
)
}
func TestOrd(t *testing.T) {
Test(t,
That(`ord a`).Puts("0x61"),
That(`ord 你好`).Puts("0x4f60", "0x597d"),
)
}
func TestChr(t *testing.T) {
Test(t,
That(`chr 0x61`).Puts("a"),
That(`chr 0x4f60 0x597d`).Puts("你好"),
That(`chr -1`).Throws(AnyError),
)
}
func TestBase(t *testing.T) {
Test(t,
That(`base 2 1 3 4 16 255`).Puts("1", "11", "100", "10000", "11111111"),
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
)
}
func TestWcswidth(t *testing.T) {
Test(t,
That(`wcswidth 你好`).Puts("4"),
That(`-override-wcwidth x 10; wcswidth 1x2x; -override-wcwidth x 1`).
Puts("22"),
)
}
func TestHasPrefix(t *testing.T) {
Test(t,
That(`has-prefix golang go`).Puts(true),
That(`has-prefix golang x`).Puts(false),
That(`has-suffix golang x`).Puts(false),
)
}
func TestHasSuffix(t *testing.T) {
Test(t,
That(`has-suffix golang x`).Puts(false),
)
}
func TestEawk(t *testing.T) {
Test(t,
That(`echo " ax by cz \n11\t22 33" | eawk [@a]{ put $a[-1] }`).
Puts("cz", "33"),
)

View File

@ -13,7 +13,7 @@ import (
"github.com/elves/elvish/pkg/testutil"
)
func TestBuiltinSpecial(t *testing.T) {
func TestDel(t *testing.T) {
Test(t,
// del - deleting variable
That("x = 1; del x").DoesNothing(),
@ -31,48 +31,69 @@ func TestBuiltinSpecial(t *testing.T) {
That("x = 1; del $x").DoesNotCompile(),
That("del [a]").DoesNotCompile(),
That("x = []; del @x").DoesNotCompile(),
)
}
// and
func TestAnd(t *testing.T) {
Test(t,
That("and $true $false").Puts(false),
// and - short circuit
That("and a b").Puts("b"),
That("and $false b").Puts(false),
That("and $true b").Puts("b"),
// short circuit
That("x = a; and $false (x = b); put $x").Puts(false, "a"),
)
}
// or
func TestOr(t *testing.T) {
Test(t,
That("or $true $false").Puts(true),
That("or a b").Puts("a"),
// or - short circuit
That("or $false b").Puts("b"),
That("or $true b").Puts(true),
// short circuit
That("x = a; or $true (x = b); put $x").Puts(true, "a"),
)
}
// if
func TestIf(t *testing.T) {
Test(t,
That("if true { put then }").Puts("then"),
That("if $false { put then } else { put else }").Puts("else"),
That("if $false { put 1 } elif $false { put 2 } else { put 3 }").
Puts("3"),
That("if $false { put 2 } elif true { put 2 } else { put 3 }").Puts("2"),
)
}
// try
func TestTry(t *testing.T) {
Test(t,
That("try { nop } except { put bad } else { put good }").Puts("good"),
That("try { e:false } except - { put bad } else { put good }").
Puts("bad"),
That("try { fail tr }").Throws(ErrorWithMessage("tr")),
That("try { fail tr } finally { put final }").
Puts("final").Throws(ErrorWithMessage(
"tr")),
Puts("final").
Throws(ErrorWithMessage("tr")),
That("try { fail tr } except { fail ex } finally { put final }").
Puts("final").Throws(ErrorWithMessage(
"ex")),
Puts("final").
Throws(ErrorWithMessage("ex")),
That("try { fail tr } except { put ex } finally { fail final }").
Puts("ex").Throws(ErrorWithMessage(
"final")),
Puts("ex").
Throws(ErrorWithMessage("final")),
That("try { fail tr } except { fail ex } finally { fail final }").Throws(ErrorWithMessage(
"final")),
That("try { fail tr } except { fail ex } finally { fail final }").
Throws(ErrorWithMessage("final")),
// try - wrong use
// wrong syntax
That("try { nop } except @a { }").DoesNotCompile(),
)
}
func TestWhile(t *testing.T) {
Test(t,
// while
That("x=0; while (< $x 4) { put $x; x=(+ $x 1) }").
Puts("0", 1.0, 2.0, 3.0),
@ -81,7 +102,11 @@ func TestBuiltinSpecial(t *testing.T) {
That("x = 0; while (< $x 4) { put $x; x=(+ $x 1) } else { put bad }").
Puts("0", 1.0, 2.0, 3.0),
That("while $false { put bad } else { put good }").Puts("good"),
)
}
func TestFor(t *testing.T) {
Test(t,
// for
That("for x [tempora mores] { put 'O '$x }").
Puts("O tempora", "O mores"),
@ -104,15 +129,17 @@ func TestBuiltinSpecial(t *testing.T) {
What: "value being iterated",
ValidLow: 1, ValidHigh: 1, Actual: 2},
"(put a b)"),
)
}
// fn.
func TestFn(t *testing.T) {
Test(t,
That("fn f [x]{ put x=$x'.' }; f lorem; f ipsum").
Puts("x=lorem.", "x=ipsum."),
// Recursive functions with fn. Regression test for #1206.
That("fn f [n]{ if (== $n 0) { put 1 } else { * $n (f (- $n 1)) } }; f 3").
Puts(6.0),
// return.
// Exception thrown by return is swallowed by a fn-defined function.
That("fn f []{ put a; return; put b }; f").Puts("a"),
)
}

View File

@ -10,7 +10,7 @@ import (
. "github.com/elves/elvish/pkg/eval/evaltest"
)
func TestClosure(t *testing.T) {
func TestClosureAsValue(t *testing.T) {
Test(t,
// Basic operations as a value.
That("kind-of { }").Puts("fn"),

View File

@ -5,34 +5,30 @@ import (
"github.com/elves/elvish/pkg/eval/errs"
. "github.com/elves/elvish/pkg/eval"
. "github.com/elves/elvish/pkg/eval/evaltest"
"github.com/elves/elvish/pkg/eval/vals"
"github.com/elves/elvish/pkg/eval/vars"
"github.com/elves/elvish/pkg/testutil"
)
func TestCompileEffect(t *testing.T) {
_, cleanup := testutil.InTestDir()
defer cleanup()
func TestChunk(t *testing.T) {
Test(t,
// Chunks
// ------
// Empty chunk
That("").DoesNothing(),
// Outputs of pipelines in a chunk are concatenated
That("put x; put y; put z").Puts("x", "y", "z"),
// A failed pipeline cause the whole chunk to fail
That("put a; e:false; put b").Puts("a").Throws(AnyError),
)
}
// Pipelines
// ---------
func TestPipeline(t *testing.T) {
Test(t,
// Pure byte pipeline
That(`echo "Albert\nAllan\nAlbraham\nBerlin" | sed s/l/1/g | grep e`).
Prints("A1bert\nBer1in\n"),
// Pure channel pipeline
// Pure value pipeline
That(`put 233 42 19 | each [x]{+ $x 10}`).Puts(243.0, 52.0, 29.0),
// Pipeline draining.
That(`range 100 | put x`).Puts("x"),
@ -44,10 +40,11 @@ func TestCompileEffect(t *testing.T) {
"slurp < $p",
"prclose $p").Puts("foo"),
// TODO: Add a useful hybrid pipeline sample
)
}
// Commands
// --------
func TestCommand(t *testing.T) {
Test(t,
That("put foo").Puts("foo"),
// Command errors when the head is not a single value.
That("{put put} foo").Throws(
@ -69,14 +66,25 @@ func TestCompileEffect(t *testing.T) {
"put &[]=[]"),
// Command errors when any optional evaluation errors.
That("put &x=[][1]").Throws(ErrorWithType(errs.OutOfRange{}), "[][1]"),
)
}
func TestCommand_Special(t *testing.T) {
Test(t,
// Regression test for #1204; ensures that the arguments of special
// forms are not accidentally compiled twice.
That("nop (and (use builtin)); nop $builtin:echo~").DoesNothing(),
// Assignments
// -----------
// Behavior of individual special commands are tested in
// builtin_special_test.go.
)
}
func TestCommand_Assignment(t *testing.T) {
// NOTE: TestClosure has more tests for the interaction between assignment
// and variable scoping.
Test(t,
// Spacey assignment.
That("a = foo; put $a").Puts("foo"),
That("a b = foo bar; put $a $b").Puts("foo", "bar"),
@ -141,9 +149,17 @@ func TestCompileEffect(t *testing.T) {
ValidLow: 2, ValidHigh: -1, Actual: 1},
"x y @z = 1"),
// Redirections
// ------------
// Trying to add a new name in a namespace throws an exception.
// Regression test for #1214.
That("ns: = (ns [&]); ns:a = b").Throws(NoSuchVariable("ns:a"), "ns:a = b"),
)
}
func TestCommand_Redir(t *testing.T) {
_, cleanup := testutil.InTestDir()
defer cleanup()
Test(t,
// Output and input redirection.
That("echo 233 > out1", " slurp < out1").Puts("233\n"),
// Append.
@ -198,7 +214,7 @@ func TestCompileEffect(t *testing.T) {
)
}
func TestStacktrace(t *testing.T) {
func TestCommand_Stacktrace(t *testing.T) {
oops := ErrorWithMessage("oops")
Test(t,
// Stack traces.

View File

@ -1,21 +0,0 @@
package eval_test
import (
"testing"
. "github.com/elves/elvish/pkg/eval"
. "github.com/elves/elvish/pkg/eval/evaltest"
)
func TestAssignment(t *testing.T) {
Test(t,
That("x = a; put $x").Puts("a"),
That("x = [a]; x[0] = b; put $x[0]").Puts("b"),
That("x = a; { x = b }; put $x").Puts("b"),
That("x = [a]; { x[0] = b }; put $x[0]").Puts("b"),
// Trying to add a new name in a namespace throws an exception.
// Regression test for #1214.
That("ns: = (ns [&]); ns:a = b").Throws(NoSuchVariable("ns:a"), "ns:a = b"),
)
}

View File

@ -11,15 +11,8 @@ import (
"github.com/elves/elvish/pkg/eval/vals"
)
func TestCompileValue(t *testing.T) {
home, cleanup := testutil.InTempHome()
testutil.MustCreateEmpty("file1")
testutil.MustCreateEmpty("file2")
defer cleanup()
func TestCompound(t *testing.T) {
Test(t,
// Compounding
// -----------
That("put {fi,elvi}sh{1.0,1.1}").Puts(
"fish1.0", "fish1.1", "elvish1.0", "elvish1.1"),
@ -36,52 +29,90 @@ func TestCompileValue(t *testing.T) {
That("put []a").Throws(ErrorWithMessage("cannot concatenate list and string")),
// Error when applying tilde throws an exception.
That("put ~[]").Throws(ErrorWithMessage("tilde doesn't work on value of type list")),
)
}
// List, Map and Indexing
// ----------------------
That("echo [a b c] [&key=value] | each $put~").
Puts("[a b c] [&key=value]"),
func TestIndexing(t *testing.T) {
Test(t,
That("put [a b c][2]").Puts("c"),
That("put [][0]").Throws(ErrorWithType(errs.OutOfRange{}), "[][0]"),
That("put [&key=value][key]").Puts("value"),
That("put [&key=value][bad]").Throws(
vals.NoSuchKey("bad"), "[&key=value][bad]"),
)
}
func TestListLiteral(t *testing.T) {
Test(t,
That("put [a b c]").Puts(vals.MakeList("a", "b", "c")),
That("put []").Puts(vals.EmptyList),
// List expression errors if an element expression errors.
That("put [ [][0] ]").Throws(ErrorWithType(errs.OutOfRange{}), "[][0]"),
)
}
func TestMapLiteral(t *testing.T) {
Test(t,
That("put [&key=value]").Puts(vals.MakeMap("key", "value")),
That("put [&]").Puts(vals.EmptyMap),
// Map keys and values may evaluate to multiple values as long as their
// numbers match.
That("put [&{a b}={foo bar}]").Puts(vals.MakeMap("a", "foo", "b", "bar")),
// List expression errors if an element expression errors.
That("put [ [][0] ]").Throws(ErrorWithType(errs.OutOfRange{}), "[][0]"),
// Map expression errors if a key or value expression errors.
That("put [ &[][0]=a ]").Throws(ErrorWithType(errs.OutOfRange{}), "[][0]"),
That("put [ &a=[][0] ]").Throws(ErrorWithType(errs.OutOfRange{}), "[][0]"),
// Map expression errors if number of keys and values in a single pair
// does not match.
That("put [&{a b}={foo bar lorem}]").Throws(ErrorWithMessage("2 keys but 3 values")),
)
}
// String Literals
// ---------------
func TestStringLiteral(t *testing.T) {
Test(t,
That(`put 'such \"''literal'`).Puts(`such \"'literal`),
That(`put "much \n\033[31;1m$cool\033[m"`).
Puts("much \n\033[31;1m$cool\033[m"),
)
}
// Captures
// ---------
func TestTilde(t *testing.T) {
home, cleanup := testutil.InTempHome()
testutil.MustCreateEmpty("file1")
testutil.MustCreateEmpty("file2")
defer cleanup()
Test(t,
// Tilde
// -----
That("put ~").Puts(home),
That("put ~/src").Puts(home+"/src"),
// Make sure that tilde processing retains trailing slashes.
That("put ~/src/").Puts(home+"/src/"),
// Tilde and wildcard.
That("put ~/*").Puts(home+"/file1", home+"/file2"),
// TODO(xiaq): Add regression test for #793.
)
}
func TestOutputCapture(t *testing.T) {
Test(t,
// Output capture
That("put (put lorem ipsum)").Puts("lorem", "ipsum"),
That("put (print \"lorem\nipsum\")").Puts("lorem", "ipsum"),
// \r\n is also supported as a line separator
That(`print "lorem\r\nipsum\r\n" | all`).Puts("lorem", "ipsum"),
)
}
func TestExceptionCapture(t *testing.T) {
Test(t,
// Exception capture
That("bool ?(nop); bool ?(e:false)").Puts(true, false),
)
}
// Variable Use
// ------------
func TestVariableUse(t *testing.T) {
Test(t,
That("x = foo", "put $x").Puts("foo"),
// Must exist before use
That("put $x").DoesNotCompile(),
@ -136,27 +167,22 @@ func TestCompileValue(t *testing.T) {
// Multi-level namespace access can be combined with the up:
// pseudo-namespaces.
That("ns: = (ns [&a:= (ns [&b= val])]); { put $up:ns:a:b }").Puts("val"),
)
}
// Tilde
// -----
That("put ~").Puts(home),
That("put ~/src").Puts(home+"/src"),
// Make sure that tilde processing retains trailing slashes.
That("put ~/src/").Puts(home+"/src/"),
// Tilde and wildcard.
That("put ~/*").Puts(home+"/file1", home+"/file2"),
// TODO(xiaq): Add regression test for #793.
// Closure
// -------
func TestClosure(t *testing.T) {
Test(t,
That("[]{ }").DoesNothing(),
That("[x]{put $x} foo").Puts("foo"),
// Variable capture
// Assigning to captured variable
That("x=lorem; []{x=ipsum}; put $x").Puts("ipsum"),
That("x=lorem; []{ put $x; x=ipsum }; put $x").Puts("lorem", "ipsum"),
// Assigning to element of captured variable
That("x = a; { x = b }; put $x").Puts("b"),
That("x = [a]; { x[0] = b }; put $x[0]").Puts("b"),
// Shadowing
That("x=ipsum; []{ local:x=lorem; put $x }; put $x").Puts("lorem", "ipsum"),