diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## MIDA 1.0.2
+
+* Refactoring, switch to Hspec for testing and Megaparsec 5.
+
 ## MIDA 1.0.1
 
 * Fixed issues with `directory` package. Please use `directory-1.2.3.0` or
diff --git a/license.txt b/license.txt
new file mode 100644
--- /dev/null
+++ b/license.txt
@@ -0,0 +1,16 @@
+MIDA — realization of MIDA, language for generation of MIDI files.
+
+Copyright © 2014–2016 Mark Karpov
+
+MIDA is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any
+later version.
+
+MIDA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/mida.cabal b/mida.cabal
--- a/mida.cabal
+++ b/mida.cabal
@@ -17,7 +17,8 @@
 -- with this program. If not, see <http://www.gnu.org/licenses/>.
 
 name:                 mida
-version:              1.0.1
+version:              1.0.2
+cabal-version:        >= 1.10
 synopsis:             Language for algorithmic generation of MIDI files
 description:
 
@@ -50,8 +51,10 @@
 copyright:            Copyright © 2014–2016 Mark Karpov
 category:             Language
 build-type:           Simple
-extra-source-files:   README.md, CHANGELOG.md
-cabal-version:        >= 1.10
+data-files:           notice.txt
+                    , license.txt
+extra-doc-files:      CHANGELOG.md
+                    , README.md
 
 flag dev
   description:        Turn on development settings.
@@ -64,18 +67,20 @@
     ghc-options:      -O2 -Wall -Werror
   else
     ghc-options:      -O2 -Wall
-  ghc-prof-options:   -O2 -Wall -prof -fprof-cafs -rtsopts
-  build-depends:      HCodecs                >= 0.5
-                    , base                   >= 4.8 && < 5
-                    , containers             >= 0.5.5.1
-                    , exceptions             >= 0.8
-                    , haskeline              >= 0.7.1.3
-                    , megaparsec             >= 4.2
-                    , mtl                    >= 2.1.3.1
+  build-depends:      HCodecs                >= 0.5     && < 0.6
+                    , QuickCheck             >= 2.8.2   && < 3.0
+                    , base                   >= 4.8     && < 5.0
+                    , containers             >= 0.5.5.1 && < 0.6
+                    , exceptions             >= 0.8     && < 0.9
+                    , haskeline              >= 0.7.1.3 && < 0.8
+                    , megaparsec             >= 5.0     && < 6.0
+                    , mtl                    >= 2.1.3.1 && < 3.0
                     , random
-                    , text                   >= 1.2.0.4
-                    , tf-random              >= 0.5
-                    , transformers           >= 0.2.0.0
+                    , text                   >= 1.2.0.4 && < 1.3
+                    , tf-random              >= 0.5     && < 1.0
+                    , transformers           >= 0.2.0.0 && < 0.6
+  if !impl(ghc >= 8.0)
+    build-depends:    semigroups             == 0.18.*
   default-extensions: FlexibleContexts
                     , FlexibleInstances
                     , OverloadedStrings
@@ -95,33 +100,35 @@
 executable mida
   main-is:            Main.hs
   hs-source-dirs:     src
-  other-modules:      Mida.Interaction
   if flag(dev)
     ghc-options:      -O2 -Wall -Werror
   else
     ghc-options:      -O2 -Wall
