packages feed

HTF 0.12.1.0 → 0.12.2.0

raw patch · 15 files changed

+581/−234 lines, 15 filesdep +aeson-prettydep +haskell-lexerdep +haskell-srcdep −haskell-src-extsdep ~HUnitdep ~basedep ~randomPVP ok

version bump matches the API change (PVP)

Dependencies added: aeson-pretty, haskell-lexer, haskell-src

Dependencies removed: haskell-src-exts

Dependency ranges changed: HUnit, base, random

API changes (from Hackage documentation)

+ Test.Framework.Preprocessor: instance Eq Definition
+ Test.Framework.Preprocessor: instance Eq ImportDecl
+ Test.Framework.Preprocessor: instance Eq Loc
+ Test.Framework.Preprocessor: instance Eq ModuleInfo
+ Test.Framework.Preprocessor: instance Show Definition
+ Test.Framework.Preprocessor: instance Show ImportDecl
+ Test.Framework.Preprocessor: instance Show Loc
+ Test.Framework.Preprocessor: instance Show ModuleInfo
+ Test.Framework.Preprocessor: preprocessorTests :: [(String, IO ())]
+ Test.Framework.Preprocessor: progName :: String
+ Test.Framework.Preprocessor: transform :: Bool -> Bool -> FilePath -> String -> IO String
+ Test.Framework.PrettyHaskell: instance Show MySuperHero
+ Test.Framework.PrettyHaskell: instance Show MySuperSuperHero
+ Test.Framework.PrettyHaskell: prettyHaskell :: Show a => a -> String
+ Test.Framework.PrettyHaskell: prettyHaskell' :: Show a => a -> Maybe String
+ Test.Framework.PrettyHaskell: prettyHaskellTests :: [([Char], IO ())]
+ Test.Framework.QuickCheckWrapper: setReplayFromString :: Args -> String -> Args

Files

