test-check

metametadata 2016-07-27T02:13:23.000049Z

@ag @gfredericks your snippets both seem to work and produce similar results

metametadata 2016-07-27T02:47:11.000051Z

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.

2016-07-27T02:50:16.000052Z

@metametadata: your gen-when ignores its first argument

2016-07-27T02:50:35.000053Z

oh I take it back

2016-07-27T02:52:37.000054Z

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

2016-07-27T02:55:18.000055Z

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

metametadata 2016-07-27T02:56:11.000056Z

yeah, agree. I guess the approach will depend on the number of additional fields in the card map

metametadata 2016-07-27T02:57:25.000057Z

ie if there are a lot of fields similar to created-at than "inlining" is more preferable

ag 2016-07-27T03:05:19.000058Z

actually my thing worked, I didn't know it. My ui was broken, I couldn't see it :)

2016-07-27T03:25:39.000059Z

@metametadata: you can also do both -- make two maps and merge them together

👍 1
mattly 2016-07-27T21:49:46.000061Z

has anyone written about reducing generation time for creating large tree structures in test.check ?

mattly 2016-07-27T21:50:34.000062Z

I added a new branch in my structure recently and it tripled the test run time

mattly 2016-07-27T21:51:34.000063Z

the branch is basically (gen/list-distinct-by :name (gen/hash-map :name gen/string-alphanumeric)) and gets fmapped over with some other stuff

mattly 2016-07-27T21:51:45.000064Z

the actual value of the string isn't important so much as that it's distinct

mattly 2016-07-27T21:52:23.000065Z

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

mattly 2016-07-27T21:53:34.000066Z

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

2016-07-27T22:53:18.000067Z

mattly: have you checked if the runtime increase roughly corresponds to an increase in the size of the generated data?

mattly 2016-07-27T22:53:42.000068Z

gfredericks: working on it

mattly 2016-07-27T22:53:49.000069Z

but I think it does

2016-07-27T22:53:53.000070Z

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

2016-07-27T22:54:10.000071Z

unless I'm misunderstanding your question

mattly 2016-07-27T22:54:40.000072Z

I don't think it's a problem of test.check per-se so much as the data structure I'm creating with it

2016-07-27T22:55:05.000073Z

mattly: how familiar are you with test.check's general sizing mechanism?

mattly 2016-07-27T22:55:40.000074Z

gfredericks: I've dug into the code a bit but haven't tried writing my own generator beyond composing from primitives

2016-07-27T22:55:55.000075Z

you shouldn't need to normally

mattly 2016-07-27T22:56:00.000076Z

yeah

2016-07-27T22:56:45.000077Z

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

mattly 2016-07-27T22:56:54.000078Z

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

mattly 2016-07-27T22:56:59.000079Z

ah

mattly 2016-07-27T22:57:01.000080Z

yeah I do

mattly 2016-07-27T22:57:10.000081Z

I've run into that quite a bit on Circle 😄

mattly 2016-07-27T22:57:34.000082Z

most of my lists / vectors anymore I put max-elements on

2016-07-27T22:58:23.000083Z

I think the distinct generator is highly unlikely to be slow without also throwing exceptions

mattly 2016-07-27T22:58:30.000084Z

ok

2016-07-27T22:58:56.000085Z

i.e., if you think the problem is that it has to throw away a bunch of stuff because of collisions

mattly 2016-07-27T22:59:08.000086Z

that was my guess

2016-07-27T22:59:18.000087Z

it'll throw an exception if it can't generate a unique thing after ~10 tries

2016-07-27T22:59:28.000088Z

so it's hard to imagine a scenario where it expends much effort on this without hitting 10 occasionally

mattly 2016-07-27T22:59:36.000089Z

fair point

mattly 2016-07-27T23:58:58.000090Z

I got some instrumentation up around the generators and my test runs

mattly 2016-07-27T23:59:17.000091Z

eliminating the need to generate distinct values on one branch of my tree cut the test run time in half

mattly 2016-07-27T23:59:42.000092Z

I'm basically putting those values in now after-the-fact similar to how you might do serial ids