diff --git a/cpp/Makefile.am b/cpp/Makefile.am
index fa8d6cf9..3cbb4002 100644
--- a/cpp/Makefile.am
+++ b/cpp/Makefile.am
@@ -61,6 +61,8 @@ EXTRA_DIST = \
 		msgpack_vc8.sln \
 		msgpack_vc8.postbuild.bat
 
+SUBDIRS = test
+
 check_PROGRAMS = \
 		msgpackc_test \
 		msgpack_test
diff --git a/cpp/configure.in b/cpp/configure.in
index 8c59ddad..596b28d4 100644
--- a/cpp/configure.in
+++ b/cpp/configure.in
@@ -39,5 +39,5 @@ add CFLAGS="--march=i686" and CXXFLAGS="-march=i686" options to ./configure as f
 ])
 fi
 
-AC_OUTPUT([Makefile])
+AC_OUTPUT([Makefile test/Makefile])
 
diff --git a/cpp/msgpack/unpack.hpp b/cpp/msgpack/unpack.hpp
index 324111a5..d39b5df8 100644
--- a/cpp/msgpack/unpack.hpp
+++ b/cpp/msgpack/unpack.hpp
@@ -81,7 +81,7 @@ public:
 	// while( /* readable */ ) {
 	//
 	//     // 1.
-	//     pac.reserve(1024);
+	//     pac.reserve_buffer(1024);
 	//
 	//     // 2.
 	//     ssize_t bytes =
