Port tests to pytest

Use simple asserts and pytest's powerful introspection to make testing
simpler. This merges the old .py/.ref file pairs into simple .py files
where the expected values are right next to the code being tested.

This commit does not touch the C++ part of the code and replicates the
Python tests exactly like the old .ref-file-based approach.
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..f433929
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,62 @@
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+  message(STATUS "Setting tests build type to MinSizeRel as none was specified")
+  set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "Choose the type of build" FORCE)
+endif()
+
+set(PYBIND11_TEST_FILES
+  test_buffers.cpp
+  test_callbacks.cpp
+  test_constants_and_functions.cpp
+  test_eval.cpp
+  test_exceptions.cpp
+  test_inheritance.cpp
+  test_issues.cpp
+  test_keep_alive.cpp
+  test_kwargs_and_defaults.cpp
+  test_methods_and_attributes.cpp
+  test_modules.cpp
+  test_numpy_dtypes.cpp
+  test_numpy_vectorize.cpp
+  test_opaque_types.cpp
+  test_operator_overloading.cpp
+  test_pickling.cpp
+  test_python_types.cpp
+  test_sequences_and_iterators.cpp
+  test_smart_ptr.cpp
+  test_stl_binders.cpp
+  test_virtual_functions.cpp
+)
+
+# Check if Eigen is available
+find_package(Eigen3 QUIET)
+
+if(EIGEN3_FOUND)
+  list(APPEND PYBIND11_TEST_FILES test_eigen.cpp)
+  message(STATUS "Building tests with Eigen v${EIGEN3_VERSION}")
+else()
+  message(STATUS "Building tests WITHOUT Eigen")
+endif()
+
+# Create the binding library
+pybind11_add_module(pybind11_tests pybind11_tests.cpp ${PYBIND11_TEST_FILES})
+pybind11_enable_warnings(pybind11_tests)
+
+if(EIGEN3_FOUND)
+  target_include_directories(pybind11_tests PRIVATE ${EIGEN3_INCLUDE_DIR})
+  target_compile_definitions(pybind11_tests PRIVATE -DPYBIND11_TEST_EIGEN)
+endif()
+
+set(testdir ${PROJECT_SOURCE_DIR}/tests)
+
+# Always write the output file directly into the 'tests' directory (even on MSVC)
+if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
+  set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${testdir})
+  foreach(config ${CMAKE_CONFIGURATION_TYPES})
+    string(TOUPPER ${config} config)
+    set_target_properties(pybind11_tests PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${config} ${testdir})
+  endforeach()
+endif()
+
+# A single command to compile and run the tests
+add_custom_target(pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest
+                  DEPENDS pybind11_tests WORKING_DIRECTORY ${testdir})
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..5641392
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,204 @@
+"""pytest configuration
+
+Extends output capture as needed by pybind11: ignore constructors, optional unordered lines.
+Adds docstring and exceptions message sanitizers: ignore Python 2 vs 3 differences.
+"""
+
+import pytest
+import textwrap
+import difflib
+import re
+import os
+import sys
+import contextlib
+
+_unicode_marker = re.compile(r'u(\'[^\']*\')')
+_long_marker    = re.compile(r'([0-9])L')
+_hexadecimal    = re.compile(r'0x[0-9a-fA-F]+')
+
+
+def _strip_and_dedent(s):
+    """For triple-quote strings"""
+    return textwrap.dedent(s.lstrip('\n').rstrip())
+
+
+def _split_and_sort(s):
+    """For output which does not require specific line order"""
+    return sorted(_strip_and_dedent(s).splitlines())
+
+
+def _make_explanation(a, b):
+    """Explanation for a failed assert -- the a and b arguments are List[str]"""
+    return ["--- actual / +++ expected"] + [line.strip('\n') for line in difflib.ndiff(a, b)]
+
+
+class Output(object):
+    """Basic output post-processing and comparison"""
+    def __init__(self, string):
+        self.string = string
+        self.explanation = []
+
+    def __str__(self):
+        return self.string
+
+    def __eq__(self, other):
+        # Ignore constructor/destructor output which is prefixed with "###"
+        a = [line for line in self.string.strip().splitlines() if not line.startswith("###")]
+        b = _strip_and_dedent(other).splitlines()
+        if a == b:
+            return True
+        else:
+            self.explanation = _make_explanation(a, b)
+            return False
+
+
+class Unordered(Output):
+    """Custom comparison for output without strict line ordering"""
+    def __eq__(self, other):
+        a = _split_and_sort(self.string)
+        b = _split_and_sort(other)
+        if a == b:
+            return True
+        else:
+            self.explanation = _make_explanation(a, b)
+            return False
+
+
+class Capture(object):
+    def __init__(self, capfd):
+        self.capfd = capfd
+        self.out = ""
+
+    def _flush_stdout(self):
+        sys.stdout.flush()
+        os.fsync(sys.stdout.fileno())  # make sure C++ output is also read
+        return self.capfd.readouterr()[0]
+
+    def __enter__(self):
+        self._flush_stdout()
+        return self
+
+    def __exit__(self, *_):
+        self.out = self._flush_stdout()
+
+    def __eq__(self, other):
+        a = Output(self.out)
+        b = other
+        if a == b:
+            return True
+        else:
+            self.explanation = a.explanation
+            return False
+
+    def __str__(self):
+        return self.out
+
+    def __contains__(self, item):
+        return item in self.out
+
+    @property
+    def unordered(self):
+        return Unordered(self.out)
+
+
+@pytest.fixture
+def capture(capfd):
+    """Extended `capfd` with context manager and custom equality operators"""
+    return Capture(capfd)
+
+
+class SanitizedString(object):
+    def __init__(self, sanitizer):
+        self.sanitizer = sanitizer
+        self.string = ""
+        self.explanation = []
+
+    def __call__(self, thing):
+        self.string = self.sanitizer(thing)
+        return self
+
+    def __eq__(self, other):
+        a = self.string
+        b = _strip_and_dedent(other)
+        if a == b:
+            return True
+        else:
+            self.explanation = _make_explanation(a.splitlines(), b.splitlines())
+            return False
+
+
+def _sanitize_general(s):
+    s = s.strip()
+    s = s.replace("pybind11_tests.", "m.")
+    s = s.replace("unicode", "str")
+    s = _long_marker.sub(r"\1", s)
+    s = _unicode_marker.sub(r"\1", s)
+    return s
+
+
+def _sanitize_docstring(thing):
+    s = thing.__doc__
+    s = _sanitize_general(s)
+    return s
+
+
+@pytest.fixture
+def doc():
+    """Sanitize docstrings and add custom failure explanation"""
+    return SanitizedString(_sanitize_docstring)
+
+
+def _sanitize_message(thing):
+    s = str(thing)
+    s = _sanitize_general(s)
+    s = _hexadecimal.sub("0", s)
+    return s
+
+
+@pytest.fixture
+def msg():
+    """Sanitize messages and add custom failure explanation"""
+    return SanitizedString(_sanitize_message)
+
+
+# noinspection PyUnusedLocal
+def pytest_assertrepr_compare(op, left, right):
+    """Hook to insert custom failure explanation"""
+    if hasattr(left, 'explanation'):
+        return left.explanation
+
+
+@contextlib.contextmanager
+def suppress(exception):
+    """Suppress the desired exception"""
+    try:
+        yield
+    except exception:
+        pass
+
+
+def pytest_namespace():
+    """Add import suppression and test requirements to `pytest` namespace"""
+    try:
+        import numpy as np
+    except ImportError:
+        np = None
+    try:
+        import scipy
+    except ImportError:
+        scipy = None
+    try:
+        from pybind11_tests import have_eigen
+    except ImportError:
+        have_eigen = False
+
+    skipif = pytest.mark.skipif
+    return {
+        'suppress': suppress,
+        'requires_numpy': skipif(not np, reason="numpy is not installed"),
+        'requires_scipy': skipif(not np, reason="scipy is not installed"),
+        'requires_eigen_and_numpy': skipif(not have_eigen or not np,
+                                           reason="eigen and/or numpy are not installed"),
+        'requires_eigen_and_scipy': skipif(not have_eigen or not scipy,
+                                           reason="eigen and/or scipy are not installed"),
+    }
diff --git a/tests/constructor_stats.h b/tests/constructor_stats.h
new file mode 100644
index 0000000..757ebf9
--- /dev/null
+++ b/tests/constructor_stats.h
@@ -0,0 +1,246 @@
+#pragma once
+/*
+    tests/constructor_stats.h -- framework for printing and tracking object
+    instance lifetimes in example/test code.
+
+    Copyright (c) 2016 Jason Rhinelander <jason@imaginary.ca>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+
+This header provides a few useful tools for writing examples or tests that want to check and/or
+display object instance lifetimes.  It requires that you include this header and add the following
+function calls to constructors:
+
+    class MyClass {
+        MyClass() { ...; print_default_created(this); }
+        ~MyClass() { ...; print_destroyed(this); }
+        MyClass(const MyClass &c) { ...; print_copy_created(this); }
+        MyClass(MyClass &&c) { ...; print_move_created(this); }
+        MyClass(int a, int b) { ...; print_created(this, a, b); }
+        MyClass &operator=(const MyClass &c) { ...; print_copy_assigned(this); }
+        MyClass &operator=(MyClass &&c) { ...; print_move_assigned(this); }
+
+        ...
+    }
+
+You can find various examples of these in several of the existing example .cpp files.  (Of course
+you don't need to add any of the above constructors/operators that you don't actually have, except
+for the destructor).
+
+Each of these will print an appropriate message such as:
+
+    ### MyClass @ 0x2801910 created via default constructor
+    ### MyClass @ 0x27fa780 created 100 200
+    ### MyClass @ 0x2801910 destroyed
+    ### MyClass @ 0x27fa780 destroyed
+
+You can also include extra arguments (such as the 100, 200 in the output above, coming from the
+value constructor) for all of the above methods which will be included in the output.
+
+For testing, each of these also keeps track the created instances and allows you to check how many
+of the various constructors have been invoked from the Python side via code such as:
+
+    from example import ConstructorStats
+    cstats = ConstructorStats.get(MyClass)
+    print(cstats.alive())
+    print(cstats.default_constructions)
+
+Note that `.alive()` should usually be the first thing you call as it invokes Python's garbage
+collector to actually destroy objects that aren't yet referenced.
+
+For everything except copy and move constructors and destructors, any extra values given to the
+print_...() function is stored in a class-specific values list which you can retrieve and inspect
+from the ConstructorStats instance `.values()` method.
+
+In some cases, when you need to track instances of a C++ class not registered with pybind11, you
+need to add a function returning the ConstructorStats for the C++ class; this can be done with:
+
+    m.def("get_special_cstats", &ConstructorStats::get<SpecialClass>, py::return_value_policy::reference_internal)
+
+Finally, you can suppress the output messages, but keep the constructor tracking (for
+inspection/testing in python) by using the functions with `print_` replaced with `track_` (e.g.
+`track_copy_created(this)`).
+
+*/
+
+#include "pybind11_tests.h"
+#include <unordered_map>
+#include <list>
+#include <typeindex>
+#include <sstream>
+
+class ConstructorStats {
+protected:
+    std::unordered_map<void*, int> _instances; // Need a map rather than set because members can shared address with parents
+    std::list<std::string> _values; // Used to track values (e.g. of value constructors)
+public:
+    int default_constructions = 0;
+    int copy_constructions = 0;
+    int move_constructions = 0;
+    int copy_assignments = 0;
+    int move_assignments = 0;
+
+    void copy_created(void *inst) {
+        created(inst);
+        copy_constructions++;
+    }
+    void move_created(void *inst) {
+        created(inst);
+        move_constructions++;
+    }
+    void default_created(void *inst) {
+        created(inst);
+        default_constructions++;
+    }
+    void created(void *inst) {
+        ++_instances[inst];
+    };
+    void destroyed(void *inst) {
+        if (--_instances[inst] < 0)
+            throw std::runtime_error("cstats.destroyed() called with unknown instance; potential double-destruction or a missing cstats.created()");
+    }
+
+    int alive() {
+        // Force garbage collection to ensure any pending destructors are invoked:
+        py::module::import("gc").attr("collect").operator py::object()();
+        int total = 0;
+        for (const auto &p : _instances) if (p.second > 0) total += p.second;
+        return total;
+    }
+
+    void value() {} // Recursion terminator
+    // Takes one or more values, converts them to strings, then stores them.
+    template <typename T, typename... Tmore> void value(const T &v, Tmore &&...args) {
+        std::ostringstream oss;
+        oss << v;
+        _values.push_back(oss.str());
+        value(std::forward<Tmore>(args)...);
+    }
+
+    // Move out stored values
+    py::list values() {
+        py::list l;
+        for (const auto &v : _values) l.append(py::cast(v));
+        _values.clear();
+        return l;
+    }
+
+    // Gets constructor stats from a C++ type index
+    static ConstructorStats& get(std::type_index type) {
+        static std::unordered_map<std::type_index, ConstructorStats> all_cstats;
+        return all_cstats[type];
+    }
+
+    // Gets constructor stats from a C++ type
+    template <typename T> static ConstructorStats& get() {
+        return get(typeid(T));
+    }
+
+    // Gets constructor stats from a Python class
+    static ConstructorStats& get(py::object class_) {
+        auto &internals = py::detail::get_internals();
+        const std::type_index *t1 = nullptr, *t2 = nullptr;
+        try {
+            auto *type_info = internals.registered_types_py.at(class_.ptr());
+            for (auto &p : internals.registered_types_cpp) {
+                if (p.second == type_info) {
+                    if (t1) {
+                        t2 = &p.first;
+                        break;
+                    }
+                    t1 = &p.first;
+                }
+            }
+        }
+        catch (std::out_of_range) {}
+        if (!t1) throw std::runtime_error("Unknown class passed to ConstructorStats::get()");
+        auto &cs1 = get(*t1);
+        // If we have both a t1 and t2 match, one is probably the trampoline class; return whichever
+        // has more constructions (typically one or the other will be 0)
+        if (t2) {
+            auto &cs2 = get(*t2);
+            int cs1_total = cs1.default_constructions + cs1.copy_constructions + cs1.move_constructions + (int) cs1._values.size();
+            int cs2_total = cs2.default_constructions + cs2.copy_constructions + cs2.move_constructions + (int) cs2._values.size();
+            if (cs2_total > cs1_total) return cs2;
+        }
+        return cs1;
+    }
+};
+
+// To track construction/destruction, you need to call these methods from the various
+// constructors/operators.  The ones that take extra values record the given values in the
+// constructor stats values for later inspection.
+template <class T> void track_copy_created(T *inst) { ConstructorStats::get<T>().copy_created(inst); }
+template <class T> void track_move_created(T *inst) { ConstructorStats::get<T>().move_created(inst); }
+template <class T, typename... Values> void track_copy_assigned(T *, Values &&...values) {
+    auto &cst = ConstructorStats::get<T>();
+    cst.copy_assignments++;
+    cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_move_assigned(T *, Values &&...values) {
+    auto &cst = ConstructorStats::get<T>();
+    cst.move_assignments++;
+    cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_default_created(T *inst, Values &&...values) {
+    auto &cst = ConstructorStats::get<T>();
+    cst.default_created(inst);
+    cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_created(T *inst, Values &&...values) {
+    auto &cst = ConstructorStats::get<T>();
+    cst.created(inst);
+    cst.value(std::forward<Values>(values)...);
+}
+template <class T, typename... Values> void track_destroyed(T *inst) {
+    ConstructorStats::get<T>().destroyed(inst);
+}
+template <class T, typename... Values> void track_values(T *, Values &&...values) {
+    ConstructorStats::get<T>().value(std::forward<Values>(values)...);
+}
+
+inline void print_constr_details_more() { std::cout << std::endl; }
+template <typename Head, typename... Tail> void print_constr_details_more(const Head &head, Tail &&...tail) {
+    std::cout << " " << head;
+    print_constr_details_more(std::forward<Tail>(tail)...);
+}
+template <class T, typename... Output> void print_constr_details(T *inst, const std::string &action, Output &&...output) {
+    std::cout << "### " << py::type_id<T>() << " @ " << inst << " " << action;
+    print_constr_details_more(std::forward<Output>(output)...);
+}
+
+// Verbose versions of the above:
+template <class T, typename... Values> void print_copy_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
+    print_constr_details(inst, "created via copy constructor", values...);
+    track_copy_created(inst);
+}
+template <class T, typename... Values> void print_move_created(T *inst, Values &&...values) { // NB: this prints, but doesn't store, given values
+    print_constr_details(inst, "created via move constructor", values...);
+    track_move_created(inst);
+}
+template <class T, typename... Values> void print_copy_assigned(T *inst, Values &&...values) {
+    print_constr_details(inst, "assigned via copy assignment", values...);
+    track_copy_assigned(inst, values...);
+}
+template <class T, typename... Values> void print_move_assigned(T *inst, Values &&...values) {
+    print_constr_details(inst, "assigned via move assignment", values...);
+    track_move_assigned(inst, values...);
+}
+template <class T, typename... Values> void print_default_created(T *inst, Values &&...values) {
+    print_constr_details(inst, "created via default constructor", values...);
+    track_default_created(inst, values...);
+}
+template <class T, typename... Values> void print_created(T *inst, Values &&...values) {
+    print_constr_details(inst, "created", values...);
+    track_created(inst, values...);
+}
+template <class T, typename... Values> void print_destroyed(T *inst, Values &&...values) { // Prints but doesn't store given values
+    print_constr_details(inst, "destroyed", values...);
+    track_destroyed(inst);
+}
+template <class T, typename... Values> void print_values(T *inst, Values &&...values) {
+    print_constr_details(inst, ":", values...);
+    track_values(inst, values...);
+}
+
diff --git a/tests/object.h b/tests/object.h
new file mode 100644
index 0000000..99a6916
--- /dev/null
+++ b/tests/object.h
@@ -0,0 +1,175 @@
+#if !defined(__OBJECT_H)
+#define __OBJECT_H
+
+#include <atomic>
+#include "constructor_stats.h"
+
+/// Reference counted object base class
+class Object {
+public:
+    /// Default constructor
+    Object() { print_default_created(this); }
+
+    /// Copy constructor
+    Object(const Object &) : m_refCount(0) { print_copy_created(this); }
+
+	/// Return the current reference count
+	int getRefCount() const { return m_refCount; };
+
+	/// Increase the object's reference count by one
+	void incRef() const { ++m_refCount; }
+
+	/** \brief Decrease the reference count of
+	 * the object and possibly deallocate it.
+	 *
+	 * The object will automatically be deallocated once
+	 * the reference count reaches zero.
+	 */
+	void decRef(bool dealloc = true) const {
+	    --m_refCount;
+	    if (m_refCount == 0 && dealloc)
+            delete this;
+        else if (m_refCount < 0)
+	        throw std::runtime_error("Internal error: reference count < 0!");
+    }
+
+    virtual std::string toString() const = 0;
+protected:
+	/** \brief Virtual protected deconstructor.
+	 * (Will only be called by \ref ref)
+	 */
+	virtual ~Object() { print_destroyed(this); }
+private:
+    mutable std::atomic<int> m_refCount { 0 };
+};
+
+// Tag class used to track constructions of ref objects.  When we track constructors, below, we
+// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
+// ref_tag.  This lets us check that the total number of ref<Anything> constructors/destructors is
+// correct without having to check each individual ref<Whatever> type individually.
+class ref_tag {};
+
+/**
+ * \brief Reference counting helper
+ *
+ * The \a ref refeference template is a simple wrapper to store a
+ * pointer to an object. It takes care of increasing and decreasing
+ * the reference count of the object. When the last reference goes
+ * out of scope, the associated object will be deallocated.
+ *
+ * \ingroup libcore
+ */
+template <typename T> class ref {
+public:
+	/// Create a nullptr reference
+    ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
+
+    /// Construct a reference from a pointer
+	ref(T *ptr) : m_ptr(ptr) {
+	    if (m_ptr) ((Object *) m_ptr)->incRef();
+
+        print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
+
+	}
+
+	/// Copy constructor
+    ref(const ref &r) : m_ptr(r.m_ptr) {
+        if (m_ptr)
+            ((Object *) m_ptr)->incRef();
+
+        print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
+    }
+
+    /// Move constructor
+    ref(ref &&r) : m_ptr(r.m_ptr) {
+        r.m_ptr = nullptr; 
+
+        print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
+    }
+
+    /// Destroy this reference
+    ~ref() {
+        if (m_ptr)
+            ((Object *) m_ptr)->decRef();
+
+        print_destroyed(this); track_destroyed((ref_tag*) this);
+    }
+
+    /// Move another reference into the current one
+	ref& operator=(ref&& r) {
+        print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
+
+		if (*this == r)
+			return *this;
+		if (m_ptr)
+			((Object *) m_ptr)->decRef();
+		m_ptr = r.m_ptr;
+		r.m_ptr = nullptr;
+		return *this;
+	}
+
+	/// Overwrite this reference with another reference
+	ref& operator=(const ref& r) {
+        print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
+
+		if (m_ptr == r.m_ptr)
+			return *this;
+		if (m_ptr)
+			((Object *) m_ptr)->decRef();
+		m_ptr = r.m_ptr;
+		if (m_ptr)
+			((Object *) m_ptr)->incRef();
+		return *this;
+	}
+
+	/// Overwrite this reference with a pointer to another object
+	ref& operator=(T *ptr) {
+        print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
+
+		if (m_ptr == ptr)
+			return *this;
+		if (m_ptr)
+			((Object *) m_ptr)->decRef();
+		m_ptr = ptr;
+		if (m_ptr)
+			((Object *) m_ptr)->incRef();
+		return *this;
+	}
+
+	/// Compare this reference with another reference
+	bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
+
+	/// Compare this reference with another reference
+	bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
+
+	/// Compare this reference with a pointer
+	bool operator==(const T* ptr) const { return m_ptr == ptr; }
+
+	/// Compare this reference with a pointer
+	bool operator!=(const T* ptr) const { return m_ptr != ptr; }
+
+	/// Access the object referenced by this reference
+	T* operator->() { return m_ptr; }
+
+	/// Access the object referenced by this reference
+	const T* operator->() const { return m_ptr; }
+
+	/// Return a C++ reference to the referenced object
+	T& operator*() { return *m_ptr; }
+
+	/// Return a const C++ reference to the referenced object
+	const T& operator*() const { return *m_ptr; }
+
+	/// Return a pointer to the referenced object
+	operator T* () { return m_ptr; }
+
+	/// Return a const pointer to the referenced object
+	T* get() { return m_ptr; }
+
+	/// Return a pointer to the referenced object
+	const T* get() const { return m_ptr; }
+private:
+	T *m_ptr;
+};
+
+#endif /* __OBJECT_H */
diff --git a/tests/pybind11_tests.cpp b/tests/pybind11_tests.cpp
new file mode 100644
index 0000000..507ede8
--- /dev/null
+++ b/tests/pybind11_tests.cpp
@@ -0,0 +1,87 @@
+/*
+    tests/pybind11_tests.cpp -- pybind example plugin
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+void init_ex_methods_and_attributes(py::module &);
+void init_ex_python_types(py::module &);
+void init_ex_operator_overloading(py::module &);
+void init_ex_constants_and_functions(py::module &);
+void init_ex_callbacks(py::module &);
+void init_ex_sequences_and_iterators(py::module &);
+void init_ex_buffers(py::module &);
+void init_ex_smart_ptr(py::module &);
+void init_ex_modules(py::module &);
+void init_ex_numpy_vectorize(py::module &);
+void init_ex_arg_keywords_and_defaults(py::module &);
+void init_ex_virtual_functions(py::module &);
+void init_ex_keep_alive(py::module &);
+void init_ex_opaque_types(py::module &);
+void init_ex_pickling(py::module &);
+void init_ex_inheritance(py::module &);
+void init_ex_stl_binder_vector(py::module &);
+void init_ex_eval(py::module &);
+void init_ex_custom_exceptions(py::module &);
+void init_ex_numpy_dtypes(py::module &);
+void init_issues(py::module &);
+
+#if defined(PYBIND11_TEST_EIGEN)
+    void init_eigen(py::module &);
+#endif
+
+void bind_ConstructorStats(py::module &m) {
+    py::class_<ConstructorStats>(m, "ConstructorStats")
+        .def("alive", &ConstructorStats::alive)
+        .def("values", &ConstructorStats::values)
+        .def_readwrite("default_constructions", &ConstructorStats::default_constructions)
+        .def_readwrite("copy_assignments", &ConstructorStats::copy_assignments)
+        .def_readwrite("move_assignments", &ConstructorStats::move_assignments)
+        .def_readwrite("copy_constructions", &ConstructorStats::copy_constructions)
+        .def_readwrite("move_constructions", &ConstructorStats::move_constructions)
+        .def_static("get", (ConstructorStats &(*)(py::object)) &ConstructorStats::get, py::return_value_policy::reference_internal)
+        ;
+}
+
+PYBIND11_PLUGIN(pybind11_tests) {
+    py::module m("pybind11_tests", "pybind example plugin");
+
+    bind_ConstructorStats(m);
+
+    init_ex_methods_and_attributes(m);
+    init_ex_python_types(m);
+    init_ex_operator_overloading(m);
+    init_ex_constants_and_functions(m);
+    init_ex_callbacks(m);
+    init_ex_sequences_and_iterators(m);
+    init_ex_buffers(m);
+    init_ex_smart_ptr(m);
+    init_ex_modules(m);
+    init_ex_numpy_vectorize(m);
+    init_ex_arg_keywords_and_defaults(m);
+    init_ex_virtual_functions(m);
+    init_ex_keep_alive(m);
+    init_ex_opaque_types(m);
+    init_ex_pickling(m);
+    init_ex_inheritance(m);
+    init_ex_stl_binder_vector(m);
+    init_ex_eval(m);
+    init_ex_custom_exceptions(m);
+    init_ex_numpy_dtypes(m);
+    init_issues(m);
+
+#if defined(PYBIND11_TEST_EIGEN)
+    init_eigen(m);
+    m.attr("have_eigen") = py::cast(true);
+#else
+    m.attr("have_eigen") = py::cast(false);
+#endif
+
+    return m.ptr();
+}
diff --git a/tests/pybind11_tests.h b/tests/pybind11_tests.h
new file mode 100644
index 0000000..ab8fff7
--- /dev/null
+++ b/tests/pybind11_tests.h
@@ -0,0 +1,7 @@
+#include <pybind11/pybind11.h>
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+namespace py = pybind11;
diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp
new file mode 100644
index 0000000..5a4dc67
--- /dev/null
+++ b/tests/test_buffers.cpp
@@ -0,0 +1,117 @@
+/*
+    tests/test_buffers.cpp -- supporting Pythons' buffer protocol
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+class Matrix {
+public:
+    Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
+        print_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+        m_data = new float[rows*cols];
+        memset(m_data, 0, sizeof(float) * rows * cols);
+    }
+
+    Matrix(const Matrix &s) : m_rows(s.m_rows), m_cols(s.m_cols) {
+        print_copy_created(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+        m_data = new float[m_rows * m_cols];
+        memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
+    }
+
+    Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
+        print_move_created(this);
+        s.m_rows = 0;
+        s.m_cols = 0;
+        s.m_data = nullptr;
+    }
+
+    ~Matrix() {
+        print_destroyed(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+        delete[] m_data;
+    }
+
+    Matrix &operator=(const Matrix &s) {
+        print_copy_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+        delete[] m_data;
+        m_rows = s.m_rows;
+        m_cols = s.m_cols;
+        m_data = new float[m_rows * m_cols];
+        memcpy(m_data, s.m_data, sizeof(float) * m_rows * m_cols);
+        return *this;
+    }
+
+    Matrix &operator=(Matrix &&s) {
+        print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
+        if (&s != this) {
+            delete[] m_data;
+            m_rows = s.m_rows; m_cols = s.m_cols; m_data = s.m_data;
+            s.m_rows = 0; s.m_cols = 0; s.m_data = nullptr;
+        }
+        return *this;
+    }
+
+    float operator()(size_t i, size_t j) const {
+        return m_data[i*m_cols + j];
+    }
+
+    float &operator()(size_t i, size_t j) {
+        return m_data[i*m_cols + j];
+    }
+
+    float *data() { return m_data; }
+
+    size_t rows() const { return m_rows; }
+    size_t cols() const { return m_cols; }
+private:
+    size_t m_rows;
+    size_t m_cols;
+    float *m_data;
+};
+
+void init_ex_buffers(py::module &m) {
+    py::class_<Matrix> mtx(m, "Matrix");
+
+    mtx.def(py::init<size_t, size_t>())
+        /// Construct from a buffer
+        .def("__init__", [](Matrix &v, py::buffer b) {
+            py::buffer_info info = b.request();
+            if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
+                throw std::runtime_error("Incompatible buffer format!");
+            new (&v) Matrix(info.shape[0], info.shape[1]);
+            memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols());
+        })
+
+       .def("rows", &Matrix::rows)
+       .def("cols", &Matrix::cols)
+
+        /// Bare bones interface
+       .def("__getitem__", [](const Matrix &m, std::pair<size_t, size_t> i) {
+            if (i.first >= m.rows() || i.second >= m.cols())
+                throw py::index_error();
+            return m(i.first, i.second);
+        })
+       .def("__setitem__", [](Matrix &m, std::pair<size_t, size_t> i, float v) {
+            if (i.first >= m.rows() || i.second >= m.cols())
+                throw py::index_error();
+            m(i.first, i.second) = v;
+        })
+       /// Provide buffer access
+       .def_buffer([](Matrix &m) -> py::buffer_info {
+            return py::buffer_info(
+                m.data(),                               /* Pointer to buffer */
+                sizeof(float),                          /* Size of one scalar */
+                py::format_descriptor<float>::format(), /* Python struct-style format descriptor */
+                2,                                      /* Number of dimensions */
+                { m.rows(), m.cols() },                 /* Buffer dimensions */
+                { sizeof(float) * m.rows(),             /* Strides (in bytes) for each index */
+                  sizeof(float) }
+            );
+        })
+        ;
+}
diff --git a/tests/test_buffers.py b/tests/test_buffers.py
new file mode 100644
index 0000000..f0ea964
--- /dev/null
+++ b/tests/test_buffers.py
@@ -0,0 +1,57 @@
+import pytest
+from pybind11_tests import Matrix, ConstructorStats
+
+with pytest.suppress(ImportError):
+    import numpy as np
+
+
+@pytest.requires_numpy
+def test_to_python():
+    m = Matrix(5, 5)
+
+    assert m[2, 3] == 0
+    m[2, 3] = 4
+    assert m[2, 3] == 4
+
+    m2 = np.array(m, copy=False)
+    assert m2.shape == (5, 5)
+    assert abs(m2).sum() == 4
+    assert m2[2, 3] == 4
+    m2[2, 3] = 5
+    assert m2[2, 3] == 5
+
+    cstats = ConstructorStats.get(Matrix)
+    assert cstats.alive() == 1
+    del m
+    assert cstats.alive() == 1
+    del m2  # holds an m reference
+    assert cstats.alive() == 0
+    assert cstats.values() == ["5x5 matrix"]
+    assert cstats.copy_constructions == 0
+    # assert cstats.move_constructions >= 0  # Don't invoke any
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
+
+
+@pytest.requires_numpy
+def test_from_python():
+    with pytest.raises(RuntimeError) as excinfo:
+        Matrix(np.array([1, 2, 3]))  # trying to assign a 1D array
+    assert str(excinfo.value) == "Incompatible buffer format!"
+
+    m3 = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.float32)
+    m4 = Matrix(m3)
+
+    for i in range(m4.rows()):
+        for j in range(m4.cols()):
+            assert m3[i, j] == m4[i, j]
+
+    cstats = ConstructorStats.get(Matrix)
+    assert cstats.alive() == 1
+    del m3, m4
+    assert cstats.alive() == 0
+    assert cstats.values() == ["2x3 matrix"]
+    assert cstats.copy_constructions == 0
+    # assert cstats.move_constructions >= 0  # Don't invoke any
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
diff --git a/tests/test_callbacks.cpp b/tests/test_callbacks.cpp
new file mode 100644
index 0000000..80a0d0e
--- /dev/null
+++ b/tests/test_callbacks.cpp
@@ -0,0 +1,103 @@
+/*
+    tests/test_callbacks.cpp -- callbacks
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/functional.h>
+
+
+bool test_callback1(py::object func) {
+    func();
+    return false;
+}
+
+int test_callback2(py::object func) {
+    py::object result = func("Hello", 'x', true, 5);
+    return result.cast<int>();
+}
+
+void test_callback3(const std::function<int(int)> &func) {
+    cout << "func(43) = " << func(43)<< std::endl;
+}
+
+std::function<int(int)> test_callback4() {
+    return [](int i) { return i+1; };
+}
+
+py::cpp_function test_callback5() {
+    return py::cpp_function([](int i) { return i+1; },
+       py::arg("number"));
+}
+
+int dummy_function(int i) { return i + 1; }
+int dummy_function2(int i, int j) { return i + j; }
+std::function<int(int)> roundtrip(std::function<int(int)> f) { 
+    if (!f)
+        std::cout << "roundtrip (got None).." << std::endl;
+    else
+        std::cout << "roundtrip.." << std::endl;
+    return f;
+}
+
+void test_dummy_function(const std::function<int(int)> &f) {
+    using fn_type = int (*)(int);
+    auto result = f.target<fn_type>();
+    if (!result) {
+        std::cout << "could not convert to a function pointer." << std::endl;
+        auto r = f(1);
+        std::cout << "eval(1) = " << r << std::endl;
+    } else if (*result == dummy_function) {
+        std::cout << "argument matches dummy_function" << std::endl;
+        auto r = (*result)(1);
+        std::cout << "eval(1) = " << r << std::endl;
+    } else {
+        std::cout << "argument does NOT match dummy_function. This should never happen!" << std::endl;
+    }
+}
+
+struct Payload {
+    Payload() {
+        print_default_created(this);
+    }
+    ~Payload() {
+        print_destroyed(this);
+    }
+    Payload(const Payload &) {
+        print_copy_created(this);
+    }
+    Payload(Payload &&) {
+        print_move_created(this);
+    }
+};
+
+void init_ex_callbacks(py::module &m) {
+    m.def("test_callback1", &test_callback1);
+    m.def("test_callback2", &test_callback2);
+    m.def("test_callback3", &test_callback3);
+    m.def("test_callback4", &test_callback4);
+    m.def("test_callback5", &test_callback5);
+
+    /* Test cleanup of lambda closure */
+
+    m.def("test_cleanup", []() -> std::function<void(void)> { 
+        Payload p;
+
+        return [p]() {
+            /* p should be cleaned up when the returned function is garbage collected */
+        };
+    });
+
+    /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
+    m.def("dummy_function", &dummy_function);
+    m.def("dummy_function2", &dummy_function2);
+    m.def("roundtrip", &roundtrip);
+    m.def("test_dummy_function", &test_dummy_function);
+    // Export the payload constructor statistics for testing purposes:
+    m.def("payload_cstats", &ConstructorStats::get<Payload>);
+}
diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py
new file mode 100644
index 0000000..3f70e87
--- /dev/null
+++ b/tests/test_callbacks.py
@@ -0,0 +1,130 @@
+import pytest
+
+
+def test_inheritance(capture, msg):
+    from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_print
+
+    roger = Rabbit('Rabbit')
+    assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
+    with capture:
+        pet_print(roger)
+    assert capture == "Rabbit is a parrot"
+
+    polly = Pet('Polly', 'parrot')
+    assert polly.name() + " is a " + polly.species() == "Polly is a parrot"
+    with capture:
+        pet_print(polly)
+    assert capture == "Polly is a parrot"
+
+    molly = Dog('Molly')
+    assert molly.name() + " is a " + molly.species() == "Molly is a dog"
+    with capture:
+        pet_print(molly)
+    assert capture == "Molly is a dog"
+
+    with capture:
+        dog_bark(molly)
+    assert capture == "Woof!"
+
+    with pytest.raises(TypeError) as excinfo:
+        dog_bark(polly)
+    assert msg(excinfo.value) == """
+        Incompatible function arguments. The following argument types are supported:
+            1. (arg0: m.Dog) -> None
+            Invoked with: <m.Pet object at 0>
+    """
+
+
+def test_callbacks(capture):
+    from functools import partial
+    from pybind11_tests import (test_callback1, test_callback2, test_callback3,
+                                test_callback4, test_callback5)
+
+    def func1():
+        print('Callback function 1 called!')
+
+    def func2(a, b, c, d):
+        print('Callback function 2 called : {}, {}, {}, {}'.format(a, b, c, d))
+        return d
+
+    def func3(a):
+        print('Callback function 3 called : {}'.format(a))
+
+    with capture:
+        assert test_callback1(func1) is False
+    assert capture == "Callback function 1 called!"
+    with capture:
+        assert test_callback2(func2) == 5
+    assert capture == "Callback function 2 called : Hello, x, True, 5"
+    with capture:
+        assert test_callback1(partial(func2, "Hello", "from", "partial", "object")) is False
+    assert capture == "Callback function 2 called : Hello, from, partial, object"
+    with capture:
+        assert test_callback1(partial(func3, "Partial object with one argument")) is False
+    assert capture == "Callback function 3 called : Partial object with one argument"
+    with capture:
+        test_callback3(lambda i: i + 1)
+    assert capture == "func(43) = 44"
+
+    f = test_callback4()
+    assert f(43) == 44
+    f = test_callback5()
+    assert f(number=43) == 44
+
+
+def test_lambda_closure_cleanup():
+    from pybind11_tests import test_cleanup, payload_cstats
+
+    test_cleanup()
+    cstats = payload_cstats()
+    assert cstats.alive() == 0
+    assert cstats.copy_constructions == 1
+    assert cstats.move_constructions >= 1
+
+
+def test_cpp_function_roundtrip(capture):
+    """Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer"""
+    from pybind11_tests import dummy_function, dummy_function2, test_dummy_function, roundtrip
+
+    with capture:
+        test_dummy_function(dummy_function)
+    assert capture == """
+        argument matches dummy_function
+        eval(1) = 2
+    """
+    with capture:
+        test_dummy_function(roundtrip(dummy_function))
+    assert capture == """
+        roundtrip..
+        argument matches dummy_function
+        eval(1) = 2
+    """
+    with capture:
+        assert roundtrip(None) is None
+    assert capture == "roundtrip (got None).."
+    with capture:
+        test_dummy_function(lambda x: x + 2)
+    assert capture == """
+        could not convert to a function pointer.
+        eval(1) = 3
+    """
+
+    with capture:
+        with pytest.raises(TypeError) as excinfo:
+            test_dummy_function(dummy_function2)
+        assert "Incompatible function arguments" in str(excinfo.value)
+    assert capture == "could not convert to a function pointer."
+
+    with capture:
+        with pytest.raises(TypeError) as excinfo:
+            test_dummy_function(lambda x, y: x + y)
+        assert any(s in str(excinfo.value) for s in ("missing 1 required positional argument",
+                                                     "takes exactly 2 arguments"))
+    assert capture == "could not convert to a function pointer."
+
+
+def test_function_signatures(doc):
+    from pybind11_tests import test_callback3, test_callback4
+
+    assert doc(test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> None"
+    assert doc(test_callback4) == "test_callback4() -> Callable[[int], int]"
diff --git a/tests/test_constants_and_functions.cpp b/tests/test_constants_and_functions.cpp
new file mode 100644
index 0000000..1977a0a
--- /dev/null
+++ b/tests/test_constants_and_functions.cpp
@@ -0,0 +1,90 @@
+/*
+    tests/test_constants_and_functions.cpp -- global constants and functions, enumerations, raw byte strings
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+enum EMyEnumeration {
+    EFirstEntry = 1,
+    ESecondEntry
+};
+
+enum class ECMyEnum {
+    Two = 2,
+    Three
+};
+
+class ExampleWithEnum {
+public:
+    enum EMode {
+        EFirstMode = 1,
+        ESecondMode
+    };
+
+    static EMode test_function(EMode mode) {
+        std::cout << "ExampleWithEnum::test_function(enum=" << mode << ")" << std::endl;
+        return mode;
+    }
+};
+
+bool test_function1() {
+    std::cout << "test_function()" << std::endl;
+    return false;
+}
+
+void test_function2(EMyEnumeration k) {
+    std::cout << "test_function(enum=" << k << ")" << std::endl;
+}
+
+float test_function3(int i) {
+    std::cout << "test_function(" << i << ")" << std::endl;
+    return (float) i / 2.f;
+}
+
+void test_ecenum(ECMyEnum z) {
+    std::cout << "test_ecenum(ECMyEnum::" << (z == ECMyEnum::Two ? "Two" : "Three") << ")" << std::endl;
+}
+
+py::bytes return_bytes() {
+    const char *data = "\x01\x00\x02\x00";
+    return std::string(data, 4);
+}
+
+void print_bytes(py::bytes bytes) {
+    std::string value = (std::string) bytes;
+    for (size_t i = 0; i < value.length(); ++i)
+        std::cout << "bytes[" << i << "]=" << (int) value[i] << std::endl;
+}
+
+void init_ex_constants_and_functions(py::module &m) {
+    m.def("test_function", &test_function1);
+    m.def("test_function", &test_function2);
+    m.def("test_function", &test_function3);
+    m.def("test_ecenum", &test_ecenum);
+    m.attr("some_constant") = py::int_(14);
+
+    py::enum_<EMyEnumeration>(m, "EMyEnumeration")
+        .value("EFirstEntry", EFirstEntry)
+        .value("ESecondEntry", ESecondEntry)
+        .export_values();
+
+    py::enum_<ECMyEnum>(m, "ECMyEnum")
+        .value("Two", ECMyEnum::Two)
+        .value("Three", ECMyEnum::Three)
+        ;
+
+    py::class_<ExampleWithEnum> exenum_class(m, "ExampleWithEnum");
+    exenum_class.def_static("test_function", &ExampleWithEnum::test_function);
+    py::enum_<ExampleWithEnum::EMode>(exenum_class, "EMode")
+        .value("EFirstMode", ExampleWithEnum::EFirstMode)
+        .value("ESecondMode", ExampleWithEnum::ESecondMode)
+        .export_values();
+
+    m.def("return_bytes", &return_bytes);
+    m.def("print_bytes", &print_bytes);
+}
diff --git a/tests/test_constants_and_functions.py b/tests/test_constants_and_functions.py
new file mode 100644
index 0000000..119965b
--- /dev/null
+++ b/tests/test_constants_and_functions.py
@@ -0,0 +1,130 @@
+import pytest
+
+
+def test_constants():
+    from pybind11_tests import some_constant
+
+    assert some_constant == 14
+
+
+def test_function_overloading(capture):
+    from pybind11_tests import EMyEnumeration, test_function
+
+    with capture:
+        assert test_function() is False
+        assert test_function(7) == 3.5
+        assert test_function(EMyEnumeration.EFirstEntry) is None
+        assert test_function(EMyEnumeration.ESecondEntry) is None
+    assert capture == """
+        test_function()
+        test_function(7)
+        test_function(enum=1)
+        test_function(enum=2)
+    """
+
+
+def test_unscoped_enum():
+    from pybind11_tests import EMyEnumeration, EFirstEntry
+
+    assert str(EMyEnumeration.EFirstEntry) == "EMyEnumeration.EFirstEntry"
+    assert str(EMyEnumeration.ESecondEntry) == "EMyEnumeration.ESecondEntry"
+    assert str(EFirstEntry) == "EMyEnumeration.EFirstEntry"
+
+    # no TypeError exception for unscoped enum ==/!= int comparisons
+    y = EMyEnumeration.ESecondEntry
+    assert y == 2
+    assert y != 3
+
+    assert int(EMyEnumeration.ESecondEntry) == 2
+    assert str(EMyEnumeration(2)) == "EMyEnumeration.ESecondEntry"
+
+
+def test_scoped_enum(capture):
+    from pybind11_tests import ECMyEnum, test_ecenum
+
+    with capture:
+        test_ecenum(ECMyEnum.Three)
+    assert capture == "test_ecenum(ECMyEnum::Three)"
+    z = ECMyEnum.Two
+    with capture:
+        test_ecenum(z)
+    assert capture == "test_ecenum(ECMyEnum::Two)"
+
+    # expected TypeError exceptions for scoped enum ==/!= int comparisons
+    with pytest.raises(TypeError):
+        assert z == 2
+    with pytest.raises(TypeError):
+        assert z != 3
+
+
+def test_implicit_conversion(capture):
+    from pybind11_tests import ExampleWithEnum
+
+    assert str(ExampleWithEnum.EMode.EFirstMode) == "EMode.EFirstMode"
+    assert str(ExampleWithEnum.EFirstMode) == "EMode.EFirstMode"
+
+    f = ExampleWithEnum.test_function
+    first = ExampleWithEnum.EFirstMode
+    second = ExampleWithEnum.ESecondMode
+
+    with capture:
+        f(first)
+    assert capture == "ExampleWithEnum::test_function(enum=1)"
+
+    with capture:
+        assert f(first) == f(first)
+        assert not f(first) != f(first)
+
+        assert f(first) != f(second)
+        assert not f(first) == f(second)
+
+        assert f(first) == int(f(first))
+        assert not f(first) != int(f(first))
+
+        assert f(first) != int(f(second))
+        assert not f(first) == int(f(second))
+    assert capture == """
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=2)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=2)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=2)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=2)
+    """
+
+    with capture:
+        # noinspection PyDictCreation
+        x = {f(first): 1, f(second): 2}
+        x[f(first)] = 3
+        x[f(second)] = 4
+    assert capture == """
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=2)
+        ExampleWithEnum::test_function(enum=1)
+        ExampleWithEnum::test_function(enum=2)
+    """
+    # Hashing test
+    assert str(x) == "{EMode.EFirstMode: 3, EMode.ESecondMode: 4}"
+
+
+def test_bytes(capture):
+    from pybind11_tests import return_bytes, print_bytes
+
+    with capture:
+        print_bytes(return_bytes())
+    assert capture == """
+        bytes[0]=1
+        bytes[1]=0
+        bytes[2]=2
+        bytes[3]=0
+    """
diff --git a/tests/test_eigen.cpp b/tests/test_eigen.cpp
new file mode 100644
index 0000000..42bb969
--- /dev/null
+++ b/tests/test_eigen.cpp
@@ -0,0 +1,132 @@
+/*
+    tests/eigen.cpp -- automatic conversion of Eigen types
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/eigen.h>
+#include <Eigen/Cholesky>
+
+Eigen::VectorXf double_col(const Eigen::VectorXf& x)
+{ return 2.0f * x; }
+
+Eigen::RowVectorXf double_row(const Eigen::RowVectorXf& x)
+{ return 2.0f * x; }
+
+Eigen::MatrixXf double_mat_cm(const Eigen::MatrixXf& x)
+{ return 2.0f * x; }
+
+// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
+Eigen::MatrixXd cholesky1(Eigen::Ref<Eigen::MatrixXd> &x) { return x.llt().matrixL(); }
+Eigen::MatrixXd cholesky2(const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.llt().matrixL(); }
+Eigen::MatrixXd cholesky3(const Eigen::Ref<Eigen::MatrixXd> &x) { return x.llt().matrixL(); }
+Eigen::MatrixXd cholesky4(Eigen::Ref<const Eigen::MatrixXd> &x) { return x.llt().matrixL(); }
+Eigen::MatrixXd cholesky5(Eigen::Ref<Eigen::MatrixXd> x) { return x.llt().matrixL(); }
+Eigen::MatrixXd cholesky6(Eigen::Ref<const Eigen::MatrixXd> x) { return x.llt().matrixL(); }
+
+typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> MatrixXfRowMajor;
+MatrixXfRowMajor double_mat_rm(const MatrixXfRowMajor& x)
+{ return 2.0f * x; }
+
+void init_eigen(py::module &m) {
+    typedef Eigen::Matrix<float, 5, 6, Eigen::RowMajor> FixedMatrixR;
+    typedef Eigen::Matrix<float, 5, 6> FixedMatrixC;
+    typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> DenseMatrixR;
+    typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> DenseMatrixC;
+    typedef Eigen::SparseMatrix<float, Eigen::RowMajor> SparseMatrixR;
+    typedef Eigen::SparseMatrix<float> SparseMatrixC;
+
+    // Non-symmetric matrix with zero elements
+    Eigen::MatrixXf mat(5, 6);
+    mat << 0, 3, 0, 0, 0, 11, 22, 0, 0, 0, 17, 11, 7, 5, 0, 1, 0, 11, 0,
+        0, 0, 0, 0, 11, 0, 0, 14, 0, 8, 11;
+
+    m.def("double_col", &double_col);
+    m.def("double_row", &double_row);
+    m.def("double_mat_cm", &double_mat_cm);
+    m.def("double_mat_rm", &double_mat_rm);
+    m.def("cholesky1", &cholesky1);
+    m.def("cholesky2", &cholesky2);
+    m.def("cholesky3", &cholesky3);
+    m.def("cholesky4", &cholesky4);
+    m.def("cholesky5", &cholesky5);
+    m.def("cholesky6", &cholesky6);
+
+    // Returns diagonals: a vector-like object with an inner stride != 1
+    m.def("diagonal", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal(); });
+    m.def("diagonal_1", [](const Eigen::Ref<const Eigen::MatrixXd> &x) { return x.diagonal<1>(); });
+    m.def("diagonal_n", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int index) { return x.diagonal(index); });
+
+    // Return a block of a matrix (gives non-standard strides)
+    m.def("block", [](const Eigen::Ref<const Eigen::MatrixXd> &x, int start_row, int start_col, int block_rows, int block_cols) {
+        return x.block(start_row, start_col, block_rows, block_cols);
+    });
+
+    // Returns a DiagonalMatrix with diagonal (1,2,3,...)
+    m.def("incr_diag", [](int k) {
+        Eigen::DiagonalMatrix<int, Eigen::Dynamic> m(k);
+        for (int i = 0; i < k; i++) m.diagonal()[i] = i+1;
+        return m;
+    });
+
+    // Returns a SelfAdjointView referencing the lower triangle of m
+    m.def("symmetric_lower", [](const Eigen::MatrixXi &m) {
+            return m.selfadjointView<Eigen::Lower>();
+    });
+    // Returns a SelfAdjointView referencing the lower triangle of m
+    m.def("symmetric_upper", [](const Eigen::MatrixXi &m) {
+            return m.selfadjointView<Eigen::Upper>();
+    });
+
+    m.def("fixed_r", [mat]() -> FixedMatrixR { 
+        return FixedMatrixR(mat);
+    });
+
+    m.def("fixed_c", [mat]() -> FixedMatrixC { 
+        return FixedMatrixC(mat);
+    });
+
+    m.def("fixed_passthrough_r", [](const FixedMatrixR &m) -> FixedMatrixR { 
+        return m;
+    });
+
+    m.def("fixed_passthrough_c", [](const FixedMatrixC &m) -> FixedMatrixC { 
+        return m;
+    });
+
+    m.def("dense_r", [mat]() -> DenseMatrixR { 
+        return DenseMatrixR(mat);
+    });
+
+    m.def("dense_c", [mat]() -> DenseMatrixC { 
+        return DenseMatrixC(mat);
+    });
+
+    m.def("dense_passthrough_r", [](const DenseMatrixR &m) -> DenseMatrixR { 
+        return m;
+    });
+
+    m.def("dense_passthrough_c", [](const DenseMatrixC &m) -> DenseMatrixC { 
+        return m;
+    });
+
+    m.def("sparse_r", [mat]() -> SparseMatrixR { 
+        return Eigen::SparseView<Eigen::MatrixXf>(mat);
+    });
+
+    m.def("sparse_c", [mat]() -> SparseMatrixC { 
+        return Eigen::SparseView<Eigen::MatrixXf>(mat);
+    });
+
+    m.def("sparse_passthrough_r", [](const SparseMatrixR &m) -> SparseMatrixR { 
+        return m;
+    });
+
+    m.def("sparse_passthrough_c", [](const SparseMatrixC &m) -> SparseMatrixC { 
+        return m;
+    });
+}
diff --git a/tests/test_eigen.py b/tests/test_eigen.py
new file mode 100644
index 0000000..43cc2fb
--- /dev/null
+++ b/tests/test_eigen.py
@@ -0,0 +1,136 @@
+import pytest
+
+with pytest.suppress(ImportError):
+    import numpy as np
+
+
+ref = np.array([[ 0,  3,  0,  0,  0, 11],
+                [22,  0,  0,  0, 17, 11],
+                [ 7,  5,  0,  1,  0, 11],
+                [ 0,  0,  0,  0,  0, 11],
+                [ 0,  0, 14,  0,  8, 11]])
+
+
+def assert_equal_ref(mat):
+    np.testing.assert_array_equal(mat, ref)
+
+
+def assert_sparse_equal_ref(sparse_mat):
+    assert_equal_ref(sparse_mat.todense())
+
+
+@pytest.requires_eigen_and_numpy
+def test_fixed():
+    from pybind11_tests import fixed_r, fixed_c, fixed_passthrough_r, fixed_passthrough_c
+
+    assert_equal_ref(fixed_c())
+    assert_equal_ref(fixed_r())
+    assert_equal_ref(fixed_passthrough_r(fixed_r()))
+    assert_equal_ref(fixed_passthrough_c(fixed_c()))
+    assert_equal_ref(fixed_passthrough_r(fixed_c()))
+    assert_equal_ref(fixed_passthrough_c(fixed_r()))
+
+
+@pytest.requires_eigen_and_numpy
+def test_dense():
+    from pybind11_tests import dense_r, dense_c, dense_passthrough_r, dense_passthrough_c
+
+    assert_equal_ref(dense_r())
+    assert_equal_ref(dense_c())
+    assert_equal_ref(dense_passthrough_r(dense_r()))
+    assert_equal_ref(dense_passthrough_c(dense_c()))
+    assert_equal_ref(dense_passthrough_r(dense_c()))
+    assert_equal_ref(dense_passthrough_c(dense_r()))
+
+
+@pytest.requires_eigen_and_numpy
+def test_nonunit_stride_from_python():
+    from pybind11_tests import double_row, double_col, double_mat_cm, double_mat_rm
+
+    counting_mat = np.arange(9.0, dtype=np.float32).reshape((3, 3))
+    first_row = counting_mat[0, :]
+    first_col = counting_mat[:, 0]
+    assert np.array_equal(double_row(first_row), 2.0 * first_row)
+    assert np.array_equal(double_col(first_row), 2.0 * first_row)
+    assert np.array_equal(double_row(first_col), 2.0 * first_col)
+    assert np.array_equal(double_col(first_col), 2.0 * first_col)
+
+    counting_3d = np.arange(27.0, dtype=np.float32).reshape((3, 3, 3))
+    slices = [counting_3d[0, :, :], counting_3d[:, 0, :], counting_3d[:, :, 0]]
+    for slice_idx, ref_mat in enumerate(slices):
+        assert np.array_equal(double_mat_cm(ref_mat), 2.0 * ref_mat)
+        assert np.array_equal(double_mat_rm(ref_mat), 2.0 * ref_mat)
+
+
+@pytest.requires_eigen_and_numpy
+def test_nonunit_stride_to_python():
+    from pybind11_tests import diagonal, diagonal_1, diagonal_n, block
+
+    assert np.all(diagonal(ref) == ref.diagonal())
+    assert np.all(diagonal_1(ref) == ref.diagonal(1))
+    for i in range(-5, 7):
+        assert np.all(diagonal_n(ref, i) == ref.diagonal(i)), "diagonal_n({})".format(i)
+
+    assert np.all(block(ref, 2, 1, 3, 3) == ref[2:5, 1:4])
+    assert np.all(block(ref, 1, 4, 4, 2) == ref[1:, 4:])
+    assert np.all(block(ref, 1, 4, 3, 2) == ref[1:4, 4:])
+
+
+@pytest.requires_eigen_and_numpy
+def test_eigen_ref_to_python():
+    from pybind11_tests import cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6
+
+    chols = [cholesky1, cholesky2, cholesky3, cholesky4, cholesky5, cholesky6]
+    for i, chol in enumerate(chols, start=1):
+        mymat = chol(np.array([[1, 2, 4], [2, 13, 23], [4, 23, 77]]))
+        assert np.all(mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]])), "cholesky{}".format(i)
+
+
+@pytest.requires_eigen_and_numpy
+def test_special_matrix_objects():
+    from pybind11_tests import incr_diag, symmetric_upper, symmetric_lower
+
+    assert np.all(incr_diag(7) == np.diag([1, 2, 3, 4, 5, 6, 7]))
+
+    asymm = np.array([[ 1,  2,  3,  4],
+                      [ 5,  6,  7,  8],
+                      [ 9, 10, 11, 12],
+                      [13, 14, 15, 16]])
+    symm_lower = np.array(asymm)
+    symm_upper = np.array(asymm)
+    for i in range(4):
+        for j in range(i + 1, 4):
+            symm_lower[i, j] = symm_lower[j, i]
+            symm_upper[j, i] = symm_upper[i, j]
+
+    assert np.all(symmetric_lower(asymm) == symm_lower)
+    assert np.all(symmetric_upper(asymm) == symm_upper)
+
+
+@pytest.requires_eigen_and_numpy
+def test_dense_signature(doc):
+    from pybind11_tests import double_col, double_row, double_mat_rm
+
+    assert doc(double_col) == "double_col(arg0: numpy.ndarray[float32[m, 1]]) -> numpy.ndarray[float32[m, 1]]"
+    assert doc(double_row) == "double_row(arg0: numpy.ndarray[float32[1, n]]) -> numpy.ndarray[float32[1, n]]"
+    assert doc(double_mat_rm) == "double_mat_rm(arg0: numpy.ndarray[float32[m, n]]) -> numpy.ndarray[float32[m, n]]"
+
+
+@pytest.requires_eigen_and_scipy
+def test_sparse():
+    from pybind11_tests import sparse_r, sparse_c, sparse_passthrough_r, sparse_passthrough_c
+
+    assert_sparse_equal_ref(sparse_r())
+    assert_sparse_equal_ref(sparse_c())
+    assert_sparse_equal_ref(sparse_passthrough_r(sparse_r()))
+    assert_sparse_equal_ref(sparse_passthrough_c(sparse_c()))
+    assert_sparse_equal_ref(sparse_passthrough_r(sparse_c()))
+    assert_sparse_equal_ref(sparse_passthrough_c(sparse_r()))
+
+
+@pytest.requires_eigen_and_scipy
+def test_sparse_signature(doc):
+    from pybind11_tests import sparse_passthrough_r, sparse_passthrough_c
+
+    assert doc(sparse_passthrough_r) == "sparse_passthrough_r(arg0: scipy.sparse.csr_matrix[float32]) -> scipy.sparse.csr_matrix[float32]"
+    assert doc(sparse_passthrough_c) == "sparse_passthrough_c(arg0: scipy.sparse.csc_matrix[float32]) -> scipy.sparse.csc_matrix[float32]"
diff --git a/tests/test_eval.cpp b/tests/test_eval.cpp
new file mode 100644
index 0000000..21098ac
--- /dev/null
+++ b/tests/test_eval.cpp
@@ -0,0 +1,102 @@
+/*
+    tests/test_eval.cpp -- Usage of eval() and eval_file()
+
+    Copyright (c) 2016 Klemens D. Morgenstern
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+
+#include <pybind11/eval.h>
+#include "pybind11_tests.h"
+
+void example_eval() {
+    py::module main_module = py::module::import("__main__");
+    py::object main_namespace = main_module.attr("__dict__");
+
+    bool ok = false;
+
+    main_module.def("call_test", [&]() -> int {
+        ok = true;
+        return 42;
+    });
+
+    cout << "eval_statements test" << endl;
+
+    auto result = py::eval<py::eval_statements>(
+            "print('Hello World!');\n"
+            "x = call_test();", main_namespace);
+
+    if (ok && result == py::none())
+        cout << "eval_statements passed" << endl;
+    else
+        cout << "eval_statements failed" << endl;
+
+    cout << "eval test" << endl;
+
+    py::object val = py::eval("x", main_namespace);
+
+    if (val.cast<int>() == 42)
+        cout << "eval passed" << endl;
+    else
+        cout << "eval failed" << endl;
+
+    ok = false;
+    cout << "eval_single_statement test" << endl;
+
+    py::eval<py::eval_single_statement>(
+        "y = call_test();", main_namespace);
+
+    if (ok)
+        cout << "eval_single_statement passed" << endl;
+    else
+        cout << "eval_single_statement failed" << endl;
+
+    cout << "eval_file test" << endl;
+
+    int val_out;
+    main_module.def("call_test2", [&](int value) {val_out = value;});
+
+    try {
+        result = py::eval_file("test_eval_call.py", main_namespace);
+    } catch (...) {
+        result = py::eval_file("tests/test_eval_call.py", main_namespace);
+    }
+
+    if (val_out == 42 && result == py::none())
+        cout << "eval_file passed" << endl;
+    else
+        cout << "eval_file failed" << endl;
+
+    ok = false;
+    cout << "eval failure test" << endl;
+    try {
+        py::eval("nonsense code ...");
+    } catch (py::error_already_set &) {
+        PyErr_Clear();
+        ok = true;
+    }
+
+    if (ok)
+        cout << "eval failure test passed" << endl;
+    else
+        cout << "eval failure test failed" << endl;
+
+    ok = false;
+    cout << "eval_file failure test" << endl;
+    try {
+        py::eval_file("nonexisting file");
+    } catch (std::exception &) {
+        ok = true;
+    }
+
+    if (ok)
+        cout << "eval_file failure test passed" << endl;
+    else
+        cout << "eval_file failure test failed" << endl;
+}
+
+void init_ex_eval(py::module & m) {
+    m.def("example_eval", &example_eval);
+}
diff --git a/tests/test_eval.py b/tests/test_eval.py
new file mode 100644
index 0000000..2d7611c
--- /dev/null
+++ b/tests/test_eval.py
@@ -0,0 +1,22 @@
+
+
+def test_eval(capture):
+    from pybind11_tests import example_eval
+
+    with capture:
+        example_eval()
+    assert capture == """
+        eval_statements test
+        Hello World!
+        eval_statements passed
+        eval test
+        eval passed
+        eval_single_statement test
+        eval_single_statement passed
+        eval_file test
+        eval_file passed
+        eval failure test
+        eval failure test passed
+        eval_file failure test
+        eval_file failure test passed
+    """
diff --git a/tests/test_eval_call.py b/tests/test_eval_call.py
new file mode 100644
index 0000000..b8a7603
--- /dev/null
+++ b/tests/test_eval_call.py
@@ -0,0 +1,4 @@
+# This file is called from 'test_eval.py'
+
+if 'call_test2' in globals():
+    call_test2(y)
diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp
new file mode 100644
index 0000000..492308f
--- /dev/null
+++ b/tests/test_exceptions.cpp
@@ -0,0 +1,108 @@
+/*
+    tests/test_custom-exceptions.cpp -- exception translation
+
+    Copyright (c) 2016 Pim Schellart <P.Schellart@princeton.edu>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+// A type that should be raised as an exeption in Python
+class MyException : public std::exception {
+public:
+    explicit MyException(const char * m) : message{m} {}
+    virtual const char * what() const noexcept override {return message.c_str();}
+private:
+    std::string message = "";
+};
+
+// A type that should be translated to a standard Python exception
+class MyException2 : public std::exception {
+public:
+    explicit MyException2(const char * m) : message{m} {}
+    virtual const char * what() const noexcept override {return message.c_str();}
+private:
+    std::string message = "";
+};
+
+// A type that is not derived from std::exception (and is thus unknown)
+class MyException3 {
+public:
+    explicit MyException3(const char * m) : message{m} {}
+    virtual const char * what() const noexcept {return message.c_str();}
+private:
+    std::string message = "";
+};
+
+// A type that should be translated to MyException
+// and delegated to its exception translator
+class MyException4 : public std::exception {
+public:
+    explicit MyException4(const char * m) : message{m} {}
+    virtual const char * what() const noexcept override {return message.c_str();}
+private:
+    std::string message = "";
+};
+
+void throws1() {
+    throw MyException("this error should go to a custom type");
+}
+
+void throws2() {
+    throw MyException2("this error should go to a standard Python exception");
+}
+
+void throws3() {
+    throw MyException3("this error cannot be translated");
+}
+
+void throws4() {
+    throw MyException4("this error is rethrown");
+}
+
+void throws_logic_error() {
+    throw std::logic_error("this error should fall through to the standard handler");
+}
+
+void init_ex_custom_exceptions(py::module &m) {
+    // make a new custom exception and use it as a translation target
+    static py::exception<MyException> ex(m, "MyException");
+    py::register_exception_translator([](std::exception_ptr p) {
+        try {
+            if (p) std::rethrow_exception(p);
+        } catch (const MyException &e) {
+            PyErr_SetString(ex.ptr(), e.what());
+        }
+    });
+
+    // register new translator for MyException2
+    // no need to store anything here because this type will
+    // never by visible from Python
+    py::register_exception_translator([](std::exception_ptr p) {
+        try {
+            if (p) std::rethrow_exception(p);
+        } catch (const MyException2 &e) {
+            PyErr_SetString(PyExc_RuntimeError, e.what());
+        }
+    });
+
+    // register new translator for MyException4
+    // which will catch it and delegate to the previously registered
+    // translator for MyException by throwing a new exception
+    py::register_exception_translator([](std::exception_ptr p) {
+        try {
+            if (p) std::rethrow_exception(p);
+        } catch (const MyException4 &e) {
+            throw MyException(e.what());
+        }
+    });
+
+    m.def("throws1", &throws1);
+    m.def("throws2", &throws2);
+    m.def("throws3", &throws3);
+    m.def("throws4", &throws4);
+    m.def("throws_logic_error", &throws_logic_error);
+}
+
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
new file mode 100644
index 0000000..24f9769
--- /dev/null
+++ b/tests/test_exceptions.py
@@ -0,0 +1,31 @@
+import pytest
+
+
+def test_custom(msg):
+    from pybind11_tests import (MyException, throws1, throws2, throws3, throws4,
+                                throws_logic_error)
+
+    # Can we catch a MyException?"
+    with pytest.raises(MyException) as excinfo:
+        throws1()
+    assert msg(excinfo.value) == "this error should go to a custom type"
+
+    # Can we translate to standard Python exceptions?
+    with pytest.raises(RuntimeError) as excinfo:
+        throws2()
+    assert msg(excinfo.value) == "this error should go to a standard Python exception"
+
+    # Can we handle unknown exceptions?
+    with pytest.raises(RuntimeError) as excinfo:
+        throws3()
+    assert msg(excinfo.value) == "Caught an unknown exception!"
+
+    # Can we delegate to another handler by rethrowing?
+    with pytest.raises(MyException) as excinfo:
+        throws4()
+    assert msg(excinfo.value) == "this error is rethrown"
+
+    # "Can we fall-through to the default handler?"
+    with pytest.raises(RuntimeError) as excinfo:
+        throws_logic_error()
+    assert msg(excinfo.value) == "this error should fall through to the standard handler"
diff --git a/tests/test_inheritance.cpp b/tests/test_inheritance.cpp
new file mode 100644
index 0000000..b70ea77
--- /dev/null
+++ b/tests/test_inheritance.cpp
@@ -0,0 +1,72 @@
+/*
+    tests/test_inheritance.cpp -- inheritance, automatic upcasting for polymorphic types
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+class Pet {
+public:
+    Pet(const std::string &name, const std::string &species)
+        : m_name(name), m_species(species) {}
+    std::string name() const { return m_name; }
+    std::string species() const { return m_species; }
+private:
+    std::string m_name;
+    std::string m_species;
+};
+
+class Dog : public Pet {
+public:
+    Dog(const std::string &name) : Pet(name, "dog") {}
+    void bark() const { std::cout << "Woof!" << std::endl; }
+};
+
+class Rabbit : public Pet {
+public:
+    Rabbit(const std::string &name) : Pet(name, "parrot") {}
+};
+
+void pet_print(const Pet &pet) {
+    std::cout << pet.name() + " is a " + pet.species() << std::endl;
+}
+
+void dog_bark(const Dog &dog) {
+    dog.bark();
+}
+
+
+struct BaseClass { virtual ~BaseClass() {} };
+struct DerivedClass1 : BaseClass { };
+struct DerivedClass2 : BaseClass { };
+
+void init_ex_inheritance(py::module &m) {
+    py::class_<Pet> pet_class(m, "Pet");
+    pet_class
+        .def(py::init<std::string, std::string>())
+        .def("name", &Pet::name)
+        .def("species", &Pet::species);
+
+    /* One way of declaring a subclass relationship: reference parent's class_ object */
+    py::class_<Dog>(m, "Dog", pet_class)
+        .def(py::init<std::string>());
+
+    /* Another way of declaring a subclass relationship: reference parent's C++ type */
+    py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
+        .def(py::init<std::string>());
+
+    m.def("pet_print", pet_print);
+    m.def("dog_bark", dog_bark);
+
+    py::class_<BaseClass>(m, "BaseClass").def(py::init<>());
+    py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>());
+    py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>());
+
+    m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); });
+    m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); });
+    m.def("return_none", []() -> BaseClass* { return nullptr; });
+}
diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py
new file mode 100644
index 0000000..a7a9778
--- /dev/null
+++ b/tests/test_inheritance.py
@@ -0,0 +1,8 @@
+
+
+def test_automatic_upcasting():
+    from pybind11_tests import return_class_1, return_class_2, return_none
+
+    assert type(return_class_1()).__name__ == "DerivedClass1"
+    assert type(return_class_2()).__name__ == "DerivedClass2"
+    assert type(return_none()).__name__ == "NoneType"
diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp
new file mode 100644
index 0000000..085dff9
--- /dev/null
+++ b/tests/test_issues.cpp
@@ -0,0 +1,177 @@
+/*
+    tests/test_issues.cpp -- collection of testcases for miscellaneous issues
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/stl.h>
+#include <pybind11/operators.h>
+
+PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
+
+#define TRACKERS(CLASS) CLASS() { print_default_created(this); } ~CLASS() { print_destroyed(this); }
+struct NestABase { int value = -2; TRACKERS(NestABase) };
+struct NestA : NestABase { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) };
+struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) };
+struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) };
+
+void init_issues(py::module &m) {
+    py::module m2 = m.def_submodule("issues");
+
+#if !defined(_MSC_VER)
+    // Visual Studio 2015 currently cannot compile this test
+    // (see the comment in type_caster_base::make_copy_constructor)
+    // #70 compilation issue if operator new is not public
+    class NonConstructible { private: void *operator new(size_t bytes) throw(); };
+    py::class_<NonConstructible>(m, "Foo");
+    m2.def("getstmt", []() -> NonConstructible * { return nullptr; },
+        py::return_value_policy::reference);
+#endif
+
+    // #137: const char* isn't handled properly
+    m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; });
+
+    // #150: char bindings broken
+    m2.def("print_char", [](char c) { std::cout << c << std::endl; });
+
+    // #159: virtual function dispatch has problems with similar-named functions
+    struct Base { virtual void dispatch(void) const {
+        /* for some reason MSVC2015 can't compile this if the function is pure virtual */
+    }; };
+
+    struct DispatchIssue : Base {
+        virtual void dispatch(void) const {
+            PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */);
+        }
+    };
+
+    py::class_<Base, std::unique_ptr<Base>, DispatchIssue>(m2, "DispatchIssue")
+        .def(py::init<>())
+        .def("dispatch", &Base::dispatch);
+
+    m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); });
+
+    struct Placeholder { int i; Placeholder(int i) : i(i) { } };
+
+    py::class_<Placeholder>(m2, "Placeholder")
+        .def(py::init<int>())
+        .def("__repr__", [](const Placeholder &p) { return "Placeholder[" + std::to_string(p.i) + "]"; });
+
+    // #171: Can't return reference wrappers (or STL datastructures containing them)
+    m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<Placeholder> p4){
+        Placeholder *p1 = new Placeholder{1};
+        Placeholder *p2 = new Placeholder{2};
+        Placeholder *p3 = new Placeholder{3};
+        std::vector<std::reference_wrapper<Placeholder>> v;
+        v.push_back(std::ref(*p1));
+        v.push_back(std::ref(*p2));
+        v.push_back(std::ref(*p3));
+        v.push_back(p4);
+        return v;
+    });
+
+    // #181: iterator passthrough did not compile
+    m2.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
+        return py::make_iterator(std::begin(s), std::end(s));
+    });
+
+    // #187: issue involving std::shared_ptr<> return value policy & garbage collection
+    struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
+    struct ElementA : ElementBase {
+        ElementA(int v) : v(v) { }
+        int value() { return v; }
+        int v;
+    };
+
+    struct ElementList {
+        void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
+        std::vector<std::shared_ptr<ElementBase>> l;
+    };
+
+    py::class_<ElementBase, std::shared_ptr<ElementBase>> (m2, "ElementBase");
+
+    py::class_<ElementA, std::shared_ptr<ElementA>>(m2, "ElementA", py::base<ElementBase>())
+        .def(py::init<int>())
+        .def("value", &ElementA::value);
+
+    py::class_<ElementList, std::shared_ptr<ElementList>>(m2, "ElementList")
+        .def(py::init<>())
+        .def("add", &ElementList::add)
+        .def("get", [](ElementList &el){
+            py::list list;
+            for (auto &e : el.l)
+                list.append(py::cast(e));
+            return list;
+        });
+
+    // (no id): should not be able to pass 'None' to a reference argument
+    m2.def("print_element", [](ElementA &el) { std::cout << el.value() << std::endl; });
+
+    // (no id): don't cast doubles to ints
+    m2.def("expect_float", [](float f) { return f; });
+    m2.def("expect_int", [](int i) { return i; });
+
+    // (no id): don't invoke Python dispatch code when instantiating C++
+    // classes that were not extended on the Python side
+    struct A {
+        virtual ~A() {}
+        virtual void f() { std::cout << "A.f()" << std::endl; }
+    };
+
+    struct PyA : A {
+        PyA() { std::cout << "PyA.PyA()" << std::endl; }
+
+        void f() override {
+            std::cout << "PyA.f()" << std::endl;
+            PYBIND11_OVERLOAD(void, A, f);
+        }
+    };
+
+    auto call_f = [](A *a) { a->f(); };
+
+    pybind11::class_<A, std::unique_ptr<A>, PyA>(m2, "A")
+        .def(py::init<>())
+        .def("f", &A::f);
+
+    m2.def("call_f", call_f);
+
+    try {
+        py::class_<Placeholder>(m2, "Placeholder");
+        throw std::logic_error("Expected an exception!");
+    } catch (std::runtime_error &) {
+        /* All good */
+    }
+
+    // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
+    class StrIssue {
+    public:
+        StrIssue(int i) : val{i} {}
+        StrIssue() : StrIssue(-1) {}
+        int value() const { return val; }
+    private:
+        int val;
+    };
+    py::class_<StrIssue> si(m2, "StrIssue");
+    si  .def(py::init<int>())
+        .def(py::init<>())
+        .def("__str__", [](const StrIssue &si) {
+                std::cout << "StrIssue.__str__ called" << std::endl;
+                return "StrIssue[" + std::to_string(si.value()) + "]";
+                })
+        ;
+
+    // Issue #328: first member in a class can't be used in operators
+    py::class_<NestABase>(m2, "NestABase").def(py::init<>()).def_readwrite("value", &NestABase::value);
+    py::class_<NestA>(m2, "NestA").def(py::init<>()).def(py::self += int())
+        .def("as_base", [](NestA &a) -> NestABase& { return (NestABase&) a; }, py::return_value_policy::reference_internal);
+    py::class_<NestB>(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a);
+    py::class_<NestC>(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b);
+    m2.def("print_NestA", [](const NestA &a) { std::cout << a.value << std::endl; });
+    m2.def("print_NestB", [](const NestB &b) { std::cout << b.value << std::endl; });
+    m2.def("print_NestC", [](const NestC &c) { std::cout << c.value << std::endl; });
+}
diff --git a/tests/test_issues.py b/tests/test_issues.py
new file mode 100644
index 0000000..0ab2e36
--- /dev/null
+++ b/tests/test_issues.py
@@ -0,0 +1,176 @@
+import pytest
+import gc
+
+
+def test_regressions(capture):
+    from pybind11_tests.issues import print_cchar, print_char
+
+    with capture:
+        print_cchar("const char *")  # #137: const char* isn't handled properly
+    assert capture == "const char *"
+    with capture:
+        print_char("c")  # #150: char bindings broken
+    assert capture == "c"
+
+
+def test_dispatch_issue(capture, msg):
+    """#159: virtual function dispatch has problems with similar-named functions"""
+    from pybind11_tests.issues import DispatchIssue, dispatch_issue_go
+
+    class PyClass1(DispatchIssue):
+        def dispatch(self):
+            print("Yay..")
+
+    class PyClass2(DispatchIssue):
+        def dispatch(self):
+            with pytest.raises(RuntimeError) as excinfo:
+                super(PyClass2, self).dispatch()
+            assert msg(excinfo.value) == 'Tried to call pure virtual function "Base::dispatch"'
+
+            p = PyClass1()
+            dispatch_issue_go(p)
+
+    b = PyClass2()
+    with capture:
+        dispatch_issue_go(b)
+    assert capture == "Yay.."
+
+
+def test_reference_wrapper():
+    """#171: Can't return reference wrappers (or STL data structures containing them)"""
+    from pybind11_tests.issues import Placeholder, return_vec_of_reference_wrapper
+
+    assert str(return_vec_of_reference_wrapper(Placeholder(4))) == \
+        "[Placeholder[1], Placeholder[2], Placeholder[3], Placeholder[4]]"
+
+
+def test_iterator_passthrough():
+    """#181: iterator passthrough did not compile"""
+    from pybind11_tests.issues import iterator_passthrough
+
+    assert list(iterator_passthrough(iter([3, 5, 7, 9, 11, 13, 15]))) == [3, 5, 7, 9, 11, 13, 15]
+
+
+def test_shared_ptr_gc():
+    """// #187: issue involving std::shared_ptr<> return value policy & garbage collection"""
+    from pybind11_tests.issues import ElementList, ElementA
+
+    el = ElementList()
+    for i in range(10):
+        el.add(ElementA(i))
+    gc.collect()
+    for i, v in enumerate(el.get()):
+        assert i == v.value()
+
+
+def test_no_id(capture, msg):
+    from pybind11_tests.issues import print_element, expect_float, expect_int
+
+    with pytest.raises(TypeError) as excinfo:
+        print_element(None)
+    assert msg(excinfo.value) == """
+        Incompatible function arguments. The following argument types are supported:
+            1. (arg0: m.issues.ElementA) -> None
+            Invoked with: None
+    """
+
+    with pytest.raises(TypeError) as excinfo:
+        expect_int(5.2)
+    assert msg(excinfo.value) == """
+        Incompatible function arguments. The following argument types are supported:
+            1. (arg0: int) -> int
+            Invoked with: 5.2
+    """
+    assert expect_float(12) == 12
+
+    from pybind11_tests.issues import A, call_f
+
+    class B(A):
+        def __init__(self):
+            super(B, self).__init__()
+
+        def f(self):
+            print("In python f()")
+
+    # C++ version
+    with capture:
+        a = A()
+        call_f(a)
+    assert capture == "A.f()"
+
+    # Python version
+    with capture:
+        b = B()
+        call_f(b)
+    assert capture == """
+        PyA.PyA()
+        PyA.f()
+        In python f()
+    """
+
+
+def test_str_issue(capture, msg):
+    """Issue #283: __str__ called on uninitialized instance when constructor arguments invalid"""
+    from pybind11_tests.issues import StrIssue
+
+    with capture:
+        assert str(StrIssue(3)) == "StrIssue[3]"
+    assert capture == "StrIssue.__str__ called"
+
+    with pytest.raises(TypeError) as excinfo:
+        str(StrIssue("no", "such", "constructor"))
+    assert msg(excinfo.value) == """
+        Incompatible constructor arguments. The following argument types are supported:
+            1. m.issues.StrIssue(arg0: int)
+            2. m.issues.StrIssue()
+            Invoked with: no, such, constructor
+    """
+
+
+def test_nested(capture):
+    """ #328: first member in a class can't be used in operators"""
+    from pybind11_tests.issues import NestA, NestB, NestC, print_NestA, print_NestB, print_NestC
+
+    a = NestA()
+    b = NestB()
+    c = NestC()
+
+    a += 10
+    b.a += 100
+    c.b.a += 1000
+    b -= 1
+    c.b -= 3
+    c *= 7
+
+    with capture:
+        print_NestA(a)
+        print_NestA(b.a)
+        print_NestA(c.b.a)
+        print_NestB(b)
+        print_NestB(c.b)
+        print_NestC(c)
+    assert capture == """
+        13
+        103
+        1003
+        3
+        1
+        35
+    """
+
+    abase = a.as_base()
+    assert abase.value == -2
+    a.as_base().value += 44
+    assert abase.value == 42
+    assert c.b.a.as_base().value == -2
+    c.b.a.as_base().value += 44
+    assert c.b.a.as_base().value == 42
+
+    del c
+    gc.collect()
+    del a  # Should't delete while abase is still alive
+    gc.collect()
+
+    assert abase.value == 42
+    del abase, b
+    gc.collect()
diff --git a/tests/test_keep_alive.cpp b/tests/test_keep_alive.cpp
new file mode 100644
index 0000000..25f852e
--- /dev/null
+++ b/tests/test_keep_alive.cpp
@@ -0,0 +1,40 @@
+/*
+    tests/test_keep_alive.cpp -- keep_alive modifier (pybind11's version
+    of Boost.Python's with_custodian_and_ward / with_custodian_and_ward_postcall)
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+class Child {
+public:
+    Child() { std::cout << "Allocating child." << std::endl; }
+    ~Child() { std::cout << "Releasing child." << std::endl; }
+};
+
+class Parent {
+public:
+    Parent() { std::cout << "Allocating parent." << std::endl; }
+    ~Parent() { std::cout << "Releasing parent." << std::endl; }
+    void addChild(Child *) { }
+    Child *returnChild() { return new Child(); }
+    Child *returnNullChild() { return nullptr; }
+};
+
+void init_ex_keep_alive(py::module &m) {
+    py::class_<Parent>(m, "Parent")
+        .def(py::init<>())
+        .def("addChild", &Parent::addChild)
+        .def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
+        .def("returnChild", &Parent::returnChild)
+        .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
+        .def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
+        .def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>());
+
+    py::class_<Child>(m, "Child")
+        .def(py::init<>());
+}
diff --git a/tests/test_keep_alive.py b/tests/test_keep_alive.py
new file mode 100644
index 0000000..c83d5d2
--- /dev/null
+++ b/tests/test_keep_alive.py
@@ -0,0 +1,98 @@
+import gc
+
+
+def test_keep_alive_argument(capture):
+    from pybind11_tests import Parent, Child
+
+    with capture:
+        p = Parent()
+    assert capture == "Allocating parent."
+    with capture:
+        p.addChild(Child())
+        gc.collect()
+    assert capture == """
+        Allocating child.
+        Releasing child.
+    """
+    with capture:
+        del p
+        gc.collect()
+    assert capture == "Releasing parent."
+
+    with capture:
+        p = Parent()
+    assert capture == "Allocating parent."
+    with capture:
+        p.addChildKeepAlive(Child())
+        gc.collect()
+    assert capture == "Allocating child."
+    with capture:
+        del p
+        gc.collect()
+    assert capture == """
+        Releasing parent.
+        Releasing child.
+    """
+
+
+def test_keep_alive_return_value(capture):
+    from pybind11_tests import Parent
+
+    with capture:
+        p = Parent()
+    assert capture == "Allocating parent."
+    with capture:
+        p.returnChild()
+        gc.collect()
+    assert capture == """
+        Allocating child.
+        Releasing child.
+    """
+    with capture:
+        del p
+        gc.collect()
+    assert capture == "Releasing parent."
+
+    with capture:
+        p = Parent()
+    assert capture == "Allocating parent."
+    with capture:
+        p.returnChildKeepAlive()
+        gc.collect()
+    assert capture == "Allocating child."
+    with capture:
+        del p
+        gc.collect()
+    assert capture == """
+        Releasing parent.
+        Releasing child.
+    """
+
+
+def test_return_none(capture):
+    from pybind11_tests import Parent
+
+    with capture:
+        p = Parent()
+    assert capture == "Allocating parent."
+    with capture:
+        p.returnNullChildKeepAliveChild()
+        gc.collect()
+    assert capture == ""
+    with capture:
+        del p
+        gc.collect()
+    assert capture == "Releasing parent."
+
+    with capture:
+        p = Parent()
+    assert capture == "Allocating parent."
+    with capture:
+        p.returnNullChildKeepAliveParent()
+        gc.collect()
+    assert capture == ""
+    with capture:
+        del p
+        gc.collect()
+    assert capture == "Releasing parent."
+
diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp
new file mode 100644
index 0000000..2816246
--- /dev/null
+++ b/tests/test_kwargs_and_defaults.cpp
@@ -0,0 +1,71 @@
+/*
+    tests/test_kwargs_and_defaults.cpp -- keyword arguments and default values
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/stl.h>
+
+void kw_func(int x, int y) { std::cout << "kw_func(x=" << x << ", y=" << y << ")" << std::endl; }
+
+void kw_func4(const std::vector<int> &entries) {
+    std::cout << "kw_func4: ";
+    for (int i : entries)
+        std::cout << i << " ";
+    std::cout << endl;
+}
+
+py::object call_kw_func(py::function f) {
+    py::tuple args = py::make_tuple(1234);
+    py::dict kwargs;
+    kwargs["y"] = py::cast(5678);
+    return f(*args, **kwargs);
+}
+
+void args_function(py::args args) {
+    for (size_t it=0; it<args.size(); ++it)
+        std::cout << "got argument: " << py::object(args[it]) << std::endl;
+}
+
+void args_kwargs_function(py::args args, py::kwargs kwargs) {
+    for (auto item : args)
+        std::cout << "got argument: " << item << std::endl;
+    if (kwargs) {
+        for (auto item : kwargs)
+            std::cout << "got keyword argument: " << item.first << " -> " << item.second << std::endl;
+    }
+}
+
+struct KWClass {
+    void foo(int, float) {}
+};
+
+void init_ex_arg_keywords_and_defaults(py::module &m) {
+    m.def("kw_func0", &kw_func);
+    m.def("kw_func1", &kw_func, py::arg("x"), py::arg("y"));
+    m.def("kw_func2", &kw_func, py::arg("x") = 100, py::arg("y") = 200);
+    m.def("kw_func3", [](const char *) { }, py::arg("data") = std::string("Hello world!"));
+
+    /* A fancier default argument */
+    std::vector<int> list;
+    list.push_back(13);
+    list.push_back(17);
+
+    m.def("kw_func4", &kw_func4, py::arg("myList") = list);
+    m.def("call_kw_func", &call_kw_func);
+
+    m.def("args_function", &args_function);
+    m.def("args_kwargs_function", &args_kwargs_function);
+
+    using namespace py::literals;
+    m.def("kw_func_udl", &kw_func, "x"_a, "y"_a=300);
+    m.def("kw_func_udl_z", &kw_func, "x"_a, "y"_a=0);
+    
+    py::class_<KWClass>(m, "KWClass")
+        .def("foo0", &KWClass::foo)
+        .def("foo1", &KWClass::foo, "x"_a, "y"_a);
+}
diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py
new file mode 100644
index 0000000..0d785a4
--- /dev/null
+++ b/tests/test_kwargs_and_defaults.py
@@ -0,0 +1,93 @@
+import pytest
+from pybind11_tests import (kw_func0, kw_func1, kw_func2, kw_func3, kw_func4, call_kw_func,
+                            args_function, args_kwargs_function, kw_func_udl, kw_func_udl_z,
+                            KWClass)
+
+
+def test_function_signatures(doc):
+    assert doc(kw_func0) == "kw_func0(arg0: int, arg1: int) -> None"
+    assert doc(kw_func1) == "kw_func1(x: int, y: int) -> None"
+    assert doc(kw_func2) == "kw_func2(x: int=100, y: int=200) -> None"
+    assert doc(kw_func3) == "kw_func3(data: str='Hello world!') -> None"
+    assert doc(kw_func4) == "kw_func4(myList: List[int]=[13, 17]) -> None"
+    assert doc(kw_func_udl) == "kw_func_udl(x: int, y: int=300) -> None"
+    assert doc(kw_func_udl_z) == "kw_func_udl_z(x: int, y: int=0) -> None"
+    assert doc(args_function) == "args_function(*args) -> None"
+    assert doc(args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> None"
+    assert doc(KWClass.foo0) == "foo0(self: m.KWClass, arg0: int, arg1: float) -> None"
+    assert doc(KWClass.foo1) == "foo1(self: m.KWClass, x: int, y: float) -> None"
+
+
+def test_named_arguments(capture, msg):
+    with capture:
+        kw_func1(5, 10)
+    assert capture == "kw_func(x=5, y=10)"
+    with capture:
+        kw_func1(5, y=10)
+    assert capture == "kw_func(x=5, y=10)"
+    with capture:
+        kw_func1(y=10, x=5)
+    assert capture == "kw_func(x=5, y=10)"
+
+    with capture:
+        kw_func2()
+    assert capture == "kw_func(x=100, y=200)"
+    with capture:
+        kw_func2(5)
+    assert capture == "kw_func(x=5, y=200)"
+    with capture:
+        kw_func2(x=5)
+    assert capture == "kw_func(x=5, y=200)"
+    with capture:
+        kw_func2(y=10)
+    assert capture == "kw_func(x=100, y=10)"
+    with capture:
+        kw_func2(5, 10)
+    assert capture == "kw_func(x=5, y=10)"
+    with capture:
+        kw_func2(x=5, y=10)
+    assert capture == "kw_func(x=5, y=10)"
+
+    with pytest.raises(TypeError) as excinfo:
+        # noinspection PyArgumentList
+        kw_func2(x=5, y=10, z=12)
+    assert msg(excinfo.value) == """
+        Incompatible function arguments. The following argument types are supported:
+            1. (x: int=100, y: int=200) -> None
+            Invoked with:
+    """
+
+    with capture:
+        kw_func4()
+    assert capture == "kw_func4: 13 17"
+    with capture:
+        kw_func4(myList=[1, 2, 3])
+    assert capture == "kw_func4: 1 2 3"
+
+    with capture:
+        kw_func_udl(x=5, y=10)
+    assert capture == "kw_func(x=5, y=10)"
+    with capture:
+        kw_func_udl_z(x=5)
+    assert capture == "kw_func(x=5, y=0)"
+
+
+def test_arg_and_kwargs(capture):
+    with capture:
+        call_kw_func(kw_func2)
+    assert capture == "kw_func(x=1234, y=5678)"
+    with capture:
+        args_function('arg1_value', 'arg2_value', 3)
+    assert capture.unordered == """
+        got argument: arg1_value
+        got argument: arg2_value
+        got argument: 3
+    """
+    with capture:
+        args_kwargs_function('arg1_value', 'arg2_value', arg3='arg3_value', arg4=4)
+    assert capture.unordered == """
+        got argument: arg1_value
+        got argument: arg2_value
+        got keyword argument: arg3 -> arg3_value
+        got keyword argument: arg4 -> 4
+    """
diff --git a/tests/test_methods_and_attributes.cpp b/tests/test_methods_and_attributes.cpp
new file mode 100644
index 0000000..9317d78
--- /dev/null
+++ b/tests/test_methods_and_attributes.cpp
@@ -0,0 +1,84 @@
+/*
+    tests/test_methods_and_attributes.cpp -- constructors, deconstructors, attribute access,
+    __str__, argument and return value conventions
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+class ExampleMandA {
+public:
+    ExampleMandA() { print_default_created(this); }
+    ExampleMandA(int value) : value(value) { print_created(this, value); }
+    ExampleMandA(const ExampleMandA &e) : value(e.value) { print_copy_created(this); }
+    ExampleMandA(ExampleMandA &&e) : value(e.value) { print_move_created(this); }
+    ~ExampleMandA() { print_destroyed(this); }
+
+    std::string toString() {
+        return "ExampleMandA[value=" + std::to_string(value) + "]";
+    }
+
+    void operator=(const ExampleMandA &e) { print_copy_assigned(this); value = e.value; }
+    void operator=(ExampleMandA &&e) { print_move_assigned(this); value = e.value; }
+
+    void add1(ExampleMandA other) { value += other.value; }           // passing by value
+    void add2(ExampleMandA &other) { value += other.value; }          // passing by reference
+    void add3(const ExampleMandA &other) { value += other.value; }    // passing by const reference
+    void add4(ExampleMandA *other) { value += other->value; }         // passing by pointer
+    void add5(const ExampleMandA *other) { value += other->value; }   // passing by const pointer
+
+    void add6(int other) { value += other; }                      // passing by value
+    void add7(int &other) { value += other; }                     // passing by reference
+    void add8(const int &other) { value += other; }               // passing by const reference
+    void add9(int *other) { value += *other; }                    // passing by pointer
+    void add10(const int *other) { value += *other; }             // passing by const pointer
+
+    ExampleMandA self1() { return *this; }                            // return by value
+    ExampleMandA &self2() { return *this; }                           // return by reference
+    const ExampleMandA &self3() { return *this; }                     // return by const reference
+    ExampleMandA *self4() { return this; }                            // return by pointer
+    const ExampleMandA *self5() { return this; }                      // return by const pointer
+
+    int internal1() { return value; }                             // return by value
+    int &internal2() { return value; }                            // return by reference
+    const int &internal3() { return value; }                      // return by const reference
+    int *internal4() { return &value; }                           // return by pointer
+    const int *internal5() { return &value; }                     // return by const pointer
+
+    int value = 0;
+};
+
+void init_ex_methods_and_attributes(py::module &m) {
+    py::class_<ExampleMandA>(m, "ExampleMandA")
+        .def(py::init<>())
+        .def(py::init<int>())
+        .def(py::init<const ExampleMandA&>())
+        .def("add1", &ExampleMandA::add1)
+        .def("add2", &ExampleMandA::add2)
+        .def("add3", &ExampleMandA::add3)
+        .def("add4", &ExampleMandA::add4)
+        .def("add5", &ExampleMandA::add5)
+        .def("add6", &ExampleMandA::add6)
+        .def("add7", &ExampleMandA::add7)
+        .def("add8", &ExampleMandA::add8)
+        .def("add9", &ExampleMandA::add9)
+        .def("add10", &ExampleMandA::add10)
+        .def("self1", &ExampleMandA::self1)
+        .def("self2", &ExampleMandA::self2)
+        .def("self3", &ExampleMandA::self3)
+        .def("self4", &ExampleMandA::self4)
+        .def("self5", &ExampleMandA::self5)
+        .def("internal1", &ExampleMandA::internal1)
+        .def("internal2", &ExampleMandA::internal2)
+        .def("internal3", &ExampleMandA::internal3)
+        .def("internal4", &ExampleMandA::internal4)
+        .def("internal5", &ExampleMandA::internal5)
+        .def("__str__", &ExampleMandA::toString)
+        .def_readwrite("value", &ExampleMandA::value)
+        ;
+}
diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py
new file mode 100644
index 0000000..9340e6f
--- /dev/null
+++ b/tests/test_methods_and_attributes.py
@@ -0,0 +1,46 @@
+from pybind11_tests import ExampleMandA, ConstructorStats
+
+
+def test_methods_and_attributes():
+    instance1 = ExampleMandA()
+    instance2 = ExampleMandA(32)
+
+    instance1.add1(instance2)
+    instance1.add2(instance2)
+    instance1.add3(instance2)
+    instance1.add4(instance2)
+    instance1.add5(instance2)
+    instance1.add6(32)
+    instance1.add7(32)
+    instance1.add8(32)
+    instance1.add9(32)
+    instance1.add10(32)
+
+    assert str(instance1) == "ExampleMandA[value=320]"
+    assert str(instance2) == "ExampleMandA[value=32]"
+    assert str(instance1.self1()) == "ExampleMandA[value=320]"
+    assert str(instance1.self2()) == "ExampleMandA[value=320]"
+    assert str(instance1.self3()) == "ExampleMandA[value=320]"
+    assert str(instance1.self4()) == "ExampleMandA[value=320]"
+    assert str(instance1.self5()) == "ExampleMandA[value=320]"
+
+    assert instance1.internal1() == 320
+    assert instance1.internal2() == 320
+    assert instance1.internal3() == 320
+    assert instance1.internal4() == 320
+    assert instance1.internal5() == 320
+
+    assert instance1.value == 320
+    instance1.value = 100
+    assert str(instance1) == "ExampleMandA[value=100]"
+
+    cstats = ConstructorStats.get(ExampleMandA)
+    assert cstats.alive() == 2
+    del instance1, instance2
+    assert cstats.alive() == 0
+    assert cstats.values() == ["32"]
+    assert cstats.default_constructions == 1
+    assert cstats.copy_constructions == 3
+    assert cstats.move_constructions >= 1
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
diff --git a/tests/test_modules.cpp b/tests/test_modules.cpp
new file mode 100644
index 0000000..3d96df6
--- /dev/null
+++ b/tests/test_modules.cpp
@@ -0,0 +1,58 @@
+/*
+    tests/test_modules.cpp -- nested modules, importing modules, and
+                            internal references
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+
+void submodule_func() {
+    std::cout << "submodule_func()" << std::endl;
+}
+
+class A {
+public:
+    A(int v) : v(v) { print_created(this, v); }
+    ~A() { print_destroyed(this); }
+    A(const A&) { print_copy_created(this); }
+    A& operator=(const A &copy) { print_copy_assigned(this); v = copy.v; return *this; }
+    std::string toString() { return "A[" + std::to_string(v) + "]"; }
+private:
+    int v;
+};
+
+class B {
+public:
+    B() { print_default_created(this); }
+    ~B() { print_destroyed(this); }
+    B(const B&) { print_copy_created(this); }
+    B& operator=(const B &copy) { print_copy_assigned(this); a1 = copy.a1; a2 = copy.a2; return *this; }
+    A &get_a1() { return a1; }
+    A &get_a2() { return a2; }
+
+    A a1{1};
+    A a2{2};
+};
+
+void init_ex_modules(py::module &m) {
+    py::module m_sub = m.def_submodule("submodule");
+    m_sub.def("submodule_func", &submodule_func);
+
+    py::class_<A>(m_sub, "A")
+        .def(py::init<int>())
+        .def("__repr__", &A::toString);
+
+    py::class_<B>(m_sub, "B")
+        .def(py::init<>())
+        .def("get_a1", &B::get_a1, "Return the internal A 1", py::return_value_policy::reference_internal)
+        .def("get_a2", &B::get_a2, "Return the internal A 2", py::return_value_policy::reference_internal)
+        .def_readwrite("a1", &B::a1)  // def_readonly uses an internal reference return policy by default
+        .def_readwrite("a2", &B::a2);
+
+    m.attr("OD") = py::module::import("collections").attr("OrderedDict");
+}
diff --git a/tests/test_modules.py b/tests/test_modules.py
new file mode 100644
index 0000000..3deb02e
--- /dev/null
+++ b/tests/test_modules.py
@@ -0,0 +1,56 @@
+
+def test_nested_modules(capture):
+    import pybind11_tests
+    from pybind11_tests.submodule import submodule_func
+
+    assert pybind11_tests.__name__ == "pybind11_tests"
+    assert pybind11_tests.submodule.__name__ == "pybind11_tests.submodule"
+
+    with capture:
+        submodule_func()
+    assert capture == "submodule_func()"
+
+
+def test_reference_internal():
+    from pybind11_tests import ConstructorStats
+    from pybind11_tests.submodule import A, B
+
+    b = B()
+    assert str(b.get_a1()) == "A[1]"
+    assert str(b.a1) == "A[1]"
+    assert str(b.get_a2()) == "A[2]"
+    assert str(b.a2) == "A[2]"
+
+    b.a1 = A(42)
+    b.a2 = A(43)
+    assert str(b.get_a1()) == "A[42]"
+    assert str(b.a1) == "A[42]"
+    assert str(b.get_a2()) == "A[43]"
+    assert str(b.a2) == "A[43]"
+
+    astats, bstats = ConstructorStats.get(A), ConstructorStats.get(B)
+    assert astats.alive() == 2
+    assert bstats.alive() == 1
+    del b
+    assert astats.alive() == 0
+    assert bstats.alive() == 0
+    assert astats.values() == ['1', '2', '42', '43']
+    assert bstats.values() == []
+    assert astats.default_constructions == 0
+    assert bstats.default_constructions == 1
+    assert astats.copy_constructions == 0
+    assert bstats.copy_constructions == 0
+    # assert astats.move_constructions >= 0  # Don't invoke any
+    # assert bstats.move_constructions >= 0  # Don't invoke any
+    assert astats.copy_assignments == 2
+    assert bstats.copy_assignments == 0
+    assert astats.move_assignments == 0
+    assert bstats.move_assignments == 0
+
+
+def test_importing():
+    from pybind11_tests import OD
+    from collections import OrderedDict
+
+    assert OD is OrderedDict
+    assert str(OD([(1, 'a'), (2, 'b')])) == "OrderedDict([(1, 'a'), (2, 'b')])"
diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp
new file mode 100644
index 0000000..9afd342
--- /dev/null
+++ b/tests/test_numpy_dtypes.cpp
@@ -0,0 +1,278 @@
+/*
+  tests/test_numpy_dtypes.cpp -- Structured and compound NumPy dtypes
+
+  Copyright (c) 2016 Ivan Smirnov
+
+  All rights reserved. Use of this source code is governed by a
+  BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+#include <pybind11/numpy.h>
+
+#ifdef __GNUC__
+#define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
+#else
+#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop))
+#endif
+
+namespace py = pybind11;
+
+struct SimpleStruct {
+    bool x;
+    uint32_t y;
+    float z;
+};
+
+std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) {
+    return os << "s:" << v.x << "," << v.y << "," << v.z;
+}
+
+PYBIND11_PACKED(struct PackedStruct {
+    bool x;
+    uint32_t y;
+    float z;
+});
+
+std::ostream& operator<<(std::ostream& os, const PackedStruct& v) {
+    return os << "p:" << v.x << "," << v.y << "," << v.z;
+}
+
+PYBIND11_PACKED(struct NestedStruct {
+    SimpleStruct a;
+    PackedStruct b;
+});
+
+std::ostream& operator<<(std::ostream& os, const NestedStruct& v) {
+    return os << "n:a=" << v.a << ";b=" << v.b;
+}
+
+struct PartialStruct {
+    bool x;
+    uint32_t y;
+    float z;
+    uint64_t dummy2;
+};
+
+struct PartialNestedStruct {
+    uint64_t dummy1;
+    PartialStruct a;
+    uint64_t dummy2;
+};
+
+struct UnboundStruct { };
+
+struct StringStruct {
+    char a[3];
+    std::array<char, 3> b;
+};
+
+std::ostream& operator<<(std::ostream& os, const StringStruct& v) {
+    os << "a='";
+    for (size_t i = 0; i < 3 && v.a[i]; i++) os << v.a[i];
+    os << "',b='";
+    for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i];
+    return os << "'";
+}
+
+template <typename T>
+py::array mkarray_via_buffer(size_t n) {
+    return py::array(py::buffer_info(nullptr, sizeof(T),
+                                     py::format_descriptor<T>::format(),
+                                     1, { n }, { sizeof(T) }));
+}
+
+template <typename S>
+py::array_t<S, 0> create_recarray(size_t n) {
+    auto arr = mkarray_via_buffer<S>(n);
+    auto req = arr.request();
+    auto ptr = static_cast<S*>(req.ptr);
+    for (size_t i = 0; i < n; i++) {
+        ptr[i].x = i % 2 != 0; ptr[i].y = (uint32_t) i; ptr[i].z = (float) i * 1.5f;
+    }
+    return arr;
+}
+
+std::string get_format_unbound() {
+    return py::format_descriptor<UnboundStruct>::format();
+}
+
+py::array_t<NestedStruct, 0> create_nested(size_t n) {
+    auto arr = mkarray_via_buffer<NestedStruct>(n);
+    auto req = arr.request();
+    auto ptr = static_cast<NestedStruct*>(req.ptr);
+    for (size_t i = 0; i < n; i++) {
+        ptr[i].a.x = i % 2 != 0; ptr[i].a.y = (uint32_t) i; ptr[i].a.z = (float) i * 1.5f;
+        ptr[i].b.x = (i + 1) % 2 != 0; ptr[i].b.y = (uint32_t) (i + 1); ptr[i].b.z = (float) (i + 1) * 1.5f;
+    }
+    return arr;
+}
+
+py::array_t<PartialNestedStruct, 0> create_partial_nested(size_t n) {
+    auto arr = mkarray_via_buffer<PartialNestedStruct>(n);
+    auto req = arr.request();
+    auto ptr = static_cast<PartialNestedStruct*>(req.ptr);
+    for (size_t i = 0; i < n; i++) {
+        ptr[i].a.x = i % 2 != 0; ptr[i].a.y = (uint32_t) i; ptr[i].a.z = (float) i * 1.5f;
+    }
+    return arr;
+}
+
+py::array_t<StringStruct, 0> create_string_array(bool non_empty) {
+    auto arr = mkarray_via_buffer<StringStruct>(non_empty ? 4 : 0);
+    if (non_empty) {
+        auto req = arr.request();
+        auto ptr = static_cast<StringStruct*>(req.ptr);
+        for (size_t i = 0; i < req.size * req.itemsize; i++)
+            static_cast<char*>(req.ptr)[i] = 0;
+        ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a';
+        ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a';
+        ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a';
+
+        ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b';
+        ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b';
+
+        ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c';
+    }
+    return arr;
+}
+
+template <typename S>
+void print_recarray(py::array_t<S, 0> arr) {
+    auto req = arr.request();
+    auto ptr = static_cast<S*>(req.ptr);
+    for (size_t i = 0; i < req.size; i++)
+        std::cout << ptr[i] << std::endl;
+}
+
+void print_format_descriptors() {
+    std::cout << py::format_descriptor<SimpleStruct>::format() << std::endl;
+    std::cout << py::format_descriptor<PackedStruct>::format() << std::endl;
+    std::cout << py::format_descriptor<NestedStruct>::format() << std::endl;
+    std::cout << py::format_descriptor<PartialStruct>::format() << std::endl;
+    std::cout << py::format_descriptor<PartialNestedStruct>::format() << std::endl;
+    std::cout << py::format_descriptor<StringStruct>::format() << std::endl;
+}
+
+void print_dtypes() {
+    std::cout << (std::string) py::dtype::of<SimpleStruct>().str() << std::endl;
+    std::cout << (std::string) py::dtype::of<PackedStruct>().str() << std::endl;
+    std::cout << (std::string) py::dtype::of<NestedStruct>().str() << std::endl;
+    std::cout << (std::string) py::dtype::of<PartialStruct>().str() << std::endl;
+    std::cout << (std::string) py::dtype::of<PartialNestedStruct>().str() << std::endl;
+    std::cout << (std::string) py::dtype::of<StringStruct>().str() << std::endl;
+}
+
+py::array_t<int32_t, 0> test_array_ctors(int i) {
+    using arr_t = py::array_t<int32_t, 0>;
+
+    std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 };
+    std::vector<size_t> shape { 3, 2 };
+    std::vector<size_t> strides { 8, 4 };
+
+    auto ptr = data.data();
+    auto vptr = (void *) ptr;
+    auto dtype = py::dtype("int32");
+
+    py::buffer_info buf_ndim1(vptr, 4, "i", 6);
+    py::buffer_info buf_ndim1_null(nullptr, 4, "i", 6);
+    py::buffer_info buf_ndim2(vptr, 4, "i", 2, shape, strides);
+    py::buffer_info buf_ndim2_null(nullptr, 4, "i", 2, shape, strides);
+
+    auto fill = [](py::array arr) {
+        auto req = arr.request();
+        for (int i = 0; i < 6; i++) ((int32_t *) req.ptr)[i] = i + 1;
+        return arr;
+    };
+
+    switch (i) {
+    // shape: (3, 2)
+    case 10: return arr_t(shape, strides, ptr);
+    case 11: return py::array(shape, strides, ptr);
+    case 12: return py::array(dtype, shape, strides, vptr);
+    case 13: return arr_t(shape, ptr);
+    case 14: return py::array(shape, ptr);
+    case 15: return py::array(dtype, shape, vptr);
+    case 16: return arr_t(buf_ndim2);
+    case 17: return py::array(buf_ndim2);
+    // shape: (3, 2) - post-fill
+    case 20: return fill(arr_t(shape, strides));
+    case 21: return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor
+    case 22: return fill(py::array(dtype, shape, strides));
+    case 23: return fill(arr_t(shape));
+    case 24: return py::array(shape, ptr); // can't have nullptr due to templated ctor
+    case 25: return fill(py::array(dtype, shape));
+    case 26: return fill(arr_t(buf_ndim2_null));
+    case 27: return fill(py::array(buf_ndim2_null));
+    // shape: (6, )
+    case 30: return arr_t(6, ptr);
+    case 31: return py::array(6, ptr);
+    case 32: return py::array(dtype, 6, vptr);
+    case 33: return arr_t(buf_ndim1);
+    case 34: return py::array(buf_ndim1);
+    // shape: (6, )
+    case 40: return fill(arr_t(6));
+    case 41: return py::array(6, ptr);  // can't have nullptr due to templated ctor
+    case 42: return fill(py::array(dtype, 6));
+    case 43: return fill(arr_t(buf_ndim1_null));
+    case 44: return fill(py::array(buf_ndim1_null));
+    }
+    return arr_t();
+}
+
+py::list test_dtype_ctors() {
+    py::list list;
+    list.append(py::dtype("int32"));
+    list.append(py::dtype(std::string("float64")));
+    list.append(py::dtype::from_args(py::str("bool")));
+    py::list names, offsets, formats;
+    py::dict dict;
+    names.append(py::str("a")); names.append(py::str("b")); dict["names"] = names;
+    offsets.append(py::int_(1)); offsets.append(py::int_(10)); dict["offsets"] = offsets;
+    formats.append(py::dtype("int32")); formats.append(py::dtype("float64")); dict["formats"] = formats;
+    dict["itemsize"] = py::int_(20);
+    list.append(py::dtype::from_args(dict));
+    list.append(py::dtype(names, formats, offsets, 20));
+    list.append(py::dtype(py::buffer_info((void *) 0, 1, "I", 1)));
+    list.append(py::dtype(py::buffer_info((void *) 0, 1, "T{i:a:f:b:}", 1)));
+    return list;
+}
+
+py::list test_dtype_methods() {
+    py::list list;
+    auto dt1 = py::dtype::of<int32_t>();
+    auto dt2 = py::dtype::of<SimpleStruct>();
+    list.append(dt1); list.append(dt2);
+    list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields()));
+    list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize()));
+    return list;
+}
+
+void init_ex_numpy_dtypes(py::module &m) {
+    PYBIND11_NUMPY_DTYPE(SimpleStruct, x, y, z);
+    PYBIND11_NUMPY_DTYPE(PackedStruct, x, y, z);
+    PYBIND11_NUMPY_DTYPE(NestedStruct, a, b);
+    PYBIND11_NUMPY_DTYPE(PartialStruct, x, y, z);
+    PYBIND11_NUMPY_DTYPE(PartialNestedStruct, a);
+    PYBIND11_NUMPY_DTYPE(StringStruct, a, b);
+
+    m.def("create_rec_simple", &create_recarray<SimpleStruct>);
+    m.def("create_rec_packed", &create_recarray<PackedStruct>);
+    m.def("create_rec_nested", &create_nested);
+    m.def("create_rec_partial", &create_recarray<PartialStruct>);
+    m.def("create_rec_partial_nested", &create_partial_nested);
+    m.def("print_format_descriptors", &print_format_descriptors);
+    m.def("print_rec_simple", &print_recarray<SimpleStruct>);
+    m.def("print_rec_packed", &print_recarray<PackedStruct>);
+    m.def("print_rec_nested", &print_recarray<NestedStruct>);
+    m.def("print_dtypes", &print_dtypes);
+    m.def("get_format_unbound", &get_format_unbound);
+    m.def("create_string_array", &create_string_array);
+    m.def("print_string_array", &print_recarray<StringStruct>);
+    m.def("test_array_ctors", &test_array_ctors);
+    m.def("test_dtype_ctors", &test_dtype_ctors);
+    m.def("test_dtype_methods", &test_dtype_methods);
+}
+
+#undef PYBIND11_PACKED
diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py
new file mode 100644
index 0000000..783f6ad
--- /dev/null
+++ b/tests/test_numpy_dtypes.py
@@ -0,0 +1,169 @@
+import pytest
+with pytest.suppress(ImportError):
+    import numpy as np
+
+
+def assert_equal(actual, expected_data, expected_dtype):
+    np.testing.assert_equal(actual, np.array(expected_data, dtype=expected_dtype))
+
+simple_dtype = np.dtype({'names': ['x', 'y', 'z'],
+                         'formats': ['?', 'u4', 'f4'],
+                         'offsets': [0, 4, 8]})
+packed_dtype = np.dtype([('x', '?'), ('y', 'u4'), ('z', 'f4')])
+
+
+@pytest.requires_numpy
+def test_format_descriptors(capture):
+    from pybind11_tests import get_format_unbound, print_format_descriptors
+
+    with pytest.raises(RuntimeError) as excinfo:
+        get_format_unbound()
+    assert 'unsupported buffer format' in str(excinfo.value)
+
+    with capture:
+        print_format_descriptors()
+    assert capture == """
+        T{=?:x:3x=I:y:=f:z:}
+        T{=?:x:=I:y:=f:z:}
+        T{=T{=?:x:3x=I:y:=f:z:}:a:=T{=?:x:=I:y:=f:z:}:b:}
+        T{=?:x:3x=I:y:=f:z:12x}
+        T{8x=T{=?:x:3x=I:y:=f:z:12x}:a:8x}
+        T{=3s:a:=3s:b:}
+    """
+
+
+@pytest.requires_numpy
+def test_dtype(capture):
+    from pybind11_tests import print_dtypes, test_dtype_ctors, test_dtype_methods
+
+    with capture:
+        print_dtypes()
+    assert capture == """
+        {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}
+        [('x', '?'), ('y', '<u4'), ('z', '<f4')]
+        [('a', {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':12}), ('b', [('x', '?'), ('y', '<u4'), ('z', '<f4')])]
+        {'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}
+        {'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}], 'offsets':[8], 'itemsize':40}
+        [('a', 'S3'), ('b', 'S3')]
+    """
+
+    d1 = np.dtype({'names': ['a', 'b'], 'formats': ['int32', 'float64'],
+                   'offsets': [1, 10], 'itemsize': 20})
+    d2 = np.dtype([('a', 'i4'), ('b', 'f4')])
+    assert test_dtype_ctors() == [np.dtype('int32'), np.dtype('float64'),
+                                  np.dtype('bool'), d1, d1, np.dtype('uint32'), d2]
+
+    assert test_dtype_methods() == [np.dtype('int32'), simple_dtype, False, True,
+                                    np.dtype('int32').itemsize, simple_dtype.itemsize]
+
+
+@pytest.requires_numpy
+def test_recarray(capture):
+    from pybind11_tests import (create_rec_simple, create_rec_packed, create_rec_nested,
+                                print_rec_simple, print_rec_packed, print_rec_nested,
+                                create_rec_partial, create_rec_partial_nested)
+
+    elements = [(False, 0, 0.0), (True, 1, 1.5), (False, 2, 3.0)]
+
+    for func, dtype in [(create_rec_simple, simple_dtype), (create_rec_packed, packed_dtype)]:
+        arr = func(0)
+        assert arr.dtype == dtype
+        assert_equal(arr, [], simple_dtype)
+        assert_equal(arr, [], packed_dtype)
+
+        arr = func(3)
+        assert arr.dtype == dtype
+        assert_equal(arr, elements, simple_dtype)
+        assert_equal(arr, elements, packed_dtype)
+
+        if dtype == simple_dtype:
+            with capture:
+                print_rec_simple(arr)
+            assert capture == """
+                s:0,0,0
+                s:1,1,1.5
+                s:0,2,3
+            """
+        else:
+            with capture:
+                print_rec_packed(arr)
+            assert capture == """
+                p:0,0,0
+                p:1,1,1.5
+                p:0,2,3
+            """
+
+    nested_dtype = np.dtype([('a', simple_dtype), ('b', packed_dtype)])
+
+    arr = create_rec_nested(0)
+    assert arr.dtype == nested_dtype
+    assert_equal(arr, [], nested_dtype)
+
+    arr = create_rec_nested(3)
+    assert arr.dtype == nested_dtype
+    assert_equal(arr, [((False, 0, 0.0), (True, 1, 1.5)),
+                       ((True, 1, 1.5), (False, 2, 3.0)),
+                       ((False, 2, 3.0), (True, 3, 4.5))], nested_dtype)
+    with capture:
+        print_rec_nested(arr)
+    assert capture == """
+        n:a=s:0,0,0;b=p:1,1,1.5
+        n:a=s:1,1,1.5;b=p:0,2,3
+        n:a=s:0,2,3;b=p:1,3,4.5
+    """
+
+    arr = create_rec_partial(3)
+    assert str(arr.dtype) == "{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}"
+    partial_dtype = arr.dtype
+    assert '' not in arr.dtype.fields
+    assert partial_dtype.itemsize > simple_dtype.itemsize
+    assert_equal(arr, elements, simple_dtype)
+    assert_equal(arr, elements, packed_dtype)
+
+    arr = create_rec_partial_nested(3)
+    assert str(arr.dtype) == "{'names':['a'], 'formats':[{'names':['x','y','z'], 'formats':['?','<u4','<f4'], 'offsets':[0,4,8], 'itemsize':24}], 'offsets':[8], 'itemsize':40}"
+    assert '' not in arr.dtype.fields
+    assert '' not in arr.dtype.fields['a'][0].fields
+    assert arr.dtype.itemsize > partial_dtype.itemsize
+    np.testing.assert_equal(arr['a'], create_rec_partial(3))
+
+
+@pytest.requires_numpy
+def test_array_constructors():
+    from pybind11_tests import test_array_ctors
+
+    data = np.arange(1, 7, dtype='int32')
+    for i in range(8):
+        np.testing.assert_array_equal(test_array_ctors(10 + i), data.reshape((3, 2)))
+        np.testing.assert_array_equal(test_array_ctors(20 + i), data.reshape((3, 2)))
+    for i in range(5):
+        np.testing.assert_array_equal(test_array_ctors(30 + i), data)
+        np.testing.assert_array_equal(test_array_ctors(40 + i), data)
+
+
+@pytest.requires_numpy
+def test_string_array(capture):
+    from pybind11_tests import create_string_array, print_string_array
+
+    arr = create_string_array(True)
+    assert str(arr.dtype) == "[('a', 'S3'), ('b', 'S3')]"
+    with capture:
+        print_string_array(arr)
+    assert capture == """
+        a='',b=''
+        a='a',b='a'
+        a='ab',b='ab'
+        a='abc',b='abc'
+    """
+    dtype = arr.dtype
+    assert arr['a'].tolist() == [b'', b'a', b'ab', b'abc']
+    assert arr['b'].tolist() == [b'', b'a', b'ab', b'abc']
+    arr = create_string_array(False)
+    assert dtype == arr.dtype
+
+
+@pytest.requires_numpy
+def test_signature(doc):
+    from pybind11_tests import create_rec_nested
+
+    assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]"
diff --git a/tests/test_numpy_vectorize.cpp b/tests/test_numpy_vectorize.cpp
new file mode 100644
index 0000000..a36b7d0
--- /dev/null
+++ b/tests/test_numpy_vectorize.cpp
@@ -0,0 +1,41 @@
+/*
+    tests/test_numpy_vectorize.cpp -- auto-vectorize functions over NumPy array
+    arguments
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/numpy.h>
+
+double my_func(int x, float y, double z) {
+    std::cout << "my_func(x:int=" << x << ", y:float=" << y << ", z:float=" << z << ")" << std::endl;
+    return (float) x*y*z;
+}
+
+std::complex<double> my_func3(std::complex<double> c) {
+    return c * std::complex<double>(2.f);
+}
+
+void init_ex_numpy_vectorize(py::module &m) {
+    // Vectorize all arguments of a function (though non-vector arguments are also allowed)
+    m.def("vectorized_func", py::vectorize(my_func));
+
+    // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization)
+    m.def("vectorized_func2",
+        [](py::array_t<int> x, py::array_t<float> y, float z) {
+            return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(x, y);
+        }
+    );
+
+    // Vectorize a complex-valued function
+    m.def("vectorized_func3", py::vectorize(my_func3));
+
+    /// Numpy function which only accepts specific data types
+    m.def("selective_func", [](py::array_t<int, py::array::c_style>) { std::cout << "Int branch taken." << std::endl; });
+    m.def("selective_func", [](py::array_t<float, py::array::c_style>) { std::cout << "Float branch taken." << std::endl; });
+    m.def("selective_func", [](py::array_t<std::complex<float>, py::array::c_style>) { std::cout << "Complex float branch taken." << std::endl; });
+}
diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py
new file mode 100644
index 0000000..6fcf808
--- /dev/null
+++ b/tests/test_numpy_vectorize.py
@@ -0,0 +1,80 @@
+import pytest
+
+with pytest.suppress(ImportError):
+    import numpy as np
+
+
+@pytest.requires_numpy
+def test_vectorize(capture):
+    from pybind11_tests import vectorized_func, vectorized_func2, vectorized_func3
+
+    assert np.isclose(vectorized_func3(np.array(3 + 7j)), [6 + 14j])
+
+    for f in [vectorized_func, vectorized_func2]:
+        with capture:
+            assert np.isclose(f(1, 2, 3), 6)
+        assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
+        with capture:
+            assert np.isclose(f(np.array(1), np.array(2), 3), 6)
+        assert capture == "my_func(x:int=1, y:float=2, z:float=3)"
+        with capture:
+            assert np.allclose(f(np.array([1, 3]), np.array([2, 4]), 3), [6, 36])
+        assert capture == """
+            my_func(x:int=1, y:float=2, z:float=3)
+            my_func(x:int=3, y:float=4, z:float=3)
+        """
+        with capture:
+            a, b, c = np.array([[1, 3, 5], [7, 9, 11]]), np.array([[2, 4, 6], [8, 10, 12]]), 3
+            assert np.allclose(f(a, b, c), a * b * c)
+        assert capture == """
+            my_func(x:int=1, y:float=2, z:float=3)
+            my_func(x:int=3, y:float=4, z:float=3)
+            my_func(x:int=5, y:float=6, z:float=3)
+            my_func(x:int=7, y:float=8, z:float=3)
+            my_func(x:int=9, y:float=10, z:float=3)
+            my_func(x:int=11, y:float=12, z:float=3)
+        """
+        with capture:
+            a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([2, 3, 4]), 2
+            assert np.allclose(f(a, b, c), a * b * c)
+        assert capture == """
+            my_func(x:int=1, y:float=2, z:float=2)
+            my_func(x:int=2, y:float=3, z:float=2)
+            my_func(x:int=3, y:float=4, z:float=2)
+            my_func(x:int=4, y:float=2, z:float=2)
+            my_func(x:int=5, y:float=3, z:float=2)
+            my_func(x:int=6, y:float=4, z:float=2)
+        """
+        with capture:
+            a, b, c = np.array([[1, 2, 3], [4, 5, 6]]), np.array([[2], [3]]), 2
+            assert np.allclose(f(a, b, c), a * b * c)
+        assert capture == """
+            my_func(x:int=1, y:float=2, z:float=2)
+            my_func(x:int=2, y:float=2, z:float=2)
+            my_func(x:int=3, y:float=2, z:float=2)
+            my_func(x:int=4, y:float=3, z:float=2)
+            my_func(x:int=5, y:float=3, z:float=2)
+            my_func(x:int=6, y:float=3, z:float=2)
+        """
+
+
+@pytest.requires_numpy
+def test_type_selection(capture):
+    from pybind11_tests import selective_func
+
+    with capture:
+        selective_func(np.array([1], dtype=np.int32))
+        selective_func(np.array([1.0], dtype=np.float32))
+        selective_func(np.array([1.0j], dtype=np.complex64))
+    assert capture == """
+        Int branch taken.
+        Float branch taken.
+        Complex float branch taken.
+    """
+
+
+@pytest.requires_numpy
+def test_docs(doc):
+    from pybind11_tests import vectorized_func
+
+    assert doc(vectorized_func) == "vectorized_func(arg0: numpy.ndarray[int], arg1: numpy.ndarray[float], arg2: numpy.ndarray[float]) -> object"
diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp
new file mode 100644
index 0000000..0ede5e3
--- /dev/null
+++ b/tests/test_opaque_types.cpp
@@ -0,0 +1,62 @@
+/*
+    tests/test_opaque_types.cpp -- opaque types, passing void pointers
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include <pybind11/stl.h>
+#include <vector>
+
+typedef std::vector<std::string> StringList;
+
+class ClassWithSTLVecProperty {
+public:
+    StringList stringList;
+};
+
+/* IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures */
+PYBIND11_MAKE_OPAQUE(StringList);
+
+void init_ex_opaque_types(py::module &m) {
+    py::class_<StringList>(m, "StringList")
+        .def(py::init<>())
+        .def("pop_back", &StringList::pop_back)
+        /* There are multiple versions of push_back(), etc. Select the right ones. */
+        .def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back)
+        .def("back", (std::string &(StringList::*)()) &StringList::back)
+        .def("__len__", [](const StringList &v) { return v.size(); })
+        .def("__iter__", [](StringList &v) {
+           return py::make_iterator(v.begin(), v.end());
+        }, py::keep_alive<0, 1>());
+
+    py::class_<ClassWithSTLVecProperty>(m, "ClassWithSTLVecProperty")
+        .def(py::init<>())
+        .def_readwrite("stringList", &ClassWithSTLVecProperty::stringList);
+
+    m.def("print_opaque_list", [](const StringList &l) {
+        std::cout << "Opaque list: [";
+        bool first = true;
+        for (auto entry : l) {
+            if (!first)
+                std::cout << ", ";
+            std::cout << entry;
+            first = false;
+        }
+        std::cout << "]" << std::endl;
+    });
+
+    m.def("return_void_ptr", []() { return (void *) 0x1234; });
+    m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; });
+    m.def("return_null_str", []() { return (char *) nullptr; });
+    m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::dec << std::endl; });
+
+    m.def("return_unique_ptr", []() -> std::unique_ptr<StringList> {
+        StringList *result = new StringList();
+        result->push_back("some value");
+        return std::unique_ptr<StringList>(result);
+    });
+}
diff --git a/tests/test_opaque_types.py b/tests/test_opaque_types.py
new file mode 100644
index 0000000..5c2ca92
--- /dev/null
+++ b/tests/test_opaque_types.py
@@ -0,0 +1,64 @@
+import pytest
+
+
+def test_string_list(capture):
+    from pybind11_tests import StringList, ClassWithSTLVecProperty, print_opaque_list
+
+    l = StringList()
+    l.push_back("Element 1")
+    l.push_back("Element 2")
+    with capture:
+        print_opaque_list(l)
+    assert capture == "Opaque list: [Element 1, Element 2]"
+    assert l.back() == "Element 2"
+
+    for i, k in enumerate(l, start=1):
+        assert k == "Element {}".format(i)
+    l.pop_back()
+    with capture:
+        print_opaque_list(l)
+    assert capture == "Opaque list: [Element 1]"
+
+    cvp = ClassWithSTLVecProperty()
+    with capture:
+        print_opaque_list(cvp.stringList)
+    assert capture == "Opaque list: []"
+
+    cvp.stringList = l
+    cvp.stringList.push_back("Element 3")
+    with capture:
+        print_opaque_list(cvp.stringList)
+    assert capture == "Opaque list: [Element 1, Element 3]"
+
+
+def test_pointers(capture, msg):
+    from pybind11_tests import (return_void_ptr, print_void_ptr, ExampleMandA,
+                                print_opaque_list, return_null_str, print_null_str,
+                                return_unique_ptr, ConstructorStats)
+
+    with capture:
+        print_void_ptr(return_void_ptr())
+    assert capture == "Got void ptr : 0x1234"
+    with capture:
+        print_void_ptr(ExampleMandA())  # Should also work for other C++ types
+    assert "Got void ptr" in capture
+    assert ConstructorStats.get(ExampleMandA).alive() == 0
+
+    with pytest.raises(TypeError) as excinfo:
+        print_void_ptr([1, 2, 3])  # This should not work
+    assert msg(excinfo.value) == """
+        Incompatible function arguments. The following argument types are supported:
+            1. (arg0: capsule) -> None
+            Invoked with: [1, 2, 3]
+    """
+
+    assert return_null_str() is None
+    with capture:
+        print_null_str(return_null_str())
+    assert capture == "Got null str : 0x0"
+
+    ptr = return_unique_ptr()
+    assert "StringList" in repr(ptr)
+    with capture:
+        print_opaque_list(ptr)
+    assert capture == "Opaque list: [some value]"
diff --git a/tests/test_operator_overloading.cpp b/tests/test_operator_overloading.cpp
new file mode 100644
index 0000000..b84a5b8
--- /dev/null
+++ b/tests/test_operator_overloading.cpp
@@ -0,0 +1,76 @@
+/*
+    tests/test_operator_overloading.cpp -- operator overloading
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/operators.h>
+
+class Vector2 {
+public:
+    Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
+    Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
+    Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
+    ~Vector2() { print_destroyed(this); }
+
+    std::string toString() const {
+        return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
+    }
+
+    void operator=(const Vector2 &v) {
+        print_copy_assigned(this);
+        x = v.x;
+        y = v.y;
+    }
+
+    void operator=(Vector2 &&v) {
+        print_move_assigned(this);
+        x = v.x; y = v.y; v.x = v.y = 0;
+    }
+
+    Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
+    Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
+    Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
+    Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
+    Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
+    Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
+    Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; }
+    Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; }
+    Vector2& operator*=(float v) { x *= v; y *= v; return *this; }
+    Vector2& operator/=(float v) { x /= v; y /= v; return *this; }
+
+    friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
+    friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
+    friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
+    friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
+private:
+    float x, y;
+};
+
+void init_ex_operator_overloading(py::module &m) {
+    py::class_<Vector2>(m, "Vector2")
+        .def(py::init<float, float>())
+        .def(py::self + py::self)
+        .def(py::self + float())
+        .def(py::self - py::self)
+        .def(py::self - float())
+        .def(py::self * float())
+        .def(py::self / float())
+        .def(py::self += py::self)
+        .def(py::self -= py::self)
+        .def(py::self *= float())
+        .def(py::self /= float())
+        .def(float() + py::self)
+        .def(float() - py::self)
+        .def(float() * py::self)
+        .def(float() / py::self)
+        .def("__str__", &Vector2::toString)
+        ;
+
+    m.attr("Vector") = m.attr("Vector2");
+}
diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py
new file mode 100644
index 0000000..e0d4239
--- /dev/null
+++ b/tests/test_operator_overloading.py
@@ -0,0 +1,41 @@
+
+def test_operator_overloading():
+    from pybind11_tests import Vector2, Vector, ConstructorStats
+
+    v1 = Vector2(1, 2)
+    v2 = Vector(3, -1)
+    assert str(v1) == "[1.000000, 2.000000]"
+    assert str(v2) == "[3.000000, -1.000000]"
+
+    assert str(v1 + v2) == "[4.000000, 1.000000]"
+    assert str(v1 - v2) == "[-2.000000, 3.000000]"
+    assert str(v1 - 8) == "[-7.000000, -6.000000]"
+    assert str(v1 + 8) == "[9.000000, 10.000000]"
+    assert str(v1 * 8) == "[8.000000, 16.000000]"
+    assert str(v1 / 8) == "[0.125000, 0.250000]"
+    assert str(8 - v1) == "[7.000000, 6.000000]"
+    assert str(8 + v1) == "[9.000000, 10.000000]"
+    assert str(8 * v1) == "[8.000000, 16.000000]"
+    assert str(8 / v1) == "[8.000000, 4.000000]"
+
+    v1 += v2
+    v1 *= 2
+    assert str(v1) == "[8.000000, 2.000000]"
+
+    cstats = ConstructorStats.get(Vector2)
+    assert cstats.alive() == 2
+    del v1
+    assert cstats.alive() == 1
+    del v2
+    assert cstats.alive() == 0
+    assert cstats.values() == ['[1.000000, 2.000000]', '[3.000000, -1.000000]',
+                               '[4.000000, 1.000000]', '[-2.000000, 3.000000]',
+                               '[-7.000000, -6.000000]', '[9.000000, 10.000000]',
+                               '[8.000000, 16.000000]', '[0.125000, 0.250000]',
+                               '[7.000000, 6.000000]', '[9.000000, 10.000000]',
+                               '[8.000000, 16.000000]', '[8.000000, 4.000000]']
+    assert cstats.default_constructions == 0
+    assert cstats.copy_constructions == 0
+    assert cstats.move_constructions >= 10
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
diff --git a/tests/test_pickling.cpp b/tests/test_pickling.cpp
new file mode 100644
index 0000000..4a48452
--- /dev/null
+++ b/tests/test_pickling.cpp
@@ -0,0 +1,51 @@
+/*
+    tests/test_pickling.cpp -- pickle support
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+class Pickleable {
+public:
+    Pickleable(const std::string &value) : m_value(value) { }
+    const std::string &value() const { return m_value; }
+
+    void setExtra1(int extra1) { m_extra1 = extra1; }
+    void setExtra2(int extra2) { m_extra2 = extra2; }
+    int extra1() const { return m_extra1; }
+    int extra2() const { return m_extra2; }
+private:
+    std::string m_value;
+    int m_extra1 = 0;
+    int m_extra2 = 0;
+};
+
+void init_ex_pickling(py::module &m) {
+    py::class_<Pickleable>(m, "Pickleable")
+        .def(py::init<std::string>())
+        .def("value", &Pickleable::value)
+        .def("extra1", &Pickleable::extra1)
+        .def("extra2", &Pickleable::extra2)
+        .def("setExtra1", &Pickleable::setExtra1)
+        .def("setExtra2", &Pickleable::setExtra2)
+        // For details on the methods below, refer to
+        // http://docs.python.org/3/library/pickle.html#pickling-class-instances
+        .def("__getstate__", [](const Pickleable &p) {
+            /* Return a tuple that fully encodes the state of the object */
+            return py::make_tuple(p.value(), p.extra1(), p.extra2());
+        })
+        .def("__setstate__", [](Pickleable &p, py::tuple t) {
+            if (t.size() != 3)
+                throw std::runtime_error("Invalid state!");
+            /* Invoke the constructor (need to use in-place version) */
+            new (&p) Pickleable(t[0].cast<std::string>());
+
+            /* Assign any additional state */
+            p.setExtra1(t[1].cast<int>());
+            p.setExtra2(t[2].cast<int>());
+        });
+}
diff --git a/tests/test_pickling.py b/tests/test_pickling.py
new file mode 100644
index 0000000..f6e4c04
--- /dev/null
+++ b/tests/test_pickling.py
@@ -0,0 +1,18 @@
+try:
+    import cPickle as pickle  # Use cPickle on Python 2.7
+except ImportError:
+    import pickle
+
+from pybind11_tests import Pickleable
+
+
+def test_roundtrip():
+    p = Pickleable("test_value")
+    p.setExtra1(15)
+    p.setExtra2(48)
+
+    data = pickle.dumps(p, 2)  # Must use pickle protocol >= 2
+    p2 = pickle.loads(data)
+    assert p2.value() == p.value()
+    assert p2.extra1() == p.extra1()
+    assert p2.extra2() == p.extra2()
diff --git a/tests/test_python_types.cpp b/tests/test_python_types.cpp
new file mode 100644
index 0000000..39e43eb
--- /dev/null
+++ b/tests/test_python_types.cpp
@@ -0,0 +1,200 @@
+/*
+    tests/test_python_types.cpp -- singleton design pattern, static functions and
+    variables, passing and interacting with Python types
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/stl.h>
+
+#ifdef _WIN32
+#  include <io.h>
+#  include <fcntl.h>
+#endif
+
+class ExamplePythonTypes {
+public:
+    static ExamplePythonTypes *new_instance() {
+        auto *ptr = new ExamplePythonTypes();
+        print_created(ptr, "via new_instance");
+        return ptr;
+    }
+    ~ExamplePythonTypes() { print_destroyed(this); }
+
+    /* Create and return a Python dictionary */
+    py::dict get_dict() {
+        py::dict dict;
+        dict[py::str("key")] = py::str("value");
+        return dict;
+    }
+
+    /* Create and return a Python set */
+    py::set get_set() {
+        py::set set;
+        set.add(py::str("key1"));
+        set.add(py::str("key2"));
+        return set;
+    }
+
+    /* Create and return a C++ dictionary */
+    std::map<std::string, std::string> get_dict_2() {
+        std::map<std::string, std::string> result;
+        result["key"] = "value";
+        return result;
+    }
+
+    /* Create and return a C++ set */
+    std::set<std::string> get_set_2() {
+        std::set<std::string> result;
+        result.insert("key1");
+        result.insert("key2");
+        return result;
+    }
+
+    /* Create, manipulate, and return a Python list */
+    py::list get_list() {
+        py::list list;
+        list.append(py::str("value"));
+        cout << "Entry at positon 0: " << py::object(list[0]) << endl;
+        list[0] = py::str("overwritten");
+        return list;
+    }
+
+    /* C++ STL data types are automatically casted */
+    std::vector<std::wstring> get_list_2() {
+        std::vector<std::wstring> list;
+        list.push_back(L"value");
+        return list;
+    }
+
+    /* C++ STL data types are automatically casted */
+    std::array<std::string, 2> get_array() {
+        return std::array<std::string, 2> {{ "array entry 1" , "array entry 2"}};
+    }
+
+    /* Easily iterate over a dictionary using a C++11 range-based for loop */
+    void print_dict(py::dict dict) {
+        for (auto item : dict)
+            std::cout << "key: " << item.first << ", value=" << item.second << std::endl;
+    }
+
+    /* Easily iterate over a set using a C++11 range-based for loop */
+    void print_set(py::set set) {
+        for (auto item : set)
+            std::cout << "key: " << item << std::endl;
+    }
+
+    /* Easily iterate over a list using a C++11 range-based for loop */
+    void print_list(py::list list) {
+        int index = 0;
+        for (auto item : list)
+            std::cout << "list item " << index++ << ": " << item << std::endl;
+    }
+
+    /* STL data types (such as maps) are automatically casted from Python */
+    void print_dict_2(const std::map<std::string, std::string> &dict) {
+        for (auto item : dict)
+            std::cout << "key: " << item.first << ", value=" << item.second << std::endl;
+    }
+
+    /* STL data types (such as sets) are automatically casted from Python */
+    void print_set_2(const std::set<std::string> &set) {
+        for (auto item : set)
+            std::cout << "key: " << item << std::endl;
+    }
+
+    /* STL data types (such as vectors) are automatically casted from Python */
+    void print_list_2(std::vector<std::wstring> &list) {
+#ifdef _WIN32 /* Can't easily mix cout and wcout on Windows */
+        _setmode(_fileno(stdout), _O_TEXT);
+#endif
+        int index = 0;
+        for (auto item : list)
+            std::wcout << L"list item " << index++ << L": " << item << std::endl;
+    }
+
+    /* pybind automatically translates between C++11 and Python tuples */
+    std::pair<std::string, bool> pair_passthrough(std::pair<bool, std::string> input) {
+        return std::make_pair(input.second, input.first);
+    }
+
+    /* pybind automatically translates between C++11 and Python tuples */
+    std::tuple<int, std::string, bool> tuple_passthrough(std::tuple<bool, std::string, int> input) {
+        return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input));
+    }
+
+    /* STL data types (such as arrays) are automatically casted from Python */
+    void print_array(std::array<std::string, 2> &array) {
+        int index = 0;
+        for (auto item : array)
+            std::cout << "array item " << index++ << ": " << item << std::endl;
+    }
+
+    void throw_exception() {
+        throw std::runtime_error("This exception was intentionally thrown.");
+    }
+
+    py::bytes get_bytes_from_string() {
+        return (py::bytes) std::string("foo");
+    }
+
+    py::bytes get_bytes_from_str() {
+        return (py::bytes) py::str("bar", 3);
+    }
+
+    py::str get_str_from_string() {
+        return (py::str) std::string("baz");
+    }
+
+    py::str get_str_from_bytes() {
+        return (py::str) py::bytes("boo", 3);
+    }
+
+    void test_print(const py::object& obj) {
+        std::cout << obj.str() << std::endl;
+        std::cout << obj.repr() << std::endl;
+    }
+
+    static int value;
+    static const int value2;
+};
+
+int ExamplePythonTypes::value = 0;
+const int ExamplePythonTypes::value2 = 5;
+
+void init_ex_python_types(py::module &m) {
+    /* No constructor is explicitly defined below. An exception is raised when
+       trying to construct it directly from Python */
+    py::class_<ExamplePythonTypes>(m, "ExamplePythonTypes", "Example 2 documentation")
+        .def("get_dict", &ExamplePythonTypes::get_dict, "Return a Python dictionary")
+        .def("get_dict_2", &ExamplePythonTypes::get_dict_2, "Return a C++ dictionary")
+        .def("get_list", &ExamplePythonTypes::get_list, "Return a Python list")
+        .def("get_list_2", &ExamplePythonTypes::get_list_2, "Return a C++ list")
+        .def("get_set", &ExamplePythonTypes::get_set, "Return a Python set")
+        .def("get_set2", &ExamplePythonTypes::get_set_2, "Return a C++ set")
+        .def("get_array", &ExamplePythonTypes::get_array, "Return a C++ array")
+        .def("print_dict", &ExamplePythonTypes::print_dict, "Print entries of a Python dictionary")
+        .def("print_dict_2", &ExamplePythonTypes::print_dict_2, "Print entries of a C++ dictionary")
+        .def("print_set", &ExamplePythonTypes::print_set, "Print entries of a Python set")
+        .def("print_set_2", &ExamplePythonTypes::print_set_2, "Print entries of a C++ set")
+        .def("print_list", &ExamplePythonTypes::print_list, "Print entries of a Python list")
+        .def("print_list_2", &ExamplePythonTypes::print_list_2, "Print entries of a C++ list")
+        .def("print_array", &ExamplePythonTypes::print_array, "Print entries of a C++ array")
+        .def("pair_passthrough", &ExamplePythonTypes::pair_passthrough, "Return a pair in reversed order")
+        .def("tuple_passthrough", &ExamplePythonTypes::tuple_passthrough, "Return a triple in reversed order")
+        .def("throw_exception", &ExamplePythonTypes::throw_exception, "Throw an exception")
+        .def("get_bytes_from_string", &ExamplePythonTypes::get_bytes_from_string, "py::bytes from std::string")
+        .def("get_bytes_from_str", &ExamplePythonTypes::get_bytes_from_str, "py::bytes from py::str")
+        .def("get_str_from_string", &ExamplePythonTypes::get_str_from_string, "py::str from std::string")
+        .def("get_str_from_bytes", &ExamplePythonTypes::get_str_from_bytes, "py::str from py::bytes")
+        .def("test_print", &ExamplePythonTypes::test_print, "test the print function")
+        .def_static("new_instance", &ExamplePythonTypes::new_instance, "Return an instance")
+        .def_readwrite_static("value", &ExamplePythonTypes::value, "Static value member")
+        .def_readonly_static("value2", &ExamplePythonTypes::value2, "Static value member (readonly)")
+        ;
+}
diff --git a/tests/test_python_types.py b/tests/test_python_types.py
new file mode 100644
index 0000000..3738d41
--- /dev/null
+++ b/tests/test_python_types.py
@@ -0,0 +1,220 @@
+import pytest
+
+from pybind11_tests import ExamplePythonTypes, ConstructorStats
+
+
+def test_static():
+    ExamplePythonTypes.value = 15
+    assert ExamplePythonTypes.value == 15
+    assert ExamplePythonTypes.value2 == 5
+
+    with pytest.raises(AttributeError) as excinfo:
+        ExamplePythonTypes.value2 = 15
+    assert str(excinfo.value) == "can't set attribute"
+
+
+def test_instance(capture):
+    with pytest.raises(TypeError) as excinfo:
+        ExamplePythonTypes()
+    assert str(excinfo.value) == "pybind11_tests.ExamplePythonTypes: No constructor defined!"
+
+    instance = ExamplePythonTypes.new_instance()
+
+    with capture:
+        dict_result = instance.get_dict()
+        dict_result['key2'] = 'value2'
+        instance.print_dict(dict_result)
+    assert capture.unordered == """
+        key: key, value=value
+        key: key2, value=value2
+    """
+    with capture:
+        dict_result = instance.get_dict_2()
+        dict_result['key2'] = 'value2'
+        instance.print_dict_2(dict_result)
+    assert capture.unordered == """
+        key: key, value=value
+        key: key2, value=value2
+    """
+    with capture:
+        set_result = instance.get_set()
+        set_result.add('key3')
+        instance.print_set(set_result)
+    assert capture.unordered == """
+        key: key1
+        key: key2
+        key: key3
+    """
+    with capture:
+        set_result = instance.get_set2()
+        set_result.add('key3')
+        instance.print_set_2(set_result)
+    assert capture.unordered == """
+        key: key1
+        key: key2
+        key: key3
+    """
+    with capture:
+        list_result = instance.get_list()
+        list_result.append('value2')
+        instance.print_list(list_result)
+    assert capture.unordered == """
+        Entry at positon 0: value
+        list item 0: overwritten
+        list item 1: value2
+    """
+    with capture:
+        list_result = instance.get_list_2()
+        list_result.append('value2')
+        instance.print_list_2(list_result)
+    assert capture.unordered == """
+        list item 0: value
+        list item 1: value2
+    """
+    array_result = instance.get_array()
+    assert array_result == ['array entry 1', 'array entry 2']
+    with capture:
+        instance.print_array(array_result)
+    assert capture.unordered == """
+        array item 0: array entry 1
+        array item 1: array entry 2
+    """
+    with pytest.raises(RuntimeError) as excinfo:
+        instance.throw_exception()
+    assert str(excinfo.value) == "This exception was intentionally thrown."
+
+    assert instance.pair_passthrough((True, "test")) == ("test", True)
+    assert instance.tuple_passthrough((True, "test", 5)) == (5, "test", True)
+
+    assert instance.get_bytes_from_string().decode() == "foo"
+    assert instance.get_bytes_from_str().decode() == "bar"
+    assert instance.get_str_from_string().encode().decode() == "baz"
+    assert instance.get_str_from_bytes().encode().decode() == "boo"
+
+    class A(object):
+        def __str__(self):
+            return "this is a str"
+
+        def __repr__(self):
+            return "this is a repr"
+
+    with capture:
+        instance.test_print(A())
+    assert capture == """
+        this is a str
+        this is a repr
+    """
+
+    cstats = ConstructorStats.get(ExamplePythonTypes)
+    assert cstats.alive() == 1
+    del instance
+    assert cstats.alive() == 0
+
+
+def test_docs(doc):
+    assert doc(ExamplePythonTypes) == "Example 2 documentation"
+    assert doc(ExamplePythonTypes.get_dict) == """
+        get_dict(self: m.ExamplePythonTypes) -> dict
+
+        Return a Python dictionary
+    """
+    assert doc(ExamplePythonTypes.get_dict_2) == """
+        get_dict_2(self: m.ExamplePythonTypes) -> Dict[str, str]
+
+        Return a C++ dictionary
+    """
+    assert doc(ExamplePythonTypes.get_list) == """
+        get_list(self: m.ExamplePythonTypes) -> list
+
+        Return a Python list
+    """
+    assert doc(ExamplePythonTypes.get_list_2) == """
+        get_list_2(self: m.ExamplePythonTypes) -> List[str]
+
+        Return a C++ list
+    """
+    assert doc(ExamplePythonTypes.get_dict) == """
+        get_dict(self: m.ExamplePythonTypes) -> dict
+
+        Return a Python dictionary
+    """
+    assert doc(ExamplePythonTypes.get_set) == """
+        get_set(self: m.ExamplePythonTypes) -> set
+
+        Return a Python set
+    """
+    assert doc(ExamplePythonTypes.get_set2) == """
+        get_set2(self: m.ExamplePythonTypes) -> Set[str]
+
+        Return a C++ set
+    """
+    assert doc(ExamplePythonTypes.get_array) == """
+        get_array(self: m.ExamplePythonTypes) -> List[str[2]]
+
+        Return a C++ array
+    """
+    assert doc(ExamplePythonTypes.print_dict) == """
+        print_dict(self: m.ExamplePythonTypes, arg0: dict) -> None
+
+        Print entries of a Python dictionary
+    """
+    assert doc(ExamplePythonTypes.print_dict_2) == """
+        print_dict_2(self: m.ExamplePythonTypes, arg0: Dict[str, str]) -> None
+
+        Print entries of a C++ dictionary
+    """
+    assert doc(ExamplePythonTypes.print_set) == """
+        print_set(self: m.ExamplePythonTypes, arg0: set) -> None
+
+        Print entries of a Python set
+    """
+    assert doc(ExamplePythonTypes.print_set_2) == """
+        print_set_2(self: m.ExamplePythonTypes, arg0: Set[str]) -> None
+
+        Print entries of a C++ set
+    """
+    assert doc(ExamplePythonTypes.print_list) == """
+        print_list(self: m.ExamplePythonTypes, arg0: list) -> None
+
+        Print entries of a Python list
+    """
+    assert doc(ExamplePythonTypes.print_list_2) == """
+        print_list_2(self: m.ExamplePythonTypes, arg0: List[str]) -> None
+
+        Print entries of a C++ list
+    """
+    assert doc(ExamplePythonTypes.print_array) == """
+        print_array(self: m.ExamplePythonTypes, arg0: List[str[2]]) -> None
+
+        Print entries of a C++ array
+    """
+    assert doc(ExamplePythonTypes.pair_passthrough) == """
+        pair_passthrough(self: m.ExamplePythonTypes, arg0: Tuple[bool, str]) -> Tuple[str, bool]
+
+        Return a pair in reversed order
+    """
+    assert doc(ExamplePythonTypes.tuple_passthrough) == """
+        tuple_passthrough(self: m.ExamplePythonTypes, arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool]
+
+        Return a triple in reversed order
+    """
+    assert doc(ExamplePythonTypes.throw_exception) == """
+        throw_exception(self: m.ExamplePythonTypes) -> None
+
+        Throw an exception
+    """
+    assert doc(ExamplePythonTypes.new_instance) == """
+        new_instance() -> m.ExamplePythonTypes
+
+        Return an instance
+    """
+
+
+def test_module():
+    import pybind11_tests
+
+    assert pybind11_tests.__name__ == "pybind11_tests"
+    assert ExamplePythonTypes.__name__ == "ExamplePythonTypes"
+    assert ExamplePythonTypes.__module__ == "pybind11_tests"
+    assert ExamplePythonTypes.get_set.__name__ == "get_set"
+    assert ExamplePythonTypes.get_set.__module__ == "pybind11_tests"
diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp
new file mode 100644
index 0000000..a92c6bf
--- /dev/null
+++ b/tests/test_sequences_and_iterators.cpp
@@ -0,0 +1,240 @@
+/*
+    tests/test_sequences_and_iterators.cpp -- supporting Pythons' sequence protocol, iterators,
+    etc.
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/operators.h>
+#include <pybind11/stl.h>
+
+class Sequence {
+public:
+    Sequence(size_t size) : m_size(size) {
+        print_created(this, "of size", m_size);
+        m_data = new float[size];
+        memset(m_data, 0, sizeof(float) * size);
+    }
+
+    Sequence(const std::vector<float> &value) : m_size(value.size()) {
+        print_created(this, "of size", m_size, "from std::vector");
+        m_data = new float[m_size];
+        memcpy(m_data, &value[0], sizeof(float) * m_size);
+    }
+
+    Sequence(const Sequence &s) : m_size(s.m_size) {
+        print_copy_created(this);
+        m_data = new float[m_size];
+        memcpy(m_data, s.m_data, sizeof(float)*m_size);
+    }
+
+    Sequence(Sequence &&s) : m_size(s.m_size), m_data(s.m_data) {
+        print_move_created(this);
+        s.m_size = 0;
+        s.m_data = nullptr;
+    }
+
+    ~Sequence() {
+        print_destroyed(this);
+        delete[] m_data;
+    }
+
+    Sequence &operator=(const Sequence &s) {
+        if (&s != this) {
+            delete[] m_data;
+            m_size = s.m_size;
+            m_data = new float[m_size];
+            memcpy(m_data, s.m_data, sizeof(float)*m_size);
+        }
+
+        print_copy_assigned(this);
+
+        return *this;
+    }
+
+    Sequence &operator=(Sequence &&s) {
+        if (&s != this) {
+            delete[] m_data;
+            m_size = s.m_size;
+            m_data = s.m_data;
+            s.m_size = 0;
+            s.m_data = nullptr;
+        }
+
+        print_move_assigned(this);
+
+        return *this;
+    }
+
+    bool operator==(const Sequence &s) const {
+        if (m_size != s.size())
+            return false;
+        for (size_t i=0; i<m_size; ++i)
+            if (m_data[i] != s[i])
+                return false;
+        return true;
+    }
+
+    bool operator!=(const Sequence &s) const {
+        return !operator==(s);
+    }
+
+    float operator[](size_t index) const {
+        return m_data[index];
+    }
+
+    float &operator[](size_t index) {
+        return m_data[index];
+    }
+
+    bool contains(float v) const {
+        for (size_t i=0; i<m_size; ++i)
+            if (v == m_data[i])
+                return true;
+        return false;
+    }
+
+    Sequence reversed() const {
+        Sequence result(m_size);
+        for (size_t i=0; i<m_size; ++i)
+            result[m_size-i-1] = m_data[i];
+        return result;
+    }
+
+    size_t size() const { return m_size; }
+
+    const float *begin() const { return m_data; }
+    const float *end() const { return m_data+m_size; }
+
+private:
+    size_t m_size;
+    float *m_data;
+};
+
+// Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic
+// map-like functionality.
+class StringMap {
+public:
+    StringMap(std::unordered_map<std::string, std::string> init = {})
+        : map(std::move(init)) {}
+
+    void set(std::string key, std::string val) {
+        map[key] = val;
+    }
+
+    std::string get(std::string key) const {
+        return map.at(key);
+    }
+
+    size_t size() const {
+        return map.size();
+    }
+
+private:
+    std::unordered_map<std::string, std::string> map;
+
+public:
+    decltype(map.cbegin()) begin() const { return map.cbegin(); }
+    decltype(map.cend()) end() const { return map.cend(); }
+};
+
+
+void init_ex_sequences_and_iterators(py::module &m) {
+    py::class_<Sequence> seq(m, "Sequence");
+
+    seq.def(py::init<size_t>())
+       .def(py::init<const std::vector<float>&>())
+       /// Bare bones interface
+       .def("__getitem__", [](const Sequence &s, size_t i) {
+            if (i >= s.size())
+                throw py::index_error();
+            return s[i];
+        })
+       .def("__setitem__", [](Sequence &s, size_t i, float v) {
+            if (i >= s.size())
+                throw py::index_error();
+            s[i] = v;
+        })
+       .def("__len__", &Sequence::size)
+       /// Optional sequence protocol operations
+       .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); },
+                        py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */)
+       .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); })
+       .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); })
+       /// Slicing protocol (optional)
+       .def("__getitem__", [](const Sequence &s, py::slice slice) -> Sequence* {
+            size_t start, stop, step, slicelength;
+            if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
+                throw py::error_already_set();
+            Sequence *seq = new Sequence(slicelength);
+            for (size_t i=0; i<slicelength; ++i) {
+                (*seq)[i] = s[start]; start += step;
+            }
+            return seq;
+        })
+       .def("__setitem__", [](Sequence &s, py::slice slice, const Sequence &value) {
+            size_t start, stop, step, slicelength;
+            if (!slice.compute(s.size(), &start, &stop, &step, &slicelength))
+                throw py::error_already_set();
+            if (slicelength != value.size())
+                throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
+            for (size_t i=0; i<slicelength; ++i) {
+                s[start] = value[i]; start += step;
+            }
+        })
+       /// Comparisons
+       .def(py::self == py::self)
+       .def(py::self != py::self);
+       // Could also define py::self + py::self for concatenation, etc.
+
+    py::class_<StringMap> map(m, "StringMap");
+
+    map .def(py::init<>())
+        .def(py::init<std::unordered_map<std::string, std::string>>())
+        .def("__getitem__", [](const StringMap &map, std::string key) {
+                try { return map.get(key); }
+                catch (const std::out_of_range&) {
+                    throw py::key_error("key '" + key + "' does not exist");
+                }
+                })
+        .def("__setitem__", &StringMap::set)
+        .def("__len__", &StringMap::size)
+        .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); },
+                py::keep_alive<0, 1>())
+        .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); },
+                py::keep_alive<0, 1>())
+        ;
+
+
+#if 0
+    // Obsolete: special data structure for exposing custom iterator types to python
+    // kept here for illustrative purposes because there might be some use cases which
+    // are not covered by the much simpler py::make_iterator
+
+    struct PySequenceIterator {
+        PySequenceIterator(const Sequence &seq, py::object ref) : seq(seq), ref(ref) { }
+
+        float next() {
+            if (index == seq.size())
+                throw py::stop_iteration();
+            return seq[index++];
+        }
+
+        const Sequence &seq;
+        py::object ref; // keep a reference
+        size_t index = 0;
+    };
+
+    py::class_<PySequenceIterator>(seq, "Iterator")
+        .def("__iter__", [](PySequenceIterator &it) -> PySequenceIterator& { return it; })
+        .def("__next__", &PySequenceIterator::next);
+
+    On the actual Sequence object, the iterator would be constructed as follows:
+    .def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
+#endif
+}
diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py
new file mode 100644
index 0000000..a35dc58
--- /dev/null
+++ b/tests/test_sequences_and_iterators.py
@@ -0,0 +1,78 @@
+import pytest
+
+
+def isclose(a, b, rel_tol=1e-05, abs_tol=0.0):
+    """Like to math.isclose() from Python 3.5"""
+    return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
+
+
+def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0):
+    return all(isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list))
+
+
+def test_sequence():
+    from pybind11_tests import Sequence, ConstructorStats
+
+    cstats = ConstructorStats.get(Sequence)
+
+    s = Sequence(5)
+    assert cstats.values() == ['of size', '5']
+
+    assert "Sequence" in repr(s)
+    assert len(s) == 5
+    assert s[0] == 0 and s[3] == 0
+    assert 12.34 not in s
+    s[0], s[3] = 12.34, 56.78
+    assert 12.34 in s
+    assert isclose(s[0], 12.34) and isclose(s[3], 56.78)
+
+    rev = reversed(s)
+    assert cstats.values() == ['of size', '5']
+
+    rev2 = s[::-1]
+    assert cstats.values() == ['of size', '5']
+
+    expected = [0, 56.78, 0, 0, 12.34]
+    assert allclose(rev, expected)
+    assert allclose(rev2, expected)
+    assert rev == rev2
+
+    rev[0::2] = Sequence([2.0, 2.0, 2.0])
+    assert cstats.values() == ['of size', '3', 'from std::vector']
+
+    assert allclose(rev, [2, 56.78, 2, 0, 2])
+
+    assert cstats.alive() == 3
+    del s
+    assert cstats.alive() == 2
+    del rev
+    assert cstats.alive() == 1
+    del rev2
+    assert cstats.alive() == 0
+
+    assert cstats.values() == []
+    assert cstats.default_constructions == 0
+    assert cstats.copy_constructions == 0
+    assert cstats.move_constructions >= 1
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
+
+
+def test_map_iterator():
+    from pybind11_tests import StringMap
+
+    m = StringMap({'hi': 'bye', 'black': 'white'})
+    assert m['hi'] == 'bye'
+    assert len(m) == 2
+    assert m['black'] == 'white'
+
+    with pytest.raises(KeyError):
+        assert m['orange']
+    m['orange'] = 'banana'
+    assert m['orange'] == 'banana'
+
+    expected = {'hi': 'bye', 'black': 'white', 'orange': 'banana'}
+    for k in m:
+        assert m[k] == expected[k]
+    for k, v in m.items():
+        assert v == expected[k]
diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp
new file mode 100644
index 0000000..46c83b3
--- /dev/null
+++ b/tests/test_smart_ptr.cpp
@@ -0,0 +1,150 @@
+/*
+    tests/test_smart_ptr.cpp -- binding classes with custom reference counting,
+    implicit conversions between types
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "object.h"
+
+/// Custom object with builtin reference counting (see 'object.h' for the implementation)
+class MyObject1 : public Object {
+public:
+    MyObject1(int value) : value(value) {
+        print_created(this, toString());
+    }
+
+    std::string toString() const {
+        return "MyObject1[" + std::to_string(value) + "]";
+    }
+
+protected:
+    virtual ~MyObject1() {
+        print_destroyed(this);
+    }
+
+private:
+    int value;
+};
+
+/// Object managed by a std::shared_ptr<>
+class MyObject2 {
+public:
+    MyObject2(int value) : value(value) {
+        print_created(this, toString());
+    }
+
+    std::string toString() const {
+        return "MyObject2[" + std::to_string(value) + "]";
+    }
+
+    virtual ~MyObject2() {
+        print_destroyed(this);
+    }
+
+private:
+    int value;
+};
+
+/// Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<>
+class MyObject3 : public std::enable_shared_from_this<MyObject3> {
+public:
+    MyObject3(int value) : value(value) {
+        print_created(this, toString());
+    }
+
+    std::string toString() const {
+        return "MyObject3[" + std::to_string(value) + "]";
+    }
+
+    virtual ~MyObject3() {
+        print_destroyed(this);
+    }
+
+private:
+    int value;
+};
+
+/// Make pybind aware of the ref-counted wrapper type (s)
+PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>);
+PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
+
+Object *make_object_1() { return new MyObject1(1); }
+ref<Object> make_object_2() { return new MyObject1(2); }
+
+MyObject1 *make_myobject1_1() { return new MyObject1(4); }
+ref<MyObject1> make_myobject1_2() { return new MyObject1(5); }
+
+MyObject2 *make_myobject2_1() { return new MyObject2(6); }
+std::shared_ptr<MyObject2> make_myobject2_2() { return std::make_shared<MyObject2>(7); }
+
+MyObject3 *make_myobject3_1() { return new MyObject3(8); }
+std::shared_ptr<MyObject3> make_myobject3_2() { return std::make_shared<MyObject3>(9); }
+
+void print_object_1(const Object *obj) { std::cout << obj->toString() << std::endl; }
+void print_object_2(ref<Object> obj) { std::cout << obj->toString() << std::endl; }
+void print_object_3(const ref<Object> &obj) { std::cout << obj->toString() << std::endl; }
+void print_object_4(const ref<Object> *obj) { std::cout << (*obj)->toString() << std::endl; }
+
+void print_myobject1_1(const MyObject1 *obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject1_2(ref<MyObject1> obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject1_3(const ref<MyObject1> &obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject1_4(const ref<MyObject1> *obj) { std::cout << (*obj)->toString() << std::endl; }
+
+void print_myobject2_1(const MyObject2 *obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject2_2(std::shared_ptr<MyObject2> obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject2_3(const std::shared_ptr<MyObject2> &obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject2_4(const std::shared_ptr<MyObject2> *obj) { std::cout << (*obj)->toString() << std::endl; }
+
+void print_myobject3_1(const MyObject3 *obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject3_2(std::shared_ptr<MyObject3> obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject3_3(const std::shared_ptr<MyObject3> &obj) { std::cout << obj->toString() << std::endl; }
+void print_myobject3_4(const std::shared_ptr<MyObject3> *obj) { std::cout << (*obj)->toString() << std::endl; }
+
+void init_ex_smart_ptr(py::module &m) {
+    py::class_<Object, ref<Object>> obj(m, "Object");
+    obj.def("getRefCount", &Object::getRefCount);
+
+    py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj)
+        .def(py::init<int>());
+
+    m.def("make_object_1", &make_object_1);
+    m.def("make_object_2", &make_object_2);
+    m.def("make_myobject1_1", &make_myobject1_1);
+    m.def("make_myobject1_2", &make_myobject1_2);
+    m.def("print_object_1", &print_object_1);
+    m.def("print_object_2", &print_object_2);
+    m.def("print_object_3", &print_object_3);
+    m.def("print_object_4", &print_object_4);
+    m.def("print_myobject1_1", &print_myobject1_1);
+    m.def("print_myobject1_2", &print_myobject1_2);
+    m.def("print_myobject1_3", &print_myobject1_3);
+    m.def("print_myobject1_4", &print_myobject1_4);
+
+    py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2")
+        .def(py::init<int>());
+    m.def("make_myobject2_1", &make_myobject2_1);
+    m.def("make_myobject2_2", &make_myobject2_2);
+    m.def("print_myobject2_1", &print_myobject2_1);
+    m.def("print_myobject2_2", &print_myobject2_2);
+    m.def("print_myobject2_3", &print_myobject2_3);
+    m.def("print_myobject2_4", &print_myobject2_4);
+
+    py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3")
+        .def(py::init<int>());
+    m.def("make_myobject3_1", &make_myobject3_1);
+    m.def("make_myobject3_2", &make_myobject3_2);
+    m.def("print_myobject3_1", &print_myobject3_1);
+    m.def("print_myobject3_2", &print_myobject3_2);
+    m.def("print_myobject3_3", &print_myobject3_3);
+    m.def("print_myobject3_4", &print_myobject3_4);
+
+    py::implicitly_convertible<py::int_, MyObject1>();
+
+    // Expose constructor stats for the ref type
+    m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
+}
diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py
new file mode 100644
index 0000000..ffc407d
--- /dev/null
+++ b/tests/test_smart_ptr.py
@@ -0,0 +1,115 @@
+from pybind11_tests import ConstructorStats
+
+
+def test_smart_ptr(capture):
+    # Object1
+    from pybind11_tests import (MyObject1, make_object_1, make_object_2,
+                                print_object_1, print_object_2, print_object_3, print_object_4)
+
+    for i, o in enumerate([make_object_1(), make_object_2(), MyObject1(3)], start=1):
+        assert o.getRefCount() == 1
+        with capture:
+            print_object_1(o)
+            print_object_2(o)
+            print_object_3(o)
+            print_object_4(o)
+        assert capture == "MyObject1[{i}]\n".format(i=i) * 4
+
+    from pybind11_tests import (make_myobject1_1, make_myobject1_2,
+                                print_myobject1_1, print_myobject1_2,
+                                print_myobject1_3, print_myobject1_4)
+
+    for i, o in enumerate([make_myobject1_1(), make_myobject1_2(), MyObject1(6), 7], start=4):
+        print(o)
+        with capture:
+            if not isinstance(o, int):
+                print_object_1(o)
+                print_object_2(o)
+                print_object_3(o)
+                print_object_4(o)
+            print_myobject1_1(o)
+            print_myobject1_2(o)
+            print_myobject1_3(o)
+            print_myobject1_4(o)
+        assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
+
+    cstats = ConstructorStats.get(MyObject1)
+    assert cstats.alive() == 0
+    expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
+    assert cstats.values() == expected_values
+    assert cstats.default_constructions == 0
+    assert cstats.copy_constructions == 0
+    # assert cstats.move_constructions >= 0 # Doesn't invoke any
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
+
+    # Object2
+    from pybind11_tests import (MyObject2, make_myobject2_1, make_myobject2_2,
+                                make_myobject3_1, make_myobject3_2,
+                                print_myobject2_1, print_myobject2_2,
+                                print_myobject2_3, print_myobject2_4)
+
+    for i, o in zip([8, 6, 7], [MyObject2(8), make_myobject2_1(), make_myobject2_2()]):
+        print(o)
+        with capture:
+            print_myobject2_1(o)
+            print_myobject2_2(o)
+            print_myobject2_3(o)
+            print_myobject2_4(o)
+        assert capture == "MyObject2[{i}]\n".format(i=i) * 4
+
+    cstats = ConstructorStats.get(MyObject2)
+    assert cstats.alive() == 1
+    o = None
+    assert cstats.alive() == 0
+    assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
+    assert cstats.default_constructions == 0
+    assert cstats.copy_constructions == 0
+    # assert cstats.move_constructions >= 0 # Doesn't invoke any
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
+
+    # Object3
+    from pybind11_tests import (MyObject3, print_myobject3_1, print_myobject3_2,
+                                print_myobject3_3, print_myobject3_4)
+
+    for i, o in zip([9, 8, 9], [MyObject3(9), make_myobject3_1(), make_myobject3_2()]):
+        print(o)
+        with capture:
+            print_myobject3_1(o)
+            print_myobject3_2(o)
+            print_myobject3_3(o)
+            print_myobject3_4(o)
+        assert capture == "MyObject3[{i}]\n".format(i=i) * 4
+
+    cstats = ConstructorStats.get(MyObject3)
+    assert cstats.alive() == 1
+    o = None
+    assert cstats.alive() == 0
+    assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
+    assert cstats.default_constructions == 0
+    assert cstats.copy_constructions == 0
+    # assert cstats.move_constructions >= 0 # Doesn't invoke any
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
+
+    # Object and ref
+    from pybind11_tests import Object, cstats_ref
+
+    cstats = ConstructorStats.get(Object)
+    assert cstats.alive() == 0
+    assert cstats.values() == []
+    assert cstats.default_constructions == 10
+    assert cstats.copy_constructions == 0
+    # assert cstats.move_constructions >= 0 # Doesn't invoke any
+    assert cstats.copy_assignments == 0
+    assert cstats.move_assignments == 0
+
+    cstats = cstats_ref()
+    assert cstats.alive() == 0
+    assert cstats.values() == ['from pointer'] * 10
+    assert cstats.default_constructions == 30
+    assert cstats.copy_constructions == 12
+    # assert cstats.move_constructions >= 0 # Doesn't invoke any
+    assert cstats.copy_assignments == 30
+    assert cstats.move_assignments == 0
diff --git a/tests/test_stl_binders.cpp b/tests/test_stl_binders.cpp
new file mode 100644
index 0000000..e2a44e1
--- /dev/null
+++ b/tests/test_stl_binders.cpp
@@ -0,0 +1,37 @@
+/*
+    tests/test_stl_binders.cpp -- Usage of stl_binders functions
+
+    Copyright (c) 2016 Sergey Lyskov
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+
+#include <pybind11/stl_bind.h>
+
+class El {
+public:
+	El() = delete;
+	El(int v) : a(v) { }
+
+	int a;
+};
+
+std::ostream & operator<<(std::ostream &s, El const&v) {
+	s << "El{" << v.a << '}';
+	return s;
+}
+
+void init_ex_stl_binder_vector(py::module &m) {
+	py::class_<El>(m, "El")
+		.def(py::init<int>());
+
+	py::bind_vector<unsigned int>(m, "VectorInt");
+	py::bind_vector<bool>(m, "VectorBool");
+
+	py::bind_vector<El>(m, "VectorEl");
+
+    py::bind_vector<std::vector<El>>(m, "VectorVectorEl");
+}
diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py
new file mode 100644
index 0000000..2aaaf3a
--- /dev/null
+++ b/tests/test_stl_binders.py
@@ -0,0 +1,53 @@
+
+
+def test_vector_int():
+    from pybind11_tests import VectorInt
+
+    v_int = VectorInt([0, 0])
+    assert len(v_int) == 2
+    assert bool(v_int) is True
+
+    v_int2 = VectorInt([0, 0])
+    assert v_int == v_int2
+    v_int2[1] = 1
+    assert v_int != v_int2
+
+    v_int2.append(2)
+    v_int2.append(3)
+    v_int2.insert(0, 1)
+    v_int2.insert(0, 2)
+    v_int2.insert(0, 3)
+    assert str(v_int2) == "VectorInt[3, 2, 1, 0, 1, 2, 3]"
+
+    v_int.append(99)
+    v_int2[2:-2] = v_int
+    assert v_int2 == VectorInt([3, 2, 0, 0, 99, 2, 3])
+    del v_int2[1:3]
+    assert v_int2 == VectorInt([3, 0, 99, 2, 3])
+    del v_int2[0]
+    assert v_int2 == VectorInt([0, 99, 2, 3])
+
+
+def test_vector_custom():
+    from pybind11_tests import El, VectorEl, VectorVectorEl
+
+    v_a = VectorEl()
+    v_a.append(El(1))
+    v_a.append(El(2))
+    assert str(v_a) == "VectorEl[El{1}, El{2}]"
+
+    vv_a = VectorVectorEl()
+    vv_a.append(v_a)
+    vv_b = vv_a[0]
+    assert str(vv_b) == "VectorEl[El{1}, El{2}]"
+
+
+def test_vector_bool():
+    from pybind11_tests import VectorBool
+
+    vv_c = VectorBool()
+    for i in range(10):
+        vv_c.append(i % 2 == 0)
+    for i in range(10):
+        assert vv_c[i] == (i % 2 == 0)
+    assert str(vv_c) == "VectorBool[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]"
diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp
new file mode 100644
index 0000000..6ea7c2c
--- /dev/null
+++ b/tests/test_virtual_functions.cpp
@@ -0,0 +1,308 @@
+/*
+    tests/test_virtual_functions.cpp -- overriding virtual functions from Python
+
+    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#include "pybind11_tests.h"
+#include "constructor_stats.h"
+#include <pybind11/functional.h>
+
+/* This is an example class that we'll want to be able to extend from Python */
+class ExampleVirt  {
+public:
+    ExampleVirt(int state) : state(state) { print_created(this, state); }
+    ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); }
+    ExampleVirt(ExampleVirt &&e) : state(e.state) { print_move_created(this); e.state = 0; }
+    ~ExampleVirt() { print_destroyed(this); }
+
+    virtual int run(int value) {
+        std::cout << "Original implementation of ExampleVirt::run(state=" << state
+                  << ", value=" << value << ")" << std::endl;
+        return state + value;
+    }
+
+    virtual bool run_bool() = 0;
+    virtual void pure_virtual() = 0;
+private:
+    int state;
+};
+
+/* This is a wrapper class that must be generated */
+class PyExampleVirt : public ExampleVirt {
+public:
+    using ExampleVirt::ExampleVirt; /* Inherit constructors */
+
+    virtual int run(int value) {
+        /* Generate wrapping code that enables native function overloading */
+        PYBIND11_OVERLOAD(
+            int,         /* Return type */
+            ExampleVirt, /* Parent class */
+            run,         /* Name of function */
+            value        /* Argument(s) */
+        );
+    }
+
+    virtual bool run_bool() {
+        PYBIND11_OVERLOAD_PURE(
+            bool,         /* Return type */
+            ExampleVirt,  /* Parent class */
+            run_bool,     /* Name of function */
+                          /* This function has no arguments. The trailing comma
+                             in the previous line is needed for some compilers */
+        );
+    }
+
+    virtual void pure_virtual() {
+        PYBIND11_OVERLOAD_PURE(
+            void,         /* Return type */
+            ExampleVirt,  /* Parent class */
+            pure_virtual, /* Name of function */
+                          /* This function has no arguments. The trailing comma
+                             in the previous line is needed for some compilers */
+        );
+    }
+};
+
+class NonCopyable {
+public:
+    NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); }
+    NonCopyable(NonCopyable &&o) { value = std::move(o.value); print_move_created(this); }
+    NonCopyable(const NonCopyable &) = delete;
+    NonCopyable() = delete;
+    void operator=(const NonCopyable &) = delete;
+    void operator=(NonCopyable &&) = delete;
+    std::string get_value() const {
+        if (value) return std::to_string(*value); else return "(null)";
+    }
+    ~NonCopyable() { print_destroyed(this); }
+
+private:
+    std::unique_ptr<int> value;
+};
+
+// This is like the above, but is both copy and movable.  In effect this means it should get moved
+// when it is not referenced elsewhere, but copied if it is still referenced.
+class Movable {
+public:
+    Movable(int a, int b) : value{a+b} { print_created(this, a, b); }
+    Movable(const Movable &m) { value = m.value; print_copy_created(this); }
+    Movable(Movable &&m) { value = std::move(m.value); print_move_created(this); }
+    int get_value() const { return value; }
+    ~Movable() { print_destroyed(this); }
+private:
+    int value;
+};
+
+class NCVirt {
+public:
+    virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); }
+    virtual Movable get_movable(int a, int b) = 0;
+
+    void print_nc(int a, int b) { std::cout << get_noncopyable(a, b).get_value() << std::endl; }
+    void print_movable(int a, int b) { std::cout << get_movable(a, b).get_value() << std::endl; }
+};
+class NCVirtTrampoline : public NCVirt {
+    virtual NonCopyable get_noncopyable(int a, int b) {
+        PYBIND11_OVERLOAD(NonCopyable, NCVirt, get_noncopyable, a, b);
+    }
+    virtual Movable get_movable(int a, int b) {
+        PYBIND11_OVERLOAD_PURE(Movable, NCVirt, get_movable, a, b);
+    }
+};
+
+int runExampleVirt(ExampleVirt *ex, int value) {
+    return ex->run(value);
+}
+
+bool runExampleVirtBool(ExampleVirt* ex) {
+    return ex->run_bool();
+}
+
+void runExampleVirtVirtual(ExampleVirt *ex) {
+    ex->pure_virtual();
+}
+
+
+// Inheriting virtual methods.  We do two versions here: the repeat-everything version and the
+// templated trampoline versions mentioned in docs/advanced.rst.
+//
+// These base classes are exactly the same, but we technically need distinct
+// classes for this example code because we need to be able to bind them
+// properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to
+// multiple python classes).
+class A_Repeat {
+#define A_METHODS \
+public: \
+    virtual int unlucky_number() = 0; \
+    virtual void say_something(unsigned times) { \
+        for (unsigned i = 0; i < times; i++) std::cout << "hi"; \
+        std::cout << std::endl; \
+    }
+A_METHODS
+};
+class B_Repeat : public A_Repeat {
+#define B_METHODS \
+public: \
+    int unlucky_number() override { return 13; } \
+    void say_something(unsigned times) override { \
+        std::cout << "B says hi " << times << " times" << std::endl; \
+    } \
+    virtual double lucky_number() { return 7.0; }
+B_METHODS
+};
+class C_Repeat : public B_Repeat {
+#define C_METHODS \
+public: \
+    int unlucky_number() override { return 4444; } \
+    double lucky_number() override { return 888; }
+C_METHODS
+};
+class D_Repeat : public C_Repeat {
+#define D_METHODS // Nothing overridden.
+D_METHODS
+};
+
+// Base classes for templated inheritance trampolines.  Identical to the repeat-everything version:
+class A_Tpl { A_METHODS };
+class B_Tpl : public A_Tpl { B_METHODS };
+class C_Tpl : public B_Tpl { C_METHODS };
+class D_Tpl : public C_Tpl { D_METHODS };
+
+
+// Inheritance approach 1: each trampoline gets every virtual method (11 in total)
+class PyA_Repeat : public A_Repeat {
+public:
+    using A_Repeat::A_Repeat;
+    int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_Repeat, unlucky_number, ); }
+    void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, A_Repeat, say_something, times); }
+};
+class PyB_Repeat : public B_Repeat {
+public:
+    using B_Repeat::B_Repeat;
+    int unlucky_number() override { PYBIND11_OVERLOAD(int, B_Repeat, unlucky_number, ); }
+    void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, B_Repeat, say_something, times); }
+    double lucky_number() override { PYBIND11_OVERLOAD(double, B_Repeat, lucky_number, ); }
+};
+class PyC_Repeat : public C_Repeat {
+public:
+    using C_Repeat::C_Repeat;
+    int unlucky_number() override { PYBIND11_OVERLOAD(int, C_Repeat, unlucky_number, ); }
+    void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, C_Repeat, say_something, times); }
+    double lucky_number() override { PYBIND11_OVERLOAD(double, C_Repeat, lucky_number, ); }
+};
+class PyD_Repeat : public D_Repeat {
+public:
+    using D_Repeat::D_Repeat;
+    int unlucky_number() override { PYBIND11_OVERLOAD(int, D_Repeat, unlucky_number, ); }
+    void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, D_Repeat, say_something, times); }
+    double lucky_number() override { PYBIND11_OVERLOAD(double, D_Repeat, lucky_number, ); }
+};
+
+// Inheritance approach 2: templated trampoline classes.
+//
+// Advantages:
+// - we have only 2 (template) class and 4 method declarations (one per virtual method, plus one for
+//   any override of a pure virtual method), versus 4 classes and 6 methods (MI) or 4 classes and 11
+//   methods (repeat).
+// - Compared to MI, we also don't have to change the non-trampoline inheritance to virtual, and can
+//   properly inherit constructors.
+//
+// Disadvantage:
+// - the compiler must still generate and compile 14 different methods (more, even, than the 11
+//   required for the repeat approach) instead of the 6 required for MI.  (If there was no pure
+//   method (or no pure method override), the number would drop down to the same 11 as the repeat
+//   approach).
+template <class Base = A_Tpl>
+class PyA_Tpl : public Base {
+public:
+    using Base::Base; // Inherit constructors
+    int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, Base, unlucky_number, ); }
+    void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, Base, say_something, times); }
+};
+template <class Base = B_Tpl>
+class PyB_Tpl : public PyA_Tpl<Base> {
+public:
+    using PyA_Tpl<Base>::PyA_Tpl; // Inherit constructors (via PyA_Tpl's inherited constructors)
+    int unlucky_number() override { PYBIND11_OVERLOAD(int, Base, unlucky_number, ); }
+    double lucky_number() override { PYBIND11_OVERLOAD(double, Base, lucky_number, ); }
+};
+// Since C_Tpl and D_Tpl don't declare any new virtual methods, we don't actually need these (we can
+// use PyB_Tpl<C_Tpl> and PyB_Tpl<D_Tpl> for the trampoline classes instead):
+/*
+template <class Base = C_Tpl> class PyC_Tpl : public PyB_Tpl<Base> {
+public:
+    using PyB_Tpl<Base>::PyB_Tpl;
+};
+template <class Base = D_Tpl> class PyD_Tpl : public PyC_Tpl<Base> {
+public:
+    using PyC_Tpl<Base>::PyC_Tpl;
+};
+*/
+
+
+void initialize_inherited_virtuals(py::module &m) {
+    // Method 1: repeat
+    py::class_<A_Repeat, std::unique_ptr<A_Repeat>, PyA_Repeat>(m, "A_Repeat")
+        .def(py::init<>())
+        .def("unlucky_number", &A_Repeat::unlucky_number)
+        .def("say_something", &A_Repeat::say_something);
+    py::class_<B_Repeat, std::unique_ptr<B_Repeat>, PyB_Repeat>(m, "B_Repeat", py::base<A_Repeat>())
+        .def(py::init<>())
+        .def("lucky_number", &B_Repeat::lucky_number);
+    py::class_<C_Repeat, std::unique_ptr<C_Repeat>, PyC_Repeat>(m, "C_Repeat", py::base<B_Repeat>())
+        .def(py::init<>());
+    py::class_<D_Repeat, std::unique_ptr<D_Repeat>, PyD_Repeat>(m, "D_Repeat", py::base<C_Repeat>())
+        .def(py::init<>());
+
+    // Method 2: Templated trampolines
+    py::class_<A_Tpl, std::unique_ptr<A_Tpl>, PyA_Tpl<>>(m, "A_Tpl")
+        .def(py::init<>())
+        .def("unlucky_number", &A_Tpl::unlucky_number)
+        .def("say_something", &A_Tpl::say_something);
+    py::class_<B_Tpl, std::unique_ptr<B_Tpl>, PyB_Tpl<>>(m, "B_Tpl", py::base<A_Tpl>())
+        .def(py::init<>())
+        .def("lucky_number", &B_Tpl::lucky_number);
+    py::class_<C_Tpl, std::unique_ptr<C_Tpl>, PyB_Tpl<C_Tpl>>(m, "C_Tpl", py::base<B_Tpl>())
+        .def(py::init<>());
+    py::class_<D_Tpl, std::unique_ptr<D_Tpl>, PyB_Tpl<D_Tpl>>(m, "D_Tpl", py::base<C_Tpl>())
+        .def(py::init<>());
+
+};
+
+
+void init_ex_virtual_functions(py::module &m) {
+    /* Important: indicate the trampoline class PyExampleVirt using the third
+       argument to py::class_. The second argument with the unique pointer
+       is simply the default holder type used by pybind11. */
+    py::class_<ExampleVirt, std::unique_ptr<ExampleVirt>, PyExampleVirt>(m, "ExampleVirt")
+        .def(py::init<int>())
+        /* Reference original class in function definitions */
+        .def("run", &ExampleVirt::run)
+        .def("run_bool", &ExampleVirt::run_bool)
+        .def("pure_virtual", &ExampleVirt::pure_virtual);
+
+    py::class_<NonCopyable>(m, "NonCopyable")
+        .def(py::init<int, int>())
+        ;
+    py::class_<Movable>(m, "Movable")
+        .def(py::init<int, int>())
+        ;
+    py::class_<NCVirt, std::unique_ptr<NCVirt>, NCVirtTrampoline>(m, "NCVirt")
+        .def(py::init<>())
+        .def("get_noncopyable", &NCVirt::get_noncopyable)
+        .def("get_movable", &NCVirt::get_movable)
+        .def("print_nc", &NCVirt::print_nc)
+        .def("print_movable", &NCVirt::print_movable)
+        ;
+
+    m.def("runExampleVirt", &runExampleVirt);
+    m.def("runExampleVirtBool", &runExampleVirtBool);
+    m.def("runExampleVirtVirtual", &runExampleVirtVirtual);
+
+    m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
+    initialize_inherited_virtuals(m);
+}
diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py
new file mode 100644
index 0000000..f2efb6b
--- /dev/null
+++ b/tests/test_virtual_functions.py
@@ -0,0 +1,227 @@
+import pytest
+from pybind11_tests import ConstructorStats
+
+
+def test_override(capture, msg):
+    from pybind11_tests import (ExampleVirt, runExampleVirt, runExampleVirtVirtual,
+                                runExampleVirtBool)
+
+    class ExtendedExampleVirt(ExampleVirt):
+        def __init__(self, state):
+            super(ExtendedExampleVirt, self).__init__(state + 1)
+            self.data = "Hello world"
+
+        def run(self, value):
+            print('ExtendedExampleVirt::run(%i), calling parent..' % value)
+            return super(ExtendedExampleVirt, self).run(value + 1)
+
+        def run_bool(self):
+            print('ExtendedExampleVirt::run_bool()')
+            return False
+
+        def pure_virtual(self):
+            print('ExtendedExampleVirt::pure_virtual(): %s' % self.data)
+
+    ex12 = ExampleVirt(10)
+    with capture:
+        assert runExampleVirt(ex12, 20) == 30
+    assert capture == "Original implementation of ExampleVirt::run(state=10, value=20)"
+
+    with pytest.raises(RuntimeError) as excinfo:
+        runExampleVirtVirtual(ex12)
+    assert msg(excinfo.value) == 'Tried to call pure virtual function "ExampleVirt::pure_virtual"'
+
+    ex12p = ExtendedExampleVirt(10)
+    with capture:
+        assert runExampleVirt(ex12p, 20) == 32
+    assert capture == """
+        ExtendedExampleVirt::run(20), calling parent..
+        Original implementation of ExampleVirt::run(state=11, value=21)
+    """
+    with capture:
+        assert runExampleVirtBool(ex12p) is False
+    assert capture == "ExtendedExampleVirt::run_bool()"
+    with capture:
+        runExampleVirtVirtual(ex12p)
+    assert capture == "ExtendedExampleVirt::pure_virtual(): Hello world"
+
+    cstats = ConstructorStats.get(ExampleVirt)
+    assert cstats.alive() == 2
+    del ex12, ex12p
+    assert cstats.alive() == 0
+    assert cstats.values() == ['10', '11']
+    assert cstats.copy_constructions == 0
+    assert cstats.move_constructions >= 0
+
+
+def test_inheriting_repeat(capture):
+    from pybind11_tests import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl
+
+    class VI_AR(A_Repeat):
+        def unlucky_number(self):
+            return 99
+
+    class VI_AT(A_Tpl):
+        def unlucky_number(self):
+            return 999
+
+    obj = VI_AR()
+    with capture:
+        obj.say_something(3)
+    assert capture == "hihihi"
+    assert obj.unlucky_number() == 99
+
+    obj = VI_AT()
+    with capture:
+        obj.say_something(3)
+    assert capture == "hihihi"
+    assert obj.unlucky_number() == 999
+
+    for obj in [B_Repeat(), B_Tpl()]:
+        with capture:
+            obj.say_something(3)
+        assert capture == "B says hi 3 times"
+        assert obj.unlucky_number() == 13
+        assert obj.lucky_number() == 7.0
+
+    for obj in [C_Repeat(), C_Tpl()]:
+        with capture:
+            obj.say_something(3)
+        assert capture == "B says hi 3 times"
+        assert obj.unlucky_number() == 4444
+        assert obj.lucky_number() == 888.0
+
+    class VI_CR(C_Repeat):
+        def lucky_number(self):
+            return C_Repeat.lucky_number(self) + 1.25
+
+    obj = VI_CR()
+    with capture:
+        obj.say_something(3)
+    assert capture == "B says hi 3 times"
+    assert obj.unlucky_number() == 4444
+    assert obj.lucky_number() == 889.25
+
+    class VI_CT(C_Tpl):
+        pass
+
+    obj = VI_CT()
+    with capture:
+        obj.say_something(3)
+    assert capture == "B says hi 3 times"
+    assert obj.unlucky_number() == 4444
+    assert obj.lucky_number() == 888.0
+
+    class VI_CCR(VI_CR):
+        def lucky_number(self):
+            return VI_CR.lucky_number(self) * 10
+
+    obj = VI_CCR()
+    with capture:
+        obj.say_something(3)
+    assert capture == "B says hi 3 times"
+    assert obj.unlucky_number() == 4444
+    assert obj.lucky_number() == 8892.5
+
+    class VI_CCT(VI_CT):
+        def lucky_number(self):
+            return VI_CT.lucky_number(self) * 1000
+
+    obj = VI_CCT()
+    with capture:
+        obj.say_something(3)
+    assert capture == "B says hi 3 times"
+    assert obj.unlucky_number() == 4444
+    assert obj.lucky_number() == 888000.0
+
+    class VI_DR(D_Repeat):
+        def unlucky_number(self):
+            return 123
+
+        def lucky_number(self):
+            return 42.0
+
+    for obj in [D_Repeat(), D_Tpl()]:
+        with capture:
+            obj.say_something(3)
+        assert capture == "B says hi 3 times"
+        assert obj.unlucky_number() == 4444
+        assert obj.lucky_number() == 888.0
+
+    obj = VI_DR()
+    with capture:
+        obj.say_something(3)
+    assert capture == "B says hi 3 times"
+    assert obj.unlucky_number() == 123
+    assert obj.lucky_number() == 42.0
+
+    class VI_DT(D_Tpl):
+        def say_something(self, times):
+            print("VI_DT says:" + (' quack' * times))
+
+        def unlucky_number(self):
+            return 1234
+
+        def lucky_number(self):
+            return -4.25
+
+    obj = VI_DT()
+    with capture:
+        obj.say_something(3)
+    assert capture == "VI_DT says: quack quack quack"
+    assert obj.unlucky_number() == 1234
+    assert obj.lucky_number() == -4.25
+
+
+def test_move_support(capture, msg):
+    from pybind11_tests import NCVirt, NonCopyable, Movable
+
+    class NCVirtExt(NCVirt):
+        def get_noncopyable(self, a, b):
+            # Constructs and returns a new instance:
+            nc = NonCopyable(a*a, b*b)
+            return nc
+
+        def get_movable(self, a, b):
+            # Return a referenced copy
+            self.movable = Movable(a, b)
+            return self.movable
+
+    class NCVirtExt2(NCVirt):
+        def get_noncopyable(self, a, b):
+            # Keep a reference: this is going to throw an exception
+            self.nc = NonCopyable(a, b)
+            return self.nc
+
+        def get_movable(self, a, b):
+            # Return a new instance without storing it
+            return Movable(a, b)
+
+    ncv1 = NCVirtExt()
+    with capture:
+        ncv1.print_nc(2, 3)
+    assert capture == "36"
+    with capture:
+        ncv1.print_movable(4, 5)
+    assert capture == "9"
+    ncv2 = NCVirtExt2()
+    with capture:
+        ncv2.print_movable(7, 7)
+    assert capture == "14"
+    # Don't check the exception message here because it differs under debug/non-debug mode
+    with pytest.raises(RuntimeError):
+        ncv2.print_nc(9, 9)
+
+    nc_stats = ConstructorStats.get(NonCopyable)
+    mv_stats = ConstructorStats.get(Movable)
+    assert nc_stats.alive() == 1
+    assert mv_stats.alive() == 1
+    del ncv1, ncv2
+    assert nc_stats.alive() == 0
+    assert mv_stats.alive() == 0
+    assert nc_stats.values() == ['4', '9', '9', '9']
+    assert mv_stats.values() == ['4', '5', '7', '7']
+    assert nc_stats.copy_constructions == 0
+    assert mv_stats.copy_constructions == 1
+    assert nc_stats.move_constructions >= 0
+    assert mv_stats.move_constructions >= 0