imp-ppl-0.1.0.0: test/Test/Util.hs
-- | Assertion and inspection helpers shared by the test modules.
module Test.Util
( assertApprox
, assertBounds
, assertMap
, assertDist
, assertContains
, assertNoFeasible
, knightNames
, roundDist
) where
import Control.Exception (ErrorCall, evaluate, try)
import Data.List (isPrefixOf)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Test.Tasty.HUnit
import Imp.DSL (Imp)
import Imp.Inference (optimizeProbability)
-- | The Knightian variable names a program allocates, as the compiler sees them.
knightNames :: Ord a => Imp g a -> [String]
knightNames prog = Map.keys (fst (optimizeProbability prog (const True) 1 0.1))
-- | Round a distribution's probabilities to 3 decimal places for comparison.
roundDist :: Map a Double -> Map a Double
roundDist = fmap (\v -> fromIntegral (round (v * 1000) :: Int) / 1000)
-- | Assert that two Doubles are approximately equal (within 1e-6).
assertApprox :: String -> Double -> Double -> Assertion
assertApprox label expected actual =
abs (actual - expected) < 1e-6 @?
(label ++ ": expected " ++ show expected ++ ", got " ++ show actual)
-- | Assert a lower/upper bound pair.
assertBounds :: String -> (Double, Double) -> (Double, Double) -> Assertion
assertBounds label (elo, ehi) (lo, hi) = do
assertApprox (label ++ " lower") elo lo
assertApprox (label ++ " upper") ehi hi
-- | Assert the exact key list and pair of a bounds map.
assertMap :: (Ord k, Show k)
=> String -> [(k, (Double, Double))] -> Map k (Double, Double) -> Assertion
assertMap label expected actual = do
Map.keys actual @?= map fst expected
mapM_ (\(k, b) -> assertBounds (label ++ " " ++ show k) b (actual Map.! k)) expected
-- | Assert the exact key list and probability of a distribution map.
assertDist :: (Ord k, Show k) => String -> [(k, Double)] -> Map k Double -> Assertion
assertDist label expected actual = do
Map.keys actual @?= map fst expected
mapM_ (\(k, p) -> assertApprox (label ++ " " ++ show k) p (actual Map.! k)) expected
-- | Assert that the second pair of bounds contains the first.
assertContains :: String -> (Double, Double) -> (Double, Double) -> Assertion
assertContains label (ilo, ihi) (olo, ohi) = do
olo <= ilo + 1e-9 @?
(label ++ ": outer lower " ++ show olo ++ " > inner lower " ++ show ilo)
ohi >= ihi - 1e-9 @?
(label ++ ": outer upper " ++ show ohi ++ " < inner upper " ++ show ihi)
-- | Assert that forcing the value throws the empty-credal-set error.
assertNoFeasible :: Show a => String -> a -> Assertion
assertNoFeasible label x = do
result <- try (evaluate (length (show x)))
case result of
Left e -> "No feasible probabilities" `isPrefixOf` show (e :: ErrorCall) @?
(label ++ ": unexpected error: " ++ show e)
Right _ -> assertFailure (label ++ ": expected an error, got " ++ show x)