MyNixOS website logo
Description

Type Level Specification by Example.

Please see README.md

Build Status

Hackage

A tiny EDSL to write type-level-unit tests.

A small example:

import Test.TypeSpec

main :: IO ()
main = print spec0

spec :: Expect "Expect something..." (Int `Isn't` Bool)
spec = Valid

This will output:

Valid:
     Expect something...
       (✓ Different)

Using the operators from TypeSpecCrazy:

specCrazy ::

    "Higher kinded assertions"
   ###########################

   "ShouldBe accepts types of kind * -> *"
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

       ShouldBe  Maybe Maybe
    -* ShouldBe  []    []
    -* ShouldBe  (->)  (->)

specCrazy = Valid
main = print specCrazy

The output:

Valid:
     Higher kinded assertions
       ShouldBe accepts types of kind * -> *
         (✓ Equal)
         (✓ Equal)
         (✓ Equal)

If you like Lisp, this might be for you:

type ALot = 1000

specAliases ::
  (Explain "There are a variety aliases for the basic combinators."
    (Context "Basic Combinators"
      (Describe "Context"
        (It "labels expectations using 'It'"
          (Describe "Describe"
            (It's "an alias for It, just like They"
              (It's "time for the first assertion"
                (1000 `Is` ALot))))))))
specAliases = Valid

main = print specAliases

This will output:

Valid:
     There are a variety aliases for the basic combinators.
       Basic Combinators
         Context
           labels expectations using 'It'
             Describe
               an alias for It, just like They
                 time for the first assertion
                   (✓ Equal)

The key feature is that the compiler checks the assertions and expectations made in a 'TypeSpec' and right away rejects invalid types.

When compiling this example:

specFailing ::
    TypeSpec
        (It "counts the number of elements in a tuple"
            (Count ((),(),()) `ShouldBe` 4))
specFailing = Valid

type family Count a :: Nat where
  Count (a,b) = 2
  Count (a,b,c) = 3
  Count (a,b,c,d) = 4

The compiler complains:

error:
   • counts the number of elements in a tuple
         Expected type: 3
         Actual type:   4
   • In the expression: Valid
     In an equation for ‘specFailing’: specFailing = Valid

After all, with TypeError GHC is quite a test-runner.

If you accept to defer type checking and have invalid specs checked during test execution, use (should-not-typecheck)[https://github.com/CRogers/should-not-typecheck].

Metadata

Version

0.4.0.0

Platforms (77)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows