diff --git a/.gitignore b/.gitignore
index 234bd3c4550c07f52be5458bc10ea92d4019b870..c23dfde0164c2ce71be3a2113f47b2f96e793753 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,9 @@
 *.toc
 *.blg
 
+# cmake
+CMakeFiles
+CMakeCache.txt
+cmake_install.cmake
+Makefile
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..717eb124c4eb1e08d455bdf73446fabec96a6265
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required (VERSION 2.8)
+
+# project info
+project (cell_algorithms)
+enable_language(CXX)
+
+# compilation flags
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -Wall")
+
+# this generates a .json file with full compilation command for each file
+set(CMAKE_EXPORT_COMPILE_COMMANDS "YES")
+
+# generated .a and .so go into /lib
+#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+#set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+
+include_directories(${CMAKE_SOURCE_DIR}/src)
+include_directories(${CMAKE_SOURCE_DIR})
+
+add_subdirectory(tests)
+
diff --git a/cells_small.json b/data/cells_small.json
similarity index 100%
rename from cells_small.json
rename to data/cells_small.json
diff --git a/makefile b/makefile
deleted file mode 100644
index 736a149f83bcb53f082a9a3656d7f1ef5ca5f321..0000000000000000000000000000000000000000
--- a/makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-CC=clang++
-FLAGS=-std=c++11 -g -pedantic
-
-test.exe : main.cpp *.hpp makefile gtest.o
-	$(CC) $(FLAGS) main.cpp -o test.exe gtest.o -pthread
-
-gtest.o :
-	$(CC) $(FLAGS) gtest-all.cc -c -o gtest.o
-
-clean :
-	rm -f test.exe
-	rm -f gtest.o
-	rm -f a.out
diff --git a/cell_tree.hpp b/src/cell_tree.hpp
similarity index 99%
rename from cell_tree.hpp
rename to src/cell_tree.hpp
index 3daf48d56620725dae2bb44cb47dfe318b4ab0c5..e6ba5b2e9dcb4c19e1708bf7d87554f47cfb5f94 100644
--- a/cell_tree.hpp
+++ b/src/cell_tree.hpp
@@ -192,7 +192,6 @@ class cell_tree {
 
         auto max       = std::max_element(depth.begin(), depth.end());
         auto max_leaf  = std::distance(depth.begin(), max);
-        auto original_depth = *max;
 
         // Calculate the depth of each compartment as the maximum distance
         // from a child leaf
diff --git a/swcio.hpp b/src/swcio.hpp
similarity index 100%
rename from swcio.hpp
rename to src/swcio.hpp
diff --git a/tree.hpp b/src/tree.hpp
similarity index 98%
rename from tree.hpp
rename to src/tree.hpp
index 772eb86c99d55ac65b076ee8ab164d1ae0c6c675..04f8ccd4d35b207a5567906d3eb84c47058340c2 100644
--- a/tree.hpp
+++ b/src/tree.hpp
@@ -58,10 +58,6 @@ class tree {
             }
         }
 
-        // The number of children is the number of branches, excluding the root branch.
-        // num_children is equivalent to the number of edges in the graph.
-        auto nchildren = nbranches-1;
-
         // allocate memory for storing the tree
         init(nbranches);
 
diff --git a/util.hpp b/src/util.hpp
similarity index 98%
rename from util.hpp
rename to src/util.hpp
index d37c7f65427f1bd7e12edc8ee10b0f95fcb47ba8..17a3a49b0a19ee867229f71e08ab27b2c6962d57 100644
--- a/util.hpp
+++ b/src/util.hpp
@@ -2,12 +2,14 @@
 
 #include "vector/include/Vector.hpp"
 
