Browse files

** Tabular facts once again print their substitutions on failure

  • Loading branch information...
1 parent 6df4535 commit 80d0c8f879fb590910541d3c0e036d3538125f54 @marick committed Mar 20, 2013
View
23 src/midje/parsing/0_to_fact_form/tabular.clj
@@ -1,16 +1,18 @@
(ns ^{:doc "A way to create multiple facts with the same template, but different data points."}
midje.parsing.0-to-fact-form.tabular
- (:use [midje.parsing.util.zip]
+ (:use midje.clojure.core
+ midje.parsing.util.zip
[midje.parsing.util.file-position :only [form-with-copied-line-numbers]]
[midje.emission.deprecation :only [deprecate]]
[midje.parsing.util.zip :only [skip-to-rightmost-leaf]]
[midje.parsing.1-to-explicit-form.facts :only [working-on-nested-facts unparse-edited-fact]]
[midje.data.metaconstant :only [metaconstant-symbol?]]
[utilize.map :only [ordered-zipmap]])
(:require [clojure.string :as str]
+ [clojure.zip :as zip]
[midje.util.unify :as unify]
[midje.parsing.util.overrides :as override]
- [midje.parsing.util.recognizing :as recognize]
+ [midje.parsing.lexical-maps :as maps]
[midje.parsing.1-to-explicit-form.metadata :as metadata]
[midje.parsing.util.error-handling :as error]))
@@ -48,7 +50,7 @@
;; (creation-time-check
;; (letfn [...] <letfn-body>
;;
- ;; It is the <letfn-body> that must be searched for expect forms,
+ ;; It is the <letfn-body> that must be searched for the construction of checkable maps,
;; which then have annotations added to them.
(letfn [(headed-by? [form string]
(and (sequential? form)
@@ -68,14 +70,17 @@
(second possible-letfn))]
(-> definite-letfn second first rest second)))
- (translate-letfn-body [expect-containing-form]
- (translate-zipper expect-containing-form
- recognize/expect? one-binding-note))
+ (translate-letfn-body [checkable-containing-form]
+ ;; TODO: Nested facts lead to nested letfns, and that stops processing,
+ ;; so nested facts don't get binding annotations.
+ (translate-zipper checkable-containing-form
+ (comp maps/checkable-map? zip/node)
+ one-binding-note))
(one-binding-note [loc]
- (skip-to-rightmost-leaf
- (override/above-arrow-sequence__add-key-value__at-arrow
- :binding-note (format-binding-map ordered-binding-map) loc)))]
+ (zip/replace loc
+ (assoc (clojure.zip/node loc)
+ :binding-note (format-binding-map ordered-binding-map))))]
(if (acceptable-body?)
(let [letfn-body (target-body)]
View
8 src/midje/parsing/lexical_maps.clj
@@ -33,8 +33,11 @@
(midje.parsing.util.file-position/line-number-known 2)))
) ; ---------------------------------------------------------------
-;;; Example maps
+;;; Checkable maps
+(defn checkable-map? [value]
+ (and (map? value)
+ (::a-midje-checkable-map? value)))
(defn example
[call-form arrow expected-result overrides]
@@ -43,7 +46,8 @@
override-map `(hash-map-duplicates-ok ~@overrides)
line (:line (meta call-form))
result `(merge
- {:function-under-test (fn [] ~call-form)
+ {::a-midje-checkable-map? true
+ :function-under-test (fn [] ~call-form)
:expected-result ~expected-result
:check-expectation ~(recognize/expect-match-or-mismatch arrow)
:expected-result-form '~expected-result ;; This is also part of the source details.
View
94 test/as_documentation/tabular_facts.clj
@@ -0,0 +1,94 @@
+(ns as-documentation.tabular-facts
+ (:use midje.repl
+ midje.test-util))
+
+;;; When you have many similar tests, you can use *tabular facts* to
+;;; clarify what's special about each test. Here, for example, is a tabular
+;;; fact about addition:
+
+(tabular "tabular facts can take a doc string"
+ (fact (+ ?a ?b) => ?result )
+ ?a ?b ?result
+ 1 2 3
+ 1 0 1)
+
+;;; You can use the repl tools to work with tabular facts just as you
+;;; can any other top-level fact:
+
+(fact
+ (map fact-description (fetch-facts "tabular facts can take a doc string"))
+ => ["tabular facts can take a doc string"])
+
+;;; On failure, the line number points to the fact, but the message
+;;; is annotated with information about the substitutions.
+
+(capturing-failure-output
+ (tabular
+ (fact (+ ?a ?b) => ?result )
+ ?a ?b ?result
+ 1 2 3333
+ 1 0 11)
+ (fact
+ @fact-output => (contains "With table substitutions: [?a 1")
+ @fact-output => (contains " ?b 2")
+ @fact-output => (contains " ?result 3333]")
+ @fact-output => (contains "Expected: 3333")
+ @fact-output => (contains " Actual: 3")
+ @fact-output => (contains "With table substitutions: [?a 1")
+ @fact-output => (contains " ?b 0")
+ @fact-output => (contains " ?result 11]")
+ @fact-output => (contains "Expected: 11")
+ @fact-output => (contains " Actual: 1")))
+
+
+;;; More about doc Strings and Metadata
+
+;;; If you prefer, you can put the doc string on the enclosed fact rather than the
+;;; tabular fact:
+
+(tabular
+ (fact "Put the doc string wherever you prefer"
+ (+ ?a ?b) => ?result )
+ ?a ?b ?result
+ 1 2 3
+ 1 0 1)
+
+;;; You can add other metadata to tabular facts, and select ones to check with it:
+
+(tabular
+ (fact :a-tabular-fact
+ (+ ?a ?b) => ?result )
+ ?a ?b ?result
+ 1 2 3
+ 1 0 1)
+
+(fact
+ (let [marked-facts (fetch-facts :a-tabular-fact)]
+ (count marked-facts) => 1
+ (:a-tabular-fact (meta (first marked-facts))) => true))
+
+
+;;; Miscellany
+
+(capturing-failure-output
+ (fact "you can nest tabular facts within other facts"
+ (+ 1 1) => 2
+ (tabular
+ (fact (+ ?a ?b) => 1)
+ ?a ?b
+ 1 0
+ 0 1
+ 1 1))
+ (fact
+ @fact-output => (contains "With table substitutions: [?a 1")
+ @fact-output => (contains " ?b 1]")
+ @fact-output => (contains "Expected: 1")
+ @fact-output => (contains " Actual: 2")))
+
+;; It's natural to think of substituting values and expressions,
+;; but you can substitute anything, such as Midje arrows.
+(tabular
+ (fact (+ ?a ?b) ?arrow ?expected)
+ ?a ?b ?arrow ?expected
+ 1 1 => 2
+ 1 2 =not=> 3000)
View
99 test/midje/parsing/0_to_fact_form/t_tabular.clj
@@ -5,27 +5,15 @@
[ordered.map :only (ordered-map)]
midje.util)
(:require [midje.util.pile :as pile]
- [midje.parsing.1-to-explicit-form.facts :as facts]
+ [midje.parsing.lexical-maps :as maps]
+ [midje.parsing.1-to-explicit-form.facts :as parse-facts]
[midje.data.fact :as fact-data]
[midje.data.compendium :as compendium]
[midje.config :as config]))
(expose-testables midje.parsing.0-to-fact-form.tabular)
-;; Core midje.sweet API
-
-(tabular
- (fact (+ ?a ?b) => ?result )
- ?a ?b ?result
- 1 2 3)
-
-(tabular
- (fact "some information about that"
- (+ ?a ?b) => ?result)
- ?a ?b ?result
- 1 2 3)
-
(tabular "no longer need to prefix table variables with '?'"
(fact (+ a b) => result )
@@ -197,56 +185,39 @@
(table-binding-maps ['?a '?b '?result] [1 2 3])
=> [ (ordered-map '?a 1, '?b 2, '?result 3) ])
-(defn as-received-by-add-binding-note [body]
- (facts/wrap-with-creation-time-code
- (facts/wrap-with-check-time-code
- body
- {:some-fact-metadata true}
- 'symbol-to-name-function-with)))
-
-
-(tabular (fact ?comment
- (let [line-no-free-original ?original
- line-no-free-expected ?expected]
- (add-binding-note line-no-free-original (ordered-map '?a 'a))
- => line-no-free-expected))
-
- ?comment ?original ?expected
-
- "binding notes can be inserted"
- (as-received-by-add-binding-note
- '(do (midje.semi-sweet/expect (a) => b)
- (do (midje.semi-sweet/expect (inc a) => M))))
-
- (as-received-by-add-binding-note
- '(do (midje.semi-sweet/expect (a) => b :binding-note "[?a a]")
- (do (midje.semi-sweet/expect (inc a) => M :binding-note "[?a a]"))))
-
- "fakes do not get insertions"
- (as-received-by-add-binding-note
- '(do (midje.semi-sweet/expect (a) => b
- (midje.semi-sweet/fake (x) => 3))))
-
- (as-received-by-add-binding-note
- '(do (midje.semi-sweet/expect (a) => b :binding-note "[?a a]"
- (midje.semi-sweet/fake (x) => 3))))
-
- "other annotations are preserved"
- (as-received-by-add-binding-note
- '(do (midje.semi-sweet/expect (a) => b :line 33)))
-
- (as-received-by-add-binding-note
- '(do (midje.semi-sweet/expect (a) => b :binding-note "[?a a]" :line 33))))
-
-(fact "binding notes are in the order of the original row - this order is maintained within the ordered-binding-map"
- (let [actual (add-binding-note
- (as-received-by-add-binding-note
- '(do (expect 1 => 2)))
- (ordered-map '?a 1, '?b 2, '?delta "0", '?result 3))
-
- expected (as-received-by-add-binding-note
- '(do (expect 1 => 2 :binding-note "[?a 1\n ?b 2\n ?delta \"0\"\n ?result 3]")))]
- actual => expected))
+
+(defn filter-checkable-maps [form]
+ (filter maps/checkable-map? (flatten form)))
+
+(defn expand-and-add-binding-note
+ ([form binding-map]
+ (add-binding-note (parse-facts/midjcoexpand form) binding-map))
+ ([form]
+ (expand-and-add-binding-note form (ordered-map '?a 'a))))
+
+(def binding-notes-from (comp filter-checkable-maps expand-and-add-binding-note))
+
+(fact "binding notes"
+ (fact "can be inserted"
+ (binding-notes-from '(fact 1 => 1)) => (just (contains {:binding-note "[?a a]"})))
+
+ (fact "are inserted into every checkable"
+ (binding-notes-from '(fact 1 => 1
+ 2 => 2)) => (just (contains {:binding-note "[?a a]"})
+ (contains {:binding-note "[?a a]"})))
+
+ (future-fact "are added to nested facts"
+ (binding-notes-from '(fact 1 => 1 (fact 2 => 2))) => (just (contains {:binding-note "[?a a]"})
+ (contains {:binding-note "[?a a]"})))
+
+ (fact "are not added to prerequisites"
+ (binding-notes-from '(fact (f 1) => 1 (provided (g 1) => 2))) => (just (contains {:binding-note "[?a a]"})))
+
+ (fact "are added in the left-to-right order of the original table"
+ (let [result (binding-notes-from '(fact (+ 1 2) => 3) (ordered-map :c 1, :b 2, :a 3))]
+ (count result) => 1
+ (:binding-note (first result)) => #"(?s):c 1.*:b 2.*:a 3")))
+
;; tabular doc-string prints in report

0 comments on commit 80d0c8f

Please sign in to comment.