packages feed

hedn 0.1.6.0 → 0.1.7.0

raw patch · 8 files changed

+669/−283 lines, 8 filesdep +QuickCheckdep +hspecdep +old-localedep ~HUnitdep ~basedep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, hspec, old-locale, template-haskell, time

Dependency ranges changed: HUnit, base, bytestring, containers, deepseq

API changes (from Hackage documentation)

+ Data.EDN.Types: instance NFData Value
+ Data.EDN.Types: instance NFData a => NFData (Tagged a)
+ Data.EDN.Types.Class: instance [incoherent] (FromEDN a, FromEDN b) => FromEDN (a, b)
+ Data.EDN.Types.Class: instance [incoherent] (FromEDN a, FromEDN b, FromEDN c) => FromEDN (a, b, c)
+ Data.EDN.Types.Class: instance [incoherent] (FromEDN a, FromEDN b, FromEDN c, FromEDN d) => FromEDN (a, b, c, d)
+ Data.EDN.Types.Class: instance [incoherent] (FromEDN a, FromEDN b, FromEDN c, FromEDN d, FromEDN e) => FromEDN (a, b, c, d, e)
+ Data.EDN.Types.Class: instance [incoherent] (FromEDN a, FromEDN b, FromEDN c, FromEDN d, FromEDN e, FromEDN f) => FromEDN (a, b, c, d, e, f)
+ Data.EDN.Types.Class: instance [incoherent] (FromEDN a, FromEDN b, FromEDN c, FromEDN d, FromEDN e, FromEDN f, FromEDN g) => FromEDN (a, b, c, d, e, f, g)
+ Data.EDN.Types.Class: instance [incoherent] (FromEDN a, FromEDN b, FromEDN c, FromEDN d, FromEDN e, FromEDN f, FromEDN g, FromEDN h) => FromEDN (a, b, c, d, e, f, g, h)
+ Data.EDN.Types.Class: instance [incoherent] (ToEDN a, ToEDN b) => ToEDN (a, b)
+ Data.EDN.Types.Class: instance [incoherent] (ToEDN a, ToEDN b, ToEDN c) => ToEDN (a, b, c)
+ Data.EDN.Types.Class: instance [incoherent] (ToEDN a, ToEDN b, ToEDN c, ToEDN d) => ToEDN (a, b, c, d)
+ Data.EDN.Types.Class: instance [incoherent] (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e) => ToEDN (a, b, c, d, e)
+ Data.EDN.Types.Class: instance [incoherent] (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e, ToEDN f) => ToEDN (a, b, c, d, e, f)
+ Data.EDN.Types.Class: instance [incoherent] (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e, ToEDN f, ToEDN g) => ToEDN (a, b, c, d, e, f, g)
+ Data.EDN.Types.Class: instance [incoherent] (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e, ToEDN f, ToEDN g, ToEDN h) => ToEDN (a, b, c, d, e, f, g, h)
+ Data.EDN.Types.Class: instance [incoherent] FromEDN Int
+ Data.EDN.Types.Class: instance [incoherent] FromEDN UTCTime
+ Data.EDN.Types.Class: instance [incoherent] ToEDN Int
+ Data.EDN.Types.Class: instance [incoherent] ToEDN UTCTime

Files

