Skip to content

Commit deefb99

Browse files
committed
add tests
1 parent 393ca74 commit deefb99

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+441
-0
lines changed

test/FileSpec.hs

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
module FileSpec (spec) where
2+
3+
import Data.Char (isSpace)
4+
import System.IO
5+
import Test.Hspec (Spec, describe, it, shouldBe, shouldReturn)
6+
7+
import File
8+
import Option
9+
10+
spec :: Spec
11+
spec = do
12+
readFromFileSpec
13+
detectSplitterSpec
14+
splitFixedSizeSpec
15+
16+
readFromFileSpec :: Spec
17+
readFromFileSpec =
18+
describe "readFromFile" $ do
19+
let opts = Option { skipHeader = True,
20+
outputHeader = False,
21+
delimiter = Nothing,
22+
tabDelimited = False,
23+
outputDelimiter = Nothing,
24+
tabDelimitedOutput = False,
25+
keepLeadingWhiteSpace = False,
26+
gzipped = False,
27+
queryFile = Nothing,
28+
query = Nothing }
29+
30+
it "should read from a test file" $ do
31+
handle <- openFile "test/tests/basic.csv" ReadMode
32+
let expected = (["foo", "bar", "baz"], [["a0", "1", "a2"], ["b0", "3", "b2"], ["c0", "", "c2"]])
33+
readFromFile opts handle `shouldReturn` expected
34+
hClose handle
35+
36+
it "should read from a gzipped file" $ do
37+
handle <- openFile "test/tests/basic.csv.gz" ReadMode
38+
let expected = (["foo", "bar", "baz"], [["a0", "1", "a2"], ["b0", "3", "b2"], ["c0", "", "c2"]])
39+
readFromFile (opts { gzipped = True }) handle `shouldReturn` expected
40+
hClose handle
41+
42+
it "should read from a test file which contains a multiline cell" $ do
43+
handle <- openFile "test/tests/multiline.csv" ReadMode
44+
let expected = (["foo", "bar", "baz", "qux", "quux"], [["a0", "1", "a2\nb0\",3,\"b2\nc0", "", "c2"]])
45+
readFromFile opts handle `shouldReturn` expected
46+
hClose handle
47+
48+
detectSplitterSpec :: Spec
49+
detectSplitterSpec =
50+
describe "detectSplitter" $ do
51+
52+
it "should detect the column splitter space" $ do
53+
let (headLine, secondLine) = ("c0 c1 c2 c3 c4", "0 1 2 3 4")
54+
detectSplitter headLine secondLine ' ' `shouldBe` True
55+
detectSplitter headLine secondLine '\t' `shouldBe` True
56+
57+
it "should detect the column splitter comma" $ do
58+
let (headLine, secondLine) = ("c0,c1,c2,c3,c4", "0,1,2,3,4")
59+
detectSplitter headLine secondLine ',' `shouldBe` True
60+
61+
it "should detect the column splitter comma even if the column title has spaces" $ do
62+
let (headLine, secondLine) = ("foo bar baz,qux quux,hoge huga,cmd", "100,200,300,foo bar baz qux")
63+
detectSplitter headLine secondLine ',' `shouldBe` True
64+
65+
splitFixedSizeSpec :: Spec
66+
splitFixedSizeSpec =
67+
describe "splitFixedSize" $ do
68+
69+
it "should split the String with isSpace" $ do
70+
let (input, expected) = ("c0 c1 c2", [ "c0", "c1", "c2" ])
71+
splitFixedSize isSpace 0 input `shouldBe` expected
72+
73+
it "should ignore the successive spaces when splitting with isSpace" $ do
74+
let (input, expected) = ("c0 c1 c2 \t\t c3", [ "c0", "c1", "c2", "c3" ])
75+
splitFixedSize isSpace 0 input `shouldBe` expected
76+
77+
it "should take the column size into account when splitting with isSpace" $ do
78+
let (input, (n1, expected1), (n2, expected2), (n3, expected3), (n4, expected4))
79+
= ("c0 c1 c2 \t\t c3 c4 c5 ",
80+
(1, [ "c0 c1 c2 \t\t c3 c4 c5 " ]),
81+
(4, [ "c0", "c1", "c2", "c3 c4 c5 " ]),
82+
(6, [ "c0", "c1", "c2", "c3", "c4", "c5 " ]),
83+
(9, [ "c0", "c1", "c2", "c3", "c4", "c5", "", "", "" ]))
84+
splitFixedSize isSpace n1 input `shouldBe` expected1
85+
splitFixedSize isSpace n2 input `shouldBe` expected2
86+
splitFixedSize isSpace n3 input `shouldBe` expected3
87+
splitFixedSize isSpace n4 input `shouldBe` expected4
88+
89+
it "should split the String with (==',')" $ do
90+
let (input, expected) = ("c0,c1,c2", [ "c0", "c1", "c2" ])
91+
splitFixedSize (==',') 0 input `shouldBe` expected
92+
93+
it "should not ignore the successive commas when splitting with (==',')" $ do
94+
let (input, expected) = ("c0,c1,c2,,c3,,,c4", [ "c0", "c1", "c2", "", "c3", "", "", "c4" ])
95+
splitFixedSize (==',') 0 input `shouldBe` expected
96+
97+
it "should take the column size into account when splitting with (==',')" $ do
98+
let (input, (n1, expected1), (n2, expected2), (n3, expected3), (n4, expected4))
99+
= ("c0,c1,,c2,foo bar baz,c4",
100+
(1, [ "c0,c1,,c2,foo bar baz,c4" ]),
101+
(4, [ "c0", "c1", "", "c2,foo bar baz,c4" ]),
102+
(6, [ "c0", "c1", "", "c2", "foo bar baz", "c4" ]),
103+
(9, [ "c0", "c1", "", "c2", "foo bar baz", "c4", "", "", "" ]))
104+
splitFixedSize (==',') n1 input `shouldBe` expected1
105+
splitFixedSize (==',') n2 input `shouldBe` expected2
106+
splitFixedSize (==',') n3 input `shouldBe` expected3
107+
splitFixedSize (==',') n4 input `shouldBe` expected4

