elvish/pkg/eval/exception_test.go
Qi Xiao b77a052e7e pkg/eval: Make Exception an interface.
This change is a preparation step for refining all *Op types to return Exception
as the error.

Keeping Exception as a struct type will make such a change error-prone, since
a (*Exception)(nil) != error(nil), so if an *Op returns a nil *Exception, it
is not nil if the return value is stored in an error-typed variable.
2021-01-08 00:56:45 +00:00

92 lines
2.2 KiB
Go

package eval_test
import (
"errors"
"reflect"
"runtime"
"testing"
"unsafe"
"github.com/elves/elvish/pkg/diag"
. "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/tt"
"github.com/xiaq/persistent/hash"
)
func TestReason(t *testing.T) {
err := errors.New("ordinary error")
tt.Test(t, tt.Fn("Reason", Reason), tt.Table{
tt.Args(err).Rets(err),
tt.Args(makeException(err)).Rets(err),
})
}
func TestException(t *testing.T) {
err := FailError{"error"}
exc := makeException(err)
vals.TestValue(t, exc).
Kind("exception").
Bool(false).
Hash(hash.Pointer(unsafe.Pointer(reflect.ValueOf(exc).Pointer()))).
Equal(exc).
NotEqual(makeException(errors.New("error"))).
AllKeys("reason").
Index("reason", err).
IndexError("stack", vals.NoSuchKey("stack")).
Repr("[&reason=[&content=error &type=fail]]")
vals.TestValue(t, OK).
Kind("exception").
Bool(true).
Repr("$ok")
}
func makeException(cause error, entries ...*diag.Context) Exception {
return NewException(cause, MakeStackTrace(entries...))
}
func TestFlow_Fields(t *testing.T) {
Test(t,
That("put ?(return)[reason][type name]").Puts("flow", "return"),
)
}
func TestExternalCmdExit_Fields(t *testing.T) {
badCmd := "false"
if runtime.GOOS == "windows" {
badCmd = "cmd /c exit 1"
}
Test(t,
That("put ?("+badCmd+")[reason][type exit-status]").
Puts("external-cmd/exited", "1"),
// TODO: Test killed and stopped commands
)
}
func TestPipelineError_Fields(t *testing.T) {
Test(t,
That("put ?(fail 1 | fail 2)[reason][type]").Puts("pipeline"),
That("count ?(fail 1 | fail 2)[reason][exceptions]").Puts("2"),
That("put ?(fail 1 | fail 2)[reason][exceptions][0][reason][type]").
Puts("fail"),
)
}
func TestErrorMethods(t *testing.T) {
tt.Test(t, tt.Fn("Error", error.Error), tt.Table{
tt.Args(makeException(errors.New("err"))).Rets("err"),
tt.Args(MakePipelineError([]Exception{
makeException(errors.New("err1")),
makeException(errors.New("err2"))})).Rets("(err1 | err2)"),
tt.Args(Return).Rets("return"),
tt.Args(Break).Rets("break"),
tt.Args(Continue).Rets("continue"),
tt.Args(Flow(1000)).Rets("!(BAD FLOW: 1000)"),
})
}