-  ghc-prof-options:   -O2 -Wall -prof -fprof-cafs -rtsopts
-  build-depends:      HCodecs                >= 0.5
-                    , aeson                  >= 0.7
-                    , base                   >= 4.8 && < 5
-                    , containers             >= 0.5.5.1
-                    , data-default           >= 0.5.3
-                    , exceptions             >= 0.8
-                    , filepath               >= 1.3.0.2
-                    , formatting             >= 6.2
-                    , haskeline              >= 0.7.1.3
-                    , megaparsec             >= 4.2
-                    , mida                   >= 1.0.1
-                    , mtl                    >= 2.1.3.1
-                    , optparse-applicative   >= 0.11.0.2
-                    , path                   >= 0.5.3
-                    , path-io                >= 0.3.1
-                    , process                >= 1.2.0.0
+  build-depends:      HCodecs                >= 0.5     && < 0.6
+                    , QuickCheck             >= 2.8.2   && < 3.0
+                    , aeson                  >= 0.7     && < 0.12
+                    , base                   >= 4.8     && < 5.0
+                    , containers             >= 0.5.5.1 && < 0.6
+                    , data-default           >= 0.5.3   && < 0.8
+                    , exceptions             >= 0.8     && < 0.9
+                    , file-embed             >= 0.0.9
+                    , filepath               >= 1.3.0.2 && < 1.5
+                    , formatting             >= 6.2     && < 7.0
+                    , haskeline              >= 0.7.1.3 && < 0.8
+                    , megaparsec             >= 5.0     && < 6.0
+                    , mida                   >= 1.0.2
+                    , mtl                    >= 2.1.3.1 && < 3.0
+                    , optparse-applicative   >= 0.11.0.2 && < 0.13
+                    , path                   >= 0.5.3   && < 0.6
+                    , path-io                >= 0.3.1   && < 2.0
+                    , process                >= 1.2     && < 1.5
                     , random
-                    , text                   >= 1.2.0.4
-                    , tf-random              >= 0.5
-                    , transformers           >= 0.2.0.0
-                    , yaml                   >= 0.8.15.1
+                    , text                   >= 1.2.0.4 && < 1.3
+                    , tf-random              >= 0.5     && < 1.0
+                    , transformers           >= 0.2.0.0 && < 0.6
+                    , yaml                   >= 0.8.15  && < 0.9
+  if !impl(ghc >= 8.0)
+    build-depends:    semigroups             == 0.18.*
   default-extensions: FlexibleContexts
                     , FlexibleInstances
                     , OverloadedStrings
@@ -153,20 +160,19 @@
   else
     ghc-options:      -O2 -Wall
   default-language:   Haskell2010
-  build-depends:      HCodecs                    >= 0.5
-                    , QuickCheck                 >= 2.4 && < 3
-                    , base                       >= 4.8 && < 5
-                    , containers                 >= 0.5.5.1
-                    , megaparsec                 >= 4.2
-                    , mida                       >= 1.0.1
-                    , mtl                        >= 2.1.3.1
+  build-depends:      HCodecs                >= 0.5     && < 0.6
+                    , QuickCheck             >= 2.8.2   && < 3.0
+                    , base                   >= 4.8     && < 5.0
+                    , containers             >= 0.5.5.1 && < 0.6
+                    , hspec                  >= 2.0     && < 3.0
+                    , megaparsec             >= 5.0     && < 6.0
+                    , mida                   >= 1.0.2
+                    , mtl                    >= 2.1.3.1 && < 3.0
                     , random
-                    , test-framework             >= 0.4 && < 1
-                    , test-framework-quickcheck2 >= 0.3 && < 0.4
-                    , text                       >= 1.2.0.4
-                    , tf-random                  >= 0.5
-                    , transformers               >= 0.2.0.0
+                    , text                   >= 1.2.0.4 && < 1.3
+                    , tf-random              >= 0.5     && < 1.0
+                    , transformers           >= 0.2.0.0 && < 0.6
 
 source-repository head
   type:               git
-  location:           git://github.com/mrkkrp/mida.git
+  location:           https://github.com/mrkkrp/mida.git
diff --git a/notice.txt b/notice.txt
new file mode 100644
--- /dev/null
+++ b/notice.txt
@@ -0,0 +1,5 @@
+MIDA Copyright © 2014–2016 Mark Karpov
+
+This program comes with ABSOLUTELY NO WARRANTY. This is free software,
+and you are welcome to redistribute it under certain conditions; see
+GNU General Public License for details.
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -16,10 +16,13 @@
 -- You should have received a copy of the GNU General Public License along
 -- with this program. If not, see <http://www.gnu.org/licenses/>.
 
