Search code examples
clojureclojure-testing

Assertion error in Clojure's deftest macro if comparing lists


My question ist about Clojures deftest macro or more generally about how to compare lists created by functions. But i´m new to Clojure and can´t recognize the specific cause. Maybe anyone else have an idea?

First the reported message:

FAIL in (to-symbol-list-test) (util_test.clj:105)
expected: (= (quote (a (not b) c)) (to-symbol-list ["a" "(not b)" "c"]))
actual: (not (= (a (not b) c) (a (not b) c)))

But it is obviously that (= (a (not b) c) (a (not b) c)) quoted should be true instead.

Second the specific test code:

(deftest to-symbol-list-test 
(is (= '(a (not b) c) (to-symbol-list ["a" "(not b)" "c"]))))

Third the definition of to-symbol-list:

(defn to-symbol-list [term]
  "Converts a vector based term into a list based term
  by converting its elements into symbols recursivly"
  (postwalk
    #(if (string? %)
       (symbol %)
       (reverse (into '() %)))
    term))

The function even should convert nested vectors. It´s an example, other functions behave in the same manner. I guessed it could cause by different types. For example list vs lazy-seq and i compare the lazy function instead of the data, but the types seems to be correct. In REPL i get:

(type (to-symbol-list ["a" "(not b)" "c"]))
=> clojure.lang.PersistentList

Solution

  • to-symbol-list returns a list of 3 symbols, and doesn't recursively deal with the nested data structure. Unfortunately the second symbol prints the same as the correctly parsed data structure you're expecting. I think in this case you'd be better off using clojure.edn/read-string (docs here) which will parse your data structure as I think you're expecting.

    (defn to-symbol-list [list-of-strings]
      (map edn/read-string list-of-strings))
    
    (to-symbol-list ["a" "(not b)" "c"])
    

    Also, as a hint to help diagnose this sort of thing in the future, you can pass an extra argument to clojure.test/is which will print out in the event of a failure. This can be the result of a function call, like:

    (ns to-symbols-test
      (:require [clojure.edn :as edn]
                [clojure.test :refer [deftest is are testing] :as t]
                [clojure.data :as data]
                [clojure.pprint :as pp]))
    
    (defn to-symbol-list [l]
      (map edn/read-string l))
    
    (defn diff [a b]
      (with-out-str (pp/pprint (take 2 (data/diff a b)))))
    
    (deftest test-to-symbol-list
      (testing "to-symbol-list should convert recursively"
        (let [expected '(a (not b) c)
              result   (to-symbol-list ["a" "(not b)" "c"])]
          (is (= expected result (diff expected result))))))