Frames-streamly-0.3.1.0: test/FramesStreamlySpec.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
module FramesStreamlySpec where
import SpecHelper
import Data.Text (Text)
import qualified DemoPaths as Paths
import qualified Frames.Streamly.CSV as FStreamly
import qualified Frames.Streamly.TH as FStreamly
import qualified Frames.Streamly.InCore as FStreamly
import qualified Frames.Streamly.Streaming.Class as Streaming
import qualified Frames.Streamly.Streaming.Pipes as Streaming
import qualified Frames.Streamly.Streaming.Streamly as Streaming
import qualified Frames
import qualified Control.Foldl as Foldl
import Pipes.Safe()
numRecs :: Foldable f => f a -> Int
numRecs = Foldl.fold Foldl.length
FStreamly.tableTypes "ForestFires" (Paths.thPath Paths.forestFiresPath)
FStreamly.tableTypes' Paths.ffColSubsetRowGen
FStreamly.tableTypes' Paths.ffRenameDayRowGen
FStreamly.tableTypes' Paths.ffNoHeaderRowGen
FStreamly.tableTypes' Paths.ffIgnoreHeaderRowGen
FStreamly.tableTypes' Paths.ffIgnoreHeaderChooseNamesRowGen
-- TODO
-- 1. Test renameSome
-- 2. Test different files with shared chosen columnNames
emptyStreamSelector :: Selector FStreamly.FramesCSVException
emptyStreamSelector FStreamly.EmptyStreamException = True
emptyStreamSelector _ = False
missingHeadersSelector :: Selector FStreamly.FramesCSVException
missingHeadersSelector (FStreamly.MissingHeadersException _) = True
missingHeadersSelector _ = False
badHeaderSelector :: Selector FStreamly.FramesCSVException
badHeaderSelector (FStreamly.BadHeaderException _) = True
badHeaderSelector _ = False
wrongNumberColumnsSelector :: Selector FStreamly.FramesCSVException
wrongNumberColumnsSelector (FStreamly.WrongNumberColumnsException _) = True
wrongNumberColumnsSelector _ = False
spec :: Spec
spec = do
let specF :: forall s.(Foldl.PrimMonad (Streaming.IOSafe s IO), Streaming.StreamFunctionsIO s IO) => String -> Spec
specF desc = do
forestFiresPath <- runIO $ Paths.usePath Paths.forestFiresPath
forestFiresNoHeaderPath <- runIO $ Paths.usePath Paths.forestFiresNoHeaderPath
forestFiresFewerColsPath <- runIO $ Paths.usePath Paths.forestFiresFewerColsPath
forestFires :: Frames.Frame ForestFires <- runIO $ Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @_ @s @IO forestFiresParser forestFiresPath
forestFiresColSubset :: Frames.Frame FFColSubset <- runIO $ Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @_ @s @IO fFColSubsetParser forestFiresPath
forestFiresFewerCols :: Frames.Frame FFColSubset <- runIO $ Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @_ @s @IO fFColSubsetParser forestFiresFewerColsPath
forestFiresRenameDay :: Frames.Frame FFRenameDay <- runIO $ Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @_ @s @IO fFColSubsetParser forestFiresPath
forestFiresNoHeader :: Frames.Frame FFNoHeader <- runIO $ Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @_ @s @IO fFNoHeaderParser forestFiresNoHeaderPath
forestFiresIgnoreHeader :: Frames.Frame FFIgnoreHeader <- runIO $ Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @_ @s @IO fFIgnoreHeaderParser forestFiresPath
forestFiresIgnoreHeaderChooseNames :: Frames.Frame FFIgnoreHeaderChooseNames <-
runIO $ Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @_ @s @IO fFIgnoreHeaderChooseNamesParser forestFiresPath
describe desc $ do
context "Can generate types and load the corresponding data a variety of ways" $ do
it "load frames and insure all have same number of rows (AllCols vs. ColSubset)" $
numRecs forestFires == numRecs forestFiresColSubset
it "load frames and insure all have same number of rows (AllCols vs. NoHeader)" $
numRecs forestFires == numRecs forestFiresNoHeader
it "load frames and insure all have same number of rows (AllCols vs. IgnoreHeader)" $
numRecs forestFires == numRecs forestFiresIgnoreHeader
it "load frames and insure all have same number of rows (AllCols vs. IgnoreHeaderChooseNames)" $
numRecs forestFires == numRecs forestFiresIgnoreHeaderChooseNames
it "generate types from each header and rcast to drop columns or load only that column subset. Those should be the same" $
let rcasted :: Frames.FrameRec [X, Y, Month, Day, Temp, Wind] = fmap Frames.rcast forestFires
in rcasted == forestFiresColSubset
it "parse a file with different columsn as long as the required subset is present. This should be the same as the full file" $
forestFiresColSubset == forestFiresFewerCols
it "generate types from column numbers rather than headers. Also from column numbers when there is no header. Those should be the same." $
forestFiresNoHeader == forestFiresIgnoreHeader
it "generate named types for columns chosen by col number. In this case, should match col subset after renaming Day to DayOfWeek" $
forestFiresIgnoreHeaderChooseNames == forestFiresRenameDay
it "throw an exception when parsing (ignoring or absent a header line) a file with the wrong number of columns" $ do
(Streaming.runSafe @s $ FStreamly.inCoreAoS $ FStreamly.readTableOpt @(Frames.RecordColumns ForestFires) @s @IO fFIgnoreHeaderParser forestFiresFewerColsPath) `shouldThrow` wrongNumberColumnsSelector
specF @(Streaming.StreamlyStream Streaming.SerialT) "Streamly backend"
specF @Streaming.PipeStream "Pipes backend"