2023-03-03 07:48:01 +08:00
|
|
|
//go:build unix
|
2020-01-12 02:57:39 +08:00
|
|
|
|
2020-09-03 13:48:39 +08:00
|
|
|
package eval_test
|
2020-01-12 02:57:39 +08:00
|
|
|
|
|
|
|
import (
|
2021-08-07 04:38:37 +08:00
|
|
|
"os"
|
2020-01-12 02:57:39 +08:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2021-10-07 08:21:28 +08:00
|
|
|
"src.elv.sh/pkg/eval/errs"
|
2021-01-27 09:28:38 +08:00
|
|
|
. "src.elv.sh/pkg/eval/evaltest"
|
2022-06-21 03:29:14 +08:00
|
|
|
"src.elv.sh/pkg/must"
|
2021-01-27 09:28:38 +08:00
|
|
|
"src.elv.sh/pkg/testutil"
|
2020-01-12 02:57:39 +08:00
|
|
|
)
|
|
|
|
|
2021-06-18 07:11:51 +08:00
|
|
|
func TestPipeline_ReaderGone_Unix(t *testing.T) {
|
2021-05-20 07:10:17 +08:00
|
|
|
Test(t,
|
|
|
|
// External commands terminated by SIGPIPE due to reader exiting early
|
|
|
|
// raise ReaderGone, which is then suppressed.
|
2021-06-25 20:51:52 +08:00
|
|
|
That("yes | true").DoesNothing(),
|
2021-05-20 07:10:17 +08:00
|
|
|
That(
|
|
|
|
"var reached = $false",
|
2021-06-25 20:51:52 +08:00
|
|
|
"{ yes; reached = $true } | true",
|
2021-05-20 07:10:17 +08:00
|
|
|
"put $reached",
|
|
|
|
).Puts(false),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-10-07 08:21:28 +08:00
|
|
|
func TestCommand_External(t *testing.T) {
|
|
|
|
d := testutil.InTempDir(t)
|
2020-01-12 02:57:39 +08:00
|
|
|
|
|
|
|
mustWriteScript("foo", "#!/bin/sh", "echo foo")
|
|
|
|
mustWriteScript("lorem/ipsum", "#!/bin/sh", "echo lorem ipsum")
|
|
|
|
|
2021-10-07 08:21:28 +08:00
|
|
|
testutil.Setenv(t, "PATH", d+"/bin")
|
|
|
|
mustWriteScript("bin/hello", "#!/bin/sh", "echo hello")
|
|
|
|
|
2020-01-12 02:57:39 +08:00
|
|
|
Test(t,
|
2021-10-07 08:21:28 +08:00
|
|
|
// External commands, searched and relative
|
|
|
|
That("hello").Prints("hello\n"),
|
2020-01-12 02:57:39 +08:00
|
|
|
That("./foo").Prints("foo\n"),
|
|
|
|
That("lorem/ipsum").Prints("lorem ipsum\n"),
|
|
|
|
// Using the explicit e: namespace.
|
2021-10-07 08:21:28 +08:00
|
|
|
That("e:hello").Prints("hello\n"),
|
2020-01-12 02:57:39 +08:00
|
|
|
That("e:./foo").Prints("foo\n"),
|
2021-10-07 08:21:28 +08:00
|
|
|
// Relative external commands may be a dynamic string.
|
|
|
|
That("var x = ipsum", "lorem/$x").Prints("lorem ipsum\n"),
|
|
|
|
// Searched external commands may not be a dynamic string.
|
|
|
|
That("var x = hello; $x").Throws(
|
|
|
|
errs.BadValue{What: "command",
|
|
|
|
Valid: "callable or string containing slash", Actual: "hello"},
|
|
|
|
"$x"),
|
|
|
|
|
2020-01-12 20:32:25 +08:00
|
|
|
// Using new FD as destination in external commands.
|
|
|
|
// Regression test against b.elv.sh/788.
|
|
|
|
That("./foo 5</dev/null").Prints("foo\n"),
|
2021-10-07 08:21:28 +08:00
|
|
|
|
|
|
|
// Using pragma to allow or disallow implicit searched commands
|
2022-10-02 12:01:39 +08:00
|
|
|
That("pragma unknown-command = disallow", "hello").DoesNotCompile("unknown command disallowed by current pragma"),
|
2021-10-07 08:21:28 +08:00
|
|
|
That("pragma unknown-command = external", "hello").Prints("hello\n"),
|
|
|
|
// Pragma applies to subscope
|
2022-10-02 12:01:39 +08:00
|
|
|
That("pragma unknown-command = disallow", "{ hello }").DoesNotCompile("unknown command disallowed by current pragma"),
|
2021-10-07 08:21:28 +08:00
|
|
|
// Explicit uses with e: is always allowed
|
|
|
|
That("pragma unknown-command = disallow", "e:hello").Prints("hello\n"),
|
|
|
|
// Relative external commands are always allowed
|
|
|
|
That("pragma unknown-command = disallow", "./foo").Prints("foo\n"),
|
|
|
|
That("pragma unknown-command = disallow", "var x = ./foo", "$x").Prints("foo\n"),
|
2020-01-12 02:57:39 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func mustWriteScript(name string, lines ...string) {
|
2022-06-21 03:29:14 +08:00
|
|
|
must.WriteFile(name, strings.Join(lines, "\n"))
|
|
|
|
must.OK(os.Chmod(name, 0700))
|
2020-01-12 02:57:39 +08:00
|
|
|
}
|