@ag @gfredericks your snippets both seem to work and produce similar results
refactoring @ag's version I came up with this (extracted amount
and gen-when
):
(defn gen-when
[x gen]
(gen/let
[x (gen/return x)]
(when x gen)))
(def gen-card
(gen/let
[debit? gen/boolean
amount gen/pos-int]
(gen/hash-map
:created-at gen/pos-int
:amount-debit (gen-when debit? amount)
:amount-credit (gen-when (not debit?) amount))))
Sample:
({:created-at 0, :amount-debit 0, :amount-credit nil}
{:created-at 0, :amount-debit nil, :amount-credit 0}
{:created-at 0, :amount-debit nil, :amount-credit 2}
{:created-at 2, :amount-debit 3, :amount-credit nil}
{:created-at 4, :amount-debit nil, :amount-credit 0})
I tend to eliminate bind
and fmap
because for me they're harder to read than let
.
I also like here how using gen/hash-map
allows to "inline" :created-at
generator.@metametadata: your gen-when
ignores its first argument
oh I take it back
okay so if you want to use let then I think (gen/let [debit? gen/boolean, amount gen/pos-int, created-at gen/pos-int] {:created-at created-at :amount-debit (when debit? amount) :amount-credit (when-not debit? amount)})
would be a bit more direct
you don't get to inline the created-at generator but on the other hand you don't have to create wrapper generators for credit/debit
yeah, agree. I guess the approach will depend on the number of additional fields in the card map
ie if there are a lot of fields similar to created-at
than "inlining" is more preferable
actually my thing worked, I didn't know it. My ui was broken, I couldn't see it :)
@metametadata: you can also do both -- make two maps and merge them together
has anyone written about reducing generation time for creating large tree structures in test.check ?
I added a new branch in my structure recently and it tripled the test run time
the branch is basically (gen/list-distinct-by :name (gen/hash-map :name gen/string-alphanumeric))
and gets fmapped over with some other stuff
the actual value of the string isn't important so much as that it's distinct
so I'm looking at strategies for getting rid of the distinct clause in the list generator and making the value distinct some other way
I'd also love to know if there's a way to peek a bit better at which parts of my tree are taking the most time generate
mattly: have you checked if the runtime increase roughly corresponds to an increase in the size of the generated data?
gfredericks: working on it
but I think it does
if it does correspond, then my initial reaction would be "that sounds reasonable"; if not, then that could potentially be a problem worth looking into
unless I'm misunderstanding your question
I don't think it's a problem of test.check per-se so much as the data structure I'm creating with it
mattly: how familiar are you with test.check's general sizing mechanism?
gfredericks: I've dug into the code a bit but haven't tried writing my own generator beyond composing from primitives
you shouldn't need to normally
yeah
I suppose I'm just wondering if you understand it well enough to know why (gen/vector (gen/vector (gen/vector (gen/vector (gen/vector gen/nat)))))
would OOM
I'm pretty sure the problem stems from the need for distinct values where the value doesn't actually matter at a low point in the tree, and then having to generate all the child branches
ah
yeah I do
I've run into that quite a bit on Circle 😄
most of my lists / vectors anymore I put max-elements on
I think the distinct generator is highly unlikely to be slow without also throwing exceptions
ok
i.e., if you think the problem is that it has to throw away a bunch of stuff because of collisions
that was my guess
it'll throw an exception if it can't generate a unique thing after ~10 tries
so it's hard to imagine a scenario where it expends much effort on this without hitting 10 occasionally
fair point
I got some instrumentation up around the generators and my test runs
eliminating the need to generate distinct values on one branch of my tree cut the test run time in half
I'm basically putting those values in now after-the-fact similar to how you might do serial ids