propcheck icon indicating copy to clipboard operation
propcheck copied to clipboard

** (FunctionClauseError) no function clause matching in :proper_arith.rand_choose/1

Open coop opened this issue 1 year ago • 3 comments

Hi,

I'm seeing this error ** (FunctionClauseError) no function clause matching in :proper_arith.rand_choose/1 while running my test. I assume the problem is one of my generators are failing but there isn't enough information to determine which generator.

I'm hoping that a better error message can be raised that can help target which generator is failing.

This is the stacktrace:

✦ ❯ mix test test/property_test.exs 
22:09:26.189 [info] Running VendWeb.Endpoint with cowboy 2.10.0 at :::4012 (http)
22:09:26.193 [info] Access VendWeb.Endpoint at http://localhost:4012
..........

  1) property it works (Vend.PropertyTest)
     test/property_test.exs:15
     ** (FunctionClauseError) no function clause matching in :proper_arith.rand_choose/1

     The following arguments were given to :proper_arith.rand_choose/1:
     
         # 1
         []
     
     stacktrace:
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_arith.erl:342: :proper_arith.rand_choose/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:491: :proper_gen.union_gen/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:198: :proper_gen.generate/3
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:136: :proper_gen.generate/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:557: :proper_gen."-fixed_list_gen/1-lc$^1/1-0-"/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:557: :proper_gen."-fixed_list_gen/1-lc$^1/1-0-"/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:198: :proper_gen.generate/3
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:136: :proper_gen.generate/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:557: :proper_gen."-fixed_list_gen/1-lc$^1/1-0-"/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:557: :proper_gen."-fixed_list_gen/1-lc$^1/1-0-"/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:524: :proper_gen.tuple_gen/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:198: :proper_gen.generate/3
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:136: :proper_gen.generate/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:198: :proper_gen.generate/3
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:136: :proper_gen.generate/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:186: :proper_gen.generate/3
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:136: :proper_gen.generate/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:198: :proper_gen.generate/3
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:136: :proper_gen.generate/1
       (proper 1.4.0) /Users/dad/Code/youtooz/vend/vend-firmware/fw/deps/proper/src/proper_gen.erl:200: :proper_gen.generate/3


Finished in 96.8 seconds (0.00s async, 96.8s sync)
1 property, 1 failure

Randomized with seed 210523

Elixir: 1.14.3 Erlang: 25.2.2 PropCheck 1.4.1

coop avatar May 17 '23 12:05 coop

That looks really bad. The error message usually appears when the generator tries to select something from an empty collection such as one_of([]). If you combine many generators it is important to not forget that these combinations are really higher order combinations of functions and not function calls. Depending on your experience and the complexity of a generator this can easily slip through.

Did you try to use the sampling functions produce to test your generator? Typically, you would use that from an IEx session to inspect generators. It might be helpful to really check the trivial generators and then move up the ladder to more complex ones like the union you have in your stack trace.

alfert avatar May 18 '23 06:05 alfert

@alfert the failing generator ending up being something like the following:

def some_value(state) do
  oneof(Map.keys(state.some_map))
end

and state.some_map was an empty map.

I've found it hard to test these generators in a console because they rely on building up state via next_state/3. I assume it's impossible to say but am I "doing it wrong"?

Is there any way to provide more context in the stacktrace to narrow down where the error is coming from?

coop avatar May 18 '23 10:05 coop

@coop Indeed, difficult to give a good advice w/o knowing your system or your test setup in more detail. But if I meditate about this issue and #217 then I come these general ideas which might be totally obvious and/or helpful:

Your state-dependent generators should we very aware of the state. Here something like

def some_value(state) where not(Map.empty? (state.some_map)) do
   ...
end

I find it sometimes helpful to have an abstract state enumeration (e.g. :init, :no_clients, :working, :overloaded) that direct which generators can be used. Modeling your system in such abstract states helps to think about your more fundamental states and which generators (and pre/post conditions) are appropriate for these states.

Generally, I think it is more an art than a science to come up with a model that is easy to analyse and provokes enough interesting test situations to torture the system under test.

alfert avatar May 19 '23 08:05 alfert