<commit_before>;; -*- indent-tabs-mode: nil -*-

(ns midje.t-semi-sweet
  (:use [clojure.test]  ;; This is used to check production mode with deftest.
        [midje.sweet]
        [midje.util form-utils]
        [midje.test-util]
        midje.util)
  (:require [clojure.zip :as zip]))
(expose-testables midje.semi-sweet)
 
(unfinished faked-function mocked-function other-function)

(defchecker odd-checker
  [actual]
  (odd? actual))

(facts "about arrows"
  (let [result (map check-for-arrow
                    '(=> midje.semi-sweet/=> midje.sweet/=>
                      =not=> midje.semi-sweet/=not=> midje.sweet/=not=>
                      =expands-to=> midje.semi-sweet/=expands-to=> midje.sweet/=expands-to=>))]
    (fact result => [:check-match :check-match :check-match
                     :check-negated-match :check-negated-match :check-negated-match
                     :check-match :check-match :check-match])))

(fact "separating overrides of an #expect from fakes"
  ;; The lets are because fact isn't smart enough not to add overrides to fake call otherwise.
  (let [actual (separate-by a-fake?  '( (fake (f 1) => 2) :key 'value))]
    actual => [  '[(fake (f 1) => 2)]
                 '[:key 'value] ])

  (let [actual (separate-by a-fake?  '( (not-called some-function) :key 'value))]
    actual => [ '[(not-called some-function)]
                '[:key 'value] ])

  ;; often passed a seq.
  (let [actual (separate-by a-fake?  (seq '( (fake (f 1) => 2) :key 'value)))]
    actual => [  '[(fake (f 1) => 2)]
                 '[:key 'value] ])

  (let [actual (separate-by a-fake?  '())]
    actual => (just empty? empty?))

  "data fakes too"
  (let [actual (separate-by a-fake?  '((data-fake ..m.. =contains=> {:a 1}) :key 'value))]
    actual => [  '[(data-fake ..m.. =contains=> {:a 1})]
                 '[:key 'value] ]))


(fact "calling a faked function raises an error"
  (faked-function) => (throws Error))

