You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@orc.apache.org by om...@apache.org on 2015/07/06 23:52:41 UTC

[12/23] orc git commit: ORC-23. Simplify directory structure.

http://git-wip-us.apache.org/repos/asf/orc/blob/7f55b453/c++/test/TestCompression.cc
----------------------------------------------------------------------
diff --git a/c++/test/TestCompression.cc b/c++/test/TestCompression.cc
new file mode 100644
index 0000000..0f6eb3c
--- /dev/null
+++ b/c++/test/TestCompression.cc
@@ -0,0 +1,647 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Compression.hh"
+#include "Exceptions.hh"
+#include "OrcTest.hh"
+#include "wrap/gtest-wrapper.h"
+
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include "zlib.h"
+#include "wrap/snappy-wrapper.h"
+
+namespace orc {
+
+  class TestCompression : public ::testing::Test {
+  public:
+    ~TestCompression();
+  protected:
+    // Per-test-case set-up.
+    static void SetUpTestCase() {
+      simpleFile = "simple-file.binary";
+      remove(simpleFile);
+      std::ofstream file;
+      file.exceptions(std::ofstream::failbit | std::ofstream::badbit);
+      file.open(simpleFile,
+                std::ios::out | std::ios::binary | std::ios::trunc);
+      for(unsigned int i = 0; i < 200; ++i) {
+        file.put(static_cast<char>(i));
+      }
+      file.close();
+    }
+
+    // Per-test-case tear-down.
+    static void TearDownTestCase() {
+      simpleFile = 0;
+    }
+
+    static const char *simpleFile;
+  };
+
+  const char *TestCompression::simpleFile;
+
+  TestCompression::~TestCompression() {
+    // PASS
+  }
+
+  TEST_F(TestCompression, testPrintBufferEmpty) {
+    std::ostringstream str;
+    printBuffer(str, 0, 0);
+    EXPECT_EQ("", str.str());
+  }
+
+  TEST_F(TestCompression, testPrintBufferSmall) {
+    std::vector<char> buffer(10);
+    std::ostringstream str;
+    for(size_t i=0; i < 10; ++i) {
+      buffer[i] = static_cast<char>(i);
+    }
+    printBuffer(str, buffer.data(), 10);
+    EXPECT_EQ("0000000 00 01 02 03 04 05 06 07 08 09\n", str.str());
+  }
+
+  TEST_F(TestCompression, testPrintBufferLong) {
+    std::vector<char> buffer(300);
+    std::ostringstream str;
+    for(size_t i=0; i < 300; ++i) {
+      buffer[i] = static_cast<char>(i);
+    }
+    printBuffer(str, buffer.data(), 300);
+    std::ostringstream expected;
+    expected << "0000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10"
+             << " 11 12 13 14 15 16 17\n"
+             << "0000018 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28"
+             << " 29 2a 2b 2c 2d 2e 2f\n"
+             << "0000030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40"
+             << " 41 42 43 44 45 46 47\n"
+             << "0000048 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58"
+             << " 59 5a 5b 5c 5d 5e 5f\n"
+             << "0000060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70"
+             << " 71 72 73 74 75 76 77\n"
+             << "0000078 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88"
+             << " 89 8a 8b 8c 8d 8e 8f\n"
+             << "0000090 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0"
+             << " a1 a2 a3 a4 a5 a6 a7\n"
+             << "00000a8 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8"
+             << " b9 ba bb bc bd be bf\n"
+             << "00000c0 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0"
+             << " d1 d2 d3 d4 d5 d6 d7\n"
+             << "00000d8 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8"
+             << " e9 ea eb ec ed ee ef\n"
+             << "00000f0 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00"
+             << " 01 02 03 04 05 06 07\n"
+             << "0000108 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18"
+             << " 19 1a 1b 1c 1d 1e 1f\n"
+             << "0000120 20 21 22 23 24 25 26 27 28 29 2a 2b\n";
+    EXPECT_EQ(expected.str(), str.str());
+  }
+
+  TEST_F(TestCompression, testArrayBackup) {
+    std::vector<char> bytes(200);
+    for(size_t i=0; i < bytes.size(); ++i) {
+      bytes[i] = static_cast<char>(i);
+    }
+    SeekableArrayInputStream stream(bytes.data(), bytes.size(), 20);
+    const void *ptr;
+    int len;
+    ASSERT_THROW(stream.BackUp(10), std::logic_error);
+    EXPECT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(bytes.data(), static_cast<const char *>(ptr));
+    EXPECT_EQ(20, len);
+    stream.BackUp(0);
+    EXPECT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(bytes.data() + 20, static_cast<const char *>(ptr));
+    EXPECT_EQ(20, len);
+    stream.BackUp(10);
+    for(unsigned int i=0; i < 8; ++i) {
+      EXPECT_EQ(true, stream.Next(&ptr, &len));
+      unsigned int consumedBytes = 30 + 20 * i;
+      EXPECT_EQ(bytes.data() + consumedBytes, static_cast<const char *>(ptr));
+      EXPECT_EQ(consumedBytes + 20, stream.ByteCount());
+      EXPECT_EQ(20, len);
+    }
+    EXPECT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(bytes.data() + 190, static_cast<const char *>(ptr));
+    EXPECT_EQ(10, len);
+    EXPECT_EQ(true, !stream.Next(&ptr, &len));
+    EXPECT_EQ(0, len);
+    ASSERT_THROW(stream.BackUp(30), std::logic_error);
+    EXPECT_EQ(200, stream.ByteCount());
+  }
+
+  TEST_F(TestCompression, testArraySkip) {
+    std::vector<char> bytes(200);
+    for(size_t i=0; i < bytes.size(); ++i) {
+      bytes[i] = static_cast<char>(i);
+    }
+    SeekableArrayInputStream stream(bytes.data(), bytes.size(), 20);
+    const void *ptr;
+    int len;
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(bytes.data(), static_cast<const char *>(ptr));
+    EXPECT_EQ(20, len);
+    ASSERT_EQ(true, !stream.Skip(-10));
+    ASSERT_EQ(true, stream.Skip(80));
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(bytes.data() + 100, static_cast<const char *>(ptr));
+    EXPECT_EQ(20, len);
+    ASSERT_EQ(true, stream.Skip(80));
+    ASSERT_EQ(true, !stream.Next(&ptr, &len));
+    ASSERT_EQ(true, !stream.Skip(181));
+    EXPECT_EQ("SeekableArrayInputStream 200 of 200", stream.getName());
+  }
+
+  TEST_F(TestCompression, testArrayCombo) {
+    std::vector<char> bytes(200);
+    for(size_t i=0; i < bytes.size(); ++i) {
+      bytes[i] = static_cast<char>(i);
+    }
+    SeekableArrayInputStream stream(bytes.data(), bytes.size(), 20);
+    const void *ptr;
+    int len;
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(bytes.data(), static_cast<const char *>(ptr));
+    EXPECT_EQ(20, len);
+    stream.BackUp(10);
+    EXPECT_EQ(10, stream.ByteCount());
+    stream.Skip(4);
+    EXPECT_EQ(14, stream.ByteCount());
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(bytes.data() + 14, static_cast<const char *>(ptr));
+    EXPECT_EQ(true, !stream.Skip(320));
+    EXPECT_EQ(200, stream.ByteCount());
+    EXPECT_EQ(true, !stream.Next(&ptr, &len));
+  }
+
+  // this checks to make sure that a given set of bytes are ascending
+  void checkBytes(const char*data, int length,
+                  unsigned int startValue) {
+    for(unsigned int i=0; static_cast<int>(i) < length; ++i) {
+      EXPECT_EQ(startValue + i, static_cast<unsigned char>(data[i]))
+        << "Output wrong at " << startValue << " + " << i;
+    }
+  }
+
+  TEST_F(TestCompression, testFileBackup) {
+    SCOPED_TRACE("testFileBackup");
+    std::unique_ptr<InputStream> file = readLocalFile(simpleFile);
+    SeekableFileInputStream stream(file.get(), 0, 200, *getDefaultPool(), 20);
+    const void *ptr;
+    int len;
+    ASSERT_THROW(stream.BackUp(10), std::logic_error);
+    EXPECT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(20, len);
+    checkBytes(static_cast<const char*>(ptr), len, 0);
+    stream.BackUp(0);
+    EXPECT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(20, len);
+    checkBytes(static_cast<const char*>(ptr), len, 20);
+    stream.BackUp(10);
+    EXPECT_EQ(30, stream.ByteCount());
+    EXPECT_EQ(true, stream.Next(&ptr, &len));
+    EXPECT_EQ(10, len);
+    checkBytes(static_cast<const char*>(ptr), len, 30);
+    for(unsigned int i=0; i < 8; ++i) {
+      EXPECT_EQ(20 * i + 40, stream.ByteCount());
+      EXPECT_EQ(true, stream.Next(&ptr, &len));
+      EXPECT_EQ(20, len);
+      checkBytes(static_cast<const char*>(ptr), len, 20 * i + 40);
+    }
+    EXPECT_EQ(true, !stream.Next(&ptr, &len));
+    EXPECT_EQ(0, len);
+    ASSERT_THROW(stream.BackUp(30), std::logic_error);
+    EXPECT_EQ(200, stream.ByteCount());
+  }
+
+  TEST_F(TestCompression, testFileSkip) {
+    SCOPED_TRACE("testFileSkip");
+    std::unique_ptr<InputStream> file = readLocalFile(simpleFile);
+    SeekableFileInputStream stream(file.get(), 0, 200, *getDefaultPool(), 20);
+    const void *ptr;
+    int len;
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    checkBytes(static_cast<const char*>(ptr), len, 0);
+    EXPECT_EQ(20, len);
+    ASSERT_EQ(true, !stream.Skip(-10));
+    ASSERT_EQ(true, stream.Skip(80));
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    checkBytes(static_cast<const char*>(ptr), len, 100);
+    EXPECT_EQ(20, len);
+    ASSERT_EQ(true, !stream.Skip(80));
+    ASSERT_EQ(true, !stream.Next(&ptr, &len));
+    ASSERT_EQ(true, !stream.Skip(181));
+    EXPECT_EQ("simple-file.binary from 0 for 200", stream.getName());
+  }
+
+  TEST_F(TestCompression, testFileCombo) {
+    SCOPED_TRACE("testFileCombo");
+    std::unique_ptr<InputStream> file = readLocalFile(simpleFile);
+    SeekableFileInputStream stream(file.get(), 0, 200, *getDefaultPool(), 20);
+    const void *ptr;
+    int len;
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    checkBytes(static_cast<const char*>(ptr), len, 0);
+    EXPECT_EQ(20, len);
+    stream.BackUp(10);
+    EXPECT_EQ(10, stream.ByteCount());
+    stream.Skip(4);
+    EXPECT_EQ(14, stream.ByteCount());
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    checkBytes(static_cast<const char*>(ptr), len, 14);
+    EXPECT_EQ(true, !stream.Skip(320));
+    EXPECT_EQ(200, stream.ByteCount());
+    EXPECT_EQ(true, !stream.Next(&ptr, &len));
+  }
+
+  TEST_F(TestCompression, testFileSeek) {
+    SCOPED_TRACE("testFileSeek");
+    std::unique_ptr<InputStream> file = readLocalFile(simpleFile);
+    SeekableFileInputStream stream(file.get(), 0, 200, *getDefaultPool(), 20);
+    const void *ptr;
+    int len;
+    EXPECT_EQ(0, stream.ByteCount());
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    checkBytes(static_cast<const char*>(ptr), len, 0);
+    EXPECT_EQ(20, len);
+    EXPECT_EQ(20, stream.ByteCount());
+    {
+      std::list<uint64_t> offsets(1, 100);
+      PositionProvider posn(offsets);
+      stream.seek(posn);
+    }
+    EXPECT_EQ(100, stream.ByteCount());
+    {
+      std::list<uint64_t> offsets(1, 5);
+      PositionProvider posn(offsets);
+      stream.seek(posn);
+    }
+    EXPECT_EQ(5, stream.ByteCount());
+    ASSERT_EQ(true, stream.Next(&ptr, &len));
+    checkBytes(static_cast<const char*>(ptr), len, 5);
+    EXPECT_EQ(20, len);
+    {
+      std::list<uint64_t> offsets(1, 201);
+      PositionProvider posn(offsets);
+      EXPECT_THROW(stream.seek(posn), std::logic_error);
+      EXPECT_EQ(200, stream.ByteCount());
+    }
+  }
+
+  TEST_F(TestCompression, testCreateNone) {
+    std::vector<char> bytes(10);
+    for(unsigned int i=0; i < bytes.size(); ++i) {
+      bytes[i] = static_cast<char>(i);
+    }
+    std::unique_ptr<SeekableInputStream> result =
+      createDecompressor(CompressionKind_NONE,
+                         std::unique_ptr<SeekableInputStream>
+                         (new SeekableArrayInputStream(bytes.data(),
+                                                       bytes.size())),
+                         32768,
+                         *getDefaultPool());
+    const void *ptr;
+    int length;
+    result->Next(&ptr, &length);
+    for(unsigned int i=0; i < bytes.size(); ++i) {
+      EXPECT_EQ(static_cast<char>(i), static_cast<const char*>(ptr)[i]);
+    }
+  }
+
+  TEST_F(TestCompression, testCreateLzo) {
+    const unsigned char buffer[] = {0};
+    EXPECT_THROW(createDecompressor(CompressionKind_LZO,
+                             std::unique_ptr<SeekableInputStream>
+                                    (new SeekableArrayInputStream(buffer, 0)),
+                                    32768, *getDefaultPool()),
+                 NotImplementedYet);
+  }
+
+  TEST(Zlib, testCreateZlib) {
+    const unsigned char buffer[] = {0x0b, 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4};
+    std::unique_ptr<SeekableInputStream> result =
+      createDecompressor(CompressionKind_ZLIB,
+                         std::unique_ptr<SeekableInputStream>
+                         (new SeekableArrayInputStream
+                          (buffer, ARRAY_SIZE(buffer))),
+                         32768, *getDefaultPool());
+    EXPECT_EQ("zlib(SeekableArrayInputStream 0 of 8)", result->getName());
+    const void *ptr;
+    int length;
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(5, length);
+    for(unsigned int i=0; i < 5; ++i) {
+      EXPECT_EQ(static_cast<char>(i), static_cast<const char*>(ptr)[i]);
+    }
+    EXPECT_EQ("zlib(SeekableArrayInputStream 8 of 8)", result->getName());
+    EXPECT_EQ(5, result->ByteCount());
+    result->BackUp(3);
+    EXPECT_EQ(2, result->ByteCount());
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(3, length);
+    for(unsigned int i=0; i < 3; ++i) {
+      EXPECT_EQ(static_cast<char>(i+2), static_cast<const char*>(ptr)[i]);
+    }
+  }
+
+  TEST(Zlib, testLiteralBlocks) {
+    const unsigned char buffer[] = {0x19, 0x0, 0x0, 0x0, 0x1,
+				    0x2, 0x3, 0x4, 0x5, 0x6,
+				    0x7, 0x8, 0x9, 0xa, 0xb,
+				    0xb, 0x0, 0x0, 0xc, 0xd,
+				    0xe, 0xf, 0x10};
+    std::unique_ptr<SeekableInputStream> result =
+      createDecompressor(CompressionKind_ZLIB,
+                         std::unique_ptr<SeekableInputStream>
+                         (new SeekableArrayInputStream
+                          (buffer, ARRAY_SIZE(buffer), 5)),
+                         5, *getDefaultPool());
+    EXPECT_EQ("zlib(SeekableArrayInputStream 0 of 23)", result->getName());
+    const void *ptr;
+    int length;
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(2, length);
+    EXPECT_EQ(0, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(1, static_cast<const char*>(ptr)[1]);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(5, length);
+    EXPECT_EQ(2, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(3, static_cast<const char*>(ptr)[1]);
+    EXPECT_EQ(4, static_cast<const char*>(ptr)[2]);
+    EXPECT_EQ(5, static_cast<const char*>(ptr)[3]);
+    EXPECT_EQ(6, static_cast<const char*>(ptr)[4]);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(5, length);
+    EXPECT_EQ(7, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(8, static_cast<const char*>(ptr)[1]);
+    EXPECT_EQ(9, static_cast<const char*>(ptr)[2]);
+    EXPECT_EQ(10, static_cast<const char*>(ptr)[3]);
+    EXPECT_EQ(11, static_cast<const char*>(ptr)[4]);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(2, length);
+    EXPECT_EQ(12, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(13, static_cast<const char*>(ptr)[1]);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(3, length);
+    EXPECT_EQ(14, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(15, static_cast<const char*>(ptr)[1]);
+    EXPECT_EQ(16, static_cast<const char*>(ptr)[2]);
+  }
+
+  TEST(Zlib, testInflate) {
+    const unsigned char buffer [] = {0xe, 0x0, 0x0, 0x63, 0x60, 0x64, 0x62,
+				     0xc0, 0x8d, 0x0};
+    std::unique_ptr<SeekableInputStream> result =
+      createDecompressor(CompressionKind_ZLIB,
+                         std::unique_ptr<SeekableInputStream>
+                         (new SeekableArrayInputStream
+                          (buffer, ARRAY_SIZE(buffer))), 1000,
+			 *getDefaultPool());
+    const void *ptr;
+    int length;
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(30, length);
+    for(int i=0; i < 10; ++i) {
+      for(int j=0; j < 3; ++j) {
+        EXPECT_EQ(j, static_cast<const char*>(ptr)[i * 3 + j]);
+      }
+    }
+  }
+
+  TEST(Zlib, testInflateSequence) {
+    const unsigned char buffer[] = {0xe, 0x0, 0x0, 0x63, 0x60,
+				    0x64, 0x62, 0xc0, 0x8d, 0x0,
+				    0xe, 0x0, 0x0, 0x63, 0x60,
+				    0x64, 0x62, 0xc0, 0x8d, 0x0};
+    std::unique_ptr<SeekableInputStream> result =
+      createDecompressor(CompressionKind_ZLIB,
+                         std::unique_ptr<SeekableInputStream>
+                         (new SeekableArrayInputStream
+                          (buffer, ARRAY_SIZE(buffer), 3)),
+                         1000,
+                         *getDefaultPool());
+    const void *ptr;
+    int length;
+    ASSERT_THROW(result->BackUp(20), std::logic_error);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(30, length);
+    for(int i=0; i < 10; ++i) {
+      for(int j=0; j < 3; ++j) {
+        EXPECT_EQ(j, static_cast<const char*>(ptr)[i * 3 + j]);
+      }
+    }
+    result->BackUp(10);
+    ASSERT_THROW(result->BackUp(2), std::logic_error);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(10, length);
+    for(int i=0; i < 10; ++i) {
+      EXPECT_EQ((i + 2) % 3, static_cast<const char*>(ptr)[i]);
+    }
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(30, length);
+    for(int i=0; i < 10; ++i) {
+      for(int j=0; j < 3; ++j) {
+        EXPECT_EQ(j, static_cast<const char*>(ptr)[i * 3 + j]);
+      }
+    }
+  }
+
+  TEST(Zlib, testSkip) {
+    const unsigned char buffer[] = {0x19, 0x0, 0x0, 0x0, 0x1,
+				    0x2, 0x3, 0x4, 0x5, 0x6,
+				    0x7, 0x8, 0x9, 0xa, 0xb,
+				    0xb, 0x0, 0x0, 0xc, 0xd,
+				    0xe, 0xf, 0x10};
+    std::unique_ptr<SeekableInputStream> result =
+      createDecompressor(CompressionKind_ZLIB,
+                         std::unique_ptr<SeekableInputStream>
+                         (new SeekableArrayInputStream
+                          (buffer, ARRAY_SIZE(buffer), 5)),
+                         5, *getDefaultPool());
+    const void *ptr;
+    int length;
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(2, length);
+    result->Skip(2);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(3, length);
+    EXPECT_EQ(4, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(5, static_cast<const char*>(ptr)[1]);
+    EXPECT_EQ(6, static_cast<const char*>(ptr)[2]);
+    result->BackUp(2);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(2, length);
+    EXPECT_EQ(5, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(6, static_cast<const char*>(ptr)[1]);
+    result->Skip(8);
+    ASSERT_EQ(true, result->Next(&ptr, &length));
+    ASSERT_EQ(2, length);
+    EXPECT_EQ(15, static_cast<const char*>(ptr)[0]);
+    EXPECT_EQ(16, static_cast<const char*>(ptr)[1]);
+  }
+
+#define HEADER_SIZE 3
+
+  class CompressBuffer {
+      std::vector<char> buf;
+
+  public:
+    CompressBuffer(size_t capacity) :
+      buf(capacity + HEADER_SIZE)
+    {}
+
+    char *getCompressed() {
+      return buf.data() + HEADER_SIZE;
+    }
+    char *getBuffer() {
+      return buf.data();
+    }
+
+    void writeHeader(size_t compressedSize) {
+      buf[0] = static_cast<char>(compressedSize << 1);
+      buf[1] = static_cast<char>(compressedSize >> 7);
+      buf[2] = static_cast<char>(compressedSize >> 15);
+    }
+
+    size_t getCompressedSize() const {
+      size_t header = static_cast<unsigned char>(buf[0]);
+      header |= static_cast<size_t>(static_cast<unsigned char>(buf[1])) << 8;
+      header |= static_cast<size_t>(static_cast<unsigned char>(buf[2])) << 16;
+      return header >> 1;
+    }
+
+    size_t getBufferSize() const {
+      return getCompressedSize() + HEADER_SIZE;
+    }
+  };
+
+  TEST(Snappy, testBasic) {
+    const int N = 1024;
+    std::vector<char> buf(N * sizeof(int));
+    for (int i=0; i < N; ++i) {
+      (reinterpret_cast<int *>(buf.data()))[i] = i % 8;
+    }
+
+    CompressBuffer compressBuffer(snappy::MaxCompressedLength(buf.size()));
+    size_t compressedSize;
+    snappy::RawCompress(buf.data(), buf.size(), compressBuffer.getCompressed(),
+                        &compressedSize);
+    // compressed size must be < original
+    ASSERT_LT(compressedSize, buf.size());
+    compressBuffer.writeHeader(compressedSize);
+
+    const long blockSize = 3;
+    std::unique_ptr<SeekableInputStream> result = createDecompressor
+        (CompressionKind_SNAPPY,
+         std::unique_ptr<SeekableInputStream>
+           (new SeekableArrayInputStream(compressBuffer.getBuffer(),
+                                         compressBuffer.getBufferSize(),
+                                         blockSize)),
+         buf.size(),
+         *getDefaultPool());
+    const void *data;
+    int length;
+    ASSERT_TRUE(result->Next(&data, &length));
+    ASSERT_EQ(N * sizeof(int), length);
+    for (int i=0; i < N; ++i) {
+      EXPECT_EQ(i % 8, (reinterpret_cast<const int *>(data))[i]);
+    }
+  }
+
+  TEST(Snappy, testMultiBuffer) {
+    const int N = 1024;
+    std::vector<char> buf(N * sizeof(int));
+    for (int i=0; i < N; ++i) {
+      (reinterpret_cast<int *>(buf.data()))[i] = i % 8;
+    }
+
+    CompressBuffer compressBuffer(snappy::MaxCompressedLength(buf.size()));
+    size_t compressedSize;
+    snappy::RawCompress(buf.data(), buf.size(), compressBuffer.getCompressed(),
+                        &compressedSize);
+    // compressed size must be < original
+    ASSERT_LT(compressedSize, buf.size());
+    compressBuffer.writeHeader(compressedSize);
+
+    std::vector<char> input(compressBuffer.getBufferSize() * 4);
+    ::memcpy(input.data(), compressBuffer.getBuffer(),
+             compressBuffer.getBufferSize());
+    ::memcpy(input.data() + compressBuffer.getBufferSize(),
+             compressBuffer.getBuffer(), compressBuffer.getBufferSize());
+    ::memcpy(input.data() + 2 * compressBuffer.getBufferSize(),
+             compressBuffer.getBuffer(), compressBuffer.getBufferSize());
+    ::memcpy(input.data() + 3 * compressBuffer.getBufferSize(),
+             compressBuffer.getBuffer(), compressBuffer.getBufferSize());
+
+    const long blockSize = 3;
+    std::unique_ptr<SeekableInputStream> result = createDecompressor
+        (CompressionKind_SNAPPY,
+         std::unique_ptr<SeekableInputStream>
+         (new SeekableArrayInputStream(input.data(), input.size(), blockSize)),
+         buf.size(),
+         *getDefaultPool());
+    for (int i=0; i < 4; ++i) {
+      const void *data;
+      int length;
+      ASSERT_TRUE(result->Next(&data, &length));
+      for (int j=0; j < N; ++j) {
+          EXPECT_EQ(j % 8, (reinterpret_cast<const int *>(data))[j]);
+      }
+    }
+  }
+
+  TEST(Snappy, testSkip) {
+    const int N = 1024;
+    std::vector<char> buf(N * sizeof(int));
+    for (int i=0; i < N; ++i) {
+      (reinterpret_cast<int *>(buf.data()))[i] = i % 8;
+    }
+
+    CompressBuffer compressBuffer(snappy::MaxCompressedLength(buf.size()));
+    size_t compressedSize;
+    snappy::RawCompress(buf.data(), buf.size(), compressBuffer.getCompressed(),
+                        &compressedSize);
+    // compressed size must be < original
+    ASSERT_LT(compressedSize, buf.size());
+    compressBuffer.writeHeader(compressedSize);
+
+    const long blockSize = 3;
+    std::unique_ptr<SeekableInputStream> result = createDecompressor
+        (CompressionKind_SNAPPY,
+         std::unique_ptr<SeekableInputStream>
+           (new SeekableArrayInputStream(compressBuffer.getBuffer(),
+                                         compressBuffer.getBufferSize(),
+                                         blockSize)),
+         buf.size(),
+         *getDefaultPool());
+    const void *data;
+    int length;
+    // skip 1/2; in 2 jumps
+    ASSERT_TRUE(result->Skip(static_cast<int>(((N / 2) - 2) * sizeof(int))));
+    ASSERT_TRUE(result->Skip(static_cast<int>(2 * sizeof(int))));
+    ASSERT_TRUE(result->Next(&data, &length));
+    ASSERT_EQ((N / 2) * sizeof(int), length);
+    for (int i=N/2; i < N; ++i) {
+      EXPECT_EQ(i % 8, (reinterpret_cast<const int *>(data))[i - N/2]);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/orc/blob/7f55b453/c++/test/TestDriver.cc
----------------------------------------------------------------------
diff --git a/c++/test/TestDriver.cc b/c++/test/TestDriver.cc
new file mode 100644
index 0000000..a34ff07
--- /dev/null
+++ b/c++/test/TestDriver.cc
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "orc/orc-config.hh"
+
+#include "wrap/orc-proto-wrapper.hh"
+#include "wrap/gtest-wrapper.h"
+
+#include <iostream>
+
+GTEST_API_ int main(int argc, char **argv) {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+  std::cout << "ORC version: " << ORC_VERSION << "\n";
+  testing::InitGoogleTest(&argc, argv);
+  int result = RUN_ALL_TESTS();
+  return result;
+}

http://git-wip-us.apache.org/repos/asf/orc/blob/7f55b453/c++/test/TestInt128.cc
----------------------------------------------------------------------
diff --git a/c++/test/TestInt128.cc b/c++/test/TestInt128.cc
new file mode 100644
index 0000000..cc3b30f
--- /dev/null
+++ b/c++/test/TestInt128.cc
@@ -0,0 +1,587 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "orc/Int128.hh"
+
+#include "wrap/gtest-wrapper.h"
+#include "OrcTest.hh"
+
+#include <iostream>
+
+namespace orc {
+
+  TEST(Int128, simpleTest) {
+    Int128 x = 12;
+    Int128 y = 13;
+    x += y;
+    EXPECT_EQ(25, x.toLong());
+    EXPECT_EQ("0x00000000000000000000000000000019", x.toHexString());
+    y -= 1;
+    EXPECT_EQ("0x0000000000000000000000000000000c", y.toHexString());
+    EXPECT_EQ(12, y.toLong());
+    EXPECT_EQ(0, y.getHighBits());
+    EXPECT_EQ(12, y.getLowBits());
+    y -= 20;
+    EXPECT_EQ("0xfffffffffffffffffffffffffffffff8", y.toHexString());
+    EXPECT_EQ(-8, y.toLong());
+    EXPECT_EQ(-1, y.getHighBits());
+    EXPECT_EQ(static_cast<uint64_t>(-8), y.getLowBits());
+    Int128 z;
+    EXPECT_EQ(0, z.toLong());
+  }
+
+  TEST(Int128, testNegate) {
+    Int128 n = -1000000000000;
+    EXPECT_EQ("0xffffffffffffffffffffff172b5af000", n.toHexString());
+    n.negate();
+    EXPECT_EQ(1000000000000, n.toLong());
+    n.abs();
+    EXPECT_EQ(1000000000000, n.toLong());
+    n.negate();
+    EXPECT_EQ(-1000000000000, n.toLong());
+    n.abs();
+    EXPECT_EQ(1000000000000, n.toLong());
+
+    Int128 big(0x12345678, 0x9abcdef0);
+    EXPECT_EQ("0x0000000012345678000000009abcdef0", big.toHexString());
+    EXPECT_EQ(305419896, big.getHighBits());
+    EXPECT_EQ(2596069104, big.getLowBits());
+    big.negate();
+    EXPECT_EQ("0xffffffffedcba987ffffffff65432110", big.toHexString());
+    EXPECT_EQ(0xffffffffedcba987, big.getHighBits());
+    EXPECT_EQ(0xffffffff65432110, big.getLowBits());
+    big.negate();
+    EXPECT_EQ("0x0000000012345678000000009abcdef0", big.toHexString());
+    big.invert();
+    EXPECT_EQ("0xffffffffedcba987ffffffff6543210f", big.toHexString());
+    big.invert();
+    EXPECT_EQ("0x0000000012345678000000009abcdef0", big.toHexString());
+  }
+
+  TEST(Int128, testPlus) {
+    Int128 n(0x1000, 0xfffffffffffffff0);
+    EXPECT_EQ("0x0000000000001000fffffffffffffff0", n.toHexString());
+    n += 0x20;
+    EXPECT_EQ("0x00000000000010010000000000000010", n.toHexString());
+    n -= 0x20;
+    EXPECT_EQ("0x0000000000001000fffffffffffffff0", n.toHexString());
+    n += Int128(2,3);
+    EXPECT_EQ("0x0000000000001002fffffffffffffff3", n.toHexString());
+
+    Int128 x(static_cast<int64_t>(0xffffffffffffff00), 0x200);
+    EXPECT_EQ("0xffffffffffffff000000000000000200", x.toHexString());
+    x -= 0x300;
+    EXPECT_EQ("0xfffffffffffffeffffffffffffffff00", x.toHexString());
+    x -= 0x100;
+    EXPECT_EQ("0xfffffffffffffefffffffffffffffe00", x.toHexString());
+    x += 0x400;
+    EXPECT_EQ("0xffffffffffffff000000000000000200", x.toHexString());
+    x -= Int128(1,2);
+    EXPECT_EQ("0xfffffffffffffeff00000000000001fe", x.toHexString());
+  }
+
+  TEST(Int128, testLogic) {
+    Int128 n = Int128(0x00000000100000002, 0x0000000400000008);
+    n |= Int128(0x0000001000000020, 0x0000004000000080);
+    EXPECT_EQ("0x00000011000000220000004400000088", n.toHexString());
+    n =  Int128(0x0000111100002222, 0x0000333300004444);
+    n &= Int128(0x0000f00000000f00, 0x000000f00000000f);
+    EXPECT_EQ( "0x00001000000002000000003000000004", n.toHexString());
+  }
+
+  TEST(Int128, testShift) {
+    Int128 n(0x123456789abcdef0,0xfedcba9876543210);
+    EXPECT_EQ("0x123456789abcdef0fedcba9876543210", n.toHexString());
+    n <<= 0;
+    EXPECT_EQ("0x123456789abcdef0fedcba9876543210", n.toHexString());
+    n <<= 4;
+    EXPECT_EQ("0x23456789abcdef0fedcba98765432100", n.toHexString());
+    n <<= 8;
+    EXPECT_EQ("0x456789abcdef0fedcba9876543210000", n.toHexString());
+    n += 0x99;
+    EXPECT_EQ("0x456789abcdef0fedcba9876543210099", n.toHexString());
+    n <<= 64;
+    EXPECT_EQ("0xcba98765432100990000000000000000", n.toHexString());
+    n += 0x312;
+    EXPECT_EQ("0xcba98765432100990000000000000312", n.toHexString());
+    n <<= 120;
+    EXPECT_EQ("0x12000000000000000000000000000000", n.toHexString());
+    n += 0x411;
+    EXPECT_EQ("0x12000000000000000000000000000411", n.toHexString());
+    n <<= 128;
+    EXPECT_EQ(0, n.toLong());
+
+    n = Int128(0x123456789abcdef0,0xfedcba9876543210);
+    EXPECT_EQ("0x123456789abcdef0fedcba9876543210", n.toHexString());
+    n >>= 0;
+    EXPECT_EQ("0x123456789abcdef0fedcba9876543210", n.toHexString());
+    n >>= 4;
+    EXPECT_EQ("0x0123456789abcdef0fedcba987654321", n.toHexString());
+    n >>= 8;
+    EXPECT_EQ("0x000123456789abcdef0fedcba9876543", n.toHexString());
+    n += Int128(0x2400000000000000, 0x0);
+    EXPECT_EQ("0x240123456789abcdef0fedcba9876543", n.toHexString());
+    n >>= 64;
+    EXPECT_EQ("0x0000000000000000240123456789abcd", n.toHexString());
+    n += Int128(0x2400000000000000, 0x0);
+    EXPECT_EQ("0x2400000000000000240123456789abcd", n.toHexString());
+    n >>= 129;
+    EXPECT_EQ(0, n.toLong());
+    n = Int128(static_cast<int64_t>(0xfedcba0987654321),0x1234567890abcdef);
+    EXPECT_EQ("0xfedcba09876543211234567890abcdef", n.toHexString());
+    n >>= 64;
+    EXPECT_EQ("0xfffffffffffffffffedcba0987654321", n.toHexString());
+    n = Int128(static_cast<int64_t>(0xfedcba0987654321),0x1234567890abcdef);
+    n >>= 129;
+    EXPECT_EQ("0xffffffffffffffffffffffffffffffff", n.toHexString());
+    n = Int128(-1, 0xffffffffffffffff);
+    n >>= 4;
+    EXPECT_EQ("0x0fffffffffffffffffffffffffffffff", n.toHexString());
+    n = Int128(-0x100, 0xffffffffffffffff);
+    n >>= 68;
+    EXPECT_EQ("0xfffffffffffffffffffffffffffffff0", n.toHexString());
+  }
+
+  TEST(Int128, testCompare) {
+    Int128 x = 123;
+    EXPECT_EQ(Int128(123), x);
+    EXPECT_EQ(true, x == 123);
+    EXPECT_EQ(true, !(x == 124));
+    EXPECT_EQ(true, !(x == -124));
+    EXPECT_EQ(true, !(x == Int128(2, 123)));
+    EXPECT_EQ(true, !(x != 123));
+    EXPECT_EQ(true, x != -123);
+    EXPECT_EQ(true, x != 124);
+    EXPECT_EQ(true, x != Int128(-1, 123));
+    x = Int128(0x123, 0x456);
+    EXPECT_EQ(true, !(x < Int128(0x123, 0x455)));
+    EXPECT_EQ(true, !(x < Int128(0x123, 0x456)));
+    EXPECT_EQ(true, x < Int128(0x123, 0x457));
+    EXPECT_EQ(true, !(x < Int128(0x122, 0x456)));
+    EXPECT_EQ(true, x < Int128(0x124, 0x456));
+
+    EXPECT_EQ(true, !(x <= Int128(0x123, 0x455)));
+    EXPECT_EQ(true, x <= Int128(0x123, 0x456));
+    EXPECT_EQ(true, x <= Int128(0x123, 0x457));
+    EXPECT_EQ(true, !(x <= Int128(0x122, 0x456)));
+    EXPECT_EQ(true, x <= Int128(0x124, 0x456));
+
+    EXPECT_EQ(true, x > Int128(0x123, 0x455));
+    EXPECT_EQ(true, !(x > Int128(0x123, 0x456)));
+    EXPECT_EQ(true, !(x > Int128(0x123, 0x457)));
+    EXPECT_EQ(true, x > Int128(0x122, 0x456));
+    EXPECT_EQ(true, !(x > Int128(0x124, 0x456)));
+
+    EXPECT_EQ(true, x >= Int128(0x123, 0x455));
+    EXPECT_EQ(true, x >= Int128(0x123, 0x456));
+    EXPECT_EQ(true, !(x >= Int128(0x123, 0x457)));
+    EXPECT_EQ(true, x >= Int128(0x122, 0x456));
+    EXPECT_EQ(true, !(x >= Int128(0x124, 0x456)));
+
+    EXPECT_EQ(true, Int128(-3) < Int128(-2));
+    EXPECT_EQ(true, Int128(-3) < Int128(0));
+    EXPECT_EQ(true, Int128(-3) < Int128(3));
+    EXPECT_EQ(true, Int128(0) < Int128(5));
+    EXPECT_EQ(true, Int128::minimumValue() < 0);
+    EXPECT_EQ(true, Int128(0) < Int128::maximumValue());
+    EXPECT_EQ(true, Int128::minimumValue() < Int128::maximumValue());
+  }
+
+  TEST(Int128, testHash) {
+    EXPECT_EQ(0, Int128().hash());
+    EXPECT_EQ(0x123, Int128(0x123).hash());
+    EXPECT_EQ(0xc3c3c3c3,
+              Int128(0x0101010102020202, 0x4040404080808080).hash());
+    EXPECT_EQ(0x122, Int128(-0x123).hash());
+    EXPECT_EQ(0x12345678, Int128(0x1234567800000000, 0x0).hash());
+    EXPECT_EQ(0x12345678, Int128(0x12345678, 0x0).hash());
+    EXPECT_EQ(0x12345678, Int128(0x0, 0x1234567800000000).hash());
+    EXPECT_EQ(0x12345678, Int128(0x0, 0x12345678).hash());
+  }
+
+  TEST(Int128, testFitsInLong) {
+    EXPECT_EQ(true, Int128(0x0, 0x7fffffffffffffff).fitsInLong());
+    EXPECT_EQ(true, !Int128(0x0, 0x8000000000000000).fitsInLong());
+    EXPECT_EQ(true, !Int128(-1, 0x7fffffffffffffff).fitsInLong());
+    EXPECT_EQ(true, Int128(-1, 0x8000000000000000).fitsInLong());
+    EXPECT_EQ(true, !Int128(1, 0x8000000000000000).fitsInLong());
+    EXPECT_EQ(true, !Int128(1, 0x7fffffffffffffff).fitsInLong());
+    EXPECT_EQ(true, !Int128(-2, 0x8000000000000000).fitsInLong());
+    EXPECT_EQ(true, !Int128(-2, 0x7fffffffffffffff).fitsInLong());
+
+    EXPECT_EQ(0x7fffffffffffffff, Int128(0x0, 0x7fffffffffffffff).toLong());
+    EXPECT_THROW(Int128(1,1).toLong(), std::runtime_error);
+    EXPECT_EQ(0x8000000000000000, Int128(-1, 0x8000000000000000).toLong());
+  }
+
+  TEST(Int128, testMultiply) {
+    Int128 x = 2;
+    x *= 3;
+    EXPECT_EQ(6, x.toLong());
+    x *= -4;
+    EXPECT_EQ(-24, x.toLong());
+    x *= 5;
+    EXPECT_EQ(-120, x.toLong());
+    x *= -7;
+    EXPECT_EQ(840, x.toLong());
+    x = Int128(0x0123456776543210,0x1111222233334444);
+    x *= 2;
+    EXPECT_EQ(0x02468aceeca86420, x.getHighBits());
+    EXPECT_EQ(0x2222444466668888, x.getLowBits());
+
+    x = Int128(0x0534AB4C, 0x59D109ADF9892FCA);
+    x *= Int128(0, 0x9033b8c7a);
+    EXPECT_EQ("0x2eead9afd0c6e0e929c18da753113e44", x.toHexString());
+  }
+
+  TEST(Int128, testMultiplyInt) {
+    Int128 x = 2;
+    x *= 1;
+    EXPECT_EQ(2, x.toLong());
+    x *= 2;
+    EXPECT_EQ(4, x.toLong());
+
+    x = 5;
+    x *= 6432346;
+    EXPECT_EQ(6432346 * 5, x.toLong());
+
+    x = (1L << 62) + (3L << 34) + 3L;
+    x *= 96;
+    EXPECT_EQ("0x00000000000000180000048000000120", x.toHexString());
+
+    x = 1;
+    x <<= 126;
+    EXPECT_EQ("0x40000000000000000000000000000000", x.toHexString());
+    x *= 2;
+    EXPECT_EQ("0x80000000000000000000000000000000", x.toHexString());
+    x *= 2;
+    EXPECT_EQ("0x00000000000000000000000000000000", x.toHexString());
+  }
+
+  TEST(Int128, testFillInArray) {
+    Int128 x(0x123456789abcdef0, 0x23456789abcdef01);
+    uint32_t array[4];
+    bool wasNegative;
+    EXPECT_EQ(4, x.fillInArray(array, wasNegative));
+    EXPECT_EQ(true, !wasNegative);
+    EXPECT_EQ(0x12345678, array[0]);
+    EXPECT_EQ(0x9abcdef0, array[1]);
+    EXPECT_EQ(0x23456789, array[2]);
+    EXPECT_EQ(0xabcdef01, array[3]);
+
+    x = 0;
+    EXPECT_EQ(0, x.fillInArray(array, wasNegative));
+    EXPECT_EQ(true, !wasNegative);
+
+    x = 1;
+    EXPECT_EQ(1, x.fillInArray(array, wasNegative));
+    EXPECT_EQ(true, !wasNegative);
+    EXPECT_EQ(1, array[0]);
+
+    x = -12345;
+    EXPECT_EQ(1, x.fillInArray(array, wasNegative));
+    EXPECT_EQ(true, wasNegative);
+    EXPECT_EQ(12345, array[0]);
+
+    x = 0x80000000;
+    EXPECT_EQ(1, x.fillInArray(array, wasNegative));
+    EXPECT_EQ(true, !wasNegative);
+    EXPECT_EQ(0x80000000, array[0]);
+
+    x = Int128(0, 0x8000000000000000);
+    EXPECT_EQ(2, x.fillInArray(array, wasNegative));
+    EXPECT_EQ(true, !wasNegative);
+    EXPECT_EQ(0x80000000, array[0]);
+    EXPECT_EQ(0x0, array[1]);
+
+    x = Int128(0x80000000, 0x123456789abcdef0);
+    EXPECT_EQ(3, x.fillInArray(array, wasNegative));
+    EXPECT_EQ(true, !wasNegative);
+    EXPECT_EQ(0x80000000, array[0]);
+    EXPECT_EQ(0x12345678, array[1]);
+    EXPECT_EQ(0x9abcdef0, array[2]);
+  }
+
+  int fls(uint32_t x);
+
+  TEST(Int128, testFindLastSet) {
+    EXPECT_EQ(0, fls(0));
+    EXPECT_EQ(1, fls(1));
+    EXPECT_EQ(8, fls(0xff));
+    EXPECT_EQ(9, fls(0x100));
+    EXPECT_EQ(29, fls(0x12345678));
+    EXPECT_EQ(31, fls(0x40000000));
+    EXPECT_EQ(32, fls(0x80000000));
+  }
+
+  void shiftArrayLeft(uint32_t* array, int64_t length, int64_t bits);
+
+  TEST(Int128, testShiftArrayLeft) {
+    uint32_t array[5];
+    // make sure nothing blows up
+    array[0] = 0x12345678;
+    shiftArrayLeft(0, 0, 30);
+    EXPECT_EQ(0x12345678, array[0]);
+
+    array[0] = 0x12345678;
+    shiftArrayLeft(array, 1, 0);
+    EXPECT_EQ(0x12345678, array[0]);
+
+    array[0] = 0x12345678;
+    array[1] = 0x9abcdef0;
+    shiftArrayLeft(array, 1, 3);
+    EXPECT_EQ(0x91a2b3c0, array[0]);
+    EXPECT_EQ(0x9abcdef0, array[1]);
+
+    array[0] = 0x12345678;
+    array[1] = 0x9abcdeff;
+    array[2] = 0xfedcba98;
+    array[3] = 0x76543210;
+    shiftArrayLeft(array, 4, 4);
+    EXPECT_EQ(0x23456789, array[0]);
+    EXPECT_EQ(0xabcdefff, array[1]);
+    EXPECT_EQ(0xedcba987, array[2]);
+    EXPECT_EQ(0x65432100, array[3]);
+
+    array[0] = 0;
+    array[1] = 0x12345678;
+    array[2] = 0x9abcdeff;
+    array[3] = 0xfedcba98;
+    array[4] = 0x76543210;
+    shiftArrayLeft(array, 5, 8);
+    EXPECT_EQ(0x00000012, array[0]);
+    EXPECT_EQ(0x3456789a, array[1]);
+    EXPECT_EQ(0xbcdefffe, array[2]);
+    EXPECT_EQ(0xdcba9876, array[3]);
+    EXPECT_EQ(0x54321000, array[4]);
+  }
+
+  void shiftArrayRight(uint32_t* array, int64_t length, int64_t bits);
+
+  TEST(Int128, testShiftArrayRight) {
+    uint32_t array[4];
+    // make sure nothing blows up
+    array[0] = 0x12345678;
+    shiftArrayRight(0, 0, 30);
+    EXPECT_EQ(0x12345678, array[0]);
+
+    array[0] = 0x12345678;
+    array[1] = 0x9abcdef0;
+    shiftArrayRight(array, 1, 3);
+    EXPECT_EQ(0x2468acf, array[0]);
+    EXPECT_EQ(0x9abcdef0, array[1]);
+
+    array[0] = 0x12345678;
+    array[1] = 0x9abcdeff;
+    array[2] = 0xfedcba98;
+    array[3] = 0x76543210;
+    shiftArrayRight(array, 4, 4);
+    EXPECT_EQ(0x01234567, array[0]);
+    EXPECT_EQ(0x89abcdef, array[1]);
+    EXPECT_EQ(0xffedcba9, array[2]);
+    EXPECT_EQ(0x87654321, array[3]);
+  }
+
+  void fixDivisionSigns(Int128 &result, Int128 &remainder,
+                        bool dividendWasNegative, bool divisorWasNegative);
+
+  TEST(Int128, testFixDivisionSigns) {
+    Int128 x = 123;
+    Int128 y = 456;
+    fixDivisionSigns(x, y, false, false);
+    EXPECT_EQ(123, x.toLong());
+    EXPECT_EQ(456, y.toLong());
+
+    x = 123;
+    y = 456;
+    fixDivisionSigns(x, y, false, true);
+    EXPECT_EQ(-123, x.toLong());
+    EXPECT_EQ(456, y.toLong());
+
+    x = 123;
+    y = 456;
+    fixDivisionSigns(x, y, true, false);
+    EXPECT_EQ(-123, x.toLong());
+    EXPECT_EQ(-456, y.toLong());
+
+    x = 123;
+    y = 456;
+    fixDivisionSigns(x, y, true, true);
+    EXPECT_EQ(123, x.toLong());
+    EXPECT_EQ(-456, y.toLong());
+
+  }
+
+  void buildFromArray(Int128& value, uint32_t* array, int64_t length);
+
+  TEST(Int128, testBuildFromArray) {
+    Int128 result;
+    uint32_t array[4]={0x12345678, 0x9abcdef0, 0xfedcba98, 0x76543210};
+
+    buildFromArray(result, array, 0);
+    EXPECT_EQ(0, result.toLong());
+
+    buildFromArray(result, array, 1);
+    EXPECT_EQ(0x12345678, result.toLong());
+
+    buildFromArray(result, array, 2);
+    EXPECT_EQ(0x123456789abcdef0, result.toLong());
+
+    buildFromArray(result, array, 3);
+    EXPECT_EQ("0x00000000123456789abcdef0fedcba98", result.toHexString());
+
+    buildFromArray(result, array, 4);
+    EXPECT_EQ("0x123456789abcdef0fedcba9876543210", result.toHexString());
+
+    EXPECT_THROW(buildFromArray(result, array, 5), std::logic_error);
+  }
+
+  Int128 singleDivide(uint32_t* dividend, int64_t dividendLength,
+                      uint32_t divisor, Int128& remainder,
+                      bool dividendWasNegative, bool divisorWasNegative);
+
+  TEST(Int128, testSingleDivide) {
+    Int128 remainder;
+    uint32_t dividend[4];
+
+    dividend[0] = 23;
+    Int128 result = singleDivide(dividend, 1, 5, remainder, true, false);
+    EXPECT_EQ(-4, result.toLong());
+    EXPECT_EQ(-3, remainder.toLong());
+
+    dividend[0] = 0x100;
+    dividend[1] = 0x120;
+    dividend[2] = 0x140;
+    dividend[3] = 0x160;
+    result = singleDivide(dividend, 4, 0x20, remainder, false, false);
+    EXPECT_EQ("0x00000008000000090000000a0000000b", result.toHexString());
+    EXPECT_EQ(0, remainder.toLong());
+
+    dividend[0] = 0x101;
+    dividend[1] = 0x122;
+    dividend[2] = 0x143;
+    dividend[3] = 0x164;
+    result = singleDivide(dividend, 4, 0x20, remainder, false, false);
+    EXPECT_EQ("0x00000008080000091000000a1800000b", result.toHexString());
+    EXPECT_EQ(4, remainder.toLong());
+
+    dividend[0] = 0x12345678;
+    dividend[1] = 0x9abcdeff;
+    dividend[2] = 0xfedcba09;
+    dividend[3] = 0x87654321;
+    result = singleDivide(dividend, 4, 123, remainder, false, false);
+    EXPECT_EQ("0x0025e390971c97aaaaa84c7077bc23ed", result.toHexString());
+    EXPECT_EQ(0x42, remainder.toLong());
+  }
+
+  TEST(Int128, testDivide) {
+    Int128 dividend;
+    Int128 result;
+    Int128 remainder;
+
+    dividend = 0x12345678;
+    result = dividend.divide(0x123456789abcdef0, remainder);
+    EXPECT_EQ(0, result.toLong());
+    EXPECT_EQ(0x12345678, remainder.toLong());
+
+    EXPECT_THROW(dividend.divide(0, remainder), std::runtime_error);
+
+    dividend = Int128(0x123456789abcdeff, 0xfedcba0987654321);
+    result = dividend.divide(123, remainder);
+    EXPECT_EQ("0x0025e390971c97aaaaa84c7077bc23ed", result.toHexString());
+    EXPECT_EQ(0x42, remainder.toLong());
+
+    dividend = Int128(0x111111112fffffff, 0xeeeeeeeedddddddd);
+    result = dividend.divide(0x1111111123456789, remainder);
+    EXPECT_EQ("0x000000000000000100000000beeeeef7", result.toHexString());
+    EXPECT_EQ("0x0000000000000000037d3b3d60479aae", remainder.toHexString());
+
+    dividend = 1234234662345;
+    result = dividend.divide(642337, remainder);
+    EXPECT_EQ(1921475, result.toLong());
+    EXPECT_EQ(175270, remainder.toLong());
+
+    dividend = Int128(0x42395ADC0534AB4C, 0x59D109ADF9892FCA);
+    result = dividend.divide(0x1234F09DC19A, remainder);
+    EXPECT_EQ("0x000000000003a327c1348bccd2f06c27", result.toHexString());
+    EXPECT_EQ("0x000000000000000000000cacef73b954", remainder.toHexString());
+
+    dividend = Int128(0xfffffffffffffff, 0xf000000000000000);
+    result = dividend.divide(Int128(0, 0x1000000000000000), remainder);
+    EXPECT_EQ("0x0000000000000000ffffffffffffffff", result.toHexString());
+    EXPECT_EQ(0, remainder.toLong());
+
+    dividend = Int128(0x4000000000000000, 0);
+    result = dividend.divide(Int128(0, 0x400000007fffffff), remainder);
+    EXPECT_EQ("0x0000000000000000fffffffe00000007", result.toHexString());
+    EXPECT_EQ("0x00000000000000003ffffffa80000007", remainder.toHexString());
+  }
+
+  TEST(Int128, testToString) {
+    Int128 num = Int128(0x123456789abcdef0, 0xfedcba0987654321);
+    EXPECT_EQ("24197857203266734881846307133640229665", num.toString());
+
+    num = Int128(0, 0xab54a98ceb1f0ad2);
+    EXPECT_EQ("12345678901234567890", num.toString());
+
+    num = 12345678;
+    EXPECT_EQ("12345678", num.toString());
+
+    num = -1234;
+    EXPECT_EQ("-1234", num.toString());
+
+    num = Int128(0x13f20d9c2, 0xfff89d38e1c70cb1);
+    EXPECT_EQ("98765432109876543210987654321", num.toString());
+    num.negate();
+    EXPECT_EQ("-98765432109876543210987654321", num.toString());
+
+    num = Int128("10000000000000000000000000000000000000");
+    EXPECT_EQ("10000000000000000000000000000000000000", num.toString());
+
+    num = Int128("-1234");
+    EXPECT_EQ("-1234", num.toString());
+
+    num = Int128("-12345678901122334455667788990011122233");
+    EXPECT_EQ("-12345678901122334455667788990011122233", num.toString());
+  }
+
+  TEST(Int128, testToDecimalString) {
+    Int128 num = Int128("98765432109876543210987654321098765432");
+    EXPECT_EQ("98765432109876543210987654321098765432",
+              num.toDecimalString(0));
+    EXPECT_EQ("987654321098765432109876543210987.65432",
+              num.toDecimalString(5));
+    num.negate();
+    EXPECT_EQ("-98765432109876543210987654321098765432",
+              num.toDecimalString(0));
+    EXPECT_EQ("-987654321098765432109876543210987.65432",
+              num.toDecimalString(5));
+    num = 123;
+    EXPECT_EQ("12.3", num.toDecimalString(1));
+    EXPECT_EQ("0.123", num.toDecimalString(3));
+    EXPECT_EQ("0.0123", num.toDecimalString(4));
+    EXPECT_EQ("0.00123", num.toDecimalString(5));
+
+    num = -123;
+    EXPECT_EQ("-123", num.toDecimalString(0));
+    EXPECT_EQ("-12.3", num.toDecimalString(1));
+    EXPECT_EQ("-0.123", num.toDecimalString(3));
+    EXPECT_EQ("-0.0123", num.toDecimalString(4));
+    EXPECT_EQ("-0.00123", num.toDecimalString(5));
+  }
+}  // namespace orc