Skip to content

Syntax and a little semantics

Phillip Mates edited this page Jun 7, 2017 · 7 revisions

Facts

A fact expression starts with one of fact, facts, future-fact, or future-facts.

It is followed by zero or more instances of <metadata>.

Facts can contain arbitrary Clojure code, including facts and <tabular facts>. That code can contain <prediction> and <provided> forms.

Example

(facts :integration
  (let [a 3]
    (fact (* a 2) => (+ a a))
    (let [b (inc a)]
      (fact 
        (g a b) => 33
        (provided (f a) => 2))))
  (println "Fact result " (fact (+ 1 1) => 2)))

Midje "compiles" facts into a value object that can be checked like this:

user=> (check-one-fact my-fact)

Tabular facts

A tabular fact has this form: (tabular <metadata> * <fact> <heading> <row>+ ).

If the tabular form is not followed by metadata, it adopts the metadata from the enclosed fact. The result of both the tabular and enclosed fact having metadata is undefined.

The heading is a series of symbols beginning with ?.

The meaning of a tabular fact with n rows is that of one outer-level fact with n nested facts. Each nested fact is generated by substituting a row's tokens for the corresponding symbols in the original fact. Consider the following:

(tabular 
  (fact "doc string" (+ ?a ?b) => ?c)
  ?a ?b ?c
  1  2  3
  8  9  17)

That is equivalent to the following nested facts:

(fact "doc string"
  (fact (+ 1 2) => 3)
  (fact (+ 8 9) => 17))

It is not an error if a given heading symbol doesn't appear in the fact, nor if the fact contains a ? symbol not named in the heading row. As a consequence, you can do clearly insane things like this:

(tabular "Crazy nesting"
  (fact
    (tabular (fact (+ ?a ?b) => ?c)
      ?a ?b
      1  2
      2  1))
  ?c
  3)

Metadata and fact groups

... have their own page.

Checkables

A checkable is <clojure form> <arrow> <clojure form> *<override>**.

Arrows can take several forms, such as => and =not=>. See checkable arrows for the list.

An override is a key/value pair. Each checkable is converted into a map. An override overrides one of the default values for a key in the map. As there are no overrides that seem useful to users (as opposed to the Midje code itself), the keys aren't defined in this documentation.

Provided (prerequisites for a single checkable)

A provided form is (provided <prediction>* ).

The body of a provided form contains checkable forms (and only checkable forms). The interpretation of those forms is different, though. Rather than a checkable claim that some concrete calculation will produce a result matching a predefined right-hand side, a provided form claims that some function call matching the left-hand side will be made. (And, when that happens, the right-hand side provides a return value for the call.)

A provided form must immediately follow a checkable. The following facts, for example, are incorrect:

(fact 
  (do (f 1 1) => 2)
  (provided
     (g 1) => 2))

(fact 
  (f 1 1) => 2
  (let []
    (provided
       (g 1) => 2)))

Within a provided form, one override is useful: :times <clojure form>. The value of the clojure form describes how often the function will be called with the described arguments. (The default is one or more times.) Here's an example:

(provided
  (g 1) => 3 :times 2
  (g 2) => 88 :times (range 2 33))

The different arrows used within within provided are described separately.

Metaconstants

Metaconstants are one of: <period>+ <valid-symbol> <period>+ | <dash>+ <valid-symbol> <dash>+.

<period> and <dash> mean the literal characters: . and -.

Two metaconstants with different arrangements of periods are the identical value. That is, all three of these are identical? to each other:

   .meta....
   ..meta..
   ...meta.

That's because it's annoying to have a typo produce two different metaconstants when you only meant to make one.

The same rule applies to dashes. However, a period-laden metaconstant is not identical to a dash-laden one.

Clone this wiki locally