((section 2 "Outdated egg!" (p "This is an egg for CHICKEN 4, the unsupported old release.  You're almost certainly looking for " (int-link "/eggref/5/missbehave" "the CHICKEN 5 version of this egg") ", if it exists.") (p "If it does not exist, there may be equivalent functionality provided by another egg; have a look at the " (link "https://wiki.call-cc.org/chicken-projects/egg-index-5.html" "egg index") ". Otherwise, please consider porting this egg to the current version of CHICKEN.") (tags "egg")) (section 2 "Missbehave" (toc) (section 3 "Introduction" (p "Missbehave is a toolkit that allows to you to bring behaviour driven development in the spirit of rspec, to your scheme of choice.") (p "It is very much inspired and mostly modeled after the famous " (link "http://rspec.info" "rspec-library") ".")) (section 3 "Sources" (p "You can find the egg sources at: " (link "https://bitbucket.org/certainty/missbehave"))) (section 3 "The name" (p "As it has been asked on #chicken and it really can be misleading, here is why the name is spelled this way. It is intended to be a pun. (I guess not a good one, as i have to explain it)") (p "It consists of the words " (b "miss") " where i mean error. And " (b "behave") " where i mean, erm, behave. So you may read as \"C'mon miss, behave!\". That's by the way also the reason why the cli is called " (b "behave") ".") (p "So the two words together form \"mis" (b "s") "behave\" which is intentionally close to \"misbehave\".") (p "To be totally fair. I quite understand why this has been discussed, as i'm very aware of my limitions regarding english spelling.")) (section 3 "Examples" (highlight scheme "(use missbehave missbehave-matchers missbehave-stubs miscmacros)\n\n(define (callee . args) 'called)\n(define (call-it n)\n  (repeat n (callee)))\n\n(describe \"Missbehave features\"\n  (describe \"implicit subject\"\n     (subject-set! 42)\n     (it (is > 10))\n     (it (is a number))\n     (it should (be 42)))\n  \n         \n  (describe \"Simple be matchers\"\n     (it \"must be true\"\n         (expect #t (to (be true))))\n     (it \"must be a string\"\n         (expect \"hello\" (to (be a string))))\n     (it \"can use standard operators\"\n         (expect 3 (is > 0)))\n     (it \"can use predicates\"\n         (expect '() (is null?))))\n\n  \n  (define (numbers ls) ls)\n  \n  (describe \"Have\"\n    (it \"can be used with a collection procedure\"\n      (expect '(1 2 3) (has 3 numbers)))\n\n    (it \"supports arbritary sugar\"\n      (expect \"foo\" (has 3 characters))))\n\n  (describe \"Matches string\"\n    (it \"checks if regex matches string\"\n      (expect '(: (+ digit)) (matches-string \"1234\")))\n    (it \"checks the submatches\"\n      (expect '(: (+ digit) (submatch (+ any))) (matches-string \"1234foo\" with-matches: '((1 . \"foo\"))))))\n\n  (describe \"Pending\"\n     (it \"is implicitly pending\")\n     (it \"is explicitly pending\"\n         (pending)\n         (expect '() (be a number))))         \n\n  (describe \"Procedure expectations\"\n    (context \"Application-count\"\n      (it \"checks application count\"\n          (expect (call-it 1) (call callee once)))\n      (it \"checks application count > 1\"\n          (expect (call-it 4) (call callee (4 times))))\n      (it \"checks for no calls\"\n          (expect (+ 1 1) (call callee never))))\n    (context \"Arguments\"\n     (it \"checks arguments\"\n         (expect (callee 1 2) (call callee (with 1 2))))\n     (it \"mixes arguments and application count\"\n         (expect (begin (callee 1 2) (callee 1 2)) (call callee (with 1 2) twice)))))\n\n\n  (describe \"Procedure stubs\"\n    (it \"can stub return values\"\n        (stub! callee (returns 'not-called))\n        (expect (callee) (be 'not-called)))\n\n    (it \"provides temporary stubs\"\n        (let ((proc (lambda () 'test)))\n          (expect (proc) (be 'test))\n          (with-stubs! ((proc (returns 'passed)))\n            (expect (proc) (be 'passed)))\n          (expect (proc) (be 'test))))))") (p "Now invoke it with:") (highlight raw "$ behave test-spec.scm") (p "Produces the following output:") (highlight raw "Missbehave features\nProcedure stubs\n  It provides temporary stubs\n  It can stub return values\nProcedure expectations\nArguments\n  It mixes arguments and application count\n  It checks arguments\nApplication-count\n  It checks for no calls\n  It checks application count > 1\n  It checks application count\nPending\n  [P] It is explicitly pending\n  [P] It is implicitly pending\nSimple be matchers\n  It can use predicates\n  It can use standard operators\n  It must be a string\n  It must be true\nimplicit subject\n  It should (be a number)\n  It should (be 42)\n\n\nTotal: 15 Successful: 13 Pending: 2 Failures: 0")) (section 3 "Authors" (p (int-link "/users/david-krentzlin" "David Krentzlin"))) (section 3 "Api" (section 4 "Contexts " (p "Contexts are a way to group your examples. You can use the the macro " (b "context") " and its alias " (b "describe") " to create them.") (def (sig (syntax "(context context-name examples ...)" (id context))) (p "Create a context with the name " (tt "context-name") ".")) (def (sig (syntax "(context context-name (meta (tags ...)) examples ...)" (id context))) (p "Create a context with name " (tt "context-name") " and mark them with " (tt "tags") ". This can be used to filter examples using the --tags command-line switch of " (b "behave") ".")) (def (sig (syntax "(context context-name (meta ((tag . value) ...)) examples ...)" (id context))) (p "Create a context with name " (tt "context-name") " and mark them with the key-value pairs. Those can be used to attach data and to filter them using the --tags command-line-switch of " (b "behave"))) (section 5 "Examples" (highlight scheme "(context \"A simple context\" \n  (it \"does nothing\"))\n\n(context \"A context with tags\" (meta (long-running verbose))\n  (it \"is pending\"))\n\n(context \"A context with value tags\" (meta ((bug . \"#402\")))\n  (it \"is pending\"))\n  "))) (section 4 "Examples" (p "Examples allow you to specify a specific behaviour of your subject.") (def (sig (syntax "(it description)" (id it))) (p "Create a pending example with the description set to " (tt "description"))) (def (sig (syntax "(it should matcher)" (id it))) (p "Creates an example that executes " (tt "matcher") " on the current subject. See also " (b "subject-set!") ".")) (def (sig (syntax "(it description expectation ...)" (id it))) (p "Creates an examples with the description set to " (tt "description") " and the  expectations.") (highlight scheme "(it \"is pending\")\n\n(it \"succeeds\"\n  (expect #t))")) (section 5 "Meta-Information" (p "Metainformation can be used to mark certain examples or provide some form of addtional information. As a plus the behave-cli allows you to use those meta-information to filter certain examples.") (def (sig (syntax "(it description (meta (tags ...)) expectations)" (id it))) (p "Creates an example with expectations and tags.")) (def (sig (syntax "(it description (meta ((tag . value))) expectations ...)" (id it))) (p "Create an example with expectations and key-value pairs, so that it can be filtered."))) (section 5 "Examples" (highlight scheme "(it \"has tags\" (meta (some tag))\n  (expect #t))\n\n(it \"has more tags\" (meta ((some . tag) (some . other)))\n  (expect #t))"))) (section 4 "Expectations" (p "Expectations are the bdd-way of stating assertions.") (def (sig (syntax "(expect form)" (id expect))) (p "Create an expection that evaluates form and will fail if " (tt "form") " evaluates to #f and pass otherwise.") (highlight scheme "(it \"succeeds\")\n  (expect (string? \"chickumber\")))\n\n(it \"fails\" )\n  (expect (> 2 3)))")) (def (sig (syntax "(expect subject to (call arguments ...))" (id expect))) (p "Creates an application-expectation. See also procedure-expections.") (highlight scheme "(define (reverse-list ls)\n  (reverse ls))\n\n(expect (reverse-list (list 1 2 3)) (call reverse)))\n(expect (reverse-list (list 1 2)) (call reverse once)))\n(expect (reverse-list (list 1 2)) (call reverse (with (list 1 2))))\n(expect (reverse-list (list 1 2)) (call reverse (with (list 1 2)) once))\n")) (def (sig (syntax "(expect subject matcher)" (id expect))) (p "Create an expection on subject with matcher " (tt "matcher") ".") (highlight scheme "(expect (list 1 2) (be a list))\n(expect \"foobar\" (have 6 characters))\n(expect 3.1 (be (close-to 3)))")) (section 5 "Negative Expectations" (p "If you want to state that a given subject should not have a certain behaviou, you can simply wrap the expect-form into a do-not form") (def (sig (syntax "(do-not (expect ....))" (id do-not))) (p "Creates an expection that fails if its inner " (tt "expectation") " succeeds and vice versa.")))) (section 4 "Matchers" (p "Matchers are  the way to implement the checks for a given behaviour. They verify that a given subject behaves as expected.") (def (sig (syntax "(matcher (check (subject) check-code) (message (form subject negate) message-code))" (id matcher))) (p "This creates a fresh matcher object. You need to implement both the " (tt "check") " and the " (tt "message") ".") (ul (li "check The check is a procedure that receives one argument, the subject. The subject is a promise so you need to force it if you want to retrieve the value.") (li "message This is the procedure that is invoked to generate the message. It receives three arguments" (ul (li (tt "form") "  This is the quoted form that was passed to expect") (li (tt "subject") "  This is the subject. Again this is a promise so you need to force it to retrieve the actual value.") (li (tt "negate") " Indicates if the check shall be negated. This is set to true if the expect-form has been wrapped into a (do-not) form.")))) (highlight scheme "(define (greater-than x)\n (matcher \n   (check (subject)\n     (> (force subject) x))\n   (message (form subject negate)\n     (if negate\n        (sprintf \"Expected ~A to be less than or equal to ~A\" (force subject) x)\n        (sprintf \"Expected ~A to be greater than ~A\" (force subject) x)))))\n\n(expect 10 (be (greater-than 5)))"))) (section 4 "Builtin Matchers" (section 5 "Be " (p "The be matcher is possibly the most used. It allows you to describe what a given subject should be. The be macro allows a fair few variations. I've listed all possible forms below") (p (b "Aliases:") " is") (def (sig (syntax "(be true)" (id be))) (p "matches if subject is #t")) (def (sig (syntax "(be false)" (id be))) (p "matches if subject is #f")) (def (sig (syntax "(be a type)" (id be))) (p "matches if subject is of the specified type. It assumes that there is a procedure type? to check that.") (highlight scheme "(expect \"string\" (be a string))\n(expect (list 1 2 3) (be a list))")) (def (sig (syntax "(be pred?)" (id be))) (p "matches if pred? evaluates to #t when it is applied to subject") (highlight scheme "(expect 0 (be zero?))")) (def (sig (syntax "(be value)" (id be))) (p "matches if current subject is equal to value in the sense of equal?.")) (def (sig (syntax "(be pred? value ...)" (id be))) (p "This expands into something like (apply pred? (list subject value ...)). It provides a handy notation to write curried checks.") (highlight scheme "(expect 2 (be > 0))\n(expect -100 (be <=  10))")) (section 6 "Be-helpers " (p "There are some procedures that enhance the possibilities of the be matcher") (def (sig (procedure "(close-to value #!key (delta 0.3))" (id close-to))) (highlight scheme "(expect 2 (be (close-to 1))\n(expect  10/3 (be (close-to 3 delta: 0.4))")) (def (sig (procedure "(any-of value . more-values)" (id any-of))) (highlight scheme "(expect 2 (be (any-of 1 2 3 4))")) (def (sig (procedure "(none-of value . more-values)" (id none-of))) (highlight scheme "(expect 5 (be (none-of 1 2 3 4))")) (def (sig (procedure "(list-including value . more-values)" (id list-including))) (highlight scheme "(expect (list 1 2 3) (be (list-including 1 2))")))) (section 5 "match-string" (p "This matcher can be used to describe the behaviour of regular expressions.") (p (b "Aliases:") " matches-string") (def (sig (procedure "(match-string str #!key (with-matches #f))" (id match-string))) (p "This succeeds if the regular expression represented by " (tt "subject") " matches the string " (tt "str") ". If " (tt "with-matches") " is supplied, it is expected to be an alist holding the expected captures.") (highlight scheme "(expect '(: (+ space) (submatch (+ any))) \n  (match-string \"    test\" with-matches: '((1 . \"test\")))\n\n(expect '(: (+ any)) (match-string \"just a test\"))"))) (section 5 "have" (p "This matcher can be used to specify expectations on the amount of items in a collection.") (p (b "Aliases:") " has") (highlight scheme "(expect \"string\" (has 6 chars))\n\n(define (even-numbers ls) (filter even? ls))\n\n(expect '(1 2 3 4 5) (has 2 even-numbers))\n")) (section 5 "call" (p "This matcher is used to express procedure-expectations. It allows you to state that a form is expected to call a procedure.") (p (b "Aliases:") " calls") (def (sig (syntax "(call proc once)" (id call))) (p "matches if proc is called exactly once.")) (def (sig (syntax "(call proc twice)" (id call))) (p "matches if proc is called twice")) (def (sig (syntax "(call proc never)" (id call))) (p "matches if proc is never called.")) (def (sig (syntax "(call proc (n time))" (id call))) (p "matches if proc is called n times.")) (def (sig (syntax "(call proc (with arg ...))" (id call))) (p "matches if proc is called at least once with the given arguments.")) (def (sig (syntax "(call proc (with arg ...) amount-spec)" (id call))) (p "matches if proc is called with the given arguments and matches the amount-spec which is one of the above (once never (n times)).") (highlight scheme "(define (foo) \"foo\")\n(define (i-call-foo) (foo))\n\n(define (bar x y) \"bar\")\n(define (i-call-bar) (bar 1 2))\n\n(expect (i-call-foo) (call foo once))\n(expect (i-call-bar) (call bar (with 1 2) once))"))) (section 5 "raise" (p "This matcher allows you to formulate expections about errors") (def (sig (syntax "(raise error)" (id raise))) (p "Matches if subject raises errors.")) (def (sig (syntax "(raise (kind ...))" (id raise))) (p "Matches if subject raises an error and sets the kind-property at least to those specified.") (highlight scheme "(expect (error \"test\") (raise error))")))) (section 4 "Stubs " (p "Missbehave provides a simple way to stub procedures. This is useful in cases where you want to control some of the procedures that interface, with the one you currently describe.") (def (sig (syntax "(with-stubs! ((name stub) ... ) code ...)" (id with-stubs!))) (p "This form replaces the behavior of " (b "name") " with the stub code. Note that there is a (returns)-form which is a short-hand to create a procedure that returns the given value.")) (def (sig (procedure "(returns value . more-values)" (id returns))) (p "Creates a procedure that returns value. If you specify multiple value the procedure will return multiple values.") (highlight scheme "(define (return-3) 3)\n(with-stubs! ((return-3 (returns \"not 3\"))\n  (printf \"return-3 returns ~A~%\" (return-3)))"))) (section 4 "Hooks"))))