HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Moduleinspection-testing-0.6.2Haskell2010

Test.Inspection

This module supports the accompanying GHC plugin Test.Inspection.Plugin and adds to GHC the ability to do inspection testing.

  • 4 types
  • 15 values

Synopsis

0 declarations

To use inspection testing, you need to

  1. enable the TemplateHaskell language extension

  2. declare your proof obligations using inspect or inspectTest

An example module is

{-# LANGUAGE TemplateHaskell #-}
module Simple where

import Test.Inspection
import Data.Maybe

lhs, rhs :: (a -> b) -> Maybe a -> Bool
lhs f x = isNothing (fmap f x)
rhs f Nothing = True
rhs f (Just _) = False

inspect $ 'lhs === 'rhs

On GHC < 8.4, you have to explicitly load the plugin: {-# OPTIONS_GHC -fplugin=Test.Inspection.Plugin #-}

Registering obligations

3 declarations
valueinspect :: Obligation -> Q [Dec]
#

As seen in the example above, the entry point to inspection testing is the inspect function, to which you pass an Obligation. It will report test failures at compile time.

valueinspectTest :: Obligation -> Q Exp
#

This is a variant of inspect that allows compilation to succeed in any case, and instead indicates the result as a value of type Result, which allows seamless integration into test frameworks.

This variant ignores the expectFail field of the obligation. Instead, it is expected that you use the corresponding functionality in your test framework (e.g. tasty-expected-failure)

Defining obligations

4 declarations
datadata Obligation
#

This data type describes an inspection testing obligation.

It is recommended to build it using mkObligation, for backwards compatibility when new fields are added. You can also use the more mnemonic convenience functions like (===) or hasNoType.

The obligation needs to be passed to inspect or inspectTest.

Constructors

Instances1Data
datadata Property
#

Properties of the obligation target to be checked.

Constructors

  • EqualTo Name Equivalence

    Are the two functions equal?

    More precisely: f is equal to g if either the definition of f is f = g, or the definition of g is g = f, or if the definitions are f = e and g = e.

    In general f and g need to be defined in this module, so that their actual defintions can be inspected.

    The Equivalence indicates how strict to check for equality

  • NoTypes [Name]

    Do none of these types appear anywhere in the definition of the function (neither locally bound nor passed as arguments)

  • NoAllocation

    Does this function perform no heap allocations.

  • NoTypeClasses [Name]

    Does this value contain dictionaries (except of the listed classes).

  • NoUseOf [Name]

    Does not contain this value (in terms or patterns)

  • CoreOf

    Always satisfied, but dumps the value in non-quiet mode.

Instances1Data
  • Data PropertyDefined in inspection-testing-0.6.2 · Test.Inspection

Convenience functions

12 declarations

These convenience functions create common test obligations directly.

value(==-) :: Name -> Name -> Obligation
#

Declare two functions to be equal, but ignoring type lambdas, type arguments, type casts and hpc ticks (see EqualTo). Note that -fhpc can prevent some optimizations; build without for more reliable analysis.

value(=/=) :: Name -> Name -> Obligation
#

Declare two functions to be equal, but expect the test to fail (see EqualTo and expectFail) (This is useful for documentation purposes, or as a TODO list.)

value(=/~) :: Name -> Name -> Obligation
#

Declare two functions to be equal up to let binding ordering (see (==~)), but expect the test to fail (see expectFail).

valuehasNoType :: Name -> Name -> Obligation
#

Declare that in a function’s implementation, the given type does not occur.

More precisely: No locally bound variable (let-bound, lambda-bound or pattern-bound) has a type that contains the given type constructor.

inspect $ fusedFunction `hasNoType` ''[]

Declare that a function’s implementation does not contain any generic types. This is just hasNoType applied to the usual type constructors used in GHC.Generics.

inspect $ hasNoGenerics genericFunction

Declare that a function's implementation does not include dictionaries.

More precisely: No locally bound variable (let-bound, lambda-bound or pattern-bound) has a type that contains a type that mentions a type class.

inspect $ hasNoTypeClasses specializedFunction
valuedoesNotUse :: Name -> Name -> Obligation
#

Declare that a function's implementation does not use the given variable (either in terms or -- if it is a constructor -- in patterns).

inspect $ foo `doesNotUse` 'error