diff --git a/cpp/test/Makefile.am b/cpp/test/Makefile.am
new file mode 100644
index 00000000..a80f3194
--- /dev/null
+++ b/cpp/test/Makefile.am
@@ -0,0 +1,26 @@
+
+AM_LDFLAGS = ../libmsgpack.la -lgtest_main
+
+check_PROGRAMS = \
+	zone \
+	pack_unpack \
+	streaming \
+	object \
+	convert \
+	buffer
+
+TESTS = $(check_PROGRAMS)
+
+zone_SOURCES = zone.cc
+
+pack_unpack_SOURCES = pack_unpack.cc
+
+streaming_SOURCES = streaming.cc
+
+object_SOURCES = object.cc
+
+convert_SOURCES = convert.cc
+
+buffer_SOURCES = buffer.cc
+buffer_LDADD = -lz
+
diff --git a/cpp/test/buffer.cc b/cpp/test/buffer.cc
new file mode 100644
index 00000000..a2e90378
--- /dev/null
+++ b/cpp/test/buffer.cc
@@ -0,0 +1,50 @@
+#include <msgpack.hpp>
+#include <msgpack/zbuffer.hpp>
+#include <gtest/gtest.h>
+#include <string.h>
+
+TEST(buffer, sbuffer)
+{
+	msgpack::sbuffer sbuf;
+	sbuf.write("a", 1);
+	sbuf.write("a", 1);
+	sbuf.write("a", 1);
+
+	EXPECT_EQ(3, sbuf.size());
+	EXPECT_TRUE( memcmp(sbuf.data(), "aaa", 3) == 0 );
+}
+
+
+TEST(buffer, vrefbuffer)
+{
+	msgpack::vrefbuffer vbuf;
+	vbuf.write("a", 1);
+	vbuf.write("a", 1);
+	vbuf.write("a", 1);
+
+	const struct iovec* vec = vbuf.vector();
+	size_t veclen = vbuf.vector_size();
+
+	msgpack::sbuffer sbuf;
+	for(size_t i=0; i < veclen; ++i) {
+		sbuf.write((const char*)vec[i].iov_base, vec[i].iov_len);
+	}
+
+	EXPECT_EQ(3, sbuf.size());
+	EXPECT_TRUE( memcmp(sbuf.data(), "aaa", 3) == 0 );
+}
+
+
+TEST(buffer, zbuffer)
+{
+	msgpack::zbuffer zbuf;
+	zbuf.write("a", 1);
+	zbuf.write("a", 1);
+	zbuf.write("a", 1);
+
+	zbuf.flush();
+
+	char* data = zbuf.data();
+	size_t size = zbuf.size();
+}
+
diff --git a/cpp/test/convert.cc b/cpp/test/convert.cc
new file mode 100644
index 00000000..f2a85237
--- /dev/null
+++ b/cpp/test/convert.cc
@@ -0,0 +1,74 @@
+#include <msgpack.hpp>
+#include <gtest/gtest.h>
+
+class compatibility {
+public:
+	compatibility() : str1("default"), str2("default") { }
+
+	std::string str1;
+	std::string str2;
+
+	MSGPACK_DEFINE(str1, str2);
+};
+
+TEST(convert, compatibility_less)
+{
+	std::vector<std::string> src(1);
+	src[0] = "kumofs";
+
+	msgpack::zone z;
+	msgpack::object obj(src, &z);
+
+	compatibility c;
+	EXPECT_NO_THROW( obj.convert(&c) );
+
+	EXPECT_EQ("kumofs",  c.str1);
+	EXPECT_EQ("default", c.str2);
+}
+
+TEST(convert, compatibility_more)
+{
+	std::vector<std::string> src(3);
+	src[0] = "kumofs";
+	src[1] = "mpio";
+	src[2] = "cloudy";
+
+	msgpack::zone z;
+	msgpack::object obj(src, &z);
+
+	compatibility to;
+	EXPECT_NO_THROW( obj.convert(&to) );
+
+	EXPECT_EQ("kumofs", to.str1);
+	EXPECT_EQ("mpio",   to.str2);
+}
+
+
+class enum_member {
+public:
+	enum_member() : flag(A) { }
+
+	enum flags_t {
+		A = 0,
+		B = 1,
+	};
+
+	flags_t flag;
+
+	MSGPACK_DEFINE((int&)flag);
+};
+
+TEST(convert, enum_member)
+{
+	enum_member src;
+	src.flag = enum_member::B;
+
+	msgpack::zone z;
+	msgpack::object obj(src, &z);
+
+	enum_member to;
+	EXPECT_NO_THROW( obj.convert(&to) );
+
+	EXPECT_EQ(enum_member::B, to.flag);
+}
+
diff --git a/cpp/test/object.cc b/cpp/test/object.cc
new file mode 100644
index 00000000..5390c4ae
--- /dev/null
+++ b/cpp/test/object.cc
@@ -0,0 +1,134 @@
+#include <msgpack.hpp>
+#include <gtest/gtest.h>
+
+struct myclass {
+	myclass() : num(0), str("default") { }
+
+	myclass(int num, const std::string& str) :
+		num(0), str("default") { }
+
+	~myclass() { }
+
+	int num;
+	std::string str;
+
+	MSGPACK_DEFINE(num, str);
+
+	bool operator==(const myclass& o) const
+	{
+		return num == o.num && str == o.str;
+	}
+};
+
+std::ostream& operator<<(std::ostream& o, const myclass& m)
+{
+	return o << "myclass("<<m.num<<",\""<<m.str<<"\")";
+}
+
+
+TEST(object, convert)
+{
+	myclass m1;
+
+	msgpack::sbuffer sbuf;
+	msgpack::pack(sbuf, m1);
+
+	msgpack::zone z;
+	msgpack::object obj;
+
+	msgpack::unpack_return ret =
+		msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &z, &obj);
+	EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
+
+	myclass m2;
+	obj.convert(&m2);
+
+	EXPECT_EQ(m1, m2);
+}
+
+
+TEST(object, as)
+{
+	myclass m1;
+
+	msgpack::sbuffer sbuf;
+	msgpack::pack(sbuf, m1);
+
+	msgpack::zone z;
+	msgpack::object obj;
+
+	msgpack::unpack_return ret =
+		msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &z, &obj);
+	EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
+
+	EXPECT_EQ(m1, obj.as<myclass>());
+}
+
+
+TEST(object, print)
+{
+	msgpack::object obj;
+	std::cout << obj << std::endl;
+}
+
+
+TEST(object, is_nil)
+{
+	msgpack::object obj;
+	EXPECT_TRUE(obj.is_nil());
+}
+
+
+TEST(object, type_error)
+{
+	msgpack::object obj(1);
+	EXPECT_THROW(obj.as<std::string>(), msgpack::type_error);
+	EXPECT_THROW(obj.as<std::vector<int> >(), msgpack::type_error);
+	EXPECT_EQ(1, obj.as<int>());
+	EXPECT_EQ(1, obj.as<short>());
+	EXPECT_EQ(1u, obj.as<unsigned int>());
+	EXPECT_EQ(1u, obj.as<unsigned long>());
+}
+
+
+TEST(object, equal_primitive)
+{
+	msgpack::object obj_nil;
+	EXPECT_EQ(obj_nil, msgpack::object());
+
+	msgpack::object obj_int(1);
+	EXPECT_EQ(obj_int, msgpack::object(1));
+	EXPECT_EQ(obj_int, 1);
+
+	msgpack::object obj_double(1.2);
+	EXPECT_EQ(obj_double, msgpack::object(1.2));
+	EXPECT_EQ(obj_double, 1.2);
+
+	msgpack::object obj_bool(true);
+	EXPECT_EQ(obj_bool, msgpack::object(true));
+	EXPECT_EQ(obj_bool, true);
+}
+
+
+TEST(object, construct_primitive)
+{
+	msgpack::object obj_nil;
+	EXPECT_EQ(msgpack::type::NIL, obj_nil.type);
+
+	msgpack::object obj_uint(1);
+	EXPECT_EQ(msgpack::type::POSITIVE_INTEGER, obj_uint.type);
+	EXPECT_EQ(1u, obj_uint.via.u64);
+
+	msgpack::object obj_int(-1);
+	EXPECT_EQ(msgpack::type::NEGATIVE_INTEGER, obj_int.type);
+	EXPECT_EQ(-1, obj_int.via.i64);
+
+	msgpack::object obj_double(1.2);
+	EXPECT_EQ(msgpack::type::DOUBLE, obj_double.type);
+	EXPECT_EQ(1.2, obj_double.via.dec);
+
+	msgpack::object obj_bool(true);
+	EXPECT_EQ(msgpack::type::BOOLEAN, obj_bool.type);
+	EXPECT_EQ(true, obj_bool.via.boolean);
+}
+
diff --git a/cpp/test/pack_unpack.cc b/cpp/test/pack_unpack.cc
new file mode 100644
index 00000000..ecf52c5a
--- /dev/null
+++ b/cpp/test/pack_unpack.cc
@@ -0,0 +1,101 @@
+#include <msgpack.hpp>
+#include <gtest/gtest.h>
+#include <sstream>
+
+TEST(pack, num)
+{
+	msgpack::sbuffer sbuf;
+	msgpack::pack(sbuf, 1);
+}
+
+
+TEST(pack, vector)
+{
+	msgpack::sbuffer sbuf;
+	std::vector<int> vec;
+	vec.push_back(1);
+	vec.push_back(2);
+	vec.push_back(3);
+	msgpack::pack(sbuf, vec);
+}
+
+
+TEST(pack, to_ostream)
+{
+	std::ostringstream stream;
+	msgpack::pack(stream, 1);
+}
+
+
+struct myclass {
+	myclass() : num(0), str("default") { }
+
+	myclass(int num, const std::string& str) :
+		num(0), str("default") { }
+
+	~myclass() { }
+
+	int num;
+	std::string str;
+
+	MSGPACK_DEFINE(num, str);
+};
+
+
+TEST(pack, myclass)
+{
+	msgpack::sbuffer sbuf;
+	myclass m(1, "msgpack");
+	msgpack::pack(sbuf, m);
+}
+
+
+TEST(unpack, myclass)
+{
+	msgpack::sbuffer sbuf;
+	myclass m1(1, "phraser");
+	msgpack::pack(sbuf, m1);
+
+	msgpack::zone z;
+	msgpack::object obj;
+
+	msgpack::unpack_return ret =
+		msgpack::unpack(sbuf.data(), sbuf.size(), NULL, &z, &obj);
+
+	EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
+
+	myclass m2 = obj.as<myclass>();
+	EXPECT_EQ(m1.num, m2.num);
+	EXPECT_EQ(m1.str, m2.str);
+}
+
+
+TEST(unpack, sequence)
+{
+	msgpack::sbuffer sbuf;
+	msgpack::pack(sbuf, 1);
+	msgpack::pack(sbuf, 2);
+	msgpack::pack(sbuf, 3);
+
+	size_t offset = 0;
+
+	msgpack::zone z;
+	msgpack::object obj;
+	msgpack::unpack_return ret;
+
+	ret = msgpack::unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj);
+	EXPECT_TRUE(ret >= 0);
+	EXPECT_EQ(ret, msgpack::UNPACK_EXTRA_BYTES);
+	EXPECT_EQ(1, obj.as<int>());
+
+	ret = msgpack::unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj);
+	EXPECT_TRUE(ret >= 0);
+	EXPECT_EQ(ret, msgpack::UNPACK_EXTRA_BYTES);
+	EXPECT_EQ(2, obj.as<int>());
+
+	ret = msgpack::unpack(sbuf.data(), sbuf.size(), &offset, &z, &obj);
+	EXPECT_TRUE(ret >= 0);
+	EXPECT_EQ(ret, msgpack::UNPACK_SUCCESS);
+	EXPECT_EQ(3, obj.as<int>());
+}
+
diff --git a/cpp/test/streaming.cc b/cpp/test/streaming.cc
new file mode 100644
index 00000000..2d03976a
--- /dev/null
+++ b/cpp/test/streaming.cc
@@ -0,0 +1,109 @@
+#include <msgpack.hpp>
+#include <gtest/gtest.h>
+#include <sstream>
+
+TEST(streaming, basic)
+{
+	std::ostringstream stream;
+	msgpack::packer<std::ostream> pk(&stream);
+
+	pk.pack(1);
+	pk.pack(2);
+	pk.pack(3);
+
+	std::istringstream input(stream.str());
+
+	msgpack::unpacker pac;
+
+	int count = 0;
+	while(count < 3) {
+		pac.reserve_buffer(32*1024);
+
+		size_t len = input.readsome(pac.buffer(), pac.buffer_capacity());
+		pac.buffer_consumed(len);
+
+		while(pac.execute()) {
+			std::auto_ptr<msgpack::zone> z(pac.release_zone());
+			msgpack::object obj = pac.data();
+			pac.reset();
+
+			switch(count++) {
+			case 0:
+				EXPECT_EQ(1, obj.as<int>());
+				break;
+			case 1:
+				EXPECT_EQ(2, obj.as<int>());
+				break;
+			case 2:
+				EXPECT_EQ(3, obj.as<int>());
+				return;
+			}
+
+		}
+	}
+}
+
+
+class event_handler {
+public:
+	event_handler(std::istream& input) : input(input) { }
+	~event_handler() { }
+
+	void on_read()
+	{
+		while(true) {
+			pac.reserve_buffer(32*1024);
+
+			size_t len = input.readsome(pac.buffer(), pac.buffer_capacity());
+
+			if(len == 0) {
+				return;
+			}
+
+			pac.buffer_consumed(len);
+
+			while(pac.execute()) {
+				std::auto_ptr<msgpack::zone> z(pac.release_zone());
+				msgpack::object obj = pac.data();
+				pac.reset();
+				on_message(obj, z);
+			}
+
+			if(pac.message_size() > 10*1024*1024) {
+				throw std::runtime_error("message is too large");
+			}
+		}
+	}
+
+	void on_message(msgpack::object obj, std::auto_ptr<msgpack::zone> z)
+	{
+		EXPECT_EQ(expect, obj.as<int>());
+	}
+
+	int expect;
+
+private:
+	std::istream& input;
+	msgpack::unpacker pac;
+};
+
+TEST(streaming, event)
+{
+	std::stringstream stream;
+	msgpack::packer<std::ostream> pk(&stream);
+
+	event_handler handler(stream);
+
+	pk.pack(1);
+	handler.expect = 1;
+	handler.on_read();
+
+	pk.pack(2);
+	handler.expect = 2;
+	handler.on_read();
+
+	pk.pack(3);
+	handler.expect = 3;
+	handler.on_read();
+}
+
diff --git a/cpp/test/zone.cc b/cpp/test/zone.cc
new file mode 100644
index 00000000..5274e9f0
--- /dev/null
+++ b/cpp/test/zone.cc
@@ -0,0 +1,78 @@
+#include <msgpack.hpp>
+#include <gtest/gtest.h>
+
+TEST(zone, malloc)
+{
+	msgpack::zone z;
+	char* buf1 = (char*)z.malloc(4);
+	memcpy(buf1, "test", 4);
+	char* buf2 = (char*)z.malloc(4);
+	memcpy(buf2, "test", 4);
+}
+
+
+class myclass {
+public:
+	myclass() : num(0), str("default") { }
+
+	myclass(int num, const std::string& str) :
+		num(num), str(str) { }
+
+	~myclass() { }
+
+	int num;
+	std::string str;
+
+private:
+	myclass(const myclass&);
+};
+
+
+TEST(zone, allocate)
+{
+	msgpack::zone z;
+	myclass* m = z.allocate<myclass>();
+	EXPECT_EQ(m->num, 0);
+	EXPECT_EQ(m->str, "default");
+}
+
+
+TEST(zone, allocate_constructor)
+{
+	msgpack::zone z;
+	myclass* m = z.allocate<myclass>(7, "msgpack");
+	EXPECT_EQ(m->num, 7);
+	EXPECT_EQ(m->str, "msgpack");
+}
+
+
+static void custom_finalizer_func(void* user)
+{
+	myclass* m = (myclass*)user;
+	delete m;
+}
+
+TEST(zone, push_finalizer)
+{
+	msgpack::zone z;
+	myclass* m = new myclass();
+	z.push_finalizer(custom_finalizer_func, (void*)m);
+}
+
+
+TEST(zone, push_finalizer_auto_ptr)
+{
+	msgpack::zone z;
+	std::auto_ptr<myclass> am(new myclass());
+	z.push_finalizer(am);
+}
+
+
+TEST(zone, malloc_no_align)
+{
+	msgpack::zone z;
+	char* buf1 = (char*)z.malloc_no_align(4);
+	char* buf2 = (char*)z.malloc_no_align(4);
+	EXPECT_EQ(buf1+4, buf2);
+}
+