diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,13 @@
 # Changelog for hpc-threshold
 
+## 0.1.0.1
+
+Added more documentation.
+
+## 0.1.0.0
+
+Initial release, feature working.
+
 ## Unreleased changes
+
+None
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,30 +1,13 @@
-Copyright Author name here (c) 2018
+Note: This license has also been called the "New BSD License" or "Modified BSD License". See also the 2-clause BSD License.
 
-All rights reserved.
+Copyright 2018 Ecky Putrady
 
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials provided
-      with the distribution.
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 
-    * Neither the name of Author name here nor the names of other
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,18 +1,21 @@
 # hpc-threshold
 
-This is a small utility for validating whether HPC result is above some defined thresholds. This program is meant to be used within a CI pipeline, in which the build will fail if the code coverage falls below the thresholds.
+[![Build Status](https://travis-ci.org/eckyputrady/hpc-threshold.svg?branch=master)](https://travis-ci.org/eckyputrady/hpc-threshold)
+[![Hackage version](https://img.shields.io/hackage/v/hpc-threshold.svg?label=Hackage)](https://hackage.haskell.org/package/hpc-threshold)
 
-The program reads a configuration file named `.hspec-threshold` and parse HPC text from stdin. The program outputs a report and will terminate with status code 1 if the coverage falls below threshold, and 0 otherwise.
+`hpc-threshold` ensures the code coverage of your Haskell project is above configured thresholds. This program is meant to be used within a CI pipeline, in which the build will fail if the code coverage falls below the configured thresholds.
 
+The program reads a configuration file named `.hpc-threshold` and parse [Haskell Program Coverage (HPC)](https://wiki.haskell.org/Haskell_program_coverage) text from `stdin`. The program outputs a report and will terminate with exit code 1 if the coverage falls below the configured threshold, and exit code 0 otherwise.
+
 ## User Guide
 
-Install the utility by using stack
+Install the program by using stack
 
 ```
 stack install hpc-threshold
 ```
 
-Then, create a configuration file named `.hspec-threshold`:
+Then, create a configuration file named `.hpc-threshold`:
 
 ```
 [ Threshold 
@@ -43,9 +46,9 @@
 ]
 ```
 
-- `thresholdRegex` is the regex to be used for extracting the coverage from HPC report. It requires 1 digit capture.
+- `thresholdRegex` is the regex to be used for extracting the coverage from HPC report. There should be one `(\\d+)` in the regex.
 - `thresholdValue` is the threshold for the code coverage.
-- `thresholdName` will be used for the threshold report
+- `thresholdName` will be used for the threshold report.
 
 Then, build the coverage report:
 
@@ -56,10 +59,10 @@
 Then, generate a text report and feed that into `hpc-threshold`:
 
 ```
-(stack hpc report --all 2&>1) | hpc-threshold
+stack hpc report --all 2>&1 | hpc-threshold
 ```
 
-The stderr -> stdout redirection is necessary there because `stack hpc report` outputs the result in stderr, but we want to pipe that into `hpc-threshold`.
+The `stderr` -> `stdout` redirection is necessary there because `stack hpc report` outputs the result in `stderr`, but we want to pipe that into `hpc-threshold`.
 
 Then, you'll get an output similar to the following:
 
@@ -72,7 +75,7 @@
 ✓ Top-level declarations used: 80.0% (≥ 80.0%)
 ```
 
-If we check the exit code of the last process, we'll get `1` since some coverage areas are below the configured threshold
+If we check the exit code of the last process, we'll get `1` since some code coverage areas are below the configured threshold:
 
 ```
 $ echo $?
@@ -90,9 +93,13 @@
 ✓ Top-level declarations used: 80.0% (≥ 80.0%)
 ```
 
-And the exit code is 0
+And the exit code is 0:
 
 ```
 $ echo $?
 0
 ```
+
+## Developer Guide
+
+See `.travis.yml`, under `scripts` section to see how to build the application
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,6 +1,14 @@
 module Main where
 
 import Lib
+import System.Exit
 
 main :: IO ()
-main = evaluateAndReport'
+main = do
+  thresholds <- read <$> readFile ".hpc-threshold"
+  src <- getContents
+  let (report, isPass) = evaluateAndReport src thresholds
+  putStrLn report
+  if isPass
+    then exitWith ExitSuccess
+    else exitWith $ ExitFailure 1
diff --git a/hpc-threshold.cabal b/hpc-threshold.cabal
--- a/hpc-threshold.cabal
+++ b/hpc-threshold.cabal
@@ -2,11 +2,11 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: c770159c575ceb1fb6989ed0a07fe3b4b8c6bead95f64e6fe17a1420a10a7189
+-- hash: 430b6966ee845f290543a6c8947d35feda02426dfb190eec88e3f92020f042f0
 
 name:           hpc-threshold
-version:        0.1.0.0
-synopsis:       Small utility for validating whether HPC result is above defined thresholds
+version:        0.1.0.1
+synopsis:       Configurable code coverage threshold for Haskell
 description:    Please see the README on Github at <https://github.com/eckyputrady/hpc-threshold#readme>
 category:       Development
 homepage:       https://github.com/eckyputrady/hpc-threshold#readme
@@ -31,6 +31,7 @@
   hs-source-dirs:
       src
   default-extensions: OverloadedStrings QuasiQuotes
+  ghc-options: -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
   build-depends:
       base >=4.7 && <5
     , bytestring
@@ -47,7 +48,7 @@
   hs-source-dirs:
       app
   default-extensions: OverloadedStrings QuasiQuotes
-  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  ghc-options: -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
   build-depends:
       base >=4.7 && <5
     , hpc-threshold
@@ -61,10 +62,13 @@
   hs-source-dirs:
       test
   default-extensions: OverloadedStrings QuasiQuotes
-  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  ghc-options: -Wall -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
   build-depends:
       base >=4.7 && <5
+    , deepseq
     , hpc-threshold
+    , hspec
   other-modules:
+      LibSpec
       Paths_hpc_threshold
   default-language: Haskell2010
diff --git a/src/Lib.hs b/src/Lib.hs
--- a/src/Lib.hs
+++ b/src/Lib.hs
@@ -3,22 +3,28 @@
 import Text.Regex.PCRE.Heavy
 import Data.ByteString (ByteString)
 import Data.String.Interpolate
-import System.Exit
 
+-- | Data structure for a single threshold configuration.
 data Threshold = Threshold
   { thresholdName :: String
   , thresholdRegex :: ByteString
   , thresholdValue :: Double
-  } deriving (Read, Show)
+  } deriving (Read, Show, Eq)
 
 type Coverage = Double
+
+-- | The result of evaluation. The _3 indicates whether the coverage passes the threshold or not.
 type ThresholdEvaluationResult = (Threshold, Coverage, Bool)
 
-extractCoverage :: String -> ByteString -> Double
+-- | Extract the coverage from input string using a regex string
+extractCoverage 
+  :: String -- ^ The input string
+  -> ByteString -- ^ The regex to extract the coverage. The regex should contain `(\\d+)` capture otherwise the coverage is always be 0.
+  -> Coverage -- ^ The extracted coverage
 extractCoverage src regexStr =
   case compileM regexStr [] of
     Left e ->
-      error e
+      error $ "Unable to compile regex " ++ show regexStr ++ ": " ++ e 
     Right regex ->
       case scan regex src of
         (_, coverage:_):_ ->
@@ -26,28 +32,34 @@
         _ ->
           0
 
-evaluate :: String -> [Threshold] -> [ThresholdEvaluationResult]
-evaluate src thresholds = do
-  threshold <- thresholds
+-- | Evaluate the given string against the given threshold, producing an evaluation result
+evaluate :: String -> Threshold -> ThresholdEvaluationResult
+evaluate src threshold =
   let 
     coverage =
       extractCoverage src (thresholdRegex threshold)
     isPass =
       coverage >= thresholdValue threshold
-  return (threshold, coverage, isPass)
+  in
+    (threshold, coverage, isPass)
 
+-- | Produce a human-friendly output of the evaluation result
 reportThreshold :: ThresholdEvaluationResult -> String
 reportThreshold (Threshold tName _ tValue, coverage, isPass) =
   let
-    remark = if isPass then "✓" else "·"
-    sign = if isPass then "≥" else "<"
+    remark = if isPass then "✓" else "·" :: String
+    sign = if isPass then "≥" else "<" :: String
   in
     [i|#{remark} #{tName}: #{coverage}% (#{sign} #{tValue}%)|]
 
-evaluateAndReport :: String -> [Threshold] -> (String, Bool)
+-- | Evaluate a string against a list of thresholds configuration and produce a report
+evaluateAndReport
+  :: String -- ^ The input string
+  -> [Threshold] -- ^ The list of thresholds
+  -> (String, Bool) -- ^ Pair of report and whether there is any coverage under thresholds
 evaluateAndReport src thresholds =
   let
-    evalResults = evaluate src thresholds
+    evalResults = map (evaluate src) thresholds
     isAllThresholdPass = all (\(_, _, isPass) -> isPass) evalResults
     reportSummary =
       if isAllThresholdPass
@@ -56,14 +68,4 @@
     report = unlines $ reportSummary : map reportThreshold evalResults
   in
     (report, isAllThresholdPass)
-
-evaluateAndReport' :: IO ()
-evaluateAndReport' = do
-  thresholds <- readFile ".hpc-threshold" >>= return . read
-  src <- getContents
-  let (report, isPass) = evaluateAndReport src thresholds
-  putStrLn report
-  if isPass
-    then exitWith ExitSuccess
-    else exitWith $ ExitFailure 1
 
diff --git a/test/LibSpec.hs b/test/LibSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/LibSpec.hs
@@ -0,0 +1,63 @@
+module LibSpec where
+
+import Test.Hspec
+import qualified Control.Exception as E
+import qualified Control.DeepSeq as D
+import Lib
+
+spec :: Spec
+spec = do
+  describe "Threshold" $
+    it "should be parsable from string" $ do
+      let threshold = Threshold "abc" "(\\d+)% abc" 80
+      (read . show) threshold `shouldBe` threshold
+
+  describe "extractCoverage" $ do
+    it "should fail with invalid regexStr" $
+      (E.evaluate . D.force) (extractCoverage "irrelevant" "ab(c")
+        `shouldThrow` anyErrorCall
+    it "should return 0 for regex with no digit capture" $
+      extractCoverage "12% abc" "abc" `shouldBe` 0
+    it "should return 0 if input string does not match regex" $
+      extractCoverage "12% abc" "(\\d+) abc" `shouldBe` 0
+    it "should capture the coverage" $
+      extractCoverage "12% abc" "(\\d+)% abc" `shouldBe` 12
+
+  describe "evaluate" $ do
+    let threshold = Threshold "abc" "(\\d+)% abc" 80
+    it "should correctly evaluate coverage < threshold as FAIL" $
+      evaluate "10% abc" threshold `shouldBe` (threshold, 10, False)
+    it "should correctly evaluate coverage == threshold as PASS" $
+      evaluate "80% abc" threshold `shouldBe` (threshold, 80, True)
+    it "should correctly evaluate coverage > threshold as PASS" $
+      evaluate "100% abc" threshold `shouldBe` (threshold, 100, True)
+
+  describe "reportThreshold" $ do
+    it "should print passing result correctly" $ do
+      let evalResult = (Threshold "abc" "(\\d+)% abc" 80, 80, True)
+      reportThreshold evalResult `shouldBe` "✓ abc: 80.0% (≥ 80.0%)"
+    it "should print failing result correctly" $ do
+      let evalResult = (Threshold "abc" "(\\d+)% abc" 80, 70, False)
+      reportThreshold evalResult `shouldBe` "· abc: 70.0% (< 80.0%)"
+
+  describe "evaluateAndReport" $ do
+    let thresholds =
+          [ Threshold "abc" "(\\d+)% abc" 80
+          , Threshold "def" "(\\d+)% def" 80
+          ]
+    it "should report passing result correctly" $
+      evaluateAndReport "80% abc -- 80% def" thresholds `shouldBe`
+        ( unlines [ "Code coverage threshold check: PASS"
+                  , "✓ abc: 80.0% (≥ 80.0%)"
+                  , "✓ def: 80.0% (≥ 80.0%)"
+                  ]
+        , True
+        )
+    it "should report failing result correctly" $
+      evaluateAndReport "70% abc -- 80% def" thresholds `shouldBe`
+        ( unlines [ "Code coverage threshold check: FAIL"
+                  , "· abc: 70.0% (< 80.0%)"
+                  , "✓ def: 80.0% (≥ 80.0%)"
+                  ]
+        , False
+        )
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,2 +1,1 @@
-main :: IO ()
-main = putStrLn "Test suite not yet implemented"
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
