'''Emacs Lisp Expectations''' is the simplest unit testing framework by [[rubikitch]]. It is very easy to use/read.

[new]
The new generation of EmacsLispExpectations is available, Lisp:ert-expectations.el , using ErtTestLibrary.
Lisp:el-expectations.el is obsolete.

Mocking is done utilizing '''EmacsLispMock'''. You should download it, too:

Lisp:el-mock.el

Emacs Lisp Expectations is modeled after [http://expectations.rubyforge.org/ Ruby's expectations] by Jay Fields. It inherits testing policy, designed to encourage unit testing best practices such as:

* Discourage setting more than one expectation at a time
* Promote maintainability by not providing a setup or teardown method
* Provide one syntax for setting up state based or behavior based expectation
* Focus on readability by providing no mechanism for describing an expectation other than the code in the expectation.

== Usage ==

# Evaluate an expectations S-exp.
# `M-x expectations-execute' to execute a test.
# If there are any errors, use `M-x next-error' (##C-x `##) and `M-x previous-error' to go to the expectations S-exp.

`expectations' defines a expectations test case. Use `expect' and
`desc' to verify the code. Note that these are neither functions nor
macros. These are keywords in expectations Domain Specific
Language (DSL).

=== Synopsis ===

* ##(expect EXPECTED-VALUE BODY ...)##

Assert that the evaluation result of ##BODY## is `equal' to ##EXPECTED-VALUE##.

* ##(desc DESCRIPTION)##

Description of a test. It is treated only as a delimiter comment.

=== Synopsis of EXPECTED-VALUE ===

* ##(buffer BUFFER-NAME)##

Body should eq buffer object of ##BUFFER-NAME##.

* ##(regexp REGEXP)##

Body should match ##REGEXP##.

* ##(type TYPE-SYMBOL)##

Body should be a ##TYPE-SYMBOL##. ##TYPE-SYMBOL## must be one of symbols
returned by `type-of' function:

   `symbol', `integer', `float', `string', `cons', `vector',
   `char-table', `bool-vector', `subr', `compiled-function',
   `marker', `overlay', `window', `buffer', `frame', `process',
   `window-configuration'

* ##(error)##

Body should raise any error.

* ##(error ERROR-SYMBOL)##

Body should raise ##ERROR-SYMBOL## error.

* ##(error ERROR-SYMBOL ERROR-DATA)##

Body should raise ##ERROR-SYMBOL## error with ##ERROR-DATA##. ##ERROR-DATA## is
2nd argument of `signal' function. Example:

    (expect (error wrong-number-of-arguments '(= 3))
      (= 1 2 3 ))

* ##(error-message ERROR-MESSAGE)##

Body should raise any error with ##ERROR-MESSAGE##. Example:

    (expect (error-message \"ERROR!!\")
      (error \"ERROR!!\"))

* ##(mock MOCK-FUNCTION-SPEC => MOCK-RETURN-VALUE)##

Body should call ##MOCK-FUNCTION-SPEC## and returns ##MOCK-RETURN-VALUE##.
Mock assertion depends on `el-mock' library. If available, you do not
have to require it: ##el-expectations## detects it.

Synopsis of ##MOCK-FUNCTION-SPEC##:

    (FUNCTION ARGUMENT ...)
    MOCK-FUNCTION-SPEC is almost same as normal function call.
    If you should specify `*' as ARGUMENT, any value is accepted.
    Otherwise, body should call FUNCTION with specified ARGUMENTs.

Example:

    (expect (mock (foo * 3) => nil)
      (foo 9 3))

* Any other ##SEXP##

Body should equal (eval SEXP).

=== Batch Mode ===

If you prefer batch mode, use this script (##el-expectations##):

  #!/bin/sh
  EMACS=emacs
  OPTIONS="-L . -L $HOME/emacs/lisp"
  OUTPUT=/tmp/.el-expectations
  $EMACS -q --no-site-file --batch $OPTIONS -l el-expectations -f batch-expectations $OUTPUT "$@"
  ret=$?
  cat $OUTPUT
  rm $OUTPUT
  exit $ret

=== Batch Mode Usage ===

  $ el-expectations el-expectations-failure-sample.el

== Example code ==

* Success example Lisp:el-expectations-success-sample.el
* Failure example Lisp:el-expectations-failure-sample.el

  (expectations
    (desc "simple expectation")
    (expect 3
      (+ 1 2))
    (expect "hoge"
      (concat "ho" "ge"))
    (expect "fuga"
      (set-buffer (get-buffer-create "tmp"))
      (erase-buffer)
      (insert "fuga")
      (buffer-string))

    (desc "extended expectation")
    (expect (buffer "*scratch*")
      (with-current-buffer "*scratch*"
        (current-buffer)))
    (expect (regexp "o")
      "hoge")
    (expect (type integer)
      3)

    (desc "error expectation")
    (expect (error arith-error)
      (/ 1 0))
    (expect (error)
      (/ 1 0)))

== Translation from Ruby's expectations ==

  (expectations
    ;; State based expectation where a value equals another value
    (expect 2
      (+ 1 1))

    ;; State based expectation where an error is expected
    ;; Simply expect error symbol of the intended exception
    (expect (error void-function '(no-function))
      (no-function))

    ;; Behavior based test using a traditional mock
    ;; TODO implement times.
    (expect (mock (dial * "2125551212") => nil)
      (dial 'phone "2125551212")
      (dial 'phone "2125551212"))

    ;; Behavior based test on a concrete mock
    (expect (mock (deal *))
      (deal 'object))

    ;; State based test utilizing a stub
    (expect 2
      (stub two => 2)
      (two))

    ;; State based test utilizing a concrete mock
    (expect 2
      (mock (bar *) => 2)
      (bar 'object))

    ;; Behavior based test utilizing a stub and a concrete mock
    (expect 1
      (mock (give-me-three 3) => 1)
      (stub three => 3)
      (give-me-three (three)))

    ;; State based test matching a Regexp
    (expect (regexp "string")
      "a string")

    ;; State based test to determine if the object is an instance of sequence
    (expect (type sequence)
      ())

    ;; State based test to determine if the object is an instance of the class
    (expect (type string)
      "a string"))

----
CategoryCode UnitTesting
