Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comparing values that have IORef in them #32

Closed
FranklinChen opened this issue Mar 9, 2019 · 4 comments
Closed

Comparing values that have IORef in them #32

FranklinChen opened this issue Mar 9, 2019 · 4 comments

Comments

@FranklinChen
Copy link

What is the recommended way to write a matcher to compare two values that have IORef in them and therefore have to be evaluated in IO both for equality comparison and showable diffs?

@sol
Copy link
Member

sol commented Mar 10, 2019

Something like this:

(readIORef actual `shouldReturn`) =<< readIORef expected

@FranklinChen
Copy link
Author

I meant, if I have

data List a = Nil | Cons (IORef a) (IORef (List a))

I want to write

shouldBeEqList :: (Show a, Eq a) => List a -> List a -> Expectation

@sol
Copy link
Member

sol commented Nov 1, 2020

@FranklinChen sorry for the late replay, there is no standard way of achieving this.

Option 1

The easiest approach might be to convert your List to a regular Haskell list, say if you have

toList :: List a -> [a]

you can do something like this:

infix 1 `shouldBeEqList`

shouldBeEqList :: HasCallStack => (Eq a, Show a) => List a -> List a -> Expectation
shouldBeEqList actual expected = do
  (toList actual `shouldReturn`) =<< toList expected

Option 2

If you have functions:

eqList :: Eq a => List a -> List a -> IO Bool
showList :: Show a => List a -> List a -> IO String

then you can do something like:

Option 2.1

shouldBeEqList :: HasCallStack => Show a => List a -> List a -> Expectation
shouldBeEqList actual expected = do
  (showList actual `shouldReturn`) =<< showList expected

We are ignoring the Eq instance here and instead rely on the fact that lists that look equal are equal and that lists that are not equal look different.

If that is not the case for some reason, you can do this instead:

Option 2.2

shouldBeEqList :: HasCallStack => (Eq a, Show a) => List a -> List a -> Expectation
shouldBeEqList actual expected = do
  eq <- eqList actual expected
  unless eq $ throwIO (HUnitFailure location $ ExpectedButGot Nothing expectedMsg actualMsg)

location :: HasCallStack => Maybe SrcLoc
location = case reverse callStack of
  (_, loc) : _ -> Just loc
  [] -> Nothing

(look at https://hackage.haskell.org/package/HUnit-1.6.1.0/docs/src/Test.HUnit.Lang.html#assertEqual for the imports you will need)

We should probably export more things from HUnit to make this kind of things easier.

@sol
Copy link
Member

sol commented Nov 1, 2020

I opened hspec/HUnit#29.

@sol sol closed this as completed Nov 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants