Skip to main content

HMock Matcher Predicates

In HMock and Impredicative Polymorphism (Part 2), I wrote about how passing an insufficient number of Predicate arguments to a Matcher was the cause of the impredicative polymorphism errors that I described in HMock and Impredicative Polymorphism. I fixed the problem by passing anything as the arguments and pattern matched against the actual values in the Rule. I have since realized that this is not the correct way to do this. The arguments should be matched in the predicates!

I defined the minimal test as follows. In this code, the predicates match any path and mode values, but the rule pattern matches against specific values. Note that this can cause non-exhaustive pattern matching warnings.

main :: IO ()
main = defaultMain . testCase "experiment" $ do
    isEmpty <- runMockT $ do
      expect $ WithFile_ anything anything anything
        |=> \(WithFile "test.txt" ReadMode _action) -> pure True
      isFileEmpty "test.txt"
    True @=? isEmpty

The predicates for the path and mode parameters should check for the expected values instead. This is done using the eq predicate. In this example, the rule does not use any of the parameters, so they can all be ignored.

main :: IO ()
main = defaultMain . testCase "experiment" $ do
    isEmpty <- runMockT $ do
      expect $ WithFile_ (eq "test.txt") (eq ReadMode) anything
        |=> \(WithFile _path _mode _action) -> pure True
      isFileEmpty "test.txt"
    True @=? isEmpty

The updated code is available on GitHub. Note that the typed example can be changed in the same way.