diff --git a/Data/Text/Format/Heavy/Build.hs b/Data/Text/Format/Heavy/Build.hs
--- a/Data/Text/Format/Heavy/Build.hs
+++ b/Data/Text/Format/Heavy/Build.hs
@@ -1,33 +1,43 @@
 {-# LANGUAGE OverloadedStrings #-}
 
 module Data.Text.Format.Heavy.Build
-  (format, formatEither,
-   makeBuilder,
+  ( format
+  , formatEither
+  , makeBuilder
+  ,
    -- * Formatters building utilities
-   align, applySign, applySharp, convertText,
-   formatInt, formatStr, formatFloat, formatBool
-  ) where
+    align
+  , applySign
+  , applySharp
+  , convertText
+  , formatInt
+  , formatStr
+  , formatFloat
+  , formatBool
+  )
+where
 
-import Control.Monad
-import Data.Monoid
-import Data.Maybe
-import qualified Data.Text as T
-import qualified Data.Text.Lazy as TL
-import qualified Data.Text.Lazy.Builder as B
-import Data.Text.Lazy.Builder.Int (decimal, hexadecimal)
-import Data.Text.Lazy.Builder.RealFloat
+import           Control.Monad
+import           Data.Monoid
+import           Data.Maybe
+import qualified Data.Text                     as T
+import qualified Data.Text.Lazy                as TL
+import qualified Data.Text.Lazy.Builder        as B
+import           Data.Text.Lazy.Builder.Int     ( decimal
+                                                , hexadecimal
+                                                )
+import           Data.Text.Lazy.Builder.RealFloat
 
-import Data.Text.Format.Heavy.Types
-import Data.Text.Format.Heavy.Formats
+import           Data.Text.Format.Heavy.Types
+import           Data.Text.Format.Heavy.Formats
 
 makeBuilder :: VarContainer c => Format -> c -> Either String B.Builder
 makeBuilder (Format items) vars = mconcat `fmap` mapM go items
-  where
-    go (FString s) = Right $ B.fromLazyText s
-    go (FVariable name fmt) =
-      case lookupVar name vars of
-        Nothing -> Left $ "Parameter not found: " ++ TL.unpack name
-        Just var -> formatVar fmt var
+ where
+  go (FString s         ) = Right $ B.fromLazyText s
+  go (FVariable name fmt) = case lookupVar name vars of
+    Nothing  -> Left $ "Parameter not found: " ++ TL.unpack name
+    Just var -> formatVar fmt var
 {-# INLINE makeBuilder #-}
 
 -- | The main formatting function.
@@ -36,10 +46,10 @@
 format fmt vars = either error id $ formatEither fmt vars
 
 -- | The main formatting function.
--- This version returns @Left@ value with error description in case of error in 
+-- This version returns @Left@ value with error description in case of error in
 -- format string or error during formatting.
 formatEither :: VarContainer vars => Format -> vars -> Either String TL.Text
-formatEither fmt vars = either Left (Right . B.toLazyText) $ makeBuilder fmt vars
+formatEither fmt vars = B.toLazyText `fmap` makeBuilder fmt vars
 
 align' :: Int -> Align -> Char -> B.Builder -> B.Builder
 align' width AlignLeft fill text =
@@ -51,65 +61,65 @@
 
 -- | Align text within available width according to format
 align :: GenericFormat -> B.Builder -> B.Builder
-align fmt text =
-  case (gfAlign fmt, gfWidth fmt) of
-    (Just a, Just w) -> align' w a (gfFillChar fmt) text
-    _ -> text
+align fmt text = case (gfAlign fmt, gfWidth fmt) of
+  (Just a, Just w) -> align' w a (gfFillChar fmt) text
+  _                -> text
 
 -- | Add @+/-@ sign to the number representation, if required
 applySign :: (Num a, Ord a) => Sign -> a -> B.Builder -> B.Builder
 applySign Always x text =
-  if x >= 0
-    then B.singleton '+' <> text
-    else B.singleton '-' <> text
+  if x >= 0 then B.singleton '+' <> text else B.singleton '-' <> text
 applySign OnlyNegative x text =
-  if x >= 0
-    then text
-    else B.singleton '-' <> text
+  if x >= 0 then text else B.singleton '-' <> text
 applySign SpaceForPositive x text =
-  if x >= 0
-    then B.singleton ' ' <> text
-    else B.singleton '-' <> text
+  if x >= 0 then B.singleton ' ' <> text else B.singleton '-' <> text
 
 -- | Add @0x@ to the number representation, if required
 applySharp :: Bool -> Radix -> B.Builder -> B.Builder
-applySharp False _ text = text
-applySharp True Decimal text = text
-applySharp True Hexadecimal text = B.fromLazyText "0x" <> text
+applySharp False _           text = text
+applySharp True  Decimal     text = text
+applySharp True  Hexadecimal text = B.fromLazyText "0x" <> text
 
 -- | Apply text conversion.
 convertText :: Maybe Conversion -> B.Builder -> B.Builder
-convertText Nothing builder = builder
-convertText (Just conv) builder = B.fromLazyText $ converter $ B.toLazyText builder
-  where
-    converter = case conv of
-                  UpperCase -> TL.toUpper
-                  LowerCase -> TL.toLower
-                  TitleCase -> TL.toTitle
+convertText Nothing     builder = builder
+convertText (Just conv) builder = B.fromLazyText $ converter $ B.toLazyText
+  builder
+ where
+  converter = case conv of
+    UpperCase -> TL.toUpper
+    LowerCase -> TL.toLower
+    TitleCase -> TL.toTitle
 
 -- | Format integer number according to GenericFormat
 formatInt :: Integral a => GenericFormat -> a -> B.Builder
-formatInt fmt x = align fmt $ applySign (gfSign fmt) x $ applySharp (gfLeading0x fmt) radix $ inRadix
-  where
-   radix = fromMaybe Decimal (gfRadix fmt)
-   inRadix = case radix of
-               Decimal -> decimal (abs x)
-               Hexadecimal -> hexadecimal (abs x)
+formatInt fmt x = align fmt $ applySign (gfSign fmt) x $ applySharp
+  (gfLeading0x fmt)
+  radix
+  inRadix
+ where
+  radix = fromMaybe Decimal (gfRadix fmt)
+  conversion = fromMaybe LowerCase (gfConvert fmt)
+  inRadix = case radix of
+    Decimal     -> decimal (abs x)
+    Hexadecimal -> case conversion of
+      LowerCase -> hexadecimal (abs x)
+      _         -> B.fromLazyText . TL.toUpper . B.toLazyText . hexadecimal . abs $ x
 
 -- | Format floating-point number according to GenericFormat
 formatFloat :: RealFloat a => GenericFormat -> a -> B.Builder
 formatFloat fmt x =
-    align fmt
+  align fmt
     $ applySign (gfSign fmt) x
     $ formatRealFloat Fixed (gfPrecision fmt)
     $ abs x
 
 -- | Format Text according to GenericFormat.
 formatStr :: GenericFormat -> TL.Text -> B.Builder
-formatStr fmt text = convertText (gfConvert fmt) $ align fmt $ B.fromLazyText text
+formatStr fmt text =
+  convertText (gfConvert fmt) $ align fmt $ B.fromLazyText text
 
 -- | Format boolean value.
 formatBool :: BoolFormat -> Bool -> B.Builder
-formatBool fmt True = B.fromLazyText $ bfTrue fmt
+formatBool fmt True  = B.fromLazyText $ bfTrue fmt
 formatBool fmt False = B.fromLazyText $ bfFalse fmt
-
diff --git a/Data/Text/Format/Heavy/Parse/VarFormat.hs b/Data/Text/Format/Heavy/Parse/VarFormat.hs
--- a/Data/Text/Format/Heavy/Parse/VarFormat.hs
+++ b/Data/Text/Format/Heavy/Parse/VarFormat.hs
@@ -4,10 +4,11 @@
   where
 
 import Data.Maybe
+import Control.Applicative ((<|>))
 import qualified Data.Text as T
 import qualified Data.Text.Lazy as TL
 import qualified Data.Text.Lazy.Builder as B
-import Text.Parsec
+import Text.Parsec hiding ((<|>))
 
 import Data.Text.Format.Heavy.Types
 import Data.Text.Format.Heavy.Formats
@@ -24,7 +25,7 @@
     let leading0x = fromMaybe False mbLeading0x
     mbWidth <- optionMaybe (pWidth <?> "width specification")
     mbPrecision <- optionMaybe (pPrecision <?> "precision specification")
-    mbRadix <- optionMaybe (pRadix <?> "radix specification")
+    mbRadixConvert <- optionMaybe (pRadix <?> "radix specification")
     mbConvert <- optionMaybe (pConvert <?> "conversion specification")
     return $ GenericFormat {
                gfFillChar = fill
@@ -33,8 +34,8 @@
              , gfLeading0x = leading0x
              , gfWidth = mbWidth
              , gfPrecision = mbPrecision
-             , gfRadix = mbRadix
-             , gfConvert = mbConvert
+             , gfRadix = fst <$> mbRadixConvert
+             , gfConvert = mbConvert <|> fmap snd mbRadixConvert
              }
   where
     pAlign :: Parsec TL.Text st Align
@@ -91,14 +92,16 @@
     pPrecision = do
       char '.'
       natural
-    
-    pRadix :: Parsec TL.Text st Radix
+
+    pRadix :: Parsec TL.Text st (Radix, Conversion)
     pRadix = do
-      rc <- oneOf "xhd"
+      rc <- oneOf "xXhHd"
       case rc of
-        'x' -> return Hexadecimal
-        'h' -> return Hexadecimal
-        'd' -> return Decimal
+        'x' -> return (Hexadecimal, LowerCase)
+        'X' -> return (Hexadecimal, UpperCase)
+        'h' -> return (Hexadecimal, LowerCase)
+        'H' -> return (Hexadecimal, UpperCase)
+        'd' -> return (Decimal, LowerCase)
 
     pConvert :: Parsec TL.Text st Conversion
     pConvert = do
@@ -175,4 +178,3 @@
   in  if TL.null xFmtStr
         then Nothing
         else Just (TL.init xFmtStr, nothingStr)
-
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
 text-format-heavy README
 ========================
 
+[![Build Status](https://travis-ci.org/portnov/text-format-heavy.svg?branch=master)](https://travis-ci.org/portnov/text-format-heavy)
+
 This is Haskell string formatting library, which prefers functionality and
 extendability over light weight and (probably, in some cases) performance.
 This library is more or less analog of Python's string.format function, and
diff --git a/tests/Spec.hs b/tests/Spec.hs
new file mode 100644
--- /dev/null
+++ b/tests/Spec.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Test.Hspec
+import Data.Time
+
+import Data.Text.Format.Heavy
+import Data.Text.Format.Heavy.Time
+
+main :: IO ()
+main = hspec $ do
+  describe "trivial" $ do
+    it "formats string literal without formatting characters" $ do
+      format "hello world" () `shouldBe` "hello world"
+
+  describe "simple" $ do
+    it "formats int properly" $ do
+      format "integer: {}" (Single (7 :: Int)) `shouldBe` "integer: 7"
+
+    it "formats strings properly" $ do
+      format "string: {}" (Single ("hello" :: String)) `shouldBe` "string: hello"
+
+    it "handles parameter numbers" $ do
+      format "one: {0}, two: {1}" ((1:: Int), (2::Int)) `shouldBe` "one: 1, two: 2"
+      format "two: {1}, one: {0}" ((1:: Int), (2::Int)) `shouldBe` "two: 2, one: 1"
+
+  describe "documentation" $ do
+    it "formats examples from wiki" $ do
+      format "hex: {:#x}" (Single (427 :: Int)) `shouldBe` "hex: 0x1ab"
+      format "hex: {:#h}" (Single (427 :: Int)) `shouldBe` "hex: 0x1ab"
+      format "hex: {:#X}" (Single (427 :: Int)) `shouldBe` "hex: 0x1AB"
+      format "hex: {:#H}" (Single (427 :: Int)) `shouldBe` "hex: 0x1AB"
+      format "dec: {:#d}" (Single (17 :: Int)) `shouldBe` "dec: 17"
+      format "center: <{0:^10}>" (Single ("hello" :: String)) `shouldBe` "center: <   hello  >"
+      format "float: {:+6.4}" (Single (2.718281828 :: Double)) `shouldBe` "float: +2.7183"
+
+    it "formats booleans" $ do
+      format "default: {}" (Single True) `shouldBe` "default: true"
+      format "enable: {:yes:no}" (Single False) `shouldBe` "enable: no"
+
+    it "formats maybes" $ do
+      format "Value: {:.3|<undefined>}." (Single (2.718281828 :: Float)) `shouldBe` "Value: 2.718."
+      format "Value: {:.3|<undefined>}." (Single (Nothing :: Maybe Float)) `shouldBe` "Value: <undefined>."
+      format "Value: {:.3}." (Single (Nothing :: Maybe Float)) `shouldBe` "Value: ."
+
+    it "formats time" $ do
+      let Just time = parseTimeM True defaultTimeLocale rfc822DateFormat "Sat,  3 Jun 2017 19:06:01 YEKT" :: Maybe ZonedTime
+      format "time: {:%H:%M:%S}" (Single time) `shouldBe` "time: 19:06:01"
+      format "time: {:%H:%M:%S %Z}" (Single time) `shouldBe` "time: 19:06:01 YEKT"
+      format "default: {}" (Single time) `shouldBe` "default: Sat,  3 Jun 2017 19:06:01 YEKT"
+
diff --git a/text-format-heavy.cabal b/text-format-heavy.cabal
--- a/text-format-heavy.cabal
+++ b/text-format-heavy.cabal
@@ -1,64 +1,83 @@
-name:                text-format-heavy
-version:             0.1.5.2
-synopsis:            Full-weight string formatting library, analog of Python's string.format
-description:         This package contains full-featured string formatting function, similar to
-                     Python's string.format. Features include:
-                     .
-                     * Automatically numbered variable placeholders;
-                     .
-                     * Positional variable placeholders;
-                     .
-                     * Named variable placeholders;
-                     .
-                     * Placeholders can be used in any order; one variable can be used several
-                       times or not used at all.
-                     .
-                     * Specific format can be used for each variable substitution.
-                     .
-                     This package prefers functionality over "light weight" and (probably) performance. 
-                     It also exposes all required interfaces to extend and customize it.
-                     .
-                     For more details, please refer to <https://github.com/portnov/text-format-heavy/wiki Wiki>.
-                     See also the @examples/@ directory.
-                     
-license:             BSD3
-license-file:        LICENSE
-author:              Ilya Portnov
-maintainer:          portnov84@rambler.ru
--- copyright:           
-category:            Text
-build-type:          Simple
-extra-source-files:  ChangeLog.md,
-                     README.md,
-                     examples/test.hs,
-                     examples/Benchmarks.hs
-cabal-version:       >=1.10
+cabal-version: 1.12
 
-library
-  exposed-modules:     Data.Text.Format.Heavy,
-                       Data.Text.Format.Heavy.Parse,
-                       Data.Text.Format.Heavy.Parse.Types,
-                       Data.Text.Format.Heavy.Parse.VarFormat,
-                       Data.Text.Format.Heavy.Parse.Braces,
-                       Data.Text.Format.Heavy.Parse.Shell,
-                       Data.Text.Format.Heavy.Build,
-                       Data.Text.Format.Heavy.Types,
-                       Data.Text.Format.Heavy.Formats,
-                       Data.Text.Format.Heavy.Instances,
-                       Data.Text.Format.Heavy.Time
-  -- other-modules:       
-  other-extensions:    ExistentialQuantification
-  build-depends:       base >=4.8 && <5,
-                       text >=1.2 && <1.3,
-                       bytestring >= 0.10,
-                       parsec >=3.1 && <3.2,
-                       containers >= 0.5,
-                       data-default >= 0.7,
-                       time >= 1.5
-  -- hs-source-dirs:      
-  default-language:    Haskell2010
+-- This file has been generated from package.yaml by hpack version 0.31.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 8997cbee7e77bc2355f247d0ff85ba397d2b6e2414b974868c48f7b720aaf3e6
 
+name:           text-format-heavy
+version:        0.1.5.3
+synopsis:       Full-weight string formatting library, analog of Python's string.format
+description:    This package contains full-featured string formatting function, similar to Python's string.format. Features include:
+                * Automatically numbered variable placeholders;
+                * Positional variable placeholders;
+                * Named variable placeholders;
+                * Placeholders can be used in any order; one variable can be used several
+                  times or not used at all.
+                .
+                * Specific format can be used for each variable substitution.
+                This package prefers functionality over "light weight" and (probably) performance.  It also exposes all required interfaces to extend and customize it.
+                For more details, please refer to <https://github.com/portnov/text-format-heavy/wiki Wiki>. See also the @examples/@ directory.
+category:       Text
+homepage:       https://github.com/portnov/text-format-heavy#readme
+bug-reports:    https://github.com/portnov/text-format-heavy/issues
+author:         Ilya Portnov
+maintainer:     portnov84@rambler.ru
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    ChangeLog.md
+    README.md
+    examples/test.hs
+    examples/Benchmarks.hs
+
 source-repository head
   type: git
-  location: https://github.com/portnov/text-format-heavy.git
+  location: https://github.com/portnov/text-format-heavy
 
+library
+  exposed-modules:
+      Data.Text.Format.Heavy
+      Data.Text.Format.Heavy.Build
+      Data.Text.Format.Heavy.Formats
+      Data.Text.Format.Heavy.Instances
+      Data.Text.Format.Heavy.Parse
+      Data.Text.Format.Heavy.Parse.Braces
+      Data.Text.Format.Heavy.Parse.Shell
+      Data.Text.Format.Heavy.Parse.Types
+      Data.Text.Format.Heavy.Parse.VarFormat
+      Data.Text.Format.Heavy.Time
+      Data.Text.Format.Heavy.Types
+  other-modules:
+      Paths_text_format_heavy
+  hs-source-dirs:
+      ./.
+  build-depends:
+      base >=4.8 && <5
+    , bytestring >=0.10
+    , containers >=0.5
+    , data-default >=0.7
+    , labels
+    , parsec >=3.1 && <3.2
+    , template-haskell >=2.8
+    , text >=1.2 && <1.3
+    , th-lift
+    , th-lift-instances
+    , time >=1.5
+  default-language: Haskell2010
+
+test-suite spec
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Paths_text_format_heavy
+  hs-source-dirs:
+      tests
+  build-depends:
+      base >=4.8 && <5
+    , hspec
+    , text-format-heavy
+    , time >=1.5
+  default-language: Haskell2010
