Codebase list test-check-clojure / fda2383
Fix issue w/ distinct collection generators If you gave a distinct collection generator a generator that could only generate a few things, but didn't give it any particular minimum size, it could still blow up because it internally picks a particular size before trying to generate the collection. In concrete terms, (gen/sample (gen/set gen/boolean)) was highly likely to fail. Added a distinction between the target size and the real minimum size, so we can give up successfully if we can't generate more things but are still above the real minimum. Gary Fredericks 8 years ago
2 changed file(s) with 22 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
537537
538538 (defn ^:private coll-distinct-by*
539539 "Returns a rose tree."
540 [empty-coll key-fn shuffle-fn gen rng size num-elements max-tries]
540 [empty-coll key-fn shuffle-fn gen rng size num-elements min-elements max-tries]
541541 {:pre [gen (:gen gen)]}
542542 (loop [rose-trees (transient [])
543543 s (transient #{})
544544 rng rng
545545 size size
546546 tries 0]
547 (cond (= max-tries tries)
548 (throw (ex-info "Couldn't generate enough distinct elements!"
549 {:gen gen, :max-tries max-tries}))
550
551 (= (count rose-trees) num-elements)
547 (cond (and (= max-tries tries)
548 (< (count rose-trees) min-elements))
549 (throw (ex-info "Couldn't generate enough distinct elements!"))
550
551
552 (or (= max-tries tries)
553 (= (count rose-trees) num-elements))
552554 (->> (persistent! rose-trees)
553555 ;; we shuffle the rose trees so that we aren't biased
554556 ;; toward generating "smaller" elements earlier in the
604606 {:keys [num-elements min-elements max-elements max-tries] :or {max-tries 10}}]
605607 (let [shuffle-fn (if ordered?
606608 the-shuffle-fn
607 (fn [_rng coll] coll))]
609 (fn [_rng coll] coll))
610 hard-min-elements (or num-elements min-elements 1)]
608611 (if num-elements
609612 (let [size-pred #(= num-elements (count %))]
610613 (assert (and (nil? min-elements) (nil? max-elements)))
617620 ;; step?
618621 (every-pred size-pred #(distinct-by? key-fn %))
619622 size-pred)
620 (coll-distinct-by* empty-coll key-fn shuffle-fn gen
621 rng gen-size num-elements max-tries)))))
623 (coll-distinct-by* empty-coll key-fn shuffle-fn gen rng gen-size
624 num-elements hard-min-elements max-tries)))))
622625 (let [min-elements (or min-elements 0)
623626 size-pred (if max-elements
624627 #(<= min-elements (count %) max-elements)
636639 ;; same comment as above
637640 (every-pred size-pred #(distinct-by? key-fn %))
638641 size-pred)
639 (coll-distinct-by* empty-coll key-fn shuffle-fn gen
640 rng gen-size num-elements max-tries)))))))))))
642 (coll-distinct-by* empty-coll key-fn shuffle-fn gen rng gen-size
643 num-elements hard-min-elements max-tries)))))))))))
641644
642645
643646 ;; I tried to reduce the duplication in these docstrings with a macro,
416416 (map #(rose/root (gen/call-gen (g gen/nat {:num-elements 3, :max-tries 100}) % 0)))
417417 (set))
418418 [[0 1 2] [0 2 1] [1 0 2] [1 2 0] [2 0 1] [2 1 0]]))))
419
420 (defspec distinct-collections-with-few-possible-values 20
421 (prop/for-all [boolean-sets (gen/vector (gen/resize 5 (gen/set gen/boolean)) 100)]
422 (= 4 (count (distinct boolean-sets)))))
423
424 (deftest can't-generate-set-of-five-booleans
425 (is (thrown? Exception
426 (gen/generate (gen/set gen/boolean {:num-elements 5})))))
419427
420428 ;; Generating proper matrices
421429 ;; ---------------------------------------------------------------------------