-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Build and evaluate trees of predicates -- -- Build and evaluate trees of predicates. For example, you might build a -- predicate of the type Int -> Bool. You do this by assembling -- several predicates into a tree. You can then verbosely evaluate this -- tree, showing why a particular result is reached. -- -- prednote also provides modules to test several subjects against a -- given predicate, and to parse infix or RPN expressions into a tree of -- predicates. @package prednote @version 0.4.0.0 -- | Trees of predicates. -- -- Exports names which conflict with Prelude names, so you probably want -- to import this module qualified. module Data.Prednote.Pdct type Label = Text -- | A tree of predicates. data Pdct a Pdct :: Label -> (Node a) -> Pdct a data Node a -- | None of the Pdct in list may be Just False. An empty list or list with -- only Nothing is Just True. And :: [Pdct a] -> Node a -- | At least one of the Pdct in the list must be Just True. An empty list -- or list with only Nothing is Just False. Or :: [Pdct a] -> Node a -- | Just True is Just False and vice versa; Nothing remains Nothing. Not :: (Pdct a) -> Node a -- | Just True if the child is Just True; Nothing otherwise. NeverFalse :: (Pdct a) -> Node a -- | Just False if the child is Just False; Nothing otherwise. NeverTrue :: (Pdct a) -> Node a -- | An operand may return Just True or Just False to indicate success or -- failure. It may also return Nothing to indicate a discard. Operand :: (a -> Maybe Bool) -> Node a -- | Renames the top level of the Pdct. The function you pass will be -- applied to the old name. rename :: (Text -> Text) -> Pdct a -> Pdct a -- | Returns a tree that is always True. always :: Pdct a -- | Returns a tree that is always False. never :: Pdct a -- | Creates a new operand. The Pdct is Just True or Just False, never -- Nothing. operand :: Text -> (a -> Bool) -> Pdct a and :: [Pdct a] -> Pdct a or :: [Pdct a] -> Pdct a not :: Pdct a -> Pdct a -- | Turns an existing Pdct to one that never says False. If the underlying -- predicate returns Just True, the new Pdct also returns Just True. -- Otherwise, the Pdct returns Nothing. neverFalse :: Pdct a -> Pdct a -- | Turns an existing Pdct to one that never says True. If the underlying -- predicate returns Just False, the new Pdct also returns Just False. -- Otherwise, the Pdct returns Nothing. neverTrue :: Pdct a -> Pdct a -- | Forms a Pdct using and. (&&&) :: Pdct a -> Pdct a -> Pdct a -- | Forms a Pdct using or. (|||) :: Pdct a -> Pdct a -> Pdct a -- | Given a function that un-boxes values of type b, changes a Pdct from -- type a to type b. boxPdct :: (b -> a) -> Pdct a -> Pdct b -- | Given a function that un-boxes values of type b, changes a Node from -- type a to type b. boxNode :: (b -> a) -> Node a -> Node b -- | How many levels of indentation to use. Typically you will start this -- at zero. It is incremented by one for each level as functions descend -- through the tree. type Level = Int -- | The number of spaces to use for each level of indentation. type IndentAmt = Int type ShowDiscards = Bool -- | Shows a Pdct tree without evaluating it. showPdct :: IndentAmt -> Level -> Pdct a -> [Chunk] -- | Evaluates a Pdct. eval :: Pdct a -> a -> Maybe Bool -- | Verbosely evaluates a Pdct. evaluate :: IndentAmt -> ShowDiscards -> a -> Level -> Pdct a -> (Maybe Bool, [Chunk]) instance Show (Pdct a) -- | Postfix, or RPN, expression parsing. -- -- This module parses RPN expressions where the operands are predicates -- and the operators are one of and, or, or -- not, where and and or are binary and -- not is unary. module Data.Prednote.Expressions.RPN type Error = Text data RPNToken a TokOperand :: (Pdct a) -> RPNToken a TokOperator :: Operator -> RPNToken a data Operator OpAnd :: Operator OpOr :: Operator OpNot :: Operator pushOperand :: Pdct a -> [Pdct a] -> [Pdct a] pushOperator :: Operator -> [Pdct a] -> Exceptional Error [Pdct a] pushToken :: [Pdct a] -> RPNToken a -> Exceptional Error [Pdct a] -- | Parses an RPN expression and returns the resulting Pdct. Fails if -- there are no operands left on the stack or if there are multiple -- operands left on the stack; the stack must contain exactly one operand -- in order to succeed. parseRPN :: Foldable f => f (RPNToken a) -> Exceptional Error (Pdct a) instance Show Operator module Data.Prednote.Expressions.Infix data InfixToken a TokRPN :: (RPNToken a) -> InfixToken a TokParen :: Paren -> InfixToken a data Paren Open :: Paren Close :: Paren -- | Creates an RPN expression from an infix one. Fails only if there are -- mismatched parentheses. It is possible to create a nonsensical RPN -- expression; the RPN parser must catch this. createRPN :: Foldable f => f (InfixToken a) -> Maybe [RPNToken a] -- | Handles parsing of both infix and RPN Pdct expressions. module Data.Prednote.Expressions -- | Is this an infix or RPN expression? data ExprDesc Infix :: ExprDesc RPN :: ExprDesc type Error = Text -- | A single type for both RPN tokens and infix tokens. data Token a -- | Creates Operands from Pdct. operand :: Pdct a -> Token a -- | The And operator opAnd :: Token a -- | The Or operator opOr :: Token a -- | The Not operator opNot :: Token a -- | Open parentheses openParen :: Token a -- | Close parentheses closeParen :: Token a -- | Parses expressions. Fails if the expression is nonsensical in some way -- (for example, unbalanced parentheses, parentheses in an RPN -- expression, or multiple stack values remaining.) Works by first -- changing infix expressions to RPN ones. parseExpression :: ExprDesc -> [Token a] -> Exceptional Error (Pdct a) instance Eq ExprDesc instance Show ExprDesc -- | Helps you build a tree of tests that run against a series of items. -- This is best illustrated with an example. -- -- Let's say that you have a list of Int. You want to make sure that -- every Int in the list is odd and that every Int is greater than zero. -- You also want to make sure that at least 5 Ints in the list are -- greater than 20. -- -- Pdct from Data.Prednote.Pdct will help you, but only -- so much: a Pdct can test individual Int, but by itself it -- will not help you run a check against a whole list of Int. Of course -- you can build such a test fairly easily with any and -- all, but what if you want to view the results of the tests -- verbosely? That's where this module comes in. -- --
--   {-# LANGUAGE OverloadedStrings #-}
--   import System.Console.Rainbow
--   import Data.Prednote.TestTree
--   import Data.Prednote.Pdct
--   
--   isOdd :: Pdct Int
--   isOdd = operand "is odd" odd
--   
--   greaterThan0 :: Pdct Int
--   greaterThan0 = operand "greater than zero" (> 0)
--   
--   greaterThan20 :: Pdct Int
--   greaterThan20 = operand "greater than 20" (> 20)
--   
--   myOpts :: TestOpts Int
--   myOpts = TestOpts
--     { tIndentAmt = 2
--     , tPassVerbosity = TrueSubjects
--     , tFailVerbosity = TrueSubjects
--     , tGroupPred = const True
--     , tTestPred = const True
--     , tShowSkippedTests = True
--     , tGroupVerbosity = AllGroups
--     , tSubjects = mySubjects
--     , tStopOnFail = False
--     }
--   
--   mySubjects :: [Int]
--   mySubjects = [2, 4, 6, 8, 10, 18, 19, 20, 21, 22, 24, 26]
--   
--   tests :: [TestTree Int]
--   tests = [ isOdd, greaterThan0, greaterThan20 ]
--   
--   main :: IO ()
--   main = do
--     let (cks, passed, failed) = runTests myOpts 0 tests
--     t <- termFromEnv
--     printChunks t cks
--     putStrLn $ "number of tests passed: " ++ show passed
--     putStrLn $ "number of tests failed: " ++ show failed
--   
module Data.Prednote.TestTree -- | The name of a test or of a group. type Name = Text -- | A test is a function of this type. The function must make chunks in a -- manner that respects the applicable verbosity. type TestFunc a = IndentAmt -> Verbosity -> Verbosity -> [a] -> Level -> (Pass, [Chunk]) -- | A tree of tests. data TestTree a TestTree :: Name -> (Payload a) -> TestTree a data Payload a Group :: [TestTree a] -> Payload a Test :: (TestFunc a) -> Payload a -- | Creates tests. test :: Name -> TestFunc a -> TestTree a -- | Passes if every subject is True. eachSubjectMustBeTrue :: Name -> (a -> Text) -> Pdct a -> TestTree a -- | Passes if at least n subjects are True. nSubjectsMustBeTrue :: Name -> (a -> Text) -> Int -> Pdct a -> TestTree a -- | Creates groups of tests. group :: Name -> [TestTree a] -> TestTree a -- | How verbose to be when reporting the results of tests. It would be -- possible to have many more knobs to control this behavior; this -- implementation is a compromise and hopefully provides enough verbosity -- settings without being too complex. data Verbosity -- | Show nothing at all Silent :: Verbosity -- | Show only whether the test passed or failed PassFail :: Verbosity -- | Show subjects that are False. In addition, shows all evaluation steps -- that led to the subject being False; however, does not show discarded -- evaluation steps. Does not show True subjects at all. FalseSubjects :: Verbosity -- | Show subjects that are True. (This is cumulative, so False subjects -- are shown too, as they would be using FalseSubjects.) Shows all -- evaluation steps that led to the subject being True; however, does not -- show discarded evaluation steps. TrueSubjects :: Verbosity -- | Shows discarded subjects. Cumulative, so also does what -- FalseSubjects and TrueSubjects do. Also shows all -- discarded evaluation steps for all subjects. Discards :: Verbosity -- | How verbose to be when showing names of groups. data GroupVerbosity -- | Show no group names at all. However, groups will still be indented. NoGroups :: GroupVerbosity -- | Show groups that are not skipped. ActiveGroups :: GroupVerbosity -- | Show all groups, and indicate which groups are skipped. AllGroups :: GroupVerbosity -- | How many levels of indentation to use. Typically you will start this -- at zero. It is incremented by one for each level as functions descend -- through the tree. type Level = Int type PassCount = Int type FailCount = Int -- | Runs each test in a list of tests (though each test might not run if -- tStopOnFail is True.) Reports on how many passed and how many -- failed. (if tStopOnFail is True, the FailCount will never -- exceed 1.) runTests :: TestOpts a -> Level -> [TestTree a] -> ([Chunk], PassCount, FailCount) -- | Shows a tree, without evaluating it. showTestTree :: IndentAmt -> Level -> TestTree a -> [Chunk] -- | Options for running tests. data TestOpts a TestOpts :: Int -> Verbosity -> Verbosity -> (Name -> Bool) -> (Name -> Bool) -> Bool -> GroupVerbosity -> [a] -> Bool -> TestOpts a -- | Indent each level by this many spaces tIndentAmt :: TestOpts a -> Int -- | Use this verbosity for tests that pass tPassVerbosity :: TestOpts a -> Verbosity -- | Use this verbosity for tests that fail tFailVerbosity :: TestOpts a -> Verbosity -- | Groups are run only if this predicate returns True. tGroupPred :: TestOpts a -> Name -> Bool -- | Tests are run only if this predicate returns True. tTestPred :: TestOpts a -> Name -> Bool -- | Some tests might be skipped; see tTestPred. This controls -- whether you want to see a notification of tests that were skipped. -- (Does not affect skipped groups; see tGroupVerbosity for that.) tShowSkippedTests :: TestOpts a -> Bool -- | Show group names? Even if you do not show the names of groups, tests -- within the group will still be indented. tGroupVerbosity :: TestOpts a -> GroupVerbosity -- | The subjects to test tSubjects :: TestOpts a -> [a] -- | If True, then tests will stop running immediately after a single test -- fails. If False, all tests are always run. tStopOnFail :: TestOpts a -> Bool -- | True if the tree returned a result without completely evaluating all -- parts of the tree. This can occur if tStopOnFail is True and -- one of the tests in the tree failed. type ShortCircuit = Bool type Pass = Bool -- | Evaluates a tree. This function is the basis of runTests, which -- is typically a bit easier to use. evalTree :: TestOpts a -> Level -> TestTree a -> (ShortCircuit, [Either [Chunk] (Pass, [Chunk])]) instance Eq Verbosity instance Ord Verbosity instance Show Verbosity instance Eq GroupVerbosity instance Ord GroupVerbosity instance Show GroupVerbosity