test/MainSpec.hs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module MainSpec (spec) where
2+
3+
import Control.Applicative
4+
import Control.Monad
5+
import System.IO
6+
import System.Process
7+
import Test.Hspec (Spec, describe, it, shouldReturn)
8+
9+
spec :: Spec
10+
spec = qhsSpec
11+
12+
qhsSpec :: Spec
13+
qhsSpec =
14+
15+
describe "qhs" $ do
16+
17+
let tests = [
18+
"basic", "columns", "stdin", "stdin_hyphen", "header", "where",
19+
"count", "is_null", "not_null", "output_header", "tab", "tab2",
20+
"spaces", "output_delimiter", "tab_delimited_output", "multiline",
21+
"query_file", "gzip", "gzip_stdin", "avg", "sum", "avg_sum", "seq",
22+
"group", "group_sum", "empty_query", "empty_query_file", "concat",
23+
"join", "invalid", "version"
24+
]
25+
26+
forM_ tests $ \test -> do
27+
28+
it ("should be executed correctly: " ++ test) $ do
29+
let cp = (shell ("bash " ++ test ++ ".sh")) {
30+
cwd = Just "test/tests",
31+
std_out = CreatePipe,
32+
std_err = CreatePipe
33+
}
34+
(_, Just out, Just err, _) <- createProcess cp
35+
hSetBuffering out NoBuffering
36+
hSetBuffering err NoBuffering
37+
outExpected <- readFile $ "test/tests/" ++ test ++ ".out"
38+
liftA2 (++) (hGetContents out) (hGetContents err) `shouldReturn` outExpected

