content: -- A little testing framework
  module Test where
  
  import Data.List (intercalate)
  import System.Exit (exitFailure)
  import Test.QuickCheck hiding (Success, Failure, expectFailure)
  
  data Expect = ExpectSuccess | ExpectFailure deriving Eq
  
  data Test = Test String Expect Property
  
  data Tests = Leaf Test | Node String [Tests]
  
  testGroup :: String -> [Tests] -> Tests
  testGroup = Node
  
  expectSuccess :: Testable a => String -> a -> Tests
  expectSuccess name p = Leaf $ Test name ExpectSuccess (property p)
  
  expectFailure :: Testable a => String -> a -> Tests
  expectFailure name p = Leaf $ Test name ExpectFailure (property p)
  
  runTest :: [String] -> Test -> IO ()
  runTest labels (Test name expect property) = do
      let label = "[" ++ intercalate "." (reverse labels) ++ "] " ++ name
      result <- quickCheckWithResult (stdArgs { chatty = False }) property
      case (expect, isSuccess result) of
          (ExpectSuccess, True) ->
              putStrLn $ "[OK] " ++ label
          (ExpectFailure, False) ->
              putStrLn $ "[OK, expected failure] " ++ label
          (ExpectFailure, True) ->
              putStrLn $ "[Warning, unexpected success] " ++ label
          (ExpectSuccess, False) -> do
              putStrLn $ "\n[Failure] " ++ label ++ "\n"
              putStrLn $ output result
              exitFailure
  
  runTests :: Tests -> IO ()
  runTests = go []
    where
      go labels (Leaf test)        = runTest labels test
      go labels (Node label tests) = mapM_ (go (label : labels)) tests
  