 (defn unfold-fakes [form]
   (with-fresh-generated-metaconstant-names
     (translate-zipper form
-        expect?
-        unfold-expect-form__then__stay_put)))
-
+      expect?
+      unfold-expect-form__then__stay_put)))
+

;; mapping. These substitutions are used both to "flatten" a fake form and also
;; to generate new fakes.

(def special-forms '[quote fn let new])

(defn- constructor? [symbol]
  (.endsWith (name symbol) "."))

(defn- mockable-function-symbol? [symbol]
  (not (or (some #{symbol} special-forms)
           (some #{symbol} checker-makers)
           (constructor? symbol)
           (checker? (resolve symbol)))))



(defn mockable-funcall? [thing]
  (and (list? thing)
       (mockable-function-symbol? (first thing))))


(defn folded-fake? [form]
  (and (sequential? form)
       (= 'midje.semi-sweet/fake (first form))
       ;; We now know this: (fake (f ...arg... ...arg...) ...)
       (some mockable-funcall? (fake-form-funcall-arglist form))))

(defn augment-substitutions [substitutions fake-form]
  (let [needed-keys (filter mockable-funcall?
                            (fake-form-funcall-arglist fake-form))]
    (reduce (fn [substitutions needed-key]
              ;; Note: because I like for a function's metaconstants to be
              ;; easily mappable to the original fake, I don't make one

(defn merge-metaconstant-bindings [bindings]
  (apply merge-with (fn [v1 v2]
                      (Metaconstant. (.name v1) (merge (.storage v1) (.storage v2))))
    bindings))

(defn- binding-map-with-data-fakes [data-fakes]
  (merge-metaconstant-bindings (data-fakes-to-metaconstant-bindings data-fakes)))

(defn binding-map [fakes]
  (let [[data-fakes function-fakes] (separate :data-fake fakes)]
    (merge (binding-map-with-function-fakes function-fakes)
      (binding-map-with-data-fakes data-fakes))))

(defmacro with-installed-fakes [fakes & forms]
  `(with-altered-roots (binding-map ~fakes) ~@forms))

;;; Checking

(defn fake-count [fake] (deref (:count-atom fake)))

(defmulti call-count-incorrect? :type )

(defmethod call-count-incorrect? :fake [fake]
  (let [method (or (:times fake) :default )
        count (fake-count fake)]
    (cond (= method :defaul t )
      (zero? count)

      (number? method)
      (not= method count)

      (coll? method)
      (not (some #{count} method))

      (fn? method)
      (not (method count)))))

(defmethod call-count-incorrect? :not-called [fake]
  (not (zero? (fake-count fake))))

(defn check-call-counts [fakes]
  (doseq [fake fakes]
    (when (call-count-incorrect? fake)
      (report {:type :mock-incorrect-call-count
               :actual-count @(fake :count-atom )
               :expected-call (fake :call-text-for-failures )
               :position (:position fake)
               :expected (fake :call-text-for-failures )}))))



;; Folded prerequisites

;; Note that folded prerequisites are in semi-sweet-style. (That is, they can only
