data-object-yaml 0.2.0.1 → 0.3.0
raw patch · 3 files changed
+383/−198 lines, 3 filesdep +MonadCatchIO-transformersdep +containersdep +iterateedep −QuickCheckdep −attemptdep −test-framework-quickcheckdep ~convertible-textdep ~data-objectdep ~failurePVP ok
version bump matches the API change (PVP)
Dependencies added: MonadCatchIO-transformers, containers, iteratee
Dependencies removed: QuickCheck, attempt, test-framework-quickcheck
Dependency ranges changed: convertible-text, data-object, failure, transformers, yaml
API changes (from Hackage documentation)
- Data.Object.Yaml: instance Applicative YAttemptIO
- Data.Object.Yaml: instance Exception UnexpectedEvent
- Data.Object.Yaml: instance Failure YamlException YAttemptIO
- Data.Object.Yaml: instance Functor YAttemptIO
- Data.Object.Yaml: instance Monad YAttemptIO
- Data.Object.Yaml: instance MonadIO YAttemptIO
- Data.Object.Yaml: instance Show UnexpectedEvent
- Data.Object.Yaml: instance Typeable UnexpectedEvent
- Data.Object.Yaml: instance With YAttemptIO
+ Data.Object.Yaml: fromYamlObject :: (IsYamlScalar k) => (IsYamlScalar v) => YamlObject -> Object k v
+ Data.Object.Yaml: instance (Monad m) => Monad (PErrorT m)
+ Data.Object.Yaml: instance (MonadCatchIO m) => MonadCatchIO (PErrorT m)
+ Data.Object.Yaml: instance (MonadIO m) => MonadIO (PErrorT m)
+ Data.Object.Yaml: instance Data YamlScalar
+ Data.Object.Yaml: instance MonadTrans PErrorT
+ Data.Object.Yaml: instance Read YamlScalar
+ Data.Object.Yaml: instance Typeable YamlScalar
+ Data.Object.Yaml: toYamlObject :: (IsYamlScalar k) => (IsYamlScalar v) => Object k v -> YamlObject
- Data.Object.Yaml: class IsYamlScalar a
+ Data.Object.Yaml: class (Eq a) => IsYamlScalar a
- Data.Object.Yaml: decode :: (MonadFailure YamlException m, IsYamlScalar k, IsYamlScalar v) => ByteString -> m (Object k v)
+ Data.Object.Yaml: decode :: (Failure ParseException m, IsYamlScalar k, IsYamlScalar v) => ByteString -> m (Object k v)
- Data.Object.Yaml: decodeFile :: (MonadFailure YamlException m, IsYamlScalar k, IsYamlScalar v, With m) => FilePath -> m (Object k v)
+ Data.Object.Yaml: decodeFile :: (Failure ParseException m, IsYamlScalar k, IsYamlScalar v) => FilePath -> IO (m (Object k v))
- Data.Object.Yaml: encodeFile :: (IsYamlScalar k, IsYamlScalar v, MonadFailure YamlException m, With m) => FilePath -> Object k v -> m ()
+ Data.Object.Yaml: encodeFile :: (IsYamlScalar k, IsYamlScalar v) => FilePath -> Object k v -> IO ()
Files
- Data/Object/Yaml.hs +216/−184
- data-object-yaml.cabal +11/−11
- runtests.hs +156/−3
Data/Object/Yaml.hs view
@@ -10,39 +10,43 @@ , YamlObject -- * Automatic scalar conversions , IsYamlScalar (..)+ , toYamlObject+ , fromYamlObject -- * Encoding/decoding , encode , encodeFile , decode , decodeFile-#if TEST- , testSuite-#endif ) where import qualified Text.Libyaml as Y import Text.Libyaml hiding (encode, decode, encodeFile, decodeFile) import Data.Object import Data.ByteString (ByteString)+import qualified Data.Map as Map import System.IO.Unsafe (unsafePerformIO)-import Control.Exception (Exception, SomeException (..))-import Data.Typeable (Typeable)--- debugging purposes import Debug.Trace import Control.Failure-import Control.Applicative+ import qualified Data.Text import qualified Data.Text.Lazy-import "transformers" Control.Monad.Trans-import Control.Monad+import qualified Data.ByteString+import qualified Data.ByteString.Lazy -#if TEST-import Test.Framework (testGroup, Test)-import Test.Framework.Providers.HUnit---import Test.Framework.Providers.QuickCheck (testProperty)-import Test.HUnit hiding (Test, path)---import Test.QuickCheck-import qualified Data.ByteString.Char8 as B8+import Data.Convertible.Text (cs)+import Data.Data++#if MIN_VERSION_transformers(0,2,0)+import "transformers" Control.Monad.Trans.Class+import "transformers" Control.Monad.IO.Class+#else+import "transformers" Control.Monad.Trans #endif+import "transformers" Control.Monad.Trans.State+import Control.Monad+import Data.Iteratee hiding (foldl)+import qualified Data.Iteratee as I+import Control.Monad.CatchIO hiding (try)+import Prelude hiding (catch) -- | Equality depends on 'value' and 'tag', not 'style'. data YamlScalar = YamlScalar@@ -50,13 +54,13 @@ , tag :: Tag , style :: Style }- deriving (Show)+ deriving (Show, Read, Data, Typeable) instance Eq YamlScalar where (YamlScalar v t _) == (YamlScalar v' t' _) = v == v' && t == t' type YamlObject = Object YamlScalar YamlScalar -class IsYamlScalar a where+class (Eq a) => IsYamlScalar a where fromYamlScalar :: YamlScalar -> a toYamlScalar :: a -> YamlScalar instance IsYamlScalar YamlScalar where@@ -71,203 +75,231 @@ instance IsYamlScalar [Char] where fromYamlScalar = cs . value toYamlScalar s = YamlScalar (cs s) NoTag Any-instance IsYamlScalar ByteString where+instance IsYamlScalar Data.ByteString.ByteString where fromYamlScalar = value toYamlScalar b = YamlScalar b NoTag Any+instance IsYamlScalar Data.ByteString.Lazy.ByteString where+ fromYamlScalar = cs . value+ toYamlScalar b = YamlScalar (cs b) NoTag Any +-- | Merge assoc-lists by keys.+-- First list overrides second:+-- [(k1, x), (k2, y)] `mergeAssocLists` [(k3, z)] == [(k1, x), (k2, y), (k3, z)]+-- [(k1, x), (k2, y)] `mergeAssocLists` [(k2, z)] == [(k1, x), (k2, y)]+mergeAssocLists :: (Eq k) => [(k, v)] -> [(k, v)] -> [(k, v)]+mergeAssocLists a [] = a+mergeAssocLists [] b = b+mergeAssocLists a ((bk, bv):bs) =+ case lookup bk a of+ Nothing -> mergeAssocLists ((bk, bv) : a) bs+ Just _ -> mergeAssocLists a bs++toYamlObject :: IsYamlScalar k+ => IsYamlScalar v+ => Object k v+ -> YamlObject+toYamlObject = mapKeysValues toYamlScalar toYamlScalar++fromYamlObject :: IsYamlScalar k+ => IsYamlScalar v+ => YamlObject+ -> Object k v+fromYamlObject = mapKeysValues fromYamlScalar fromYamlScalar+ encode :: (IsYamlScalar k, IsYamlScalar v) => Object k v -> ByteString-encode = unsafePerformIO . Y.encode . ge+encode obj =+ unsafePerformIO+ (enumPure1Chunk+ (objToEvents $ toYamlObject obj)+ Y.encode >>= run) -encodeFile :: (IsYamlScalar k, IsYamlScalar v, MonadFailure YamlException m,- With m)+encodeFile :: (IsYamlScalar k, IsYamlScalar v) => FilePath -> Object k v- -> m ()-encodeFile fp = Y.encodeFile fp . ge+ -> IO ()+encodeFile fp obj =+ enumPure1Chunk (objToEvents $ toYamlObject obj) (Y.encodeFile fp)+ >>= run -emitEvents :: (MonadIO m, MonadFailure YamlException m)- => Event -> Event -> YamlEncoder m () -> YamlEncoder m ()-emitEvents start stop body = emitEvent start >> body >> emitEvent stop+objToEvents :: YamlObject -> [Y.Event]+objToEvents o = (:) EventStreamStart+ . (:) EventDocumentStart+ $ objToEvents' o+ [ EventDocumentEnd+ , EventStreamEnd+ ] -ge :: (MonadIO m, MonadFailure YamlException m, IsYamlScalar k,- IsYamlScalar v)- => Object k v- -> YamlEncoder m ()-ge yo = emitEvents EventStreamStart EventStreamEnd- $ emitEvents EventDocumentStart EventDocumentEnd- $ geO yo+scalarToEvent :: YamlScalar -> Event+scalarToEvent (YamlScalar v t s) = EventScalar v t s Nothing -geO :: (MonadIO m, MonadFailure YamlException m, IsYamlScalar k,- IsYamlScalar v)- => Object k v- -> YamlEncoder m ()-geO (Scalar s) = geS s-geO (Sequence yos) = emitEvents EventSequenceStart EventSequenceEnd- $ mapM_ geO yos-geO (Mapping pairs) = emitEvents EventMappingStart EventMappingEnd- $ mapM_ gePair pairs+objToEvents' :: YamlObject -> [Y.Event] -> [Y.Event]+objToEvents' (Scalar s) rest = scalarToEvent s : rest+objToEvents' (Sequence list) rest =+ EventSequenceStart Nothing+ : foldr ($) (EventSequenceEnd : rest) (map objToEvents' list)+objToEvents' (Mapping pairs) rest =+ EventMappingStart Nothing+ : foldr ($) (EventMappingEnd : rest) (map pairToEvents pairs) -gePair :: (MonadIO m, MonadFailure YamlException m, IsYamlScalar k,- IsYamlScalar v)- => (k, Object k v)- -> YamlEncoder m ()-gePair (ys, yo) = geS ys >> geO yo+pairToEvents :: (YamlScalar, YamlObject) -> [Y.Event] -> [Y.Event]+pairToEvents (k, v) rest =+ scalarToEvent k+ : objToEvents' v rest -geS :: (MonadIO m, IsYamlScalar a, MonadFailure YamlException m)- => a- -> YamlEncoder m ()-geS = emitEvent . toEventScalar . toYamlScalar+-- Parsing -toEventScalar :: YamlScalar -> Event-toEventScalar (YamlScalar v t s) = EventScalar v t s+data ParseException = NonScalarKey+ | UnknownAlias { _anchorName :: Y.AnchorName }+ | UnexpectedEvent { _received :: Maybe Event+ , _expected :: Maybe Event+ }+ | InvalidYaml (Maybe ErrMsg)+ deriving (Show, Typeable)+instance Exception ParseException -decode :: (MonadFailure YamlException m, IsYamlScalar k, IsYamlScalar v)- => ByteString- -> m (Object k v)-decode bs = try $ unsafePerformIO $ unYAttemptIO $ Y.decode bs parse+newtype PErrorT m a = PErrorT { runPErrorT :: m (Either ParseException a) }+instance Monad m => Monad (PErrorT m) where+ return = PErrorT . return . Right+ (PErrorT m) >>= f = PErrorT $ do+ e <- m+ case e of+ Left e' -> return $ Left e'+ Right a -> runPErrorT $ f a+instance MonadTrans PErrorT where+ lift = PErrorT . liftM Right+instance MonadIO m => MonadIO (PErrorT m) where+ liftIO = lift . liftIO+instance MonadCatchIO m => MonadCatchIO (PErrorT m) where+ m `catch` f = mapPErrorT (\m' -> m' `catch` \e -> runPErrorT $ f e) m+ block = mapPErrorT block+ unblock = mapPErrorT unblock -newtype YAttemptIO v = YAttemptIO- { unYAttemptIO :: IO (Either YamlException v)- }-instance Monad YAttemptIO where- return = YAttemptIO . return . Right- (YAttemptIO io) >>= f = YAttemptIO $ do- x <- io- case x of- Left e -> return $ Left e- Right y -> unYAttemptIO $ f y-instance Functor YAttemptIO where- fmap = liftM-instance Applicative YAttemptIO where- pure = return- (<*>) = ap-instance Failure YamlException YAttemptIO where- failure = YAttemptIO . return . Left-instance MonadIO YAttemptIO where- liftIO = YAttemptIO . fmap Right-instance With YAttemptIO where- with orig = YAttemptIO . orig . (unYAttemptIO .)+mapPErrorT :: (m (Either ParseException a) -> n (Either ParseException b))+ -> PErrorT m a+ -> PErrorT n b+mapPErrorT f m = PErrorT $ f (runPErrorT m) -decodeFile :: (MonadFailure YamlException m, IsYamlScalar k, IsYamlScalar v,- With m)- => FilePath- -> m (Object k v)-decodeFile fp = Y.decodeFile fp parse+pfailure :: Monad m => ParseException -> PErrorT m a+pfailure = PErrorT . return . Left -requireEvent :: (With m, MonadFailure YamlException m)- => Event- -> YamlDecoder m ()-requireEvent e = do- e' <- parseEvent- unless (e == e')- $ failure $ YamlOtherException $ SomeException- $ UnexpectedEvent e' $ Just e+type Parser = PErrorT (StateT (Map.Map String YamlObject) IO) -data UnexpectedEvent = UnexpectedEvent- { _received :: Event- , _expected :: Maybe Event- }- deriving (Show, Typeable)-instance Exception UnexpectedEvent+requireEvent :: Event -> IterateeG [] Event Parser ()+requireEvent e = do+ f <- peek+ if f == Just e+ then I.drop 1+ else lift $ pfailure $ UnexpectedEvent f $ Just e -parse :: (With m, MonadFailure YamlException m, IsYamlScalar k,- IsYamlScalar v)- => YamlDecoder m (Object k v)+parse :: IterateeG [] Event Parser YamlObject parse = do requireEvent EventStreamStart requireEvent EventDocumentStart- e <- parseEvent- res <- parseO e+ res <- parseO requireEvent EventDocumentEnd requireEvent EventStreamEnd- requireEvent EventNone return res -parseO :: (IsYamlScalar k, IsYamlScalar v, With m,- MonadFailure YamlException m)- => Event- -> YamlDecoder m (Object k v)-parseO (EventScalar v t s) =- return $ Scalar $ fromYamlScalar $ YamlScalar v t s-parseO EventSequenceStart = parseS id-parseO EventMappingStart = parseM id-parseO e = failure $ YamlOtherException $ SomeException- $ UnexpectedEvent e Nothing--parseS :: (IsYamlScalar k, IsYamlScalar v, With m,- MonadFailure YamlException m)- => ([Object k v] -> [Object k v])- -> YamlDecoder m (Object k v)-parseS front = do- e <- parseEvent- case e of- EventSequenceEnd -> return $ Sequence $ front []- _ -> do- o <- parseO e- parseS $ front . (:) o--parseM :: (IsYamlScalar k, IsYamlScalar v, With m,- MonadFailure YamlException m)- => ([(k, Object k v)] -> [(k, Object k v)])- -> YamlDecoder m (Object k v)-parseM front = do- e <- parseEvent- case e of- EventMappingEnd -> return $ Mapping $ front []- EventScalar v' t s -> do- let k = fromYamlScalar $ YamlScalar v' t s- v <- parseEvent >>= parseO- parseM $ front . (:) (k, v)- _ -> failure $ YamlOtherException- $ SomeException NonScalarKey--data ParseException = NonScalarKey- deriving (Show, Typeable)-instance Exception ParseException--#if TEST-mkScalar :: String -> YamlScalar-mkScalar s = YamlScalar (cs s) StrTag Folded+safeHead :: IterateeG [] Event Parser (Maybe Event)+safeHead = do+ x <- peek+ I.drop 1+ return x -sample :: YamlObject-sample = Sequence- [ Scalar $ mkScalar "foo"- , Mapping- [ (mkScalar "bar1", Scalar $ mkScalar "bar2")- ]- ]+parseScalar :: ByteString -> Tag -> Style -> Anchor+ -> IterateeG [] Event Parser YamlScalar+parseScalar v t s a = do+ let res = YamlScalar v t s+ case a of+ Nothing -> return res+ Just an -> do+ lift $ lift $ modify (Map.insert an $ Scalar res)+ return res -sampleStr :: Object String String-sampleStr = mapKeysValues fromYamlScalar fromYamlScalar sample+parseO :: IterateeG [] Event Parser YamlObject+parseO = do+ me <- safeHead+ case me of+ Just (EventScalar v t s a) -> Scalar `liftM` parseScalar v t s a+ Just (EventSequenceStart a) -> parseS a id+ Just (EventMappingStart a) -> parseM a id+ Just (EventAlias an) -> do+ m <- lift $ lift get+ case Map.lookup an m of+ Nothing -> lift $ pfailure $ UnknownAlias an+ Just v -> return v+ _ -> lift $ pfailure $ UnexpectedEvent me Nothing -testSuite :: Test-testSuite = testGroup "Data.Object.Yaml"- [ testCase "encode/decode" caseEncodeDecode- , testCase "encode/decode file" caseEncodeDecodeFile- , testCase "encode/decode strings" caseEncodeDecodeStrings- , testCase "decode invalid file" caseDecodeInvalid- ]+parseS :: Y.Anchor+ -> ([YamlObject] -> [YamlObject])+ -> IterateeG [] Event Parser YamlObject+parseS a front = do+ me <- peek+ case me of+ Just EventSequenceEnd -> do+ I.drop 1+ let res = Sequence $ front []+ case a of+ Nothing -> return res+ Just an -> do+ lift $ lift $ modify $ Map.insert an res+ return res+ _ -> do+ o <- parseO+ parseS a $ front . (:) o -caseEncodeDecode :: Assertion-caseEncodeDecode = do- out <- decode $ encode sample- out @?= sample+parseM :: Y.Anchor+ -> ([(YamlScalar, YamlObject)] -> [(YamlScalar, YamlObject)])+ -> IterateeG [] Event Parser YamlObject+parseM a front = do+ me <- peek+ case me of+ Just EventMappingEnd -> do+ I.drop 1+ let res = Mapping $ front []+ case a of+ Nothing -> return res+ Just an -> do+ lift $ lift $ modify $ Map.insert an res+ return res+ _ -> do+ me' <- safeHead+ s <- case me' of+ Just (EventScalar v t s a') -> parseScalar v t s a'+ _ -> lift $ pfailure $ UnexpectedEvent me' Nothing+ o <- parseO+ let al = mergeAssocLists [(s, o)] $ front []+ al' = if fromYamlScalar s == "<<"+ then case o of+ Scalar _ -> al+ Mapping l -> mergeAssocLists al l+ Sequence l -> mergeAssocLists al $ foldl merge' [] l+ else al+ parseM a (`mergeAssocLists` al')+ where merge' :: (Eq k) => [(k, Object k v)] -> Object k v -> [(k, Object k v)]+ merge' al (Mapping om) = mergeAssocLists al om+ merge' al _ = al -caseEncodeDecodeFile :: Assertion-caseEncodeDecodeFile = do- let fp = "tmp.yaml"- encodeFile fp sample- out <- decodeFile fp- out @?= sample+decode :: (Failure ParseException m, IsYamlScalar k, IsYamlScalar v)+ => ByteString+ -> m (Object k v)+decode bs = try $ unsafePerformIO $ run' $ joinIM $ Y.decode bs parse -caseEncodeDecodeStrings :: Assertion-caseEncodeDecodeStrings = do- out <- decode $ encode sampleStr- out @?= sampleStr+decodeFile :: (Failure ParseException m, IsYamlScalar k, IsYamlScalar v)+ => FilePath+ -> IO (m (Object k v))+decodeFile fp = fmap try $ run' $ joinIM $ Y.decodeFile fp parse -caseDecodeInvalid :: Assertion-caseDecodeInvalid = do- let invalid = B8.pack "\tthis is 'not' valid :-)"- Nothing @=? (decode invalid :: Maybe YamlObject)+run' :: (IsYamlScalar k, IsYamlScalar v)+ => IterateeG [] Event Parser YamlObject+ -> IO (Either ParseException (Object k v))+run' iter = do+ let mmmitergv = runIter iter $ EOF Nothing+ mmitergv = runPErrorT mmmitergv+ mitergv = evalStateT mmitergv Map.empty+ itergv <- mitergv+ case itergv of+ Left e -> return $ Left e+ Right (Done x _) -> return $ Right $ fromYamlObject x+ Right (Cont _ e) -> return $ Left $ InvalidYaml e -#endif
data-object-yaml.cabal view
@@ -1,8 +1,8 @@ name: data-object-yaml-version: 0.2.0.1+version: 0.3.0 license: BSD3 license-file: LICENSE-author: Michael Snoyman <michael@snoyman.com>+author: Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com> maintainer: Michael Snoyman <michael@snoyman.com> synopsis: Serialize data to and from Yaml files description: Provides high level conversions based on the data-object package. Parsing and emitting is handled by the yaml package, which in turn uses the libyaml C library.@@ -18,14 +18,16 @@ library build-depends: base >= 4 && < 5,- data-object >= 0.2.0 && < 0.3,+ data-object >= 0.3.0 && < 0.4, bytestring >= 0.9.1.4 && < 0.10, text >= 0.7 && < 0.8,- convertible-text >= 0.2.0 && < 0.3,- attempt >= 0.2.0 && < 0.3,- failure >= 0.0.0 && < 0.1,- transformers >= 0.1.4.0 && < 0.2,- yaml >= 0.2.0 && < 0.3+ failure >= 0.1.0 && < 0.2,+ transformers >= 0.1.4.0 && < 0.3,+ yaml >= 0.3.0 && < 0.4,+ containers >= 0.2.0.0 && < 0.4,+ iteratee >= 0.3.5 && < 0.4,+ MonadCatchIO-transformers >= 0.2.2 && < 0.3,+ convertible-text >= 0.3.0 && < 0.4 exposed-modules: Data.Object.Yaml ghc-options: -Wall @@ -34,10 +36,8 @@ Buildable: True cpp-options: -DTEST build-depends: test-framework,- test-framework-quickcheck, test-framework-hunit,- HUnit,- QuickCheck >= 1 && < 2+ HUnit else Buildable: False ghc-options: -Wall
runtests.hs view
@@ -1,8 +1,161 @@-import Test.Framework (defaultMain)+{-# LANGUAGE NamedFieldPuns #-}+import Test.Framework (Test, defaultMain, testGroup)+import Test.Framework.Providers.HUnit+import Test.HUnit hiding (Test) -import qualified Data.Object.Yaml+import Data.Maybe+import qualified Data.ByteString.Char8 as B8+import Data.Convertible.Text (cs) +import qualified Text.Libyaml as LY++import Data.Object+import Data.Object.Yaml++import Control.Monad++mkFoldedScalar :: String -> YamlScalar+mkFoldedScalar s = YamlScalar (cs s) LY.StrTag LY.Folded++mkScalar :: String -> YamlScalar+mkScalar s = YamlScalar (cs s) LY.NoTag LY.Plain++mkStrScalar :: String -> YamlScalar+mkStrScalar s = YamlScalar (cs s) LY.StrTag LY.Plain++mappingKey :: YamlObject -> String -> YamlObject+mappingKey (Mapping m) k = (fromJust . lookup (mkScalar k) $ m)+mappingKey _ _ = error "expected Mapping"++decodeYaml :: String -> Maybe YamlObject+decodeYaml s = decode $ B8.pack s++sample :: YamlObject+sample = Sequence+ [ Scalar $ mkFoldedScalar "foo"+ , Mapping+ [ (mkFoldedScalar "bar1", Scalar $ mkFoldedScalar "bar2")+ ]+ ]++sampleStr :: Object String String+sampleStr = mapKeysValues fromYamlScalar fromYamlScalar sample+ main :: IO () main = defaultMain- [ Data.Object.Yaml.testSuite+ [ testSuite+ , testSuiteOfAliases+ , testSuiteOfMergeKeys ]++testSuite :: Test+testSuite = testGroup "Data.Object.Yaml"+ [ testCase "encode/decode" caseEncodeDecode+ , testCase "encode/decode file" caseEncodeDecodeFile+ , testCase "encode/decode strings" caseEncodeDecodeStrings+ , testCase "decode invalid file" caseDecodeInvalid+ ]++caseEncodeDecode :: Assertion+caseEncodeDecode = do+ out <- decode $ encode sample+ out @?= sample++caseEncodeDecodeFile :: Assertion+caseEncodeDecodeFile = do+ let fp = "tmp.yaml"+ encodeFile fp sample+ out <- join $ decodeFile fp+ out @?= sample++caseEncodeDecodeStrings :: Assertion+caseEncodeDecodeStrings = do+ out <- decode $ encode $ toYamlObject sampleStr+ fromYamlObject out @?= sampleStr++caseDecodeInvalid :: Assertion+caseDecodeInvalid = do+ let invalid = B8.pack "\tthis is 'not' valid :-)"+ Nothing @=? (decode invalid :: Maybe YamlObject)+++testSuiteOfAliases :: Test+testSuiteOfAliases = testGroup "Tests of aliases"+ [ testCase "simple scalar alias" caseSimpleScalarAlias+ , testCase "simple sequence alias" caseSimpleSequenceAlias+ , testCase "simple mapping alias" caseSimpleMappingAlias+ , testCase "mapping alias before anchor" caseMappingAliasBeforeAnchor+ , testCase "mapping alias inside anchor" caseMappingAliasInsideAnchor+ , testCase "scalar alias overriding" caseScalarAliasOverriding+ ]++caseSimpleScalarAlias :: Assertion+caseSimpleScalarAlias = do+ let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch"+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"+ let res = fromJust maybeRes+ res @?= Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz"), Scalar (mkScalar "foo")]++caseSimpleSequenceAlias :: Assertion+caseSimpleSequenceAlias = do+ let maybeRes = decodeYaml "seq: &anch\n - foo\n - baz\nseq2: *anch"+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"+ let res = fromJust maybeRes+ res @?= Mapping [(mkScalar "seq", Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz")]), (mkScalar "seq2", Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz")])]++caseSimpleMappingAlias :: Assertion+caseSimpleMappingAlias = do+ let maybeRes = decodeYaml "map: &anch\n key1: foo\n key2: baz\nmap2: *anch"+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"+ let res = fromJust maybeRes+ res @?= Mapping [(mkScalar "map", Mapping [(mkScalar "key1", Scalar (mkScalar "foo")), (mkScalar "key2", Scalar (mkScalar "baz"))]), (mkScalar "map2", Mapping [(mkScalar "key1", Scalar (mkScalar "foo")), (mkScalar "key2", Scalar (mkScalar "baz"))])]++caseMappingAliasBeforeAnchor :: Assertion+caseMappingAliasBeforeAnchor = do+ let res = decodeYaml "map: *anch\nmap2: &anch\n key1: foo\n key2: baz"+ isNothing res @? "decode should return Nothing due to unknown alias"++caseMappingAliasInsideAnchor :: Assertion+caseMappingAliasInsideAnchor = do+ let res = decodeYaml "map: &anch\n key1: foo\n key2: *anch"+ isNothing res @? "decode should return Nothing due to unknown alias"++caseScalarAliasOverriding :: Assertion+caseScalarAliasOverriding = do+ let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch"+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"+ let res = fromJust maybeRes+ res @?= Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz"), Scalar (mkScalar "foo"), Scalar (mkScalar "boo"), Scalar (mkScalar "buz"), Scalar (mkScalar "boo")]+++testSuiteOfMergeKeys :: Test+testSuiteOfMergeKeys = testGroup "Tests of 'merge keys' feature"+ [ testCase "test uniqueness of keys" caseAllKeysShouldBeUnique+ , testCase "test mapping merge" caseSimpleMappingMerge+ , testCase "test sequence of mappings merging" caseMergeSequence+ ]++caseAllKeysShouldBeUnique :: Assertion+caseAllKeysShouldBeUnique = do+ let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\nfoo1: buz"+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"+ let res = fromJust maybeRes+ mappingKey res "foo1" @?= Scalar (mkScalar "buz")++caseSimpleMappingMerge :: Assertion+caseSimpleMappingMerge = do+ let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\n<<:\n foo1: buz\n foo3: fuz"+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"+ let res = fromJust maybeRes+ mappingKey res "foo1" @?= Scalar (mkScalar "foo")+ mappingKey res "foo3" @?= Scalar (mkScalar "fuz")++caseMergeSequence :: Assertion+caseMergeSequence = do+ let maybeRes = decodeYaml "m1: &m1\n k1: !!str 1\n k2: !!str 2\nm2: &m2\n k1: !!str 3\n k3: !!str 4\nfoo1: foo\n<<: [ *m1, *m2 ]"+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"+ let res = fromJust maybeRes+ mappingKey res "foo1" @?= Scalar (mkScalar "foo")+ mappingKey res "k1" @?= Scalar (mkStrScalar "1")+ mappingKey res "k2" @?= Scalar (mkStrScalar "2")+ mappingKey res "k3" @?= Scalar (mkStrScalar "4")