incremental
diff --git a/src/test_utils.cpp b/src/test_utils.cpp
new file mode 100644
index 0000000..65ef721
--- /dev/null
+++ b/src/test_utils.cpp
@@ -0,0 +1,67 @@
+#include <zlib.h>
+#include <test_utils.hpp>
+#include <cstring>
+
+bool gzipInflate(const std::string& compressedBytes,
+                 std::string& uncompressedBytes) {
+  if (compressedBytes.size() == 0) {
+    uncompressedBytes = compressedBytes;
+    return true;
+  }
+
+  uncompressedBytes.clear();
+
+  unsigned full_length = compressedBytes.size();
+  unsigned half_length = compressedBytes.size() / 2;
+
+  unsigned uncompLength = full_length;
+  char* uncomp = (char*)calloc(sizeof(char), uncompLength);
+
+  z_stream strm;
+  strm.next_in = (Bytef*)compressedBytes.c_str();
+  strm.avail_in = compressedBytes.size();
+  strm.total_out = 0;
+  strm.zalloc = Z_NULL;
+  strm.zfree = Z_NULL;
+
+  bool done = false;
+
+  if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
+    free(uncomp);
+    return false;
+  }
+
+  while (!done) {
+    // If our output buffer is too small
+    if (strm.total_out >= uncompLength) {
+      // Increase size of output buffer
+      char* uncomp2 = (char*)calloc(sizeof(char), uncompLength + half_length);
+      std::memcpy(uncomp2, uncomp, uncompLength);
+      uncompLength += half_length;
+      free(uncomp);
+      uncomp = uncomp2;
+    }
+
+    strm.next_out = (Bytef*)(uncomp + strm.total_out);
+    strm.avail_out = uncompLength - strm.total_out;
+
+    // Inflate another chunk.
+    int err = inflate(&strm, Z_SYNC_FLUSH);
+    if (err == Z_STREAM_END)
+      done = true;
+    else if (err != Z_OK) {
+      break;
+    }
+  }
+
+  if (inflateEnd(&strm) != Z_OK) {
+    free(uncomp);
+    return false;
+  }
+
+  for (size_t i = 0; i < strm.total_out; ++i) {
+    uncompressedBytes += uncomp[i];
+  }
+  free(uncomp);
+  return true;
+}
\ No newline at end of file