Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# CSV/TSV test fixtures are byte-exact inputs for byte-level parsers
# (dataframe-fastcsv reads raw bytes); git must never translate their
# line endings on checkout, or quoted embedded newlines gain \r on
# Windows and round-trip tests fail.
*.csv -text
*.tsv -text
6 changes: 5 additions & 1 deletion dataframe-fastcsv/tests/Operations/Projection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ module Operations.Projection (tests) where

import qualified Data.Map as M
import qualified Data.Text as T
import qualified Data.Text.IO as TIO

-- UTF-8 byte-mode IO: the plain Data.Text.IO writer honours the
-- handle's text mode, which on Windows turns \n into \r\n and
-- corrupts inputs meant for byte-level parsers.
import qualified Data.Text.IO.Utf8 as TIO

import Control.Exception (SomeException, evaluate, try)
import Data.List (isInfixOf)
Expand Down
15 changes: 14 additions & 1 deletion dataframe-fastcsv/tests/Operations/ReadCsv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@ import DataFrame.Internal.DataFrame (
)
import DataFrame.Schema (Schema (..), SchemaType (..))
import System.Directory (removeFile)
import System.IO (IOMode (..), withFile)
import System.IO (
IOMode (..),
hSetEncoding,
hSetNewlineMode,
noNewlineTranslation,
utf8,
withFile,
)
import Test.HUnit
import Type.Reflection (typeRep)

Expand All @@ -59,6 +66,12 @@ prettyPrintTsv = prettyPrintSeparated '\t'

prettyPrintSeparated :: Char -> FilePath -> DataFrame -> IO ()
prettyPrintSeparated sep filepath df = withFile filepath WriteMode $ \handle -> do
-- Byte-exact UTF-8 output: a default handle uses the OS locale
-- encoding (crashes on non-ANSI text under a non-UTF-8 codepage)
-- and translates \n to \r\n on Windows, corrupting quoted embedded
-- newlines for the byte-level reader.
hSetEncoding handle utf8
hSetNewlineMode handle noNewlineTranslation
let (rows, _) = dataframeDimensions df
let headers = map fst (L.sortBy (compare `on` snd) (M.toList (columnIndices df)))
TIO.hPutStrLn
Expand Down
6 changes: 5 additions & 1 deletion dataframe-fastcsv/tests/Operations/TypedExtraction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import qualified Data.Map as M
import qualified Data.Proxy as P
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Text.IO as TIO

-- UTF-8 byte-mode IO: the plain Data.Text.IO writer honours the
-- handle's text mode, which on Windows turns \n into \r\n and
-- corrupts inputs meant for byte-level parsers.
import qualified Data.Text.IO.Utf8 as TIO

import Control.Exception (ErrorCall, evaluate, try)
import Data.Time (Day)
Expand Down
10 changes: 7 additions & 3 deletions dataframe-fastcsv/tests/Properties/Csv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import qualified Data.List as L
import qualified Data.Map as M
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Text.IO as TIO

-- UTF-8 byte-mode IO: the plain Data.Text.IO writer honours the
-- handle's text mode, which on Windows turns \n into \r\n and
-- corrupts inputs meant for byte-level parsers.
import qualified Data.Text.IO.Utf8 as TIO
import qualified Data.Vector as V

import DataFrame.IO.CSV (defaultReadOptions)
Expand Down Expand Up @@ -130,7 +134,7 @@ the temp file afterwards no matter what.
-}
withCsvFile :: String -> T.Text -> (FilePath -> IO a) -> IO a
withCsvFile label body action = do
let path = "/tmp/fastcsv_prop_" <> label <> ".csv"
let path = "./tests/data/unstable_csv/fastcsv_prop_" <> label <> ".csv"
TIO.writeFile path body
r <- action path
removeFile path
Expand Down Expand Up @@ -209,7 +213,7 @@ prop_unclosed_quote_throws = forAll (listOf1 arbitrary) $ \(cells :: [Cell]) ->
T.intercalate "," (map (encodeCell ',' . unCell) cells)
csv = "v\n" <> plainRow <> ",\"dangling\n"
result <- run $ do
let path = "/tmp/fastcsv_prop_unclosed.csv"
let path = "./tests/data/unstable_csv/fastcsv_prop_unclosed.csv"
TIO.writeFile path csv
r <- try @CsvParseError (D.fastReadCsv path)
removeFile path
Expand Down
10 changes: 8 additions & 2 deletions tests/Operations/Record.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ module Operations.Record where
import Data.Int (Int64)
import qualified Data.Map.Strict as M
import qualified Data.Text as T
import qualified Data.Text.IO as TIO

-- UTF-8 byte-mode IO: the plain Data.Text.IO writer honours the
-- handle's text mode, which on Windows turns \n into \r\n and
-- corrupts inputs meant for byte-level parsers.
import qualified Data.Text.IO.Utf8 as TIO
import GHC.Generics (Generic)

import qualified DataFrame as D
Expand All @@ -27,6 +31,7 @@ import DataFrame.Operators
import qualified DataFrame.Schema as IS
import DataFrame.Typed (Schema)
import qualified DataFrame.Typed as DT
import System.Directory (getTemporaryDirectory)

import Test.HUnit

Expand Down Expand Up @@ -289,7 +294,8 @@ deriveSchemaReadsCsv = TestCase $ do
, "2,eu,20.5"
, "3,ap,30.0"
]
tmp = "/tmp/dataframe_test_deriveSchema.csv"
tmpDir <- getTemporaryDirectory
let tmp = tmpDir <> "/dataframe_test_deriveSchema.csv"
TIO.writeFile tmp csv
df <- D.readCsvWithSchema orderSchema tmp
assertEqual
Expand Down
10 changes: 8 additions & 2 deletions tests/Operations/WriteCsv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
module Operations.WriteCsv where

import qualified Data.Text as T
import qualified Data.Text.IO as TIO

-- UTF-8 byte-mode IO: the plain Data.Text.IO writer honours the
-- handle's text mode, which on Windows turns \n into \r\n and
-- corrupts inputs meant for byte-level parsers.
import qualified Data.Text.IO.Utf8 as TIO
import qualified DataFrame as D
import qualified DataFrame.Internal.Column as DI
import DataFrame.Internal.DataFrame (DataFrame (..), toCsv, toSeparated)
import System.Directory (getTemporaryDirectory)
import Test.HUnit

-- Basic test: Int and Text columns produce correct CSV
Expand Down Expand Up @@ -81,7 +86,8 @@ toCsvRoundTrip = TestLabel "toCsv_roundTrip" $ TestCase $ do
, ("b", DI.fromList @T.Text ["hello", "world", "test"])
]
let csvText = toCsv df
let tmpPath = "/tmp/dataframe_test_toCsv_roundtrip.csv"
tmpDir <- getTemporaryDirectory
let tmpPath = tmpDir <> "/dataframe_test_toCsv_roundtrip.csv"
TIO.writeFile tmpPath csvText
df' <- D.readCsv tmpPath
assertEqual
Expand Down
Loading