+{-# LANGUAGE TemplateHaskell #-}
+
 module Main (main) where
 
 import Control.Monad
 import Control.Monad.IO.Class
+import Data.FileEmbed
 import Data.Text.Lazy (Text)
 import Data.Version (showVersion)
 import Formatting
@@ -64,31 +67,12 @@
 -- | Shortish copyright notice.
 
 notice :: Text
-notice =
-  "MIDA Copyright © 2014–2016 Mark Karpov\n\n\
-  \This program comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
-  \and you are welcome to redistribute it under certain conditions; see\n\
-  \GNU General Public License for details.\n"
+notice = $(embedStringFile "notice.txt")
 
 -- | Longer copyright notice.
 
 license :: Text
-license =
-  "MIDA — realization of MIDA, language for generation of MIDI files.\n\
-  \Copyright © 2014–2016 Mark Karpov\n\
-  \\n\
-  \MIDA is free software: you can redistribute it and/or modify it under the\n\
-  \terms of the GNU General Public License as published by the Free Software\n\
-  \Foundation, either version 3 of the License, or (at your option) any\n\
-  \later version.\n\
-  \\n\
-  \MIDA is distributed in the hope that it will be useful, but WITHOUT ANY\n\
-  \WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n\
-  \FOR A PARTICULAR PURPOSE. See the GNU General Public License for more\n\
-  \details.\n\
-  \\n\
-  \You should have received a copy of the GNU General Public License along\n\
-  \with this program. If not, see <http://www.gnu.org/licenses/>.\n"
+license = $(embedStringFile "license.txt")
 
 -- | Read configuration file if present and run MIDA monad.
 
diff --git a/src/Mida/Interaction.hs b/src/Mida/Interaction.hs
--- a/src/Mida/Interaction.hs
+++ b/src/Mida/Interaction.hs
@@ -90,7 +90,7 @@
   file <- gets stSrcFile
   case parseMida (fromAbsFile file) expr of
     Right x -> mapM_ f x
-    Left  x -> liftIO $ fprint (string % "\n") x
+    Left  x -> liftIO (putStr x)
     where f (Definition n t) = processDef n t
           f (Exposition   t) = do
             len     <- gets stPrevLen
diff --git a/src/Mida/Interaction/Commands.hs b/src/Mida/Interaction/Commands.hs
--- a/src/Mida/Interaction/Commands.hs
+++ b/src/Mida/Interaction/Commands.hs
@@ -50,11 +50,11 @@
   , createProcess
   , waitForProcess
   , delegate_ctlc )
-import qualified Codec.Midi as Midi
-import qualified Data.Text.Lazy as T
-import qualified Data.Text.Lazy.IO as T
+import qualified Codec.Midi               as Midi
+import qualified Data.Text.Lazy           as T
+import qualified Data.Text.Lazy.IO        as T
 import qualified System.Console.Haskeline as L
-import qualified System.FilePath as FP
+import qualified System.FilePath          as FP
 
 -- | Description of REPL command.
 
diff --git a/src/Mida/Language.hs b/src/Mida/Language.hs
--- a/src/Mida/Language.hs
+++ b/src/Mida/Language.hs
@@ -19,6 +19,7 @@
 module Mida.Language
   ( SyntaxTree
   , Sel     (..)
+  , Statement (..)
   , Principle
   , Element (..)
   , MidaEnv
@@ -38,7 +39,7 @@
   , toPrin )
 where
 
-import Mida.Language.SyntaxTree (SyntaxTree, Sel (..))
+import Mida.Language.SyntaxTree (SyntaxTree, Sel (..), Statement (..))
 import Mida.Language.Element (Principle, Element (..))
 import Mida.Language.Environment
 import Mida.Language.Eval (evalDef, eval, toPrin)
diff --git a/src/Mida/Language/Element.hs b/src/Mida/Language/Element.hs
--- a/src/Mida/Language/Element.hs
+++ b/src/Mida/Language/Element.hs
@@ -26,6 +26,7 @@
 where
 
 import Control.Arrow ((***))
+import Data.List.NonEmpty (NonEmpty (..))
 import Numeric.Natural
 
 -- | Collection of elements for evaluation, representation of some aspect of
@@ -39,7 +40,7 @@
   = Val  a             -- ^ Single value, evaluates to itself
   | Sec  [Element a]   -- ^ Universal container for other values
   | Mul  [Element a]   -- ^ Multivalue, the way to introduce varying elements