(facts "about the creation of fake maps"
  (let [some-variable 5
        previous-line-position (file-position 1)
        fake-0 (fake (faked-function) => 2)
        fake-1 (fake (faked-function some-variable) => (+ 2 some-variable))
        fake-2 (fake (faked-function 1 some-variable) => [1 some-variable])
        fake-streamed (fake (faked-function 0) =streams=> ['r1 'r2])]

    (fact "The basic parts"
      (:lhs fake-0) => #'midje.t-semi-sweet/faked-function
      (:call-text-for-failures fake-1) => "(faked-function some-variable)"
      (deref (:count-atom fake-0)) => 0)

    (fact "argument matching"
      (count (:arg-matchers fake-0)) => 0)

    (fact "Note that lexical scoping is obeyed"
      (count (:arg-matchers fake-1)) => 1
      (apply-pairwise (:arg-matchers fake-1) [5] [nil]) => [[true] [false]]
      (count (:arg-matchers fake-2)) => 2
      (apply-pairwise (:arg-matchers fake-2) [5 5] [1 1]) => [  [false true]
                                                                [true false] ])

    (fact "Result supplied"
      ((:result-supplier fake-0)) => 2
      ((:result-supplier fake-1)) => (+ 2 some-variable)
      ((:result-supplier fake-2)) => [1 some-variable])

    (fact "Streamed results"
      ((:result-supplier fake-streamed)) => 'r1
      ((:result-supplier fake-streamed)) => 'r2)))

(facts "key-value arguments can override fakes"
  (let [fake (fake (faked-function) => 2 :position 33)]
    (fake :position) => 33)

  (let [filepos 33
        fake (fake (faked-function) => 2 :position filepos)]
    (:position fake) => 33))

(facts "about not-called"
  (let [fake-0 (not-called faked-function)]

    (:lhs fake-0) => #'midje.t-semi-sweet/faked-function
    (:call-text-for-failures fake-0) => "faked-function was called."
    @(:count-atom fake-0) => 0
    (:arg-matchers fake-0) => nil?
    ((:result-supplier fake-0)) => nil?))

(defn function-under-test [& rest]
  (apply mocked-function rest))
(defn no-caller [])

(facts "about expect"
  (fact "success"
    (after-silently 
     (expect (+ 1 3) => 4)
     @reported => (one-of pass)))

  (fact "There is a =not=> arrow."
    (expect (+ 1 3) =not=> 5))

  (fact "actual doesn't match expected"
    (after-silently 
     (expect (+ 1 3) => nil)
     @reported => (just (contains {:type :mock-expected-result-failure
                                   :actual 4
                                   :expected nil}))))

  (fact "not-called in the first position"
    (after-silently 
     (expect (function-under-test) => 33
             (not-called no-caller)
             (fake (mocked-function) => 33))
     @reported => (one-of pass)))

  (fact "not-called in last position"
    (after-silently 
     (expect (function-under-test) => 33
             (fake (mocked-function) => 33)
             (not-called no-caller))
     @reported => (one-of pass)))

  (fact "mocked calls go fine, but function under test produces the wrong result"
    (after-silently
     (expect (function-under-test 33) => 12
             (fake (mocked-function 33) => (not 12) ))
     @reported => (just (contains {:actual false
                                   :expected 12}))))

  (fact "mock call supposed to be made, but wasn't (zero call count)"
    (after-silently
     (expect (no-caller) => "irrelevant"
             (fake (mocked-function) => 33))
     @reported => (just wrong-call-count bad-result)))

  (fact "mock call was not supposed to be made, but was (non-zero call count)"
    (after-silently
      (expect (function-under-test 33) => "irrelevant"
              (not-called mocked-function))
      @reported => (just wrong-call-count bad-result)))

  (fact "call not from inside function"
    (after-silently 
      (expect (+ (mocked-function 12) (other-function 12)) => 12
              (fake (mocked-function 12) => 11)
              (fake (other-function 12) => 1))
      @reported => (just pass)))

  (fact "call that matches none of the expected arguments"
    (after-silently
      (expect (+ (mocked-function 12) (mocked-function 33)) => "result irrelevant because of earlier failure"
              (fake (mocked-function 12) => "hi"))
     ;; At the moment, this does not produce a :mock-argument-match-failure. What it does
     ;; is call the "unfinished" function, which blows up, producing a `bad-result` (the exception
     ;; object). That's not horrible, especially at the semi-sweet level, but it does suggest
     ;; that the implementation of the sweet behavior (where an unfinished function produces
     ;; an argument-match failure) is fragile.
     @reported =future=> (just (contains {:type :mock-argument-match-failure :actual '(33)})<commit_msg>Better documentation of current behavior.<commit_after>;; -*- indent-tabs-mode: nil -*-

(ns midje.t-semi-sweet
  (:use [clojure.test]  ;; This is used to check production mode with deftest.
        [midje.sweet]
        [midje.util form-utils]
        [midje.test-util]
        midje.util)
  (:require [clojure.zip :as zip]))
(expose-testables midje.semi-sweet)
 
(unfinished faked-function mocked-function other-function)

(defchecker odd-checker
  [actual]
  (odd? actual))

(facts "about arrows"
  (let [result (map check-for-arrow
                    '(=> midje.semi-sweet/=> midje.sweet/=>
                      =not=> midje.semi-sweet/=not=> midje.sweet/=not=>
                      =expands-to=> midje.semi-sweet/=expands-to=> midje.sweet/=expands-to=>))]
    (fact result => [:check-match :check-match :check-match
                     :check-negated-match :check-negated-match :check-negated-match
                     :check-match :check-match :check-match])))

(fact "separating overrides of an #expect from fakes"
  ;; The lets are because fact isn't smart enough not to add overrides to fake call otherwise.
  (let [actual (separate-by a-fake?  '( (fake (f 1) => 2) :key 'value))]
    actual => [  '[(fake (f 1) => 2)]
                 '[:key 'value] ])

  (let [actual (separate-by a-fake?  '( (not-called some-function) :key 'value))]
    actual => [ '[(not-called some-function)]
                '[:key 'value] ])

  ;; often passed a seq.
  (let [actual (separate-by a-fake?  (seq '( (fake (f 1) => 2) :key 'value)))]
    actual => [  '[(fake (f 1) => 2)]
                 '[:key 'value] ])

  (let [actual (separate-by a-fake?  '())]
    actual => (just empty? empty?))

  "data fakes too"
  (let [actual (separate-by a-fake?  '((data-fake ..m.. =contains=> {:a 1}) :key 'value))]
    actual => [  '[(data-fake ..m.. =contains=> {:a 1})]
                 '[:key 'value] ]))


(fact "calling a faked function raises an error"
  (faked-function) => (throws Error))

(facts "about the creation of fake maps"
  (let [some-variable 5
        previous-line-position (file-position 1)
        fake-0 (fake (faked-function) => 2)
        fake-1 (fake (faked-function some-variable) => (+ 2 some-variable))
        fake-2 (fake (faked-function 1 some-variable) => [1 some-variable])
        fake-streamed (fake (faked-function 0) =streams=> ['r1 'r2])]

    (fact "The basic parts"
      (:lhs fake-0) => #'midje.t-semi-sweet/faked-function
      (:call-text-for-failures fake-1) => "(faked-function some-variable)"
      (deref (:count-atom fake-0)) => 0)

    (fact "argument matching"
      (count (:arg-matchers fake-0)) => 0)

    (fact "Note that lexical scoping is obeyed"
      (count (:arg-matchers fake-1)) => 1
      (apply-pairwise (:arg-matchers fake-1) [5] [nil]) => [[true] [false]]
      (count (:arg-matchers fake-2)) => 2
      (apply-pairwise (:arg-matchers fake-2) [5 5] [1 1]) => [  [false true]
                                                                [true false] ])

    (fact "Result supplied"
      ((:result-supplier fake-0)) => 2
      ((:result-supplier fake-1)) => (+ 2 some-variable)
      ((:result-supplier fake-2)) => [1 some-variable])

    (fact "Streamed results"
      ((:result-supplier fake-streamed)) => 'r1
      ((:result-supplier fake-streamed)) => 'r2)))

(facts "key-value arguments can override fakes"
  (let [fake (fake (faked-function) => 2 :position 33)]
    (fake :position) => 33)

  (let [filepos 33
        fake (fake (faked-function) => 2 :position filepos)]
    (:position fake) => 33))

(facts "about not-called"
  (let [fake-0 (not-called faked-function)]

    (:lhs fake-0) => #'midje.t-semi-sweet/faked-function
    (:call-text-for-failures fake-0) => "faked-function was called."
    @(:count-atom fake-0) => 0
    (:arg-matchers fake-0) => nil?
    ((:result-supplier fake-0)) => nil?))

(defn function-under-test [& rest]
  (apply mocked-function rest))
(defn no-caller [])

(facts "about expect"
  (fact "success"
    (after-silently 
     (expect (+ 1 3) => 4)
     @reported => (one-of pass)))

  (fact "There is a =not=> arrow."
    (expect (+ 1 3) =not=> 5))

  (fact "actual doesn't match expected"
    (after-silently 
     (expect (+ 1 3) => nil)
     @reported => (just (contains {:type :mock-expected-result-failure
                                   :actual 4
                                   :expected nil}))))

  (fact "not-called in the first position"
    (after-silently 
     (expect (function-under-test) => 33
             (not-called no-caller)
             (fake (mocked-function) => 33))
     @reported => (one-of pass)))

  (fact "not-called in last position"
    (after-silently 
     (expect (function-under-test) => 33
             (fake (mocked-function) => 33)
             (not-called no-caller))
     @reported => (one-of pass)))

  (fact "mocked calls go fine, but function under test produces the wrong result"
    (after-silently
     (expect (function-under-test 33) => 12
             (fake (mocked-function 33) => (not 12) ))
     @reported => (just (contains {:actual false
                                   :expected 12}))))

  (fact "mock call supposed to be made, but wasn't (zero call count)"
    (after-silently
     (expect (no-caller) => "irrelevant"
             (fake (mocked-function) => 33))
     @reported => (just wrong-call-count bad-result)))

  (fact "mock call was not supposed to be made, but was (non-zero call count)"
    (after-silently
      (expect (function-under-test 33) => "irrelevant"
              (not-called mocked-function))
      @reported => (just wrong-call-count bad-result)))

  (fact "call not from inside function"
    (after-silently 
      (expect (+ (mocked-function 12) (other-function 12)) => 12
              (fake (mocked-function 12) => 11)
              (fake (other-function 12) => 1))
      @reported => (just pass)))

  (fact "call that matches none of the expected arguments falls through to existing function"
    (after-silently
      (expect (+ (mocked-function 33)) => "result irrelevant because of failure"
              (fake (mocked-function 12) => "hi"))
     ;; At the moment, this does not produce a :mock-argument-match-failure. What it does
     ;; is call the "unfinished" function, which blows up, producing a `bad-result` (the exception
     ;; object). That's not horrible, especially at the semi-sweet level, but it does suggest
     ;; that the implementation of the sweet behavior (where an unfinished function produces
     ;; an argument-match failure) is fragile.
     @reported =future=> (just (contains {:type :mock-argument-match-failure :actual '(33)})
{'fraction_non_alphanumeric': 0.16176692296095282, 'fraction_numerical': 0.017337554650987488, 'mean_word_length': 2.452250845693469, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 153, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4910113', 'n_tokens_mistral': 4581, 'n_tokens_neox': 4203, 'n_words': 1249}