THRIFT-582 C(c_glib) implementation of Thrift

Patch: Anatol Pomozov and Michael Lum


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@1027933 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
new file mode 100644
index 0000000..a8889be
--- /dev/null
+++ b/lib/c_glib/test/Makefile.am
@@ -0,0 +1,229 @@
+SUBDIRS =
+
+AM_CPPFLAGS = -g -Wall -I../src $(GLIB_CFLAGS)
+AM_LDFLAGS = $(GLIB_LIBS) $(GOBJECT_LIBS) @GCOV_LDFLAGS@
+
+CFLAGS = @GCOV_CFLAGS@
+CXXFLAGS = -g
+
+check_SCRIPTS = \
+  testwrapper-testtransportsocket \
+  testwrapper-testprotocolbinary \
+  testwrapper-testbufferedtransport \
+  testwrapper-testframedtransport \
+  testwrapper-testmemorybuffer \
+  testwrapper-teststruct \
+  testwrapper-testsimpleserver \
+  testwrapper-testdebugproto \
+  testwrapper-testoptionalrequired \
+  testwrapper-testthrifttest
+
+if WITH_CPP
+  check_SCRIPTS += testwrapper-testthrifttestclient
+endif
+
+check_PROGRAMS = \
+  testtransportsocket \
+  testprotocolbinary \
+  testbufferedtransport \
+  testframedtransport \
+  testmemorybuffer \
+  teststruct \
+  testsimpleserver \
+  testdebugproto \
+  testoptionalrequired \
+  testthrifttest
+
+if WITH_CPP
+  check_PROGRAMS += testthrifttestclient
+endif
+
+testtransportsocket_SOURCES = testtransportsocket.c
+testtransportsocket_LDADD = \
+    ../libthrift_c_glib_la-thrift_transport.o \
+    ../libthrift_c_glib_la-thrift_server_transport.o \
+    ../libthrift_c_glib_la-thrift_server_socket.o
+
+testprotocolbinary_SOURCES = testprotocolbinary.c
+testprotocolbinary_LDADD = \
+    ../libthrift_c_glib_la-thrift_protocol.o \
+    ../libthrift_c_glib_la-thrift_transport.o \
+    ../libthrift_c_glib_la-thrift_socket.o \
+    ../libthrift_c_glib_la-thrift_server_transport.o \
+    ../libthrift_c_glib_la-thrift_server_socket.o
+
+testbufferedtransport_SOURCES = testbufferedtransport.c
+testbufferedtransport_LDADD = \
+    ../libthrift_c_glib_la-thrift_transport.o \
+    ../libthrift_c_glib_la-thrift_socket.o \
+    ../libthrift_c_glib_la-thrift_server_transport.o \
+    ../libthrift_c_glib_la-thrift_server_socket.o
+
+testframedtransport_SOURCES = testframedtransport.c
+testframedtransport_LDADD = \
+    ../libthrift_c_glib_la-thrift_transport.o \
+    ../libthrift_c_glib_la-thrift_socket.o \
+    ../libthrift_c_glib_la-thrift_server_transport.o \
+    ../libthrift_c_glib_la-thrift_server_socket.o
+
+testmemorybuffer_SOURCES = testmemorybuffer.c
+testmemorybuffer_LDADD = \
+    ../libthrift_c_glib_la-thrift_transport.o
+
+teststruct_SOURCES = teststruct.c
+teststruct_LDADD = \
+    ../libthrift_c_glib_la-thrift_protocol.o \
+    ../libthrift_c_glib_la-thrift_transport.o
+
+testsimpleserver_SOURCES = testsimpleserver.c
+testsimpleserver_LDADD = \
+    ../libthrift_c_glib_la-thrift_protocol.o \
+    ../libthrift_c_glib_la-thrift_transport.o \
+    ../libthrift_c_glib_la-thrift_transport_factory.o \
+    ../libthrift_c_glib_la-thrift_processor.o \
+    ../libthrift_c_glib_la-thrift_protocol_factory.o \
+    ../libthrift_c_glib_la-thrift_binary_protocol.o \
+    ../libthrift_c_glib_la-thrift_binary_protocol_factory.o \
+    ../libthrift_c_glib_la-thrift_socket.o \
+    ../libthrift_c_glib_la-thrift_server_transport.o \
+    ../libthrift_c_glib_la-thrift_server_socket.o \
+    ../libthrift_c_glib_la-thrift_server.o
+
+testdebugproto_SOURCES = testdebugproto.c
+testdebugproto_LDADD = libtestgenc.la
+
+testoptionalrequired_SOURCES = testoptionalrequired.c
+testoptionalrequired_LDADD = \
+    ../libthrift_c_glib_la-thrift_protocol.o \
+    ../libthrift_c_glib_la-thrift_transport.o \
+    libtestgenc.la
+
+testthrifttest_SOURCES = testthrifttest.c
+testthrifttest_LDADD = libtestgenc.la
+
+testthrifttestclient_SOURCES = testthrifttestclient.cpp
+testthrifttestclient_CPPFLAGS = -I../../cpp/src $(BOOST_CPPFLAGS) -I./gen-cpp -I../src -I./gen-c_glib $(GLIB_CFLAGS)
+testthrifttestclient_LDADD = ../../cpp/.libs/libthrift.la ../libthrift_c_glib.la libtestgenc.la libtestgencpp.la
+testthrifttestclient_LDFLAGS = -L../.libs -L../../cpp/.libs $(GLIB_LIBS) $(GOBJECT_LIBS)
+
+check_LTLIBRARIES = libtestgenc.la
+
+if WITH_CPP
+  check_LTLIBRARIES += libtestgencpp.la
+endif
+
+libtestgenc_la_SOURCES = \
+        gen-c_glib/t_test_debug_proto_test_types.c \
+        gen-c_glib/t_test_empty_service.c \
+        gen-c_glib/t_test_inherited.c \
+        gen-c_glib/t_test_optional_required_test_types.c \
+        gen-c_glib/t_test_reverse_order_service.c \
+        gen-c_glib/t_test_second_service.c \
+        gen-c_glib/t_test_service_for_exception_with_a_map.c \
+        gen-c_glib/t_test_srv.c \
+        gen-c_glib/t_test_thrift_test.c \
+        gen-c_glib/t_test_thrift_test_types.c \
+        gen-c_glib/t_test_debug_proto_test_types.h \
+        gen-c_glib/t_test_empty_service.h \
+        gen-c_glib/t_test_inherited.h \
+        gen-c_glib/t_test_optional_required_test_types.h \
+        gen-c_glib/t_test_reverse_order_service.h \
+        gen-c_glib/t_test_second_service.h \
+        gen-c_glib/t_test_service_for_exception_with_a_map.h \
+        gen-c_glib/t_test_srv.h \
+        gen-c_glib/t_test_thrift_test.h \
+        gen-c_glib/t_test_thrift_test_types.h
+libtestgenc_la_LIBADD = $(top_builddir)/lib/c_glib/libthrift_c_glib.la
+
+libtestgencpp_la_SOURCES = \
+        gen-cpp/ThriftTest.cpp \
+        gen-cpp/ThriftTest_constants.cpp \
+        gen-cpp/ThriftTest_types.cpp \
+        gen-cpp/ThriftTest.h \
+        gen-cpp/ThriftTest_constants.h \
+        gen-cpp/ThriftTest_types.h
+libtestgencpp_la_CPPFLAGS = -I../../cpp/src $(BOOST_CPPFLAGS) -I./gen-cpp
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+gen-c_glib/t_test_debug_proto_test_types.c gen-c_glib/t_test_debug_proto_test_types.h gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.c gen-c_glib/t_test_inherited.h gen-c_glib/t_test_reverse_order_service.c gen-c_glib/t_test_reverse_order_service.h gen-c_glib/t_test_service_for_exception_with_a_map.c gen-c_glib/t_test_service_for_exception_with_a_map.h gen-c_glib/t_test_srv.c gen-c_glib/t_test_srv.h: ../../../test/DebugProtoTest.thrift
+	$(THRIFT) --gen c_glib $<
+
+gen-c_glib/t_test_optional_required_test_types.c gen-c_glib/t_test_optional_required_test_types.h: ../../../test/OptionalRequiredTest.thrift
+	$(THRIFT) --gen c_glib $<
+
+gen-c_glib/t_test_second_service.c gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test-.h gen-c_glib/t_test_thrift_test_types.h: ../../../test/ThriftTest.thrift
+	$(THRIFT) --gen c_glib $<
+
+gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h: ../../../test/ThriftTest.thrift
+	$(THRIFT) --gen cpp $<
+
+
+TESTS = \
+  $(testwrapper-%) \
+  $(check_PROGRAMS) \
+  $(check_SCRIPTS)
+
+# globally added to all instances of valgrind calls
+# VALGRIND_OPTS = --suppressions=glib.suppress
+VALGRIND_OPTS =
+
+# globally added to all memcheck calls
+VALGRIND_MEM_OPTS = --tool=memcheck \
+                    --num-callers=10 \
+                    ${myextravalgrindmemopts}
+
+# globally added to all leakcheck calls
+VALGRIND_LEAK_OPTS = --tool=memcheck \
+                     --num-callers=10 \
+                     --leak-check=full \
+                     --leak-resolution=high \
+                     ${myextravalgrindleakopts}
+
+memcheck: $(check_PROGRAMS)
+	@for x in $(check_PROGRAMS);                                     \
+	  do                                                             \
+	    $(MAKE) memcheck-$$x;                                        \
+	  done
+
+leakcheck: $(check_PROGRAMS)
+	@for x in $(check_PROGRAMS);                                     \
+	  do                                                             \
+	    $(MAKE) leakcheck-$$x;                                       \
+	done
+
+memcheck-%: %
+	@echo "*****************************************";               \
+	echo "MEMCHECK: $<";                                             \
+	echo "ARGS: ${VALGRIND_OPTS} ${VALGRIND_MEM_OPTS} ${$<_VALGRIND_MEM_OPTS}";                                                                      \
+	$(LIBTOOL) --mode=execute                                        \
+	  valgrind                                                       \
+	    ${VALGRIND_OPTS}                                             \
+	    ${VALGRIND_MEM_OPTS}                                         \
+	    ${$<_VALGRIND_MEM_OPTS} ./$<
+
+leakcheck-%: %
+	@echo "*****************************************";              \
+	echo "LEAKCHECK: $<";                                           \
+	echo "ARGS: ${VALGRIND_OPTS} ${VALGRIND_LEAK_OPTS} ${$<_VALGRIND_LEAK_OPTS}";                                                                   \
+	G_SLICE=always-malloc $(LIBTOOL) --mode=execute                 \
+	  valgrind                                                      \
+	    ${VALGRIND_OPTS}                                            \
+	    ${VALGRIND_LEAK_OPTS}                                       \
+	    ${$<_VALGRIND_LEAK_OPTS}  ./$<
+
+testwrapper-%: % test-wrapper.sh
+	@ln -sf test-wrapper.sh $@
+
+clean-local:
+	$(RM) -r gen-c_glib gen-cpp
+
+CLEANFILES =                            \
+    testwrapper-*                       \
+    *.bb                                \
+    *.bbg                               \
+    *.da                                \
+    *.gcno                              \
+    *.gcda                              \
+    *.gcov                              \
+    test-wrapper.sh
diff --git a/lib/c_glib/test/glib.suppress b/lib/c_glib/test/glib.suppress
new file mode 100644
index 0000000..0e0e9fe
--- /dev/null
+++ b/lib/c_glib/test/glib.suppress
@@ -0,0 +1,64 @@
+{
+   g_type_init_1
+   Memcheck:Leak
+   fun:malloc
+   ...
+   fun:g_type_init_with_debug_flags
+}
+
+{
+   g_type_init_2
+   Memcheck:Leak
+   fun:calloc
+   ...
+   fun:g_type_init_with_debug_flags
+}
+
+{
+   g_type_init_3
+   Memcheck:Leak
+   fun:realloc
+   ...
+   fun:g_type_init_with_debug_flags
+}
+
+{
+   g_type_register_static_1
+   Memcheck:Leak
+   fun:realloc
+   ...
+   fun:g_type_register_static
+}
+
+{
+   g_type_register_statuc_2
+   Memcheck:Leak
+   fun:malloc
+   fun:realloc
+   fun:g_realloc
+   ...
+   fun:g_type_register_static
+}
+
+{
+   type_class_init_Wm1
+   Memcheck:Leak
+   fun:calloc
+   fun:g_malloc0
+   fun:type_class_init_Wm
+   fun:g_type_class_ref
+   ...
+   fun:g_object_newv
+}
+
+{
+   type_class_init_Wm2
+   Memcheck:Leak
+   fun:calloc
+   fun:g_malloc0
+   fun:type_class_init_Wm
+   fun:g_type_class_ref
+   ...
+   fun:type_class_init_Wm
+}
+
diff --git a/lib/c_glib/test/test-wrapper.sh.in b/lib/c_glib/test/test-wrapper.sh.in
new file mode 100644
index 0000000..956b2d1
--- /dev/null
+++ b/lib/c_glib/test/test-wrapper.sh.in
@@ -0,0 +1,58 @@
+# /bin/sh
+
+command="$0"
+
+stripcommand=`echo "$command" | sed 's/testwrapper-//'`
+
+"$stripcommand" "$@" || exit $?
+
+if test "x@ENABLE_COVERAGE@" = "x1"; then
+  # linux: 97.67% of 86 lines executed in file ../src/test123.h
+  # bsd: 100.00% of 196 source lines executed in file testbimap.c
+
+  extrastripcommand=`echo "$stripcommand" | sed 's/\.\///'`
+    ${GCOV:-gcov} "$extrastripcommand" 2>&1                        \
+  | perl -ne 'BEGIN { $file = undef; }
+      next if m!^Creating!;
+      next if m!creating!;
+      next if m!^$!;
+      next if m!not exhausted!;
+      next if m!^Unexpected EOF!;
+      if (m!([\d\.]+)\% of \d+( source)? lines executed in file (.+)!)
+        {
+          do
+            {
+              if ( $3 !~ m#^/# )
+                {
+                  $a = $3 =~ m%([\-\w\.]+)$%;
+                  print STDERR $_;
+                  print "$1.gcov\n";
+                }
+            } if $1 < 110.0;
+        }
+      elsif (m#^File .(.*?).$#)
+        {
+          $file = $1;
+        }
+      elsif (m#Lines executed:([\d\.]+)\% of (\d+)#)
+        {
+          $percent = $1;
+          $lines = $2;
+          do
+            {
+              if ( $file !~ m#^/# )
+                {
+                  $a = $file =~ m%([\-\w\.]+)$%;
+                  print STDERR "$percent% of $lines executed in file $file\n";
+                  print "$1.gcov\n";
+                }
+            } if $percent < 110.0;
+        }
+      else
+        {
+          print
+        }'                 \
+  | xargs grep -n -A2 -B2 '#####.*\w'
+  exit 0
+fi
+
diff --git a/lib/c_glib/test/testbufferedtransport.c b/lib/c_glib/test/testbufferedtransport.c
new file mode 100644
index 0000000..6759509
--- /dev/null
+++ b/lib/c_glib/test/testbufferedtransport.c
@@ -0,0 +1,188 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+#include "../src/transport/thrift_buffered_transport.c"
+
+static const char TEST_ADDRESS[] = "localhost";
+static const short TEST_PORT = 64444;
+
+static void thrift_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+  ThriftTransport *transport = NULL;
+  guint r_buf_size = 0;
+  guint w_buf_size = 0;
+
+  GObject *object = NULL;
+  object = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, NULL);
+  assert (object != NULL);
+  g_object_get (G_OBJECT (object), "transport", &transport,
+                "r_buf_size", &r_buf_size,
+                "w_buf_size", &w_buf_size, NULL);
+  g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  GError *err = NULL;
+
+  /* create a ThriftSocket */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                          "port", 51188, NULL); 
+
+  /* create a BufferedTransport wrapper of the Socket */
+  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+  /* this shouldn't work */
+  assert (thrift_buffered_transport_open (transport, NULL) == FALSE);
+  assert (thrift_buffered_transport_is_open (transport) == TRUE);
+  assert (thrift_buffered_transport_close (transport, NULL) == TRUE);
+  g_object_unref (transport);
+  g_object_unref (tsocket);
+
+  /* try and underlying socket failure */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+                          NULL);
+
+  /* create a BufferedTransport wrapper of the Socket */
+  transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+  assert (thrift_buffered_transport_open (transport, &err) == FALSE);
+  g_object_unref (transport);
+  g_object_unref (tsocket);
+  g_error_free (err);
+  err = NULL;
+}
+
+static void
+test_read_and_write(void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  int port = 51199;
+  guchar buf[10] = TEST_DATA; /* a buffer */
+
+  pid = fork ();
+  assert ( pid >= 0 );
+
+  if ( pid == 0 )
+  {
+    /* child listens */
+    thrift_server (port);
+    exit (0);
+  } else {
+    /* parent connects, wait a bit for the socket to be created */
+    sleep (1);
+
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
+                              "transport", THRIFT_TRANSPORT (tsocket),
+                              "w_buf_size", 4, NULL);
+
+    assert (thrift_buffered_transport_open (transport, NULL) == TRUE);
+    assert (thrift_buffered_transport_is_open (transport));
+
+    /* write 10 bytes */
+    thrift_buffered_transport_write (transport, buf, 10, NULL);
+
+    /* write 1 byte at a time */
+    thrift_buffered_transport_write (transport, buf, 1, NULL);
+    thrift_buffered_transport_write (transport, buf, 1, NULL);
+    thrift_buffered_transport_write (transport, buf, 1, NULL);
+
+    /* overflow the buffer */
+    thrift_buffered_transport_write (transport, buf, 2, NULL);
+    thrift_buffered_transport_write (transport, buf, 1, NULL);
+    thrift_buffered_transport_flush (transport, NULL);
+
+    /* write 1 byte and flush */
+    thrift_buffered_transport_write (transport, buf, 1, NULL);
+    thrift_buffered_transport_flush (transport, NULL);
+
+    /* write and overflow buffer with 2 system calls */
+    thrift_buffered_transport_write (transport, buf, 1, NULL);
+    thrift_buffered_transport_write (transport, buf, 3, NULL);
+
+    /* write 10 bytes */
+    thrift_buffered_transport_write (transport, buf, 10, NULL);
+
+    thrift_buffered_transport_write_end (transport, NULL);
+    thrift_buffered_transport_flush (transport, NULL);
+    thrift_buffered_transport_close (transport, NULL);
+
+    g_object_unref (transport);
+    g_object_unref (tsocket);
+
+    assert ( wait (&status) == pid );
+    assert ( status == 0 );
+  }
+}
+
+static void
+thrift_server (const int port)
+{
+  int bytes = 0;
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  guchar buf[10]; /* a buffer */
+  guchar match[10] = TEST_DATA;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+
+  /* wrap the client in a BufferedTransport */
+  client = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, "transport",
+                         thrift_server_transport_accept (transport, NULL),
+                         "r_buf_size", 5, NULL);
+  assert (client != NULL);
+
+  /* read 10 bytes */
+  bytes = thrift_buffered_transport_read (client, buf, 10, NULL);
+  assert (bytes == 10); /* make sure we've read 10 bytes */
+  assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
+
+  /* read 1 byte */
+  bytes = thrift_buffered_transport_read (client, buf, 1, NULL);
+
+  bytes = thrift_buffered_transport_read (client, buf, 6, NULL);
+  bytes = thrift_buffered_transport_read (client, buf, 2, NULL);
+  bytes = thrift_buffered_transport_read (client, buf, 1, NULL);
+
+  thrift_buffered_transport_read_end (client, NULL);
+  thrift_buffered_transport_close (client, NULL);
+  g_object_unref (client);
+  g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+  g_type_init();
+  test_create_and_destroy();
+  test_open_and_close();
+  test_read_and_write();
+
+  return 0;
+}
+
diff --git a/lib/c_glib/test/testdebugproto.c b/lib/c_glib/test/testdebugproto.c
new file mode 100644
index 0000000..b111e12
--- /dev/null
+++ b/lib/c_glib/test/testdebugproto.c
@@ -0,0 +1,64 @@
+#include <math.h>
+#include <glib-object.h>
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932385
+#endif
+
+#include "gen-c_glib/t_test_debug_proto_test_types.h"
+
+
+int
+main(void)
+{
+  g_type_init ();
+
+  TTestOneOfEach *ooe = NULL;
+  TTestNesting *n = NULL;
+  TTestHolyMoley *hm = NULL;
+
+  ooe = g_object_new (T_TEST_TYPE_ONE_OF_EACH, NULL);
+  ooe->im_true = TRUE;
+  ooe->im_false = FALSE;
+  ooe->a_bite = 0xd6;
+  ooe->integer16 = 27000;
+  ooe->integer32 = 1<<24;
+  ooe->integer64 = (guint64) 6000 * 1000 * 1000;
+  ooe->double_precision = M_PI;
+  ooe->some_characters = "Debug THIS!";
+  ooe->zomg_unicode = "\xd7\n\a\t";
+
+  n = g_object_new (T_TEST_TYPE_NESTING, NULL);
+  n->my_ooe = ooe;
+  n->my_ooe->integer16 = 16;
+  n->my_ooe->integer32 = 32;
+  n->my_ooe->integer64 = 64;
+  n->my_ooe->double_precision = (sqrt(5.0) + 1) / 2;
+  n->my_ooe->some_characters = ":R (me going \"rrrr\")";
+  n->my_ooe->zomg_unicode = "\xd3\x80\xe2\x85\xae\xce\x9d\x20";
+  n->my_bonk->type = 31337;
+  n->my_bonk->message = "I am a bonk... xor!";
+
+  hm = g_object_new (T_TEST_TYPE_HOLY_MOLEY, NULL);
+  g_ptr_array_add (hm->big, ooe);
+  g_ptr_array_add (hm->big, n->my_ooe);
+  ((TTestOneOfEach *) g_ptr_array_index (hm->big, 0))->a_bite = 0x22;
+  ((TTestOneOfEach *) g_ptr_array_index (hm->big, 1))->a_bite = 0x33;
+
+  g_hash_table_insert (hm->contain, "random string", "random string");
+
+  TTestBonk *bonk = NULL;
+  bonk = g_object_new (T_TEST_TYPE_BONK, NULL);
+  GPtrArray *bonks = g_ptr_array_new ();
+  g_ptr_array_add (bonks, bonk);
+  g_hash_table_insert (hm->bonks, "nothing", bonks);
+
+  g_ptr_array_free (bonks, TRUE);
+  g_object_unref (bonk);
+  g_object_unref (ooe);
+  g_object_unref (n);
+  g_object_unref (hm);
+
+  return 0;
+}
+
diff --git a/lib/c_glib/test/testframedtransport.c b/lib/c_glib/test/testframedtransport.c
new file mode 100644
index 0000000..23951f7
--- /dev/null
+++ b/lib/c_glib/test/testframedtransport.c
@@ -0,0 +1,176 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+#include "../src/transport/thrift_framed_transport.c"
+
+static const char TEST_ADDRESS[] = "localhost";
+static const short TEST_PORT = 64444;
+
+static void thrift_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+  ThriftTransport *transport = NULL;
+  guint r_buf_size = 0;
+  guint w_buf_size = 0;
+
+  GObject *object = NULL;
+  object = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, NULL);
+  assert (object != NULL);
+  g_object_get (G_OBJECT (object), "transport", &transport,
+                "r_buf_size", &r_buf_size,
+                "w_buf_size", &w_buf_size, NULL);
+  g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  GError *err = NULL;
+
+  /* create a ThriftSocket */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                          "port", 51188, NULL); 
+
+  /* create a BufferedTransport wrapper of the Socket */
+  transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+  /* this shouldn't work */
+  assert (thrift_framed_transport_open (transport, NULL) == FALSE);
+  assert (thrift_framed_transport_is_open (transport) == TRUE);
+  assert (thrift_framed_transport_close (transport, NULL) == TRUE);
+  g_object_unref (transport);
+  g_object_unref (tsocket);
+
+  /* try and underlying socket failure */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+                          NULL);
+
+  /* create a BufferedTransport wrapper of the Socket */
+  transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+                            "transport", THRIFT_TRANSPORT (tsocket), NULL);
+
+  assert (thrift_framed_transport_open (transport, &err) == FALSE);
+  g_object_unref (transport);
+  g_object_unref (tsocket);
+  g_error_free (err);
+  err = NULL;
+}
+
+static void
+test_read_and_write(void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  int port = 51199;
+  guchar buf[10] = TEST_DATA; /* a buffer */
+
+  pid = fork ();
+  assert ( pid >= 0 );
+
+  if ( pid == 0 )
+  {
+    /* child listens */
+    thrift_server (port);
+    exit (0);
+  } else {
+    /* parent connects, wait a bit for the socket to be created */
+    sleep (1);
+
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    transport = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT,
+                              "transport", THRIFT_TRANSPORT (tsocket),
+                              "w_buf_size", 4, NULL);
+
+    assert (thrift_framed_transport_open (transport, NULL) == TRUE);
+    assert (thrift_framed_transport_is_open (transport));
+
+    /* write 10 bytes */
+    thrift_framed_transport_write (transport, buf, 10, NULL);
+    thrift_framed_transport_flush (transport, NULL);
+
+    thrift_framed_transport_write (transport, buf, 1, NULL);
+    thrift_framed_transport_flush (transport, NULL);
+
+    thrift_framed_transport_write (transport, buf, 10, NULL);
+    thrift_framed_transport_flush (transport, NULL);
+
+    thrift_framed_transport_write (transport, buf, 10, NULL);
+    thrift_framed_transport_flush (transport, NULL);
+
+    thrift_framed_transport_write_end (transport, NULL);
+    thrift_framed_transport_flush (transport, NULL);
+    thrift_framed_transport_close (transport, NULL);
+
+    g_object_unref (transport);
+    g_object_unref (tsocket);
+
+    assert ( wait (&status) == pid );
+    assert ( status == 0 );
+  }
+}
+
+static void
+thrift_server (const int port)
+{
+  int bytes = 0;
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  guchar buf[10]; /* a buffer */
+  guchar match[10] = TEST_DATA;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+
+  /* wrap the client in a BufferedTransport */
+  client = g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, "transport",
+                         thrift_server_transport_accept (transport, NULL),
+                         "r_buf_size", 5, NULL);
+  assert (client != NULL);
+
+  /* read 10 bytes */
+  bytes = thrift_framed_transport_read (client, buf, 10, NULL);
+  assert (bytes == 10); /* make sure we've read 10 bytes */
+  assert ( memcmp (buf, match, 10) == 0 ); /* make sure what we got matches */
+
+  bytes = thrift_framed_transport_read (client, buf, 6, NULL);
+  bytes = thrift_framed_transport_read (client, buf, 5, NULL);
+  bytes = thrift_framed_transport_read (client, buf, 1, NULL);
+
+  bytes = thrift_framed_transport_read (client, buf, 12, NULL);
+
+  thrift_framed_transport_read_end (client, NULL);
+  thrift_framed_transport_close (client, NULL);
+  g_object_unref (client);
+  g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+  g_type_init();
+  test_create_and_destroy();
+  test_open_and_close();
+  test_read_and_write();
+
+  return 0;
+}
+
diff --git a/lib/c_glib/test/testmemorybuffer.c b/lib/c_glib/test/testmemorybuffer.c
new file mode 100644
index 0000000..52b18bf
--- /dev/null
+++ b/lib/c_glib/test/testmemorybuffer.c
@@ -0,0 +1,75 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+#include "../src/transport/thrift_memory_buffer.c"
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+  GObject *object = NULL;
+  object = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+  assert (object != NULL);
+  g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+  ThriftMemoryBuffer *tbuffer = NULL;
+
+  /* create a ThriftMemoryBuffer */
+  tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+
+  /* this shouldn't work */
+  assert (thrift_memory_buffer_open (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
+  assert (thrift_memory_buffer_is_open (THRIFT_TRANSPORT (tbuffer)) == TRUE);
+  assert (thrift_memory_buffer_close (THRIFT_TRANSPORT (tbuffer), NULL) == TRUE);
+  g_object_unref (tbuffer);
+}
+
+static void
+test_read_and_write(void)
+{
+  ThriftMemoryBuffer *tbuffer = NULL;
+  guchar buf[10] = TEST_DATA;
+  guchar read[10];
+  GError *error = NULL;
+
+  tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 5, NULL);
+  assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+                                      (gpointer) buf,
+                                      10, &error) == FALSE);
+  assert (error != NULL);
+  g_error_free (error);
+  error = NULL;
+  g_object_unref (tbuffer);
+
+  tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, "buf_size", 15, NULL);
+  assert (thrift_memory_buffer_write (THRIFT_TRANSPORT (tbuffer),
+                                      (gpointer) buf, 10, &error) == TRUE);
+  assert (error == NULL);
+
+  assert (thrift_memory_buffer_read (THRIFT_TRANSPORT (tbuffer),
+                                     &read, 10, &error) > 0);
+  assert (error == NULL);
+}
+
+int
+main(void)
+{
+  g_type_init();
+  test_create_and_destroy();
+  test_open_and_close();
+  test_read_and_write();
+
+  return 0;
+}
+
diff --git a/lib/c_glib/test/testoptionalrequired.c b/lib/c_glib/test/testoptionalrequired.c
new file mode 100644
index 0000000..cf44413
--- /dev/null
+++ b/lib/c_glib/test/testoptionalrequired.c
@@ -0,0 +1,182 @@
+#include <assert.h>
+#include <glib.h>
+
+#include "thrift_struct.h"
+#include "protocol/thrift_protocol.h"
+#include "protocol/thrift_binary_protocol.h"
+#include "transport/thrift_memory_buffer.h"
+#include "gen-c_glib/t_test_optional_required_test_types.h"
+
+#include "gen-c_glib/t_test_optional_required_test_types.c"
+
+static void
+write_to_read (ThriftStruct *w, ThriftStruct *r, GError **write_error,
+               GError **read_error)
+{
+  ThriftMemoryBuffer *tbuffer = NULL;
+  ThriftProtocol *protocol = NULL;
+
+  tbuffer = g_object_new (THRIFT_TYPE_MEMORY_BUFFER, NULL);
+  protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                           tbuffer, NULL);
+
+  thrift_struct_write (w, protocol, write_error);
+  thrift_struct_read (r, protocol, read_error);
+
+  g_object_unref (protocol);
+  g_object_unref (tbuffer);
+}
+
+static void
+test_old_school1 (void)
+{
+  TTestOldSchool *o = NULL;
+
+  o = g_object_new (T_TEST_TYPE_OLD_SCHOOL, NULL);
+  o->im_int = 10;
+  o->im_str = g_strdup ("test");
+  o->im_big = g_ptr_array_new ();
+  g_ptr_array_free (o->im_big, FALSE);
+  g_free (o->im_str);
+  g_object_unref (o);
+}
+
+/**
+ * Write to read with optional fields
+ */
+static void
+test_simple (void)
+{
+  TTestSimple *s1 = NULL, *s2 = NULL, *s3 = NULL;
+
+  s1 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
+  s2 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
+  s3 = g_object_new (T_TEST_TYPE_SIMPLE, NULL);
+
+  // write-to-read with optional fields
+  s1->im_optional = 10;
+  assert (s1->__isset_im_default == FALSE);
+  assert (s1->__isset_im_optional == FALSE);  
+  write_to_read (THRIFT_STRUCT (s1), THRIFT_STRUCT (s2), NULL, NULL);
+  assert (s2->__isset_im_default = TRUE);
+  assert (s2->__isset_im_optional == FALSE);
+  assert (s2->im_optional == 0);
+
+  s1->__isset_im_optional = TRUE;
+  write_to_read (THRIFT_STRUCT (s1), THRIFT_STRUCT (s3), NULL, NULL);
+  assert (s3->__isset_im_default == TRUE);
+  assert (s3->__isset_im_optional == TRUE);
+  assert (s3->im_optional == 10);
+
+  g_object_unref (s1);
+  g_object_unref (s2);
+}
+
+/**
+ * Writing between optional and default
+ */
+static void
+test_tricky1 (void)
+{
+  TTestTricky1 *t1 = NULL;
+  TTestTricky2 *t2 = NULL;
+
+  t1 = g_object_new (T_TEST_TYPE_TRICKY1, NULL);
+  t2 = g_object_new (T_TEST_TYPE_TRICKY2, NULL);
+
+  t2->im_optional = 10;
+  write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t1), NULL, NULL);
+  write_to_read (THRIFT_STRUCT (t1), THRIFT_STRUCT (t2), NULL, NULL);
+
+  assert (t1->__isset_im_default == FALSE);
+  assert (t2->__isset_im_optional == TRUE);
+  assert (t1->im_default == t2->im_optional);
+  assert (t1->im_default == 0);
+
+  g_object_unref (t1);
+  g_object_unref (t2);
+}
+
+/**
+ * Writing between default and required.
+ */
+static void
+test_tricky2 (void)
+{
+  TTestTricky1 *t1 = NULL;
+  TTestTricky3 *t3 = NULL;
+
+  t1 = g_object_new (T_TEST_TYPE_TRICKY1, NULL);
+  t3 = g_object_new (T_TEST_TYPE_TRICKY3, NULL);
+
+  write_to_read (THRIFT_STRUCT (t1), THRIFT_STRUCT (t3), NULL, NULL);
+  write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t1), NULL, NULL);
+
+  assert (t1->__isset_im_default == TRUE);
+
+  g_object_unref (t1);
+  g_object_unref (t3);
+}
+
+/**
+ * Writing between optional and required.
+ */
+static void
+test_tricky3 (void)
+{
+  TTestTricky2 *t2 = NULL;
+  TTestTricky3 *t3 = NULL;
+
+  t2 = g_object_new (T_TEST_TYPE_TRICKY2, NULL);
+  t3 = g_object_new (T_TEST_TYPE_TRICKY3, NULL);
+
+  t2->__isset_im_optional = TRUE;
+
+  write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t3), NULL, NULL);
+  write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t2), NULL, NULL);
+
+  g_object_unref (t2);
+  g_object_unref (t3);
+}
+
+/**
+ * Catch an optional not set exception.  To quote the
+ * C++ test, "Mu-hu-ha-ha-ha!"
+ */
+static void
+test_tricky4 (void)
+{
+  TTestTricky2 *t2 = NULL;
+  TTestTricky3 *t3 = NULL;
+  GError *read_error = NULL;
+
+  t2 = g_object_new (T_TEST_TYPE_TRICKY2, NULL);
+  t3 = g_object_new (T_TEST_TYPE_TRICKY3, NULL);
+
+  // throws protocol exception
+  write_to_read (THRIFT_STRUCT (t2), THRIFT_STRUCT (t3), NULL, &read_error);
+  assert (read_error != NULL);
+  g_error_free (read_error);
+
+  write_to_read (THRIFT_STRUCT (t3), THRIFT_STRUCT (t2), NULL, NULL);
+
+  assert (t2->__isset_im_optional);
+
+  g_object_unref (t2);
+  g_object_unref (t3);
+}
+
+int
+main(void)
+{
+  g_type_init ();
+  test_old_school1 ();
+  test_simple ();
+  test_tricky1 ();
+  test_tricky2 ();
+  test_tricky3 ();
+  test_tricky4 ();
+  return 0;
+}
+
+
diff --git a/lib/c_glib/test/testprotocolbinary.c b/lib/c_glib/test/testprotocolbinary.c
new file mode 100644
index 0000000..c8a54b9
--- /dev/null
+++ b/lib/c_glib/test/testprotocolbinary.c
@@ -0,0 +1,652 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "protocol/thrift_protocol.h"
+#include "transport/thrift_socket.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_BOOL TRUE
+#define TEST_BYTE 123
+#define TEST_I16 12345
+#define TEST_I32 1234567890
+#define TEST_I64 123456789012345LL
+#define TEST_DOUBLE 1234567890.123
+#define TEST_STRING "this is a test string 1234567890!@#$%^&*()"
+#define TEST_PORT 51199
+
+static int transport_read_count = 0;
+static int transport_read_error = 0;
+static int transport_read_error_at = -1;
+gint32
+my_thrift_transport_read (ThriftTransport *transport, gpointer buf,
+                          guint32 len, GError **error)
+{
+  if (transport_read_count != transport_read_error_at
+      && transport_read_error == 0)
+  {
+    transport_read_count++;
+    return thrift_transport_read (transport, buf, len, error);
+  }
+  return -1;
+}
+
+static int transport_write_count = 0;
+static int transport_write_error = 0;
+static int transport_write_error_at = -1;
+gboolean
+my_thrift_transport_write (ThriftTransport *transport, const gpointer buf,
+                           const guint32 len, GError **error)
+{
+  if (transport_write_count != transport_write_error_at
+      && transport_write_error == 0)
+  {
+    transport_write_count++;
+    return thrift_transport_write (transport, buf, len, error);
+  }
+  return FALSE;
+}
+
+#define thrift_transport_read my_thrift_transport_read
+#define thrift_transport_write my_thrift_transport_write
+#include "../src/protocol/thrift_binary_protocol.c"
+#undef thrift_transport_read
+#undef thrift_transport_write
+
+static void thrift_server_primitives (const int port);
+static void thrift_server_complex_types (const int port);
+
+static void
+test_create_and_destroy(void)
+{
+  GObject *object = NULL;
+
+  /* create an object and then destroy it */
+  object = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, NULL);
+  assert (object != NULL);
+  g_object_unref (object);
+}
+
+static void
+test_initialize(void)
+{
+  ThriftSocket *tsocket = NULL;
+  ThriftBinaryProtocol *protocol = NULL;
+  ThriftSocket *temp = NULL;
+
+  /* create a ThriftTransport */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                          "port", 51188, NULL);
+  assert (tsocket != NULL);
+  /* create a ThriftBinaryProtocol using the Transport */
+  protocol = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                           tsocket, NULL);
+  assert (protocol != NULL);
+  /* fetch the properties */
+  g_object_get (G_OBJECT(protocol), "transport", &temp, NULL);
+  g_object_unref (temp);
+
+  /* clean up memory */
+  g_object_unref (protocol);
+  g_object_unref (tsocket);
+}
+
+static void
+test_read_and_write_primitives(void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  ThriftBinaryProtocol *tb = NULL;
+  ThriftProtocol *protocol = NULL;
+  gpointer binary = (gpointer *) TEST_STRING;
+  guint32 len = strlen (TEST_STRING);
+  int port = TEST_PORT;
+
+  /* fork a server from the client */
+  pid = fork ();
+  assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    /* child listens */
+    thrift_server_primitives (port);
+    exit (0);
+  } else {
+    /* parent.  wait a bit for the socket to be created. */
+    sleep (1);
+
+    /* create a ThriftSocket */
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    transport = THRIFT_TRANSPORT (tsocket);
+    thrift_transport_open (transport, NULL);
+    assert (thrift_transport_is_open (transport));
+
+    /* create a ThriftBinaryTransport */
+    tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                       tsocket, NULL);
+    protocol = THRIFT_PROTOCOL (tb);
+    assert (protocol != NULL);
+
+    /* write a bunch of primitives */
+    assert (thrift_binary_protocol_write_bool (protocol, TEST_BOOL, NULL) > 0);
+    assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, NULL) > 0);
+    assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) > 0);
+    assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) > 0);
+    assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) > 0);
+    assert (thrift_binary_protocol_write_double (protocol, 
+                                                 TEST_DOUBLE, NULL) > 0);
+    assert (thrift_binary_protocol_write_string (protocol,
+                                                 TEST_STRING, NULL) > 0);
+    assert (thrift_binary_protocol_write_binary (protocol, binary, 
+                                                 len, NULL) > 0);
+    assert (thrift_binary_protocol_write_binary (protocol, NULL, 0, NULL) > 0);
+    assert (thrift_binary_protocol_write_binary (protocol, binary,
+                                                 len, NULL) > 0);
+
+    /* test write errors */
+    transport_write_error = 1;
+    assert (thrift_binary_protocol_write_byte (protocol, TEST_BYTE, 
+                                               NULL) == -1);
+    assert (thrift_binary_protocol_write_i16 (protocol, TEST_I16, NULL) == -1);
+    assert (thrift_binary_protocol_write_i32 (protocol, TEST_I32, NULL) == -1);
+    assert (thrift_binary_protocol_write_i64 (protocol, TEST_I64, NULL) == -1);
+    assert (thrift_binary_protocol_write_double (protocol, TEST_DOUBLE,
+                                                 NULL) == -1);
+    assert (thrift_binary_protocol_write_binary (protocol, binary, len,
+                                                 NULL) == -1);
+    transport_write_error = 0;
+
+    /* test binary partial failure */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    assert (thrift_binary_protocol_write_binary (protocol, binary,
+                                                 len, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* clean up */
+    thrift_transport_close (transport, NULL);
+    g_object_unref (tsocket);
+    g_object_unref (protocol);
+    assert (wait (&status) == pid);
+    assert (status == 0);
+  }
+}
+
+static void
+test_read_and_write_complex_types (void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  ThriftBinaryProtocol *tb = NULL;
+  ThriftProtocol *protocol = NULL;
+  int port = TEST_PORT;
+
+  /* fork a server from the client */
+  pid = fork ();
+  assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    /* child listens */
+    thrift_server_complex_types (port);
+    exit (0);
+  } else {
+    /* parent.  wait a bit for the socket to be created. */
+    sleep (1);
+
+    /* create a ThriftSocket */
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    transport = THRIFT_TRANSPORT (tsocket);
+    thrift_transport_open (transport, NULL);
+    assert (thrift_transport_is_open (transport));
+
+    /* create a ThriftBinaryTransport */
+    tb = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                       tsocket, NULL);
+    protocol = THRIFT_PROTOCOL (tb);
+    assert (protocol != NULL);
+
+    /* test structures */
+    assert (thrift_binary_protocol_write_struct_begin (protocol, 
+                                                       NULL, NULL) == 0);
+    assert (thrift_binary_protocol_write_struct_end (protocol, NULL) == 0);
+
+    assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
+                                                      1, NULL) > 0);
+    assert (thrift_binary_protocol_write_field_end (protocol, NULL) == 0);
+
+    /* test write error */
+    transport_write_error = 1;
+    assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID, 
+                                                      1, NULL) == -1);
+    transport_write_error = 0;
+
+    /* test 2nd write error */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    assert (thrift_binary_protocol_write_field_begin (protocol, "test", T_VOID,
+                                                      1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* test 2nd read failure on a field */
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+    /* test write_field_stop */
+    assert (thrift_binary_protocol_write_field_stop (protocol, NULL) > 0);
+
+    /* write a map */
+    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+                                                    1, NULL) > 0);
+    assert (thrift_binary_protocol_write_map_end (protocol, NULL) == 0);
+
+    /* test 2nd read failure on a map */
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+    /* test 3rd read failure on a map */
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+    /* test 1st write failure on a map */
+    transport_write_error = 1;
+    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+                                                    1, NULL) == -1);
+    transport_write_error = 0;
+
+    /* test 2nd write failure on a map */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+                                                    1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* test 3rd write failure on a map */
+    transport_write_count = 0;
+    transport_write_error_at = 2;
+    assert (thrift_binary_protocol_write_map_begin (protocol, T_VOID, T_VOID,
+                                                    1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* test negative map size */
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+    thrift_binary_protocol_write_i32 (protocol, -10, NULL);
+
+    /* test list operations */
+    assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+                                                     1, NULL) > 0);
+    assert (thrift_binary_protocol_write_list_end (protocol, NULL) == 0);
+
+    /* test 2nd read failure on a list */
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+
+    /* test negative list size */
+    thrift_binary_protocol_write_byte (protocol, T_VOID, NULL);
+    thrift_binary_protocol_write_i32 (protocol, -10, NULL);
+
+    /* test first write error on a list */
+    transport_write_error = 1;
+    assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+                                                     1, NULL) == -1);
+    transport_write_error = 0;
+
+    /* test 2nd write error on a list */
+    transport_write_count = 0;
+    transport_write_error_at = 1;
+    assert (thrift_binary_protocol_write_list_begin (protocol, T_VOID,
+                                                     1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* test set operation s*/
+    assert (thrift_binary_protocol_write_set_begin (protocol, T_VOID,
+                                                    1, NULL) > 0);
+    assert (thrift_binary_protocol_write_set_end (protocol, NULL) == 0);
+
+    /* invalid version */
+    assert (thrift_binary_protocol_write_i32 (protocol, -1, NULL) > 0);
+
+    /* sz > 0 for a message */
+    assert (thrift_binary_protocol_write_i32 (protocol, 1, NULL) > 0);
+
+    /* send a valid message */
+    thrift_binary_protocol_write_i32 (protocol, 0x80010000, NULL);
+    thrift_binary_protocol_write_string (protocol, "test", NULL);
+    thrift_binary_protocol_write_i32 (protocol, 1, NULL);
+
+    /* broken 2nd read */
+    thrift_binary_protocol_write_i32 (protocol, 0x80010000, NULL);
+
+    /* send a broken 3rd read */
+    thrift_binary_protocol_write_i32 (protocol, 0x80010000, NULL);
+    thrift_binary_protocol_write_string (protocol, "test", NULL);
+
+    /* send a valid message */
+    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) > 0);
+
+    assert (thrift_binary_protocol_write_message_end (protocol, NULL) == 0);
+
+    /* send broken writes */
+    transport_write_error = 1;
+    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) == -1);
+    transport_write_error = 0;
+
+    transport_write_count = 0;
+    transport_write_error_at = 2;
+    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    transport_write_count = 0;
+    transport_write_error_at = 3;
+    assert (thrift_binary_protocol_write_message_begin (protocol, "test",
+                                                        T_CALL, 1, NULL) == -1);
+    transport_write_error_at = -1;
+
+    /* clean up */
+    thrift_transport_close (transport, NULL);
+    g_object_unref (tsocket);
+    g_object_unref (protocol);
+    assert (wait (&status) == pid);
+    assert (status == 0);
+  }
+}
+
+
+static void
+thrift_server_primitives (const int port)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  ThriftBinaryProtocol *tbp = NULL;
+  ThriftProtocol *protocol = NULL;
+  gboolean value_boolean = FALSE;
+  gint8 value_byte = 0;
+  gint16 value_16 = 0;
+  gint32 value_32 = 0;
+  gint64 value_64 = 0;
+  gdouble value_double = 0;
+  gchar *string = NULL;
+  gpointer binary = NULL;
+  guint32 len = 0;
+  void *comparator = (void *) TEST_STRING;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  client = thrift_server_transport_accept (transport, NULL);
+  assert (client != NULL);
+
+  tbp = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                      client, NULL);
+  protocol = THRIFT_PROTOCOL (tbp);
+
+  assert (thrift_binary_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) > 0);
+  assert (thrift_binary_protocol_read_byte (protocol, &value_byte, NULL) > 0);
+  assert (thrift_binary_protocol_read_i16 (protocol, &value_16, NULL) > 0);
+  assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) > 0);
+  assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) > 0);
+  assert (thrift_binary_protocol_read_double (protocol,
+                                              &value_double, NULL) > 0);
+  assert (thrift_binary_protocol_read_string (protocol, &string, NULL) > 0);
+  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) > 0);
+
+  assert (value_boolean == TEST_BOOL);
+  assert (value_byte = TEST_BYTE);
+  assert (value_16 = TEST_I16);
+  assert (value_32 = TEST_I32);
+  assert (value_64 = TEST_I64);
+  assert (value_double = TEST_DOUBLE);
+  assert (strcmp (TEST_STRING, string) == 0);
+  assert (memcmp (comparator, binary, len) == 0);
+
+  g_free (string);
+  g_free (binary);
+
+  thrift_binary_protocol_read_binary (protocol, &binary, &len, NULL);
+  g_free (binary);
+
+  transport_read_count = 0;
+  transport_read_error_at = 0;
+  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) == -1);
+  transport_read_error_at = -1;
+
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  assert (thrift_binary_protocol_read_binary (protocol, &binary,
+                                              &len, NULL) == -1);
+  transport_read_error_at = -1;
+
+  transport_read_error = 1;
+  assert (thrift_binary_protocol_read_bool (protocol,
+                                            &value_boolean, NULL) == -1);
+  assert (thrift_binary_protocol_read_byte (protocol,
+                                            &value_byte, NULL) == -1);
+  assert (thrift_binary_protocol_read_i16 (protocol,
+                                           &value_16, NULL) == -1);
+  assert (thrift_binary_protocol_read_i32 (protocol, &value_32, NULL) == -1);
+  assert (thrift_binary_protocol_read_i64 (protocol, &value_64, NULL) == -1);
+  assert (thrift_binary_protocol_read_double (protocol,
+                                              &value_double, NULL) == -1);
+  transport_read_error = 0;
+
+  /* test partial write failure */
+  thrift_protocol_read_i32 (protocol, &value_32, NULL);
+
+  thrift_transport_read_end (client, NULL);
+  thrift_transport_close (client, NULL);
+
+  g_object_unref (tbp);
+  g_object_unref (client);
+  g_object_unref (tsocket);
+}
+
+static void
+thrift_server_complex_types (const int port)
+{
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  ThriftBinaryProtocol *tbp = NULL;
+  ThriftProtocol *protocol = NULL;
+  gchar *struct_name = NULL;
+  gchar *field_name = NULL;
+  gchar *message_name = NULL;
+  ThriftType element_type, key_type, value_type, field_type;
+  ThriftMessageType message_type;
+  gint8 value = 0;
+  gint16 field_id = 0;
+  guint32 size = 0;
+  gint32 seqid = 0;
+  gint32 version = 0;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  client = thrift_server_transport_accept (transport, NULL);
+  assert (client != NULL);
+
+  tbp = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL, "transport",
+                      client, NULL);
+  protocol = THRIFT_PROTOCOL (tbp);
+
+  thrift_binary_protocol_read_struct_begin (protocol, &struct_name, NULL);
+  thrift_binary_protocol_read_struct_end (protocol, NULL);
+
+  thrift_binary_protocol_read_field_begin (protocol, &field_name, &field_type,
+                                           &field_id, NULL);
+  thrift_binary_protocol_read_field_end (protocol, NULL);
+
+  /* test first read error on a field */
+  transport_read_error = 1;
+  assert (thrift_binary_protocol_read_field_begin (protocol,
+                                                   &field_name, &field_type,
+                                                   &field_id, NULL) == -1);
+  transport_read_error = 0;
+
+  /* test 2nd write failure */
+  thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+  /* test 2nd read failure on a field */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  assert (thrift_binary_protocol_read_field_begin (protocol,
+                                                   &field_name, &field_type,
+                                                   &field_id, NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* test field stop */
+  thrift_binary_protocol_read_field_begin (protocol, &field_name, &field_type,
+                                           &field_id, NULL);
+
+  thrift_binary_protocol_read_map_begin (protocol, &key_type, &value_type,
+                                         &size, NULL);
+  thrift_binary_protocol_read_map_end (protocol, NULL);
+
+  /* test read failure on a map */
+  transport_read_count = 0;
+  transport_read_error_at = 0;
+  assert (thrift_binary_protocol_read_map_begin (protocol,
+                                                 &key_type, &value_type,
+                                                 &size, NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* test 2nd read failure on a map */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  assert (thrift_binary_protocol_read_map_begin (protocol,
+                                                 &key_type, &value_type,
+                                                 &size, NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* test 3rd read failure on a map */
+  transport_read_count = 0;
+  transport_read_error_at = 2;
+  assert (thrift_binary_protocol_read_map_begin (protocol,
+                                                 &key_type, &value_type,
+                                                 &size, NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* test 2nd write failure */
+  thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+  /* test 3rd write failure */
+  thrift_binary_protocol_read_byte (protocol, &value, NULL);
+  thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+  /* test negative map size */
+  assert (thrift_binary_protocol_read_map_begin (protocol,
+                                                 &key_type, &value_type,
+                                                 &size, NULL) == -1);
+
+  /* test list operations */
+  thrift_binary_protocol_read_list_begin (protocol, &element_type, &size, NULL);
+  thrift_binary_protocol_read_list_end (protocol, NULL);
+
+  /* test read failure */
+  transport_read_error = 1;
+  assert (thrift_binary_protocol_read_list_begin (protocol, &element_type,
+                                                  &size, NULL) == -1);
+  transport_read_error = 0;
+
+  /* test 2nd read failure */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  thrift_binary_protocol_read_list_begin (protocol, &element_type, &size, NULL);
+  transport_read_error_at = -1;
+
+  /* test negative list size failure */
+  thrift_binary_protocol_read_list_begin (protocol, &element_type, &size, NULL);
+
+  /* test 2nd write failure */
+  thrift_binary_protocol_read_byte (protocol, &value, NULL);
+
+  /* test set operations */
+  thrift_binary_protocol_read_set_begin (protocol, &element_type, &size, NULL);
+  thrift_binary_protocol_read_set_end (protocol, NULL);
+
+  /* broken read */
+  transport_read_error = 1;
+  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+  transport_read_error = 0;
+
+  /* invalid protocol version */
+  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+
+  /* sz > 0 */
+  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) > 0);
+
+  /* read a valid message */
+  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) > 0);
+  g_free (message_name);
+
+  /* broken 2nd read on a message */
+  transport_read_count = 0;
+  transport_read_error_at = 1;
+  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+  transport_read_error_at = -1;
+
+  /* broken 3rd read on a message */
+  transport_read_count = 0;
+  transport_read_error_at = 3; /* read_string does two reads */
+  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid,
+                                                     NULL) == -1);
+  g_free (message_name);
+  transport_read_error_at = -1;
+
+  /* read a valid message */
+  assert (thrift_binary_protocol_read_message_begin (protocol, &message_name,
+                                                     &message_type, &seqid, 
+                                                     NULL) > 0);
+  g_free (message_name);
+
+  assert (thrift_binary_protocol_read_message_end (protocol, NULL) == 0);
+
+  /* handle 2nd write failure on a message */
+  thrift_binary_protocol_read_i32 (protocol, &version, NULL);
+
+  /* handle 2nd write failure on a message */
+  thrift_binary_protocol_read_i32 (protocol, &version, NULL);
+  thrift_binary_protocol_read_string (protocol, &message_name, NULL);
+
+  g_object_unref (client);
+  // TODO: investigate g_object_unref (tbp);
+  g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+  g_type_init ();
+  test_create_and_destroy ();
+  test_initialize ();
+  test_read_and_write_primitives ();
+  test_read_and_write_complex_types ();
+
+  return 0;
+}
+
diff --git a/lib/c_glib/test/testsimpleserver.c b/lib/c_glib/test/testsimpleserver.c
new file mode 100644
index 0000000..182e9ef
--- /dev/null
+++ b/lib/c_glib/test/testsimpleserver.c
@@ -0,0 +1,113 @@
+#include <assert.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "processor/thrift_processor.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_PORT 51199
+
+#include "server/thrift_simple_server.c"
+
+/* create a rudimentary processor */
+#define TEST_PROCESSOR_TYPE (test_processor_get_type ())
+
+struct _TestProcessor
+{
+  ThriftProcessor parent;
+};
+typedef struct _TestProcessor TestProcessor;
+
+struct _TestProcessorClass
+{
+  ThriftProcessorClass parent;
+};
+typedef struct _TestProcessorClass TestProcessorClass;
+
+gboolean
+test_processor_process (ThriftProcessor *processor, ThriftProtocol *in,
+                        ThriftProtocol *out)
+{
+  return FALSE;
+}
+
+static void
+test_processor_class_init (ThriftProcessorClass *proc)
+{
+  proc->process = test_processor_process;
+}
+
+GType
+test_processor_get_type (void)
+{
+  static GType type = 0;
+
+  if (type == 0)
+  {
+    static const GTypeInfo info =
+    {
+      sizeof (TestProcessorClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) test_processor_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (TestProcessor),
+      0, /* n_preallocs */
+      NULL, /* instance_init */
+      NULL, /* value_table */
+    };
+
+    type = g_type_register_static (THRIFT_TYPE_PROCESSOR,
+                                   "TestProcessorType",
+                                   &info, 0);
+  }
+
+  return type;
+}
+
+static void
+test_server (void)
+{
+  int status;
+  pid_t pid;
+  TestProcessor *p = NULL;
+  ThriftServerSocket *tss = NULL;
+  ThriftSimpleServer *ss = NULL;
+
+  p = g_object_new (TEST_PROCESSOR_TYPE, NULL);
+  tss = g_object_new (THRIFT_TYPE_SERVER_SOCKET, "port", TEST_PORT, NULL);
+  ss = g_object_new (THRIFT_TYPE_SIMPLE_SERVER, "processor", p,
+                     "server_transport", THRIFT_SERVER_TRANSPORT (tss), NULL);
+
+  /* run the server in a child process */
+  pid = fork ();
+  assert (pid >= 0);
+
+  if (pid == 0)
+  {
+    THRIFT_SERVER_GET_CLASS (THRIFT_SERVER (ss))->serve (THRIFT_SERVER (ss));
+    exit (0);
+  } else {
+    sleep (5);
+    kill (pid, SIGINT);
+
+    g_object_unref (ss);
+    g_object_unref (tss);
+    g_object_unref (p);
+    assert (wait (&status) == pid);
+    assert (status == SIGINT);
+  }
+}
+
+int
+main (void)
+{
+  g_type_init ();
+  test_server ();
+
+  return 0;
+}
diff --git a/lib/c_glib/test/teststruct.c b/lib/c_glib/test/teststruct.c
new file mode 100644
index 0000000..cb401e2
--- /dev/null
+++ b/lib/c_glib/test/teststruct.c
@@ -0,0 +1,121 @@
+#include <assert.h>
+#include <glib-object.h>
+
+#include "../src/thrift_struct.c"
+
+/* tests to ensure we can extend a ThriftStruct */
+
+struct _ThriftTestStruct
+{
+  ThriftStruct parent;
+};
+typedef struct _ThriftTestStruct ThriftTestStruct;
+
+struct _ThriftTestStructClass
+{
+  ThriftStructClass parent;
+};
+typedef struct _ThriftTestStructClass ThriftTestStructClass;
+
+GType thrift_test_struct_get_type (void);
+
+#define THRIFT_TYPE_TEST_STRUCT (thrift_test_struct_get_type ())
+#define THRIFT_TEST_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                     THRIFT_TYPE_TEST_STRUCT, \
+                                     ThriftTestStruct))
+#define THRIFT_TEST_STRUCT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), \
+                                         THRIFT_TYPE_TEST_STRUCT, \
+                                         ThriftTestStructClass))
+#define THRIFT_IS_TEST_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+                                        THRIFT_TYPE_TEST_STRUCT))
+#define THRIFT_IS_TEST_STRUCT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), \
+                                            THRIFT_TYPE_TEST_STRUCT))
+#define THRIFT_TEST_STRUCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                               THRIFT_TYPE_TEST_STRUCT, \
+                                               ThriftTestStructClass))
+
+/* test declarations */
+gint32 thrift_test_struct_read (ThriftStruct *object, ThriftProtocol *protocol,
+                                GError **error);
+gint32 thrift_test_struct_write (ThriftStruct *object, ThriftProtocol *protocol,
+                                 GError **error);
+
+static void
+thrift_test_struct_class_init (ThriftTestStructClass *cls)
+{
+  ThriftStructClass *ts_cls = THRIFT_STRUCT_CLASS (cls);
+  ts_cls->read = thrift_test_struct_read;
+  ts_cls->write = thrift_test_struct_write;
+}
+
+static void
+thrift_test_struct_instance_init (ThriftTestStruct *s)
+{
+  (void) s;
+}
+
+GType
+thrift_test_struct_get_type (void)
+{
+  static GType type = 0;
+
+  if (type == 0)
+  {
+    static const GTypeInfo type_info =
+    {
+      sizeof (ThriftTestStructClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) thrift_test_struct_class_init,
+      NULL,
+      NULL,
+      sizeof (ThriftTestStruct),
+      0,
+      (GInstanceInitFunc) thrift_test_struct_instance_init,
+      NULL, 
+    };
+
+    type = g_type_register_static (THRIFT_TYPE_STRUCT,
+                                   "ThriftTestStructType", &type_info, 0);
+  }
+
+  return type;
+}
+
+gint32
+thrift_test_struct_read (ThriftStruct *object, ThriftProtocol *protocol,
+                         GError **error)
+{
+  return 0;
+}
+
+gint32
+thrift_test_struct_write (ThriftStruct *object, ThriftProtocol *protocol,
+                          GError **error)
+{
+  return 0;
+}
+
+
+static void
+test_initialize_object (void)
+{
+  ThriftTestStruct *t = NULL;
+
+  t = g_object_new (THRIFT_TYPE_TEST_STRUCT, NULL);
+  assert ( THRIFT_IS_STRUCT (t));
+  thrift_struct_read (THRIFT_STRUCT (t), NULL, NULL);
+  thrift_struct_write (THRIFT_STRUCT (t), NULL, NULL);
+  thrift_test_struct_read (THRIFT_STRUCT (t), NULL, NULL);
+  thrift_test_struct_write (THRIFT_STRUCT (t), NULL, NULL);
+  g_object_unref (t);
+}
+
+int
+main(void)
+{
+  g_type_init ();
+  test_initialize_object ();
+
+  return 0;
+}
diff --git a/lib/c_glib/test/testthrifttest.c b/lib/c_glib/test/testthrifttest.c
new file mode 100644
index 0000000..6020f9c
--- /dev/null
+++ b/lib/c_glib/test/testthrifttest.c
@@ -0,0 +1,28 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+static const char TEST_ADDRESS[] = "localhost";
+static const int TEST_PORT = 64444;
+
+static void thrift_server (const int port);
+
+static void
+thrift_server (const int port)
+{
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+
+  g_object_unref (tsocket);
+}
+
+int
+main(void)
+{
+  g_type_init ();
+  thrift_server (TEST_PORT);
+  return 0;
+}
+
diff --git a/lib/c_glib/test/testthrifttestclient.cpp b/lib/c_glib/test/testthrifttestclient.cpp
new file mode 100644
index 0000000..4b5b841
--- /dev/null
+++ b/lib/c_glib/test/testthrifttestclient.cpp
@@ -0,0 +1,551 @@
+
+/* test a C client with a C++ server */
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <protocol/TBinaryProtocol.h>
+#include <protocol/TDebugProtocol.h>
+#include <server/TSimpleServer.h>
+#include <transport/TServerSocket.h>
+#include "ThriftTest.h"
+#include "ThriftTest_types.h"
+
+#include <iostream>
+
+using namespace std;
+using namespace boost;
+
+using namespace apache::thrift;
+using namespace apache::thrift::concurrency;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+
+using namespace thrift::test;
+
+#define TEST_PORT 9980
+
+// Extra functions required for ThriftTest_types to work
+namespace thrift { namespace test {
+
+bool Insanity::operator<(thrift::test::Insanity const& other) const {
+  using apache::thrift::ThriftDebugString;
+  return ThriftDebugString(*this) < ThriftDebugString(other);
+}
+
+}}
+
+class TestHandler : public ThriftTestIf {
+  public:
+  TestHandler() {}
+
+  void testVoid() {
+    printf("[C -> C++] testVoid()\n");
+  }
+
+  void testString(string& out, const string &thing) {
+    printf("[C -> C++] testString(\"%s\")\n", thing.c_str());
+    out = thing;
+  }
+
+  int8_t testByte(const int8_t thing) {
+    printf("[C -> C++] testByte(%d)\n", (int)thing);
+    return thing;
+  }
+  int32_t testI32(const int32_t thing) {
+    printf("[C -> C++] testI32(%d)\n", thing);
+    return thing;
+  }
+
+  int64_t testI64(const int64_t thing) {
+    printf("[C -> C++] testI64(%lld)\n", thing);
+    return thing;
+  }
+
+  double testDouble(const double thing) {
+    printf("[C -> C++] testDouble(%lf)\n", thing);
+    return thing;
+  }
+
+  void testStruct(Xtruct& out, const Xtruct &thing) {
+    printf("[C -> C++] testStruct({\"%s\", %d, %d, %lld})\n", thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing);
+    out = thing;
+  }
+
+  void testNest(Xtruct2& out, const Xtruct2& nest) {
+    const Xtruct &thing = nest.struct_thing;
+    printf("[C -> C++] testNest({%d, {\"%s\", %d, %d, %lld}, %d})\n", (int)nest.byte_thing, thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing, nest.i32_thing);
+    out = nest;
+  }
+
+  void testMap(map<int32_t, int32_t> &out, const map<int32_t, int32_t> &thing) {
+    printf("[C -> C++] testMap({");
+    map<int32_t, int32_t>::const_iterator m_iter;
+    bool first = true;
+    for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d => %d", m_iter->first, m_iter->second);
+    }
+    printf("})\n");
+    out = thing;
+  }
+
+  void testSet(set<int32_t> &out, const set<int32_t> &thing) {
+    printf("[C -> C++] testSet({");
+    set<int32_t>::const_iterator s_iter;
+    bool first = true;
+    for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *s_iter);
+    }
+    printf("})\n");
+    out = thing;
+  }
+
+  void testList(vector<int32_t> &out, const vector<int32_t> &thing) {
+    printf("[C -> C++] testList({");
+    vector<int32_t>::const_iterator l_iter;
+    bool first = true;
+    for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) {
+      if (first) {
+        first = false;
+      } else {        printf(", ");
+      }
+      printf("%d", *l_iter);
+    }
+    printf("})\n");
+    out = thing;
+  }
+
+  Numberz::type testEnum(const Numberz::type thing) {
+    printf("[C -> C++] testEnum(%d)\n", thing);
+    return thing;
+  }
+
+  UserId testTypedef(const UserId thing) {
+    printf("[C -> C++] testTypedef(%lld)\n", thing);
+    return thing;  }
+
+  void testMapMap(map<int32_t, map<int32_t,int32_t> > &mapmap, const int32_t hello) {
+    printf("[C -> C++] testMapMap(%d)\n", hello);
+
+    map<int32_t,int32_t> pos;
+    map<int32_t,int32_t> neg;
+    for (int i = 1; i < 5; i++) {
+      pos.insert(make_pair(i,i));
+      neg.insert(make_pair(-i,-i));
+    }
+
+    mapmap.insert(make_pair(4, pos));
+    mapmap.insert(make_pair(-4, neg));
+
+  }
+
+  void testInsanity(map<UserId, map<Numberz::type,Insanity> > &insane, const Insanity &argument) {
+    printf("[C -> C++] testInsanity()\n");
+
+    Xtruct hello;
+    hello.string_thing = "Hello2";
+    hello.byte_thing = 2;
+    hello.i32_thing = 2;
+    hello.i64_thing = 2;
+
+    Xtruct goodbye;
+    goodbye.string_thing = "Goodbye4";
+    goodbye.byte_thing = 4;
+    goodbye.i32_thing = 4;
+    goodbye.i64_thing = 4;
+
+    Insanity crazy;
+    crazy.userMap.insert(make_pair(Numberz::EIGHT, 8));
+    crazy.xtructs.push_back(goodbye);
+
+    Insanity looney;
+    crazy.userMap.insert(make_pair(Numberz::FIVE, 5));
+    crazy.xtructs.push_back(hello);
+
+    map<Numberz::type, Insanity> first_map;
+    map<Numberz::type, Insanity> second_map;
+
+    first_map.insert(make_pair(Numberz::TWO, crazy));
+    first_map.insert(make_pair(Numberz::THREE, crazy));
+
+    second_map.insert(make_pair(Numberz::SIX, looney));
+
+    insane.insert(make_pair(1, first_map));
+    insane.insert(make_pair(2, second_map));
+
+    printf("return");
+    printf(" = {");
+    map<UserId, map<Numberz::type,Insanity> >::const_iterator i_iter;
+    for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) {
+      printf("%lld => {", i_iter->first);
+      map<Numberz::type,Insanity>::const_iterator i2_iter;
+      for (i2_iter = i_iter->second.begin();
+           i2_iter != i_iter->second.end();
+           ++i2_iter) {
+        printf("%d => {", i2_iter->first);
+        map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
+        map<Numberz::type, UserId>::const_iterator um;
+        printf("{");
+        for (um = userMap.begin(); um != userMap.end(); ++um) {
+          printf("%d => %lld, ", um->first, um->second);
+        }
+        printf("}, ");
+
+        vector<Xtruct> xtructs = i2_iter->second.xtructs;
+        vector<Xtruct>::const_iterator x;
+        printf("{");
+        for (x = xtructs.begin(); x != xtructs.end(); ++x) {
+          printf("{\"%s\", %d, %d, %lld}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing);
+        }
+        printf("}");
+
+        printf("}, ");
+      }
+      printf("}, ");
+    }
+    printf("}\n");
+
+
+  }
+
+  void testMulti(Xtruct &hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string>  &arg3, const Numberz::type arg4, const UserId arg5) {
+    printf("[C -> C++] testMulti()\n");
+
+    hello.string_thing = "Hello2";
+    hello.byte_thing = arg0;
+    hello.i32_thing = arg1;
+    hello.i64_thing = (int64_t)arg2;
+  }
+
+  void testException(const std::string &arg)
+    throw(Xception, apache::thrift::TException)
+  {
+    printf("[C -> C++] testException(%s)\n", arg.c_str());
+    if (arg.compare("Xception") == 0) {
+      Xception e;
+      e.errorCode = 1001;
+      e.message = arg;
+      throw e;
+    } else if (arg.compare("ApplicationException") == 0) {
+      apache::thrift::TException e;
+      throw e;
+    } else {
+      Xtruct result;
+      result.string_thing = arg;
+      return;
+    }
+  }
+
+  void testMultiException(Xtruct &result, const std::string &arg0, const std::string &arg1) throw(Xception, Xception2) {
+
+    printf("[C -> C++] testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str());
+
+    if (arg0.compare("Xception") == 0) {
+      Xception e;
+      e.errorCode = 1001;
+      e.message = "This is an Xception";
+      throw e;
+    } else if (arg0.compare("Xception2") == 0) {
+      Xception2 e;
+      e.errorCode = 2002;
+      e.struct_thing.string_thing = "This is an Xception2";
+      throw e;
+    } else {
+      result.string_thing = arg1;
+      return;
+    }
+  }
+
+  void testOneway(int sleepFor) {
+    printf("testOneway(%d): Sleeping...\n", sleepFor);
+    sleep(sleepFor);
+    printf("testOneway(%d): done sleeping!\n", sleepFor);
+  }
+};
+
+// C CLIENT
+extern "C" {
+
+#include "t_test_thrift_test.h"
+#include "t_test_thrift_test_types.h"
+#include "transport/thrift_socket.h"
+#include "protocol/thrift_protocol.h"
+#include "protocol/thrift_binary_protocol.h"
+
+static void
+test_thrift_client (void)
+{
+  ThriftSocket *tsocket = NULL;
+  ThriftBinaryProtocol *protocol = NULL;
+  TTestThriftTestClient *client = NULL;
+  TTestThriftTestIf *iface = NULL;
+  GError *error = NULL;
+  gchar *string = NULL;
+  gint8 byte = 0;
+  gint16 i16 = 0;
+  gint32 i32 = 0, another_i32 = 56789; 
+  gint64 i64 = 0;
+  double dbl = 0.0;
+  TTestXtruct *xtruct_in, *xtruct_out;
+  TTestXtruct2 *xtruct2_in, *xtruct2_out;
+  GHashTable *map_in = NULL, *map_out = NULL;
+  GHashTable *set_in = NULL, *set_out = NULL;
+  GArray *list_in = NULL, *list_out = NULL;
+  TTestNumberz enum_in, enum_out;
+  TTestUserId user_id_in, user_id_out; 
+  GHashTable *insanity_in = NULL;
+  TTestXtruct *xtruct1, *xtruct2;
+  TTestInsanity *insanity_out = NULL;
+  TTestXtruct *multi_in = NULL;
+  GHashTable *multi_map_out = NULL;
+  TTestXception *xception = NULL;
+  TTestXception2 *xception2 = NULL;
+
+  // initialize gobject
+  g_type_init ();
+
+  // create a C client
+  tsocket = (ThriftSocket *) g_object_new (THRIFT_TYPE_SOCKET, 
+                          "hostname", "localhost",
+                          "port", TEST_PORT, NULL);
+  protocol = (ThriftBinaryProtocol *) g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
+                           "transport",
+                           tsocket, NULL);
+  client = (TTestThriftTestClient *) g_object_new (T_TEST_TYPE_THRIFT_TEST_CLIENT, "input_protocol", protocol, "output_protocol", protocol, NULL);
+  iface = T_TEST_THRIFT_TEST_IF (client);
+
+  // open and send
+  thrift_transport_open (THRIFT_TRANSPORT(tsocket), NULL);
+
+  assert (t_test_thrift_test_client_test_void (iface, &error) == TRUE);
+  assert (error == NULL);
+
+  assert (t_test_thrift_test_client_test_string (iface, &string, "test123", &error) == TRUE);
+  assert (strcmp (string, "test123") == 0);
+  g_free (string);
+  assert (error == NULL);
+
+  assert (t_test_thrift_test_client_test_byte (iface, &byte, (gint8) 5, &error) == TRUE);
+  assert (byte == 5);
+  assert (error == NULL);
+
+  assert (t_test_thrift_test_client_test_i32 (iface, &i32, 123, &error) == TRUE);
+  assert (i32 == 123);
+  assert (error == NULL);
+
+  assert (t_test_thrift_test_client_test_i64 (iface, &i64, 12345, &error) == TRUE);
+  assert (i64 == 12345);
+  assert (error == NULL);
+
+  assert (t_test_thrift_test_client_test_double (iface, &dbl, 5.6, &error) == TRUE);
+  assert (dbl == 5.6);
+  assert (error == NULL);
+
+  xtruct_out = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+  xtruct_out->byte_thing = 1;
+  xtruct_out->__isset_byte_thing = TRUE;
+  xtruct_out->i32_thing = 15;
+  xtruct_out->__isset_i32_thing = TRUE;
+  xtruct_out->i64_thing = 151;
+  xtruct_out->__isset_i64_thing = TRUE;
+  xtruct_out->string_thing = g_strdup ("abc123");
+  xtruct_out->__isset_string_thing = TRUE;
+  assert (t_test_thrift_test_client_test_struct (iface, &xtruct_in, xtruct_out, &error) == TRUE);
+  assert (error == NULL);
+
+  xtruct2_out = (TTestXtruct2 *) g_object_new (T_TEST_TYPE_XTRUCT2, NULL);
+  xtruct2_out->byte_thing = 1;
+  xtruct2_out->__isset_byte_thing = TRUE;
+  xtruct2_out->struct_thing = xtruct_out;
+  xtruct2_out->__isset_struct_thing = TRUE;
+  xtruct2_out->i32_thing = 123;
+  xtruct2_out->__isset_i32_thing = TRUE;
+  assert (t_test_thrift_test_client_test_nest (iface, &xtruct2_in, xtruct2_out, &error) == TRUE);
+  assert (error == NULL);
+
+  g_object_unref (xtruct2_out);
+  g_object_unref (xtruct2_in);
+  g_free (xtruct_out->string_thing);
+  g_object_unref (xtruct_out);
+  g_object_unref (xtruct_in);
+
+  map_out = g_hash_table_new (NULL, NULL);
+  map_in = g_hash_table_new (NULL, NULL);  g_hash_table_insert (map_out, &i32, &i32);
+  assert (t_test_thrift_test_client_test_map (iface, &map_in, map_out, &error) == TRUE);
+  assert (error == NULL);
+  g_hash_table_destroy (map_out);
+  g_hash_table_destroy (map_in);
+
+  set_out = g_hash_table_new (NULL, NULL);
+  set_in = g_hash_table_new (NULL, NULL);
+  g_hash_table_insert (set_out, &i32, &i32);
+  assert (t_test_thrift_test_client_test_set (iface, &set_in, set_out, &error) == TRUE);
+  assert (error == NULL);
+  g_hash_table_destroy (set_out);
+  g_hash_table_destroy (set_in);
+
+  list_out = g_array_new(TRUE, TRUE, sizeof(gint32));
+  list_in = g_array_new(TRUE, TRUE, sizeof(gint32));
+  another_i32 = 456;
+  g_array_append_val (list_out, i32);
+  g_array_append_val (list_out, another_i32);
+  assert (t_test_thrift_test_client_test_list (iface, &list_in, list_out, &error) == TRUE);
+  assert (error == NULL);
+  g_array_free (list_out, TRUE);
+  g_array_free (list_in, TRUE);
+
+  enum_out = T_TEST_NUMBERZ_ONE;
+  assert (t_test_thrift_test_client_test_enum (iface, &enum_in, enum_out, &error) == TRUE);
+  assert (enum_in == enum_out);
+  assert (error == NULL);
+
+  user_id_out = 12345;
+  assert (t_test_thrift_test_client_test_typedef (iface, &user_id_in, user_id_out, &error) == TRUE);
+  assert (user_id_in == user_id_out);
+  assert (error == NULL);
+
+  map_in = g_hash_table_new (NULL, NULL);
+  assert (t_test_thrift_test_client_test_map_map (iface, &map_in, i32, &error) == TRUE);
+  assert (error == NULL);
+  g_hash_table_destroy (map_in);
+
+  // insanity
+  insanity_out = (TTestInsanity *) g_object_new (T_TEST_TYPE_INSANITY, NULL);
+  insanity_out->userMap = g_hash_table_new (NULL, NULL);
+  g_hash_table_insert (insanity_out->userMap, &enum_out, &user_id_out);
+
+  xtruct1 = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+  xtruct1->byte_thing = 1;
+  xtruct1->__isset_byte_thing = TRUE;
+  xtruct1->i32_thing = 15;
+  xtruct1->__isset_i32_thing = TRUE;
+  xtruct1->i64_thing = 151;
+  xtruct1->__isset_i64_thing = TRUE;
+  xtruct1->string_thing = g_strdup ("abc123");
+  xtruct1->__isset_string_thing = TRUE;
+  xtruct2 = (TTestXtruct *) g_object_new (T_TEST_TYPE_XTRUCT, NULL);
+  xtruct2->byte_thing = 1;
+  xtruct2->__isset_byte_thing = TRUE;
+  xtruct2->i32_thing = 15;
+  xtruct2->__isset_i32_thing = TRUE;
+  xtruct2->i64_thing = 151;
+  xtruct2->__isset_i64_thing = TRUE;
+  xtruct2->string_thing = g_strdup ("abc123");
+  xtruct2->__isset_string_thing = TRUE;
+
+  insanity_out->xtructs = g_ptr_array_new ();
+  insanity_in = g_hash_table_new (NULL, NULL);
+  g_ptr_array_add (insanity_out->xtructs, xtruct1);
+  g_ptr_array_add (insanity_out->xtructs, xtruct2);
+  assert (t_test_thrift_test_client_test_insanity (iface, &insanity_in, insanity_out, &error) == TRUE);
+
+  g_hash_table_unref (insanity_in);
+  g_ptr_array_free (insanity_out->xtructs, TRUE);
+  g_free (xtruct1->string_thing);
+  g_free (xtruct2->string_thing);
+  g_object_unref (xtruct1);
+  g_object_unref (xtruct2);
+
+  multi_map_out = g_hash_table_new (NULL, NULL);
+  string = g_strdup ("abc123");
+  g_hash_table_insert (multi_map_out, &i16, string);
+  assert (t_test_thrift_test_client_test_multi (iface, &multi_in, byte, i32, i64, multi_map_out, enum_out, user_id_out, &error) == TRUE);
+  assert (multi_in->i32_thing == i32);
+  assert (multi_in->i64_thing == i64);
+  g_object_unref (multi_in);
+  g_hash_table_unref (multi_map_out);
+  g_free (string); 
+
+  assert (t_test_thrift_test_client_test_exception (iface, "Xception", &xception, &error) == FALSE);
+  assert (xception->errorCode == 1001);
+  g_error_free (error);
+  error = NULL;
+
+  assert (t_test_thrift_test_client_test_exception (iface, "ApplicationException", &xception, &error) == FALSE);
+  g_error_free (error);
+  error = NULL;
+  g_object_unref (xception);
+  xception = NULL;
+
+  assert (t_test_thrift_test_client_test_exception (iface, "Test", &xception, &error) == TRUE);
+  assert (error == NULL);
+
+  assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, "Xception", NULL, &xception, &xception2, &error) == FALSE);
+  assert (xception->errorCode == 1001);
+  g_error_free (error);
+  error = NULL;
+  g_object_unref (xception);
+  xception = NULL;
+  xception2 = NULL;
+
+  assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, "Xception2", NULL, &xception, &xception2, &error) == FALSE);
+  assert (xception2->errorCode == 2002);
+  g_error_free (error);
+  error = NULL;
+  g_object_unref (xception2);
+  xception2 = NULL;
+
+  assert (t_test_thrift_test_client_test_multi_exception (iface, &multi_in, NULL , NULL, &xception, &xception2, &error) == TRUE);
+  assert (error == NULL);
+
+  assert (t_test_thrift_test_client_test_oneway (iface, 1, &error) == TRUE);
+  assert (error == NULL);
+
+  /* sleep to let the oneway call go through */
+  sleep (5);
+
+  thrift_transport_close (THRIFT_TRANSPORT(tsocket), NULL);
+  g_object_unref (client);
+  g_object_unref (protocol);
+  g_object_unref (tsocket);
+}
+
+
+} /* extern "C" */
+
+
+static void
+bailout (int signum)
+{
+  exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+  int status;
+  int pid = fork ();
+  assert (pid >= 0);
+
+  if (pid == 0) /* child */
+  {
+    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+    shared_ptr<TestHandler> testHandler(new TestHandler());
+    shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
+    shared_ptr<TServerSocket> serverSocket(new TServerSocket(TEST_PORT));
+    shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+    TSimpleServer simpleServer(testProcessor, serverSocket, transportFactory, protocolFactory);
+    signal (SIGALRM, bailout);
+    alarm (60);
+    simpleServer.serve();
+  } else {
+    sleep (1);
+    test_thrift_client ();
+    kill (pid, SIGINT);
+    wait (&status) == pid;
+  }
+
+  return 0;
+}
+
diff --git a/lib/c_glib/test/testtransportsocket.c b/lib/c_glib/test/testtransportsocket.c
new file mode 100644
index 0000000..14579c8
--- /dev/null
+++ b/lib/c_glib/test/testtransportsocket.c
@@ -0,0 +1,200 @@
+#include <assert.h>
+#include <netdb.h>
+
+#include "transport/thrift_transport.h"
+#include "transport/thrift_server_transport.h"
+#include "transport/thrift_server_socket.h"
+
+#define TEST_DATA { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
+
+/* substituted functions to test failures of system and library calls */
+static int socket_error = 0;
+int
+my_socket(int domain, int type, int protocol)
+{
+  if (socket_error == 0)
+  {
+    return socket (domain, type, protocol);
+  }
+  return -1;
+}
+
+static int recv_error = 0;
+ssize_t
+my_recv(int socket, void *buffer, size_t length, int flags)
+{
+  if (recv_error == 0)
+  {
+    return recv (socket, buffer, length, flags);
+  }
+  return -1;
+}
+
+static int send_error = 0;
+ssize_t
+my_send(int socket, const void *buffer, size_t length, int flags)
+{
+  if (send_error == 0)
+  {
+    return send (socket, buffer, length, flags);
+  }
+  return -1;
+}
+
+#define socket my_socket
+#define recv my_recv
+#define send my_send
+#include "../src/transport/thrift_socket.c"
+#undef socket
+#undef recv
+#undef send
+
+static const char TEST_ADDRESS[] = "localhost";
+static const short TEST_PORT = 64444;
+
+static void thrift_socket_server (const int port);
+
+/* test object creation and destruction */
+static void
+test_create_and_destroy(void)
+{
+  gchar *hostname = NULL;
+  guint port = 0;
+
+  GObject *object = NULL;
+  object = g_object_new (THRIFT_TYPE_SOCKET, NULL);
+  assert (object != NULL);
+  g_object_get (G_OBJECT(object), "hostname", &hostname, "port", &port, NULL);
+  g_free (hostname);
+
+  g_object_unref (object);
+}
+
+static void
+test_open_and_close(void)
+{
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  GError *err = NULL;
+
+  /* open a connection and close it */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                          "port", 51188, NULL); 
+  transport = THRIFT_TRANSPORT (tsocket);
+  thrift_socket_open (transport, NULL);
+  assert (thrift_socket_is_open (transport) == TRUE);
+  thrift_socket_close (transport, NULL);
+  assert (thrift_socket_is_open (transport) == FALSE);
+
+  /* test close failure */
+  tsocket->sd = -1;
+  thrift_socket_close (transport, NULL);
+  g_object_unref (tsocket);
+
+  /* try a hostname lookup failure */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost.broken",
+                          NULL);
+  transport = THRIFT_TRANSPORT (tsocket);
+  assert (thrift_socket_open (transport, &err) == FALSE);
+  g_object_unref (tsocket);
+  g_error_free (err);
+  err = NULL;
+
+  /* try an error call to socket() */
+  tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost", NULL);
+  transport = THRIFT_TRANSPORT (tsocket);
+  socket_error = 1;
+  assert (thrift_socket_open (transport, &err) == FALSE);
+  socket_error = 0;
+  g_object_unref (tsocket);
+  g_error_free (err);
+}
+
+static void
+test_read_and_write(void)
+{
+  int status;
+  pid_t pid;
+  ThriftSocket *tsocket = NULL;
+  ThriftTransport *transport = NULL;
+  int port = 51199;
+  guchar buf[10] = TEST_DATA; /* a buffer */
+
+  pid = fork ();
+  assert ( pid >= 0 );
+
+  if ( pid == 0 )
+  {
+    /* child listens */
+    thrift_socket_server (port);
+    exit (0);
+  } else {
+    /* parent connects, wait a bit for the socket to be created */
+    sleep (1);
+
+    tsocket = g_object_new (THRIFT_TYPE_SOCKET, "hostname", "localhost",
+                            "port", port, NULL);
+    transport = THRIFT_TRANSPORT (tsocket);
+    assert (thrift_socket_open (transport, NULL) == TRUE);
+    assert (thrift_socket_is_open (transport));
+    thrift_socket_write (transport, buf, 10, NULL);
+
+    /* write fail */
+    send_error = 1;
+    thrift_socket_write (transport, buf, 1, NULL);
+    send_error = 0;
+
+    thrift_socket_write_end (transport, NULL);
+    thrift_socket_flush (transport, NULL);
+    thrift_socket_close (transport, NULL);
+    g_object_unref (tsocket);
+
+    assert ( wait (&status) == pid );
+    assert ( status == 0 );
+  }
+}
+
+static void
+thrift_socket_server (const int port)
+{
+  int bytes = 0;
+  ThriftServerTransport *transport = NULL;
+  ThriftTransport *client = NULL;
+  guchar buf[10]; /* a buffer */
+  guchar match[10] = TEST_DATA;
+
+  ThriftServerSocket *tsocket = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+                                              "port", port, NULL);
+
+  transport = THRIFT_SERVER_TRANSPORT (tsocket);
+  thrift_server_transport_listen (transport, NULL);
+  client = thrift_server_transport_accept (transport, NULL);
+  assert (client != NULL);
+
+  /* read 10 bytes */
+  bytes = thrift_socket_read (client, buf, 10, NULL);
+  assert (bytes == 10); /* make sure we've read 10 bytes */
+  assert ( memcmp(buf, match, 10) == 0 ); /* make sure what we got matches */
+
+  /* failed read */
+  recv_error = 1;
+  thrift_socket_read (client, buf, 1, NULL);
+  recv_error = 0;
+
+  thrift_socket_read_end (client, NULL);
+  thrift_socket_close (client, NULL);
+  g_object_unref (tsocket);
+  g_object_unref (client);
+}
+
+int
+main(void)
+{
+  g_type_init();
+  test_create_and_destroy();
+  test_open_and_close();
+  test_read_and_write();
+
+  return 0;
+}
+