-  | CMul [([Element a], [Element a])] -- ^ Conditional multivalue
+  | CMul (NonEmpty ([Element a], [Element a])) -- ^ Conditional multivalue
     deriving (Eq, Show, Functor, Foldable)
 
 instance Applicative Element where
diff --git a/src/Mida/Language/Environment.hs b/src/Mida/Language/Environment.hs
--- a/src/Mida/Language/Environment.hs
+++ b/src/Mida/Language/Environment.hs
@@ -48,10 +48,11 @@
 import Mida.Representation.Base (noteAlias, modifiers)
 import Mida.Representation.Show (showDefinition)
 import Numeric.Natural
-import System.Console.Haskeline.MonadException -- FIXME
+import System.Console.Haskeline.MonadException
 import System.Random (split)
 import System.Random.TF (TFGen, mkTFGen)
-import qualified Data.Map.Strict as M
+import qualified Data.List.NonEmpty as NE
+import qualified Data.Map.Strict    as M
 
 -- | MIDA environment state. Basically this amounts to collection of
 -- definitions and random number generator.
@@ -184,7 +185,7 @@
         f (Value      _) = mempty
         f (Section    x) = cm x
         f (Multi      x) = cm x
-        f (CMulti     x) = x >>= (cm *** cm >>> uncurry (<>))
+        f (CMulti     x) = NE.toList x >>= (cm *** cm >>> uncurry (<>))
         f (Reference  x) = return x <> tDefs x defs
         f (Range    _ _) = mempty
         f (Product  x y) = f x <> f y
diff --git a/src/Mida/Language/Eval.hs b/src/Mida/Language/Eval.hs
--- a/src/Mida/Language/Eval.hs
+++ b/src/Mida/Language/Eval.hs
@@ -29,6 +29,7 @@
 import Control.Monad.State.Class
 import Control.Monad.State.Lazy
 import Data.List (tails)
+import Data.List.NonEmpty (NonEmpty (..))
 import Data.Maybe (listToMaybe)
 import Data.Monoid ((<>))
 import Mida.Language.Element
@@ -37,6 +38,7 @@
 import Numeric.Natural
 import System.Random (next)
 import System.Random.TF (TFGen)
+import qualified Data.List.NonEmpty as NE
 
 -- | State record used for calculation\/evaluation of principles.
 
@@ -70,8 +72,8 @@
   where f (Val  x) = addHistory x >> return [x]
         f (Sec  x) = resolve x
         f (Mul  x) = choice x >>= maybe (return []) f
-        f (CMul x) = listToMaybe <$> filterM (matchHistory . fst) x >>=
-          maybe (f . toMul $ x) (f . Mul . snd)
+        f (CMul x) = listToMaybe <$> filterM (matchHistory . fst) (NE.toList x)
+          >>= maybe (f . toMul $ x) (f . Mul . snd)
 
 -- | Run lazy state monad with 'CalcSt' state.
 
@@ -112,9 +114,9 @@
 -- | Convert internals of conditional multivalue into plain multivalue.
 
 toMul
-  :: [([Element Natural], [Element Natural])] -- ^ Pattern\/result pairs
+  :: NonEmpty ([Element Natural], [Element Natural]) -- ^ Pattern\/result pairs
   -> Element Natural   -- ^ Internals of plain multivalue
-toMul xs = Mul (xs >>= snd)
+toMul xs = Mul (NE.toList xs >>= snd)
 
 -- | A monadic wrapper around 'condMatch'.
 
@@ -155,13 +157,13 @@
 -- several elements after simplification.
 
 simplifyElt :: Element Natural -> Principle
