Bladeren bron

Convert to GoogleTest.
Fix constructors to properly handle things...
Fix doxygen comment tokens
Add proper includes for each header.

Sam Jaffe 5 jaren geleden
bovenliggende
commit
523abc78fb

+ 9 - 7
include/iterator/end_aware_iterator.hpp

@@ -14,9 +14,9 @@
 namespace iterator {
   /**
    * @class end_aware_iterator
-   * @breif An iterator that keeps track of the relative end of the range.
+   * @brief An iterator that keeps track of the relative end of the range.
    *
-   * @param Iterator The underlying iterator type
+   * @tparam Iterator The underlying iterator type
    */
   template <typename Iterator>
   class end_aware_iterator {
@@ -79,15 +79,17 @@ namespace iterator {
 }
 
 template <typename Iter>
-iterator::end_aware_iterator<Iter> make_end_aware_iterator(Iter a, Iter b) { return {a, b}; }
+iterator::end_aware_iterator<Iter> make_end_aware_iterator(Iter a, Iter b) {
+  return iterator::end_aware_iterator<Iter>(a, b);
+}
 
 template <typename C>
-auto make_end_aware_iterator(C & collect) -> iterator::end_aware_iterator<decltype(std::begin(collect))> {
-  return { std::begin(collect), std::end(collect) };
+auto make_end_aware_iterator(C & collect) {
+  return make_end_aware_iterator(std::begin(collect), std::end(collect));
 }
 
 template <typename C>
-auto make_end_aware_iterator(C const & collect) -> iterator::end_aware_iterator<decltype(std::begin(collect))> {
-  return { std::begin(collect), std::end(collect) };
+auto make_end_aware_iterator(C const & collect) {
+  return make_end_aware_iterator(std::begin(collect), std::end(collect));
 }
 

+ 2 - 0
include/iterator/filter_iterator.hpp

@@ -7,6 +7,8 @@
 
 #pragma once
 
+#include <functional>
+
 #include "end_aware_iterator.hpp"
 
 namespace iterator {

+ 3 - 0
include/iterator/iterator_fwd.hpp

@@ -7,6 +7,9 @@
 
 #pragma once
 
+#include <iterator>
+#include <utility>
+
 namespace iterator {
   namespace detail {
     template <typename> struct void_t { using type = void; };

+ 29 - 17
include/iterator/recursive_iterator.hpp

@@ -7,6 +7,8 @@
 
 #pragma once
 
+#include <tuple>
+
 #include "iterator_fwd.hpp"
 #include "end_aware_iterator.hpp"
 
@@ -16,7 +18,7 @@ namespace iterator { namespace detail {
   
   /**
    * @class recursive_iterator_base
-   * @breif A thin wrapper around end_aware_iterator for the purposes of template metaprogramming.
+   * @brief A thin wrapper around end_aware_iterator for the purposes of template metaprogramming.
    */
   template <typename Iterator, typename = void>
   class recursive_iterator_base : public end_aware_iterator<Iterator> {
@@ -26,6 +28,8 @@ namespace iterator { namespace detail {
     using recursive_category = terminal_layer_tag_t;
   public:
     using super::super;
+    recursive_iterator_base(super const & iter) : super(iter) {}
+    recursive_iterator_base(super && iter) : super(std::move(iter)) {}
     recursive_iterator_base() = default;
     operator super() const { return *this; }
   protected:
@@ -58,6 +62,8 @@ namespace iterator { namespace detail {
     using reference = std::tuple<first_type &, second_type &>;
   public:
     using super::super;
+    recursive_iterator_base(super const & iter) : super(iter) {}
+    recursive_iterator_base(super && iter) : super(std::move(iter)) {}
     recursive_iterator_base() = default;
     operator super() const { return *this; }
   protected:
@@ -75,15 +81,15 @@ namespace iterator { namespace detail {
   
   /**
    * @class recursive_iterator_layer
-   * @breif A single layer for recursing down a nested collection. Represents non-associative containers.
+   * @brief A single layer for recursing down a nested collection. Represents non-associative containers.
    *
    * Provides dispatch/overloading for types and functions of recursive_iterator
    * chains to resolve ambiguous typedefs and operators.
    *
    * @see recursive_iterator_impl
    * @see bounded_recursive_iterator_impl
-   * @param Iterator The underlying iterator type of the layer
-   * @param RecursiveIterator_NextLayer The next layer, either a recursive_iterator_impl, or a bounded_recursive_iterator_impl
+   * @tparam Iterator The underlying iterator type of the layer
+   * @tparam RecursiveIterator_NextLayer The next layer, either a recursive_iterator_impl, or a bounded_recursive_iterator_impl
    */
   template <typename Iterator, typename RecursiveIterator_NextLayer>
   class recursive_iterator_layer :
@@ -107,10 +113,13 @@ namespace iterator { namespace detail {
       update();
     }
     template <typename OIter, typename Rec>
-    recursive_iterator_layer(recursive_iterator_layer<OIter, Rec> const & other) : layer(static_cast<recursive_iterator_base<OIter>const&>(other)), super(static_cast<Rec const&>(other)) {}
+    recursive_iterator_layer(recursive_iterator_layer<OIter, Rec> const & other)
+        : layer(static_cast<recursive_iterator_base<OIter>const&>(other)),
+          super(static_cast<Rec const&>(other)) {}
     template <typename OIter, typename... Iterators>
-    recursive_iterator_layer(in_place_t, OIter it, Iterators && ...iter)
-    : layer(it), super(in_place, iter...) {
+    recursive_iterator_layer(in_place_t, OIter && it, Iterators && ...iter)
+    : layer(std::forward<OIter>(it)),
+      super(in_place, std::forward<Iterators>(iter)...) {
       update();
     }
     
@@ -171,7 +180,7 @@ namespace iterator { namespace detail {
   
   /**
    * @class flatten_iterator_layer
-   * @breif A single layer for recursing down a nested collection. Represents associative containers.
+   * @brief A single layer for recursing down a nested collection. Represents associative containers.
    *
    * @copydoc recursive_iterator_layer
    */
@@ -204,13 +213,14 @@ namespace iterator { namespace detail {
     template <typename OIter, typename Rec>
     flatten_iterator_layer(flatten_iterator_layer<OIter, Rec> const & other) : layer(static_cast<recursive_iterator_base<OIter>const&>(other)), super(static_cast<Rec const&>(other)) {}
     template <typename OIter, typename... Iterators>
-    flatten_iterator_layer(in_place_t, OIter it, Iterators && ...iter)
-    : layer(it), super(in_place, iter...) {
+    flatten_iterator_layer(in_place_t, OIter && it, Iterators && ...iter)
+    : layer(std::forward<OIter>(it)),
+      super(in_place, std::forward<Iterators>(iter)...) {
       update();
     }
     
     /**
-     * @breif Concatenate the key in this layer, with the dereferenced data from the next.
+     * @brief Concatenate the key in this layer, with the dereferenced data from the next.
      *
      * Due to the use of the next_layer_type metaprogramming, a type such as
      * std::map<K, std::vector<std::tuple<T1, T2, T3>>> would return a reference
@@ -269,7 +279,7 @@ namespace iterator { namespace detail {
 namespace iterator {
   /**
    * @class recursive_iterator
-   * @breif An iterator type for nested collections, allowing you to treat it as a single-layer collection.
+   * @brief An iterator type for nested collections, allowing you to treat it as a single-layer collection.
    *
    * In order to provide a simple interface, if an associative container is used
    * in the chain, the type returned by operator*() is a tuple. If multiple
@@ -277,7 +287,7 @@ namespace iterator {
    * std::tuple<key1, key2, ..., keyN, value>. To avoid copies, and allow
    * editting of underlying values, the tuple contains references.
    *
-   * @param Iterator The iterator type of the top-level collection.
+   * @tparam Iterator The iterator type of the top-level collection.
    */
   template <typename Iterator>
   class recursive_iterator : public detail::recursive_iterator_impl< Iterator > {
@@ -287,7 +297,8 @@ namespace iterator {
     using super::super;
     recursive_iterator() = default;
     template <typename... Iterators>
-    recursive_iterator(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+    recursive_iterator(in_place_t, Iterators && ...iter)
+        : super(in_place, std::forward<Iterators>(iter)...) {}
 
     recursive_iterator & operator++() {
       (void) super::next();
@@ -318,7 +329,7 @@ namespace iterator {
    * reload_data_from_file( std::get<1>(*iter), data );
    * @endcode
    *
-   * @param N The maximum depth to recurse into the object
+   * @tparam N The maximum depth to recurse into the object
    */
   template <typename Iterator, std::size_t N>
   class recursive_iterator_n : public detail::bounded_recursive_iterator_impl< Iterator, 1, N > {
@@ -328,7 +339,8 @@ namespace iterator {
     using super::super;
     recursive_iterator_n() = default;
     template <typename... Iterators>
-    recursive_iterator_n(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+    recursive_iterator_n(in_place_t, Iterators && ...iter)
+        : super(in_place, std::forward<Iterators>(iter)...) {}
     
     recursive_iterator_n & operator++() {
       (void) super::next();
@@ -354,7 +366,7 @@ namespace std {
 
 template <typename Iter0, typename... Iters>
 auto make_recursive_iterator(iterator::end_aware_iterator<Iter0> it, Iters &&... iters) -> iterator::recursive_iterator<Iter0> {
-  return { iterator::in_place, it, iters... };
+  return { iterator::in_place, std::move(it), std::forward<Iters>(iters)... };
 }
 
 template <typename C>

+ 12 - 6
include/iterator/recursive_iterator_meta.hpp

@@ -24,7 +24,8 @@ namespace iterator { namespace detail {
     using super::super;
     recursive_iterator_impl() = default;
     template <typename OIter>
-    recursive_iterator_impl(in_place_t, OIter iter) : super(iter) {}
+    recursive_iterator_impl(in_place_t, OIter && iter)
+        : super(std::forward<OIter>(iter)) {}
   protected:
     void next() { super::operator++(); }
     void assign(super eat) { static_cast<super&>(*this) = eat; }
@@ -54,7 +55,8 @@ namespace iterator { namespace detail {
     using super::super;
     recursive_iterator_impl() = default;
     template <typename... Iterators>
-    recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+    recursive_iterator_impl(in_place_t, Iterators && ...iter)
+        : super(in_place, std::forward<Iterators>(iter)...) {}
   };
   
   /**
@@ -74,7 +76,8 @@ namespace iterator { namespace detail {
     using super::super;
     recursive_iterator_impl() = default;
     template <typename... Iterators>
-    recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+    recursive_iterator_impl(in_place_t, Iterators && ...iter)
+        : super(in_place, std::forward<Iterators>(iter)...) {}
   };
   
   /**
@@ -95,7 +98,8 @@ namespace iterator { namespace detail {
     using super::super;
     bounded_recursive_iterator_impl() = default;
     template <typename OIter>
-    bounded_recursive_iterator_impl(in_place_t, OIter iter) : super(iter) {}
+    bounded_recursive_iterator_impl(in_place_t, OIter && iter)
+        : super(std::forward<OIter>(iter)) {}
   protected:
     void next() { super::operator++(); }
     void assign(super eat) { static_cast<super&>(*this) = eat; }
@@ -125,7 +129,8 @@ namespace iterator { namespace detail {
     using super::super;
     bounded_recursive_iterator_impl() = default;
     template <typename... Iterators>
-    bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+    bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter)
+        : super(in_place, std::forward<Iterators>(iter)...) {}
   };
   
   /**
@@ -145,7 +150,8 @@ namespace iterator { namespace detail {
     using super::super;
     bounded_recursive_iterator_impl() = default;
     template <typename... Iterators>
-    bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter) : super(in_place, iter...) {}
+    bounded_recursive_iterator_impl(in_place_t, Iterators && ...iter)
+        : super(in_place, std::forward<Iterators>(iter)...) {}
   };
 } }
 

+ 22 - 0
iterator-test/Info.plist

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>

+ 253 - 33
iterator.xcodeproj/project.pbxproj

@@ -7,9 +7,56 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		CD21AE2B1E4A3EB000536178 /* iterator_tc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD21AE291E4A3EB000536178 /* iterator_tc.cpp */; };
+		CDCB3BCA24E1D39B0029B771 /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDEC1E09235167920091D9F2 /* GoogleMock.framework */; };
+		CDCB3BD624E1D5320029B771 /* join_iterator_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BCD24E1D5320029B771 /* join_iterator_test.cxx */; };
+		CDCB3BD724E1D5320029B771 /* unkeyed_iterator_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BCE24E1D5320029B771 /* unkeyed_iterator_test.cxx */; };
+		CDCB3BD824E1D5320029B771 /* recursive_iterator_vector_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BCF24E1D5320029B771 /* recursive_iterator_vector_test.cxx */; };
+		CDCB3BD924E1D5320029B771 /* recursive_iterator_accessors_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD024E1D5320029B771 /* recursive_iterator_accessors_test.cxx */; };
+		CDCB3BDA24E1D5320029B771 /* recursive_iterator_mixed_container_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD124E1D5320029B771 /* recursive_iterator_mixed_container_test.cxx */; };
+		CDCB3BDB24E1D5320029B771 /* end_aware_iterator_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD224E1D5320029B771 /* end_aware_iterator_test.cxx */; };
+		CDCB3BDC24E1D5320029B771 /* filter_iterator_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD324E1D5320029B771 /* filter_iterator_test.cxx */; };
+		CDCB3BDD24E1D5320029B771 /* indexed_iterator_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD424E1D5320029B771 /* indexed_iterator_test.cxx */; };
+		CDCB3BDE24E1D5320029B771 /* recursive_iterator_map_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDCB3BD524E1D5320029B771 /* recursive_iterator_map_test.cxx */; };
 /* End PBXBuildFile section */
 
+/* Begin PBXContainerItemProxy section */
+		CDCB3BCB24E1D3B50029B771 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 05818F851A685AEA0072A469;
+			remoteInfo = GoogleMock;
+		};
+		CDEC1E08235167920091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F861A685AEA0072A469;
+			remoteInfo = GoogleMock;
+		};
+		CDEC1E0A235167920091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96ABD1A68600C00204102;
+			remoteInfo = gmock;
+		};
+		CDEC1E0C235167920091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96B1F1A68634900204102;
+			remoteInfo = gtest;
+		};
+		CDEC1E0E235167920091D9F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F901A685AEA0072A469;
+			remoteInfo = GoogleMockTests;
+		};
+/* End PBXContainerItemProxy section */
+
 /* Begin PBXCopyFilesBuildPhase section */
 		CD21AE1B1E4A3E7900536178 /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -23,18 +70,20 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-		CD13DDDD1E6CAB1500554B52 /* indexed_iterator.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = indexed_iterator.t.h; sourceTree = "<group>"; };
 		CD21AE1D1E4A3E7900536178 /* iterator_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iterator_tc; sourceTree = BUILT_PRODUCTS_DIR; };
-		CD21AE291E4A3EB000536178 /* iterator_tc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = iterator_tc.cpp; sourceTree = "<group>"; };
-		CD21AE2A1E4A3EB000536178 /* join_iterator.t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = join_iterator.t.h; sourceTree = "<group>"; };
-		CD21AE2F1E4A428D00536178 /* end_aware_iterator.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = end_aware_iterator.t.h; sourceTree = "<group>"; };
-		CD46DF4C1EF5A69F0092D121 /* filter_iterator.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = filter_iterator.t.h; sourceTree = "<group>"; };
-		CD595EE01E5BA3D300FC25BB /* unkeyed_iterator.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = unkeyed_iterator.t.h; sourceTree = "<group>"; };
-		CD679D731E5D19B900F9F843 /* recursive_iterator_accessors.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = recursive_iterator_accessors.t.h; sourceTree = "<group>"; };
-		CD7172EA1E57C91D0048DFFF /* recursive_iterator_one_dimension.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = recursive_iterator_one_dimension.t.h; sourceTree = "<group>"; };
-		CD7172ED1E58BC930048DFFF /* recursive_iterator_nested_map.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = recursive_iterator_nested_map.t.h; sourceTree = "<group>"; };
-		CD7172EE1E58C9930048DFFF /* recursive_iterator_mixed_container.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = recursive_iterator_mixed_container.t.h; sourceTree = "<group>"; };
 		CDCB3BBC24E1CDE40029B771 /* iterator */ = {isa = PBXFileReference; lastKnownFileType = folder; name = iterator; path = include/iterator; sourceTree = "<group>"; };
+		CDCB3BC124E1D3880029B771 /* iterator-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "iterator-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+		CDCB3BC524E1D3880029B771 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		CDCB3BCD24E1D5320029B771 /* join_iterator_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = join_iterator_test.cxx; sourceTree = "<group>"; };
+		CDCB3BCE24E1D5320029B771 /* unkeyed_iterator_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unkeyed_iterator_test.cxx; sourceTree = "<group>"; };
+		CDCB3BCF24E1D5320029B771 /* recursive_iterator_vector_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = recursive_iterator_vector_test.cxx; sourceTree = "<group>"; };
+		CDCB3BD024E1D5320029B771 /* recursive_iterator_accessors_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = recursive_iterator_accessors_test.cxx; sourceTree = "<group>"; };
+		CDCB3BD124E1D5320029B771 /* recursive_iterator_mixed_container_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = recursive_iterator_mixed_container_test.cxx; sourceTree = "<group>"; };
+		CDCB3BD224E1D5320029B771 /* end_aware_iterator_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = end_aware_iterator_test.cxx; sourceTree = "<group>"; };
+		CDCB3BD324E1D5320029B771 /* filter_iterator_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filter_iterator_test.cxx; sourceTree = "<group>"; };
+		CDCB3BD424E1D5320029B771 /* indexed_iterator_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = indexed_iterator_test.cxx; sourceTree = "<group>"; };
+		CDCB3BD524E1D5320029B771 /* recursive_iterator_map_test.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = recursive_iterator_map_test.cxx; sourceTree = "<group>"; };
+		CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -45,15 +94,26 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		CDCB3BBE24E1D3880029B771 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CDCB3BCA24E1D39B0029B771 /* GoogleMock.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
 		CD21AE141E4A3E7900536178 = {
 			isa = PBXGroup;
 			children = (
+				CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */,
 				CDCB3BBC24E1CDE40029B771 /* iterator */,
 				CD21AE271E4A3E8600536178 /* test */,
+				CDCB3BC224E1D3880029B771 /* iterator-test */,
 				CD21AE1E1E4A3E7900536178 /* Products */,
+				CDCB3BC924E1D39B0029B771 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -61,6 +121,7 @@
 			isa = PBXGroup;
 			children = (
 				CD21AE1D1E4A3E7900536178 /* iterator_tc */,
+				CDCB3BC124E1D3880029B771 /* iterator-test.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -68,33 +129,43 @@
 		CD21AE271E4A3E8600536178 /* test */ = {
 			isa = PBXGroup;
 			children = (
-				CD21AE2F1E4A428D00536178 /* end_aware_iterator.t.h */,
-				CD21AE2A1E4A3EB000536178 /* join_iterator.t.h */,
-				CD7172EA1E57C91D0048DFFF /* recursive_iterator_one_dimension.t.h */,
-				CD7172ED1E58BC930048DFFF /* recursive_iterator_nested_map.t.h */,
-				CD7172EE1E58C9930048DFFF /* recursive_iterator_mixed_container.t.h */,
-				CD679D731E5D19B900F9F843 /* recursive_iterator_accessors.t.h */,
-				CD595EE01E5BA3D300FC25BB /* unkeyed_iterator.t.h */,
-				CD13DDDD1E6CAB1500554B52 /* indexed_iterator.t.h */,
-				CD46DF4C1EF5A69F0092D121 /* filter_iterator.t.h */,
-				CD21AE291E4A3EB000536178 /* iterator_tc.cpp */,
+				CDCB3BD224E1D5320029B771 /* end_aware_iterator_test.cxx */,
+				CDCB3BD324E1D5320029B771 /* filter_iterator_test.cxx */,
+				CDCB3BD424E1D5320029B771 /* indexed_iterator_test.cxx */,
+				CDCB3BCD24E1D5320029B771 /* join_iterator_test.cxx */,
+				CDCB3BD024E1D5320029B771 /* recursive_iterator_accessors_test.cxx */,
+				CDCB3BD124E1D5320029B771 /* recursive_iterator_mixed_container_test.cxx */,
+				CDCB3BD524E1D5320029B771 /* recursive_iterator_map_test.cxx */,
+				CDCB3BCF24E1D5320029B771 /* recursive_iterator_vector_test.cxx */,
+				CDCB3BCE24E1D5320029B771 /* unkeyed_iterator_test.cxx */,
 			);
 			path = test;
 			sourceTree = "<group>";
 		};
-		CD21AE281E4A3E8C00536178 /* src */ = {
+		CDCB3BC224E1D3880029B771 /* iterator-test */ = {
+			isa = PBXGroup;
+			children = (
+				CDCB3BC524E1D3880029B771 /* Info.plist */,
+			);
+			path = "iterator-test";
+			sourceTree = "<group>";
+		};
+		CDCB3BC924E1D39B0029B771 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		CDEC1E02235167920091D9F2 /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				CD7172EC1E5897B80048DFFF /* iterator_fwd.hpp */,
-				CD21AE2E1E4A3F8E00536178 /* end_aware_iterator.hpp */,
-				CD21AE2C1E4A3EC100536178 /* join_iterator.hpp */,
-				CD7172E91E57C6580048DFFF /* recursive_iterator.hpp */,
-				CD679D721E5D127600F9F843 /* recursive_iterator_meta.hpp */,
-				CD595EDF1E5BA27300FC25BB /* unkeyed_iterator.hpp */,
-				CD13DDDC1E6CAB0A00554B52 /* indexed_iterator.hpp */,
-				CD46DF4B1EF5A6600092D121 /* filter_iterator.hpp */,
+				CDEC1E09235167920091D9F2 /* GoogleMock.framework */,
+				CDEC1E0B235167920091D9F2 /* gmock.framework */,
+				CDEC1E0D235167920091D9F2 /* gtest.framework */,
+				CDEC1E0F235167920091D9F2 /* GoogleMockTests.xctest */,
 			);
-			name = src;
+			name = Products;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -118,18 +189,40 @@
 			productReference = CD21AE1D1E4A3E7900536178 /* iterator_tc */;
 			productType = "com.apple.product-type.tool";
 		};
+		CDCB3BC024E1D3880029B771 /* iterator-test */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CDCB3BC624E1D3880029B771 /* Build configuration list for PBXNativeTarget "iterator-test" */;
+			buildPhases = (
+				CDCB3BBD24E1D3880029B771 /* Sources */,
+				CDCB3BBE24E1D3880029B771 /* Frameworks */,
+				CDCB3BBF24E1D3880029B771 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				CDCB3BCC24E1D3B50029B771 /* PBXTargetDependency */,
+			);
+			name = "iterator-test";
+			productName = "iterator-test";
+			productReference = CDCB3BC124E1D3880029B771 /* iterator-test.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
 		CD21AE151E4A3E7900536178 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1030;
+				LastUpgradeCheck = 1110;
 				ORGANIZATIONNAME = "Sam Jaffe";
 				TargetAttributes = {
 					CD21AE1C1E4A3E7900536178 = {
 						CreatedOnToolsVersion = 7.2.1;
 					};
+					CDCB3BC024E1D3880029B771 = {
+						CreatedOnToolsVersion = 11.3.1;
+						ProvisioningStyle = Automatic;
+					};
 				};
 			};
 			buildConfigurationList = CD21AE181E4A3E7900536178 /* Build configuration list for PBXProject "iterator" */;
@@ -143,13 +236,61 @@
 			mainGroup = CD21AE141E4A3E7900536178;
 			productRefGroup = CD21AE1E1E4A3E7900536178 /* Products */;
 			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = CDEC1E02235167920091D9F2 /* Products */;
+					ProjectRef = CDEC1E01235167920091D9F2 /* GoogleMock.xcodeproj */;
+				},
+			);
 			projectRoot = "";
 			targets = (
 				CD21AE1C1E4A3E7900536178 /* iterator_tc */,
+				CDCB3BC024E1D3880029B771 /* iterator-test */,
 			);
 		};
 /* End PBXProject section */
 
+/* Begin PBXReferenceProxy section */
+		CDEC1E09235167920091D9F2 /* GoogleMock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = GoogleMock.framework;
+			remoteRef = CDEC1E08235167920091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDEC1E0B235167920091D9F2 /* gmock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gmock.framework;
+			remoteRef = CDEC1E0A235167920091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDEC1E0D235167920091D9F2 /* gtest.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gtest.framework;
+			remoteRef = CDEC1E0C235167920091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDEC1E0F235167920091D9F2 /* GoogleMockTests.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = GoogleMockTests.xctest;
+			remoteRef = CDEC1E0E235167920091D9F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		CDCB3BBF24E1D3880029B771 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
 /* Begin PBXShellScriptBuildPhase section */
 		CD21AE2D1E4A3EF600536178 /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
@@ -181,12 +322,35 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				CD21AE2B1E4A3EB000536178 /* iterator_tc.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		CDCB3BBD24E1D3880029B771 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CDCB3BDB24E1D5320029B771 /* end_aware_iterator_test.cxx in Sources */,
+				CDCB3BD824E1D5320029B771 /* recursive_iterator_vector_test.cxx in Sources */,
+				CDCB3BDC24E1D5320029B771 /* filter_iterator_test.cxx in Sources */,
+				CDCB3BDE24E1D5320029B771 /* recursive_iterator_map_test.cxx in Sources */,
+				CDCB3BDD24E1D5320029B771 /* indexed_iterator_test.cxx in Sources */,
+				CDCB3BD624E1D5320029B771 /* join_iterator_test.cxx in Sources */,
+				CDCB3BD724E1D5320029B771 /* unkeyed_iterator_test.cxx in Sources */,
+				CDCB3BDA24E1D5320029B771 /* recursive_iterator_mixed_container_test.cxx in Sources */,
+				CDCB3BD924E1D5320029B771 /* recursive_iterator_accessors_test.cxx in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
+/* Begin PBXTargetDependency section */
+		CDCB3BCC24E1D3B50029B771 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = GoogleMock;
+			targetProxy = CDCB3BCB24E1D3B50029B771 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
 /* Begin XCBuildConfiguration section */
 		CD21AE221E4A3E7900536178 /* Debug */ = {
 			isa = XCBuildConfiguration;
@@ -239,6 +403,7 @@
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = include/;
 			};
 			name = Debug;
 		};
@@ -286,12 +451,14 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = include/;
 			};
 			name = Release;
 		};
 		CD21AE251E4A3E7900536178 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CODE_SIGN_IDENTITY = "-";
 				HEADER_SEARCH_PATHS = /usr/local/include/;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
@@ -300,11 +467,55 @@
 		CD21AE261E4A3E7900536178 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CODE_SIGN_IDENTITY = "-";
 				HEADER_SEARCH_PATHS = /usr/local/include/;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Release;
 		};
+		CDCB3BC724E1D3880029B771 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				INFOPLIST_FILE = "iterator-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.iterator-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		CDCB3BC824E1D3880029B771 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				INFOPLIST_FILE = "iterator-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				MTL_FAST_MATH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.iterator-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
@@ -326,6 +537,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		CDCB3BC624E1D3880029B771 /* Build configuration list for PBXNativeTarget "iterator-test" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CDCB3BC724E1D3880029B771 /* Debug */,
+				CDCB3BC824E1D3880029B771 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 /* End XCConfigurationList section */
 	};
 	rootObject = CD21AE151E4A3E7900536178 /* Project object */;

+ 0 - 50
test/end_aware_iterator.t.h

@@ -1,50 +0,0 @@
-//
-//  end_aware_iterator.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 2/7/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include <vector>
-
-#include "end_aware_iterator.hpp"
-
-class end_aware_TestSuite : public CxxTest::TestSuite {
-public:
-  using vec_t = std::vector<int>;
-  using ea_iter = iterator::end_aware_iterator<vec_t::iterator>;
-public:
-  void test_iterator_points_to_same() {
-    vec_t v{1, 2, 3, 4, 5};
-    TS_ASSERT_EQUALS(*v.begin(), *ea_iter(v.begin(), v.end()));
-  }
-
-  void test_iterator_edits_same() {
-    vec_t v{1, 2, 3, 4, 5};
-    *ea_iter(v.begin(), v.end()) = -1;
-    TS_ASSERT_EQUALS(v[0], -1);
-  }
-  
-  void test_not_done_until_end() {
-    vec_t v{1, 2, 3, 4, 5};
-    ea_iter it{v.end()-1, v.end()};
-    TS_ASSERT(!it.done());
-    ++it;
-    TS_ASSERT_EQUALS(it, ea_iter(v.end(),v.end()));
-    TS_ASSERT(it.done());
-  }
-
-  void test_cannot_go_past_end() {
-    vec_t v{1, 2, 3, 4, 5};
-    ea_iter it{v.end(), v.end()};
-    ea_iter const cp = it;
-    ++it;
-    TS_ASSERT_EQUALS(it, cp);
-    TS_ASSERT(it.done());
-  }
-  
-};

+ 36 - 0
test/end_aware_iterator_test.cxx

@@ -0,0 +1,36 @@
+#include "iterator/end_aware_iterator.hpp"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+
+using end_aware_iterator = ::iterator::end_aware_iterator<std::vector<int>::iterator>;
+
+TEST(EndAwareIteratorTest, BeginWrapperIsEqualToBegin) {
+  std::vector<int> v{1, 2, 3, 4, 5};
+  EXPECT_THAT(*v.begin(), *end_aware_iterator(v.begin(), v.end()));
+}
+
+TEST(EndAwareIteratorTest, MutableActionsArePassthrough) {
+  std::vector<int> v{1, 2, 3, 4, 5};
+  *end_aware_iterator(v.begin(), v.end()) = -1;
+  EXPECT_THAT(v[0], -1);
+}
+
+TEST(EndAwareIteratorTest, CanTellYouThatItsReachedEnd) {
+  std::vector<int> v{1, 2, 3, 4, 5};
+  end_aware_iterator it{v.end()-1, v.end()};
+  EXPECT_FALSE(it.done());
+  ++it;
+  EXPECT_THAT(it, end_aware_iterator(v.end(),v.end()));
+  EXPECT_TRUE(it.done());
+}
+
+TEST(EndAwareIteratorTest, IncrementOnEndIsNoOp) {
+  std::vector<int> v{1, 2, 3, 4, 5};
+  end_aware_iterator it{v.end(), v.end()};
+  end_aware_iterator const cp = it;
+  ++it;
+  EXPECT_THAT(it, cp);
+  EXPECT_TRUE(it.done());
+}

+ 0 - 44
test/filter_iterator.t.h

@@ -1,44 +0,0 @@
-//
-//  filter_iterator.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 6/17/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "filter_iterator.hpp"
-
-class filter_iterator_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_returns_subset() {
-    int data[] = { 1, 2, 3, 4, 5 };
-    auto pred = [](int i) { return i%2 == 0; };
-    auto it = make_filter_iterator(pred, data);
-    decltype(it) end = {};
-    TS_ASSERT_EQUALS(std::distance(it, end), 2);
-    TS_ASSERT_EQUALS(*it++, 2);
-    TS_ASSERT_EQUALS(*it++, 4);
-  }
-  
-  void test_no_matches_marks_end() {
-    int data[] = { 1, 3, 5 };
-    auto pred = [](int i) { return i%2 == 0; };
-    auto it = make_filter_iterator(pred, data);
-    decltype(it) end = {};
-    TS_ASSERT_EQUALS(it, end);
-  }
-  
-  void test_cannot_advance_past_end() {
-    int data[] = { 1, 2, 3, 4, 5 };
-    auto pred = [](int i) { return i%2 == 0; };
-    auto it = make_filter_iterator(pred, data);
-    decltype(it) end = {};
-    ++++it;
-    TS_ASSERT_EQUALS(it, end);
-    ++it;
-    TS_ASSERT_EQUALS(it, end);
-  }
-};

+ 32 - 0
test/filter_iterator_test.cxx

@@ -0,0 +1,32 @@
+#include "iterator/filter_iterator.hpp"
+
+#include <gmock/gmock.h>
+
+TEST(FilterIteratorTest, CanPerformSkipsOnData) {
+  int data[] = { 1, 2, 3, 4, 5 };
+  auto pred = [](int i) { return i%2 == 0; };
+  auto it = make_filter_iterator(pred, data);
+  decltype(it) end = {};
+  EXPECT_THAT(std::distance(it, end), 2);
+  EXPECT_THAT(*it++, 2);
+  EXPECT_THAT(*it++, 4);
+}
+
+TEST(FilterIteratorTest, IfNonMatchThenStartIsEnd) {
+  int data[] = { 1, 3, 5 };
+  auto pred = [](int i) { return i%2 == 0; };
+  auto it = make_filter_iterator(pred, data);
+  decltype(it) end = {};
+  EXPECT_THAT(it, end);
+}
+
+TEST(FilterIteratorTest, IncrementEndIsNoOp) {
+  int data[] = { 1, 2, 3, 4, 5 };
+  auto pred = [](int i) { return i%2 == 0; };
+  auto it = make_filter_iterator(pred, data);
+  decltype(it) end = {};
+  ++++it;
+  EXPECT_THAT(it, end);
+  ++it;
+  EXPECT_THAT(it, end);
+}

+ 0 - 23
test/indexed_iterator.t.h

@@ -1,23 +0,0 @@
-//
-//  indexed_iterator.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 3/5/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "indexed_iterator.hpp"
-
-class indexed_iterator_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_index_aligns_with_data() {
-    std::vector<int> const vec{5, 3, 2, 8, 9, 11, 2, 4};
-    iterator::indexed_iterator<std::vector<int>::const_iterator> it{vec.begin()}, end{vec.end()};
-    for (; it != end; ++it) {
-      TS_ASSERT_EQUALS((*it).second, vec[(*it).first]);
-    }
-  }
-};

+ 23 - 0
test/indexed_iterator_test.cxx

@@ -0,0 +1,23 @@
+#include "iterator/indexed_iterator.hpp"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+
+using idx_iterator = iterator::indexed_iterator<std::vector<int>::const_iterator>;
+
+TEST(IndexedIteratorTest, TreatsVectorIteratorAsMapIdxToValue) {
+  std::vector<int> const vec{5, 3, 2, 8, 9, 11, 2, 4};
+  idx_iterator it{vec.begin()}, end{vec.end()};
+  for (; it != end; ++it) {
+    EXPECT_THAT((*it).second, vec[(*it).first]);
+  }
+}
+
+TEST(IndexedIteratorTest, ContainsReferencesToContainersElements) {
+  std::vector<int> const vec{5, 3, 2, 8, 9, 11, 2, 4};
+  idx_iterator it{vec.begin()}, end{vec.end()};
+  for (; it != end; ++it) {
+    EXPECT_THAT(&(*it).second, &vec[(*it).first]);
+  }
+}

+ 0 - 46
test/join_iterator.t.h

@@ -1,46 +0,0 @@
-//
-//  iterator.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 2/7/17.
-//
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "join_iterator.hpp"
-
-class join_iterator_TestSuite : public CxxTest::TestSuite {
-public:
-  using vec_t = std::vector<int>;
-  using meta_vec_t = std::vector<vec_t>;
-  using jn_iter = iterator::joining_iterator<meta_vec_t::iterator>;
-  
-//  vec_t v{1,2,3,4,5,6};
-//  meta_vec_t mv{{1,2,3},{4,5,6}};
-public:
-  void test_points_to_beginning() {
-    meta_vec_t mv{{1,2,3},{4,5,6}};
-    TS_ASSERT_EQUALS(*jn_iter(make_end_aware_iterator(mv)), mv[0][0]);
-  }
-  
-  void test_empty_constructor_is_end() {
-    meta_vec_t mv{{1,2,3},{4,5,6}};
-    jn_iter it( { mv.end(), mv.end() }, { mv.back().end(), mv.back().end() } );
-    TS_ASSERT_EQUALS(it, jn_iter());
-  }
-  
-  void test_steps_to_next_list() {
-    meta_vec_t mv{{1,2,3},{4,5,6}};
-    jn_iter it(make_end_aware_iterator(mv), { mv[0].end(), mv[0].end() });
-    TS_ASSERT_EQUALS(*++it, mv[1][0]);
-  }
-  
-  void test_cannot_go_past_end() {
-    meta_vec_t mv{{1,2,3},{4,5,6}};
-    jn_iter it( { mv.end(), mv.end() }, { mv.back().end(), mv.back().end() });
-    jn_iter const cp = it;
-    ++it;
-    TS_ASSERT_EQUALS(it, cp);
-  }
-};

+ 32 - 0
test/join_iterator_test.cxx

@@ -0,0 +1,32 @@
+#include "iterator/join_iterator.hpp"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+
+using join_iterator = iterator::joining_iterator<std::vector<std::vector<int>>::iterator>;
+
+TEST(JoinIteratorTest, FirstDereferencedElemIsTheFirstInTheChain) {
+  std::vector<std::vector<int>> mv{{1,2,3},{4,5,6}};
+  EXPECT_THAT(*join_iterator(make_end_aware_iterator(mv)), mv[0][0]);
+}
+
+TEST(JoinIteratorTest, EmptyConstructorEqualsEnd) {
+  std::vector<std::vector<int>> mv{{1,2,3},{4,5,6}};
+  join_iterator it({ mv.end(), mv.end() }, { mv.back().end(), mv.back().end() } );
+  EXPECT_THAT(it, join_iterator());
+}
+
+TEST(JoinIteratorTest, MovesFromListToListWhenReachingEnd) {
+  std::vector<std::vector<int>> mv{{1,2,3},{4,5,6}};
+  join_iterator it(make_end_aware_iterator(mv), { mv[0].end(), mv[0].end() });
+  EXPECT_THAT(*++it, mv[1][0]);
+}
+
+TEST(JoinIteratorTest, IncrementEndIsNoOp) {
+  std::vector<std::vector<int>> mv{{1,2,3},{4,5,6}};
+  join_iterator it( { mv.end(), mv.end() }, { mv.back().end(), mv.back().end() });
+  join_iterator const cp = it;
+  ++it;
+  EXPECT_THAT(it, cp);
+}

+ 0 - 55
test/recursive_iterator_accessors.t.h

@@ -1,55 +0,0 @@
-//
-//  recursive_iterator_accessors.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 2/21/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-class recursive_iterator_accessors_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_access_iterator_types() {
-    using layer1 = std::map<int, int>;
-    using layer2 = std::vector<layer1>;
-    using object_type = std::map<int, layer2>;
-    object_type const obj{{ 1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}};
-    auto rit = make_recursive_iterator(obj);
-    TS_ASSERT_EQUALS(typeid(decltype(std::get<0>(rit))).name(),
-                     typeid(iterator::end_aware_iterator<object_type::const_iterator>).name());
-    TS_ASSERT_EQUALS(typeid(decltype(std::get<1>(rit))).name(),
-                     typeid(iterator::end_aware_iterator<layer2::const_iterator>).name());
-    TS_ASSERT_EQUALS(typeid(decltype(std::get<2>(rit))).name(),
-                     typeid(iterator::end_aware_iterator<layer1::const_iterator>).name());
-  }
-  
-  void test_construct_inplace_recursive_iterator() {
-    using layer1 = std::map<int, int>;
-    using layer2 = std::vector<layer1>;
-    using object_type = std::map<int, layer2>;
-    object_type const obj{{ 1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}};
-    auto const it = make_end_aware_iterator(obj.begin(), obj.end());
-    auto const it_1 = ++make_end_aware_iterator(it->second);
-    auto const it_2 = make_end_aware_iterator(*it_1);
-    TS_ASSERT_THROWS_NOTHING(make_recursive_iterator(it, it_1, it_2));
-  }
-  
-  void test_access_iterator_values_match_inplace() {
-    using layer1 = std::map<int, int>;
-    using layer2 = std::vector<layer1>;
-    using object_type = std::map<int, layer2>;
-    object_type const obj{{ 1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}};
-    auto const it = make_end_aware_iterator(obj.begin(), obj.end());
-    auto const it_1 = ++make_end_aware_iterator(it->second);
-    auto const it_2 = make_end_aware_iterator(*it_1);
-    iterator::recursive_iterator<object_type::const_iterator> rit{
-      iterator::in_place,
-      it, it_1, it_2
-    };
-    TS_ASSERT_EQUALS(std::get<0>(rit), it);
-    TS_ASSERT_EQUALS(std::get<1>(rit), it_1);
-    TS_ASSERT_EQUALS(std::get<2>(rit), it_2);
-  }
-};

+ 48 - 0
test/recursive_iterator_accessors_test.cxx

@@ -0,0 +1,48 @@
+#include "iterator/recursive_iterator.hpp"
+
+#include <map>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+TEST(RecursiveIteratorTest, CanStdGetToAllLayersOfInternalIteration) {
+  std::map<int, std::vector<std::map<int, int>>> obj{
+    {1, {{{1, 1}}, {{2, 2}}}}, // 2 1-element maps
+    {2, {{{3, 3}, {4, 4}}}} // 1 2-element map
+  };
+  auto rit = make_recursive_iterator(obj);
+  EXPECT_TRUE((testing::StaticAssertTypeEq<decltype(std::get<0>(rit)),
+               iterator::end_aware_iterator<std::map<int, std::vector<std::map<int, int>>>::iterator>>()));
+  EXPECT_TRUE((testing::StaticAssertTypeEq<decltype(std::get<1>(rit)),
+               iterator::end_aware_iterator<std::vector<std::map<int, int>>::iterator>>()));
+  EXPECT_TRUE((testing::StaticAssertTypeEq<decltype(std::get<2>(rit)),
+               iterator::end_aware_iterator<std::map<int, int>::iterator>>()));
+}
+
+TEST(RecursiveIteratorTest, CanConstructInPlaceFromIterators) {
+  std::map<int, std::vector<std::map<int, int>>> const obj{
+    {1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}
+  };
+  auto const it = make_end_aware_iterator(obj.begin(), obj.end());
+  auto const it_1 = ++make_end_aware_iterator(it->second);
+  auto const it_2 = make_end_aware_iterator(*it_1);
+  // Note that this carries the weakness of non bounds-checking that our
+  // iterators are all sitting on the same hierarchy...
+  EXPECT_NO_THROW(make_recursive_iterator(it, it_1, it_2));
+}
+
+TEST(RecursiveIteratorTest, InternalIteratorsFromStdGetMatchCtorArgs) {
+  std::map<int, std::vector<std::map<int, int>>> const obj{
+    {1, {{{1, 1}}, {{2, 2}}}}, {2, {{{3, 3}, {4, 4}}}}
+  };
+  auto const it = make_end_aware_iterator(obj.begin(), obj.end());
+  auto const it_1 = ++make_end_aware_iterator(it->second);
+  auto const it_2 = make_end_aware_iterator(*it_1);
+  iterator::recursive_iterator<decltype(obj.cbegin())> rit{
+    iterator::in_place,
+    it, it_1, it_2
+  };
+  EXPECT_THAT(std::get<0>(rit), it);
+  EXPECT_THAT(std::get<1>(rit), it_1);
+  EXPECT_THAT(std::get<2>(rit), it_2);
+}

+ 89 - 0
test/recursive_iterator_map_test.cxx

@@ -0,0 +1,89 @@
+#include "iterator/recursive_iterator.hpp"
+
+#include <map>
+#include <tuple>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+TEST(RecursiveIteratorSingleMapTest, IterDistanceIsContainerSize) {
+  std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
+  auto rit = make_recursive_iterator(map);
+  decltype(rit) end{ };
+  EXPECT_THAT(std::distance(rit, end), map.size());
+}
+
+TEST(RecursiveIteratorSingleMapTest, DataMatchesContainerIterator) {
+  std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
+  auto rit = make_recursive_iterator(map);
+  // TODO: Collapse into a container instead
+  for (auto it = map.begin(), end = map.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}
+
+TEST(RecursiveIteratorSingleMapTest, CanMutatePointedToData) {
+  std::map<int, int> map{{1, 1}, {2, 2}, {3, 3}};
+  auto rit = make_recursive_iterator(map);
+  std::get<1>(*rit) = 4;
+  EXPECT_THAT(map[1], 4);
+}
+
+TEST(RecursiveIteratorMapMapTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::map<int, std::map<int, int>> const map{
+    {1, {{1, 1}}},
+    {2, {{2, 2}, {3, 3}}}
+  };
+  auto rit = make_recursive_iterator(map);
+  decltype(rit) end{ };
+  // TODO: Actually perform the summation?
+  EXPECT_THAT(std::distance(rit, end), 3);
+}
+
+TEST(RecursiveIteratorMapMapTest, ElementsAreUnwrappedAsATuple) {
+  std::map<int, std::map<int, int>> const map{
+    {1, {{1, 1}}},
+    {2, {{2, 2}, {3, 3}}}
+  };
+  std::vector<std::tuple<int, int, int>> const expected{
+    {1, 1, 1}, {2, 2, 2}, {2, 3, 3}};
+  auto rit = make_recursive_iterator(map);
+  // TODO: Collapse into a container instead
+  for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(std::tuple_cat(*it), *rit);
+  }
+}
+
+TEST(RecursiveIteratorMapMapTest, CanMutatePointedToData) {
+  std::map<int, std::map<int, int>> map{
+    {1, {{1, 1}}},
+    {2, {{2, 2}, {3, 3}}}
+  };
+  auto rit = make_recursive_iterator(map);
+  std::get<2>(*rit) = 4;
+  EXPECT_THAT(map[1][1], 4);
+}
+
+TEST(BoundRecursiveIteratorMapMapTest, IterDistanceSumOnNLayersSize) {
+  std::map<int, std::map<int, int>> map{
+    {1, {{1, 1}}},
+    {2, {{2, 2}, {3, 3}}}
+  };
+  auto rit = make_recursive_iterator<1>(map);
+  decltype(rit) end{ };
+  
+  EXPECT_THAT(std::distance(rit, end), map.size());
+}
+
+TEST(BoundRecursiveIteratorMapMapTest, ElementsAreUnwrappedAsATuple) {
+  std::map<int, std::map<int, int>> map{
+    {1, {{1, 1}}},
+    {2, {{2, 2}, {3, 3}}}
+  };
+  auto rit = make_recursive_iterator<1>(map);
+  
+  // TODO: Collapse into a container instead
+  for (auto it = map.begin(), end = map.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}

+ 0 - 111
test/recursive_iterator_mixed_container.t.h

@@ -1,111 +0,0 @@
-//
-//  recursive_iterator_mixed_container.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 2/18/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "recursive_iterator.hpp"
-
-class recursive_iterator_mixed_container_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_map_vector_iterator_matches_size() {
-    std::map<int, std::vector<int>> const obj{{1, {1, 2}}, {2, {3, 4, 5}}};
-    std::vector<std::tuple<int, int>> const expected{{1, 1}, {1, 2}, {2, 3}, {2, 4}, {2, 5}};
-    auto rit = make_recursive_iterator(obj);
-    decltype(rit) end{ };
-    TS_ASSERT_EQUALS(std::distance(rit, end), expected.size());
-  }
-  
-  void test_map_vector_iterator_matches_data() {
-    std::map<int, std::vector<int>> const obj{{1, {1, 2}}, {2, {3, 4, 5}}};
-    std::vector<std::tuple<int, int>> const expected{{1, 1}, {1, 2}, {2, 3}, {2, 4}, {2, 5}};
-    auto rit = make_recursive_iterator(obj);
-    for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-
-  void test_map_vector_iterator_can_edit_data() {
-    std::map<int, std::vector<int>> obj{{1, {1, 2}}, {2, {3, 4, 5}}};
-    auto rit = make_recursive_iterator(obj);
-    std::get<1>(*rit) = 6;
-    TS_ASSERT_EQUALS(obj[1][0], 6);
-  }
-  
-  void test_vector_map_iterator_matches_size() {
-    std::vector<std::map<int, int>> const obj{{{1, 1}, {2, 2}}, {{3, 3}, {4, 4}, {5, 5}}};
-    std::vector<std::pair<int const, int>> const expected{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
-    auto rit = make_recursive_iterator(obj);
-    decltype(rit) end{ };
-    TS_ASSERT_EQUALS(std::distance(rit, end), expected.size());
-  }
-  
-  void test_vector_map_iterator_matches_data() {
-    std::vector<std::map<int, int>> const obj{{{1, 1}, {2, 2}}, {{3, 3}, {4, 4}, {5, 5}}};
-    std::vector<std::pair<int const, int>> const expected{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
-    auto rit = make_recursive_iterator(obj);
-    for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-  
-  void test_vector_map_iterator_can_edit_data() {
-    std::vector<std::map<int, int>> obj{{{1, 1}, {2, 2}}, {{3, 3}, {4, 4}, {5, 5}}};
-    auto rit = make_recursive_iterator(obj);
-    std::get<1>(*rit) = 6;
-    TS_ASSERT_EQUALS(obj[0][1], 6);
-  }
-  
-  void test_map_vector_map_iterator_matches_size() {
-    std::map<int, std::vector<std::map<int, int>>> const obj{{1, {{{1, 1}, {2, 2}}}}};
-    std::vector<std::tuple<int, int, int>> const expected{{1, 1, 1}, {1, 2, 2}};
-    auto rit = make_recursive_iterator(obj);
-    decltype(rit) end{ };
-    TS_ASSERT_EQUALS(std::distance(rit, end), expected.size());
-  }
-
-  void test_map_vector_map_iterator_matches_data() {
-    std::map<int, std::vector<std::map<int, int>>> const obj{{1, {{{1, 1}, {2, 2}}}}};
-    std::vector<std::tuple<int, int, int>> const expected{{1, 1, 1}, {1, 2, 2}};
-    auto rit = make_recursive_iterator(obj);
-    for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-
-  void test_map_vector_map_iterator_can_edit_data() {
-    std::map<int, std::vector<std::map<int, int>>> obj{{1, {{{1, 1}, {2, 2}}}}};
-    auto rit = make_recursive_iterator(obj);
-    std::get<2>(*rit) = 4;
-    TS_ASSERT_EQUALS(obj[1][0][1], 4);
-  }
-  
-  void test_vector_map_vector_iterator_matches_size() {
-    std::vector<std::map<int, std::vector<int>>> const obj{{{1, {1, 2}}, {2, {3, 4, 5}}}, {{1, {3, 4}}}};
-    std::vector<std::tuple<int, int>> const expected{{1, 1}, {1, 2}, {2, 3}, {2, 4}, {2, 5}, {1, 3}, {1, 4}};
-    auto rit = make_recursive_iterator(obj);
-    decltype(rit) end{ };
-    TS_ASSERT_EQUALS(std::distance(rit, end), expected.size());
-  }
-  
-  void test_vector_map_vector_iterator_matches_data() {
-    std::vector<std::map<int, std::vector<int>>> const obj{{{1, {1, 2}}, {2, {3, 4, 5}}}, {{1, {3, 4}}}};
-    std::vector<std::tuple<int, int>> const expected{{1, 1}, {1, 2}, {2, 3}, {2, 4}, {2, 5}, {1, 3}, {1, 4}};
-    auto rit = make_recursive_iterator(obj);
-    for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-  
-  void test_vector_map_vector_iterator_can_edit_data() {
-    std::vector<std::map<int, std::vector<int>>> obj{{{1, {1, 2}}, {2, {3, 4, 5}}}, {{1, {3, 4}}}};
-    auto rit = make_recursive_iterator(obj);
-    std::get<1>(*rit) = 6;
-    TS_ASSERT_EQUALS(obj[0][1][0], 6);
-  }
-};

+ 159 - 0
test/recursive_iterator_mixed_container_test.cxx

@@ -0,0 +1,159 @@
+#include "iterator/recursive_iterator.hpp"
+
+#include <map>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+TEST(RecursiveIteratorMapVectorTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::map<int, std::vector<int>> const obj{
+    {1, {1, 2}},
+    {2, {3, 4, 5}}
+  };
+  auto rit = make_recursive_iterator(obj);
+  decltype(rit) end{ };
+  // TODO: Actually perform the summation?
+  EXPECT_THAT(std::distance(rit, end), 5);
+}
+
+TEST(RecursiveIteratorMapVectorTest, ElementsAreUnwrappedAsATuple) {
+  std::map<int, std::vector<int>> const obj{
+    {1, {1, 2}},
+    {2, {3, 4, 5}}
+  };
+  std::vector<std::tuple<int, int>> const expected{
+    {1, 1}, {1, 2}, {2, 3}, {2, 4}, {2, 5}};
+  // TODO: Collapse into a container instead
+  auto rit = make_recursive_iterator(obj);
+  for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}
+
+TEST(RecursiveIteratorMapVectorTest, CanMutatePointedToData) {
+  std::map<int, std::vector<int>> obj{
+    {1, {1, 2}},
+    {2, {3, 4, 5}}
+  };
+  auto rit = make_recursive_iterator(obj);
+  std::get<1>(*rit) = 6;
+  EXPECT_THAT(obj[1][0], 6);
+}
+
+TEST(RecursiveIteratorVectorMapTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::vector<std::map<int, int>> const obj{
+    {{1, 1}, {2, 2}},
+    {{3, 3}, {4, 4}, {5, 5}}
+  };
+  auto rit = make_recursive_iterator(obj);
+  decltype(rit) end{ };
+  // TODO: Actually perform the summation?
+  EXPECT_THAT(std::distance(rit, end), 5);
+}
+
+TEST(RecursiveIteratorVectorMapTest, ElementsAreUnwrappedAsATuple) {
+  std::vector<std::map<int, int>> const obj{
+    {{1, 1}, {2, 2}},
+    {{3, 3}, {4, 4}, {5, 5}}
+  };
+  std::vector<std::pair<int const, int>> const expected{
+    {1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
+  auto rit = make_recursive_iterator(obj);
+  // TODO: Collapse into a container instead
+  for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}
+
+TEST(RecursiveIteratorVectorMapTest, CanMutatePointedToData) {
+  std::vector<std::map<int, int>> obj{
+    {{1, 1}, {2, 2}},
+    {{3, 3}, {4, 4}, {5, 5}}
+  };
+  auto rit = make_recursive_iterator(obj);
+  std::get<1>(*rit) = 6;
+  EXPECT_THAT(obj[0][1], 6);
+}
+
+TEST(RecursiveIteratorMapVecMapTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::map<int, std::vector<std::map<int, int>>> const obj{
+    {1, {
+      {{1, 1}, {2, 2}}
+    }}
+  };
+  std::vector<std::tuple<int, int, int>> const expected{{1, 1, 1}, {1, 2, 2}};
+  auto rit = make_recursive_iterator(obj);
+  decltype(rit) end{ };
+  EXPECT_THAT(std::distance(rit, end), expected.size());
+}
+
+TEST(RecursiveIteratorMapVecMapTest, ElementsAreUnwrappedAsATuple) {
+  std::map<int, std::vector<std::map<int, int>>> const obj{
+    {1, {
+      {{1, 1}, {2, 2}}
+    }}
+  };
+  std::vector<std::tuple<int, int, int>> const expected{{1, 1, 1}, {1, 2, 2}};
+  auto rit = make_recursive_iterator(obj);
+  // TODO: Collapse into a container instead
+  for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}
+
+TEST(RecursiveIteratorMapVecMapTest, CanMutatePointedToData) {
+  std::map<int, std::vector<std::map<int, int>>> obj{{1, {{{1, 1}, {2, 2}}}}};
+  auto rit = make_recursive_iterator(obj);
+  std::get<2>(*rit) = 4;
+  EXPECT_THAT(obj[1][0][1], 4);
+}
+
+TEST(RecursiveIteratorVecMapVecTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::vector<std::map<int, std::vector<int>>> const obj{
+    {
+      {1, {1, 2}},
+      {2, {3, 4, 5}}
+    },
+    {
+      {1, {3, 4}}
+    }
+  };
+  auto rit = make_recursive_iterator(obj);
+  decltype(rit) end{ };
+  // TODO: Actually perform the summation?
+  EXPECT_THAT(std::distance(rit, end), 7);
+}
+
+TEST(RecursiveIteratorVecMapVecTest, ElementsAreUnwrappedAsATuple) {
+  std::vector<std::map<int, std::vector<int>>> const obj{
+    {
+      {1, {1, 2}},
+      {2, {3, 4, 5}}
+    },
+    {
+      {1, {3, 4}}
+    }
+  };
+  std::vector<std::tuple<int, int>> const expected{
+    {1, 1}, {1, 2}, {2, 3}, {2, 4}, {2, 5}, {1, 3}, {1, 4}};
+  auto rit = make_recursive_iterator(obj);
+  // TODO: Collapse into a container instead
+  for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}
+
+TEST(RecursiveIteratorVecMapVecTest, CanMutatePointedToData) {
+  std::vector<std::map<int, std::vector<int>>> obj{
+    {
+      {1, {1, 2}},
+      {2, {3, 4, 5}}
+    },
+    {
+      {1, {3, 4}}
+    }
+  };
+  auto rit = make_recursive_iterator(obj);
+  std::get<1>(*rit) = 6;
+  EXPECT_THAT(obj[0][1][0], 6);
+}

+ 0 - 79
test/recursive_iterator_nested_map.t.h

@@ -1,79 +0,0 @@
-//
-//  recursive_iterator_nested_map.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 2/18/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "recursive_iterator.hpp"
-
-class recursive_iterator_nested_map_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_map_iterator_matches_size() {
-    std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
-    auto rit = make_recursive_iterator(map);
-    decltype(rit) end{ };
-    TS_ASSERT_EQUALS(std::distance(rit, end), map.size());
-  }
-  
-  void test_map_iterator_matches_data() {
-    std::map<int, int> const map{{1, 1}, {2, 2}, {3, 3}};
-    auto rit = make_recursive_iterator(map);
-    for (auto it = map.begin(), end = map.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-  
-  void test_map_iterator_can_edit_data() {
-    std::map<int, int> map{{1, 1}, {2, 2}, {3, 3}};
-    auto rit = make_recursive_iterator(map);
-    std::get<1>(*rit) = 4;
-    TS_ASSERT_EQUALS(map[1], 4);
-  }
-  
-  void test_map_map_iterator_matches_size() {
-    std::map<int, std::map<int, int>> const map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
-    std::vector<std::tuple<int, int, int>> const expected{{1, 1, 1}, {2, 2, 2}, {2, 3, 3}};
-    auto rit = make_recursive_iterator(map);
-    decltype(rit) end{ };
-    TS_ASSERT_EQUALS(std::distance(rit, end), expected.size());
-  }
-  
-  void test_map_map_iterator_matches_data() {
-    std::map<int, std::map<int, int>> const map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
-    std::vector<std::tuple<int, int, int>> const expected{{1, 1, 1}, {2, 2, 2}, {2, 3, 3}};
-    auto rit = make_recursive_iterator(map);
-    for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(std::tuple_cat(*it), *rit);
-    }
-  }
-  
-  void test_map_map_iterator_can_edit_data() {
-    std::map<int, std::map<int, int>> map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
-    auto rit = make_recursive_iterator(map);
-    std::get<2>(*rit) = 4;
-    TS_ASSERT_EQUALS(map[1][1], 4);
-  }
-  
-  void test_map_map_bounded_matches_size() {
-    std::map<int, std::map<int, int>> map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
-    auto rit = make_recursive_iterator<1>(map);
-    decltype(rit) end{ };
-    
-    TS_ASSERT_EQUALS(std::distance(rit, end), map.size());
-  }
-  
-  void test_map_map_bounded_matches_data() {
-    std::map<int, std::map<int, int>> map{{1, {{1, 1}}}, {2, {{2, 2}, {3, 3}}}};
-    auto rit = make_recursive_iterator<1>(map);
-    
-    for (auto it = map.begin(), end = map.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-
-};

+ 0 - 82
test/recursive_iterator_one_dimension.t.h

@@ -1,82 +0,0 @@
-//
-//  recursive_iterator.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 2/17/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "recursive_iterator.hpp"
-
-class recursive_iterator_one_dimension_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_vector_iterator_matches_size() {
-    std::vector<int> const vec{1, 2, 3, 4, 5};
-    auto rit = make_recursive_iterator(vec);
-    decltype(rit) end{ };
-    TS_ASSERT_EQUALS(std::distance(rit, end), vec.size());
-  }
-  
-  void test_vector_iterator_matches_data() {
-    std::vector<int> const vec{1, 2, 3, 4, 5};
-    auto rit = make_recursive_iterator(vec);
-    
-    for (auto it = vec.begin(), end = vec.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-  
-  void test_vector_can_edit_data() {
-    std::vector<int> vec{1, 2, 3, 4, 5};
-    auto rit = make_recursive_iterator(vec);
-    *rit = 6;
-    TS_ASSERT_EQUALS(vec[0], 6);
-  }
-  
-  void test_vector_vector_matches_size() {
-    std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
-    std::vector<int> const expected{1, 2, 3, 4, 5};
-    auto rit = make_recursive_iterator(vec);
-    decltype(rit) end{ };
-
-    TS_ASSERT_EQUALS(std::distance(rit, end), expected.size());
-  }
-
-  void test_vector_vector_matches_data() {
-    std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
-    std::vector<int> const expected{1, 2, 3, 4, 5};
-    auto rit = make_recursive_iterator(vec);
-    
-    for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-  
-  void test_vector_vector_can_edit_data() {
-    std::vector<std::vector<int>> vec{{1, 2}, {3, 4, 5}};
-    auto rit = make_recursive_iterator(vec);
-    *rit = 6;
-    TS_ASSERT_EQUALS(vec[0][0], 6);
-  }
-  
-  void test_vector_vector_bounded_matches_size() {
-    std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
-    auto rit = make_recursive_iterator<1>(vec);
-    decltype(rit) end{ };
-    
-    TS_ASSERT_EQUALS(std::distance(rit, end), vec.size());
-  }
-
-  void test_vector_vector_bounded_matches_data() {
-    std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
-    auto rit = make_recursive_iterator<1>(vec);
-
-    for (auto it = vec.begin(), end = vec.end(); it != end; ++it, ++rit) {
-      TS_ASSERT_EQUALS(*it, *rit);
-    }
-  }
-
-};

+ 74 - 0
test/recursive_iterator_vector_test.cxx

@@ -0,0 +1,74 @@
+#include "iterator/recursive_iterator.hpp"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+
+TEST(RecursiveIteratorSingleVectorTest, IterDistanceIsContainerSize) {
+  std::vector<int> const vec{1, 2, 3, 4, 5};
+  auto rit = make_recursive_iterator(vec);
+  decltype(rit) end{ };
+  EXPECT_THAT(std::distance(rit, end), vec.size());
+}
+
+TEST(RecursiveIteratorSingleVectorTest, ElementsAreUnwrappedAsATuple) {
+  std::vector<int> const vec{1, 2, 3, 4, 5};
+  auto rit = make_recursive_iterator(vec);
+  
+  // TODO: Collapse into a container instead
+  for (auto it = vec.begin(), end = vec.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}
+
+TEST(RecursiveIteratorSingleVectorTest, CanMutatePointedToData) {
+  std::vector<int> vec{1, 2, 3, 4, 5};
+  auto rit = make_recursive_iterator(vec);
+  *rit = 6;
+  EXPECT_THAT(vec[0], 6);
+}
+
+TEST(RecursiveIteratorVectorVectorTest, IterDistanceIsSumOfInnerContainerSizes) {
+  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
+  auto rit = make_recursive_iterator(vec);
+  decltype(rit) end{ };
+
+  // TODO: Actually perform the summation?
+  EXPECT_THAT(std::distance(rit, end), 5);
+}
+
+TEST(RecursiveIteratorVectorVectorTest, ElementsAreUnwrappedAsATuple) {
+  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
+  std::vector<int> const expected{1, 2, 3, 4, 5};
+  auto rit = make_recursive_iterator(vec);
+  
+  // TODO: Collapse into a container instead
+  for (auto it = expected.begin(), end = expected.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}
+
+TEST(RecursiveIteratorVectorVectorTest, CanMutatePointedToData) {
+  std::vector<std::vector<int>> vec{{1, 2}, {3, 4, 5}};
+  auto rit = make_recursive_iterator(vec);
+  *rit = 6;
+  EXPECT_THAT(vec[0][0], 6);
+}
+
+TEST(BoundedRecursiveIteratorVectorVectorTest, IterDistanceSumOnNLayersSize) {
+  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
+  auto rit = make_recursive_iterator<1>(vec);
+  decltype(rit) end{ };
+  
+  EXPECT_THAT(std::distance(rit, end), vec.size());
+}
+
+TEST(BoundedRecursiveIteratorVectorVectorTest, ElementsAreUnwrappedAsATuple) {
+  std::vector<std::vector<int>> const vec{{1, 2}, {3, 4, 5}};
+  auto rit = make_recursive_iterator<1>(vec);
+
+  // TODO: Collapse into a container instead
+  for (auto it = vec.begin(), end = vec.end(); it != end; ++it, ++rit) {
+    EXPECT_THAT(*it, *rit);
+  }
+}

+ 0 - 23
test/unkeyed_iterator.t.h

@@ -1,23 +0,0 @@
-//
-//  unkeyed_iterator.t.h
-//  iterator
-//
-//  Created by Sam Jaffe on 2/20/17.
-//
-
-#pragma once
-
-#include <cxxtest/TestSuite.h>
-
-#include "unkeyed_iterator.hpp"
-
-class unkeyed_iterator_TestSuite : public CxxTest::TestSuite {
-public:
-  void test_unkeyed_iterator_discards_key_map() {
-    using map_t = std::map<int, int>;
-    map_t map{{1, 2}, {2, 3}};
-    iterator::unkeyed_iterator<map_t::iterator> uit{map.begin()};
-    *uit = 4;
-    TS_ASSERT_EQUALS(map[1], 4);
-  }
-};

+ 24 - 0
test/unkeyed_iterator_test.cxx

@@ -0,0 +1,24 @@
+#include "iterator/unkeyed_iterator.hpp"
+
+#include <map>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+TEST(UnkeyedIteratorTest, IteratorOnlyReturnsValues) {
+  std::map<int, int> map{{1, 2}, {2, 3}};
+  std::vector<int> const expected{2, 3};
+  iterator::unkeyed_iterator<std::map<int, int>::iterator>{map.begin()};
+  std::vector<int> const result{
+    iterator::unkeyed_iterator<std::map<int, int>::iterator>{map.begin()},
+    iterator::unkeyed_iterator<std::map<int, int>::iterator>{map.end()}
+  };
+  EXPECT_THAT(result, expected);
+}
+
+TEST(UnkeyedIteratorTest, CanModifyIteratedCollectionValues) {
+  std::map<int, int> map{{1, 2}, {2, 3}};
+  iterator::unkeyed_iterator<std::map<int, int>::iterator> uit{map.begin()};
+  *uit = 4;
+  EXPECT_THAT(map[1], 4);
+}