UnkindPartition / tasty

Modern and extensible testing framework for Haskell
640 stars 110 forks source link

Unhandled resource exception on pure IO action #401

Open bolt12 opened 1 year ago

bolt12 commented 1 year ago

This issue was found whilst using tasty-bench, please refer to https://github.com/Bodigrim/tasty-bench/issues/52 for more details.

Essentially I was able to reproduce this with the following minimal code:

bug :: String -> TestTree
bug title = withResource
              (pure ((), ()) >>= evaluate . force)
              (pure (pure ()))
              ((\(x,y) -> testCase title (unBenchmarkable (nf id (x,y)) maxBound)) . unsafePerformIO)

When I try to run this function I get Unhandled resource. Probably a bug in the runner you're using. This seems to be a bug since my test case does not depend on anything from the environment. I think what makes this fail is the fact I am pattern matching on the tuple, because if I rewrite my function to: (\x -> testCase title (unBenchmarkable (nf id x) maxBound) everything works.

bolt12 commented 1 year ago

It seems I can work around the issue by not pattern matching on the tuple and using uncurry, but there are cases when I can't do that

bolt12 commented 1 year ago

There was one thing I hadn't tried yet which was lazy pattern matching which seems to be something that libraries like criterion requires in similar situations. Indeed adding lazy pattern matching \ ~(x,y) to the function fixes my problem.

This is what you can find in criterion haddocks:

Lazy pattern matching. In situations where a "real" environment is not needed, e.g. if a list of benchmark names is being generated, a value which throws an exception will be passed to the function that receives the environment. This avoids the overhead of generating an environment that will not actually be used.

The function that receives the environment must use lazy pattern matching to deconstruct the tuple (e.g., ~(x, y), not (x, y)), as use of strict pattern matching will cause a crash if an exception-throwing value is passed in.

So this issue might be a bug or a lack of documentation

Bodigrim commented 7 months ago

This is a lack of documentation, a PR improving it would be most welcome.