-simplifyElt x@(Val _)        = [x]
-simplifyElt (Sec  [x])       = simplify [x]
-simplifyElt (Mul  [x])       = simplify [x]
-simplifyElt (CMul [(_, xs)]) = simplifyElt (Mul xs)
-simplifyElt (Sec  xs)        = [Sec (simplifySec xs)]
-simplifyElt (Mul  xs)        = [Mul (simplify xs)]
-simplifyElt (CMul xs)        = [CMul ((simplify *** simplify) <$> xs)]
+simplifyElt x@(Val _)  = [x]
+simplifyElt (Sec  [x]) = simplify [x]
+simplifyElt (Mul  [x]) = simplify [x]
+simplifyElt (CMul ((_, xs):|[])) = simplifyElt (Mul xs)
+simplifyElt (Sec  xs)  = [Sec (simplifySec xs)]
+simplifyElt (Mul  xs)  = [Mul (simplify xs)]
+simplifyElt (CMul xs)  = [CMul ((simplify *** simplify) <$> xs)]
 
 -- | The meat of the algorithm that transforms 'SyntaxTree' into 'Principle'.
 
diff --git a/src/Mida/Language/SyntaxTree.hs b/src/Mida/Language/SyntaxTree.hs
--- a/src/Mida/Language/SyntaxTree.hs
+++ b/src/Mida/Language/SyntaxTree.hs
@@ -18,16 +18,20 @@
 
 module Mida.Language.SyntaxTree
   ( SyntaxTree
-  , Sel (..) )
+  , Sel (..)
+  , Statement (..) )
 where
 
+import Data.Char (isLetter, isAlphaNum)
+import Data.List.NonEmpty (NonEmpty (..))
 import Numeric.Natural
+import Test.QuickCheck
 
 -- | Syntax tree in our case is just a collection of syntactic elements.
 
 type SyntaxTree = [Sel]
 
--- | Syntactic element corresponds to language features. Some of them have
+-- | Syntactic element corresponds to language tokens. Some of them have
 -- direct corresponding constructor in 'Mida.Language.Element.Element',
 -- others have to be simplified first.
 
@@ -35,7 +39,7 @@
   = Value     Natural  -- ^ Literal value
   | Section   [Sel]    -- ^ Section
   | Multi     [Sel]    -- ^ Multivalue
-  | CMulti    [([Sel], [Sel])] -- ^ Conditional multivalue
+  | CMulti    (NonEmpty ([Sel], [Sel])) -- ^ Conditional multivalue
   | Reference String   -- ^ Reference (name of variable)
   | Range     Natural Natural -- ^ Range of values
   | Product   Sel Sel  -- ^ Product of principles
@@ -46,3 +50,53 @@
   | Rotation  Sel Sel  -- ^ Rotation
   | Reverse   Sel      -- ^ Reversed principle
     deriving (Eq, Show)
+
+instance Arbitrary Sel where
+  arbitrary = sized arbitrarySel
+
+arbitrarySel :: Int -> Gen Sel
+arbitrarySel 0 =
+  oneof [ Value     <$> nonNegative
+        , Reference <$> identifier
+        , Range     <$> nonNegative <*> nonNegative ]
+  where nonNegative = getNonNegative <$> arbitrary
+arbitrarySel n =
+  oneof [ Section  <$> listSel
+        , Multi    <$> listSel
+        , CMulti   <$> listCnd
+        , Product  <$> leafSel <*> leafSel
+        , Division <$> leafSel <*> leafSel
+        , Sum      <$> leafSel <*> leafSel
+        , Diff     <$> leafSel <*> leafSel
+        , Loop     <$> leafSel <*> leafSel
+        , Rotation <$> leafSel <*> leafSel
+        , Reverse  <$> leafSel ]
+  where cnSel d = arbitrarySel (n `div` d)
+        vcSel d = listOf (cnSel $ d * 20)
+        leafSel = cnSel 10
+        listSel = vcSel 20
+        listCnd =
+          let x = (,) <$> vcSel 25 <*> vcSel 25
+          in (:|) <$> x <*> listOf x
+
+-- | Statement can be either definition or exposition. Expositions are only
+-- used in REPL.
+
+data Statement
+  = Definition String SyntaxTree
+  | Exposition SyntaxTree
+    deriving (Eq, Show)
+
+instance Arbitrary Statement where
+  arbitrary =
+    oneof [ Definition <$> identifier <*> arbitrary
+          , Exposition <$> arbitrary ]
+
+----------------------------------------------------------------------------
+-- Helpers
+
+identifier :: Gen String
+identifier = (:) <$> ch0 <*> chN
+  where ch0 = u isLetter
+        chN = listOf $ u isAlphaNum
+        u f = frequency [(1, return '_'), (74, arbitrary `suchThat` f)]
diff --git a/src/Mida/Representation.hs b/src/Mida/Representation.hs
--- a/src/Mida/Representation.hs
+++ b/src/Mida/Representation.hs
@@ -18,8 +18,7 @@
 -- with this program. If not, see <http://www.gnu.org/licenses/>.
 
 module Mida.Representation