ChangeLog view
@@ -1,3 +1,7 @@+* 0.12.2.0 (2014-10-18)+  - drop dependency on haskell-src-exts (took too long to compile)+  - only color error counts if they are > 0 (thanks to Matthias Fischmann)+ * 0.12.1.0 (2014-09-16)   - support for haskell-src-exts version 1.16   - Functor and Applicative instances for AssertBool
HTF.cabal view
@@ -1,8 +1,8 @@ Name:             HTF-Version:          0.12.1.0+Version:          0.12.2.0 License:          LGPL License-File:     LICENSE-Copyright:        (c) 2005-2012 Stefan Wehr+Copyright:        (c) 2005-2014 Stefan Wehr Author:           Stefan Wehr <wehr@factisresearch.com> Maintainer:       Stefan Wehr <wehr@factisresearch.com> Stability:        Beta@@ -81,8 +81,8 @@       the imported tests. See "Test.Framework.Tutorial" for details.  Tested-With:-                  GHC==7.4.2,-                  GHC==7.6.2+                  GHC==7.6.2,+                  GHC==7.8.2 Build-Type:       Simple Cabal-Version:    >= 1.10 Extra-Source-Files:@@ -133,13 +133,15 @@  Executable htfpp   Main-Is:          HTFPP.hs-  Build-Depends:    cpphs >= 1.12,-                    haskell-src-exts >= 1.14,-                    old-time >= 1.0,-                    directory >= 1.0,+  Build-Depends:    HUnit,                     array,-                    random >= 1.0,                     base == 4.*,+                    cpphs >= 1.12,+                    directory >= 1.0,+                    haskell-lexer,+                    mtl >= 1.1,+                    old-time >= 1.0,+                    random >= 1.0,                     text   Other-Modules:     Test.Framework.Preprocessor@@ -147,30 +149,31 @@   Default-language:  Haskell2010  Library-  Build-Depends:+  Build-Depends:    Diff >= 0.3,                     HUnit >= 1.2.5,                     QuickCheck >= 2.3,+                    aeson >= 0.6,+                    array,                     base == 4.*,-                    random >= 1.0,-                    containers >= 0.4.2.1,-                    process >= 1.0,+                    base64-bytestring,+                    bytestring >= 0.9,+                    containers >= 0.5,+                    cpphs >= 1.12,                     directory >= 1.0,-                    mtl >= 1.1,-                    monad-control >= 0.3,+                    haskell-lexer,+                    haskell-src,                     lifted-base >= 0.1,+                    monad-control >= 0.3,+                    mtl >= 1.1,+                    old-time >= 1.0,                     pretty >= 1.0,-                    Diff >= 0.3,-                    bytestring >= 0.9,+                    process >= 1.0,+                    random >= 1.0,                     regex-compat >= 0.92,-                    haskell-src-exts >= 1.11,-                    aeson >= 0.6,                     text >= 0.11,-                    old-time >= 1.0,-                    array,-                    xmlgen >= 0.6,-                    base64-bytestring,+                    time,                     vector,-                    time+                    xmlgen >= 0.6   if !os(windows)     Build-Depends:   unix >= 2.4   Exposed-Modules:@@ -192,6 +195,8 @@     Test.Framework.ThreadPool     Test.Framework.AssertM     Test.Framework.Colors+    Test.Framework.PrettyHaskell+    Test.Framework.Preprocessor   Other-Modules:     Test.Framework.Utils     Test.Framework.Diff@@ -199,23 +204,36 @@   Default-language:  Haskell2010   Ghc-Options: -W -fwarn-unused-imports -fwarn-unused-binds -fwarn-unused-matches -fwarn-unused-do-bind -fwarn-wrong-do-bind +Test-Suite MiscTests+  Main-is:           MiscTest.hs+  Type:              exitcode-stdio-1.0+  Hs-Source-Dirs:    tests+  Build-depends:     HTF,+                     HUnit,+                     base == 4.*,+                     mtl,+                     random+  Default-language:  Haskell2010+ Test-Suite TestHTF   Main-is:           TestHTF.hs   Hs-Source-Dirs:    tests, tests/real-bbt   Type:              exitcode-stdio-1.0-  Build-depends:     base == 4.*,-                     bytestring >= 0.9,+  Build-depends:     HTF,                      aeson >= 0.6,-                     unordered-containers >= 0.2,-                     temporary >= 1.1,-                     text >= 0.11,-                     process >= 1.0,-                     filepath >= 1.1,+                     aeson-pretty,+                     base == 4.*,+                     bytestring >= 0.9,                      directory >= 1.0,-                     regex-compat >= 0.92,+                     filepath >= 1.1,+                     process >= 1.0,                      random,-                     HTF+                     regex-compat >= 0.92,+                     temporary >= 1.1,+                     text >= 0.11,+                     unordered-containers >= 0.2   Default-language:  Haskell2010+  Ghc-Options: -keep-tmp-files -tmpdir ./tmp   Other-Modules:     Foo.A, Foo.B, TestHTFHunitBackwardsCompatible @@ -223,19 +241,8 @@   Main-is:           ThreadPoolTest.hs   Type:              exitcode-stdio-1.0   Hs-Source-Dirs:    tests-  Build-depends:     base == 4.*,-                     random,-                     mtl,-                     HTF-  Default-language:  Haskell2010--Test-Suite MiscTests-  Main-is:           MiscTest.hs-  Type:              exitcode-stdio-1.0-  Hs-Source-Dirs:    tests-  Build-depends:     base == 4.*,-                     random,+  Build-depends:     HTF,+                     base == 4.*,                      mtl,-                     HTF,-                     HUnit+                     random   Default-language:  Haskell2010
HTFPP.hs view
@@ -35,7 +35,7 @@ usage =     hPutStrLn stderr       ("Preprocessor for the Haskell Test Framework\n\n" ++-       "Usage: " ++ progName ++ " [--hunit] [FILE1 [FILE2 [FILE3]]]\n\n" +++       "Usage: " ++ progName ++ " [--hunit|--debug] [FILE1 [FILE2 [FILE3]]]\n\n" ++        "* If no argument is given, input is read from stdin and\n" ++        "  output is written to stdout.\n" ++        "* If only FILE1 is given, input is read from this file\n" ++@@ -52,6 +52,7 @@ outputVersion :: IO () outputVersion =     hPutStrLn stderr (showVersion Paths_HTF.version)+ saveOpenFile :: FilePath -> IOMode -> IO Handle saveOpenFile path mode =     openFile path mode `catch` exHandler@@ -72,10 +73,9 @@        when ("--version" `elem` args) $             do outputVersion                exitWith ExitSuccess-       let (restArgs, hunitBackwardsCompat) =-               case reverse args of-                 "--hunit":rrest -> (reverse rrest, True)-                 rrest -> (reverse rrest, False)+       let hunitBackwardsCompat = "--hunit" `elem` args+           debug = "--debug" `elem` args+           restArgs = flip filter args $ \x -> x /= "--hunit" && x /= "--debug"        (origInputFilename, hIn, hOut) <-            case restArgs of              [] ->@@ -92,10 +92,11 @@                     h2 <- saveOpenFile file3 WriteMode                     return (file1, h1, h2)              _ ->-                 do usage+                 do hPutStrLn stderr ("Too many arguments: " ++ show restArgs)+                    usage                     exitWith (ExitFailure 1)        input <- hGetContents hIn-       output <- transform hunitBackwardsCompat origInputFilename input `catch`+       output <- transform hunitBackwardsCompat debug origInputFilename input `catch`                    (\ (e::SomeException) ->                         do hPutStrLn stderr (progName ++                                              ": unexpected exception: " ++
Test/Framework/CmdlineOptions.hs view
@@ -198,7 +198,7 @@  {- | -Parse commandline arguments into 'CmdlineOptions'. Here's a synopsis+Parse commandline arguments into 'CmdlineOptions'. Here is a synopsis of the format of the commandline arguments:  > USAGE: COMMAND [OPTION ...] PATTERN ...
Test/Framework/HUnitWrapper.hs view
@@ -114,8 +114,6 @@ import qualified Control.Exception.Lifted as ExL import Control.Monad.Trans.Control import Control.Monad.Trans-import qualified Language.Haskell.Exts.Pretty as HE-import qualified Language.Haskell.Exts.Parser as HE import qualified Test.HUnit.Lang as HU  import Data.List ( (\\) )@@ -127,6 +125,7 @@ import Test.Framework.Colors import Test.Framework.Pretty import Test.Framework.AssertM+import Test.Framework.PrettyHaskell  -- WARNING: do not forget to add a preprocessor macro for new assertions!! @@ -259,7 +258,7 @@                       Nothing -> ""           in noColor' (f True) (f False)       (expP, actP, stringEq) =-          case (pp exp, pp act) of+          case (prettyHaskell' exp, prettyHaskell' act) of             (Nothing, _) -> (exp, act, exp == act)             (_, Nothing) -> (exp, act, exp == act)             (Just expP, Just actP)@@ -268,19 +267,10 @@                        then (exp, act, exp == act)                        else (expP, actP, True)                 | otherwise -> (expP, actP, False)-      pp s =-          case HE.parseExp s of-            HE.ParseOk x -> Just $ HE.prettyPrint x-            HE.ParseFailed{} -> Nothing  notEqualityFailedMessage :: String -> String notEqualityFailedMessage exp =-    (": Objects are equal\n" ++ pp exp)-    where-      pp s =-          case HE.parseExp s of-            HE.ParseOk x -> HE.prettyPrint x-            HE.ParseFailed{} -> s+    (": Objects are equal\n" ++ prettyHaskell exp)  _assertEqual_ :: (Eq a, Show a, AssertM m)                  => String -> Location -> String -> a -> a -> m ()
Test/Framework/Preprocessor.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE PackageImports #-}  -- -- Copyright (c) 2009-2014 Stefan Wehr - http://www.stefanwehr.de@@ -19,20 +21,24 @@ -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA -- -module Test.Framework.Preprocessor ( transform, progName ) where+module Test.Framework.Preprocessor ( +    transform, progName, preprocessorTests++) where+ import Control.Monad-import qualified Data.Text as T-import Data.Char ( toLower, isSpace, isDigit )-import Data.Maybe ( mapMaybe )-import qualified Data.List as List-import System.IO ( hPutStrLn, stderr )+import Data.Char ( isDigit, isSpace )+import "haskell-lexer" Language.Haskell.Lexer import Language.Preprocessor.Cpphs ( runCpphs,                                      CpphsOptions(..),                                      BoolOptions(..),                                      defaultCpphsOptions)+import System.IO ( hPutStrLn, stderr )+import Test.HUnit hiding (State)+import Control.Monad.State.Strict+import qualified Data.List as List -import Test.Framework.HaskellParser import Test.Framework.Location  _DEBUG_ :: Bool@@ -112,172 +118,336 @@       expansion a suffix = "(" ++ prefix ++ a ++ suffix ++ " (" ++                            prefix ++ "makeLoc __FILE__ __LINE__))" -warn :: String -> IO ()-warn s =-    hPutStrLn stderr $ progName ++ " warning: " ++ s--note :: String -> IO ()-note s =-    when _DEBUG_ $ hPutStrLn stderr $ progName ++ " note: " ++ s- data ModuleInfo = ModuleInfo { mi_htfPrefix  :: String                              , mi_htfImports :: [ImportDecl]                              , mi_defs       :: [Definition]                              , mi_moduleName :: String }-                  deriving (Show)+                  deriving (Show, Eq) +data ImportDecl = ImportDecl { imp_moduleName :: Name+                             , imp_qualified :: Bool+                             , imp_alias :: Maybe Name+                             , imp_loc :: Location }+                  deriving (Show, Eq)+ data Definition = TestDef String Location String                 | PropDef String Location String                   deriving (Eq, Show) -data ImportOrPragma = IsImport ImportDecl | IsPragma Pragma-                  deriving (Show)+type Name = String -analyse :: FilePath -> String-        -> IO (ParseResult ModuleInfo)-analyse originalFileName inputString =-    do parseResult <- parse originalFileName inputString-       case parseResult of-         ParseOK (Module moduleName imports decls pragmas) ->-             do -- putStrLn $ show decls-                let defs = mapMaybe defFromDecl decls-                    htfImports = findHtfImports imports pragmas-                htfPrefix <--                  case mapMaybe prefixFromImport imports of-                    (s:_) -> return s-                    [] -> do warn ("No import found for " ++ htfModule ++-                                   " in " ++ originalFileName)-                             return (htfModule ++ ".")-                return $ ParseOK (ModuleInfo htfPrefix htfImports defs moduleName)-         ParseError loc err -> return (ParseError loc err)-    where-      prefixFromImport :: ImportDecl -> Maybe String-      prefixFromImport (ImportDecl s qualified alias _)-          | s == htfModule =-              if qualified-                  then case alias of-                         Just s' -> Just $ s' ++ "."-                         Nothing -> Just $ s ++ "."-                  else Just ""-      prefixFromImport _ = Nothing-      defFromDecl :: Decl -> Maybe Definition-      defFromDecl (Decl loc name) = defFromNameAndLoc name loc-      defFromNameAndLoc :: Name -> Location -> Maybe Definition-      defFromNameAndLoc name loc =-          case name of-            ('t':'e':'s':'t':'_':rest) | not (null rest) ->-                Just (TestDef rest loc name)-            ('p':'r':'o':'p':'_':rest) | not (null rest) ->-                Just (PropDef rest loc name)-            _ -> Nothing-      findHtfImports allImports allPragmas =-          let importPragmas = filter (\p -> pr_name p == "HTF_TESTS") allPragmas-              importsAndPragmas = List.sortBy cmpByLine (map IsImport allImports ++-                                                         map IsPragma importPragmas)-              loop (IsImport imp : IsPragma prag : rest) =-                  if lineNumber (imp_loc imp) == lineNumber (pr_loc prag)-                     then imp : loop rest-                     else loop rest-              loop (_ : rest) = loop rest-              loop [] = []-          in loop importsAndPragmas-      cmpByLine x y = getLine x `compare` getLine y-      getLine (IsImport imp) = (lineNumber (imp_loc imp))-      getLine (IsPragma prag) = (lineNumber (pr_loc prag))+type PMA a = State ModuleInfo a -breakOn :: T.Text -> T.Text -> Maybe (T.Text, T.Text)-breakOn t1 t2 =-    let (pref, suf) = T.breakOn t1 t2-    in if pref == t2-       then Nothing-       else Just (pref, T.drop (T.length t1) suf)+setModName :: String -> PMA ()+setModName name =+    modify $ \mi -> mi { mi_moduleName = name } -poorMensAnalyse :: FilePath -> String -> IO ModuleInfo-poorMensAnalyse originalFileName inputString =-    let (modName, defs, impDecls) = doAna (zip [1..] (lines inputString)) ("", [], [])-    in return $ ModuleInfo "Test.Framework." impDecls defs modName+addTestDef :: String -> String -> Location -> PMA ()+addTestDef name fullName loc =+    modify $ \mi -> mi { mi_defs = (TestDef name loc fullName) : mi_defs mi }++addPropDef :: String -> String -> Location -> PMA ()+addPropDef name fullName loc =+    modify $ \mi -> mi { mi_defs = (PropDef name loc fullName) : mi_defs mi }++addHtfImport :: ImportDecl -> PMA ()+addHtfImport decl =+    modify $ \mi -> mi { mi_htfImports = decl : mi_htfImports mi }++setTestFrameworkImport :: String -> PMA ()+setTestFrameworkImport name =+    modify $ \mi -> mi { mi_htfPrefix = name }++poorManAnalyzeTokens :: [LocToken] -> ModuleInfo+poorManAnalyzeTokens toks =+    -- show toks `trace`+    let revRes =+            execState (loop toks) $+                      ModuleInfo { mi_htfPrefix = htfModule ++ "."+                                 , mi_htfImports = []+                                 , mi_defs = []+                                 , mi_moduleName = "Main" }+    in ModuleInfo { mi_htfPrefix = mi_htfPrefix revRes+                  , mi_htfImports = reverse (mi_htfImports revRes)+                  , mi_defs = reverse $ List.nubBy defEqByName (mi_defs revRes)+                  , mi_moduleName = mi_moduleName revRes+                  }     where       defEqByName (TestDef n1 _ _) (TestDef n2 _ _) = n1 == n2       defEqByName (PropDef n1 _ _) (PropDef n2 _ _) = n1 == n2       defEqByName _ _ = False-      doAna [] (modName, revDefs, impDecls) = (modName, reverse (List.nubBy defEqByName revDefs), reverse impDecls)-      doAna ((lineNo, line) : restLines) (modName, defs, impDecls) =-          case line of-            'm':'o':'d':'u':'l':'e':rest ->-                if null modName-                then doAna restLines (takeWhile (not . isSpace) (dropWhile isSpace rest),-                                      defs, impDecls)-                else doAna restLines (modName, defs, impDecls)-            't':'e':'s':'t':'_':rest ->-                let testName = takeWhile (not . isSpace) rest-                    def = TestDef testName loc ("test_" ++ testName)-                in doAna restLines (modName, def : defs, impDecls)-            'p':'r':'o':'p':'_':rest ->-                let testName = takeWhile (not . isSpace) rest-                    def = PropDef testName loc ("prop_" ++ testName)-                in doAna restLines (modName, def : defs, impDecls)-            'i':'m':'p':'o':'r':'t':rest ->-                case breakOn importPragma (T.pack rest) of-                  Just (pref, suf) ->-                      case poorMensParseImportLine loc (pref `T.append` suf) of-                        Just impDecl -> doAna restLines (modName, defs, impDecl : impDecls)-                        Nothing -> doAna restLines (modName, defs, impDecls)-                  Nothing -> doAna restLines (modName, defs, impDecls)-            _ -> doAna restLines (modName, defs, impDecls)-          where-            loc = makeLoc originalFileName lineNo-            importPragma = T.pack "{-@ HTF_TESTS @-}"+      loop toks =+        case toks of+          (Reservedid, (_, "module")) : rest ->+              case rest of+                (Conid, (_, name)):rest2 ->+                    do setModName name+                       loop rest2+                (Qconid, (_, name)):rest2 ->+                    do setModName name+                       loop rest2+                _ -> loop rest+          (Varid, (loc, name)) : rest+              | isStartOfLine loc ->+                  case name of+                    't':'e':'s':'t':'_':shortName ->+                        do addTestDef shortName name (locToLocation loc)+                           loop rest+                    'p':'r':'o':'p':'_':shortName ->+                        do addPropDef shortName name (locToLocation loc)+                           loop rest+                    _ -> loop rest+              | otherwise -> loop rest+          (Special, (loc, "import_HTF_TESTS")) : rest ->+              case parseImport loc rest of+                Just (imp, rest2) ->+                    do addHtfImport imp+                       loop rest2+                Nothing -> loop rest+          (Reservedid, (loc, "import")) : rest ->+              do case parseImport loc rest of+                   Nothing -> loop rest+                   Just (imp, rest2) ->+                       do when (imp_moduleName imp == htfModule) $+                            let prefix = case (imp_alias imp, imp_qualified imp) of+                                           (Just alias, True) -> alias+                                           (Nothing, True) -> imp_moduleName imp+                                           _ -> ""+                            in setTestFrameworkImport+                                   (if null prefix then prefix else prefix ++ ".")+                          loop rest2+          _ : rest -> loop rest+          [] -> return ()+      parseImport loc toks =+          do let (qualified, toks2) =+                  case toks of+                    (Varid, (_, "qualified")):rest -> (True, rest)+                    _ -> (False, toks)+             (name, toks3) <-+                  case toks2 of+                    (Conid, (_, name)):rest -> return (name, rest)+                    (Qconid, (_, name)):rest -> return (name, rest)+                    _ -> fail "no import"+             let (mAlias, toks4) =+                   case toks3 of+                     (Varid, (_, "as")):(Conid, (_, alias)):rest -> (Just alias, rest)+                     _ -> (Nothing, toks3)+                 decl = ImportDecl { imp_moduleName = name+                                   , imp_qualified = qualified+                                   , imp_alias = mAlias+                                   , imp_loc = locToLocation loc }+             return (decl, toks4)+      locToLocation loc =+          makeLoc (l_file loc) (l_line loc)+      isStartOfLine loc =+          l_column loc == 1 -poorMensParseImportLine :: Location -> T.Text -> Maybe ImportDecl-poorMensParseImportLine loc t =-    let (q, rest) =-            case breakOn "qualified" t of-              Nothing -> (False, T.strip t)-              Just (_, rest) -> (True, T.strip rest)-        modName = T.takeWhile (not . isSpace) rest-        afterModName = T.strip $ T.drop (T.length modName) rest-    in case breakOn "as" afterModName of-         Nothing -> Just $ ImportDecl (T.unpack modName) q Nothing loc-         Just (_, suf) ->-             let strippedSuf = T.strip suf-                 alias = if T.null strippedSuf then Nothing else Just (T.unpack strippedSuf)-             in Just $ ImportDecl (T.unpack modName) q alias loc+cleanupTokens :: [PosToken] -> [PosToken]+cleanupTokens toks =+    -- Remove whitespace tokens, remove comments, but replace+    -- 'import {-@ HTF_TESTS @-}' with a single+    -- token Special with value "import_HTF_TESTS"+    case toks of+      (Whitespace, _):rest -> cleanupTokens rest+      (NestedComment, (loc, "{-@ HTF_TESTS @-}")) : rest ->+          (Special, (loc, "import_HTF_TESTS")) :+          cleanupTokens rest+      tok:rest -> tok : cleanupTokens rest+      [] -> [] -transform :: Bool -> FilePath -> String -> IO String-transform hunitBackwardsCompat originalFileName input =-    do analyseResult <- analyse originalFileName input-       case analyseResult of-         ParseError loc err ->-             do poorInfo <- poorMensAnalyse originalFileName input-                note ("Parsing of " ++ originalFileName ++ " failed at line "-                      ++ show (lineNumber loc) ++ ": " ++ err ++-                      "\nFalling back to poor man's parser. This parser may " ++-                      "return incomplete results. The result returned was: " ++-                      "\nPrefix: " ++ mi_htfPrefix poorInfo ++-                      "\nModule name: " ++ mi_moduleName poorInfo ++-                      "\nDefinitions: " ++ show (mi_defs poorInfo) ++-                      "\nHTF imports: " ++ show (mi_htfImports poorInfo))-                preprocess poorInfo input-         ParseOK info ->-             preprocess info input+cleanupInputString :: String -> String+cleanupInputString s =+    case s of+      '\'':'\\':rest ->         -- escaped character literal+        case span (/= '\'') rest of+          (esc,'\'':rest) ->+              "'\\" ++ esc ++ "'" ++ cleanupInputString rest+          _ -> s                -- should not happen+      '\'':c:'\'':rest ->   -- regular character literal+        '\'':c:'\'':cleanupInputString rest+      c:'\'':'\'':rest+          | isSpace c ->         -- TH type quote+              cleanupInputString rest+      c:'\'':rest                -- TH name quote+          | isSpace c ->+              cleanupInputString rest+      c:rest -> c : cleanupInputString rest+      [] -> []++type LocToken =  (Token,(Loc,String))++data Loc+    = Loc+      { l_file :: FilePath+      , l_line :: Int+      , l_column :: Int+      }+    deriving (Eq, Show)++-- token stream should not contain whitespace+fixPositions :: FilePath -> [PosToken] -> [LocToken]+fixPositions originalFileName = loop Nothing     where-      preprocess :: ModuleInfo -> String -> IO String-      preprocess info input =-          do preProcessedInput <- runCpphs (cpphsOptions info) originalFileName+      loop mPragma toks =+          case toks of+            [] -> []+            (Varsym, (pos, "#")) : (Varid, (_, "line")) : (IntLit, (_, lineNo)) : (StringLit,(_, fileName)) : rest+                | column pos == 1 ->+                    map (\(tt, (pos, x)) -> (tt, (fixPos Nothing pos, x))) (take 4 toks) +++                    loop (Just (line pos, fileName, read lineNo)) rest+            (tt, (pos, x)) : rest ->+                (tt, (fixPos mPragma pos, x)) : loop mPragma rest+      fixPos mPragma pos =+          case mPragma of+            Nothing ->+                Loc { l_column = column pos+                    , l_file = originalFileName+                    , l_line = line pos+                    }+            Just (lineActivated, fileName, lineNo) ->+                let offset = line pos - lineActivated - 1+                in Loc { l_column = column pos+                       , l_file = fileName+                       , l_line = lineNo + offset+                       }++fixPositionsTest :: IO ()+fixPositionsTest =+    let toks = concatMap (\(f, i) -> f i)+                   (zip [tok, linePragma "bar" 10, tok, tok, linePragma "foo" 99, tok] [1..])+        fixedToks = fixPositions origFileName toks+        expectedToks = concat $+                       [tok' origFileName 1+                       ,linePragma' "bar" 10 2+                       ,tok' "bar" 10+                       ,tok' "bar" 11+                       ,linePragma' "foo" 99 5+                       ,tok' "foo" 99]+    in assertEqual (show expectedToks ++ "\n\n  /=  \n\n" ++ show toks) expectedToks fixedToks+    where+      origFileName = "spam"+      tok line = [(Varid, (Pos 0 line 1, "_"))]+      linePragma fname line lineHere =+          let pos = Pos 0 lineHere 1+          in [(Varsym, (pos, "#"))+             ,(Varid, (pos, "line"))+             ,(IntLit, (pos, show line))+             ,(StringLit, (pos, fname))]+      tok' fname line =+          let loc = Loc fname line 1+          in [(Varid, (loc, "_"))]+      linePragma' fname line lineHere =+          let loc = Loc origFileName lineHere 1+          in [(Varsym, (loc, "#"))+             ,(Varid, (loc, "line"))+             ,(IntLit, (loc, show line))+             ,(StringLit,(loc, fname))]++analyze :: FilePath -> String -> ModuleInfo+analyze originalFileName input =+    poorManAnalyzeTokens (fixPositions originalFileName (cleanupTokens (lexerPass0 (cleanupInputString input))))++analyzeTests =+    [(unlines ["module FOO where"+              ,"import Test.Framework"+              ,"import {-@ HTF_TESTS @-} qualified Foo as Bar"+              ,"import {-@ HTF_TESTS @-} qualified Foo.X as Egg"+              ,"import {-@ HTF_TESTS @-} Foo.Y as Spam"+              ,"import {-@ HTF_TESTS @-} Foo.Z"+              ,"import {-@ HTF_TESTS @-} Baz"+              ,"deriveSafeCopy 1 'base ''T"+              ,"$(deriveSafeCopy 2 'extension ''T)"+              ,"test_blub test_foo = 1"+              ,"test_blah test_foo = 1"+              ,"prop_abc prop_foo = 2"+              ,"prop_xyz = True"]+     ,ModuleInfo { mi_htfPrefix = ""+                 , mi_htfImports =+                     [ImportDecl { imp_moduleName = "Foo"+                                 , imp_qualified = True+                                 , imp_alias = Just "Bar"+                                 , imp_loc = makeLoc "<input>" 3}+                     ,ImportDecl { imp_moduleName = "Foo.X"+                                 , imp_qualified = True+                                 , imp_alias = Just "Egg"+                                 , imp_loc = makeLoc "<input>" 4}+                     ,ImportDecl { imp_moduleName = "Foo.Y"+                                 , imp_qualified = False+                                 , imp_alias = Just "Spam"+                                 , imp_loc = makeLoc "<input>" 5}+                     ,ImportDecl { imp_moduleName = "Foo.Z"+                                 , imp_qualified = False+                                 , imp_alias = Nothing+                                 , imp_loc = makeLoc "<input>" 6}+                     ,ImportDecl { imp_moduleName = "Baz"+                                 , imp_qualified = False+                                 , imp_alias = Nothing+                                 , imp_loc = makeLoc "<input>" 7}]+                 , mi_moduleName = "FOO"+                 , mi_defs = [TestDef "blub" (makeLoc "<input>" 10) "test_blub"+                             ,TestDef "blah" (makeLoc "<input>" 11) "test_blah"+                             ,PropDef "abc" (makeLoc "<input>" 12) "prop_abc"+                             ,PropDef "xyz" (makeLoc "<input>" 13) "prop_xyz"]+                 })+    ,(unlines ["module Foo.Bar where"+              ,"import Test.Framework as Blub"+              ,"prop_xyz = True"]+     ,ModuleInfo { mi_htfPrefix = ""+                 , mi_htfImports = []+                 , mi_moduleName = "Foo.Bar"+                 , mi_defs = [PropDef "xyz" (makeLoc "<input>" 3) "prop_xyz"]+                 })+    ,(unlines ["module Foo.Bar where"+              ,"import qualified Test.Framework as Blub"+              ,"prop_xyz = True"]+     ,ModuleInfo { mi_htfPrefix = "Blub."+                 , mi_htfImports = []+                 , mi_moduleName = "Foo.Bar"+                 , mi_defs = [PropDef "xyz" (makeLoc "<input>" 3) "prop_xyz"]+                 })+    ,(unlines ["module Foo.Bar where"+              ,"import qualified Test.Framework"+              ,"prop_xyz = True"]+     ,ModuleInfo { mi_htfPrefix = "Test.Framework."+                 , mi_htfImports = []+                 , mi_moduleName = "Foo.Bar"+                 , mi_defs = [PropDef "xyz" (makeLoc "<input>" 3) "prop_xyz"]+                 })]++testAnalyze =+    do mapM_ runTest (zip [1..] analyzeTests)+    where+      runTest (i, (src, mi)) =+          let givenMi = analyze "<input>" src+          in if givenMi == mi+             then return ()+             else assertFailure ("Error in test " ++ show i +++                                 ", expected:\n" ++ show mi +++                                 "\nGiven:\n" ++ show givenMi +++                                 "\nSrc:\n" ++ src)++transform :: Bool -> Bool -> FilePath -> String -> IO String+transform hunitBackwardsCompat debug originalFileName input =+    let info = analyze originalFileName fixedInput+    in preprocess info+    where+      preprocess :: ModuleInfo -> IO String+      preprocess info =+          do when debug $ hPutStrLn stderr ("Module info:\n" ++ show info)+             preProcessedInput <- runCpphs (cpphsOptions info) originalFileName                                            fixedInput              return $ preProcessedInput ++ "\n\n" ++ additionalCode info ++ "\n"+      -- fixedInput serves two purposes:+      -- 1. add a trailing \n+      -- 2. turn lines of the form '# <number> "<filename>"' into line directives '#line <number> <filename>'+      -- (see http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html#Preprocessor-Output).+      fixedInput :: String+      fixedInput = (unlines . map fixLine . lines) input           where-              -- fixedInput serves two purposes:-              -- 1. add a trailing \n-              -- 2. turn lines of the form '# <number> "<filename>"' into line directives '#line <number> <filename>'-              -- (see http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html#Preprocessor-Output).-              fixedInput :: String-              fixedInput = (unlines . map fixLine . lines) input-                  where-                    fixLine s =-                        case parseCppLineInfoOut s of-                          Just (line, fileName) -> "#line " ++ line ++ " " ++ fileName-                          _ -> s+            fixLine s =+                case parseCppLineInfoOut s of+                  Just (line, fileName) -> "#line " ++ line ++ " " ++ fileName+                  _ -> s       cpphsOptions :: ModuleInfo -> CpphsOptions       cpphsOptions info =           defaultCpphsOptions { defines =@@ -328,3 +498,26 @@             (False, _) -> name             (True, Just alias) -> alias ++ "." ++ name             (True, _) -> imp_moduleName imp ++ "." ++ name++-- Returns for lines of the form '# <number> "<filename>"'+-- (see http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html#Preprocessor-Output)+-- the value 'Just <number> "<filename>"'+parseCppLineInfoOut :: String -> Maybe (String, String)+parseCppLineInfoOut line =+    case line of+      '#':' ':c:rest+        | isDigit c ->+            case List.span isDigit rest of+              (restDigits, ' ' : '"' : rest) ->+                  case dropWhile (/= '"') (reverse rest) of+                    '"' : fileNameRev ->+                        let line = (c:restDigits)+                            file = "\"" ++ reverse fileNameRev ++ "\""+                        in Just (line, file)+                    _ -> Nothing+              _ -> Nothing+      _ -> Nothing++preprocessorTests =+    [("testAnalyze", testAnalyze)+    ,("fixPositionsTest", fixPositionsTest)]
+ Test/Framework/PrettyHaskell.hs view
@@ -0,0 +1,83 @@+module Test.Framework.PrettyHaskell (++    prettyHaskell, prettyHaskell', prettyHaskellTests++) where++import qualified Data.List as List+import Language.Haskell.Parser+import Language.Haskell.Pretty+import Test.HUnit+import Test.Framework.Utils++prettyHaskell :: Show a => a -> String+prettyHaskell x =+    case prettyHaskell' x of+      Just s -> s+      Nothing -> "FALLBACK: " ++ show x++prettyHaskell' :: Show a => a -> Maybe String+prettyHaskell' x =+    fmap (postProcess (show x)) (prettyHaskell'' x )++prettyHaskell'' :: Show a => a -> Maybe String+prettyHaskell'' x =+    let str = show x+        code = "module M where TOP = " ++ str+    in case parseModule code of+         ParseOk x -> Just (prettyPrint x)+         ParseFailed _ _ -> Nothing++postProcess :: String -> String -> String+postProcess fallback s =+    case dropWhile (\l -> not ('=' `elem` l)) (lines s) of+      [] -> fallback+      (l:ls) ->+          case List.span (/= '=') l of+            (prefix, '=':' ':suffix) ->+                let indentLen = length prefix + 2+                in strip $ unlines (suffix : (map (drop indentLen) ls))+            _ -> fallback++prettyHaskellTests =+    [("testPrettyHaskell", testPrettyHaskell)]++data MySuperHero+    = MySuperHero+      { msh_age :: Int+      , msh_name :: String+      , msh_address :: String+      , msh_fun :: Int+      }+    deriving (Show)++data MySuperSuperHero+    = MySuperSuperHero+      { mssh_isHere :: Bool+      , mssh_hero :: MySuperHero+      }+    deriving (Show)++testPrettyHaskell =+    do assertPretty "Just 1" (Just 1)+       let hero =+               MySuperHero+               { msh_age = 35+               , msh_name = "FOO"+               , msh_address = "address"+               , msh_fun = 1+               }+       assertPretty+         ("MySuperHero{msh_age = 35, msh_name = \"FOO\",\n" +++          "            msh_address = \"address\", msh_fun = 1}")+         hero+       assertPretty+          ("MySuperSuperHero{mssh_isHere = True,\n" +++           "                 mssh_hero =\n" +++           "                   MySuperHero{msh_age = 35, msh_name = \"FOO\",\n" +++           "                               msh_address = \"address\", msh_fun = 1}}")+          (MySuperSuperHero { mssh_isHere = True, mssh_hero = hero })+    where+      assertPretty s x =+          assertEqual (s ++ " /=\n" ++ prettyHaskell x)+                      s (prettyHaskell x)
Test/Framework/QuickCheckWrapper.hs view
@@ -32,7 +32,7 @@    -- * Arguments for evaluating properties   defaultArgs, getCurrentArgs, setDefaultArgs,-  withQCArgs, WithQCArgs,+  withQCArgs, WithQCArgs, setReplayFromString,    -- * Pending properties   qcPending,@@ -58,10 +58,11 @@ import qualified Data.List as List import System.IO.Unsafe (unsafePerformIO) import Data.IORef+import System.Random  import Test.QuickCheck-import Test.QuickCheck.Property hiding (reason) import Test.Framework.TestInterface+import Test.Framework.Utils  _DEBUG_ :: Bool _DEBUG_ = False@@ -205,3 +206,22 @@ assertionAsProperty :: IO () -> Property assertionAsProperty action =     ioProperty $ action >> return True++-- | Sets the 'replay' parameter of the 'Args' datatype by parsing the given string.+setReplayFromString :: Args -> String -> Args+setReplayFromString args str =+#if !MIN_VERSION_QuickCheck(2,7,0)+    case readM str of+      Just x -> args { replay = x }+      Nothing -> error ("Could not parse replay parameter from string " ++ show str)+#else+    -- Starting with QC 2.7 the type of the replay field changed from+    -- 'Maybe (StdGen, Int)' to 'Maybe (QCGen, Int'+    case readM str of+      Just x -> args { replay = x }+      Nothing ->+          case readM str of+            Just (_ :: Maybe (StdGen, Int)) ->+                error ("Your replay parameter has been produced with QuickCheck <= 2.6. It cannot be used with QuickCheck >= 2.7")+            Nothing -> error ("Could not parse replay parameter from string " ++ show str)+#endif
Test/Framework/TestReporter.hs view
@@ -196,9 +196,9 @@            timedOut = length (rgra_timedOut arg)            filtered = length (rgra_filtered arg)            total = passed + failed + error + pending-       let pendings = colorize pendingColor "* Pending:"-           failures = colorize warningColor "* Failures:"-           errors = colorize warningColor "* Errors:"+       let pendings = (if pending > 0 then colorize pendingColor else noColor) "* Pending:"+           failures = (if failed > 0 then colorize warningColor else noColor) "* Failures:"+           errors = (if error > 0 then colorize warningColor else noColor) "* Errors:"        reportTR Info ("* Tests:     " +++ showC total +++ "\n" +++                       "* Passed:    " +++ showC passed +++ "\n" +++                       pendings +++ "   " +++ showC pending +++ "\n" +++
run-all-tests.sh view
@@ -1,7 +1,17 @@ #!/bin/bash +SANDBOX_FILE="cabal.sandbox.config"+SANDBOX_DIR=".cabal-sandbox"+ set -e-ghc-pkg unregister HTF || true+if [ -e "$SANDBOX_FILE"  ]+then+    have_sandbox=yes+    cabal sandbox hc-pkg unregister HTF || true+else+    have_sandbox=no+    ghc-pkg unregister HTF || true+fi  cabal configure --enable-tests || exit 1 cabal build || exit 1@@ -9,6 +19,13 @@ cabal install || exit 1  cd sample++if [ "$have_sandbox" == "yes" ]+then+    rm -f cabal.sandbox.config+    cabal sandbox init --sandbox ../"$SANDBOX_DIR"+fi+ cabal configure --enable-tests || exit 1 cabal build || exit 1 cabal test || exit 1
sample/sample-HTF.cabal view
@@ -13,12 +13,12 @@ executable sample   main-is:           Main.hs   other-modules:     MyPkg.A MyPkg.B-  build-depends:     base, HTF == 0.11.*+  build-depends:     base, HTF == 0.12.*   default-language:  Haskell2010  test-suite sample-tests   type:              exitcode-stdio-1.0   main-is:           TestMain.hs   other-modules:     MyPkg.A MyPkg.B-  build-depends:     base, HTF == 0.11.*+  build-depends:     base, HTF == 0.12.*   default-language:  Haskell2010
tests/Foo/test.h view
@@ -4,3 +4,6 @@  y :: Int y = 2++test_h_FAIL =+    assertEqual 4 5
tests/MiscTest.hs view
@@ -18,10 +18,12 @@ --  import Test.Framework.History+import Test.Framework.Preprocessor+import Test.Framework.PrettyHaskell import System.Exit import Test.HUnit -allTests = historyTests+allTests = historyTests ++ preprocessorTests ++ prettyHaskellTests  main :: IO () main =
tests/TestHTF.hs view
@@ -36,11 +36,14 @@ import qualified Data.HashMap.Strict as M import qualified Data.HashSet as Set import qualified Data.Aeson as J+import qualified Data.Aeson.Encode.Pretty as J import Data.Aeson ( (.=) ) import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy.Char8 as BSLC import Data.Maybe import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Encoding.Error as T import qualified Data.List as List import qualified Text.Regex as R import {-@ HTF_TESTS @-} qualified TestHTFHunitBackwardsCompatible@@ -143,7 +146,7 @@                                (xs::[Int]) == (reverse (reverse xs))  prop_fail'_FAIL =-    withQCArgs (\a -> a { replay = read "Just (1292732529 652912053,3)" }) prop+    prop     where prop xs = xs == (reverse xs)               where types = xs::[Int] @@ -177,6 +180,7 @@ -- $ find . -name '*.hs' | xargs egrep -w -o -h "[a-zA-Z0-9_']+_FAIL" | sed 's/test_//g; s/prop_//g' | sort -u     ["1_FAIL"     ,"a_FAIL"+    ,"h_FAIL"     ,"assertElem_FAIL"     ,"assertEmpty_FAIL"     ,"assertEqualNoShow_FAIL"@@ -260,6 +264,12 @@                              ,"location" .= J.object ["file" .= J.String "./Foo/A.hs"                                                      ,"line" .= J.toJSON (11::Int)]])        check jsons (J.object ["type" .= J.String "test-end"+                             ,"test" .= J.object ["flatName" .= J.String "Foo.A:h_FAIL"]])+                   (J.object ["test" .= J.object ["location" .= J.object ["file" .= J.String "Foo/test.h"+                                                                         ,"line" .= J.toJSON (8::Int)]]+                             ,"location" .= J.object ["file" .= J.String "./Foo/test.h"+                                                     ,"line" .= J.toJSON (9::Int)]])+       check jsons (J.object ["type" .= J.String "test-end"                              ,"test" .= J.object ["flatName" .= J.String "Main:subAssert_FAIL"]])                    (J.object ["callers" .= J.toJSON [J.object ["message" .= J.Null                                                               ,"location" .= J.object ["file" .= J.String "TestHTF.hs"@@ -269,7 +279,7 @@                                                                                       ,"line" .= J.toJSON (97+lineOffset)]]]])     where       lineOffset :: Int-      lineOffset = 9+      lineOffset = 12       checkStatus tuple@(pass, fail, error, pending, timedOut) json =           {-             {"location":null@@ -315,8 +325,8 @@           case filter (\j -> matches j pred) jsons of             [json] ->                 if not (matches json assert)-                   then error ("Predicate " ++ show pred ++ " match JSON " ++ show json ++ ", but assertion " ++-                               show assert ++ " not satisfied")+                   then error ("Predicate\n" ++ ppJ pred ++ " match JSON\n" ++ ppJ json ++ ", but assertion\n" +++                               ppJ assert ++ " not satisfied")                    else return ()             l -> error ("not exactly one JSON matches predicate " ++ show pred ++ " but " ++ show l)       matches :: J.Value -> J.Value -> Bool@@ -348,6 +358,11 @@                            else case splitJson rest of                                   [] -> error "invalid json output from HTF"                                   (x:xs) -> (start `BSL.append` x : xs)+      ppJ json =+          T.unpack $+          T.decodeUtf8With T.lenientDecode $+          BSL.toStrict $+          J.encodePretty' (J.Config 2 J.compare) json  runRealBlackBoxTests =     do b <- doesDirectoryExist "tests/bbt"
tests/compile-errors/run-tests.sh view
@@ -2,9 +2,21 @@  cd "$(dirname $0)" -FLAGS="-hide-all-packages -package base -package-conf ../../dist/package.conf.inplace -package HTF --make"-lineno=7+FLAGS="-hide-all-packages -package base -package-db ../../dist/package.conf.inplace -package HTF --make"+SANDBOX_FILE="../../cabal.sandbox.config"+SANDBOX_DIR="../../.cabal-sandbox"+GHC_VERSION=$(ghc --version | sed 's/.*version //g') +if [ -e "$SANDBOX_FILE"  ]+then+    for pkg_db in $(ls -d -1 $SANDBOX_DIR/*$GHC_VERSION*-packages.conf.d)+    do+        FLAGS="$FLAGS -package-db $pkg_db"+    done+fi+echo $FLAGS++lineno=7 function check() {     test="$1"