+/*
 using memory::util::red;
 using memory::util::yellow;
 using memory::util::green;
 using memory::util::white;
 using memory::util::blue;
 using memory::util::cyan;
+*/
 
 #include <ostream>
 #include <vector>
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ba8b481ad51109f2a758ebd19c4281d5f3792d2f
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(HEADERS
+    ../src/swcio.hpp
+    ../src/tree.hpp
+    ../src/cell_tree.hpp
+)
+
+set(TEST_SOURCES
+    # google test framework
+    gtest-all.cpp
+
+    # unit tests
+    test_swcio.cpp
+    test_tree.cpp
+
+    # unit test driver
+    main.cpp
+)
+
+add_executable(test.exe ${TEST_SOURCES} ${HEADERS})
+
+#target_link_libraries(test_compiler LINK_PUBLIC compiler gtest)
+
+#set_target_properties( test.exe
+#   PROPERTIES
+#   RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests"
+#)
+
diff --git a/gtest-all.cc b/tests/gtest-all.cpp
similarity index 99%
rename from gtest-all.cc
rename to tests/gtest-all.cpp
index c3fb36ab25b692ce827eda4ccf8a85fbc3a923ae..641a64833c5b79f930e0206d82b44279f2f1dbe8 100644
--- a/gtest-all.cc
+++ b/tests/gtest-all.cpp
@@ -36,7 +36,7 @@
 
 // This line ensures that gtest.h can be compiled on its own, even
 // when it's fused.
-#include "gtest/gtest.h"
+#include "gtest.h"
 
 // The following lines pull in the real gtest *.cc files.
 // Copyright 2005, Google Inc.
