diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011, 2012 Simon Hengel <sol@typeful.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.lhs b/README.lhs
new file mode 100644
--- /dev/null
+++ b/README.lhs
@@ -0,0 +1,113 @@
+# Catchy combinators for HUnit
+
+(inspired by [ScalaTest's ShouldMatchers](http://www.scalatest.org/))
+
+The three main primitives are `shouldBe`, `shouldSatisfy` and
+`shouldThrow`. They can be used with
+[HUnit](http://hackage.haskell.org/package/HUnit), or any framework that
+integrates with HUnit, like
+[test-framework](http://hackage.haskell.org/package/test-framework) or
+[Hspec](http://hackage.haskell.org/package/hspec).
+
+## An introductory example
+
+Here is an example that uses Hspec. It's a partial specification of
+itself.
+
+~~~ {.haskell .literate}
+import Test.Hspec.Monadic
+import Test.Hspec.HUnit ()
+import Test.Hspec.Expectations
+import Control.Exception
+
+main :: IO ()
+main = hspec $ do
+
+  describe "shouldBe" $ do
+
+    it "asserts equality" $ do
+      "foo" `shouldBe` "foo"
+
+  describe "shouldSatisfy" $ do
+
+    it "asserts that a predicate holds" $ do
+      "bar" `shouldSatisfy` (not . null)
+
+  describe "shouldThrow" $ do
+
+    it "asserts that an exception is thrown" $ do
+      throw DivideByZero `shouldThrow` (== DivideByZero)
+~~~
+
+## shouldBe
+
+`shouldBe` is just an alias for HUnit's `@?=`.
+
+## shouldSatisfy
+
+`shouldSatisfy` asserts that some predicate holds for a given value.
+
+~~~ {.haskell}
+"bar" `shouldSatisfy` (not . null)
+~~~
+
+It is similar to HUnit's `assertBool`, but gives a useful error message.
+
+    >>> 23 `shouldSatisfy` (> 42)
+    *** Exception: HUnitFailure "23 did not satisfy predicate!"
+
+## shouldReturn
+
+`shouldReturn` asserts that an action returns a given value.
+
+~~~ {.haskell}
+return "bar" `shouldReturn` "bar"
+~~~
+
+## shouldThrow
+
+`shouldThrow` asserts that an exception is thrown. The precise nature of
+that exception is described with a `Selector`.
+
+~~~ {.haskell}
+error "foobar" `shouldThrow` anyException
+~~~
+
+A `Selector` is a predicate, it can simultaneously constrain the type
+and value of an exception.
+
+~~~ {.haskell}
+throw DivideByZero `shouldThrow` (== DivideByZero)
+~~~
+
+To select all exceptions of a given type, `const True` can be used.
+
+~~~ {.haskell}
+error "foobar" `shouldThrow` (const True :: Selector ErrorCall)
+~~~
+
+For convenience, predefined selectors for some standard exceptions are
+provided.
+
+~~~ {.haskell}
+error "foobar" `shouldThrow` anyErrorCall
+~~~
+
+Some exceptions (like `ErrorCall`) have no `Eq` instance, so checking
+for a specific value requires pattern matching.
+
+~~~ {.haskell}
+error "foobar" `shouldThrow` (\e -> case e of
+    ErrorCall "foobar" -> True
+    _ -> False
+    )
+~~~
+
+For such exceptions, combinators that construct selectors are provided.
+Each combinator corresponds to a constructor; it takes the same
+arguments, and has the same name (but starting with a lower-case
+letter).
+
+~~~ {.haskell}
+error "foobar" `shouldThrow` errorCall "foobar"
+~~~
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/hspec-expectations.cabal b/hspec-expectations.cabal
new file mode 100644
--- /dev/null
+++ b/hspec-expectations.cabal
@@ -0,0 +1,58 @@
+name:             hspec-expectations
+version:          0.3.0
+synopsis:         Catchy combinators for HUnit
+description:      Catchy combinators for HUnit: <https://github.com/sol/hspec-expectations#readme>
+license:          MIT
+license-file:     LICENSE
+copyright:        (c) 2011, 2012 Simon Hengel
+author:           Simon Hengel <sol@typeful.net>
+maintainer:       Simon Hengel <sol@typeful.net>
+build-type:       Simple
+category:         Testing
+cabal-version:    >= 1.8
+homepage:         https://github.com/sol/hspec-expectations#readme
+
+source-repository head
+  type: git
+  location: https://github.com/sol/hspec-expectations
+
+library
+  ghc-options:
+      -Wall
+  build-depends:
+      base < 4.6
+    , HUnit
+  hs-source-dirs:
+      src
+  exposed-modules:
+      Test.Hspec.Expectations
+    , Test.Hspec.Expectations.Contrib
+
+test-suite spec
+  main-is:
+      Spec.hs
+  type:
+      exitcode-stdio-1.0
+  ghc-options:
+      -Wall -Werror
+  hs-source-dirs:
+      test
+  build-depends:
+      base        >= 4.0  && < 4.6
+    , hspec-expectations
+    , HUnit
+    , silently
+    , hspec
+    , hspec-discover
+
+test-suite readme-attoparsec
+  type:
+      exitcode-stdio-1.0
+  ghc-options:
+      -Wall -Werror -pgmL pandoc-unlit
+  main-is:
+      README.lhs
+  build-depends:
+      base
+    , hspec-expectations
+    , hspec
diff --git a/src/Test/Hspec/Expectations.hs b/src/Test/Hspec/Expectations.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/Hspec/Expectations.hs
@@ -0,0 +1,102 @@
+-- |
+-- Introductory documentation: <https://github.com/sol/test-shouldbe#readme>
+module Test.Hspec.Expectations (
+
+-- * Setting expectations
+  Expectation
+, shouldBe
+, shouldSatisfy
+, shouldReturn
+
+-- * Expecting exceptions
+, shouldThrow
+
+-- ** Selecting exceptions
+, Selector
+
+-- ** Predefined type-based selectors
+-- |
+-- There are predefined selectors for some standard exceptions.  Each selector
+-- is just @const True@ with an appropriate type.
+, anyException
+, anyErrorCall
+, anyIOException
+, anyArithException
+
+-- ** Combinators for defining value-based selectors
+-- |
+-- Some exceptions (most prominently `ErrorCall`) have no `Eq` instance.
+-- Selecting a specific value would require pattern matching.
+--
+-- For such exceptions, combinators that construct selectors are provided.
+-- Each combinator corresponds to a constructor; it takes the same arguments,
+-- and has the same name (but starting with a lower-case letter).
+, errorCall
+) where
+
+import           Prelude hiding (catch)
+import           Test.HUnit
+import           Control.Exception
+import           Data.Typeable
+
+type Expectation = Assertion
+
+infix 1 `shouldBe`, `shouldSatisfy`, `shouldReturn`, `shouldThrow`
+
+-- |
+-- @actual \`shouldBe\` expected@ sets the expectation that @actual@ is equal
+-- to @expected@ (this is just an alias for `@?=`).
+shouldBe :: (Show a, Eq a) => a -> a -> Expectation
+actual `shouldBe` expected = actual @?= expected
+
+-- |
+-- @v \`shouldSatisfy\` p@ sets the expectation that @p v@ is @True@.
+shouldSatisfy :: (Show a) => a -> (a -> Bool) -> Expectation
+v `shouldSatisfy` p = assertBool (show v ++ " did not satisfy predicate!") (p v)
+
+-- |
+-- @action \`shouldReturn\` expected@ sets the expectation that @action@
+-- returns @expected@.
+shouldReturn :: (Show a, Eq a) => IO a -> a -> Expectation
+action `shouldReturn` expected = action >>= (`shouldBe` expected)
+
+-- |
+-- A @Selector@ is a predicate; it can simultaneously constrain the type and
+-- value of an exception.
+type Selector a = (a -> Bool)
+
+-- |
+-- @action \`shouldThrow\` selector@ sets the expectation that @action@ throws
+-- an exception.  The precise nature of the expected exception is described
+-- with a 'Selector'.
+shouldThrow :: Exception e => IO a -> Selector e -> Expectation
+action `shouldThrow` p = do
+  r <- try action
+  case r of
+    Right _ ->
+      assertFailure $
+        "did not get expected exception: " ++ exceptionType
+    Left e ->
+      (`assertBool` p e) $
+        "predicate failed on expected exception: " ++ exceptionType ++ " (" ++ show e ++ ")"
+  where
+    -- a string repsentation of the expected exception's type
+    exceptionType = (show . typeOf . instanceOf) p
+      where
+        instanceOf :: Selector a -> a
+        instanceOf _ = error "Test.HUnit.ShouldBe.shouldThrow: brocken Typeable instance"
+
+anyException :: Selector SomeException
+anyException = const True
+
+anyErrorCall :: Selector ErrorCall
+anyErrorCall = const True
+
+errorCall :: String -> Selector ErrorCall
+errorCall s (ErrorCall msg) = s == msg
+
+anyIOException :: Selector IOException
+anyIOException = const True
+
+anyArithException :: Selector ArithException
+anyArithException = const True
diff --git a/src/Test/Hspec/Expectations/Contrib.hs b/src/Test/Hspec/Expectations/Contrib.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/Hspec/Expectations/Contrib.hs
@@ -0,0 +1,22 @@
+-- |
+-- Experimental combinators, that may become part of the main distribution, if
+-- they turn out to be useful for a wider audience.
+module Test.Hspec.Expectations.Contrib (
+
+  module Test.Hspec.Expectations
+
+-- * Predicates
+-- | (useful in combination with `shouldSatisfy`)
+, isLeft
+, isRight
+) where
+
+import Test.Hspec.Expectations
+
+isLeft :: Either a b -> Bool
+isLeft (Left  _) = True
+isLeft (Right _) = False
+
+isRight :: Either a b -> Bool
+isRight (Left  _) = False
+isRight (Right _) = True
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
