marick / Midje

Midje provides a migration path from clojure.test to a more flexible, readable, abstract, and gracious style of testing
MIT License
1.69k stars 129 forks source link

Don't allow prerequisite values for inlined functions #60

Closed marick closed 13 years ago

marick commented 13 years ago

It doesn't work to override functions like #'+ because they're inlined. Processing of provided should consider an attempt to do so a user error.

(defn doubler [n] (+ n n))
(fact (doubler 3) => 0 (provided (+ 3 3) => 0))   ;;; Should be rejected

In Clojure 1.3 (at least), the var for a function that will be inlined has an :inline key in its metadata.

AlexBaranosky commented 13 years ago

Would this be adding to (defmethod validate "fake" ...) to have it check that the function's metadata doesn't identify it is inlinable?

AlexBaranosky commented 13 years ago

So something like this?:

;; tst
(defn doubler [n] (+ n n))

(after-silently
  (expect (doubler 3) => 0
    (fake (+ 3 3) => 0))
  (expect @reported => (user-error-with-notes #"cannot fake the function")))

;; src
(defn- compiler-will-inline-fn? [[fn & args :as funcall]]
  (contains? (meta (var fn)) :inline))

(defmethod validate "fake" [[_fake_ & fake-form :as form]]
  (let [funcall (first fake-form)]
    (cond (not (list? funcall))
          (user-error-report-form
            form
            "The left-hand-side of a prerequisite must look like a function call."
            (cl-format nil "`~S` doesn't." funcall))

          (compiler-will-inline-fn? funcall)
          (user-error-report-form
            form
            (cl-format nil "You cannot fake the function `~S` because it is inlined by the Clojure compiler." (first funcall)))

          :else
          fake-form)))
marick commented 13 years ago

That seems a reasonable way to do it. Are you going to? Otherwise I will.

(I wouldn't use "fake" in the error message, since that's not a word midje.sweet exposes. Perhaps "you cannot override a call to + because the Clojure compiler inlines it.")

On Nov 5, 2011, at 8:08 PM, AlexBaranosky wrote:

So something like this?:

;; tst
(defn doubler [n] (+ n n))

(after-silently
 (expect (doubler 3) => 0
   (fake (+ 3 3) => 0))
 (expect @reported => (user-error-with-notes #"cannot fake the function")))

;; src
(defn- compiler-will-inline-fn? [[fn & args :as funcall]]
 (contains? (meta (var fn)) :inline))

(defmethod validate "fake" [[_fake_ & fake-form :as form]]
 (let [funcall (first fake-form)]
   (cond (not (list? funcall))
         (user-error-report-form
           form
           "The left-hand-side of a prerequisite must look like a function call."
           (cl-format nil "`~S` doesn't." funcall))

         (compiler-will-inline-fn? funcall)
         (user-error-report-form
           form
           (cl-format nil "You cannot fake the function `~S` because it is inlined by the Clojure compiler." (first funcall)))

         :else
         fake-form)))

Reply to this email directly or view it on GitHub: https://github.com/marick/Midje/issues/60#issuecomment-2643352


Brian Marick, Artisanal Labrador Now working at http://path11.com Contract programming in Ruby and Clojure Occasional consulting on Agile

AlexBaranosky commented 13 years ago

I tried it out and wasn't quite sure if I had it right. You can finish it off if you'd like.

marick commented 13 years ago

OK, I'll take a look at it.

On Nov 6, 2011, at 6:29 PM, AlexBaranosky wrote:

I tried it out and wasn't quite sure if I had it right. You can finish it off if you'd like.


Reply to this email directly or view it on GitHub: https://github.com/marick/Midje/issues/60#issuecomment-2648821


Brian Marick, Artisanal Labrador Now working at http://path11.com Contract programming in Ruby and Clojure Occasional consulting on Agile

marick commented 13 years ago

In 1.3-alpha5

AlexBaranosky commented 13 years ago

Great! Looks like resolve was the piece I was missing.