Make errors a little nicer

This commit is contained in:
Brandon Dyck 2022-11-24 21:51:44 -07:00
parent 2bd8d9a5de
commit 9fbb3ab637
2 changed files with 92 additions and 42 deletions

109
ph7.go
View File

@ -16,98 +16,125 @@ import (
"fmt" "fmt"
) )
type ResultCode int
const (
ResultCodeOK = ResultCode(C.PH7_OK)
ResultCodeNoMem = ResultCode(C.PH7_NOMEM)
ResultCodeAbort = ResultCode(C.PH7_ABORT)
ResultCodeIOErr = ResultCode(C.PH7_IO_ERR)
ResultCodeLooked = ResultCode(C.PH7_LOOKED)
ResultCodeCorrupt = ResultCode(C.PH7_CORRUPT)
ResultCodeCompileErr = ResultCode(C.PH7_COMPILE_ERR)
ResultCodeVMErr = ResultCode(C.PH7_VM_ERR)
)
func (r ResultCode) String() string {
switch r {
case ResultCodeOK:
return "PH7_OK"
case ResultCodeNoMem:
return "PH7_NOMEM"
case ResultCodeAbort:
return "PH7_ABORT"
case ResultCodeIOErr:
return "PH7_IO_ERR"
case ResultCodeLooked:
return "PH7_LOOKED"
case ResultCodeCorrupt:
return "PH7_CORRUPT"
case ResultCodeCompileErr:
return "PH7_COMPILE_ERR"
case ResultCodeVMErr:
return "PH7_VM_ERR"
default:
return "UNKNOWN"
}
}
type Error struct { type Error struct {
Value int Code ResultCode
}
func newError(code C.int) error {
if code != C.PH7_OK {
return Error{
Code: ResultCode(code),
}
}
return nil
} }
func (e Error) Error() string { func (e Error) Error() string {
return fmt.Sprintf("ph7 error: %d", e.Value) return fmt.Sprintf("ph7: %s", e.Code)
}
func newError(value C.int) Error {
return Error{
Value: int(value),
}
} }
type Engine struct { type Engine struct {
ptr *C.ph7 ptr *C.ph7
} }
func NewEngine() (*Engine, error) { func NewEngine() (Engine, error) {
engine := new(Engine) var engine Engine
result := C.ph7_init(&engine.ptr) result := C.ph7_init(&engine.ptr)
if result != C.PH7_OK { if result != C.PH7_OK {
return nil, newError(result) return Engine{}, newError(result)
} }
return engine, nil return engine, nil
} }
func (e *Engine) ExtractErrLog() (string, error) { func (e Engine) ErrLog() (string, error) {
var s *C.char var s *C.char
var n C.int var n C.int
result := C.engine_config_err_log(e.ptr, &s, &n) err := newError(C.engine_config_err_log(e.ptr, &s, &n))
if result != C.PH7_OK { if err != nil {
return "", newError(result) return "", err
} }
return C.GoStringN(s, n), nil return C.GoStringN(s, n), nil
} }
func (e *Engine) Compile(source []byte, phpOnly bool) (*VM, error) { func (e Engine) Compile(source []byte, phpOnly bool) (*VM, error) {
csource := C.CBytes(source) csource := C.CBytes(source)
vm := new(VM) vm := new(VM)
var flags C.int var flags C.int
if phpOnly { if phpOnly {
flags |= C.PH7_PHP_ONLY flags |= C.PH7_PHP_ONLY
} }
result := C.ph7_compile_v2(e.ptr, (*C.char)(csource), C.int(len(source)), &vm.ptr, flags) err := newError(C.ph7_compile_v2(e.ptr, (*C.char)(csource), C.int(len(source)), &vm.ptr, flags))
if result != C.PH7_OK { if err != nil {
return nil, newError(result) return nil, err
} }
// TODO free csource // TODO free csource
return vm, nil return vm, nil
} }
func (e *Engine) Close() error { func (e Engine) Close() error {
result := C.ph7_release(e.ptr) return newError(C.ph7_release(e.ptr))
if result != C.PH7_OK {
return newError(result)
}
return nil
} }
type VM struct { type VM struct {
ptr *C.ph7_vm ptr *C.ph7_vm
} }
func (vm *VM) ExtractOutput() (string, error) { func (vm VM) ExtractOutput() (string, error) {
var s *C.char var s *C.char
var n C.int var n C.int
result := C.vm_extract_output(vm.ptr, &s, &n) err := newError(C.vm_extract_output(vm.ptr, &s, &n))
if result != C.PH7_OK { if err != nil {
return "", newError(result) return "", err
} }
return C.GoStringN(s, n), nil return C.GoStringN(s, n), nil
} }
func (v *VM) Exec() error { func (v VM) Exec() error {
result := C.ph7_vm_exec(v.ptr, (*C.int)(nil)) return newError(C.ph7_vm_exec(v.ptr, (*C.int)(nil)))
if result != C.PH7_OK {
return newError(result)
}
return nil
} }
func (v *VM) Close() error { func (v VM) Close() error {
result := C.ph7_vm_release(v.ptr) return newError(C.ph7_vm_release(v.ptr))
if result != C.PH7_OK {
return newError(result)
}
return nil
} }

View File

@ -7,19 +7,28 @@ import (
) )
func mustSucceed(t *testing.T, err error) { func mustSucceed(t *testing.T, err error) {
t.Helper()
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
} }
func mustFail(t *testing.T, err error) {
t.Helper()
if err == nil {
t.Fatal("expected error, got nil")
}
}
func mustSucceedF(t *testing.T, f func() error) { func mustSucceedF(t *testing.T, f func() error) {
t.Helper()
err := f() err := f()
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
} }
func TestDoStuff(t *testing.T) { func TestHelloWorld(t *testing.T) {
engine, err := ph7.NewEngine() engine, err := ph7.NewEngine()
mustSucceed(t, err) mustSucceed(t, err)
defer mustSucceedF(t, engine.Close) defer mustSucceedF(t, engine.Close)
@ -36,3 +45,17 @@ func TestDoStuff(t *testing.T) {
t.Fatalf("unexpected output: %s", output) t.Fatalf("unexpected output: %s", output)
} }
} }
func TestCompileError(t *testing.T) {
engine, err := ph7.NewEngine()
mustSucceed(t, err)
defer mustSucceedF(t, engine.Close)
_, err = engine.Compile([]byte("<?php 1234 echo 'Hello world!'; ?>"), false)
mustFail(t, err)
msg, err := engine.ErrLog()
mustSucceed(t, err)
if msg == "" {
t.Fatalf("expected error message, got nothing")
}
}