packages feed

hspec-meta 2.11.13 → 2.11.14

raw patch · 10 files changed

+263/−111 lines, 10 filesdep ~QuickCheckPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: QuickCheck

API changes (from Hackage documentation)

+ Test.Hspec.Meta: --
+ Test.Hspec.Meta: -- <a>Arg</a> is <tt>()</tt>, no argument is required and the
+ Test.Hspec.Meta: -- <a>Example</a> can be run as-is.
+ Test.Hspec.Meta: -- <a>Test.Hspec.Core.Hooks</a> such as <a>around</a>, <a>before</a>,
+ Test.Hspec.Meta: -- <a>mapSubject</a> and similar.
+ Test.Hspec.Meta: -- <tt><a>SpecWith</a> a</tt>, which cannot be executed without turning
+ Test.Hspec.Meta: -- The value of <a>Arg</a> is the difference between <a>Spec</a> (aka
+ Test.Hspec.Meta: -- To supply an argument to examples, use the functions in
+ Test.Hspec.Meta: -- it into <a>Spec</a> first.
+ Test.Hspec.Meta: -- | The argument type that is needed to run this <a>Example</a>. If

Files

hspec-core/src/Test/Hspec/Core/Example.hs view
@@ -40,12 +40,66 @@ import           Test.Hspec.Core.QuickCheck.Util (liftHook) import           Test.Hspec.Core.Example.Location --- | A type class for examples+-- | A type class for examples, that is to say, test bodies as used in+-- `Test.Hspec.Core.Spec.it` and similar functions. class Example e where+  -- | The argument type that is needed to run this `Example`.+  -- If `Arg` is @()@, no argument is required and the `Example` can be run+  -- as-is.+  --+  -- The value of `Arg` is the difference between `Test.Hspec.Core.Spec.Spec`+  -- (aka @`Test.Hspec.Core.Hspec.SpecWith` ()@), which can be executed, and+  -- @`Test.Hspec.Core.Spec.SpecWith` a@, which cannot be executed without+  -- turning it into `Test.Hspec.Core.Spec.Spec` first.+  --+  -- To supply an argument to examples, use the functions in+  -- "Test.Hspec.Core.Hooks" such as `Test.Hspec.Core.Hooks.around',+  -- `Test.Hspec.Core.Hooks.before', `Test.Hspec.Core.Hooks.mapSubject' and+  -- similar.   type Arg e   type Arg e = ()-  evaluateExample :: e -> Params -> (ActionWith (Arg e) -> IO ()) -> ProgressCallback -> IO Result +  -- | Evaluates an example.+  --+  -- `evaluateExample` is expected to execute the test body inside the IO action+  -- passed to the hook. It's often necessary to use an `IORef` to pass data+  -- out like whether the test succeeded to the outer IO action so it can be+  -- returned as a `Result`.+  --+  -- Example:+  --+  -- @+  -- newtype MyAction = MyAction (Int -> IO Bool)+  --+  -- instance Example MyAction where+  --   type Arg MyAction = Int+  --+  --   evaluateExample (MyAction act) _params hook _progress = do+  --     result <- newIORef (Result "" Success)+  --     hook $ \arg -> do+  --       -- e.g. determines if arg is 42+  --       ok <- act arg+  --       let result' = Result "" $ if ok then Success else Failure Nothing NoReason+  --       writeIORef result result'+  --     readIORef result+  -- @+  evaluateExample+    :: e+    -- ^ The example being evaluated+    -> Params+    -- ^ QuickCheck/SmallCheck settings+    -> (ActionWith (Arg e) -> IO ())+    -- ^ Hook: takes an @`ActionWith` (`Arg` e)@, namely, the IO action to run+    -- the test body, obtains @`Arg` e@ from somewhere, then executes the test+    -- body (or possibly decides not to execute it!).+    --+    -- This is used to implement `Test.Hspec.Core.Hooks.around` and similar+    -- hook functionality.+    -> ProgressCallback+    -- ^ Callback for composite tests like QuickCheck to report their progress.+    -> IO Result++-- | QuickCheck and SmallCheck related parameters. data Params = Params {   paramsQuickCheckArgs  :: QC.Args , paramsSmallCheckDepth :: Maybe Int@@ -57,10 +111,17 @@ , paramsSmallCheckDepth = Nothing } +-- | @(CurrentItem, TotalItems)@ tuple. type Progress = (Int, Int)+-- | Callback used by composite test items that contain many tests to report+-- their progress towards finishing them all.+--+-- This is used, for example, to report how many QuickCheck examples are finished. type ProgressCallback = Progress -> IO () --- | An `IO` action that expects an argument of type @a@+-- | An `IO` action that expects an argument of type @a@.+--+-- This type is what `Example`s are ultimately unlifted into for execution. type ActionWith a = a -> IO ()  -- | The result of running an example
hspec-core/src/Test/Hspec/Core/Formatters/Pretty.hs view
@@ -56,8 +56,8 @@         go value = case value of           Char _ -> False           String _ -> True-          Rational _ _ -> False           Number _ -> False+          Operator _ _ _ -> True           Record _ _ -> True           Constructor _ xs -> any go xs           Tuple xs -> any go xs@@ -97,8 +97,8 @@     render indentation = \ case       Char c -> shows c       String str -> if unicode then Builder $ ushows str else shows str-      Rational n d -> render indentation n <> " % " <> render indentation d       Number n -> fromString n+      Operator a name b -> render indentation a <> " " <> fromString name <> " " <> render indentation b       Record name fields -> fromString name <> renderFields fields       Constructor name values -> intercalate " " (fromString name : map (render indentation) values)       Tuple [e@Record{}] -> render indentation e
hspec-core/src/Test/Hspec/Core/Formatters/Pretty/Parser.hs view
@@ -1,107 +1,171 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables #-} module Test.Hspec.Core.Formatters.Pretty.Parser (   Value(..) , parseValue ) where  import           Prelude ()-import           Test.Hspec.Core.Compat--import           Test.Hspec.Core.Formatters.Pretty.Parser.Parser hiding (Parser)-import qualified Test.Hspec.Core.Formatters.Pretty.Parser.Parser as P+import           Test.Hspec.Core.Compat hiding (Alternative(..), read, exp) -import           Language.Haskell.Lexer hiding (Pos(..))+import           Language.Haskell.Lexer hiding (Token, Pos(..))+import qualified Language.Haskell.Lexer as Lexer  type Name = String  data Value =     Char Char   | String String-  | Rational Value Value   | Number String+  | Operator Value Name Value   | Record Name [(Name, Value)]   | Constructor Name [Value]   | Tuple [Value]   | List [Value]   deriving (Eq, Show) -type Parser = P.Parser (Token, String)+type Token = (TokenType, String) +type TokenType = Lexer.Token++newtype Parser a = Parser {+  runParser :: [Token] -> Maybe (a, [Token])+} deriving Functor++instance Applicative Parser where+  pure a = Parser $ \ input -> Just (a, input)+  (<*>) = ap++instance Monad Parser where+  return = pure+  p1 >>= p2 = Parser $ runParser p1 >=> uncurry (runParser . p2)+ parseValue :: String -> Maybe Value-parseValue input = case runParser value (tokenize input) of+parseValue input = case runParser exp (tokenize input) of   Just (v, []) -> Just v   _ -> Nothing -value :: Parser Value-value =-      char-  <|> string-  <|> rational-  <|> number-  <|> record-  <|> constructor-  <|> tuple-  <|> list+tokenize :: String -> [Token]+tokenize = go . map (fmap snd) . rmSpace . lexerPass0+  where+    go :: [Token] -> [Token]+    go tokens = case tokens of+      [] -> []+      (Varsym, "-") : (IntLit, n) : xs -> (IntLit, "-" ++ n) : go xs+      (Varsym, "-") : (FloatLit, n) : xs -> (FloatLit, "-" ++ n) : go xs+      x : xs -> x : go xs -char :: Parser Value-char = Char <$> (token CharLit >>= readA)+exp :: Parser Value+exp = infixexp -string :: Parser Value-string = String <$> (token StringLit >>= readA)+infixexp :: Parser Value+infixexp = aexp accept reject+  where+    accept :: Value -> Parser Value+    accept value = peek >>= \ case+      (Varsym, "%") -> skip >> Operator value "%" <$> exp+      (Consym, name) -> skip >> Operator value name <$> exp+      _ -> return value -rational :: Parser Value-rational = Rational <$> (number <|> tuple) <* require (Varsym, "%") <*> number+    reject :: Parser Value+    reject = next >>= unexpected -number :: Parser Value-number = integer <|> float+aexp :: forall a. (Value -> Parser a) -> Parser a -> Parser a+aexp continue done = peek >>= \ case+  (CharLit, value) -> read Char value+  (StringLit, value) -> read String value+  (IntLit, value) -> number value+  (FloatLit, value) -> number value+  (Conid, name) -> accept $ constructor name+  (Special, "(") -> accept tuple+  (Special, "[") -> accept list+  _ -> done   where-    integer :: Parser Value-    integer = Number <$> token IntLit+    read :: Read v => (v -> Value) -> String -> Parser a+    read c v = skip >> c <$> readValue v >>= continue -    float :: Parser Value-    float = Number <$> token FloatLit+    number :: String -> Parser a+    number value = skip >> continue (Number value) -record :: Parser Value-record = Record <$> token Conid <* special "{" <*> fields <* special "}"-  where-    fields :: Parser [(Name, Value)]-    fields = field `sepBy1` comma+    accept :: Parser Value -> Parser a+    accept action = skip >> action >>= continue -    field :: Parser (Name, Value)-    field = (,) <$> token Varid <* equals <*> value+constructor :: String -> Parser Value+constructor name = peek >>= \ case+  (Special, "{") -> skip >> Record name <$> commaSeparated field "}"+    where+      field :: Parser (Name, Value)+      field = (,) <$> require Varid <* equals <*> exp -constructor :: Parser Value-constructor = Constructor <$> token Conid <*> many value+  _ -> Constructor name <$> parameters+    where+      parameters :: Parser [Value]+      parameters = aexp more done +      more :: Value -> Parser [Value]+      more v = (:) v <$> parameters++      done :: Parser [Value]+      done = return []+ tuple :: Parser Value-tuple = Tuple <$> (special "(" *> items) <* special ")"+tuple = Tuple <$> commaSeparated exp ")"  list :: Parser Value-list = List <$> (special "[" *> items) <* special "]"--items :: Parser [Value]-items = value `sepBy` comma+list = List <$> commaSeparated exp "]" -special :: String -> Parser ()-special s = require (Special, s)+commaSeparated :: forall a. Parser a -> String -> Parser [a]+commaSeparated item close = peek >>= \ case+  (Special, c) | c == close -> skip >> return []+  _ -> items+  where+    items :: Parser [a]+    items = (:) <$> item <*> moreItems -comma :: Parser ()-comma = special ","+    moreItems :: Parser [a]+    moreItems = next >>= \ case+      (Special, c)+        | c == "," -> items+        | c == close -> return []+      t -> unexpected t  equals :: Parser ()-equals = require (Reservedop, "=")+equals = requireToken (Reservedop, "=") -token :: Token -> Parser String-token t = snd <$> satisfy (fst >>> (== t))+require :: TokenType -> Parser String+require expected = next >>= \ case+  (token, v) | token == expected -> return v+  token -> unexpected token -require :: (Token, String) -> Parser ()-require t = void $ satisfy (== t)+requireToken :: Token -> Parser ()+requireToken expected = next >>= \ case+  token | token == expected -> return ()+  token -> unexpected token -tokenize :: String -> [(Token, String)]-tokenize = go . map (fmap snd) . rmSpace . lexerPass0-  where-    go :: [(Token, String)] -> [(Token, String)]-    go tokens = case tokens of-      [] -> []-      (Varsym, "-") : (IntLit, n) : xs -> (IntLit, "-" ++ n) : go xs-      (Varsym, "-") : (FloatLit, n) : xs -> (FloatLit, "-" ++ n) : go xs-      x : xs -> x : go xs+peek :: Parser Token+peek = Parser $ \ input -> case input of+  t : _ -> Just (t, input)+  [] -> Just ((GotEOF, ""), input)++next :: Parser Token+next = Parser $ \ case+  t : ts -> Just (t, ts)+  ts -> Just ((GotEOF, ""), ts)++skip :: Parser ()+skip = Parser $ \ case+  _ : ts -> Just ((), ts)+  ts -> Just ((), ts)++empty :: Parser a+empty = Parser $ const Nothing++readValue :: Read a => String -> Parser a+readValue = maybe empty pure . readMaybe++unexpected :: Token -> Parser a+unexpected _ = empty++-- unexpected :: HasCallStack => (Token, String) -> Parser a+-- unexpected = error . show
− hspec-core/src/Test/Hspec/Core/Formatters/Pretty/Parser/Parser.hs
@@ -1,34 +0,0 @@-{-# LANGUAGE DeriveFunctor #-}-module Test.Hspec.Core.Formatters.Pretty.Parser.Parser where--import           Prelude ()-import           Test.Hspec.Core.Compat--newtype Parser token a = Parser { runParser :: [token] -> Maybe (a, [token]) }-  deriving Functor--instance Applicative (Parser token) where-  pure a = Parser $ \ input -> Just (a, input)-  (<*>) = ap--instance Monad (Parser token) where-  return = pure-  p1 >>= p2 = Parser $ runParser p1 >=> uncurry (runParser . p2)--instance Alternative (Parser token) where-  empty = Parser $ const Nothing-  p1 <|> p2 = Parser $ \ input -> runParser p1 input <|> runParser p2 input--satisfy :: (token -> Bool) -> Parser token token-satisfy p = Parser $ \ input -> case input of-  t : ts | p t -> Just (t, ts)-  _ -> Nothing--sepBy :: Alternative m => m a -> m sep -> m [a]-sepBy p sep = sepBy1 p sep <|> pure []--sepBy1 :: Alternative m => m a -> m sep -> m [a]-sepBy1 p sep = (:) <$> p <*> many (sep *> p)--readA :: (Alternative m, Read a) => String -> m a-readA = maybe empty pure . readMaybe
hspec-core/src/Test/Hspec/Core/Hooks.hs view
@@ -96,8 +96,18 @@ after_ :: IO () -> SpecWith a -> SpecWith a after_ action = after $ \_ -> action --- | Run a custom action before and/or after every spec item.-around :: (ActionWith a -> IO ()) -> SpecWith a -> Spec+-- | Run a custom action before and/or after every spec item, supplying it with+-- an argument obtained via IO.+--+-- This is useful for tasks like creating a file handle or similar resource+-- before a test and destroying it after the test.+around+  :: (ActionWith a -> IO ())+  -- ^ Function provided with an action to run the spec item as argument. It+  -- should return the action to actually execute the item.+  -> SpecWith a+  -- ^ Spec to modify+  -> Spec around action = aroundWith $ \e () -> action e  -- | Run a custom action after the last spec item.
hspec-core/src/Test/Hspec/Core/QuickCheck/Util.hs view
@@ -37,7 +37,16 @@  import           Test.Hspec.Core.Util -liftHook :: r -> ((a -> IO ()) -> IO ()) -> (a -> IO r) -> IO r+liftHook+  :: r+  -- ^ Default result, taken if the hook decides to not run the test+  -> ((a -> IO ()) -> IO ())+  -- ^ Hook: given an action to actually run the test, potentially does+  -- some IO actions before the test, runs it while supplying an argument (or+  -- skips it!), then may execute some more actions after running it.+  -> (a -> IO r)+  -- ^ The actual test being run, producing a result+  -> IO r liftHook def hook inner = do   ref <- newIORef def   hook $ inner >=> writeIORef ref
hspec-core/src/Test/Hspec/Core/Spec.hs view
@@ -19,6 +19,10 @@ , xdescribe , xcontext +-- * Focused spec items #focus#+-- |+-- During a test run, when a spec contains /focused/ spec items, all other spec+-- items are ignored. , focus , fit , fspecify@@ -125,6 +129,16 @@ -- > describe "absolute" $ do -- >   it "returns a positive number when given a negative number" $ -- >     absolute (-1) == 1+--+-- @`Example` a@ optionally accepts an argument @`Arg` a@, which is then given+-- to the test body. This is useful for provisioning resources for a test which+-- are created and cleaned up outside the test itself. See `Arg` for details.+--+-- Note that this function is often on the scene of nasty type errors due to GHC failing+-- to infer the type of @do@ notation in the test body.+-- It can be helpful to use+-- [TypeApplications](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_applications.html)+-- to explicitly specify the intended `Example` type. it :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a) it label action = fromSpecList [specItem label action] @@ -149,6 +163,7 @@ focus :: SpecWith a -> SpecWith a focus = mapSpecForest focusForest +-- | Marks an entire spec forest as focused if nothing in it is already focused. focusForest :: [SpecTree a] -> [SpecTree a] focusForest xs   | any (any itemIsFocused) xs = xs
hspec-core/src/Test/Hspec/Core/Spec/Monad.hs view
@@ -32,8 +32,24 @@  import           Test.Hspec.Core.Config.Definition (Config) +-- | A `SpecWith` that can be evaluated directly by the+-- `Test.Hspec.Core.Runner.hspec` function as it does not require any+-- parameters. type Spec = SpecWith () +-- | A @'SpecWith' a@ represents a test or group of tests that require an @a@+-- value to run.+--+-- In the common case, a 'Spec' is a @'SpecWith' ()@ which requires @()@ and+-- can thus be executed with `Test.Hspec.Core.Runner.hspec'.+--+-- To supply an argument to `SpecWith` tests to turn them into `Spec`, use+-- functions from "Test.Hspec.Core.Hooks" such as+-- `Test.Hspec.Core.Hooks.around`, `Test.Hspec.Core.Hooks.before',+-- `Test.Hspec.Core.Hooks.mapSubject' and similar.+--+-- Values of this type are created by `Test.Hspec.Core.Spec.it`,+-- `Test.Hspec.Core.Spec.describe` and similar. type SpecWith a = SpecM a ()  -- |@@ -41,7 +57,13 @@ modifyConfig :: (Config -> Config) -> SpecWith a modifyConfig f = SpecM $ tell (Endo f, mempty) --- | A writer monad for `SpecTree` forests+-- | A writer monad for `SpecTree` forests.+--+-- This is used by `Test.Hspec.Core.Spec.describe` and is used+-- to construct the forest of spec items.+--+-- It allows for dynamically generated spec trees, for example, by using data+-- obtained by performing IO actions with 'runIO'. newtype SpecM a r = SpecM { unSpecM :: WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r }   deriving (Functor, Applicative, Monad) @@ -60,7 +82,7 @@ -- | Run an IO action while constructing the spec tree. -- -- `SpecM` is a monad to construct a spec tree, without executing any spec--- items.  @runIO@ allows you to run IO actions during this construction phase.+-- items itself.  @runIO@ allows you to run IO actions during this construction phase. -- The IO action is always run when the spec tree is constructed (e.g. even -- when @--dry-run@ is specified). -- If you do not need the result of the IO action to construct the spec tree,@@ -79,12 +101,19 @@ mapSpecItem_ :: (Item a -> Item b) -> SpecWith a -> SpecWith b mapSpecItem_ = mapSpecForest . bimapForest id +-- | Modifies the `Params` on the spec items to be generated by `SpecWith`. modifyParams :: (Params -> Params) -> SpecWith a -> SpecWith a modifyParams f = mapSpecItem_ $ \item -> item {itemExample = \p -> (itemExample item) (f p)}  newtype Env = Env {+  -- | The path of _parent_ `Hspec.Core.Spec.describe` labels from innermost to+  -- outermost.   envSpecDescriptionPath :: [String] } +-- | Applies a function to modify the `Env` of items being written by a child+-- spec writer.+--+-- This is used to implement `Hspec.Core.Spec.describe`. withEnv :: (Env -> Env) -> SpecM a r -> SpecM a r withEnv f = SpecM . WriterT . local f . runWriterT . unSpecM
hspec-meta.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           hspec-meta-version:        2.11.13+version:        2.11.14 synopsis:       A version of Hspec which is used to test Hspec itself description:    A stable version of Hspec which is used to test the                 in-development version of Hspec.@@ -66,7 +66,6 @@       Test.Hspec.Core.Formatters.Internal       Test.Hspec.Core.Formatters.Pretty       Test.Hspec.Core.Formatters.Pretty.Parser-      Test.Hspec.Core.Formatters.Pretty.Parser.Parser       Test.Hspec.Core.Formatters.Pretty.Unicode       Test.Hspec.Core.Formatters.V1       Test.Hspec.Core.Formatters.V1.Free
hspec/src/Test/Hspec.hs view
@@ -10,8 +10,7 @@ -- * Types   Spec , SpecWith-, Arg-, Example+, Example(Arg)  -- * Setting expectations , module Test.Hspec.Expectations@@ -40,7 +39,7 @@ , xdescribe , xcontext --- * Focused spec items+-- * Focused spec items #focus# -- | -- During a test run, when a spec contains /focused/ spec items, all other spec -- items are ignored.