diff --git a/gtest/gtest.h b/tests/gtest.h
similarity index 100%
rename from gtest/gtest.h
rename to tests/gtest.h
diff --git a/tests/main.cpp b/tests/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2eab0931a0b4b2a5b17ed12ba6c2f3d1d09d27c
--- /dev/null
+++ b/tests/main.cpp
@@ -0,0 +1,11 @@
+#include <iostream>
+#include <fstream>
+#include <numeric>
+#include <vector>
+
+#include "gtest.h"
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/make_image.sh b/tests/make_image.sh
similarity index 100%
rename from make_image.sh
rename to tests/make_image.sh
diff --git a/tests/test_swcio.cpp b/tests/test_swcio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..862f5a1cc343c62aa0e192e352c188bb22e86f74
--- /dev/null
+++ b/tests/test_swcio.cpp
@@ -0,0 +1,182 @@
+#include <iostream>
+#include <fstream>
+#include <numeric>
+#include <vector>
+
+#include "gtest.h"
+
+#include "swcio.hpp"
+
+// SWC tests
+void expect_cell_equals(const neuron::io::cell_record &expected,
+                        const neuron::io::cell_record &actual)
+{
+    EXPECT_EQ(expected.id(), actual.id());
+    EXPECT_EQ(expected.type(), actual.type());
+    EXPECT_FLOAT_EQ(expected.x(), actual.x());
+    EXPECT_FLOAT_EQ(expected.y(), actual.y());
+    EXPECT_FLOAT_EQ(expected.z(), actual.z());
+    EXPECT_FLOAT_EQ(expected.radius(), actual.radius());
+    EXPECT_EQ(expected.parent(), actual.parent());
+}
+
+TEST(cell_record, construction)
+{
+    using namespace neuron::io;
+
+    {
+        // force an invalid type
+        cell_record::kind invalid_type = static_cast<cell_record::kind>(100);
+        EXPECT_THROW(cell_record cell(invalid_type, 7, 1., 1., 1., 1., 5),
+                     std::invalid_argument);
+    }
+
+    {
+        // invalid id
+        EXPECT_THROW(cell_record cell(
+                         cell_record::custom, -3, 1., 1., 1., 1., 5),
+                     std::invalid_argument);
+    }
+
+    {
+        // invalid parent id
+        EXPECT_THROW(cell_record cell(
+                         cell_record::custom, 0, 1., 1., 1., 1., -5),
+                     std::invalid_argument);
+    }
+
+    {
+        // invalid radius
+        EXPECT_THROW(cell_record cell(
+                         cell_record::custom, 0, 1., 1., 1., -1., -1),
+                     std::invalid_argument);
+    }
+
+    {
+        // parent_id > id
+        EXPECT_THROW(cell_record cell(
+                         cell_record::custom, 0, 1., 1., 1., 1., 2),
+                     std::invalid_argument);
+    }
+
+    {
+        // parent_id == id
+        EXPECT_THROW(cell_record cell(
+                         cell_record::custom, 0, 1., 1., 1., 1., 0),
+                     std::invalid_argument);
+    }
+
+    {
+        // check standard construction by value
+        cell_record cell(cell_record::custom, 0, 1., 1., 1., 1., -1);
+        EXPECT_EQ(cell.id(), 0);
+        EXPECT_EQ(cell.type(), cell_record::custom);
+        EXPECT_EQ(cell.x(), 1.);
+        EXPECT_EQ(cell.y(), 1.);
+        EXPECT_EQ(cell.z(), 1.);
+        EXPECT_EQ(cell.radius(), 1.);
+        EXPECT_EQ(cell.diameter(), 2*1.);
+        EXPECT_EQ(cell.parent(), -1);
+    }
+
+    {
+        // check copy constructor
+        cell_record cell_orig(cell_record::custom, 0, 1., 1., 1., 1., -1);
+        cell_record cell(cell_orig);
+        expect_cell_equals(cell_orig, cell);
+    }
+}
+
+TEST(swc_parser, invalid_input)
+{
+    using namespace neuron::io;
+
+    {
+        // check incomplete lines; missing parent
+        std::istringstream is("1 1 14.566132 34.873772 7.857000 0.717830\n");
+        cell_record cell;
+        EXPECT_THROW(is >> cell, std::logic_error);
+    }
+
+    {
+        // Check non-parsable values
+        std::istringstream is("1a 1 14.566132 34.873772 7.857000 0.717830 -1\n");
+        cell_record cell;
+        EXPECT_THROW(is >> cell, std::logic_error);
+    }
+
+    {
+        // Check invalid cell type
+        std::istringstream is("1 10 14.566132 34.873772 7.857000 0.717830 -1\n");
+        cell_record cell;
+        EXPECT_THROW(is >> cell, std::invalid_argument);
+    }
+}
+
+
+TEST(swc_parser, valid_input)
+{
+    using namespace neuron::io;
+
+    {
+        // check empty file; no cell may be parsed
+        cell_record cell, cell_orig;
+        std::istringstream is("");
+        EXPECT_NO_THROW(is >> cell);
+        expect_cell_equals(cell_orig, cell);
+    }
+
+    {
+        // check comment-only file not ending with a newline;
+        // no cell may be parsed
+        cell_record cell, cell_orig;
+        std::istringstream is("#comment\n#comment");
+        EXPECT_NO_THROW(is >> cell);
+        expect_cell_equals(cell_orig, cell);
+    }
+
+
+    {
+        // check last line case (no newline at the end)
+        std::istringstream is("1 1 14.566132 34.873772 7.857000 0.717830 -1");
+        cell_record cell;
+        EXPECT_NO_THROW(is >> cell);
+        EXPECT_EQ(0, cell.id());    // zero-based indexing
+        EXPECT_EQ(cell_record::soma, cell.type());
+        EXPECT_FLOAT_EQ(14.566132, cell.x());
+        EXPECT_FLOAT_EQ(34.873772, cell.y());
+        EXPECT_FLOAT_EQ( 7.857000, cell.z());
+        EXPECT_FLOAT_EQ( 0.717830, cell.radius());
+        EXPECT_FLOAT_EQ( -1, cell.parent());
+    }
+
+    {
+        // check valid input with a series of records
+        std::vector<cell_record> cells_orig = {
+            cell_record(cell_record::soma, 0,
+                        14.566132, 34.873772, 7.857000, 0.717830, -1),
+            cell_record(cell_record::dendrite, 1,
+                        14.566132+1, 34.873772+1, 7.857000+1, 0.717830+1, -1)
+        };
+
+        std::stringstream swc_input;
+        swc_input << "# this is a comment\n";
+        swc_input << "# this is a comment\n";
+        for (auto c : cells_orig)
+            swc_input << c << "\n";
+
+        swc_input << "# this is a final comment\n";
+        try {
+            std::size_t nr_records = 0;
+            cell_record cell;
+            while ( !(swc_input >> cell).eof()) {
+                ASSERT_LT(nr_records, cells_orig.size());
+                expect_cell_equals(cells_orig[nr_records], cell);
+                ++nr_records;
+            }
+        } catch (std::exception &e) {
+            ADD_FAILURE();
+        }
+    }
+}
+
diff --git a/main.cpp b/tests/test_tree.cpp
similarity index 58%
rename from main.cpp
rename to tests/test_tree.cpp
index ed8c3307699c64dc2ed19860d54de7739cd88e4e..3bd26796147d8d906fd88ae9b57c8708ef61e2e7 100644
--- a/main.cpp
+++ b/tests/test_tree.cpp
@@ -3,10 +3,9 @@
 #include <numeric>
 #include <vector>
 
