You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2015/10/31 23:22:17 UTC

[02/14] lucy git commit: Custom Go bindings for InStream/OutStream.

Custom Go bindings for InStream/OutStream.


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/dee4ee87
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/dee4ee87
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/dee4ee87

Branch: refs/heads/master
Commit: dee4ee870694e7c33e89f0ecbc481730af291b5a
Parents: 0b2ceea
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Thu Oct 8 18:20:30 2015 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Mon Oct 19 18:07:33 2015 -0700

----------------------------------------------------------------------
 go/build.go           |  37 ++++++
 go/lucy/store.go      | 301 +++++++++++++++++++++++++++++++++++++++++++++
 go/lucy/store_test.go | 254 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 592 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/dee4ee87/go/build.go
----------------------------------------------------------------------
diff --git a/go/build.go b/go/build.go
index 4ec7a72..0a03d90 100644
--- a/go/build.go
+++ b/go/build.go
@@ -215,6 +215,43 @@ func specClasses(parcel *cfc.Parcel) {
 	sortCollBinding := cfc.NewGoClass(parcel, "Lucy::Search::Collector::SortCollector")
 	sortCollBinding.SpecMethod("Pop_Match_Docs", "PopMatchDocs() []MatchDoc")
 	sortCollBinding.Register()
+
+	inStreamBinding := cfc.NewGoClass(parcel, "Lucy::Store::InStream")
+	inStreamBinding.SpecMethod("Reopen", "Reopen(string, int64, int64) (InStream, error)")
+	inStreamBinding.SpecMethod("Close", "Close() error")
+	inStreamBinding.SpecMethod("Seek", "Seek(int64) error")
+	inStreamBinding.SpecMethod("", "ReadBytes([]byte, int) error")
+	inStreamBinding.SpecMethod("", "ReadString() (string, error)")
+	inStreamBinding.SpecMethod("Read_I8", "ReadI8() (int8, error)")
+	inStreamBinding.SpecMethod("Read_I32", "ReadI32() (int32, error)")
+	inStreamBinding.SpecMethod("Read_I64", "ReadI64() (int64, error)")
+	inStreamBinding.SpecMethod("Read_U8", "ReadU8() (uint8, error)")
+	inStreamBinding.SpecMethod("Read_U32", "ReadU32() (uint32, error)")
+	inStreamBinding.SpecMethod("Read_U64", "ReadU64() (uint64, error)")
+	inStreamBinding.SpecMethod("Read_C32", "ReadC32() (uint32, error)")
+	inStreamBinding.SpecMethod("Read_C64", "ReadC64() (uint64, error)")
+	inStreamBinding.SpecMethod("Read_F32", "ReadF32() (float32, error)")
+	inStreamBinding.SpecMethod("Read_F64", "ReadF64() (float64, error)")
+	inStreamBinding.Register()
+
+	outStreamBinding := cfc.NewGoClass(parcel, "Lucy::Store::OutStream")
+	outStreamBinding.SpecMethod("Close", "Close() error")
+	outStreamBinding.SpecMethod("Grow", "Grow(int64) error")
+	outStreamBinding.SpecMethod("Align", "Align(int64) error")
+	outStreamBinding.SpecMethod("", "WriteBytes([]byte, int) error")
+	outStreamBinding.SpecMethod("", "WriteString(string) error")
+	outStreamBinding.SpecMethod("Write_I8", "WriteI8(int8) error")
+	outStreamBinding.SpecMethod("Write_I32", "WriteI32(int32) error")
+	outStreamBinding.SpecMethod("Write_I64", "WriteI64(int64) error")
+	outStreamBinding.SpecMethod("Write_U8", "WriteU8(uint8) error")
+	outStreamBinding.SpecMethod("Write_U32", "WriteU32(uint32) error")
+	outStreamBinding.SpecMethod("Write_U64", "WriteU64(uint64) error")
+	outStreamBinding.SpecMethod("Write_C32", "WriteC32(uint32) error")
+	outStreamBinding.SpecMethod("Write_C64", "WriteC64(uint64) error")
+	outStreamBinding.SpecMethod("Write_F32", "WriteF32(float32) error")
+	outStreamBinding.SpecMethod("Write_F64", "WriteF64(float64) error")
+	outStreamBinding.SpecMethod("Absorb", "Absorb(InStream) error")
+	outStreamBinding.Register()
 }
 
 func build() {

http://git-wip-us.apache.org/repos/asf/lucy/blob/dee4ee87/go/lucy/store.go
----------------------------------------------------------------------
diff --git a/go/lucy/store.go b/go/lucy/store.go
index 9e81d3b..503327e 100644
--- a/go/lucy/store.go
+++ b/go/lucy/store.go
@@ -17,10 +17,17 @@
 package lucy
 
 /*
+#include <stdlib.h>
+
 #include "Lucy/Store/Lock.h"
+#include "Lucy/Store/InStream.h"
+#include "Lucy/Store/OutStream.h"
+
+#include "Clownfish/Err.h"
 */
 import "C"
 import "unsafe"
+import "fmt"
 
 import "git-wip-us.apache.org/repos/asf/lucy-clownfish.git/runtime/go/clownfish"
 
@@ -28,3 +35,297 @@ func (e *LockErrIMP) Error() string {
 	self := ((*C.lucy_LockErr)(unsafe.Pointer(e.TOPTR())))
 	return clownfish.CFStringToGo(unsafe.Pointer(C.LUCY_LockErr_Get_Mess(self)))
 }
+
+func OpenInStream(file interface{}) (in InStream, err error) {
+	err = clownfish.TrapErr(func() {
+		fileC := (*C.cfish_Obj)(clownfish.GoToClownfish(file, unsafe.Pointer(C.CFISH_OBJ), false))
+		defer C.cfish_decref(unsafe.Pointer(fileC))
+		cfObj := C.lucy_InStream_open(fileC)
+		if cfObj == nil {
+			cfErr := C.cfish_Err_get_error();
+
+			panic(clownfish.WRAPAny(unsafe.Pointer(C.cfish_incref(unsafe.Pointer(cfErr)))).(error))
+		}
+		in = WRAPInStream(unsafe.Pointer(cfObj))
+	})
+	return in, err
+}
+
+func (in *InStreamIMP) Reopen(fileName string, offset int64, length int64) (InStream, error) {
+	var retval InStream
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		fileNameCF := (*C.cfish_String)(clownfish.GoToClownfish(fileName, unsafe.Pointer(C.CFISH_STRING), true))
+		defer C.cfish_decref(unsafe.Pointer(fileNameCF))
+		retvalCF := C.LUCY_InStream_Reopen(self, fileNameCF,
+			C.int64_t(offset), C.int64_t(length))
+		retval = WRAPInStream(unsafe.Pointer(retvalCF))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) Close() error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		C.LUCY_InStream_Close(self)
+	})
+}
+
+func (in *InStreamIMP) Seek(target int64) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		C.LUCY_InStream_Seek(self, C.int64_t(target))
+	})
+}
+
+func (in *InStreamIMP) ReadString() (string, error) {
+	var retval string
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		size := C.size_t(C.LUCY_InStream_Read_C32(self))
+		buf := (*C.char)(C.malloc(size))
+		defer C.free(unsafe.Pointer(buf))
+		C.LUCY_InStream_Read_Bytes(self, buf, size)
+		retval = C.GoStringN(buf, C.int(size))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadBytes(b []byte, size int) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		buf := (*C.char)(C.malloc(C.size_t(size)))
+		defer C.free(unsafe.Pointer(buf))
+		C.LUCY_InStream_Read_Bytes(self, buf, C.size_t(size))
+		dupe := []byte(C.GoStringN(buf, C.int(size)))
+		for i := 0; i < size; i++ {
+			b[i] = dupe[i]
+		}
+	})
+}
+
+func (in *InStreamIMP) ReadI8() (int8, error) {
+	var retval int8
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = int8(C.LUCY_InStream_Read_I8(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadI32() (int32, error) {
+	var retval int32
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = int32(C.LUCY_InStream_Read_I32(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadI64() (int64, error) {
+	var retval int64
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = int64(C.LUCY_InStream_Read_I64(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadU8() (uint8, error) {
+	var retval uint8
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = uint8(C.LUCY_InStream_Read_U8(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadU32() (uint32, error) {
+	var retval uint32
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = uint32(C.LUCY_InStream_Read_U32(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadU64() (uint64, error) {
+	var retval uint64
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = uint64(C.LUCY_InStream_Read_U64(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadC32() (uint32, error) {
+	var retval uint32
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = uint32(C.LUCY_InStream_Read_C32(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadC64() (uint64, error) {
+	var retval uint64
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = uint64(C.LUCY_InStream_Read_C64(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadF32() (float32, error) {
+	var retval float32
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = float32(C.LUCY_InStream_Read_F32(self))
+	})
+	return retval, err
+}
+
+func (in *InStreamIMP) ReadF64() (float64, error) {
+	var retval float64
+	err := clownfish.TrapErr(func() {
+		self := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		retval = float64(C.LUCY_InStream_Read_F64(self))
+	})
+	return retval, err
+}
+
+func OpenOutStream(file interface{}) (out OutStream, err error) {
+	err = clownfish.TrapErr(func() {
+		fileC := (*C.cfish_Obj)(clownfish.GoToClownfish(file, unsafe.Pointer(C.CFISH_OBJ), false))
+		defer C.cfish_decref(unsafe.Pointer(fileC))
+		cfObj := C.lucy_OutStream_open(fileC)
+		if cfObj == nil {
+			cfErr := C.cfish_Err_get_error();
+			panic(clownfish.WRAPAny(unsafe.Pointer(C.cfish_incref(unsafe.Pointer(cfErr)))).(error))
+		}
+		out = WRAPOutStream(unsafe.Pointer(cfObj))
+	})
+	return out, err
+}
+
+func (out *OutStreamIMP) Close() error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Close(self)
+	})
+}
+
+func (out *OutStreamIMP) Grow(length int64) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Grow(self, C.int64_t(length))
+	})
+}
+
+func (out *OutStreamIMP) Align(modulus int64) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Align(self, C.int64_t(modulus))
+	})
+}
+
+func (out *OutStreamIMP) WriteBytes(content []byte, size int) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		if size > len(content) {
+			panic(clownfish.NewErr(fmt.Sprintf("Buf only %d long, can't write %d bytes",
+				len(content), size)))
+		}
+		octets := C.CString(string(content))
+		defer C.free(unsafe.Pointer(octets))
+		C.LUCY_OutStream_Write_Bytes(self, unsafe.Pointer(octets), C.size_t(size))
+	})
+}
+
+func (out *OutStreamIMP) WriteString(content string) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		octets := C.CString(content)
+		defer C.free(unsafe.Pointer(octets))
+		size := len(content)
+		C.LUCY_OutStream_Write_String(self, octets, C.size_t(size))
+	})
+}
+
+func (out *OutStreamIMP) WriteI8(value int8) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_I8(self, C.int8_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteI32(value int32) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_I32(self, C.int32_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteI64(value int64) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_I64(self, C.int64_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteU8(value uint8) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_U8(self, C.uint8_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteU32(value uint32) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_U32(self, C.uint32_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteU64(value uint64) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_U64(self, C.uint64_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteC32(value uint32) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_C32(self, C.uint32_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteC64(value uint64) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_C64(self, C.uint64_t(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteF32(value float32) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_F32(self, C.float(value))
+	})
+}
+
+func (out *OutStreamIMP) WriteF64(value float64) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		C.LUCY_OutStream_Write_F64(self, C.double(value))
+	})
+}
+
+func (out *OutStreamIMP) Absorb(in InStream) error {
+	return clownfish.TrapErr(func() {
+		self := (*C.lucy_OutStream)(clownfish.Unwrap(out, "out"))
+		inStreamC := (*C.lucy_InStream)(clownfish.Unwrap(in, "in"))
+		C.LUCY_OutStream_Absorb(self, inStreamC)
+	})
+}

http://git-wip-us.apache.org/repos/asf/lucy/blob/dee4ee87/go/lucy/store_test.go
----------------------------------------------------------------------
diff --git a/go/lucy/store_test.go b/go/lucy/store_test.go
index 640b11f..d37025c 100644
--- a/go/lucy/store_test.go
+++ b/go/lucy/store_test.go
@@ -18,6 +18,7 @@ package lucy
 
 import "testing"
 import "reflect"
+import "os"
 
 import "git-wip-us.apache.org/repos/asf/lucy-clownfish.git/runtime/go/clownfish"
 
@@ -39,3 +40,256 @@ func TestRAMFileBasics(t *testing.T) {
 		t.Errorf("GetContents: %v", got)
 	}
 }
+
+func TestIOStreamOpenClose(t *testing.T) {
+	var outStream OutStream
+	var inStream InStream
+	var err error
+
+	ramFile := NewRAMFile(nil, false)
+	outStream, err = OpenOutStream(ramFile)
+	if err != nil {
+		t.Errorf("OpenOutStream(RAMFile): %s", err)
+	}
+	err = outStream.Close()
+	if err != nil {
+		t.Errorf("OutStream(RAMFile).Close(): %s", err)
+	}
+	inStream, err = OpenInStream(ramFile)
+	if err != nil {
+		t.Errorf("OpenInStream(RAMFile): %s", err)
+	}
+	err = inStream.Close()
+	if err != nil {
+		t.Errorf("InStream(RAMFile).Close(): %s", err)
+	}
+
+	path := "_iostream_open_test"
+	defer os.Remove(path)
+	outStream, err = OpenOutStream(path)
+	if err != nil {
+		t.Errorf("OpenOutStream(string): %s", err)
+	}
+	err = outStream.Close()
+	if err != nil {
+		t.Errorf("OutStream(string).Close(): %s", err)
+	}
+	inStream, err = OpenInStream(path)
+	if err != nil {
+		t.Errorf("OpenInStream(string): %s", err)
+	}
+	err = inStream.Close()
+	if err != nil {
+		t.Errorf("InStream(string).Close(): %s", err)
+	}
+
+	outStream, err = OpenOutStream(42)
+	if err == nil || outStream != nil {
+		t.Errorf("OpenOutStream(number) should fail: %v, %s", outStream, err)
+	}
+	inStream, err = OpenInStream(42)
+	if err == nil || inStream != nil {
+		t.Errorf("OpenInStream(number) should fail: %v, %s", inStream, err)
+	}
+
+	outStream, err = OpenOutStream(nil)
+	if err == nil || outStream != nil {
+		t.Errorf("OpenOutStream(nil) should fail: %v, %s", outStream, err)
+	}
+	inStream, err = OpenInStream(nil)
+	if err == nil || inStream != nil {
+		t.Errorf("OpenInStream(nil) should fail: %v, %s", inStream, err)
+	}
+}
+
+func TestIOStreamDupe(t *testing.T) {
+	var err error
+	file := NewRAMFile(nil, false)
+	outStream, _ := OpenOutStream(file)
+	for i := 0; i < 100; i++ {
+		outStream.WriteU8(uint8(i + 100))
+	}
+	outStream.Close()
+
+	inStream, _ := OpenInStream(file)
+	inStream.Seek(50)
+	if got, err := inStream.ReadU8(); got != 150 || err != nil {
+		t.Errorf("ReadU8: %d, %v", got, err)
+	}
+
+	clone := inStream.Clone().(InStream)
+	if got, err := clone.ReadU8(); got != 151 || err != nil {
+		t.Errorf("Clone had unexpected read: %d, %v", got, err)
+	}
+
+	dupe, err := inStream.Reopen("foo.dat", 99, 1)
+	if fileName := dupe.GetFilename(); fileName != "foo.dat" {
+		t.Errorf("Reopen filename: %s", fileName)
+	}
+	if err != nil {
+		t.Errorf("Bad Reopen: %v", err)
+	}
+	if got, err := dupe.ReadU8(); got != 199 || err != nil {
+		t.Errorf("Reopen had unexpected read: %d, %v", got, err)
+	}
+}
+
+func TestIOStreamFilePos(t *testing.T) {
+	var err error
+	file := NewRAMFile(nil, false)
+	outStream, _ := OpenOutStream(file)
+
+	err = outStream.WriteI32(42)
+	if err != nil {
+		t.Errorf("WriteI32 error: %v", err)
+	}
+	if got := outStream.Tell(); got != 4 {
+		t.Errorf("OutStream.Tell: %d", got)
+	}
+
+	err = outStream.Grow(32)
+	if err != nil {
+		t.Errorf("Grow error: %v", err)
+	}
+	if got := outStream.Length(); got != 4 {
+		t.Errorf("Grow/Length: %d", got)
+	}
+
+	err = outStream.Align(8)
+	if err != nil {
+		t.Errorf("Align error: %v", err)
+	}
+	if got := outStream.Tell(); got != 8 {
+		t.Errorf("Align/Tell: %d", got)
+	}
+
+	outStream.Close()
+	inStream, _ := OpenInStream(file)
+	if got := inStream.Length(); got != 8 {
+		t.Errorf("InStream.Length: %d", got)
+	}
+
+	err = inStream.Seek(4)
+	if err != nil {
+	}
+	if got := inStream.Tell(); got != 4 {
+		t.Errorf("InStream.Tell: %d", got)
+	}
+
+	err = inStream.Seek(30)
+	if err == nil {
+		t.Error("Out of bounds seek should fail")
+	}
+}
+
+func TestIOStreamReadWrite(t *testing.T) {
+	var err error
+	file := NewRAMFile(nil, false)
+	outStream, _ := OpenOutStream(file)
+
+	err = outStream.WriteString("foo")
+	if err != nil {
+		t.Errorf("WriteString error: %v", err)
+	}
+	err = outStream.WriteBytes([]byte("bar"), 3)
+	if err != nil {
+		t.Errorf("WriteBytes error: %v", err)
+	}
+	if err = outStream.WriteI8(42); err != nil {
+		t.Errorf("WriteI8: %s", err)
+	}
+	if err = outStream.WriteI32(42); err != nil {
+		t.Errorf("WriteI32: %s", err)
+	}
+	if err = outStream.WriteI64(42); err != nil {
+		t.Errorf("WriteI64: %s", err)
+	}
+	if err = outStream.WriteU8(42); err != nil {
+		t.Errorf("WriteU8: %s", err)
+	}
+	if err = outStream.WriteU32(42); err != nil {
+		t.Errorf("WriteU32: %s", err)
+	}
+	if err = outStream.WriteU64(42); err != nil {
+		t.Errorf("WriteU64: %s", err)
+	}
+	if err = outStream.WriteC32(42); err != nil {
+		t.Errorf("WriteC32: %s", err)
+	}
+	if err = outStream.WriteC64(42); err != nil {
+		t.Errorf("WriteC64: %s", err)
+	}
+	if err = outStream.WriteF32(1.5); err != nil {
+		t.Errorf("WriteF32: %s", err)
+	}
+	if err = outStream.WriteF64(1.5); err != nil {
+		t.Errorf("WriteF64: %s", err)
+	}
+	barContents := clownfish.NewByteBuf(5)
+	barContents.Cat([]byte{3, 'b', 'a', 'r'})
+	barInStream, _ := OpenInStream(NewRAMFile(barContents, true))
+	if err = outStream.Absorb(barInStream); err != nil {
+		t.Errorf("Aborb: %s", err)
+	}
+
+	outStream.Close()
+	inStream, _ := OpenInStream(file)
+
+	if got, err := inStream.ReadString(); got != "foo" || err != nil {
+		t.Errorf("WriteString/ReadString: %s, %v", got, err)
+	}
+	buf := make([]byte, 3)
+	err = inStream.ReadBytes(buf, 3)
+	if !reflect.DeepEqual(buf, []byte("bar")) || err != nil {
+		t.Errorf("WriteBytes/ReadBytes: %v, %v", buf, err)
+	}
+	if got, err := inStream.ReadI8(); got != 42 || err != nil {
+		t.Errorf("ReadI8: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadI32(); got != 42 || err != nil {
+		t.Errorf("ReadI32: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadI64(); got != 42 || err != nil {
+		t.Errorf("ReadI64: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadU8(); got != 42 || err != nil {
+		t.Errorf("ReadU8: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadU32(); got != 42 || err != nil {
+		t.Errorf("ReadU32: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadU64(); got != 42 || err != nil {
+		t.Errorf("ReadU64: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadC32(); got != 42 || err != nil {
+		t.Errorf("ReadC32: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadC64(); got != 42 || err != nil {
+		t.Errorf("ReadC64: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadF32(); got != 1.5 || err != nil {
+		t.Errorf("ReadF32: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadF64(); got != 1.5 || err != nil {
+		t.Errorf("ReadF64: %d, %s", got, err)
+	}
+	if got, err := inStream.ReadString(); got != "bar" || err != nil {
+		t.Errorf("WriteString/ReadString: %s, %v", got, err)
+	}
+}
+
+func TestIOStreamMisc(t *testing.T) {
+	folder := NewRAMFolder("mydir")
+	outStream := folder.OpenOut("file.dat")
+	if got := outStream.GetPath(); got != "mydir/file.dat" {
+		t.Errorf("GetPath: %s", got)
+	}
+	outStream.WriteU32(1)
+	outStream.Flush()
+	outStream.Close()
+
+	inStream := folder.OpenIn("file.dat")
+	if got := inStream.GetFilename(); got != "mydir/file.dat" {
+		t.Errorf("GetFilename: %s", got)
+	}
+}