yamlet-1.0.0.0: tests/Yamlet/Test/Inspection/Obligations.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskellQuotes #-}
-- | Obligations for the inspection tests. They are in their own module,
-- because a splice cannot use a function of the module that holds it.
--
-- Keep every function of this module, also one that no test uses at the
-- moment, e.g. 'assertFailureIf' and 'ghcVersion' when no test expects a
-- failure. A later change to the library or a new version of GHC can need
-- them again.
module Yamlet.Test.Inspection.Obligations
( hasNoGenericRep
, hasNoGenericDictionaries
, assertSuccess
, assertFailureIf
, ghcVersion
) where
import GHC.Generics qualified as G
import Language.Haskell.TH
import Test.Inspection
import Test.Tasty.HUnit
import Yamlet
-- | The code uses no function and no constructor of the generic
-- representation. 'hasNoGenerics' checks the types instead, but the types
-- appear in coercions and in the types of join points after the optimizer
-- removed the representation. The constructors of the newtypes 'G.K1' and
-- 'G.M1' are casts in Core, so the list cannot name them.
hasNoGenericRep :: Name -> Obligation
hasNoGenericRep name =
mkObligation name $
NoUseOf
[ 'G.from
, 'G.to
, '(G.:*:)
, 'G.L1
, 'G.R1
, 'G.U1
]
-- | The code passes no dictionaries of the generic classes, e.g. to a method
-- of the instance for t'Yamlet.GenericYaml' that GHC did not inline at the
-- type. That method keeps the generic representation in another module.
-- 'hasNoGenericRep' sees such a call only through the 'G.Generic' instance
-- of a type in the module of the test.
hasNoGenericDictionaries :: Name -> Obligation
hasNoGenericDictionaries name =
mkObligation name $
NoTypes
[ ''G.Generic
, ''GenericYamlOptions
, ''GDatatype
, ''GConstructors
, ''GEncoding
, ''GToConstructor
, ''GFromConstructor
, ''GFields
, ''GToFields
, ''GFromFields
]
-- | Fail with the Core of the function if the obligation does not hold.
assertSuccess :: Result -> Assertion
assertSuccess = \case
Success _ -> pure ()
Failure err -> assertFailure err
-- | If the flag is set, fail if the obligation holds, for a known failure,
-- e.g. on a version of GHC that optimizes the code less. Then the test also
-- shows when a version of GHC fixes the failure. Otherwise, 'assertSuccess'.
assertFailureIf :: Bool -> Result -> Assertion
assertFailureIf = \case
True -> \case
Success msg -> assertFailure ("expected a failure, but " ++ msg)
Failure _ -> pure ()
False -> assertSuccess
-- | The major version of GHC, e.g. @(9, 12)@.
ghcVersion :: (Int, Int)
ghcVersion = __GLASGOW_HASKELL__ `quotRem` 100