diff --git a/Tests/Codec/Compression/LZF/ByteString.hs b/Tests/Codec/Compression/LZF/ByteString.hs
new file mode 100644
--- /dev/null
+++ b/Tests/Codec/Compression/LZF/ByteString.hs
@@ -0,0 +1,57 @@
+module Tests.Codec.Compression.LZF.ByteString (lzfByteStringTests) where
+
+import Codec.Compression.LZF.ByteString
+    (
+     compressByteString,
+     compressLazyByteString,
+     decompressByteString,
+     decompressByteStringFixed,
+     decompressLazyByteString
+    )
+
+import Control.Applicative((<$>))
+
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Lazy as BSL
+
+import Test.Framework
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.QuickCheck
+import Test.QuickCheck.Instances
+import Test.QuickCheck.Monadic (assert, monadic, run)
+
+_compare :: Eq t => (t -> t) -> (t -> t) -> t -> Property
+_compare a b x = property $ x == (a $ b x)
+
+prop_DecompressCompressInverses :: BS.ByteString -> Property
+prop_DecompressCompressInverses x =
+    _compare decompressByteString compressByteString x
+
+prop_LazyDecompressCompressInverses :: BSL.ByteString -> Property
+prop_LazyDecompressCompressInverses x =
+    _compare decompressLazyByteString compressLazyByteString x
+
+data NSmall = NSmall Int deriving (Show)
+data BSSmall = BSSmall BS.ByteString deriving (Show)
+
+instance Arbitrary NSmall where
+    arbitrary = NSmall <$> choose (0,10000)
+
+instance Arbitrary BSSmall where
+    arbitrary = do
+      size <- choose(0,10000)
+      BSSmall <$> BS.pack <$> vector size
+
+prop_DecompressingAnyGarbageDoesntCauseACrash :: NSmall -> BSSmall -> Property
+prop_DecompressingAnyGarbageDoesntCauseACrash (NSmall n) (BSSmall bs) =
+    property $
+    case decompressByteStringFixed n bs of
+      Nothing -> True
+      Just x -> BS.length x >= 0
+
+lzfByteStringTests =
+    testGroup "Codec.Compression.LZF.ByteString" [
+        testProperty "Decompress and compress inverses" prop_DecompressCompressInverses,
+        testProperty "Lazy Decompress and compress inverses" prop_LazyDecompressCompressInverses,
+        testProperty "Checking for crashes on arbitrary ByteStrings" prop_DecompressingAnyGarbageDoesntCauseACrash
+    ]
diff --git a/Tests/Data/Binary/C.hs b/Tests/Data/Binary/C.hs
new file mode 100644
--- /dev/null
+++ b/Tests/Data/Binary/C.hs
@@ -0,0 +1,30 @@
+module Tests.Data.Binary.C (cBinaryTests) where
+
+import Control.Applicative
+import Data.Binary
+import Data.Binary.C
+import Foreign.C.Types
+import GHC.Prim (coerce)
+import Test.Framework
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.QuickCheck
+import Test.QuickCheck.Instances
+import Test.QuickCheck.Monadic (assert, monadic, run)
+
+prop_CFloat :: CFloat -> Property
+prop_CFloat x = property $ (decode $ encode x) == x
+
+prop_CDouble :: CDouble -> Property
+prop_CDouble x = property $ (decode $ encode x) == x
+
+instance Arbitrary CFloat where
+  arbitrary = realToFrac <$> (arbitrary :: Gen Float)
+
+instance Arbitrary CDouble where
+  arbitrary = realToFrac <$> (arbitrary :: Gen Double)
+
+cBinaryTests =
+    testGroup "Binary instances for C types" [
+        testProperty "CFloat" prop_CFloat,
+        testProperty "CDouble" prop_CDouble
+    ]
diff --git a/Tests/Database/Alteryx.hs b/Tests/Database/Alteryx.hs
new file mode 100644
--- /dev/null
+++ b/Tests/Database/Alteryx.hs
@@ -0,0 +1,282 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Tests.Database.Alteryx (yxdbTests) where
+
+import qualified Database.Alteryx.CLI.Csv2Yxdb as C2Y
+import qualified Database.Alteryx.CLI.Yxdb2Csv as Y2C
+import Database.Alteryx
+import Tests.Database.Alteryx.Arbitrary
+import Tests.Database.Utils
+
+import Prelude hiding (readFile)
+
+import Control.Applicative
+import Control.Lens hiding (elements)
+import Control.Monad (replicateM, when)
+import Control.Monad.State (evalStateT)
+import Control.Monad.Trans.Resource
+import Data.Array.IArray (listArray)
+import Data.Binary
+import Data.Binary.Get (runGet)
+import Data.Binary.Put (runPut)
+import Data.ByteString as BS
+import Data.ByteString.Char8 as BSC
+import Data.ByteString.Lazy as BSL
+import Data.Conduit
+import Data.Conduit.Combinators
+import Data.Conduit.Lift
+import Data.Conduit.List as CL
+import qualified Data.Conduit.Text as CT
+import qualified Data.CSV.Conduit as CSVT
+import Data.Text as T
+import Data.Text.Encoding as T
+import Data.Text.IO as T
+
+import Test.Framework
+import Test.Framework.Providers.HUnit (testCase)
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.HUnit
+import Test.QuickCheck
+
+assertEq :: (Eq a, Show a) => a -> a -> Property
+assertEq a b = let
+    aStr = show a
+    bStr = show b
+    in printTestCase ("\nA: " ++ aStr ++ "\nB: " ++ bStr) (a == b)
+
+numBytes :: Binary a => a -> Int
+numBytes x = fromIntegral $ BSL.length $ runPut $ put x
+
+prop_HeaderLength :: Header -> Property
+prop_HeaderLength header =
+    assertEq headerPageSize (numBytes header)
+
+prop_MetadataLength :: YxdbFile -> Property
+prop_MetadataLength yxdb =
+    assertEq (numMetadataBytesHeader $ yxdb ^. yxdbFileHeader)
+             (numMetadataBytesActual $ yxdb ^. yxdbFileMetadata)
+
+-- prop_BlocksLength :: YxdbFile -> Property
+-- prop_BlocksLength yxdb =
+--     assertEq (numBlocksBytesHeader $ header yxdb) (numBlocksBytesActual $ blocks yxdb)
+
+prop_ValueGetAndPutAreInverses :: PairedValue -> Property
+prop_ValueGetAndPutAreInverses (PairedValue field value) =
+    assertEq (runGet (getValue field) (runPut $ putValue field value)) value
+
+prop_BlockIndexGetAndPutAreInverses :: BlockIndex -> Property
+prop_BlockIndexGetAndPutAreInverses x = assertEq (decode $ encode x) x
+
+prop_MetadataGetAndPutAreInverses :: RecordInfo -> Property
+prop_MetadataGetAndPutAreInverses x = assertEq (decode $ encode x) x
+
+prop_HeaderGetAndPutAreInverses :: Header -> Property
+prop_HeaderGetAndPutAreInverses x = assertEq (decode $ encode x) x
+
+prop_BlocksGetAndPutAreInverses :: Block -> Property
+prop_BlocksGetAndPutAreInverses x = assertEq (decode $ encode x) x
+
+prop_YxdbFileGetAndPutAreInverses :: YxdbFile -> Property
+prop_YxdbFileGetAndPutAreInverses x = assertEq (decode $ encode x) x
+
+test_LoadingSmallModule :: Assertion
+test_LoadingSmallModule = do
+  parsed <- decodeFileOrFail "test-data/samples_of_various_field_types.yxdb"
+  case parsed of
+    Left (bytes, msg) -> assertFailure (msg ++ " at " ++ show bytes ++ " bytes")
+    Right yxdbFile -> const (return ()) (yxdbFile :: YxdbFile)
+
+csv2yxdb2csv :: C2Y.Settings -> FilePath -> FilePath -> IO T.Text
+csv2yxdb2csv settings inputFilename outputFilename = do
+  let c2ySettings = settings & C2Y.settingFilename .~ inputFilename
+                             & C2Y.settingOutput .~ outputFilename
+  let y2cSettings = Y2C.defaultSettings & Y2C.settingFilename .~ outputFilename
+  evalStateT C2Y.runCsv2Yxdb c2ySettings
+  newCsv <- T.decodeUtf8 <$> (captureStdout $ evalStateT Y2C.runYxdb2Csv y2cSettings)
+
+  return newCsv
+
+readCsvRecords :: Maybe Text -> FilePath -> IO [Record]
+readCsvRecords header filename =
+    runResourceT $
+      sourceCsvRecords filename header alteryxCsvSettings $$
+      sinkList
+
+test_csv2yxdb2csvIsIdentity :: Assertion
+test_csv2yxdb2csvIsIdentity = do
+  let inputFilename = "test-data/samples.csv"
+  let outputFilename = "test-data/samples.yxdb"
+  newCsv <- csv2yxdb2csv C2Y.defaultSettings inputFilename outputFilename
+  originalCsv <- T.readFile inputFilename
+  assertEqual "CSV to YXDB to CSV" originalCsv newCsv
+
+test_csv2yxdbQuoteParsing :: Assertion
+test_csv2yxdbQuoteParsing = do
+  let inputFilename = "test-data/quote-parsing.csv"
+  let outputFilename = "test-data/quote-parsing.yxdb"
+  oldCsv <- T.readFile inputFilename
+  newCsv <- csv2yxdb2csv C2Y.defaultSettings inputFilename outputFilename
+  assertEqual "" oldCsv newCsv
+
+test_csv2yxdbDateFormat :: Assertion
+test_csv2yxdbDateFormat = do
+  let inputFilename = "test-data/date-format.csv"
+      outputFilename = "test-data/date-format.yxdb"
+  oldCsv <- T.readFile inputFilename
+  newCsv <- csv2yxdb2csv C2Y.defaultSettings inputFilename outputFilename
+  assertEqual "" oldCsv newCsv
+
+nonAnsiCodepointFieldValue :: Maybe FieldValue
+nonAnsiCodepointFieldValue = Just $ FVString "plátano"
+
+nonAnsiCodepointField :: Field
+nonAnsiCodepointField = Field {
+                          _fieldName = "derp",
+                          _fieldType = FTString,
+                          _fieldSize = Just 10,
+                          _fieldScale = Nothing
+                        }
+
+test_renderNonAnsiCodepoint :: Assertion
+test_renderNonAnsiCodepoint = do
+  let fieldValue = nonAnsiCodepointFieldValue
+      field = nonAnsiCodepointField
+      bs = runPut (putValue field fieldValue)
+      parsedValue = runGet (getValue field) bs
+  assertEqual "Converting a non-ANSI character lost information" fieldValue parsedValue
+
+test_renderNonAnsiCodepointRecord :: Assertion
+test_renderNonAnsiCodepointRecord = do
+    let fieldValue = nonAnsiCodepointFieldValue
+        field = nonAnsiCodepointField
+
+        record = Record [ fieldValue ]
+        recordInfo = RecordInfo [ field ]
+
+        record2recordConduit = record2csv recordInfo =$=
+                         csv2bytes =$=
+                         CT.decode CT.utf8 =$=
+                         csv2records alteryxCsvSettings
+    newRecords <- runResourceT $ CL.sourceList [ record ] =$= record2recordConduit $$ sinkList
+
+    let result = Prelude.head newRecords
+    assertEqual "Converting a non-ANSI character lost information" record result
+
+test_renderNonAnsiCodepointCSVRecord :: Assertion
+test_renderNonAnsiCodepointCSVRecord =
+  let csvText = "derp:string(10)\nplátano\n"
+      recordInfo = RecordInfo [ nonAnsiCodepointField ]
+      csv2csvConduit =
+          csv2records alteryxCsvSettings =$=
+          record2csv recordInfo =$=
+          csv2bytes =$=
+          CT.decode CT.utf8
+
+  in do
+    newCsv <- runResourceT $ CL.sourceList [ csvText ] =$= csv2csvConduit $$ sinkList
+    assertEqual "" csvText $ T.concat newCsv
+
+test_renderNonAnsiCodepointCSV2Record2Block2Record2CSV :: Assertion
+test_renderNonAnsiCodepointCSV2Record2Block2Record2CSV =
+  let csvText = "derp:string(10)\nplátano\n"
+      recordInfo = RecordInfo [ nonAnsiCodepointField ]
+      csv2csvConduit =
+          csv2records alteryxCsvSettings =$=
+          evalStateLC defaultStatistics (recordsToBlocks recordInfo) =$=
+          blocksToRecords recordInfo =$=
+          record2csv recordInfo =$=
+          csv2bytes =$=
+          CT.decode CT.utf8
+  in do
+    newCsv <- runResourceT $ CL.sourceList [ csvText ] =$= csv2csvConduit $$ sinkList
+    assertEqual "" csvText $ T.concat newCsv
+
+
+test_recordParsing :: Assertion
+test_recordParsing = do
+  let inputFilename = "test-data/samples.csv"
+      outputFilename = "test-data/samples.yxdb"
+      secondOutputFilename = "test-data/samples.yxdb.csv"
+      expectedRecord =
+          [
+           Record [
+            Just (FVByte 1),
+            Just (FVInt16 256),
+            Just (FVInt32 32768),
+            Just (FVInt64 4294967296),
+            Just (FVString "1.10000"),
+            Just (FVFloat 1.1),
+            Just (FVDouble 1.1),
+            Just (FVString "plátano"),
+            Just (FVWString "香蕉"),
+            Just (FVString "plátano"),
+            Just (FVWString "香蕉"),
+            Just (FVString "2013-12-31"),
+            Just (FVString "23:34:56"),
+            Just (FVString "2013-12-31 23:34:56")
+           ]
+          ]
+  records <- readCsvRecords Nothing inputFilename
+  assertEqual "Parse from CSV" expectedRecord records
+
+  newCsv <- csv2yxdb2csv C2Y.defaultSettings inputFilename outputFilename
+  yxdbFile <- decodeFile outputFilename :: IO YxdbFile
+
+  T.writeFile secondOutputFilename newCsv
+  newRecords <- readCsvRecords Nothing secondOutputFilename
+
+  assertEqual "Parse from YXDB" expectedRecord (yxdbFile ^. yxdbFileRecords)
+  assertEqual "New CSV doesn't match old" expectedRecord newRecords
+
+test_signedRecordParsing :: Assertion
+test_signedRecordParsing = do
+  let inputFilename = "test-data/signed.csv"
+      outputFilename = "test-data/signed.yxdb"
+      secondOutputFilename = "test-data/signed.yxdb.csv"
+      expectedRecord =
+          [
+           Record [
+            Just (FVByte $ -1),
+            Just (FVInt16 $ -256),
+            Just (FVInt32 $ -32768),
+            Just (FVInt64 $ -4294967296),
+            Just (FVString "1.10000"),
+            Just (FVFloat $ -1.1),
+            Just (FVDouble $ -1.1)
+           ]
+          ]
+  records <- readCsvRecords Nothing inputFilename
+  assertEqual "Parse from CSV" expectedRecord records
+
+  newCsv <- csv2yxdb2csv C2Y.defaultSettings inputFilename outputFilename
+  yxdbFile <- decodeFile outputFilename :: IO YxdbFile
+
+  T.writeFile secondOutputFilename newCsv
+  newRecords <- readCsvRecords Nothing secondOutputFilename
+
+  assertEqual "Parse from YXDB" expectedRecord (yxdbFile ^. yxdbFileRecords)
+  assertEqual "New CSV doesn't match old" expectedRecord newRecords
+
+yxdbTests :: Test.Framework.Test
+yxdbTests =
+    testGroup "YXDB" [
+        testProperty "Header length" prop_HeaderLength,
+        testProperty "Metadata length" prop_MetadataLength,
+--        testProperty "Blocks length" prop_BlocksLength, --
+        testProperty "Block Index get & put inverses" prop_BlockIndexGetAndPutAreInverses,
+        testProperty "Metadata get and put inverses" prop_MetadataGetAndPutAreInverses,
+        testProperty "Header get & put inverses" prop_HeaderGetAndPutAreInverses,
+        testProperty "Value get & put inverses" prop_ValueGetAndPutAreInverses,
+        testProperty "Blocks get & put inverses" prop_BlocksGetAndPutAreInverses,
+--        testProperty "Yxdb get & put inverses" prop_YxdbFileGetAndPutAreInverses,
+        testCase "Loading small module" test_LoadingSmallModule,
+        testCase "CSV to YXDB to CSV is the identity" test_csv2yxdb2csvIsIdentity,
+        testCase "Quotes are not used to escape" test_csv2yxdbQuoteParsing,
+        testCase "Can parse ISO style dates" test_csv2yxdbDateFormat,
+        testCase "Example CSV parses into correct structures" test_recordParsing,
+        testCase "Example CSV with signed values" test_signedRecordParsing,
+        testCase "Rendering a non-ANSI codepoint" test_renderNonAnsiCodepoint,
+        testCase "Rendering a non-ANSI codepoint at record level" test_renderNonAnsiCodepointRecord,
+        testCase "Rendering a non-ANSI codepoint from CSV to CSV" test_renderNonAnsiCodepointCSVRecord,
+        testCase "Rendering a non-ANSI codepoint from CSV to YXDB blocks to CSV" test_renderNonAnsiCodepointCSV2Record2Block2Record2CSV
+    ]
diff --git a/Tests/Database/Alteryx/Arbitrary.hs b/Tests/Database/Alteryx/Arbitrary.hs
new file mode 100644
--- /dev/null
+++ b/Tests/Database/Alteryx/Arbitrary.hs
@@ -0,0 +1,170 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module Tests.Database.Alteryx.Arbitrary where
+
+import Database.Alteryx
+
+import Conduit
+import Data.Conduit.Lift as CL
+import Control.Applicative
+import Control.Lens hiding (elements)
+import Control.Monad
+import Data.Array.IArray
+import Data.Binary
+import Data.Binary.Put
+import Data.ByteString as BS
+import Data.ByteString.Lazy as BSL
+import Data.Maybe
+import qualified Data.Text as T
+import Data.Text.Encoding
+import Data.Time.Clock.POSIX
+import Data.Word
+import Test.QuickCheck
+import Test.QuickCheck.Instances()
+
+instance Arbitrary YxdbFile where
+  arbitrary = do
+    fMetadata   <- arbitrary
+    fBlocks     <- arbitraryBlocksMatching fMetadata
+    fHeader     <- arbitraryHeaderMatching fMetadata fBlocks
+    fBlockIndex <- arbitrary
+
+    fRecords <- arbitraryRecordsMatching fMetadata
+
+    return $ YxdbFile {
+      _yxdbFileHeader     = fHeader,
+      _yxdbFileRecords    = fRecords,
+      _yxdbFileMetadata   = fMetadata,
+      _yxdbFileBlockIndex = fBlockIndex
+    }
+
+arbitraryBlocksMatching :: RecordInfo -> Gen [Block]
+arbitraryBlocksMatching recordInfo = do
+  records <- arbitraryRecordsMatching recordInfo
+  let blocks = fromJust $ yieldMany records $= CL.evalStateLC defaultStatistics (recordsToBlocks recordInfo) $$ sinkList
+  return blocks
+
+arbitraryHeaderMatching :: RecordInfo -> [Block] -> Gen Header
+arbitraryHeaderMatching metadata blocks = do
+  fDescription <- replicateM 64 $ choose(0,127) :: Gen [Word8]
+  fFileId <- arbitrary
+  fCreationDate <- posixSecondsToUTCTime <$> fromIntegral <$> (arbitrary :: Gen Word32)
+  fFlags1 <- arbitrary
+  fFlags2 <- arbitrary
+  fMystery <- arbitrary
+  fSpatialIndexPos <- arbitrary
+  let numMetadataBytes = numMetadataBytesActual metadata
+  let fMetaInfoLength = fromIntegral $ numMetadataBytes `div` 2
+  let numBlockBytes = sum $ Prelude.map numBlockBytesActual blocks
+  let startOfBlocks = fromIntegral $ headerPageSize + (fromIntegral $ numMetadataBytes)
+  let fRecordBlockIndexPos = startOfBlocks + (fromIntegral numBlockBytes)
+  fNumRecords <- arbitrary
+  fCompressionVersion <- arbitrary
+  fReservedSpace <- vector (512 - 64 - (4 * 7) - (8 * 3)) :: Gen [Word8]
+  return $ Header {
+               _description         = decodeUtf8 $ BS.pack $ fDescription,
+               _fileId              = fFileId,
+               _creationDate        = fCreationDate,
+               _flags1              = fFlags1,
+               _flags2              = fFlags2,
+               _metaInfoLength      = fMetaInfoLength,
+               _mystery             = fMystery,
+               _spatialIndexPos     = fSpatialIndexPos,
+               _recordBlockIndexPos = fRecordBlockIndexPos,
+               _numRecords          = fNumRecords,
+               _compressionVersion  = fCompressionVersion,
+               _reservedSpace       = BS.pack fReservedSpace
+             }
+
+instance Arbitrary Header where
+    arbitrary = do
+      metadata <- arbitrary
+      blocks <- arbitraryBlocksMatching metadata
+      arbitraryHeaderMatching metadata blocks
+
+arbitraryRecordsMatching :: RecordInfo -> Gen [Record]
+arbitraryRecordsMatching metadata = do
+  size <- choose(0,10000)
+  vectorOf size (arbitraryRecordMatching metadata)
+
+arbitraryRecordMatching :: RecordInfo -> Gen Record
+arbitraryRecordMatching (RecordInfo fields) =
+    Record <$> mapM arbitraryValueMatching fields
+
+arbitraryValueMatching :: Field -> Gen (Maybe FieldValue)
+arbitraryValueMatching field =
+  let value =
+        case field ^. fieldType of
+          FTBool -> FVBool <$> arbitrary
+          FTByte -> FVByte <$> arbitrary
+          FTInt16 -> FVInt16 <$> arbitrary
+          FTInt32 -> FVInt32 <$> arbitrary
+          FTInt64 -> FVInt64 <$> arbitrary
+          FTFloat -> FVFloat <$> arbitrary
+          FTDouble -> FVDouble <$> arbitrary
+  in do
+    isNull <- arbitrary
+    if isNull
+       then return Nothing
+       else Just <$> value
+
+instance Arbitrary Block where
+    arbitrary = Prelude.head <$> (arbitraryBlocksMatching =<< arbitrary)
+
+instance Arbitrary FieldType where
+    arbitrary = elements [
+                 -- FTBool,
+                 FTByte,
+                 FTInt16,
+                 FTInt32,
+                 FTInt64,
+                 -- FTFixedDecimal,
+                 FTFloat,
+                 FTDouble
+                 -- FTString,
+                 -- FTWString,
+                 -- FTVString,
+                 -- FTVWString,
+                 -- FTDate,
+                 -- FTTime,
+                 -- FTDateTime,
+                 -- FTBlob,
+                 -- FTSpatialObject,
+                 -- FTUnknown
+                ]
+
+instance Arbitrary Field where
+    arbitrary = do
+      fName <- arbitrary
+      fType <- arbitrary
+      fSize <- arbitrary
+      fScale <- arbitrary
+      return $ Field {
+                   _fieldName = fName,
+                   _fieldType = fType,
+                   _fieldSize = fSize,
+                   _fieldScale = fScale
+                 }
+
+instance Arbitrary Record where
+    arbitrary = arbitraryRecordMatching =<< arbitrary
+
+instance Arbitrary RecordInfo where
+    arbitrary = do
+      len <- choose(1,10)
+      RecordInfo <$> vector len
+
+instance Arbitrary BlockIndex where
+    arbitrary =
+        sized $
+            \chunkSize -> do
+                indices <- replicateM chunkSize arbitrary
+                return $ BlockIndex $ listArray (0, chunkSize) indices
+
+data PairedValue = PairedValue Field (Maybe FieldValue) deriving (Eq, Show)
+
+instance Arbitrary PairedValue where
+    arbitrary = do
+      field <- arbitrary
+      value <- arbitraryValueMatching field
+      return $ PairedValue field value
diff --git a/Tests/Database/Utils.hs b/Tests/Database/Utils.hs
new file mode 100644
--- /dev/null
+++ b/Tests/Database/Utils.hs
@@ -0,0 +1,19 @@
+module Tests.Database.Utils where
+
+import Data.ByteString as BS
+import GHC.IO.Handle
+import System.IO
+import System.Directory
+
+captureStdout :: IO () -> IO BS.ByteString
+captureStdout f = do
+  tmpd <- getTemporaryDirectory
+  (tmpf, tmph) <- openTempFile tmpd "haskell_stdout"
+  stdout_dup <- hDuplicate stdout
+  hDuplicateTo tmph stdout
+  hClose tmph
+  f
+  hDuplicateTo stdout_dup stdout
+  bs <- BS.readFile tmpf
+  removeFile tmpf
+  return bs
diff --git a/test-data/date-format.csv b/test-data/date-format.csv
new file mode 100644
--- /dev/null
+++ b/test-data/date-format.csv
@@ -0,0 +1,2 @@
+f1:int(16)|f2:int(16)|f3:date|f4:time|f5:datetime
+500|1|2014-01-01|06:00:00|2014-0-0 06:00:00
diff --git a/test-data/quote-parsing.csv b/test-data/quote-parsing.csv
new file mode 100644
--- /dev/null
+++ b/test-data/quote-parsing.csv
@@ -0,0 +1,3 @@
+f1:string(7)
+aoeu
+"aoeu"
diff --git a/test-data/samples.csv b/test-data/samples.csv
new file mode 100644
--- /dev/null
+++ b/test-data/samples.csv
@@ -0,0 +1,2 @@
+f1:int(8)|f2:int(16)|f3:int(32)|f4:int(64)|f5:decimal(7,5)|f6:float|f7:double|f8:string(8)|f9:wstring(2)|f10:string(8)|f11:wstring(2)|f12:date|f13:time|f14:datetime
+1|256|32768|4294967296|1.10000|1.1000|1.1000|plátano|香蕉|plátano|香蕉|2013-12-31|23:34:56|2013-12-31 23:34:56
diff --git a/test-data/samples_of_various_field_types.yxdb b/test-data/samples_of_various_field_types.yxdb
new file mode 100644
Binary files /dev/null and b/test-data/samples_of_various_field_types.yxdb differ
diff --git a/test-data/samples_without_header.csv b/test-data/samples_without_header.csv
new file mode 100644
--- /dev/null
+++ b/test-data/samples_without_header.csv
@@ -0,0 +1,1 @@
+1|256|32768|4294967296|1.10000|1.1000|1.1000|plátano|香蕉|plátano|香蕉|2013-12-31|23:34:56|2013-12-31 23:34:56
diff --git a/test-data/signed.csv b/test-data/signed.csv
new file mode 100644
--- /dev/null
+++ b/test-data/signed.csv
@@ -0,0 +1,2 @@
+f1:int(8)|f2:int(16)|f3:int(32)|f4:int(64)|f5:decimal(7,5)|f6:float|f7:double
+-1|-256|-32768|-4294967296|1.10000|-1.1000|-1.1000
diff --git a/yxdb-utils.cabal b/yxdb-utils.cabal
--- a/yxdb-utils.cabal
+++ b/yxdb-utils.cabal
@@ -10,7 +10,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.1.0.0
+version:             0.1.0.1
 
 -- A short (one-line) description of the package.
 synopsis:            Utilities for reading and writing Alteryx .yxdb files
@@ -41,6 +41,10 @@
 -- Constraint on the version of Cabal needed to build this package.
 cabal-version:       >=1.8
 
+extra-source-files:
+  test-data/*.csv
+  test-data/*.yxdb
+
 executable csv2yxdb
   hs-source-dirs: bin-src
   main-is: Csv2Yxdb.hs
@@ -108,6 +112,13 @@
 test-suite yxdb-tests
   ghc-options: -O2 -fprof-auto
   hs-source-dirs: src, .
+  other-modules:
+    Tests.Codec.Compression.LZF.ByteString
+    Tests.Data.Binary.C
+    Tests.Database.Alteryx
+    Tests.Database.Alteryx.Arbitrary
+    Tests.Database.Utils
+    Tests.Main
   type: exitcode-stdio-1.0
   build-depends:
     Codec-Compression-LZF,
@@ -152,7 +163,6 @@
   buildable: True
   hs-source-dirs: src
   ghc-options: -rtsopts -with-rtsopts=-M512m
-
 source-repository head
   type: git
   location: https://github.com/MichaelBurge/yxdb-utils
