Assertion error in Clojure's deftest macro if comparing lists

288 Views Asked by At

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
2

There are 2 best solutions below

1
On BEST ANSWER

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))))))
0
On

It seems that to-symbol-list turns "(not b)" string a symbol, but not a nested list. To fix that, you'll need to refactor that function to take parens into account. Say, if it sees ( as the first symbol of a string, it calls itself recursively appending the result into some kind of accumulator (SICP is full of such exercises by the way).