holmes-0.3.2.0: test/Test/Regression/Issue7.hs
{-# OPTIONS_GHC -Wno-missing-methods #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ViewPatterns #-}
module Test.Regression.Issue7 where
import Data.Function ((&))
import Data.Hashable (Hashable)
import Data.Holmes
import GHC.Generics (Generic)
import Test.Tasty.Hspec (Spec, describe, it, shouldBe)
-------------------------------------------------------------------------------
-- #7: stack overflow / infinite loop when solving with Intersect instead of
-- Defined
countEqual
:: ( Eq (f x)
, Lifting f c
, Mapping f c
, c x, c v
, Num v, Num (f v), SumR (f v)
, MonadCell m
)
=> [(Int, x)]
-> [Prop m (f x)]
-> Prop m (f v)
countEqual values cells = foldr (.+) (lift 0) (map f values)
where
f (index, expected) = cells !! index & over \actual ->
if lift' expected == actual then 1 else 0
spec_17_defined :: Spec
spec_17_defined = describe "Issue #17" do
it "Defined" do
let checks :: [( Int, Int )]
checks = [( 0, 3 )]
threshold :: MonadCell m => Prop m (Defined Int)
threshold = lift 0
example <- (1 `from` [ 1 ]) `satisfying` \cells -> do
countEqual checks cells .>= threshold
example `shouldBe` Just [ 1 ]
it "Intersect" do
let checks :: [( Int, Val4 )]
checks = [( 0, 3 )]
threshold :: MonadCell m => Prop m (Intersect Val4)
threshold = lift 0
example <- (1 `from` [ 1 ]) `satisfying` \cells -> do
countEqual checks cells .>= threshold
example `shouldBe` Just [ 1 ]
newtype Val4 = V4 Int
deriving stock (Show, Eq, Ord, Generic)
deriving anyclass (Hashable)
instance Num Val4 where
fromInteger = toEnum . fromInteger
-- this is not a valid Num instance, we just want to use
-- it for counting
V4 a + V4 b = if a + b > 4 then V4 4 else V4 (a + b)
V4 a - V4 b = if a - b < 0 then V4 0 else V4 (a - b)
instance Enum Val4 where
toEnum n
| n < 0 || n > 4 = error $ "toEnum Val4 out of bounds: " ++ show n
| otherwise = V4 n
fromEnum v@(V4 m)
| m < 0 || m > 4 = error $ "fromEnum Val4 out of bounds: " ++ show v
| otherwise = m
instance Bounded Val4 where
minBound = toEnum 0
maxBound = toEnum 4