test/ParserSpec.hs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
module ParserSpec (spec) where
2+
3+
import Data.Either
4+
import qualified Data.Map as Map
5+
import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)
6+
7+
import Parser
8+
9+
spec :: Spec
10+
spec = do
11+
replaceTableNamesSpec
12+
roughlyExtractTableNamesSpec
13+
replaceBackTableNamesSpec
14+
extractTableNamesSpec
15+
16+
replaceTableNamesSpec :: Spec
17+
replaceTableNamesSpec =
18+
describe "replaceTableNames" $ do
19+
20+
it "should replace the file names with table names" $ do
21+
let query = "SELECT * FROM table0 WHERE c0 > 0"
22+
let expected1 = ("SELECT * FROM ttable WHERE c0 > 0",
23+
Map.fromList [("table0", "ttable")])
24+
replaceTableNames query `shouldBe` expected1
25+
26+
it "should replace multiple file names with table names" $ do
27+
let query = "SELECT * FROM ./src/table0.csv\nJOIN /tmp/table1.csv\tON c1 = c2 WHERE c0 > 0"
28+
let expected2 = ("SELECT * FROM tsrctable0csvWor\nJOIN ttmptable1csvWo\tON c1 = c2 WHERE c0 > 0",
29+
Map.fromList [("./src/table0.csv", "tsrctable0csvWor"),("/tmp/table1.csv", "ttmptable1csvWo")])
30+
replaceTableNames query `shouldBe` expected2
31+
32+
roughlyExtractTableNamesSpec :: Spec
33+
roughlyExtractTableNamesSpec =
34+
describe "roughlyExtractTableNames" $ do
35+
36+
it "should roughly extract table name" $ do
37+
roughlyExtractTableNames "SELECT * FROM table0 WHERE c0 > 0" `shouldBe` [ "table0" ]
38+
roughlyExtractTableNames "select * from table0 where c0 > 0" `shouldBe` [ "table0" ]
39+
40+
it "should roughly extract multiple table names" $ do
41+
roughlyExtractTableNames "SELECT * FROM table0 JOIN table1 ON c1 = c2 WHERE c0 > 0" `shouldBe` [ "table0", "table1" ]
42+
roughlyExtractTableNames "select * from table0 join table1 on c1 = c2 where c0 > 0" `shouldBe` [ "table0", "table1" ]
43+
44+
replaceBackTableNamesSpec :: Spec
45+
replaceBackTableNamesSpec =
46+
describe "replaceBackTableNames" $ do
47+
48+
it "should replace back table names to the file names" $ do
49+
let query = "SELECT * FROM table0 WHERE c0 > 0"
50+
let (query', tableMap) = replaceTableNames query
51+
replaceBackTableNames tableMap query' `shouldBe` query
52+
53+
it "should replace back multiple table names with the file names" $ do
54+
let query = "SELECT * FROM ./src/table0.csv\nJOIN /tmp/table1.csv\tON c1 = c2 WHERE c0 > 0"
55+
let (query', tableMap) = replaceTableNames query
56+
replaceBackTableNames tableMap query' `shouldBe` query
57+
58+
extractTableNamesSpec :: Spec
59+
extractTableNamesSpec =
60+
describe "extractTableNames" $ do
61+
62+
it "should extract table name" $ do
63+
extractTableNames "SELECT * FROM table0 WHERE c0 > 0" "" `shouldBe` Right [ "table0" ]
64+
extractTableNames "select * from table0 where c0 > 0" "" `shouldBe` Right [ "table0" ]
65+
66+
it "should extract multiple table names" $ do
67+
extractTableNames "SELECT * FROM table0 JOIN table1 ON c1 = c2 WHERE c0 > 0" "" `shouldBe` Right [ "table0", "table1" ]
68+
extractTableNames "select * from table0 join table1 on c1 = c2 where c0 > 0" "" `shouldBe` Right [ "table0", "table1" ]
69+
70+
it "should return a parse error" $ do
71+
extractTableNames "SELECT ** FROM table0 WHERE c0 > 0" "" `shouldSatisfy` isLeft
72+
extractTableNames "SELECT * FROM table0 WHERE > 0" "" `shouldSatisfy` isLeft

test/SQLSpec.hs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
module SQLSpec (spec) where
2+
3+
import Control.Monad
4+
import qualified Database.SQLite as SQLite
5+
import Test.Hspec (Spec, describe, it, shouldBe)
6+
7+
import SQL
8+
9+
spec :: Spec
10+
spec = do
11+
openCloseSpec
12+
tableSpec
13+
14+
openCloseSpec :: Spec
15+
openCloseSpec =
16+
describe "open, close" $ do
17+
18+
it "should not throw exception" $ do
19+
conn <- SQL.open ":memory:"
20+
SQL.close conn
21+
22+
tableSpec :: Spec
23+
tableSpec =
24+
describe "createTable, insertRow, execute" $ do
25+
26+
it "should create a table" $ do
27+
conn <- SQL.open ":memory:"
28+
let columns = ["foo", "bar", "baz", "qux"]
29+
let types = repeat $ SQLite.SQLChar Nothing
30+
_ <- SQL.createTable conn "test_table" columns types
31+
let entries = [ ["c0", "c1", "c2", "c3"],
32+
["d0", "d1", "d2", "d3"],
33+
["f0", "f1", "f2", "f3"] ]
34+
forM_ entries $ SQL.insertRow conn "test_table" columns types
35+
ret <- SQL.execute conn "SELECT * FROM test_table"
36+
ret `shouldBe` Right [map (zip columns) entries]
37+
SQL.close conn
38+
39+
it "should take care of null values in a number column" $ do
40+
conn <- SQL.open ":memory:"
41+
let columns = ["foo", "num", "bar", "baz"]
42+
let types = cycle [SQLite.SQLChar Nothing, SQLite.SQLInt SQLite.NORMAL False False]
43+
_ <- SQL.createTable conn "test_table" columns types
44+
let entries = [ ["c0", "2", "c2", "3"],
45+
["d0", "", "d2", "2"],
46+
["f0", "3", "f2", ""],
47+
["e0", "", "e2", "4"] ]
48+
forM_ entries $ SQL.insertRow conn "test_table" columns types
49+
ret0 <- SQL.execute conn "SELECT * FROM test_table"
50+
ret0 `shouldBe` Right [map (zip columns) entries]
51+
ret1 <- SQL.execute conn "SELECT * FROM test_table WHERE num IS NOT NULL"
52+
ret1 `shouldBe` Right [map (zip columns) [ e | e <- entries, e !! 1 /= ""]]
53+
ret2 <- SQL.execute conn "SELECT avg(num) FROM test_table"
54+
ret2 `shouldBe` Right [[[("avg(num)", "2.5")]]]
55+
ret3 <- SQL.execute conn "SELECT avg(baz) FROM test_table"
56+
ret3 `shouldBe` Right [[[("avg(baz)", "3.0")]]]
57+
SQL.close conn
58+
59+
it "can create a table when name and column names contain spaces" $ do
60+
conn <- SQL.open ":memory:"
61+
let columns = ["foo bar", "baz qux"]
62+
let types = repeat $ SQLite.SQLChar Nothing
63+
_ <- SQL.createTable conn "test table" columns types
64+
let entries = [ ["c0 c1", "c2 c3"],
65+
["d0 d1", "d2 d3"],
66+
["f0 f1", "f2 f3"] ]
67+
forM_ entries $ SQL.insertRow conn "test table" columns types
68+
ret0 <- SQL.execute conn "SELECT * FROM `test table`"
69+
ret0 `shouldBe` Right [map (zip columns) entries]
70+
ret1 <- SQL.execute conn "SELECT `foo bar` FROM `test table`"
71+
ret1 `shouldBe` Right [map (zip columns) (map (take 1) entries)]
72+
SQL.close conn

test/Spec.hs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

test/tests/avg.out

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2.0

test/tests/avg.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -H "SELECT avg(bar) FROM basic.csv"

test/tests/avg_sum.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
avg(bar) sum(bar)
2+
2.0 4

test/tests/avg_sum.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -H -O "SELECT avg(bar),sum(bar) FROM basic.csv"

test/tests/basic.csv

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo,bar,baz
2+
a0,1,a2
3+
b0,3,b2
4+
c0,,c2

test/tests/basic.csv.gz

64 Bytes
Binary file not shown.

test/tests/basic.out

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo bar baz
2+
a0 1 a2
3+
b0 3 b2
4+
c0 c2

test/tests/basic.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs "SELECT * FROM basic.csv"

test/tests/big.csv

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
foo,bar,baz
2+
a0,1,a2
3+
b1,2,b1
4+
c1,,c1
5+
a0,2,a1
6+
b0,1,b2
7+
c1,,c2
8+
a0,3,a3
9+
c1,,c3
10+
c0,,c1
11+
b1,2,b3
12+
c0,,c2
13+
a0,2,a3

test/tests/columns.out

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo baz
2+
a0 a2
3+
b0 b2
4+
c0 c2

test/tests/columns.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs "SELECT c1,c3 FROM basic.csv"

test/tests/concat.out

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
foo||baz
2+
a0a2
3+
b1b1
4+
a0a1
5+
b0b2
6+
a0a3
7+
b1b3
8+
a0a3

test/tests/concat.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -H -O "SELECT foo||baz FROM big.csv WHERE bar IS NOT NULL"

test/tests/count.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
COUNT(*)
2+
2

test/tests/count.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -H -O "SELECT COUNT(*) FROM basic.csv WHERE baz <> 'b2'"

test/tests/empty.sql

Whitespace-only changes.

test/tests/empty_query.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Query cannot be empty.
2+
For basic information, try the `--help' option.

test/tests/empty_query.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs ""

test/tests/empty_query_file.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Query cannot be empty.
2+
For basic information, try the `--help' option.

test/tests/empty_query_file.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -q empty.sql

test/tests/group.out

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo cnt
2+
a0 4
3+
c1 3
4+
b1 2

test/tests/group.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -H -O "SELECT foo,COUNT(*) cnt FROM big.csv GROUP BY foo ORDER BY cnt DESC LIMIT 3"

test/tests/group_sum.out

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo sum(bar) cnt
2+
a0 8 4
3+
b1 4 2
4+
b0 1 1

test/tests/group_sum.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -H -O "SELECT foo,sum(bar),COUNT(*) cnt FROM big.csv WHERE bar IS NOT NULL GROUP BY foo ORDER BY cnt DESC LIMIT 3"

test/tests/gzip.out

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
foo bar baz
2+
a0 1 a2
3+
b0 3 b2
4+
c0 c2

test/tests/gzip.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs "SELECT * FROM basic.csv.gz"

test/tests/gzip_stdin.out

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
a0 a2
2+
b0 b2

test/tests/gzip_stdin.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cat basic.csv.gz | qhs -H -z "SELECT foo,baz FROM - WHERE bar IS NOT NULL"

test/tests/header.out

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
a0 a2
2+
b0 b2
3+
c0 c2

test/tests/header.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qhs -H "SELECT foo,baz FROM basic.csv"

0 commit comments

Comments
 (0)