Skip to content

Commit 212c324

Browse files
authored
Merge pull request #1035 from haskell/issue-1013-space-before-zulu
Resolves #1013: Don't accept space before Zulu/TZ offset
2 parents 14d796e + 64d4c5f commit 212c324

File tree

2 files changed

+20
-12
lines changed

2 files changed

+20
-12
lines changed

attoparsec-iso8601/src/Data/Attoparsec/Time.hs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ module Data.Attoparsec.Time
2424
) where
2525

2626
import Control.Applicative ((<|>))
27-
import Control.Monad (void, when)
28-
import Data.Attoparsec.Text (Parser, char, digit, option, anyChar, peekChar, peekChar', takeWhile1, satisfy)
27+
import Data.Attoparsec.Text (Parser, char, digit, option, anyChar, peekChar, takeWhile1, satisfy)
2928
import Data.Bits ((.&.))
3029
import Data.Char (isDigit, ord)
3130
import Data.Fixed (Pico, Fixed (..))
@@ -136,8 +135,6 @@ seconds = do
136135
-- zero. (This makes some speedups possible.)
137136
timeZone :: Parser (Maybe Local.TimeZone)
138137
timeZone = do
139-
let maybeSkip c = do ch <- peekChar'; when (ch == c) (void anyChar)
140-
maybeSkip ' '
141138
ch <- satisfy $ \c -> c == 'Z' || c == '+' || c == '-'
142139
if ch == 'Z'
143140
then return Nothing

tests/UnitTests.hs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,14 @@ import Data.Maybe (fromMaybe)
5454
import Data.Scientific (Scientific, scientific)
5555
import Data.Tagged (Tagged(..))
5656
import Data.Text (Text)
57-
import Data.Time (UTCTime)
57+
import Data.Time (UTCTime, ZonedTime)
5858
import Data.Time.Format.Compat (parseTimeM, defaultTimeLocale)
5959
import GHC.Generics (Generic)
6060
import GHC.Generics.Generically (Generically (..))
6161
import Instances ()
6262
import Numeric.Natural (Natural)
6363
import Test.Tasty (TestTree, testGroup)
64-
import Test.Tasty.HUnit (Assertion, assertFailure, assertEqual, testCase, (@?=))
64+
import Test.Tasty.HUnit (Assertion, assertFailure, assertEqual, testCase, testCaseSteps, (@?=))
6565
import Text.Printf (printf)
6666
import UnitTests.NullaryConstructors (nullaryConstructors)
6767
import qualified Data.ByteString as S
@@ -188,8 +188,8 @@ utcTimeGood = do
188188

189189
-- Test that a few non-timezone qualified timestamp formats get
190190
-- rejected if decoding to UTCTime.
191-
utcTimeBad :: Assertion
192-
utcTimeBad = do
191+
utcTimeBad :: (String -> IO ()) -> Assertion
192+
utcTimeBad info = do
193193
verifyFailParse "2000-01-01T12:13:00" -- missing Zulu time not allowed (some TZ required)
194194
verifyFailParse "2000-01-01 12:13:00" -- missing Zulu time not allowed (some TZ required)
195195
verifyFailParse "2000-01-01" -- date only not OK
@@ -199,10 +199,21 @@ utcTimeBad = do
199199
verifyFailParse "2015-01-03 12:13:00.Z" -- decimal at the end but no digits
200200
verifyFailParse "2015-01-03 12:13.000Z" -- decimal at the end, but no seconds
201201
verifyFailParse "2015-01-03 23:59:61Z" -- exceeds allowed seconds per day
202+
verifyFailParse "2015-01-03 12:13:00 Z" -- space before Zulu
203+
verifyFailParse "2015-01-03 12:13:00 +00:00" -- space before offset
202204
where
203-
verifyFailParse (s :: LT.Text) =
204-
let (dec :: Maybe UTCTime) = decode . LT.encodeUtf8 $ LT.concat ["\"", s, "\""] in
205-
assertEqual "verify failure" Nothing dec
205+
verifyFailParse :: LT.Text -> Assertion
206+
verifyFailParse s = do
207+
info (LT.unpack s)
208+
let bs = LT.encodeUtf8 $ LT.concat ["\"", s, "\""]
209+
let decU = decode bs :: Maybe UTCTime
210+
let decZ = decode bs :: Maybe ZonedTime
211+
assertIsNothing "verify failure UTCTime" decU
212+
assertIsNothing "verify failure ZonedTime" decZ
213+
214+
assertIsNothing :: Show a => String -> Maybe a -> Assertion
215+
assertIsNothing _ Nothing = return ()
216+
assertIsNothing err (Just a) = assertFailure $ err ++ " " ++ show a
206217

207218
-- Non identifier keys should be escaped & enclosed in brackets
208219
formatErrorExample :: Assertion
@@ -787,7 +798,7 @@ tests = testGroup "unit" [
787798
]
788799
, testGroup "utctime" [
789800
testCase "good" utcTimeGood
790-
, testCase "bad" utcTimeBad
801+
, testCaseSteps "bad" utcTimeBad
791802
]
792803
, testGroup "formatError" [
793804
testCase "example 1" formatErrorExample

0 commit comments

Comments
 (0)