yxdb-utils-0.1.0.1: Tests/Database/Alteryx/Arbitrary.hs
{-# 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