-  ( Statement (..)
-  , probeMida
+  ( probeMida
   , parseMida
   , showStatement
   , showSyntaxTree
diff --git a/src/Mida/Representation/Parser.hs b/src/Mida/Representation/Parser.hs
--- a/src/Mida/Representation/Parser.hs
+++ b/src/Mida/Representation/Parser.hs
@@ -18,30 +18,22 @@
 -- with this program. If not, see <http://www.gnu.org/licenses/>.
 
 module Mida.Representation.Parser
-  ( Statement (..)
-  , probeMida
+  ( probeMida
   , parseMida )
 where
 
 import Control.Applicative (empty)
 import Control.Monad (void)
 import Data.Text.Lazy (Text)
-import Mida.Language.SyntaxTree (SyntaxTree, Sel (..))
+import Mida.Language.SyntaxTree
 import Numeric.Natural
 import Text.Megaparsec
 import Text.Megaparsec.Expr
 import Text.Megaparsec.Text.Lazy
-import qualified Data.Text.Lazy as T
+import qualified Data.List.NonEmpty       as NE
+import qualified Data.Text.Lazy           as T
 import qualified Mida.Representation.Base as B
-import qualified Text.Megaparsec.Lexer as L
-
--- | Statement can be either definition or exposition. Expositions are only
--- used in REPL.
-
-data Statement
-  = Definition String SyntaxTree
-  | Exposition SyntaxTree
-    deriving (Eq, Show)
+import qualified Text.Megaparsec.Lexer    as L
 
 -- | Test if given fragment of MIDA code is finished and self-contained.
 
@@ -67,7 +59,7 @@
     Right x -> if null x
       then Left ('\"' : file ++ "\":\ninvalid definition syntax")
       else Right x
-    Left  e -> Left (show e)
+    Left  e -> Left (parseErrorPretty e)
   where parser = if T.pack B.defOp `T.isInfixOf` txt
          then pSource
          else pure <$> pExposition
@@ -121,7 +113,8 @@
 pMulti = Multi <$> braces pPrinciple
 
 pCMulti :: Parser Sel
-pCMulti = CMulti <$> braces (many $ (,) <$> angles pPrinciple <*> pPrinciple)
+pCMulti = CMulti . NE.fromList <$>
+  braces (some $ (,) <$> angles pPrinciple <*> pPrinciple)
 
 pExpression :: Parser Sel
 pExpression = makeExprParser (parens pExpression <|> pElement) optTable
diff --git a/src/Mida/Representation/Show.hs b/src/Mida/Representation/Show.hs
--- a/src/Mida/Representation/Show.hs
+++ b/src/Mida/Representation/Show.hs
@@ -30,10 +30,10 @@
 import Data.Text.Lazy (Text)
 import Mida.Language.Element
 import Mida.Language.SyntaxTree
-import Mida.Representation.Parser (Statement (..))
-import qualified Data.Text.Lazy.Builder as T (Builder, fromString, toLazyText)
+import qualified Data.List.NonEmpty         as NE
+import qualified Data.Text.Lazy.Builder     as T (Builder, fromString, toLazyText)
 import qualified Data.Text.Lazy.Builder.Int as T (decimal)
-import qualified Mida.Representation.Base as B
+import qualified Mida.Representation.Base   as B
 
 -- | Render a statement. This handles definitions and expositions.
 
@@ -86,7 +86,7 @@
     f (Value       x) = T.decimal x
     f (Section     x) = "[" <> cm f x <> "]"
     f (Multi       x) = "{" <> cm f x <> "}"
-    f (CMulti      x) = "{" <> cm (c *** cm f >>> uncurry (<>)) x <> "}"
+    f (CMulti      x) = "{" <> cm (c *** cm f >>> uncurry (<>)) (NE.toList x) <> "}"
     f (Reference   x) = T.fromString x
     f (Range     x y) = T.decimal x <> T.fromString B.rangeOp <> T.decimal y
     f (Product   x y) = f x <> pad B.productOp   <> p y
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -1,5 +1,5 @@
 --
--- QuickCheck tests for MIDA.
+-- Test suite of MIDA.
 --
 -- Copyright © 2014–2016 Mark Karpov
 --
@@ -16,84 +16,21 @@
 -- You should have received a copy of the GNU General Public License along
 -- with this program. If not, see <http://www.gnu.org/licenses/>.
 
-{-
-  TODO:
-  - parser for configuration files;
-  - translation from syntax tree to internal language;
-  - process of translation Principle -> [Int];
-  - generation of MIDI files.
--}
-
-{-# OPTIONS -fno-warn-orphans #-}
-
 module Main (main) where
 
-import Control.Arrow ((&&&), (>>>))
-import Data.Char (isLetter, isAlphaNum)
-
-import Test.Framework (defaultMain, testGroup, Test)
-import Test.Framework.Providers.QuickCheck2 (testProperty)
-import Test.QuickCheck
-
-import Mida.Language (Sel (..))
 import Mida.Representation
-  ( Statement (..)
-  , probeMida
-  , parseMida
-  , showStatement )
+import Test.Hspec
+import Test.QuickCheck
 
 main :: IO ()
-main = defaultMain tests
-
-tests :: [Test]
-tests =
-  [ testGroup "Printer and Parser"
-    [ testProperty "Valid MIDA Probe"               prop_valid_probe
-    , testProperty "Printer and Parser Consistency" prop_pp_consistency ] ]
-
-prop_valid_probe :: Statement -> Bool
-prop_valid_probe = probeMida . showStatement
-
-prop_pp_consistency :: Statement -> Bool
-prop_pp_consistency = id &&& (parseMida "" . showStatement) >>> check
-  where check (x, Right [y]) = x == y
-        check _              = False
-
-instance Arbitrary Statement where
-  arbitrary =
-    oneof [ Definition <$> identifier <*> arbitrary
-          , Exposition <$> arbitrary ]
-
-instance Arbitrary Sel where
-  arbitrary = sized arbitrarySel
-
-arbitrarySel :: Int -> Gen Sel
-arbitrarySel 0 =
-  oneof [ Value     <$> nonNegative
-        , Reference <$> identifier
-        , Range     <$> nonNegative <*> nonNegative ]
-  where nonNegative = getNonNegative <$> arbitrary
-arbitrarySel n =
-  oneof [ Section  <$> listSel
-        , Multi    <$> listSel
-        , CMulti   <$> listCnd
-        , Product  <$> leafSel <*> leafSel
-        , Division <$> leafSel <*> leafSel
-        , Sum      <$> leafSel <*> leafSel
-        , Diff     <$> leafSel <*> leafSel
-        , Loop     <$> leafSel <*> leafSel
-        , Rotation <$> leafSel <*> leafSel
-        , Reverse  <$> leafSel ]
-  where cnSel d = arbitrarySel (n `div` d)
-        vcSel d = (getNonNegative <$> arbitrary)
-                  >>= \s -> vectorOf s (cnSel $ d * s)
-        leafSel = cnSel 2
-        listSel = vcSel 1
-        listCnd = (getPositive <$> arbitrary)
-                  >>= \s -> vectorOf s $ (,) <$> vcSel s <*> vcSel s
+main = hspec spec
 
-identifier :: Gen String
-identifier = (:) <$> ch0 <*> chN
-  where ch0 = u isLetter
-        chN = listOf $ u isAlphaNum
-        u f = frequency [(1, return '_'), (74, arbitrary `suchThat` f)]
+spec :: Spec
+spec = do
+  describe "probeMida" $
+    it "returns True for every correct statement" $
+      property (probeMida . showStatement)
+  describe "parser and printer" $
+    it "printed representation of statement can be parsed back" $
+      property $ \stmt ->
+        parseMida "" (showStatement stmt) `shouldBe` Right [stmt]
