git.iko.soy/typeable/postgresql-simple
on master help sign in
119 lines 4.3 kB history raw
1{-# LANGUAGE QuasiQuotes #-}
3{-
5Testing strategies:
7fromString . toString == id ** Todo?
9toString . fromString == almost id ** Todo?
11postgresql -> haskell -> postgresql * Done
13haskell -> postgresql -> haskell ** Todo?
15But still, what we really want to establish is that the two values
16correspond; for example, a conversion that consistently added hour
17when printed to a string and subtracted an hour when parsed from string
18would still pass these tests.
21Right now, we are checking that 1400+ timestamps in the range of 1860 to
222060 round trip from postgresql to haskell and back in 5 different timezones.
23In addition to UTC, the four timezones were selected so that 2 have a positive
24offset, and 2 have a negative offset, and that 2 have an offset of a
25whole number of hours, while the other two do not.
27It may be worth adding a few more timezones to ensure better test coverage.
29We are checking a handful of selected timestamps to ensure we hit
30various corner-cases in the code, in addition to 1400 timestamps randomly
31generated with granularity of seconds down to microseconds in powers of ten.
33-}
35module Time (testTime) where
37import Common
38import Control.Monad(forM_, replicateM_)
39import Data.Time.Compat
40import Data.ByteString(ByteString)
41import Database.PostgreSQL.Simple.SqlQQ
43numTests :: Int
44numTests = 200
46testTime :: TestEnv -> Assertion
47testTime env@TestEnv{..} = do
48 initializeTable env
49 execute_ conn "SET timezone TO 'UTC'"
50 checkRoundTrips env "1860-01-01 00:00:00+00"
51 execute_ conn "SET timezone TO 'America/Chicago'" -- -5:00
52 checkRoundTrips env "1883-11-18 12:00:00-06"
53 execute_ conn "SET timezone TO 'Asia/Tokyo'" -- +9:00
54 checkRoundTrips env "1888-01-01 00:00:00+09"
55 execute_ conn "SET timezone TO 'Asia/Kathmandu'" -- +5:45
56 checkRoundTrips env "1919-12-31 23:48:44+05:30"
57 execute_ conn "SET timezone TO 'America/St_Johns'" -- -3:30
58 checkRoundTrips env "1935-03-30 00:00:52-03:30"
60initializeTable :: TestEnv -> IO ()
61initializeTable TestEnv{..} = withTransaction conn $ do
62 execute_ conn
63 [sql| CREATE TEMPORARY TABLE testtime
64 ( x serial, y timestamptz, PRIMARY KEY(x) ) |]
66 let test :: ByteString -> IO () = \x -> do
67 execute conn [sql|
68 INSERT INTO testtime (y) VALUES (?)
69 |] (Only x)
70 return ()
71 -- America/Chicago
72 test "1883-11-18 11:59:59-05:50:36"
73 test "1883-11-18 12:09:23-05:50:36"
74 test "1883-11-18 12:00:00-06"
75 -- Asia/Tokyo
76 test "1887-12-31 23:59:59+09:18:59"
77 test "1888-01-01 00:18:58+09:18:59"
78 test "1888-01-01 00:00:00+09"
79 -- Asia/Kathmandu
80 test "1919-12-31 23:59:59+05:41:16"
81 test "1919-12-31 23:48:44+05:30"
82 test "1985-12-31 23:59:59+05:30"
83 test "1986-01-01 00:15:00+05:45"
84 -- America/St_Johns
85 test "1935-03-29 23:59:59-03:30:52"
86 test "1935-03-30 00:00:52-03:30"
88 -- While the above special cases are probably a decent start, there
89 -- are probably more that are well worth adding to ensure better
90 -- coverage.
92 let pop :: ByteString -> Double -> IO () = \x y ->
93 replicateM_ numTests $ execute conn
94 [sql| INSERT INTO testtime (y) VALUES
95 ('1860-01-01 00:00:00+00'::timestamptz
96 + ?::interval * ROUND(RANDOM() * ?)) |] (x,y)
97 pop "1 microsecond" 6.3113904e15
98 pop "10 microseconds" 6.3113904e14
99 pop "100 microseconds" 6.3113904e13
100 pop "1 millisecond" 6.3113904e12
101 pop "10 milliseconds" 6.3113904e11
102 pop "100 milliseconds" 6.3113904e10
103 pop "1 second" 6.3113904e9
105checkRoundTrips :: TestEnv -> ByteString -> IO ()
106checkRoundTrips TestEnv{..} limit = do
107 yxs :: [(UTCTime, Int)] <- query_ conn [sql| SELECT y, x FROM testtime |]
108 forM_ yxs $ \yx -> do
109 res <- query conn [sql| SELECT y=? FROM testtime WHERE x=? |] yx
110 assertBool "UTCTime did not round-trip from SQL to Haskell and back" $
111 res == [Only True]
113 yxs :: [(ZonedTime, Int)] <- query conn [sql|
114 SELECT y, x FROM testtime WHERE y > ?
115 |] (Only limit)
116 forM_ yxs $ \yx -> do
117 res <- query conn [sql| SELECT y=? FROM testtime WHERE x=? |] yx
118 assertBool "ZonedTime did not round-trip from SQL to Haskell and back" $
119 res == [Only True]