elvish/pkg/eval/builtin_fn_io_test.go
Kurtis Rader 87656c99fa Replace AnyError in tests with a specific error
The `AnyError` placeholder error can cause tests to succeed for errors
other than what was expected. That is, the use of `AnyError` can mask
bugs in a unit test. So replace it with the specific error, or error type,
the test expects to be raised.

This does not remove the anyError structure because it is used in
the TestCase.DoesNotCompile() method. To keep the size of this change
as small as possible I want to defer updating that use to a separate
change. However, remove the public AnyError var so future test writers
don't attempt to use it.
2021-12-13 01:08:24 +00:00

212 lines
6.0 KiB
Go

package eval_test
import (
"encoding/json"
"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"
)
func TestPut(t *testing.T) {
Test(t,
That(`put foo bar`).Puts("foo", "bar"),
That(`put $nil`).Puts(nil),
thatOutputErrorIsBubbled("put foo"),
)
}
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"),
That("print abcd | read-upto cd").Throws(
errs.BadValue{What: "terminator",
Valid: "a single ASCII character", Actual: "cd"}),
thatOutputErrorIsBubbled("print abcd | read-upto c"),
)
}
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"),
thatOutputErrorIsBubbled(`print eof-ending | read-line`),
)
}
func TestPrint(t *testing.T) {
Test(t,
That(`print [foo bar]`).Prints("[foo bar]"),
That(`print foo bar &sep=,`).Prints("foo,bar"),
thatOutputErrorIsBubbled("print foo"),
)
}
func TestEcho(t *testing.T) {
Test(t,
That(`echo [foo bar]`).Prints("[foo bar]\n"),
thatOutputErrorIsBubbled("echo foo"),
)
}
func TestPprint(t *testing.T) {
Test(t,
That(`pprint [foo bar]`).Prints("[\n foo\n bar\n]\n"),
thatOutputErrorIsBubbled("pprint foo"),
)
}
func TestReprCmd(t *testing.T) {
Test(t,
That(`repr foo bar ['foo bar']`).Prints("foo bar ['foo bar']\n"),
thatOutputErrorIsBubbled("repr foo"),
)
}
func TestShow(t *testing.T) {
Test(t,
// A sanity test that show writes something.
That(`show ?(fail foo) | !=s (slurp) ''`).Puts(true),
thatOutputErrorIsBubbled("repr ?(fail foo)"),
)
}
func TestOnlyBytesAndOnlyValues(t *testing.T) {
Test(t,
// Baseline
That(`{ print bytes; put values }`).Prints("bytes").Puts("values"),
That(`{ print bytes; put values } | only-bytes`).Prints("bytes").Puts(),
thatOutputErrorIsBubbled("{ print bytes; put values } | only-bytes"),
)
}
func TestOnlyValues(t *testing.T) {
Test(t,
// Baseline
That(`{ print bytes; put values }`).Prints("bytes").Puts("values"),
That(`{ print bytes; put values } | only-values`).Prints("").Puts("values"),
thatOutputErrorIsBubbled("{ print bytes; put values } | only-values"),
)
}
func TestSlurp(t *testing.T) {
Test(t,
That(`print "a\nb" | slurp`).Puts("a\nb"),
thatOutputErrorIsBubbled(`print "a\nb" | slurp`),
)
}
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"),
thatOutputErrorIsBubbled(`print "a\nb\n" | from-lines`),
)
}
func TestFromTerminated(t *testing.T) {
Test(t,
That(`print "a\nb\x00\x00c\x00d" | from-terminated "\x00"`).Puts("a\nb", "", "c", "d"),
That(`print "a\x00b\x00" | from-terminated "\x00"`).Puts("a", "b"),
That(`print aXbXcXXd | from-terminated "X"`).Puts("a", "b", "c", "", "d"),
That(`from-terminated "xyz"`).Throws(
errs.BadValue{What: "terminator",
Valid: "a single ASCII character", Actual: "xyz"}),
thatOutputErrorIsBubbled("print aXbX | from-terminated X"),
)
}
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(ErrorWithType(&json.SyntaxError{})),
thatOutputErrorIsBubbled(`echo '[]' | from-json`),
)
}
func TestToLines(t *testing.T) {
Test(t,
That(`put "l\norem" ipsum | to-lines`).Prints("l\norem\nipsum\n"),
thatOutputErrorIsBubbled("to-lines [foo]"),
)
}
func TestToTerminated(t *testing.T) {
Test(t,
That(`put "l\norem" ipsum | to-terminated "\x00"`).Prints("l\norem\x00ipsum\x00"),
That(`to-terminated "X" [a b c]`).Prints("aXbXcX"),
That(`to-terminated "XYZ" [a b c]`).Throws(
errs.BadValue{What: "terminator",
Valid: "a single ASCII character", Actual: "XYZ"}),
thatOutputErrorIsBubbled(`to-terminated "X" [a b c]`),
)
}
func TestToJson(t *testing.T) {
Test(t,
That(`put [&k=v &a=[1 2]] foo | to-json`).
Prints(`{"a":["1","2"],"k":"v"}
"foo"
`),
That(`put [$nil foo] | to-json`).Prints("[null,\"foo\"]\n"),
thatOutputErrorIsBubbled("to-json [foo]"),
)
}
func TestPrintf(t *testing.T) {
Test(t,
That(`printf abcd`).Prints("abcd"),
That(`printf "%s\n%s\n" abc xyz`).Prints("abc\nxyz\n"),
That(`printf "%q" "abc xyz"`).Prints(`'abc xyz'`),
That(`printf "%q" ['a b']`).Prints(`['a b']`),
That(`printf "%v" abc`).Prints("abc"),
That(`printf "%#v" "abc xyz"`).Prints(`'abc xyz'`),
That(`printf '%5.3s' 3.1415`).Prints(" 3.1"),
That(`printf '%5.3s' (float64 3.1415)`).Prints(" 3.1"),
That(`printf '%t' $true`).Prints("true"),
That(`printf '%t' $nil`).Prints("false"),
That(`printf '%3d' (num 5)`).Prints(" 5"),
That(`printf '%3d' 5`).Prints(" 5"),
That(`printf '%08b' (num 5)`).Prints("00000101"),
That(`printf '%08b' 5`).Prints("00000101"),
That(`printf '%.1f' 3.1415`).Prints("3.1"),
That(`printf '%.1f' (float64 3.1415)`).Prints("3.1"),
// Does not interpret escape sequences
That(`printf '%s\n%s\n' abc xyz`).Prints("abc\\nxyz\\n"),
// Error cases
// Float verb with argument that can't be converted to float
That(`printf '%f' 1.3x`).Prints("%!f(cannot parse as number: 1.3x)"),
// Integer verb with argument that can't be converted to integer
That(`printf '%d' 3.5`).Prints("%!d(cannot parse as integer: 3.5)"),
// Unsupported verb
That(`printf '%A' foo`).Prints("%!A(unsupported formatting verb)"),
thatOutputErrorIsBubbled("printf foo"),
)
}
func thatOutputErrorIsBubbled(code string) Case {
return That(code + " >&-").Throws(OneOfErrors(os.ErrInvalid, eval.ErrNoValueOutput))
}