diff --git a/Data/Object/Yaml.hs b/Data/Object/Yaml.hs
--- a/Data/Object/Yaml.hs
+++ b/Data/Object/Yaml.hs
@@ -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
diff --git a/data-object-yaml.cabal b/data-object-yaml.cabal
--- a/data-object-yaml.cabal
+++ b/data-object-yaml.cabal
@@ -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
diff --git a/runtests.hs b/runtests.hs
--- a/runtests.hs
+++ b/runtests.hs
@@ -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")
