Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 219 lines (192 sloc) 8.591 kb
74b3f35 Johan Tibell Fix test bug
authored
1 {-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
87a4daf Johan Tibell Add tests for name-based decoding
authored
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
3
1fae7b8 Johan Tibell Add unit test
authored
4 module Main
5 ( main
6 ) where
7
8 import qualified Data.ByteString as B
9 import qualified Data.ByteString.Lazy as BL
da2cd94 Johan Tibell Clean up tests
authored
10 import qualified Data.ByteString.Lazy.Char8 as BL8
dd3dda1 Johan Tibell encodeByHeader: Fix bug where header was omitted
authored
11 import qualified Data.HashMap.Strict as HM
875fd47 Johan Tibell Add round-trip unit tests
authored
12 import Data.Int
13 import qualified Data.Text as T
14 import qualified Data.Text.Lazy as LT
15 import Data.Vector ((!))
1fae7b8 Johan Tibell Add unit test
authored
16 import qualified Data.Vector as V
875fd47 Johan Tibell Add round-trip unit tests
authored
17 import Data.Word
1fae7b8 Johan Tibell Add unit test
authored
18 import Test.HUnit
19 import Test.Framework as TF
20 import Test.Framework.Providers.HUnit as TF
875fd47 Johan Tibell Add round-trip unit tests
authored
21 import Test.QuickCheck
22 import Test.Framework.Providers.QuickCheck2 as TF
1fae7b8 Johan Tibell Add unit test
authored
23
d169845 Johan Tibell Rename D.Ceason to D.Csv
authored
24 import Data.Csv
1fae7b8 Johan Tibell Add unit test
authored
25
875fd47 Johan Tibell Add round-trip unit tests
authored
26 ------------------------------------------------------------------------
27 -- Parse tests
28
90bbf52 Johan Tibell Refactor tests to be more readable
authored
29 decodesAs :: BL.ByteString -> [[B.ByteString]] -> Assertion
743d226 Johan Tibell Fix bug in custom field delimiter parsing
authored
30 decodesAs input expected = assertResult input expected $ decode input
31
32 decodesWithAs :: DecodeOptions -> BL.ByteString -> [[B.ByteString]] -> Assertion
33 decodesWithAs opts input expected =
34 assertResult input expected $ decodeWith opts input
35
36 assertResult :: BL.ByteString -> [[B.ByteString]]
37 -> Either String (V.Vector (V.Vector B.ByteString)) -> Assertion
38 assertResult input expected res = case res of
c528fe9 Johan Tibell Add test for embedded newlines and quoted quotes
authored
39 Right r -> V.fromList (map V.fromList expected) @=? r
da2cd94 Johan Tibell Clean up tests
authored
40 Left err -> assertFailure $
41 " input: " ++ show (BL8.unpack input) ++ "\n" ++
42 "parse error: " ++ err
1fae7b8 Johan Tibell Add unit test
authored
43
90bbf52 Johan Tibell Refactor tests to be more readable
authored
44 encodesAs :: [[B.ByteString]] -> BL.ByteString -> Assertion
45 encodesAs input expected =
8f87940 Johan Tibell Implement encodeByHeader and fix a bug in escape
authored
46 encode (V.fromList (map V.fromList input)) @?= expected
47
fe8fba2 Johan Tibell Add test for encoding with custom delimiter
authored
48 encodesWithAs :: EncodeOptions -> [[B.ByteString]] -> BL.ByteString -> Assertion
49 encodesWithAs opts input expected =
50 encodeWith opts (V.fromList (map V.fromList input)) @?= expected
51
dd3dda1 Johan Tibell encodeByHeader: Fix bug where header was omitted
authored
52 namedEncodesAs :: [B.ByteString] -> [[(B.ByteString, B.ByteString)]]
53 -> BL.ByteString -> Assertion
54 namedEncodesAs hdr input expected =
6f22b50 Johan Tibell Rename byHeader functions to byName
authored
55 encodeByName (V.fromList hdr)
bc4db86 Johan Tibell Recreate a file that was accidentally deleted
authored
56 (V.fromList $ map HM.fromList input) @?= expected
dd3dda1 Johan Tibell encodeByHeader: Fix bug where header was omitted
authored
57
87a4daf Johan Tibell Add tests for name-based decoding
authored
58 namedDecodesAs :: BL.ByteString -> [B.ByteString]
59 -> [[(B.ByteString, B.ByteString)]] -> Assertion
6f22b50 Johan Tibell Rename byHeader functions to byName
authored
60 namedDecodesAs input ehdr expected = case decodeByName input of
87a4daf Johan Tibell Add tests for name-based decoding
authored
61 Right r -> (V.fromList ehdr, expected') @=? r
62 Left err -> assertFailure $
63 " input: " ++ show (BL8.unpack input) ++ "\n" ++
64 "parse error: " ++ err
65 where
bc4db86 Johan Tibell Recreate a file that was accidentally deleted
authored
66 expected' = V.fromList $ map HM.fromList expected
87a4daf Johan Tibell Add tests for name-based decoding
authored
67
c528fe9 Johan Tibell Add test for embedded newlines and quoted quotes
authored
68 testRfc4180 :: Assertion
90bbf52 Johan Tibell Refactor tests to be more readable
authored
69 testRfc4180 = (BL8.pack $
c528fe9 Johan Tibell Add test for embedded newlines and quoted quotes
authored
70 "#field1,field2,field3\n" ++
a334a56 Johan Tibell Filter blank lines and add more tests
authored
71 "\"aaa\",\"bb\n" ++
c528fe9 Johan Tibell Add test for embedded newlines and quoted quotes
authored
72 "b\",\"ccc\"\n" ++
73 "\"a,a\",\"b\"\"bb\",\"ccc\"\n" ++
74 "zzz,yyy,xxx\n")
90bbf52 Johan Tibell Refactor tests to be more readable
authored
75 `decodesAs`
c528fe9 Johan Tibell Add test for embedded newlines and quoted quotes
authored
76 [["#field1", "field2", "field3"],
77 ["aaa", "bb\nb", "ccc"],
78 ["a,a", "b\"bb", "ccc"],
79 ["zzz", "yyy", "xxx"]]
80
3632111 Johan Tibell Refactor tests
authored
81 positionalTests :: [TF.Test]
82 positionalTests =
01cd3a2 Johan Tibell Fix typo
authored
83 [ testGroup "encode" $ map encodeTest
f41607c Johan Tibell More test refactoring
authored
84 [ ("simple", [["abc"]], "abc\r\n")
85 , ("quoted", [["\"abc\""]], "\"\"\"abc\"\"\"\r\n")
86 , ("quote", [["a\"b"]], "\"a\"\"b\"\r\n")
87 , ("quotedQuote", [["\"a\"b\""]], "\"\"\"a\"\"b\"\"\"\r\n")
88 , ("leadingSpace", [[" abc"]], "\" abc\"\r\n")
89 , ("comma", [["abc,def"]], "\"abc,def\"\r\n")
90 , ("twoFields", [["abc","def"]], "abc,def\r\n")
91 , ("twoRecords", [["abc"], ["def"]], "abc\r\ndef\r\n")
92 , ("newline", [["abc\ndef"]], "\"abc\ndef\"\r\n")
8f87940 Johan Tibell Implement encodeByHeader and fix a bug in escape
authored
93 ]
fe8fba2 Johan Tibell Add test for encoding with custom delimiter
authored
94 , testGroup "encodeWith"
95 [ testCase "tab-delim" $ encodesWithAs (defEnc { encDelimiter = 9 })
96 [["1", "2"]] "1\t2\r\n"
97 ]
3632111 Johan Tibell Refactor tests
authored
98 , testGroup "decode" $ map decodeTest
99 [ ("simple", "a,b,c\n", [["a", "b", "c"]])
100 , ("crlf", "a,b\r\nc,d\r\n", [["a", "b"], ["c", "d"]])
101 , ("noEol", "a,b,c", [["a", "b", "c"]])
102 , ("blankLine", "a,b,c\n\nd,e,f\n\n",
103 [["a", "b", "c"], ["d", "e", "f"]])
104 , ("leadingSpace", " a, b, c\n", [[" a", " b", " c"]])
105 ] ++ [testCase "rfc4180" testRfc4180]
743d226 Johan Tibell Fix bug in custom field delimiter parsing
authored
106 , testGroup "decodeWith"
fe8fba2 Johan Tibell Add test for encoding with custom delimiter
authored
107 [ testCase "tab-delim" $ decodesWithAs (defDec { decDelimiter = 9 })
108 "1\t2" [["1", "2"]]
743d226 Johan Tibell Fix bug in custom field delimiter parsing
authored
109 ]
2c3454e Johan Tibell Fix parsing bugs
authored
110 ]
f41607c Johan Tibell More test refactoring
authored
111 where
112 encodeTest (name, input, expected) =
113 testCase name $ input `encodesAs` expected
3632111 Johan Tibell Refactor tests
authored
114 decodeTest (name, input, expected) =
115 testCase name $ input `decodesAs` expected
fe8fba2 Johan Tibell Add test for encoding with custom delimiter
authored
116 defEnc = defaultEncodeOptions
117 defDec = defaultDecodeOptions
f41607c Johan Tibell More test refactoring
authored
118
119 nameBasedTests :: [TF.Test]
87a4daf Johan Tibell Add tests for name-based decoding
authored
120 nameBasedTests =
121 [ testGroup "encode" $ map encodeTest
122 [ ("simple", ["field"], [[("field", "abc")]], "field\r\nabc\r\n")
123 , ("twoFields", ["field1", "field2"],
124 [[("field1", "abc"), ("field2", "def")]],
125 "field1,field2\r\nabc,def\r\n")
126 , ("twoRecords", ["field"], [[("field", "abc")], [("field", "def")]],
127 "field\r\nabc\r\ndef\r\n")
128 ]
129 , testGroup "decode" $ map decodeTest
130 [("simple", "field\r\nabc\r\n", ["field"], [[("field", "abc")]])
131 , ("twoFields", "field1,field2\r\nabc,def\r\n", ["field1", "field2"],
132 [[("field1", "abc"), ("field2", "def")]])
133 , ("twoRecords", "field\r\nabc\r\ndef\r\n", ["field"],
134 [[("field", "abc")], [("field", "def")]])
135 ]
dd3dda1 Johan Tibell encodeByHeader: Fix bug where header was omitted
authored
136 ]
137 where
138 encodeTest (name, hdr, input, expected) =
139 testCase name $ namedEncodesAs hdr input expected
87a4daf Johan Tibell Add tests for name-based decoding
authored
140 decodeTest (name, input, hdr, expected) =
141 testCase name $ namedDecodesAs input hdr expected
1fae7b8 Johan Tibell Add unit test
authored
142
875fd47 Johan Tibell Add round-trip unit tests
authored
143 ------------------------------------------------------------------------
144 -- Conversion tests
145
146 instance Arbitrary B.ByteString where
147 arbitrary = B.pack `fmap` arbitrary
148
149 instance Arbitrary BL.ByteString where
150 arbitrary = BL.fromChunks `fmap` arbitrary
151
152 instance Arbitrary T.Text where
153 arbitrary = T.pack `fmap` arbitrary
154
155 instance Arbitrary LT.Text where
156 arbitrary = LT.fromChunks `fmap` arbitrary
157
74b3f35 Johan Tibell Fix test bug
authored
158 -- A single column with an empty string is indistinguishable from an
159 -- empty line (which we will ignore.) We therefore encode at least two
160 -- columns.
875fd47 Johan Tibell Add round-trip unit tests
authored
161 roundTrip :: (Eq a, FromField a, ToField a) => a -> Bool
74b3f35 Johan Tibell Fix test bug
authored
162 roundTrip x = case decode (encode (V.singleton (x, dummy))) of
163 Right v | V.length v == 1 -> let (y, _ :: Char) = v ! 0 in x == y
164 _ -> False
165 where dummy = 'a'
166
80d4bcc Johan Tibell Add test for bounday conditions
authored
167 boundary :: forall a. (Bounded a, Eq a, FromField a, ToField a) => a -> Bool
168 boundary _dummy = roundTrip (minBound :: a) && roundTrip (maxBound :: a)
169
74b3f35 Johan Tibell Fix test bug
authored
170 -- TODO: Right now we only encode ASCII properly. Should we support
171 -- UTF-8? Arbitrary byte strings?
875fd47 Johan Tibell Add round-trip unit tests
authored
172
173 conversionTests :: [TF.Test]
174 conversionTests =
3632111 Johan Tibell Refactor tests
authored
175 [ testGroup "roundTrip"
176 [ testProperty "Char" (roundTrip :: Char -> Bool)
177 , testProperty "ByteString" (roundTrip :: B.ByteString -> Bool)
178 , testProperty "Int" (roundTrip :: Int -> Bool)
179 , testProperty "Integer" (roundTrip :: Integer -> Bool)
180 , testProperty "Int8" (roundTrip :: Int8 -> Bool)
181 , testProperty "Int16" (roundTrip :: Int16 -> Bool)
182 , testProperty "Int32" (roundTrip :: Int32 -> Bool)
183 , testProperty "Int64" (roundTrip :: Int64 -> Bool)
184 , testProperty "Word" (roundTrip :: Word -> Bool)
185 , testProperty "Word8" (roundTrip :: Word8 -> Bool)
186 , testProperty "Word16" (roundTrip :: Word16 -> Bool)
187 , testProperty "Word32" (roundTrip :: Word32 -> Bool)
188 , testProperty "Word64" (roundTrip :: Word64 -> Bool)
189 , testProperty "lazy ByteString"
190 (roundTrip :: BL.ByteString -> Bool)
191 , testProperty "Text" (roundTrip :: T.Text -> Bool)
192 , testProperty "lazy Text" (roundTrip :: LT.Text -> Bool)
193 ]
194 , testGroup "boundary"
195 [ testProperty "Int" (boundary (undefined :: Int))
196 , testProperty "Int8" (boundary (undefined :: Int8))
197 , testProperty "Int16" (boundary (undefined :: Int16))
198 , testProperty "Int32" (boundary (undefined :: Int32))
199 , testProperty "Int64" (boundary (undefined :: Int64))
200 , testProperty "Word" (boundary (undefined :: Word))
201 , testProperty "Word8" (boundary (undefined :: Word8))
202 , testProperty "Word16" (boundary (undefined :: Word16))
203 , testProperty "Word32" (boundary (undefined :: Word32))
204 , testProperty "Word64" (boundary (undefined :: Word64))
205 ]
875fd47 Johan Tibell Add round-trip unit tests
authored
206 ]
207
208 ------------------------------------------------------------------------
209 -- Test harness
210
211 allTests :: [TF.Test]
3632111 Johan Tibell Refactor tests
authored
212 allTests = [ testGroup "positional" positionalTests
213 , testGroup "named" nameBasedTests
214 , testGroup "conversion" conversionTests
215 ]
875fd47 Johan Tibell Add round-trip unit tests
authored
216
1fae7b8 Johan Tibell Add unit test
authored
217 main :: IO ()
218 main = defaultMain allTests
Something went wrong with that request. Please try again.