Customize and test Go bindings for FileHandle.
Project: http://git-wip-us.apache.org/repos/asf/lucy/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/5bd926fc Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/5bd926fc Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/5bd926fc Branch: refs/heads/master Commit: 5bd926fce657c2c9eb03677001859936db992d22 Parents: 5492483 Author: Marvin Humphrey <[email protected]> Authored: Mon Oct 26 19:02:51 2015 -0700 Committer: Marvin Humphrey <[email protected]> Committed: Mon Oct 26 21:18:38 2015 -0700 ---------------------------------------------------------------------- go/build.go | 9 +++++ go/lucy/store.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++ go/lucy/store_test.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy/blob/5bd926fc/go/build.go ---------------------------------------------------------------------- diff --git a/go/build.go b/go/build.go index d15f5c8..3921e18 100644 --- a/go/build.go +++ b/go/build.go @@ -271,6 +271,15 @@ func specClasses(parcel *cfc.Parcel) { folderBinding.SpecMethod("Local_Open_Dir", "LocalOpenDir() (DirHandle, error)") folderBinding.SpecMethod("Local_MkDir", "LocalMkDir(string) error") folderBinding.Register() + + fhBinding := cfc.NewGoClass(parcel, "Lucy::Store::FileHandle") + fhBinding.SpecMethod("", "Write([]byte, int) error") + fhBinding.SpecMethod("", "Read([]byte, int64, int) error") + fhBinding.SpecMethod("Window", "Window(FileWindow, int64, int64) error") + fhBinding.SpecMethod("Release_Window", "ReleaseWindow(FileWindow) error") + fhBinding.SpecMethod("Grow", "Grow(int64) error") + fhBinding.SpecMethod("Close", "Close() error") + fhBinding.Register() } func build() { http://git-wip-us.apache.org/repos/asf/lucy/blob/5bd926fc/go/lucy/store.go ---------------------------------------------------------------------- diff --git a/go/lucy/store.go b/go/lucy/store.go index da6e1c7..e89fbbe 100644 --- a/go/lucy/store.go +++ b/go/lucy/store.go @@ -23,6 +23,9 @@ package lucy #include "Lucy/Store/Folder.h" #include "Lucy/Store/InStream.h" #include "Lucy/Store/OutStream.h" +#include "Lucy/Store/FileHandle.h" +#include "Lucy/Store/FSFileHandle.h" +#include "Lucy/Store/RAMFileHandle.h" #include "Clownfish/Err.h" */ @@ -545,3 +548,94 @@ func (f *FolderIMP) LocalMkDir(name string) error { } return nil } + +func (fh *FileHandleIMP) Write(data []byte, size int) error { + return clownfish.TrapErr(func() { + self := (*C.lucy_FileHandle)(clownfish.Unwrap(fh, "fh")) + if size > len(data) { + panic(clownfish.NewErr(fmt.Sprintf("Buf only %d long, can't write %d bytes", + len(data), size))) + } + octets := C.CString(string(data)) + defer C.free(unsafe.Pointer(octets)) + C.LUCY_FH_Write(self, unsafe.Pointer(octets), C.size_t(size)) + }) +} + +func (fh *FileHandleIMP) Read(b []byte, offset int64, length int) error { + return clownfish.TrapErr(func() { + self := (*C.lucy_FileHandle)(clownfish.Unwrap(fh, "fh")) + buf := (*C.char)(C.malloc(C.size_t(length))) + defer C.free(unsafe.Pointer(buf)) + C.LUCY_FH_Read(self, buf, C.int64_t(offset), C.size_t(length)) + dupe := []byte(C.GoStringN(buf, C.int(length))) + for i := 0; i < length; i++ { + b[i] = dupe[i] + } + }) +} + +func (fh *FileHandleIMP) Grow(length int64) error { + return clownfish.TrapErr(func() { + self := (*C.lucy_FileHandle)(clownfish.Unwrap(fh, "fh")) + C.LUCY_FH_Grow(self, C.int64_t(length)) + }) +} + +func (fh *FileHandleIMP) Window(window FileWindow, offset, length int64) error { + self := (*C.lucy_FileHandle)(clownfish.Unwrap(fh, "fh")) + windowC := (*C.lucy_FileWindow)(clownfish.Unwrap(window, "window")) + success := C.LUCY_FH_Window(self, windowC, C.int64_t(offset), C.int64_t(length)) + if !success { + cfErr := C.cfish_Err_get_error(); + return clownfish.WRAPAny(unsafe.Pointer(C.cfish_incref(unsafe.Pointer(cfErr)))).(error) + } + return nil +} + +func (fh *FileHandleIMP) ReleaseWindow(window FileWindow) error { + self := (*C.lucy_FileHandle)(clownfish.Unwrap(fh, "fh")) + windowC := (*C.lucy_FileWindow)(clownfish.Unwrap(window, "window")) + success := C.LUCY_FH_Release_Window(self, windowC) + if !success { + cfErr := C.cfish_Err_get_error(); + return clownfish.WRAPAny(unsafe.Pointer(C.cfish_incref(unsafe.Pointer(cfErr)))).(error) + } + return nil +} + +func (fh *FileHandleIMP) Close() error { + return clownfish.TrapErr(func() { + self := (*C.lucy_FileHandle)(clownfish.Unwrap(fh, "fh")) + C.LUCY_FH_Close(self) + }) +} + +func OpenFSFileHandle(path string, flags uint32) (fh FSFileHandle, err error) { + err = clownfish.TrapErr(func() { + pathC := (*C.cfish_String)(clownfish.GoToClownfish(path, unsafe.Pointer(C.CFISH_STRING), false)) + defer C.cfish_decref(unsafe.Pointer(pathC)) + cfObj := C.lucy_FSFH_open(pathC, C.uint32_t(flags)) + if cfObj == nil { + cfErr := C.cfish_Err_get_error(); + panic(clownfish.WRAPAny(unsafe.Pointer(C.cfish_incref(unsafe.Pointer(cfErr)))).(error)) + } + fh = WRAPFSFileHandle(unsafe.Pointer(cfObj)) + }) + return fh, err +} + +func OpenRAMFileHandle(path string, flags uint32, ramFile RAMFile) (fh RAMFileHandle, err error) { + err = clownfish.TrapErr(func() { + pathC := (*C.cfish_String)(clownfish.GoToClownfish(path, unsafe.Pointer(C.CFISH_STRING), false)) + ramFileC := (*C.lucy_RAMFile)(clownfish.GoToClownfish(ramFile, unsafe.Pointer(C.LUCY_RAMFILE), true)) + defer C.cfish_decref(unsafe.Pointer(pathC)) + cfObj := C.lucy_RAMFH_open(pathC, C.uint32_t(flags), ramFileC) + if cfObj == nil { + cfErr := C.cfish_Err_get_error(); + panic(clownfish.WRAPAny(unsafe.Pointer(C.cfish_incref(unsafe.Pointer(cfErr)))).(error)) + } + fh = WRAPRAMFileHandle(unsafe.Pointer(cfObj)) + }) + return fh, err +} http://git-wip-us.apache.org/repos/asf/lucy/blob/5bd926fc/go/lucy/store_test.go ---------------------------------------------------------------------- diff --git a/go/lucy/store_test.go b/go/lucy/store_test.go index c5aa6dd..762141b 100644 --- a/go/lucy/store_test.go +++ b/go/lucy/store_test.go @@ -443,3 +443,97 @@ func TestFSFolderBasics(t *testing.T) { defer os.RemoveAll("_fsfolder_go_test") runFolderTests(t, folder) } + +func TestFileWindowBasics(t *testing.T) { + window := NewFileWindow() + window.SetOffset(30) + if got := window.GetOffset(); got != 30 { + t.Errorf("SetOffset/GetOffset: %d", got) + } + if got := window.GetLen(); got != 0 { + t.Errorf("GetLen: %d", got) + } +} + +func runFileHandleCommonTests(t *testing.T, makeFH func(uint32) FileHandle) { + var err error + fh := makeFH(0x2 | 0x4) // FH_WRITE_ONLY | FH_CREATE + if fh == nil { + t.Errorf("Failed to open FileHandle for write: %v", err) + return + } + fh.SetPath("fake") + if got := fh.GetPath(); got != "fake" { + t.Errorf("SetPath/GetPath: %v", got) + } + err = fh.Grow(20) + if err != nil { + t.Errorf("Grow: %v", err) + } + fh.Write([]byte("hello"), 5) + err = fh.Close() + if err != nil { + t.Errorf("Close: %v", err) + } + + fh = makeFH(0x1) // FH_READ_ONLY + if fh == nil { + t.Errorf("Failed to open FileHandle for read: %v", err) + } + fh.SetPath("fake") + if got := fh.GetPath(); got != "fake" { + t.Errorf("SetPath/GetPath: %v", got) + } + if got := fh.Length(); got != 5 { + t.Errorf("Unexpected Length: %d", got) + } + buf := make([]byte, 3) + fh.Read(buf, 1, 3) + if !reflect.DeepEqual(buf, []byte("ell")) { + t.Errorf("FH read/write: %v", buf) + } + + window := NewFileWindow() + err = fh.Window(window, 1, 2) + if err != nil { + t.Errorf("Window: %v", err) + } + err = fh.Window(window, 1, 2) + if err != nil { + t.Errorf("ReleaseWindow: %v", err) + } + + err = fh.Close() + if err != nil { + t.Errorf("Close: %v", err) + } +} + +func TestRAMFileHandleAll(t *testing.T) { + ramFile := NewRAMFile(nil, false) + makeFH := func(flags uint32) FileHandle { + fh, err := OpenRAMFileHandle("content", flags, ramFile) + if fh == nil || err != nil { + t.Errorf("OpenRAMFileHandle: %v", err) + } + return fh + } + runFileHandleCommonTests(t, makeFH) + fh := makeFH(0x1).(RAMFileHandle) // FH_READ_ONLY + if _, ok := fh.GetFile().(RAMFile); !ok { + t.Errorf("GetFile") + } +} + +func TestFSFileHandleAll(t *testing.T) { + path := "_fsfilehandle_test" + defer os.Remove(path) + makeFH := func(flags uint32) FileHandle { + fh, err := OpenFSFileHandle(path, flags) + if fh == nil || err != nil { + t.Errorf("OpenFSFileHandle: %v", err) + } + return fh + } + runFileHandleCommonTests(t, makeFH) +}
