test-check

Kayla 2018-10-12T18:18:46.000100Z

In this snippet, frequency evals render too early. I think I need mutually recursive generators, and don’t want to lose the ability to shrink. If it actually ran it wouldn’t go on forever, but instead it explodes the stack. Anybody have any ideas?

(letfn [(render []
          (tcgen/frequency [[1 (gen/tuple (render))]
                            [15 (gen/return [])]]))]
  (gen/generate (render)))

2018-10-12T19:04:49.000100Z

the problem isn't frequency

2018-10-12T19:05:20.000100Z

frequency is a function, so all the arguments are evaluated before the function is called

taylor 2018-10-12T19:06:06.000100Z

what kinda output are you hoping to get out of that. nested, empty vectors? @sean

2018-10-12T19:06:08.000100Z

you may want to checkout gen/recursive-gen

Kayla 2018-10-12T20:00:11.000100Z

@taylor I distilled my problem down to this. I am generating a tree where any given node’s children’s generator is dependent on the node that produces it. Also, some nodes must have children, and some must not. Also some of the data in the child needs to be consistent with what was generated the parent. Then the thing that breaks it is some nodes can have children of the same type, which use the same generator. I am trying to make a generator for the whole tree. So a generator for a node might produce something like: {:id 1 :parent-id 0 :type :foo} Nodes of type :foo can have children of types :bar and :foo. The generators for the potential children of this node would produce something that looks like: {:id 2 :parent-id 1 :type :foo} or {:id 2 :parent-id 1 :type :bar :another-quality "junk"}

Kayla 2018-10-12T20:01:04.000100Z

:bar nodes have no children.

2018-10-12T20:16:54.000100Z

You could use recursive-gen to get the structure, then fmap the whole thing to fix up consistency issues

taylor 2018-10-12T20:18:09.000100Z

are the child nodes associated inside the parent nodes? or are they all in one big sequence and only correlated by :id and :parent-id?

Kayla 2018-10-12T20:18:29.000100Z

One big sequence

2018-10-12T20:19:43.000100Z

(defn type-foo [g]
  (gen/let [children (gen/vector g)]
    (gen/return
     {:id 1 :parent-id 0 :type :foo :children children})))

(defn type-bar [g]
  (gen/return
   {:id 2 :parent-id 1 :type :bar :another-quality "junk"}))


(defn foo-bar-tree [_]
  (gen/recursive
   (fn [g]
     (gen/one-of (type-foo g)
                 (type-bar g)))
   (type-bar nil)))

2018-10-12T20:27:31.000100Z

I will say often times it is easier to generate instructions to build a complex datastructure then it is to generate the datastructure. so for example if you wanted a tree of files in directories, it might be easier to generate a list of create file, move file, create directory, delete, etc, then just interpret that list to get some tree, instead of generating the tree

taylor 2018-10-12T20:55:07.000100Z

@sean even though you want a flat sequence of maps, you could maybe do something like this with recursive-gen:

(gen/sample
  (gen/recursive-gen
    (fn [g]
      (gen/let [{:keys [id type] :as m} (s/gen ::my-map)
                children (gen/vector g)]
        (if (= :bar type)
          m
          (update m :children concat (map #(assoc % :parent-id id) children)))))
    (s/gen ::my-map))
  100)
then you could fmap over that generator to flatten and fix-up the ID relations:
(gen/sample
  (gen/fmap
    (fn [m]
      (map #(dissoc % :children)
           (tree-seq #(seq (:children %)) :children m)))
    (gen/recursive-gen
      (fn [g]
        (gen/let [m (s/gen ::my-map)
                  children (gen/vector g)]
          (if (= :bar (:type m))
            m
            (update m :children concat (map #(assoc % :parent-id (:id m)) children)))))
      (s/gen ::my-map))))
although I think this still leaves you with a problem of non-unique IDs

taylor 2018-10-12T20:56:21.000100Z

oh and I used some specs for the map generator:

(s/def ::id pos-int?)
(s/def ::type #{:foo :bar})
(s/def ::parent-id ::id)
(s/def ::my-map (s/keys :req-un [::id ::type ::parent-id]))

Kayla 2018-10-12T21:22:35.000100Z

Thanks Everybody for all the help. I’m signing off for the weekend.