-#include "gtest/gtest.h"
+#include "gtest.h"
 
 #include "cell_tree.hpp"
-#include "swcio.hpp"
 #include "json/src/json.hpp"
 
 using json = nlohmann::json;
@@ -242,7 +241,7 @@ TEST(cell_tree, balance) {
 // from a json file and creates a .dot file for it
 TEST(cell_tree, json_load) {
     json  cell_data;
-    std::ifstream("cells_small.json") >> cell_data;
+    std::ifstream("../data/cells_small.json") >> cell_data;
 
     for(auto c : range(0,cell_data.size())) {
         std::vector<int> parent_index = cell_data[c]["parent_index"];
@@ -252,180 +251,3 @@ TEST(cell_tree, json_load) {
     }
 }
 
-// SWC tests
-void expect_cell_equals(const neuron::io::cell_record &expected,
-                        const neuron::io::cell_record &actual)
-{
-    EXPECT_EQ(expected.id(), actual.id());
-    EXPECT_EQ(expected.type(), actual.type());
-    EXPECT_FLOAT_EQ(expected.x(), actual.x());
-    EXPECT_FLOAT_EQ(expected.y(), actual.y());
-    EXPECT_FLOAT_EQ(expected.z(), actual.z());
-    EXPECT_FLOAT_EQ(expected.radius(), actual.radius());
-    EXPECT_EQ(expected.parent(), actual.parent());
-}
-
-TEST(cell_record, construction)
-{
-    using namespace neuron::io;
-
-    {
-        // force an invalid type
-        cell_record::kind invalid_type = static_cast<cell_record::kind>(100);
-        EXPECT_THROW(cell_record cell(invalid_type, 7, 1., 1., 1., 1., 5),
-                     std::invalid_argument);
-    }
-
-    {
-        // invalid id
-        EXPECT_THROW(cell_record cell(
-                         cell_record::custom, -3, 1., 1., 1., 1., 5),
-                     std::invalid_argument);
-    }
-
-    {
-        // invalid parent id
-        EXPECT_THROW(cell_record cell(
-                         cell_record::custom, 0, 1., 1., 1., 1., -5),
-                     std::invalid_argument);
-    }
-
-    {
-        // invalid radius
-        EXPECT_THROW(cell_record cell(
-                         cell_record::custom, 0, 1., 1., 1., -1., -1),
-                     std::invalid_argument);
-    }
-
-    {
-        // parent_id > id
-        EXPECT_THROW(cell_record cell(
-                         cell_record::custom, 0, 1., 1., 1., 1., 2),
-                     std::invalid_argument);
-    }
-
-    {
-        // parent_id == id
-        EXPECT_THROW(cell_record cell(
-                         cell_record::custom, 0, 1., 1., 1., 1., 0),
-                     std::invalid_argument);
-    }
-
-    {
-        // check standard construction by value
-        cell_record cell(cell_record::custom, 0, 1., 1., 1., 1., -1);
-        EXPECT_EQ(cell.id(), 0);
-        EXPECT_EQ(cell.type(), cell_record::custom);
-        EXPECT_EQ(cell.x(), 1.);
-        EXPECT_EQ(cell.y(), 1.);
-        EXPECT_EQ(cell.z(), 1.);
-        EXPECT_EQ(cell.radius(), 1.);
-        EXPECT_EQ(cell.diameter(), 2*1.);
-        EXPECT_EQ(cell.parent(), -1);
-    }
-
-    {
-        // check copy constructor
-        cell_record cell_orig(cell_record::custom, 0, 1., 1., 1., 1., -1);
-        cell_record cell(cell_orig);
-        expect_cell_equals(cell_orig, cell);
-    }
-}
-
-TEST(swc_parser, invalid_input)
-{
-    using namespace neuron::io;
-
-    {
-        // check incomplete lines; missing parent
-        std::istringstream is("1 1 14.566132 34.873772 7.857000 0.717830\n");
-        cell_record cell;
-        EXPECT_THROW(is >> cell, std::logic_error);
-    }
-
-    {
-        // Check non-parsable values
-        std::istringstream is("1a 1 14.566132 34.873772 7.857000 0.717830 -1\n");
-        cell_record cell;
-        EXPECT_THROW(is >> cell, std::logic_error);
-    }
-
-    {
-        // Check invalid cell type
-        std::istringstream is("1 10 14.566132 34.873772 7.857000 0.717830 -1\n");
-        cell_record cell;
-        EXPECT_THROW(is >> cell, std::invalid_argument);
-    }
-}
-
-
-TEST(swc_parser, valid_input)
-{
-    using namespace neuron::io;
-
-    {
-        // check empty file; no cell may be parsed
-        cell_record cell, cell_orig;
-        std::istringstream is("");
-        EXPECT_NO_THROW(is >> cell);
-        expect_cell_equals(cell_orig, cell);
-    }
-
-    {
-        // check comment-only file not ending with a newline;
-        // no cell may be parsed
-        cell_record cell, cell_orig;
-        std::istringstream is("#comment\n#comment");
-        EXPECT_NO_THROW(is >> cell);
-        expect_cell_equals(cell_orig, cell);
-    }
-
-
-    {
-        // check last line case (no newline at the end)
-        std::istringstream is("1 1 14.566132 34.873772 7.857000 0.717830 -1");
-        cell_record cell;
-        EXPECT_NO_THROW(is >> cell);
-        EXPECT_EQ(0, cell.id());    // zero-based indexing
-        EXPECT_EQ(cell_record::soma, cell.type());
-        EXPECT_FLOAT_EQ(14.566132, cell.x());
-        EXPECT_FLOAT_EQ(34.873772, cell.y());
-        EXPECT_FLOAT_EQ( 7.857000, cell.z());
-        EXPECT_FLOAT_EQ( 0.717830, cell.radius());
-        EXPECT_FLOAT_EQ( -1, cell.parent());
-    }
-
-    {
-        // check valid input with a series of records
-        std::vector<cell_record> cells_orig = {
-            cell_record(cell_record::soma, 0,
-                        14.566132, 34.873772, 7.857000, 0.717830, -1),
-            cell_record(cell_record::dendrite, 1,
-                        14.566132+1, 34.873772+1, 7.857000+1, 0.717830+1, -1)
-        };
-
-        std::stringstream swc_input;
-        swc_input << "# this is a comment\n";
-        swc_input << "# this is a comment\n";
-        for (auto c : cells_orig)
-            swc_input << c << "\n";
-
-        swc_input << "# this is a final comment\n";
-        try {
-            std::size_t nr_records = 0;
-            cell_record cell;
-            while ( !(swc_input >> cell).eof()) {
-                ASSERT_LT(nr_records, cells_orig.size());
-                expect_cell_equals(cells_orig[nr_records], cell);
-                ++nr_records;
-            }
-        } catch (std::exception &e) {
-            ADD_FAILURE();
-        }
-    }
-}
-
-int main(int argc, char **argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    return RUN_ALL_TESTS();
-}
diff --git a/vector b/vector
index 9c86d0a84efed0dd739888503d275378df67fe71..79ad5236b219a7618a8cda8caad6cd3de1f9e122 160000
--- a/vector
+++ b/vector
@@ -1 +1 @@
-Subproject commit 9c86d0a84efed0dd739888503d275378df67fe71
+Subproject commit 79ad5236b219a7618a8cda8caad6cd3de1f9e122