hedn.cabal view
@@ -1,8 +1,5 @@--- Initial hedn.cabal generated by cabal init.  For further documentation, --- see http://haskell.org/cabal/users-guide/- name:                hedn-version:             0.1.6.0+version:             0.1.7.0 synopsis:            EDN parsing and encoding homepage:            https://bitbucket.org/dpwiz/hedn license:             BSD3@@ -20,29 +17,50 @@  extra-source-files:   tests/Main.hs+  tests/Data/EDN/Test/*.hs+  tests/Data/EDN/Test/QuickCheck/TH.hs  flag developer   description: operate in developer mode   default: False  library-  exposed-modules:     Data.EDN, Data.EDN.Types, Data.EDN.Parser, Data.EDN.Encode, Data.EDN.Types.Class-  other-modules:       Data.Parser-  hs-source-dirs:      src/-  build-depends:       base ==4.*, attoparsec, text, bytestring, containers, vector, stringsearch, mtl, deepseq+  exposed-modules:+      Data.EDN,+      Data.EDN.Types,+      Data.EDN.Types.Class,+      Data.EDN.Parser,+      Data.EDN.Encode -  if flag(developer)-    ghc-options: -Werror-    ghc-prof-options: -auto-all+  other-modules:+      Data.Parser -  ghc-options: -O2 -Wall -fno-warn-unused-do-bind+  hs-source-dirs: src/+  build-depends:+      base ==4.*,+      attoparsec,+      text,+      bytestring >=0.10,+      containers,+      vector,+      stringsearch,+      mtl,+      deepseq,+      old-locale,+      time +--  if flag(developer)+--    ghc-options: -Werror -fhpc+--    ghc-prof-options: -auto-all +  ghc-options: -O2 -Wall -fno-warn-unused-do-bind+ Test-Suite tests   type:              exitcode-stdio-1.0   main-is:           Main.hs   hs-source-dirs:    tests/-  build-depends:     base, hedn, HUnit, bytestring, text, containers, vector+  build-depends:     base, hedn, bytestring, text, containers, vector, template-haskell, time,+                     QuickCheck >= 2.5.1, hspec == 1.5.*, HUnit >= 1.2.5   ghc-options:       -Wall  source-repository head
src/Data/EDN/Parser.hs view
@@ -10,20 +10,22 @@     parseValue, parseTagged ) where -import Prelude hiding (String, takeWhile)-import Data.Attoparsec.Char8 as A-import qualified Data.Attoparsec.Lazy as AL-import Data.Attoparsec.Combinator()-import Control.Applicative (pure, (<|>), (*>))-import qualified Data.ByteString.Char8 as BS+import           Control.Applicative        (pure, (*>), (<|>))+import           Data.Attoparsec.Char8      as A+import           Data.Attoparsec.Combinator ()+import qualified Data.Attoparsec.Lazy       as AL+import qualified Data.ByteString.Char8      as BS import qualified Data.ByteString.Lazy.Char8 as BSL-import qualified Data.Text as T-import qualified Data.Text.Encoding as TE-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TLE-import Data.ByteString.Search (replace)+import           Data.ByteString.Search     (replace)+import qualified Data.Text                  as T+import qualified Data.Text.Encoding         as TE+import qualified Data.Text.Lazy             as TL+import qualified Data.Text.Lazy.Encoding    as TLE+import           Prelude                    hiding (String, takeWhile) -import Data.EDN.Types (Value(..), Tagged(..), TaggedValue, makeVec, makeMap, makeSet)+import           Data.EDN.Types             (Tagged (..), TaggedValue,+                                             Value (..), makeMap, makeSet,+                                             makeVec)  isSpaceOrComma :: Char -> Bool isSpaceOrComma ' ' = True@@ -64,7 +66,14 @@     char '"'      if '\\' `BS.elem` x-        then return $! String . TE.decodeUtf8 . rep "\\\"" "\"". rep "\\\\" "\\" . rep "\\n" "\n" . rep "\\r" "\r" . rep "\\t" "\t" $ x+        then return $! String+                     . TE.decodeUtf8+                     . rep "\\\"" "\""+                     . rep "\\\\" "\\"+                     . rep "\\n" "\n"+                     . rep "\\r" "\r"+                     . rep "\\t" "\t"+                     $ x         else return $! String . TE.decodeUtf8 $ x      where rep f t s = BS.concat . BSL.toChunks $! replace (BS.pack f) (BS.pack t) s@@ -119,7 +128,9 @@ parseList = do     skipSoC     char '('+    A.skipSpace     vs <- parseTagged `sepBy` spaceOrComma+    A.skipSpace     char ')'     return $! List vs @@ -127,7 +138,9 @@ parseVector = do     skipSoC     char '['+    A.skipSpace     vs <- parseTagged `sepBy` spaceOrComma+    A.skipSpace     char ']'     return $! makeVec vs @@ -135,7 +148,9 @@ parseMap = do     skipSoC     char '{'+    A.skipSpace     pairs <- parseAssoc `sepBy` spaceOrComma+    A.skipSpace     char '}'     return $! makeMap pairs     where@@ -149,7 +164,9 @@     skipSoC     char '#'     char '{'+    A.skipSpace     vs <- parseTagged `sepBy` spaceOrComma+    A.skipSpace     char '}'     return $! makeSet vs 
src/Data/EDN/Types.hs view
@@ -25,6 +25,7 @@ ) where  import Data.String (IsString(..))+import Control.DeepSeq (NFData(..)) import Data.Text (Text) import qualified Data.Text as T import Data.ByteString.Char8 (ByteString)@@ -42,6 +43,10 @@     fmap f (NoTag v) = NoTag (f v)     fmap f (Tagged v ns t) = Tagged (f v) ns t +instance NFData a => NFData (Tagged a) where+    rnf (NoTag v) = rnf v+    rnf (Tagged v ns t) = rnf v `seq` rnf ns `seq` rnf t+ type TaggedValue = Tagged Value  type EDNList = [TaggedValue] -- ^ An EDN list (head:tail container).@@ -74,6 +79,20 @@ instance IsString (Tagged Value) where   fromString = string . T.pack   {-# INLINE fromString #-}++instance NFData Value where+  rnf (Map m) = rnf m+  rnf (Set s) = rnf s+  rnf (Vec v) = V.foldl' (\x y -> rnf y `seq` x) () v+  rnf (List l) = rnf l+  rnf (Floating f) = rnf f+  rnf (Integer i) = rnf i+  rnf (Symbol ns s) = rnf ns `seq` rnf s+  rnf (Keyword kw) = rnf kw+  rnf (String t) = rnf t+  rnf (Character c) = rnf c+  rnf (Boolean b) = rnf b+  rnf Nil = ()  -- | Basic EDN nil. nil :: TaggedValue
src/Data/EDN/Types/Class.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE OverloadedStrings, FlexibleInstances, IncoherentInstances #-}-+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE IncoherentInstances #-}+{-# LANGUAGE OverloadedStrings   #-} module Data.EDN.Types.Class (     -- * Type conversion     ToEDN(..), FromEDN(..), fromEDN, fromEDNv,@@ -11,23 +12,27 @@     (.=), (.:), (.:?), (.!=), typeMismatch ) where -import Control.Applicative (pure, (<$>))-import Control.Monad (liftM, liftM2)-import Data.Maybe (fromMaybe)-import qualified Data.Text as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Encoding as TE-import qualified Data.Text.Lazy.Encoding as TLE-import qualified Data.ByteString.Char8 as BS+import           Control.Applicative        (pure, (<$>), (<*>))+import           Control.Monad              (liftM, liftM2)+import qualified Data.ByteString.Char8      as BS import qualified Data.ByteString.Lazy.Char8 as BSL-import qualified Data.Vector as V-import qualified Data.Set as S-import qualified Data.Map as M+import qualified Data.Map                   as M+import           Data.Maybe                 (fromMaybe)+import           Data.Monoid                (First (..), mconcat)+import qualified Data.Set                   as S+import qualified Data.Text                  as T+import qualified Data.Text.Encoding         as TE+import qualified Data.Text.Lazy             as TL+import qualified Data.Text.Lazy.Encoding    as TLE+import           Data.Time.Clock            (UTCTime)+import           Data.Time.Format           (formatTime, parseTime)+import qualified Data.Vector                as V -import Data.Parser (Parser, Result)-import qualified Data.Parser as DP-import qualified Data.EDN.Parser as P-import qualified Data.EDN.Types as E+import qualified Data.EDN.Parser            as P+import qualified Data.EDN.Types             as E+import           Data.Parser                (Parser, Result)+import qualified Data.Parser                as DP+import           System.Locale              (defaultTimeLocale)  -- | A type that can be converted to JSON. class ToEDN a where@@ -59,8 +64,8 @@     {-# INLINE toEDN #-}  instance (FromEDN a) => (FromEDN (Maybe a)) where-    parseEDNv E.Nil = pure Nothing-    parseEDNv a = Just <$> parseEDNv a+    parseEDN (E.NoTag E.Nil) = pure Nothing+    parseEDN a = Just <$> parseEDN a     {-# INLINE parseEDNv #-}  instance (ToEDN a, ToEDN b) => ToEDN (Either a b) where@@ -178,6 +183,46 @@     parseEDNv v = typeMismatch "Integer" v     {-# INLINE parseEDNv #-} +instance ToEDN Int where+    toEDNv = E.Integer . fromIntegral+    {-# INLINE toEDNv #-}++instance FromEDN Int where+    parseEDNv (E.Integer i) = return (fromIntegral i)+    parseEDNv v = typeMismatch "Int" v+++showRFC3339 :: UTCTime -> String+showRFC3339 time =+    concat [fm "%FT%T." time+           ,  take 3 $ fm "%-q" time+           ,  "+00:00"]+  where+    fm s = formatTime defaultTimeLocale s++instance ToEDN UTCTime where+    toEDN time = E.Tagged (E.String . T.pack $ showRFC3339 time)+                          ""+                          "inst"+    {-# INLINE toEDN #-}++instance FromEDN UTCTime where+    parseEDN val@(E.Tagged (E.String ts) "" "inst") = do+        let result = getFirst . mconcat $ map (First . parseTime') validRFC3339+        case result of+          Just time -> return time+          Nothing -> typeMismatch "UTCTime" $ E.stripTag val+      where+        tsStr = T.unpack ts+        parseTime' fmt = parseTime defaultTimeLocale fmt tsStr+        validRFC3339 = [ "%FT%T%Q%z"+                       , "%FT%T%QZ"+                       , "%FT%T%z"+                       , "%FT%TZ" ]+    parseEDN v = typeMismatch "UTCTime" $ E.stripTag v+    {-# INLINE parseEDN #-}++ instance ToEDN a => ToEDN [a] where     toEDNv = E.List . map toEDN     {-# INLINE toEDNv #-}@@ -214,6 +259,146 @@     parseEDNv v = typeMismatch "Map" v     {-# INLINE parseEDNv #-} +instance (ToEDN a, ToEDN b) => ToEDN (a, b) where+    toEDNv (a, b) = E.Vec $! V.fromList [toEDN a, toEDN b]+    {-# INLINE toEDNv #-}++instance (FromEDN a, FromEDN b) => FromEDN (a, b) where+    parseEDNv v@(E.Vec vec)+      | (V.length vec == 2) = (,) <$> (parseEDN (vec V.! 0))+                                  <*> (parseEDN (vec V.! 1))+      | otherwise = typeMismatch "(a, b)" v+    parseEDNv v = typeMismatch "(a, b)" v+    {-# INLINE parseEDNv #-}++instance (ToEDN a, ToEDN b, ToEDN c) => ToEDN (a, b, c) where+    toEDNv (a, b, c) = E.Vec $! V.fromList [toEDN a, toEDN b, toEDN c]+    {-# INLINE toEDNv #-}++instance (FromEDN a, FromEDN b, FromEDN c) => FromEDN (a, b, c) where+    parseEDNv v@(E.Vec vec)+      | V.length vec == 3 = (,,) <$> (parseEDN (vec V.! 0))+                                 <*> (parseEDN (vec V.! 1))+                                 <*> (parseEDN (vec V.! 2))+      | otherwise = typeMismatch "(a, b, c)" v+    parseEDNv v = typeMismatch "(a, b, c)" v+    {-# INLINE parseEDNv #-}++instance (ToEDN a, ToEDN b, ToEDN c, ToEDN d) => ToEDN (a, b, c, d) where+    toEDNv (a, b, c, d) = E.Vec $! V.fromList [toEDN a, toEDN b, toEDN c, toEDN d]+    {-# INLINE toEDNv #-}++instance (FromEDN a, FromEDN b, FromEDN c, FromEDN d) => FromEDN (a, b, c, d) where+    parseEDNv v@(E.Vec vec)+      | V.length vec == 4 = (,,,) <$> (parseEDN (vec V.! 0))+                                  <*> (parseEDN (vec V.! 1))+                                  <*> (parseEDN (vec V.! 2))+                                  <*> (parseEDN (vec V.! 3))+      | otherwise = typeMismatch "(a, b, c, d)" v+    parseEDNv v = typeMismatch "(a, b, c, d)" v+    {-# INLINE parseEDNv #-}++instance (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e) => ToEDN (a, b, c, d, e) where+    toEDNv (a, b, c, d, e) = E.Vec $! V.fromList [+                               toEDN a+                             , toEDN b+                             , toEDN c+                             , toEDN d+                             , toEDN e ]+    {-# INLINE toEDNv #-}++instance (FromEDN a, FromEDN b, FromEDN c, FromEDN d, FromEDN e)+    => FromEDN (a, b, c, d, e) where+    parseEDNv v@(E.Vec vec)+      | V.length vec == 5 = (,,,,) <$> (parseEDN (vec V.! 0))+                                   <*> (parseEDN (vec V.! 1))+                                   <*> (parseEDN (vec V.! 2))+                                   <*> (parseEDN (vec V.! 3))+                                   <*> (parseEDN (vec V.! 4))+      | otherwise = typeMismatch "(a, b, c, d, e)" v+    parseEDNv v = typeMismatch "(a, b, c, d, e)" v+    {-# INLINE parseEDNv #-}++instance (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e, ToEDN f)+    => ToEDN (a, b, c, d, e, f) where+    toEDNv (a, b, c, d, e, f) = E.Vec $! V.fromList [+                               toEDN a+                             , toEDN b+                             , toEDN c+                             , toEDN d+                             , toEDN e+                             , toEDN f]+    {-# INLINE toEDNv #-}++instance (FromEDN a, FromEDN b, FromEDN c, FromEDN d, FromEDN e, FromEDN f)+    => FromEDN (a, b, c, d, e, f) where+    parseEDNv v@(E.Vec vec)+      | V.length vec == 6 = (,,,,,) <$> (parseEDN (vec V.! 0))+                                    <*> (parseEDN (vec V.! 1))+                                    <*> (parseEDN (vec V.! 2))+                                    <*> (parseEDN (vec V.! 3))+                                    <*> (parseEDN (vec V.! 4))+                                    <*> (parseEDN (vec V.! 5))+      | otherwise = typeMismatch "(a, b, c, d, e, f)" v+    parseEDNv v = typeMismatch "(a, b, c, d, e, f)" v+    {-# INLINE parseEDNv #-}++instance (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e, ToEDN f, ToEDN g)+    => ToEDN (a, b, c, d, e, f, g) where+    toEDNv (a, b, c, d, e, f, g) = E.Vec $! V.fromList [+                               toEDN a+                             , toEDN b+                             , toEDN c+                             , toEDN d+                             , toEDN e+                             , toEDN f+                             , toEDN g]+    {-# INLINE toEDNv #-}++instance (FromEDN a, FromEDN b, FromEDN c, FromEDN d, FromEDN e, FromEDN f, FromEDN g)+    => FromEDN (a, b, c, d, e, f, g) where+    parseEDNv v@(E.Vec vec)+      | V.length vec == 7 = (,,,,,,) <$> (parseEDN (vec V.! 0))+                                     <*> (parseEDN (vec V.! 1))+                                     <*> (parseEDN (vec V.! 2))+                                     <*> (parseEDN (vec V.! 3))+                                     <*> (parseEDN (vec V.! 4))+                                     <*> (parseEDN (vec V.! 5))+                                     <*> (parseEDN (vec V.! 6))+      | otherwise = typeMismatch "(a, b, c, d, e, f, g)" v+    parseEDNv v = typeMismatch "(a, b, c, d, e, f, g)" v+    {-# INLINE parseEDNv #-}++instance (ToEDN a, ToEDN b, ToEDN c, ToEDN d, ToEDN e, ToEDN f, ToEDN g, ToEDN h)+    => ToEDN (a, b, c, d, e, f, g, h) where+    toEDNv (a, b, c, d, e, f, g, h) = E.Vec $! V.fromList [+                               toEDN a+                             , toEDN b+                             , toEDN c+                             , toEDN d+                             , toEDN e+                             , toEDN f+                             , toEDN g+                             , toEDN h]+    {-# INLINE toEDNv #-}++instance (FromEDN a, FromEDN b, FromEDN c, FromEDN d,+          FromEDN e, FromEDN f, FromEDN g, FromEDN h)+    => FromEDN (a, b, c, d, e, f, g, h) where+    parseEDNv v@(E.Vec vec)+      | V.length vec == 8 = (,,,,,,,) <$> (parseEDN (vec V.! 0))+                                      <*> (parseEDN (vec V.! 1))+                                      <*> (parseEDN (vec V.! 2))+                                      <*> (parseEDN (vec V.! 3))+                                      <*> (parseEDN (vec V.! 4))+                                      <*> (parseEDN (vec V.! 5))+                                      <*> (parseEDN (vec V.! 6))+                                      <*> (parseEDN (vec V.! 7))+      | otherwise = typeMismatch "(a, b, c, d, e, f, g, h)" v+    parseEDNv v = typeMismatch "(a, b, c, d, e, f, g, h)" v+    {-# INLINE parseEDNv #-}++ instance ToEDN E.Value where     toEDNv = id @@ -281,7 +466,7 @@ -- from an object without affecting its validity and we know a default -- value to assign in that case.  If the key and value are mandatory, -- use '(.:)' instead.--- +-- -- Example usage: -- -- @ v1 <- o '.:?' \"opt_field_with_dfl\" .!= \"default_val\"@@ -314,10 +499,17 @@         E.Map _ -> "Map"         E.Set _ -> "Set" -mapMset :: (Monad m, Ord b) => (a -> m b) -> S.Set a -> m (S.Set b)+mapMset :: (Monad m, Ord b)+        => (a -> m b)+        -> S.Set a+        -> m (S.Set b) mapMset f s = mapM f (S.toList s) >>= return . S.fromList {-# INLINE mapMset #-} -mapMmap :: (Ord a2, Monad m) => (a1 -> m a2) -> (b1 -> m b2) -> M.Map a1 b1 -> m (M.Map a2 b2)+mapMmap :: (Ord a2, Monad m)+        => (a1 -> m a2)+        -> (b1 -> m b2)+        -> M.Map a1 b1+        -> m (M.Map a2 b2) mapMmap kf vf = liftM M.fromList . mapM (\(k, v) -> liftM2 (,) (kf k) (vf v)) . M.assocs {-# INLINE mapMmap #-}
+ tests/Data/EDN/Test/QuickCheck.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Data.EDN.Test.QuickCheck where++import           Data.EDN.Test.QuickCheck.TH+import           Data.Time                   (UTCTime)++import qualified Data.Time.Calendar          as Calendar+import           Data.Time.Clock             (UTCTime (..), UniversalTime (..),+                                              secondsToDiffTime)+import           Data.Time.LocalTime         (localTimeToUT1, localTimeToUTC,+                                              ut1ToLocalTime, utc,+                                              utcToLocalTime)++import qualified Test.QuickCheck             as QC++-- * UTCTime Arbitrary instance ------------------------------------------------++fromGregorian :: Integer -> Int -> Int -> Int -> Int -> Int -> UTCTime+fromGregorian year month day hours minutes seconds =+    UTCTime day' (secondsToDiffTime . fromIntegral $ seconds')+  where+    day'     = Calendar.fromGregorian year month day+    seconds' = 3600 * hours + 60 * minutes + seconds++fromUniversalTime :: UniversalTime -> UTCTime+fromUniversalTime = localTimeToUTC utc . ut1ToLocalTime 0++toUniversalTime :: UTCTime -> UniversalTime+toUniversalTime = localTimeToUT1 0 . utcToLocalTime utc++fromGregorian' :: Integer -> Int -> Int -> UTCTime+fromGregorian' y m d = fromGregorian y m d 0 0 0++startOfTime :: UTCTime+startOfTime = fromGregorian' 1970 1 1++fromMJD :: Rational -> UTCTime+fromMJD = fromUniversalTime . ModJulianDate++fromMJD' :: Float -> UTCTime+fromMJD' = fromMJD . realToFrac++startOfTimeMJD :: Rational+startOfTimeMJD = toMJD startOfTime++toMJD :: UTCTime -> Rational+toMJD = getModJulianDate . toUniversalTime++instance QC.Arbitrary UTCTime where+    -- coarbitrary = undefined+    arbitrary = do+      offset <- QC.choose (0, 20000) :: QC.Gen Float+      return . fromMJD' $ offset + fromRational startOfTimeMJD++--------------------------------------------------------------------------------++type MUTCTime = Maybe UTCTime+type Tuple  = (Int, Int)+type Triple = (Int, String, UTCTime)+type Tuple4 = (Int, String, [Maybe UTCTime], [Maybe Bool])+type Tuple5 = (Int, [String], [Maybe UTCTime], [Maybe Bool], (Bool, Bool))++$(mkSerializeSpecs [+                   -- ''Char    -- encode/decode are not isomorphic with Char+                   --  ''Double -- encode/decode are not isomorphic with Double+                   -- ''String+                     ''UTCTime+                   , ''MUTCTime+                   -- , ''Tuple+                   -- , ''Triple+                   -- , ''Tuple4+                   -- , ''Tuple5+                   ])
+ tests/Data/EDN/Test/QuickCheck/TH.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE TemplateHaskell #-}+module Data.EDN.Test.QuickCheck.TH where++import           Control.Applicative   ((<$>), (<*>))+import           Language.Haskell.TH+import           Test.Hspec            (Spec, describe)+import           Test.Hspec.QuickCheck (prop)++++import qualified Data.EDN              as E+import qualified Test.QuickCheck       as QC++--------------------------------------------------------------------------------++serializeProperty :: (QC.Arbitrary a, Eq a, E.ToEDN a, E.FromEDN a) => a -> Bool+serializeProperty object = do+  case decoded of+    Just result -> result == object+    Nothing -> False+  where+      encoded = E.encode object+      decoded = E.decode encoded++getTestPropertyName :: Name -> Name+getTestPropertyName qualTypeName =+    mkName $ "test" ++ (nameBase qualTypeName) ++ "Serialization"++mkEDNSerializeSpecGroup :: [Name] -> Q [Dec]+mkEDNSerializeSpecGroup names = do+    let fnName = mkName "ednSerializationProperties"+    specType <- [t| Spec |]+    describeFn <- [| describe |]+    return $ [ SigD fnName specType+             , ValD (VarP fnName)+                    (NormalB (AppE (AppE describeFn+                                        (LitE (StringL "EDN.Serialization")))+                                   (DoE (map (NoBindS . VarE . getTestPropertyName)+                                             names)))) []]++mkSerializeSpec :: Name -> Q [Dec]+mkSerializeSpec qualTypeName = do+    let typeName = nameBase qualTypeName+        fnName = getTestPropertyName qualTypeName+    propFn <- [| prop |]+    serializePropertyFn <- [| serializeProperty |]+    boolType <- [t| Bool |]+    specType <- [t| Spec |]+    return [ SigD fnName specType+           , ValD (VarP fnName)+                    (NormalB (AppE+                      (AppE propFn+                        (LitE (StringL $ typeName ++ " serialization/deserialization")))+                      (SigE serializePropertyFn+                        (AppT (AppT ArrowT (ConT qualTypeName))+                              boolType)))) []]++mkSerializeSpecs :: [Name] -> Q [Dec]+mkSerializeSpecs types =+    (++) <$> (concat `fmap` mapM mkSerializeSpec types)+         <*> (mkEDNSerializeSpecGroup types)
+ tests/Data/EDN/Test/Unit.hs view
@@ -0,0 +1,233 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ExistentialQuantification #-}+module Data.EDN.Test.Unit (tests) where++import Test.HUnit++import qualified Data.ByteString.Lazy.Char8 as BSL+import qualified Data.ByteString.Char8 as BS+import qualified Data.Text.Lazy as TL+import qualified Data.Text as T++import qualified Data.Vector as V+import qualified Data.Set as S+import qualified Data.Map as M++import Data.EDN (encode, decode, ToEDN, toEDN, FromEDN, fromEDN)+import Data.EDN.Types as E+import Data.EDN.Types.Class (Result(..), (.=))+import Data.EDN.Parser (parseMaybe)++tests :: Test+tests = TestList [ TestLabel "BSL -> TV parser" $ TestList $ map makeParserCase parserCases+                 , TestLabel "TV -> BSL encoder" $ TestList $ map makeEncodeCase encodeCases+                 , TestLabel "ToEDN conversion" $ TestList $ map makeToEDNcase toEDNcases+                 , TestLabel "FromEDN converter/decoder" $ TestList $ map makeFromEDNcase fromEDNcases+                 , TestLabel "decoder fail" (TestCase (assertEqual "bad unicode" Nothing (parseMaybe "№")))+                 , TestLabel "'Tagged a' conversion" $ TestList taggedConversion+                 ]++makeParserCase :: (BSL.ByteString, E.TaggedValue) -> Test+makeParserCase (i, o) = TestCase (assertEqual (BSL.unpack i) (Just o) (parseMaybe i))++makeEncodeCase :: (E.TaggedValue, BSL.ByteString) -> Test+makeEncodeCase (i, o) = TestCase (assertEqual (BSL.unpack o) o (encode i))++parserCases :: [(BSL.ByteString, E.TaggedValue)]+parserCases = [ ("nil", E.nil)++              , ("true", E.true)+              , ("false", E.false)++              , ("\"a nice string\"", "a nice string")+              , ("\"split\\second \\t\\rai\\n\"", "split\\second \t\rai\n")+              , ("\"test \\\"sausage\\\" shmest\"", "test \"sausage\" shmest")+              , ("\"\"", "")++              , ("\\c", E.char 'c')+              , ("\\\\", E.char '\\')+              , ("\\newline", E.char '\n')+              , ("\\space", E.char ' ')+              , ("\\tab", E.char '\t')++              , ("justasymbol", E.symbol "justasymbol")+              , ("with#stuff:inside", E.symbol "with#stuff:inside")+              , ("my-namespace/foo", E.symbolNS "my-namespace" "foo")+              , ("/", E.symbol "/")++              , (":fred", E.keyword "fred")+              , (":my/fred", E.keyword "my/fred")++              , ("42", E.integer 42)+              , ("-1", E.integer (-1))++              , ("100.50", E.floating 100.5)+              , ("-3.14", E.floating (-3.14))+               -- ...and many other strange stuff...++              , ("(a b 42)", sampleList)+              , ("()", E.notag $ E.makeList [])++              , ("[a b 42]", sampleVec)+              , ("[]", E.notag $ E.makeVec [])++              , ("{:a 1, \"foo\" :bar, [1 2 3] four}", sampleMap)+              , ("{}", E.notag $ E.makeMap [])++              , ("#{a b [1 2 3]}", sampleSet)+              , ("#{}", E.notag $ E.makeSet [])++              , ("[a b #_foo 42]", sampleDiscard)+              , ("(1 2 ;more to go!\n 3 4)", sampleComment)++              , ("#myapp/Person {:first \"Fred\" :last \"Mertz\"}", E.tag "myapp" "Person" sampleTaggedMap)+              , ("{:first \"Fred\" :last \"Mertz\"}", E.notag sampleTaggedMap)+              ]++encodeCases :: [(E.TaggedValue, BSL.ByteString)]+encodeCases = [ (E.nil, "nil")++              , (E.true, "true")+              , (E.false, "false")++              , (E.string "a nice string", "\"a nice string\"")+              , ("overloaded", "\"overloaded\"")+              , ("escape \rou\te \\ \"\north\"", "\"escape \\rou\\te \\\\ \\\"\\north\\\"\"")++              , (E.char 'c', "\\c")+              , (E.char '\\', "\\\\")+              , (E.char '\n', "\\newline")+              , (E.char '\r', "\\return")+              , (E.char '\t', "\\tab")+              , (E.char ' ', "\\space")++              , (E.symbol "justasymbol", "justasymbol")+              , (E.symbol "with#stuff:inside", "with#stuff:inside")+              , (E.symbolNS "whatever" "whenever", "whatever/whenever")+              , (E.symbol "/", "/")++              , (E.keyword "fred", ":fred")+              , (E.keyword "my/fred", ":my/fred")+              , (E.notag ":overloaded", ":overloaded") -- IsString kw transform only for untagged values++              , (E.integer 42, "42")+              , (E.integer (-1), "-1")++              , (E.floating 100.50, "100.5")+              , (E.floating (-3.14), "-3.14")++              , (sampleList, "(a b 42)")+              , (E.notag $ E.makeList [], "()")++              , (sampleVec, "[a b 42]")+              , (E.notag $ E.makeVec [], "[]")++              , (sampleMap, "{\"foo\" :bar :a 1 [1 2 3] four}") -- Order not guaranteed+              , (E.notag $ E.makeMap [], "{}")++              , (E.tag "myapp" "Person" sampleTaggedMap, "#myapp/Person {:first \"Fred\" :last \"Mertz\"}")+              ]++sampleList :: E.TaggedValue+sampleList = E.notag $ E.makeList [E.symbol "a", E.symbol "b", E.integer 42]++sampleVec :: E.TaggedValue+sampleVec = E.notag $ E.makeVec [E.symbol "a", E.symbol "b", E.integer 42]++sampleMap :: E.TaggedValue+sampleMap = E.notag $ E.makeMap [ (":a",                                              E.integer 1)+                                , ("foo",                                             E.keyword "bar")+                                , (E.makeVec [E.integer 1, E.integer 2, E.integer 3], E.symbol "four")+                                ]++sampleSet :: E.TaggedValue+sampleSet = E.notag $ E.makeSet [ E.symbol "a"+                                , E.symbol "b"+                                , E.notag $ E.makeVec [E.integer 1, E.integer 2, E.integer 3]+                                ]++sampleDiscard :: E.TaggedValue+sampleDiscard = E.notag $ E.makeVec [E.symbol "a", E.symbol "b", E.integer 42]++sampleComment :: E.TaggedValue+sampleComment = E.notag $ E.makeList [E.integer 1, E.integer 2, E.integer 3, E.integer 4]++sampleTaggedMap :: E.Value+sampleTaggedMap = E.makeMap [ "first" .= E.string "Fred", "last" .= E.string "Mertz" ]++data ToEDNCase = forall a. ToEDN a => ToEDNCase !a !E.TaggedValue++makeToEDNcase :: ToEDNCase -> Test+makeToEDNcase (ToEDNCase i o) = TestCase (assertEqual (show o) o (toEDN i))++toEDNcases :: [ToEDNCase]+toEDNcases = [ ToEDNCase (Nothing :: Maybe Bool) E.nil++             , ToEDNCase (Left "hi" :: Either String ()) $ E.tag "either" "left" "hi"+             , ToEDNCase (Right "z" :: Either () String) $ E.tag "either" "right" "z"+             , ToEDNCase (Just '!') (E.char '!')++             , ToEDNCase True E.true+             , ToEDNCase False E.false++             , ToEDNCase ("test" :: String) (E.string "test")+             , ToEDNCase ("test" :: BSL.ByteString) "test"+             , ToEDNCase ("test" :: BS.ByteString) "test"+             , ToEDNCase ("test" :: TL.Text) "test"+             , ToEDNCase ("test" :: T.Text) "test"++             , ToEDNCase 'c' $ E.char 'c'+             , ToEDNCase '\n' $ E.char '\n'+             , ToEDNCase '\\' $ E.char '\\'++             , ToEDNCase (3.14 :: Double) $ E.floating 3.14+             , ToEDNCase (42 :: Integer) $ E.integer 42++             , ToEDNCase () (E.notag $ E.makeList [])+             , ToEDNCase ([] :: [()]) (E.notag $ E.makeList [])+             , ToEDNCase (["yo", "wassup"] :: [String]) (E.notag $ E.makeList ["yo", "wassup"])+             , ToEDNCase [E.string "i", "am", E.symbolNS "boxed" "container"] (E.notag $ E.makeList [E.string "i", "am", E.symbolNS "boxed" "container"])++             , ToEDNCase (V.fromList ['o', 'm', 'g']) (E.notag $ E.makeVec [E.char 'o', E.char 'm', E.char 'g'])++             , ToEDNCase (S.fromList ['o', 'm', 'g']) (E.notag $ E.makeSet [E.char 'o', E.char 'm', E.char 'g'])++             , ToEDNCase (M.fromList [("test", "shmest"), ("foo", "bar")] :: M.Map String String) (E.notag $ E.makeMap [("test", "shmest"), ("foo", "bar")])+             , ToEDNCase (M.fromList [(":test", "shmest"), (":foo", "bar")] :: EDNMap) (E.notag $ E.makeMap ["test" .= E.string "shmest", "foo" .= E.string "bar"])+             ]++data FromEDNCase = forall a. (FromEDN a, Show a, Eq a) => FromEDNCase !BSL.ByteString !a++makeFromEDNcase :: FromEDNCase -> Test+makeFromEDNcase (FromEDNCase i o) = TestCase $ assertEqual (BSL.unpack i) (Just o) (decode i)++fromEDNcases :: [FromEDNCase]+fromEDNcases = [ FromEDNCase "nil" (Nothing :: Maybe Bool)++               , FromEDNCase "false" False+               , FromEDNCase "true" True++               , FromEDNCase "#either/left hi" (Left "hi" :: Either String ())+               , FromEDNCase "#either/right z" (Right "z" :: Either () String)+               , FromEDNCase "\"ok fine\"" (Just "ok fine" :: Maybe T.Text)+               , FromEDNCase "nil" (Nothing :: Maybe BSL.ByteString)++               , FromEDNCase "\\newline" '\n'+               , FromEDNCase "\\z" 'z'++               , FromEDNCase "42" (42 :: Integer)+               , FromEDNCase "-3.14" (-3.14 :: Double)++               , FromEDNCase "(hello world)" (["hello", "world"] :: [String])+               , FromEDNCase "[3 2 1 \"Kaboom!\"]" $ E.makeVec [E.integer 3, E.integer 2, E.integer 1, "Kaboom!"]+               , FromEDNCase "#{a/bag :of \"bugs\"}" $ E.makeSet [E.symbolNS "a" "bag", E.keyword "of", E.string "bugs"]+               , FromEDNCase "{json: \"like\", but/not: \"really\"}" $ (M.fromList [("json:", "like"), ("but/not:", "really")] :: M.Map String String)+               , FromEDNCase "{ json: \"like\", but/not: \"really\" }" $ (M.fromList [("json:", "like"), ("but/not:", "really")] :: M.Map String String)+               ]++taggedConversion :: [Test]+taggedConversion = [ TestCase (assertEqual "toEDN tagged" (E.tag "wo" "ot" (E.Boolean False)) (toEDN $ E.tag "wo" "ot" False))+                   , TestCase (assertEqual "toEDN notag" E.false (toEDN $ E.notag False))+                   , TestCase (assertEqual "fromEDN tagged" (Success $ E.tag "wo" "ot" False) (fromEDN $ E.tag "wo" "ot" (E.Boolean False)))+                   , TestCase (assertEqual "fromEDN notag" (Success $ E.notag False) (fromEDN $ E.false))+                   ]
tests/Main.hs view
@@ -1,239 +1,11 @@-{-# LANGUAGE OverloadedStrings, ExistentialQuantification #-}- module Main where--import Test.HUnit-import Control.Monad (when)-import System.Exit (exitFailure)--import qualified Data.ByteString.Lazy.Char8 as BSL-import qualified Data.ByteString.Char8 as BS-import qualified Data.Text.Lazy as TL-import qualified Data.Text as T--import qualified Data.Vector as V-import qualified Data.Set as S-import qualified Data.Map as M+import           Test.Hspec.HUnit         (fromHUnitTest)+import           Test.Hspec.Runner        (hspec) -import Data.EDN (encode, decode, ToEDN, toEDN, FromEDN, fromEDN)-import Data.EDN.Types as E-import Data.EDN.Types.Class (Result(..), (.=))-import Data.EDN.Parser (parseMaybe)+import           Data.EDN.Test.QuickCheck (ednSerializationProperties)+import           Data.EDN.Test.Unit       (tests)  main :: IO ()-main = do-    (Counts _ _ e f) <- runTestTT tests-    when (e > 0 || f > 0) $ exitFailure--tests :: Test-tests = TestList [ TestLabel "BSL -> TV parser" $ TestList $ map makeParserCase parserCases-                 , TestLabel "TV -> BSL encoder" $ TestList $ map makeEncodeCase encodeCases-                 , TestLabel "ToEDN conversion" $ TestList $ map makeToEDNcase toEDNcases-                 , TestLabel "FromEDN converter/decoder" $ TestList $ map makeFromEDNcase fromEDNcases-                 , TestLabel "decoder fail" (TestCase (assertEqual "bad unicode" Nothing (parseMaybe "№")))-                 , TestLabel "'Tagged a' conversion" $ TestList taggedConversion-                 ]--makeParserCase :: (BSL.ByteString, E.TaggedValue) -> Test-makeParserCase (i, o) = TestCase (assertEqual (BSL.unpack i) (Just o) (parseMaybe i))--makeEncodeCase :: (E.TaggedValue, BSL.ByteString) -> Test-makeEncodeCase (i, o) = TestCase (assertEqual (BSL.unpack o) o (encode i))--parserCases :: [(BSL.ByteString, E.TaggedValue)]-parserCases = [ ("nil", E.nil)--              , ("true", E.true)-              , ("false", E.false)--              , ("\"a nice string\"", "a nice string")-              , ("\"split\\second \\t\\rai\\n\"", "split\\second \t\rai\n")-              , ("\"test \\\"sausage\\\" shmest\"", "test \"sausage\" shmest")-              , ("\"\"", "")--              , ("\\c", E.char 'c')-              , ("\\\\", E.char '\\')-              , ("\\newline", E.char '\n')-              , ("\\space", E.char ' ')-              , ("\\tab", E.char '\t')--              , ("justasymbol", E.symbol "justasymbol")-              , ("with#stuff:inside", E.symbol "with#stuff:inside")-              , ("my-namespace/foo", E.symbolNS "my-namespace" "foo")-              , ("/", E.symbol "/")--              , (":fred", E.keyword "fred")-              , (":my/fred", E.keyword "my/fred")--              , ("42", E.integer 42)-              , ("-1", E.integer (-1))--              , ("100.50", E.floating 100.5)-              , ("-3.14", E.floating (-3.14))-               -- ...and many other strange stuff...--              , ("(a b 42)", sampleList)-              , ("()", E.notag $ E.makeList [])--              , ("[a b 42]", sampleVec)-              , ("[]", E.notag $ E.makeVec [])--              , ("{:a 1, \"foo\" :bar, [1 2 3] four}", sampleMap)-              , ("{}", E.notag $ E.makeMap [])--              , ("#{a b [1 2 3]}", sampleSet)-              , ("#{}", E.notag $ E.makeSet [])--              , ("[a b #_foo 42]", sampleDiscard)-              , ("(1 2 ;more to go!\n 3 4)", sampleComment)--              , ("#myapp/Person {:first \"Fred\" :last \"Mertz\"}", E.tag "myapp" "Person" sampleTaggedMap)-              , ("{:first \"Fred\" :last \"Mertz\"}", E.notag sampleTaggedMap)-              ]--encodeCases :: [(E.TaggedValue, BSL.ByteString)]-encodeCases = [ (E.nil, "nil")--              , (E.true, "true")-              , (E.false, "false")--              , (E.string "a nice string", "\"a nice string\"")-              , ("overloaded", "\"overloaded\"")-              , ("escape \rou\te \\ \"\north\"", "\"escape \\rou\\te \\\\ \\\"\\north\\\"\"")--              , (E.char 'c', "\\c")-              , (E.char '\\', "\\\\")-              , (E.char '\n', "\\newline")-              , (E.char '\r', "\\return")-              , (E.char '\t', "\\tab")-              , (E.char ' ', "\\space")--              , (E.symbol "justasymbol", "justasymbol")-              , (E.symbol "with#stuff:inside", "with#stuff:inside")-              , (E.symbolNS "whatever" "whenever", "whatever/whenever")-              , (E.symbol "/", "/")--              , (E.keyword "fred", ":fred")-              , (E.keyword "my/fred", ":my/fred")-              , (E.notag ":overloaded", ":overloaded") -- IsString kw transform only for untagged values--              , (E.integer 42, "42")-              , (E.integer (-1), "-1")--              , (E.floating 100.50, "100.5")-              , (E.floating (-3.14), "-3.14")--              , (sampleList, "(a b 42)")-              , (E.notag $ E.makeList [], "()")--              , (sampleVec, "[a b 42]")-              , (E.notag $ E.makeVec [], "[]")--              , (sampleMap, "{\"foo\" :bar :a 1 [1 2 3] four}") -- Order not guaranteed-              , (E.notag $ E.makeMap [], "{}")--              , (E.tag "myapp" "Person" sampleTaggedMap, "#myapp/Person {:first \"Fred\" :last \"Mertz\"}")-              ]--sampleList :: E.TaggedValue-sampleList = E.notag $ E.makeList [E.symbol "a", E.symbol "b", E.integer 42]--sampleVec :: E.TaggedValue-sampleVec = E.notag $ E.makeVec [E.symbol "a", E.symbol "b", E.integer 42]--sampleMap :: E.TaggedValue-sampleMap = E.notag $ E.makeMap [ (":a",                                              E.integer 1)-                                , ("foo",                                             E.keyword "bar")-                                , (E.makeVec [E.integer 1, E.integer 2, E.integer 3], E.symbol "four")-                                ]--sampleSet :: E.TaggedValue-sampleSet = E.notag $ E.makeSet [ E.symbol "a"-                                , E.symbol "b"-                                , E.notag $ E.makeVec [E.integer 1, E.integer 2, E.integer 3]-                                ]--sampleDiscard :: E.TaggedValue-sampleDiscard = E.notag $ E.makeVec [E.symbol "a", E.symbol "b", E.integer 42]--sampleComment :: E.TaggedValue-sampleComment = E.notag $ E.makeList [E.integer 1, E.integer 2, E.integer 3, E.integer 4]--sampleTaggedMap :: E.Value-sampleTaggedMap = E.makeMap [ "first" .= E.string "Fred", "last" .= E.string "Mertz" ]--data ToEDNCase = forall a. ToEDN a => ToEDNCase !a !E.TaggedValue--makeToEDNcase :: ToEDNCase -> Test-makeToEDNcase (ToEDNCase i o) = TestCase (assertEqual (show o) o (toEDN i))--toEDNcases :: [ToEDNCase]-toEDNcases = [ ToEDNCase (Nothing :: Maybe Bool) E.nil--             , ToEDNCase (Left "hi" :: Either String ()) $ E.tag "either" "left" "hi"-             , ToEDNCase (Right "z" :: Either () String) $ E.tag "either" "right" "z"-             , ToEDNCase (Just '!') (E.char '!')--             , ToEDNCase True E.true-             , ToEDNCase False E.false--             , ToEDNCase ("test" :: String) (E.string "test")-             , ToEDNCase ("test" :: BSL.ByteString) "test"-             , ToEDNCase ("test" :: BS.ByteString) "test"-             , ToEDNCase ("test" :: TL.Text) "test"-             , ToEDNCase ("test" :: T.Text) "test"--             , ToEDNCase 'c' $ E.char 'c'-             , ToEDNCase '\n' $ E.char '\n'-             , ToEDNCase '\\' $ E.char '\\'--             , ToEDNCase (3.14 :: Double) $ E.floating 3.14-             , ToEDNCase (42 :: Integer) $ E.integer 42--             , ToEDNCase () (E.notag $ E.makeList [])-             , ToEDNCase ([] :: [()]) (E.notag $ E.makeList [])-             , ToEDNCase (["yo", "wassup"] :: [String]) (E.notag $ E.makeList ["yo", "wassup"])-             , ToEDNCase [E.string "i", "am", E.symbolNS "boxed" "container"] (E.notag $ E.makeList [E.string "i", "am", E.symbolNS "boxed" "container"])--             , ToEDNCase (V.fromList ['o', 'm', 'g']) (E.notag $ E.makeVec [E.char 'o', E.char 'm', E.char 'g'])--             , ToEDNCase (S.fromList ['o', 'm', 'g']) (E.notag $ E.makeSet [E.char 'o', E.char 'm', E.char 'g'])--             , ToEDNCase (M.fromList [("test", "shmest"), ("foo", "bar")] :: M.Map String String) (E.notag $ E.makeMap [("test", "shmest"), ("foo", "bar")])-             , ToEDNCase (M.fromList [(":test", "shmest"), (":foo", "bar")] :: EDNMap) (E.notag $ E.makeMap ["test" .= E.string "shmest", "foo" .= E.string "bar"])-             ]--data FromEDNCase = forall a. (FromEDN a, Show a, Eq a) => FromEDNCase !BSL.ByteString !a--makeFromEDNcase :: FromEDNCase -> Test-makeFromEDNcase (FromEDNCase i o) = TestCase $ assertEqual (BSL.unpack i) (Just o) (decode i)--fromEDNcases :: [FromEDNCase]-fromEDNcases = [ FromEDNCase "nil" (Nothing :: Maybe Bool)--               , FromEDNCase "false" False-               , FromEDNCase "true" True--               , FromEDNCase "#either/left hi" (Left "hi" :: Either String ())-               , FromEDNCase "#either/right z" (Right "z" :: Either () String)-               , FromEDNCase "\"ok fine\"" (Just "ok fine" :: Maybe T.Text)-               , FromEDNCase "nil" (Nothing :: Maybe BSL.ByteString)--               , FromEDNCase "\\newline" '\n'-               , FromEDNCase "\\z" 'z'--               , FromEDNCase "42" (42 :: Integer)-               , FromEDNCase "-3.14" (-3.14 :: Double)--               , FromEDNCase "(hello world)" (["hello", "world"] :: [String])-               , FromEDNCase "[3 2 1 \"Kaboom!\"]" $ E.makeVec [E.integer 3, E.integer 2, E.integer 1, "Kaboom!"]-               , FromEDNCase "#{a/bag :of \"bugs\"}" $ E.makeSet [E.symbolNS "a" "bag", E.keyword "of", E.string "bugs"]-               , FromEDNCase "{json: \"like\", but/not: \"really\"}" $ (M.fromList [("json:", "like"), ("but/not:", "really")] :: M.Map String String)-               ]--taggedConversion :: [Test]-taggedConversion = [ TestCase (assertEqual "toEDN tagged" (E.tag "wo" "ot" (E.Boolean False)) (toEDN $ E.tag "wo" "ot" False))-                   , TestCase (assertEqual "toEDN notag" E.false (toEDN $ E.notag False))-                   , TestCase (assertEqual "fromEDN tagged" (Success $ E.tag "wo" "ot" False) (fromEDN $ E.tag "wo" "ot" (E.Boolean False)))-                   , TestCase (assertEqual "fromEDN notag" (Success $ E.notag False) (fromEDN $ E.false))-                   ]+main = hspec $ do+  fromHUnitTest tests+  ednSerializationProperties