diff --git a/Properties.hs b/Properties.hs
--- a/Properties.hs
+++ b/Properties.hs
@@ -4,13 +4,13 @@
 import qualified Data.RingBuffer as R
 import qualified Data.Vector as V
 
-testAppend :: (Eq a)
+testAppend :: (Eq a, Show a)
            => Positive Int -> [a] -> Property
 testAppend (Positive cap) xs = monadicIO $ do
     r <- liftIO $ R.new cap :: PropertyM IO (R.RingBuffer V.Vector a)
     liftIO $ mapM_ (`R.append` r) (reverse xs)
     xs' <- liftIO $ R.toList r
-    return $ xs' == take cap xs
+    return $ counterexample (show xs') $ xs' == take cap xs
 
 main :: IO ()
 main = quickCheck (testAppend :: Positive Int -> [Int] -> Property)
diff --git a/Test.hs b/Test.hs
new file mode 100644
--- /dev/null
+++ b/Test.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE FlexibleContexts #-}
+
+import Data.List
+import qualified Data.Vector as V
+import qualified Data.Vector.Generic as VG
+import Data.RingBuffer as RB
+import Test.HUnit
+
+main :: IO ()
+main = do
+    runTestTT $ test [testConcat]
+    return ()
+
+testConcat :: Test
+testConcat = TestCase $ do
+    rb <- RB.new 40 :: IO (RB.RingBuffer V.Vector Int)
+    --mapM_ (flip RB.append rb) [0..44]
+    RB.concat (V.fromList [0..4]) rb
+    RB.concat (V.fromList [0..50]) rb
+
+    checkLength rb 40
+    checkItems rb [50,49..11]
+    withItems rb $ \items -> do
+        let expected = [11..50]
+        assertEqual "withItems: expected" expected (sort $ V.toList items)
+
+checkLength :: VG.Vector v a => RingBuffer v a -> Int -> Assertion
+checkLength rb expected = do
+    len <- RB.length rb
+    assertEqual ("Expected length "++show expected) expected len
+
+checkItems :: (Eq a, Show a, VG.Vector v a)
+           => RingBuffer v a -> [a] -> Assertion
+checkItems rb expected = do
+    items <- RB.toList rb
+    assertEqual ("Expected items "++show expected) expected items
diff --git a/ring-buffer.cabal b/ring-buffer.cabal
--- a/ring-buffer.cabal
+++ b/ring-buffer.cabal
@@ -1,7 +1,7 @@
 name:                ring-buffer
-version:             0.3
+version:             0.4
 synopsis:            A concurrent, mutable ring-buffer
-description:         A concurrent, mutable ring-buffer
+description:         A mutable ring-buffer implementation suitable for concurrent access.
 homepage:            http://github.com/bgamari/ring-buffer
 license:             BSD3
 license-file:        LICENSE
@@ -18,8 +18,8 @@
 
 library
   exposed-modules:     Data.RingBuffer
-  build-depends:       base >=4.7 && <4.10,
-                       vector >=0.10 && <0.12,
+  build-depends:       base >=4.7 && <4.11,
+                       vector >=0.10 && <0.13,
                        mtl >=2.2 && <2.3,
                        primitive >=0.5 && <0.7,
                        exceptions >=0.8 && <0.9
@@ -30,7 +30,16 @@
   type:                exitcode-stdio-1.0
   main-is:             Properties.hs
   default-language:    Haskell2010
-  build-depends:       base >= 4.9,
-                       QuickCheck >= 2.7,
-                       vector >= 0.11,
+  build-depends:       base,
+                       QuickCheck >= 2.7 && < 2.11,
+                       vector,
+                       ring-buffer
+
+test-suite tests
+  type:                exitcode-stdio-1.0
+  main-is:             Test.hs
+  default-language:    Haskell2010
+  build-depends:       base,
+                       HUnit,
+                       vector,
                        ring-buffer
diff --git a/src/Data/RingBuffer.hs b/src/Data/RingBuffer.hs
--- a/src/Data/RingBuffer.hs
+++ b/src/Data/RingBuffer.hs
@@ -29,7 +29,9 @@
                  , ringState  :: MVar RingState
                  }
 
-data RingState = RingState { ringFull :: !Bool, ringHead :: !Int }
+data RingState = RingState { ringFull :: !Bool -- ^ is the ring full?
+                           , ringHead :: !Int -- ^ index of next entry to be written
+                           }
 
 -- | We use the @Mutable@ vector type to ensure injectiveness
 type RingM m vm a = StateT RingState (ReaderT (vm (PrimState IO) a) m)
@@ -59,8 +61,8 @@
 new n = do
     when (n < 1) $ fail "Data.RingBuffer.new: invalid ring size"
     buffer <- VGM.new n
-    state <- newMVar $ RingState False 0
-    return $ RingBuffer { ringBuffer=buffer, ringState=state }
+    state0 <- newMVar $ RingState False 0
+    return $ RingBuffer { ringBuffer=buffer, ringState=state0 }
 
 -- | Reset the ringbuffer to its empty state
 clear :: VG.Vector v a => RingBuffer v a -> IO ()
@@ -114,7 +116,7 @@
 length :: (VG.Vector v a) => RingBuffer v a -> IO Int
 length rb = withRing rb length'
 
--- | Retrieve the $n$th most-recently added item of the ring
+-- | Retrieve the \(n\)th most-recently added item of the ring
 latest :: (VG.Vector v a) => RingBuffer v a -> Int -> IO (Maybe a)
 latest rb n = withRing rb $ do
     len <- length'
@@ -127,7 +129,8 @@
     len <- length'
     cap <- capacity'
     when (n >= len) $ error "Data.RingBuffer.latest': invalid index"
-    let idx = (cap + len - n - 1) `mod` cap
+    RingState _ hd <- get
+    let idx = (hd - n - 1) `mod` cap
     buf <- ask
     liftIO $ VGM.unsafeRead buf idx
 
