diff --git a/ph7.go b/ph7.go index b913c03..51bb6b0 100644 --- a/ph7.go +++ b/ph7.go @@ -16,98 +16,125 @@ import ( "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 { - 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 { - return fmt.Sprintf("ph7 error: %d", e.Value) -} - -func newError(value C.int) Error { - return Error{ - Value: int(value), - } + return fmt.Sprintf("ph7: %s", e.Code) } type Engine struct { ptr *C.ph7 } -func NewEngine() (*Engine, error) { - engine := new(Engine) +func NewEngine() (Engine, error) { + var engine Engine result := C.ph7_init(&engine.ptr) if result != C.PH7_OK { - return nil, newError(result) + return Engine{}, newError(result) } return engine, nil } -func (e *Engine) ExtractErrLog() (string, error) { +func (e Engine) ErrLog() (string, error) { var s *C.char var n C.int - result := C.engine_config_err_log(e.ptr, &s, &n) - if result != C.PH7_OK { - return "", newError(result) + err := newError(C.engine_config_err_log(e.ptr, &s, &n)) + if err != nil { + return "", err } 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) vm := new(VM) var flags C.int if phpOnly { flags |= C.PH7_PHP_ONLY } - result := C.ph7_compile_v2(e.ptr, (*C.char)(csource), C.int(len(source)), &vm.ptr, flags) - if result != C.PH7_OK { - return nil, newError(result) + err := newError(C.ph7_compile_v2(e.ptr, (*C.char)(csource), C.int(len(source)), &vm.ptr, flags)) + if err != nil { + return nil, err } // TODO free csource return vm, nil } -func (e *Engine) Close() error { - result := C.ph7_release(e.ptr) - if result != C.PH7_OK { - return newError(result) - } - return nil +func (e Engine) Close() error { + return newError(C.ph7_release(e.ptr)) } type VM struct { ptr *C.ph7_vm } -func (vm *VM) ExtractOutput() (string, error) { +func (vm VM) ExtractOutput() (string, error) { var s *C.char var n C.int - result := C.vm_extract_output(vm.ptr, &s, &n) - if result != C.PH7_OK { - return "", newError(result) + err := newError(C.vm_extract_output(vm.ptr, &s, &n)) + if err != nil { + return "", err } return C.GoStringN(s, n), nil } -func (v *VM) Exec() error { - result := C.ph7_vm_exec(v.ptr, (*C.int)(nil)) - if result != C.PH7_OK { - return newError(result) - } - return nil +func (v VM) Exec() error { + return newError(C.ph7_vm_exec(v.ptr, (*C.int)(nil))) } -func (v *VM) Close() error { - result := C.ph7_vm_release(v.ptr) - if result != C.PH7_OK { - return newError(result) - } - return nil +func (v VM) Close() error { + return newError(C.ph7_vm_release(v.ptr)) } diff --git a/ph7_test.go b/ph7_test.go index 999c3f8..a1fde66 100644 --- a/ph7_test.go +++ b/ph7_test.go @@ -7,19 +7,28 @@ import ( ) func mustSucceed(t *testing.T, err error) { + t.Helper() if err != nil { 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) { + t.Helper() err := f() if err != nil { t.Fatal(err.Error()) } } -func TestDoStuff(t *testing.T) { +func TestHelloWorld(t *testing.T) { engine, err := ph7.NewEngine() mustSucceed(t, err) defer mustSucceedF(t, engine.Close) @@ -36,3 +45,17 @@ func TestDoStuff(t *testing.T) { 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(""), false) + mustFail(t, err) + msg, err := engine.ErrLog() + mustSucceed(t, err) + if msg == "" { + t.Fatalf("expected error message, got nothing") + } +}