diff --git a/Data/Bson.hs b/Data/Bson.hs
--- a/Data/Bson.hs
+++ b/Data/Bson.hs
@@ -2,7 +2,7 @@
 
 Use the GHC language extension /OverloadedStrings/ to automatically convert String literals to UString (UTF8) -}
 
-{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, FlexibleInstances, DeriveDataTypeable, RankNTypes, OverlappingInstances, IncoherentInstances, ScopedTypeVariables, ForeignFunctionInterface, BangPatterns #-}
+{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, FlexibleInstances, DeriveDataTypeable, RankNTypes, OverlappingInstances, IncoherentInstances, ScopedTypeVariables, ForeignFunctionInterface, BangPatterns, CPP #-}
 
 module Data.Bson (
 	-- * UTF-8 String
@@ -19,6 +19,10 @@
 	Regex(..), Javascript(..), Symbol(..), MongoStamp(..), MinMaxKey(..),
 	-- ** ObjectId
 	ObjectId(..), timestamp, genObjectId
+#ifdef TEST
+    , composite
+    , roundTo
+#endif
 ) where
 
 import Prelude hiding (lookup)
@@ -58,8 +62,9 @@
 
 showHexLen :: (Integral n) => Int -> n -> ShowS
 -- ^ showHex of n padded with leading zeros if necessary to fill d digits
-showHexLen d n = showString (replicate (d - sigDigits) '0') . showHex n
-	where sigDigits = ceiling $ logBase 16 $ fromIntegral n
+showHexLen d n = showString (replicate (d - sigDigits n) '0') . showHex n  where
+	sigDigits 0 = 1
+	sigDigits n' = truncate (logBase 16 $ fromIntegral n') + 1
 
 -- * Document
 
@@ -424,8 +429,9 @@
  	{-# NOINLINE counter #-}
  	nextCount :: IO Word24
  	nextCount = atomicModifyIORef counter $ \n -> (wrap24 (n + 1), n)
- 	composite :: Word24 -> Word16 -> Word24 -> Word64
- 	composite mid pid inc = fromIntegral mid `shift` 40 .|. fromIntegral pid `shift` 24 .|. fromIntegral inc
+
+composite :: Word24 -> Word16 -> Word24 -> Word64
+composite mid pid inc = fromIntegral mid `shift` 40 .|. fromIntegral pid `shift` 24 .|. fromIntegral inc
 
 type Word24 = Word32
 -- ^ low 3 bytes only, high byte must be zero
diff --git a/bson.cabal b/bson.cabal
--- a/bson.cabal
+++ b/bson.cabal
@@ -1,16 +1,56 @@
 Name: bson
-Version: 0.1.5
+Version: 0.1.6
 Synopsis: BSON documents are JSON-like objects with a standard binary encoding
 Description: A BSON Document is an untyped (dynamically type-checked) record. I.e. it is a list of name-value pairs, where a Value is a single sum type with constructors for basic types (Bool, Int, Float, String, and Time), compound types (List, and (embedded) Document), and special types (Binary, Javascript, ObjectId, RegEx, and a few others).
 	.
 	A BSON Document is serialized to a standard binary encoding defined at <http://bsonspec.org>. This implements version 1 of that spec.
+
 Category: Data
 Homepage: http://github.com/TonyGen/bson-haskell
 Author: Tony Hannan
 Maintainer: Tony Hannan <tony@10gen.com>
+
 License: OtherLicense
 License-file: LICENSE
-Build-Depends: base < 5, time, bytestring, network, cryptohash, binary, data-binary-ieee754, compact-string-fix, mtl >= 2
-Build-Type: Simple
-Exposed-modules: Data.UString, Data.Bson, Data.Bson.Binary
-ghc-prof-options: -auto-all
+cabal-version: >= 1.8
+build-type: Simple
+
+Library
+    Build-Depends: base < 5,
+                   time,
+                   bytestring,
+                   network,
+                   cryptohash,
+                   binary,
+                   data-binary-ieee754,
+                   compact-string-fix,
+                   mtl >= 2
+
+    Exposed-modules: Data.UString,
+                     Data.Bson,
+                     Data.Bson.Binary
+
+    ghc-prof-options: -auto-all
+
+test-suite test
+    type:          exitcode-stdio-1.0
+    main-is:       main.hs
+    hs-source-dirs: test, .
+
+    build-depends:   HUnit
+                   , hspec >= 0.6.1 && < 0.7
+                   , file-location >= 0.4 && < 0.5
+                   , base >= 4 && < 5
+                   , bson
+                   , QuickCheck == 2.4.*
+
+                   , mtl >= 2
+                   , network
+                   , cryptohash
+                   , bytestring
+                   , time
+                   , data-binary-ieee754
+                   , compact-string-fix
+                   , file-location
+
+    cpp-options:   -DTEST
diff --git a/test/main.hs b/test/main.hs
new file mode 100644
--- /dev/null
+++ b/test/main.hs
@@ -0,0 +1,29 @@
+-- import Test.HUnit hiding (Test)
+import Test.Hspec.Monadic (Specs, describe, it, hspecX)
+import Test.Hspec.HUnit()
+import Test.Hspec.QuickCheck(prop)
+import Test.QuickCheck
+import Data.Bson
+import FileLocation (debug)
+
+main :: IO ()
+main = hspecX specs
+
+instance Arbitrary ObjectId where
+  arbitrary = do
+      t <- arbitrary
+      p <- arbitrary
+      m <- arbitrary
+      i <- arbitrary
+      return $ Oid t $ composite m p i
+
+specs :: Specs
+specs = do
+  describe "ObjectId" $ do
+    prop "read <-> show" $ \objId ->
+      (debug . read . show . debug) objId == (objId :: ObjectId)
+
+  describe "roundTo" $ do
+    prop "round" $ \d ->
+      let r =  roundTo (1 / 10) (d :: Double)
+      in  r == roundTo (1 / 10) r
