packages feed

witch-0.2.0.1: src/test/Main.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}

import qualified Control.Exception as Exception
import qualified Control.Monad as Monad
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as LazyByteString
import qualified Data.ByteString.Short as ShortByteString
import qualified Data.Complex as Complex
import qualified Data.Fixed as Fixed
import qualified Data.Int as Int
import qualified Data.IntMap as IntMap
import qualified Data.IntSet as IntSet
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Map as Map
import qualified Data.Ratio as Ratio
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Data.Text.Lazy as LazyText
import qualified Data.Word as Word
import qualified Numeric.Natural as Natural
import qualified Test.Hspec as Hspec
import qualified Witch

main :: IO ()
main = Hspec.hspec . Hspec.describe "Witch" $ do

  Hspec.describe "Cast" $ do

    Hspec.describe "cast" $ do
      test $ Witch.cast (1 :: Int.Int8) `Hspec.shouldBe` (1 :: Int.Int16)

  Hspec.describe "TryCast" $ do

    Hspec.describe "tryCast" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Int.Int8
      test $ f 1 `Hspec.shouldBe` Just 1
      test $ f 128 `Hspec.shouldBe` Nothing

  Hspec.describe "Utility" $ do

    Hspec.describe "as" $ do
      test $ Witch.as @Int.Int8 1 `Hspec.shouldBe` 1

    Hspec.describe "from" $ do
      test $ Witch.from @Int.Int8 1 `Hspec.shouldBe` (1 :: Int.Int16)

    Hspec.describe "into" $ do
      test $ Witch.into @Int.Int16 (1 :: Int.Int8) `Hspec.shouldBe` 1

    Hspec.describe "over" $ do
      test $ Witch.over @String (<> "!") (Name "Kiki") `Hspec.shouldBe` Name "Kiki!"

    Hspec.describe "via" $ do
      test $ Witch.via @Int.Int16 (1 :: Int.Int8) `Hspec.shouldBe` (1 :: Int.Int32)

    Hspec.describe "tryFrom" $ do
      test $ hush (Witch.tryFrom @Int.Int16 1) `Hspec.shouldBe` Just (1 :: Int.Int8)

    Hspec.describe "tryInto" $ do
      test $ hush (Witch.tryInto @Int.Int8 (1 :: Int.Int16)) `Hspec.shouldBe` Just 1

    Hspec.describe "unsafeCast" $ do
      test $ Witch.unsafeCast (1 :: Int.Int16) `Hspec.shouldBe` (1 :: Int.Int8)
      test $ Exception.evaluate (Witch.unsafeCast @Int.Int16 @Int.Int8 128) `Hspec.shouldThrow` Hspec.anyException

    Hspec.describe "unsafeFrom" $ do
      test $ Witch.unsafeFrom @Int.Int16 1 `Hspec.shouldBe` (1 :: Int.Int8)

    Hspec.describe "unsafeInto" $ do
      test $ Witch.unsafeInto @Int.Int8 (1 :: Int.Int16) `Hspec.shouldBe` 1

  Hspec.describe "Lift" $ do

    Hspec.describe "liftedCast" $ do
      test $ ($$(Witch.liftedCast (1 :: Int.Int16)) :: Int.Int8) `Hspec.shouldBe` 1

    Hspec.describe "liftedFrom" $ do
      test $ ($$(Witch.liftedFrom @Int.Int16 1) :: Int.Int8) `Hspec.shouldBe` 1

    Hspec.describe "liftedInto" $ do
      test $ $$(Witch.liftedInto @Int.Int8 (1 :: Int.Int16)) `Hspec.shouldBe` 1

  Hspec.describe "Instances" $ do

    -- Int8

    Hspec.describe "Cast Int8 Int16" $ do
      let f = Witch.cast @Int.Int8 @Int.Int16
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 127 `Hspec.shouldBe` 127
      test $ f (-128) `Hspec.shouldBe` (-128)

    Hspec.describe "Cast Int8 Int32" $ do
      let f = Witch.cast @Int.Int8 @Int.Int32
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 127 `Hspec.shouldBe` 127
      test $ f (-128) `Hspec.shouldBe` (-128)

    Hspec.describe "Cast Int8 Int64" $ do
      let f = Witch.cast @Int.Int8 @Int.Int64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 127 `Hspec.shouldBe` 127
      test $ f (-128) `Hspec.shouldBe` (-128)

    Hspec.describe "Cast Int8 Int" $ do
      let f = Witch.cast @Int.Int8 @Int
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 127 `Hspec.shouldBe` 127
      test $ f (-128) `Hspec.shouldBe` (-128)

    Hspec.describe "Cast Int8 Integer" $ do
      let f = Witch.cast @Int.Int8 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 127 `Hspec.shouldBe` 127
      test $ f (-128) `Hspec.shouldBe` (-128)

    Hspec.describe "TryCast Int8 Word8" $ do
      let f = hush . Witch.tryCast @Int.Int8 @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int8 Word16" $ do
      let f = hush . Witch.tryCast @Int.Int8 @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int8 Word32" $ do
      let f = hush . Witch.tryCast @Int.Int8 @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int8 Word64" $ do
      let f = hush . Witch.tryCast @Int.Int8 @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int8 Word" $ do
      let f = hush . Witch.tryCast @Int.Int8 @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int8 Natural" $ do
      let f = hush . Witch.tryCast @Int.Int8 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Int8 Float" $ do
      let f = Witch.cast @Int.Int8 @Float
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 127 `Hspec.shouldBe` 127
      test $ f (-128) `Hspec.shouldBe` (-128)

    Hspec.describe "Cast Int8 Double" $ do
      let f = Witch.cast @Int.Int8 @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 127 `Hspec.shouldBe` 127
      test $ f (-128) `Hspec.shouldBe` (-128)

    -- Int16

    Hspec.describe "TryCast Int16 Int8" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing
      test $ f (-128) `Hspec.shouldBe` Just (-128)
      test $ f (-129) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Int16 Int32" $ do
      let f = Witch.cast @Int.Int16 @Int.Int32
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 32767 `Hspec.shouldBe` 32767
      test $ f (-32768) `Hspec.shouldBe` (-32768)

    Hspec.describe "Cast Int16 Int64" $ do
      let f = Witch.cast @Int.Int16 @Int.Int64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 32767 `Hspec.shouldBe` 32767
      test $ f (-32768) `Hspec.shouldBe` (-32768)

    Hspec.describe "Cast Int16 Int" $ do
      let f = Witch.cast @Int.Int16 @Int
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 32767 `Hspec.shouldBe` 32767
      test $ f (-32768) `Hspec.shouldBe` (-32768)

    Hspec.describe "Cast Int16 Integer" $ do
      let f = Witch.cast @Int.Int16 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 32767 `Hspec.shouldBe` 32767
      test $ f (-32768) `Hspec.shouldBe` (-32768)

    Hspec.describe "TryCast Int16 Word8" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int16 Word16" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int16 Word32" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int16 Word64" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int16 Word" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int16 Natural" $ do
      let f = hush . Witch.tryCast @Int.Int16 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Int16 Float" $ do
      let f = Witch.cast @Int.Int16 @Float
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 32767 `Hspec.shouldBe` 32767
      test $ f (-32768) `Hspec.shouldBe` (-32768)

    Hspec.describe "Cast Int16 Double" $ do
      let f = Witch.cast @Int.Int16 @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 32767 `Hspec.shouldBe` 32767
      test $ f (-32768) `Hspec.shouldBe` (-32768)

    -- Int32

    Hspec.describe "TryCast Int32 Int8" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing
      test $ f (-128) `Hspec.shouldBe` Just (-128)
      test $ f (-129) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int32 Int16" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing
      test $ f (-32768) `Hspec.shouldBe` Just (-32768)
      test $ f (-32769) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Int32 Int64" $ do
      let f = Witch.cast @Int.Int32 @Int.Int64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 2147483647 `Hspec.shouldBe` 2147483647
      test $ f (-2147483648) `Hspec.shouldBe` (-2147483648)

    Hspec.describe "TryCast Int32 Int" $ do
      Monad.when (toInteger (maxBound :: Int) < 2147483647) untested
      let f = hush . Witch.tryCast @Int.Int32 @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f (-2147483648) `Hspec.shouldBe` Just (-2147483648)

    Hspec.describe "Cast Int32 Integer" $ do
      let f = Witch.cast @Int.Int32 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 2147483647 `Hspec.shouldBe` 2147483647
      test $ f (-2147483648) `Hspec.shouldBe` (-2147483648)

    Hspec.describe "TryCast Int32 Word8" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int32 Word16" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int32 Word32" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int32 Word64" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int32 Word" $ do
      Monad.when (toInteger (maxBound :: Word) < 2147483647) untested
      let f = hush . Witch.tryCast @Int.Int32 @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int32 Natural" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int32 Float" $ do
      let f = hush . Witch.tryCast @Int.Int32 @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Int32 Double" $ do
      let f = Witch.cast @Int.Int32 @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 2147483647 `Hspec.shouldBe` 2147483647
      test $ f (-2147483648) `Hspec.shouldBe` (-2147483648)

    -- Int64

    Hspec.describe "TryCast Int64 Int8" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing
      test $ f (-128) `Hspec.shouldBe` Just (-128)
      test $ f (-129) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Int16" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing
      test $ f (-32768) `Hspec.shouldBe` Just (-32768)
      test $ f (-32769) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Int32" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing
      test $ f (-2147483648) `Hspec.shouldBe` Just (-2147483648)
      test $ f (-2147483649) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Int" $ do
      Monad.when (toInteger (maxBound :: Int) < 9223372036854775807) untested
      let f = hush . Witch.tryCast @Int.Int64 @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f (-9223372036854775808) `Hspec.shouldBe` Just (-9223372036854775808)

    Hspec.describe "Cast Int64 Integer" $ do
      let f = Witch.cast @Int.Int64 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 9223372036854775807 `Hspec.shouldBe` 9223372036854775807
      test $ f (-9223372036854775808) `Hspec.shouldBe` (-9223372036854775808)

    Hspec.describe "TryCast Int64 Word8" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Word16" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Word32" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Word64" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Word" $ do
      Monad.when (toInteger (maxBound :: Word) < 9223372036854775807) untested
      let f = hush . Witch.tryCast @Int.Int64 @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Natural" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Float" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int64 Double" $ do
      let f = hush . Witch.tryCast @Int.Int64 @Double
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (-9007199254740991) `Hspec.shouldBe` Just (-9007199254740991)
      test $ f (-9007199254740992) `Hspec.shouldBe` Nothing

    -- Int

    Hspec.describe "TryCast Int Int8" $ do
      let f = hush . Witch.tryCast @Int @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing
      test $ f (-128) `Hspec.shouldBe` Just (-128)
      test $ f (-129) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Int16" $ do
      let f = hush . Witch.tryCast @Int @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing
      test $ f (-32768) `Hspec.shouldBe` Just (-32768)
      test $ f (-32769) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Int32" $ do
      Monad.when (toInteger (maxBound :: Int) < 2147483647) untested
      let f = hush . Witch.tryCast @Int @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing
      test $ f (-2147483648) `Hspec.shouldBe` Just (-2147483648)
      test $ f (-2147483649) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Int Int64" $ do
      let f = Witch.cast @Int @Int.Int64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f maxBound `Hspec.shouldBe` fromIntegral (maxBound :: Int)
      test $ f minBound `Hspec.shouldBe` fromIntegral (minBound :: Int)

    Hspec.describe "Cast Int Integer" $ do
      let f = Witch.cast @Int @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f maxBound `Hspec.shouldBe` fromIntegral (maxBound :: Int)
      test $ f minBound `Hspec.shouldBe` fromIntegral (minBound :: Int)

    Hspec.describe "TryCast Int Word8" $ do
      let f = hush . Witch.tryCast @Int @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Word16" $ do
      let f = hush . Witch.tryCast @Int @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Word32" $ do
      Monad.when (toInteger (maxBound :: Int) < 4294967295) untested
      let f = hush . Witch.tryCast @Int @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295
      test $ f 4294967296 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Word64" $ do
      let f = hush . Witch.tryCast @Int @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f maxBound `Hspec.shouldBe` Just (fromIntegral (maxBound :: Int))
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Word" $ do
      let f = hush . Witch.tryCast @Int @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f maxBound `Hspec.shouldBe` Just (fromIntegral (maxBound :: Int))
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Natural" $ do
      let f = hush . Witch.tryCast @Int @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f maxBound `Hspec.shouldBe` Just (fromIntegral (maxBound :: Int))
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Float" $ do
      let f = hush . Witch.tryCast @Int @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Int Double" $ do
      Monad.when (toInteger (maxBound :: Int) < 9007199254740991) untested
      let f = hush . Witch.tryCast @Int @Double
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (-9007199254740991) `Hspec.shouldBe` Just (-9007199254740991)
      test $ f (-9007199254740992) `Hspec.shouldBe` Nothing

    -- Integer

    Hspec.describe "TryCast Integer Int8" $ do
      let f = hush . Witch.tryCast @Integer @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing
      test $ f (-128) `Hspec.shouldBe` Just (-128)
      test $ f (-129) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Int16" $ do
      let f = hush . Witch.tryCast @Integer @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing
      test $ f (-32768) `Hspec.shouldBe` Just (-32768)
      test $ f (-32769) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Int32" $ do
      let f = hush . Witch.tryCast @Integer @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing
      test $ f (-2147483648) `Hspec.shouldBe` Just (-2147483648)
      test $ f (-2147483649) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Int64" $ do
      let f = hush . Witch.tryCast @Integer @Int.Int64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f 9223372036854775808 `Hspec.shouldBe` Nothing
      test $ f (-9223372036854775808) `Hspec.shouldBe` Just (-9223372036854775808)
      test $ f (-9223372036854775809) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Int" $ do
      let f = hush . Witch.tryCast @Integer @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ let x = maxBound :: Int in f (fromIntegral x) `Hspec.shouldBe` Just x
      test $ let x = toInteger (maxBound :: Int) + 1 in f x `Hspec.shouldBe` Nothing
      test $ let x = minBound :: Int in f (fromIntegral x) `Hspec.shouldBe` Just x
      test $ let x = toInteger (minBound :: Int) - 1 in f x `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Word8" $ do
      let f = hush . Witch.tryCast @Integer @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Word16" $ do
      let f = hush . Witch.tryCast @Integer @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Word32" $ do
      let f = hush . Witch.tryCast @Integer @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295
      test $ f 4294967296 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Word64" $ do
      let f = hush . Witch.tryCast @Integer @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 18446744073709551615 `Hspec.shouldBe` Just 18446744073709551615
      test $ f 18446744073709551616 `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Word" $ do
      let f = hush . Witch.tryCast @Integer @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ let x = maxBound :: Word in f (fromIntegral x) `Hspec.shouldBe` Just x
      test $ let x = toInteger (maxBound :: Word) + 1 in f x `Hspec.shouldBe` Nothing
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Natural" $ do
      let f = hush . Witch.tryCast @Integer @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 18446744073709551616 `Hspec.shouldBe` Just 18446744073709551616
      test $ f (-1) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Float" $ do
      let f = hush . Witch.tryCast @Integer @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Integer Double" $ do
      let f = hush . Witch.tryCast @Integer @Double
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (-9007199254740991) `Hspec.shouldBe` Just (-9007199254740991)
      test $ f (-9007199254740992) `Hspec.shouldBe` Nothing

    -- Word8

    Hspec.describe "Cast Word8 Word16" $ do
      let f = Witch.cast @Word.Word8 @Word.Word16
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Word32" $ do
      let f = Witch.cast @Word.Word8 @Word.Word32
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Word64" $ do
      let f = Witch.cast @Word.Word8 @Word.Word64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Word" $ do
      let f = Witch.cast @Word.Word8 @Word
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Natural" $ do
      let f = Witch.cast @Word.Word8 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "TryCast Word8 Int8" $ do
      let f = hush . Witch.tryCast @Word.Word8 @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word8 Int16" $ do
      let f = Witch.cast @Word.Word8 @Int.Int16
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Int32" $ do
      let f = Witch.cast @Word.Word8 @Int.Int32
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Int64" $ do
      let f = Witch.cast @Word.Word8 @Int.Int64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Int" $ do
      let f = Witch.cast @Word.Word8 @Int
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Integer" $ do
      let f = Witch.cast @Word.Word8 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Float" $ do
      let f = Witch.cast @Word.Word8 @Float
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    Hspec.describe "Cast Word8 Double" $ do
      let f = Witch.cast @Word.Word8 @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 255 `Hspec.shouldBe` 255

    -- Word16

    Hspec.describe "TryCast Word16 Word8" $ do
      let f = hush . Witch.tryCast @Word.Word16 @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word16 Word32" $ do
      let f = Witch.cast @Word.Word16 @Word.Word32
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Word64" $ do
      let f = Witch.cast @Word.Word16 @Word.Word64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Word" $ do
      let f = Witch.cast @Word.Word16 @Word
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Natural" $ do
      let f = Witch.cast @Word.Word16 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "TryCast Word16 Int8" $ do
      let f = hush . Witch.tryCast @Word.Word16 @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word16 Int16" $ do
      let f = hush . Witch.tryCast @Word.Word16 @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word16 Int32" $ do
      let f = Witch.cast @Word.Word16 @Int.Int32
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Int64" $ do
      let f = Witch.cast @Word.Word16 @Int.Int64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Int" $ do
      let f = Witch.cast @Word.Word16 @Int
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Integer" $ do
      let f = Witch.cast @Word.Word16 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Float" $ do
      let f = Witch.cast @Word.Word16 @Float
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    Hspec.describe "Cast Word16 Double" $ do
      let f = Witch.cast @Word.Word16 @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 65535 `Hspec.shouldBe` 65535

    -- Word32

    Hspec.describe "TryCast Word32 Word8" $ do
      let f = hush . Witch.tryCast @Word.Word32 @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word32 Word16" $ do
      let f = hush . Witch.tryCast @Word.Word32 @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word32 Word64" $ do
      let f = Witch.cast @Word.Word32 @Word.Word64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 4294967295 `Hspec.shouldBe` 4294967295

    Hspec.describe "TryCast Word32 Word" $ do
      Monad.when (toInteger (maxBound :: Word) < 4294967295) untested
      let f = hush . Witch.tryCast @Word.Word32 @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295

    Hspec.describe "Cast Word32 Natural" $ do
      let f = Witch.cast @Word.Word32 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 4294967295 `Hspec.shouldBe` 4294967295

    Hspec.describe "TryCast Word32 Int8" $ do
      let f = hush . Witch.tryCast @Word.Word32 @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word32 Int16" $ do
      let f = hush . Witch.tryCast @Word.Word32 @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word32 Int32" $ do
      let f = hush . Witch.tryCast @Word.Word32 @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word32 Int64" $ do
      let f = Witch.cast @Word.Word32 @Int.Int64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 4294967295 `Hspec.shouldBe` 4294967295

    Hspec.describe "TryCast Word32 Int" $ do
      Monad.when (toInteger (maxBound :: Int) < 4294967295) untested
      let f = hush . Witch.tryCast @Word.Word32 @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295

    Hspec.describe "Cast Word32 Integer" $ do
      let f = Witch.cast @Word.Word32 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 4294967295 `Hspec.shouldBe` 4294967295

    Hspec.describe "TryCast Word32 Float" $ do
      let f = hush . Witch.tryCast @Word.Word32 @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word32 Double" $ do
      let f = Witch.cast @Word.Word32 @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 4294967295 `Hspec.shouldBe` 4294967295

    -- Word64

    Hspec.describe "TryCast Word64 Word8" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Word16" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Word32" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295
      test $ f 4294967296 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Word" $ do
      Monad.when (toInteger (maxBound :: Word) < 18446744073709551615) untested
      let f = hush . Witch.tryCast @Word.Word64 @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 18446744073709551615 `Hspec.shouldBe` Just 18446744073709551615

    Hspec.describe "Cast Word64 Natural" $ do
      let f = Witch.cast @Word.Word64 @Natural.Natural
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 18446744073709551615 `Hspec.shouldBe` 18446744073709551615

    Hspec.describe "TryCast Word64 Int8" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Int16" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Int32" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Int64" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Int.Int64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f 9223372036854775808 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Int" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ let x = maxBound :: Int in hush (Witch.tryCast @Word.Word64 @Int (fromIntegral x)) `Hspec.shouldBe` Just x
      test $ let x = fromIntegral (maxBound :: Int) + 1 :: Word.Word64 in hush (Witch.tryCast @Word.Word64 @Int x) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word64 Integer" $ do
      let f = Witch.cast @Word.Word64 @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 18446744073709551615 `Hspec.shouldBe` 18446744073709551615

    Hspec.describe "TryCast Word64 Float" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word64 Double" $ do
      let f = hush . Witch.tryCast @Word.Word64 @Double
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing

    -- Word

    Hspec.describe "TryCast Word Word8" $ do
      let f = hush . Witch.tryCast @Word @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word Word16" $ do
      let f = hush . Witch.tryCast @Word @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word Word32" $ do
      Monad.when (toInteger (maxBound :: Word) < 4294967295) untested
      let f = hush . Witch.tryCast @Word @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295
      test $ f 4294967296 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word Word64" $ do
      let f = Witch.cast @Word @Word.Word64
      test $ f 0 `Hspec.shouldBe` 0
      test $ f maxBound `Hspec.shouldBe` fromIntegral (maxBound :: Word)

    Hspec.describe "Cast Word Natural" $ do
      let f = Witch.cast @Word @Natural.Natural
      test $ f 0 `Hspec.shouldBe` 0
      test $ f maxBound `Hspec.shouldBe` fromIntegral (maxBound :: Word)

    Hspec.describe "TryCast Word Int8" $ do
      let f = hush . Witch.tryCast @Word @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word Int16" $ do
      let f = hush . Witch.tryCast @Word @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word Int32" $ do
      Monad.when (toInteger (maxBound :: Word) < 2147483647) untested
      let f = hush . Witch.tryCast @Word @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word Int64" $ do
      Monad.when (toInteger (maxBound :: Word) < 9223372036854775807) untested
      let f = hush . Witch.tryCast @Word @Int.Int64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f 9223372036854775808 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word Int" $ do
      let f = hush . Witch.tryCast @Word @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ let x = maxBound :: Int in hush (Witch.tryCast @Word @Int (fromIntegral x)) `Hspec.shouldBe` Just x
      test $ let x = fromIntegral (maxBound :: Int) + 1 :: Word in hush (Witch.tryCast @Word @Int x) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Word Integer" $ do
      let f = Witch.cast @Word @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f maxBound `Hspec.shouldBe` fromIntegral (maxBound :: Word)

    Hspec.describe "TryCast Word Float" $ do
      let f = hush . Witch.tryCast @Word @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Word Double" $ do
      Monad.when (toInteger (maxBound :: Word) < 9007199254740991) untested
      let f = hush . Witch.tryCast @Word @Double
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing

    -- Natural

    Hspec.describe "TryCast Natural Word8" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Word16" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Word32" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295
      test $ f 4294967296 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Word64" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 18446744073709551615 `Hspec.shouldBe` Just 18446744073709551615
      test $ f 18446744073709551616 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Word" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ let x = maxBound :: Word in hush (Witch.tryCast @Natural.Natural @Word (fromIntegral x)) `Hspec.shouldBe` Just x
      test $ let x = fromIntegral (maxBound :: Word) + 1 :: Natural.Natural in hush (Witch.tryCast @Natural.Natural @Word x) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Int8" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Int16" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Int32" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Int64" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Int.Int64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9223372036854775807 `Hspec.shouldBe` Just 9223372036854775807
      test $ f 9223372036854775808 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Int" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ let x = maxBound :: Int in hush (Witch.tryCast @Natural.Natural @Int (fromIntegral x)) `Hspec.shouldBe` Just x
      test $ let x = fromIntegral (maxBound :: Int) + 1 :: Natural.Natural in hush (Witch.tryCast @Natural.Natural @Int x) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Natural Integer" $ do
      let f = Witch.cast @Natural.Natural @Integer
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 9223372036854775808 `Hspec.shouldBe` 9223372036854775808

    Hspec.describe "TryCast Natural Float" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Float
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Natural Double" $ do
      let f = hush . Witch.tryCast @Natural.Natural @Double
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing

    -- Float

    Hspec.describe "TryCast Float Int8" $ do
      let f = hush . Witch.tryCast @Float @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing
      test $ f (-128) `Hspec.shouldBe` Just (-128)
      test $ f (-129) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Int16" $ do
      let f = hush . Witch.tryCast @Float @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing
      test $ f (-32768) `Hspec.shouldBe` Just (-32768)
      test $ f (-32769) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Int32" $ do
      let f = hush . Witch.tryCast @Float @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Int64" $ do
      let f = hush . Witch.tryCast @Float @Int.Int64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Int" $ do
      let f = hush . Witch.tryCast @Float @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Integer" $ do
      let f = hush . Witch.tryCast @Float @Integer
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f (-16777216) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Word8" $ do
      let f = hush . Witch.tryCast @Float @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Word16" $ do
      let f = hush . Witch.tryCast @Float @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Word32" $ do
      let f = hush . Witch.tryCast @Float @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Word64" $ do
      let f = hush . Witch.tryCast @Float @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Word" $ do
      let f = hush . Witch.tryCast @Float @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Natural" $ do
      let f = hush . Witch.tryCast @Float @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f 16777216 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Float Rational" $ do
      let f = hush . Witch.tryCast @Float @Rational
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f (-0) `Hspec.shouldBe` Just 0
      test $ f 0.5 `Hspec.shouldBe` Just 0.5
      test $ f (-0.5) `Hspec.shouldBe` Just (-0.5)
      test $ f 16777215 `Hspec.shouldBe` Just 16777215
      test $ f (-16777215) `Hspec.shouldBe` Just (-16777215)
      test $ f 16777216 `Hspec.shouldBe` Just 16777216
      test $ f (-16777216) `Hspec.shouldBe` Just (-16777216)
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Float Double" $ do
      let f = Witch.cast @Float @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 0.5 `Hspec.shouldBe` 0.5
      test $ f (-0.5) `Hspec.shouldBe` (-0.5)
      test $ f (0 / 0) `Hspec.shouldSatisfy` isNaN
      test $ f (1 / 0) `Hspec.shouldBe` (1 / 0)
      test $ f (-1 / 0) `Hspec.shouldBe` (-1 / 0)

    -- Double

    Hspec.describe "TryCast Double Int8" $ do
      let f = hush . Witch.tryCast @Double @Int.Int8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 127 `Hspec.shouldBe` Just 127
      test $ f 128 `Hspec.shouldBe` Nothing
      test $ f (-128) `Hspec.shouldBe` Just (-128)
      test $ f (-129) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Int16" $ do
      let f = hush . Witch.tryCast @Double @Int.Int16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 32767 `Hspec.shouldBe` Just 32767
      test $ f 32768 `Hspec.shouldBe` Nothing
      test $ f (-32768) `Hspec.shouldBe` Just (-32768)
      test $ f (-32769) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Int32" $ do
      let f = hush . Witch.tryCast @Double @Int.Int32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 2147483647 `Hspec.shouldBe` Just 2147483647
      test $ f 2147483648 `Hspec.shouldBe` Nothing
      test $ f (-2147483648) `Hspec.shouldBe` Just (-2147483648)
      test $ f (-2147483649) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Int64" $ do
      let f = hush . Witch.tryCast @Double @Int.Int64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (-9007199254740991) `Hspec.shouldBe` Just (-9007199254740991)
      test $ f (-9007199254740992) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Int" $ do
      Monad.when (toInteger (maxBound :: Int) < 9007199254740991) untested
      let f = hush . Witch.tryCast @Double @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (-9007199254740991) `Hspec.shouldBe` Just (-9007199254740991)
      test $ f (-9007199254740992) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Integer" $ do
      let f = hush . Witch.tryCast @Double @Integer
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (-9007199254740991) `Hspec.shouldBe` Just (-9007199254740991)
      test $ f (-9007199254740992) `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Word8" $ do
      let f = hush . Witch.tryCast @Double @Word.Word8
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 255 `Hspec.shouldBe` Just 255
      test $ f 256 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Word16" $ do
      let f = hush . Witch.tryCast @Double @Word.Word16
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 65535 `Hspec.shouldBe` Just 65535
      test $ f 65536 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Word32" $ do
      let f = hush . Witch.tryCast @Double @Word.Word32
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 4294967295 `Hspec.shouldBe` Just 4294967295
      test $ f 4294967296 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Word64" $ do
      let f = hush . Witch.tryCast @Double @Word.Word64
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Word" $ do
      Monad.when (toInteger (maxBound :: Word) < 9007199254740991) untested
      let f = hush . Witch.tryCast @Double @Word
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Natural" $ do
      let f = hush . Witch.tryCast @Double @Natural.Natural
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f 9007199254740992 `Hspec.shouldBe` Nothing
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "TryCast Double Rational" $ do
      let f = hush . Witch.tryCast @Double @Rational
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f (-0) `Hspec.shouldBe` Just 0
      test $ f 0.5 `Hspec.shouldBe` Just 0.5
      test $ f (-0.5) `Hspec.shouldBe` Just (-0.5)
      test $ f 9007199254740991 `Hspec.shouldBe` Just 9007199254740991
      test $ f (-9007199254740991) `Hspec.shouldBe` Just (-9007199254740991)
      test $ f 9007199254740992 `Hspec.shouldBe` Just 9007199254740992
      test $ f (-9007199254740992) `Hspec.shouldBe` Just (-9007199254740992)
      test $ f (0 / 0) `Hspec.shouldBe` Nothing
      test $ f (1 / 0) `Hspec.shouldBe` Nothing
      test $ f (-1 / 0) `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Double Float" $ do
      let f = Witch.cast @Double @Float
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 0.5 `Hspec.shouldBe` 0.5
      test $ f (-0.5) `Hspec.shouldBe` (-0.5)
      test $ f (0 / 0) `Hspec.shouldSatisfy` isNaN
      test $ f (1 / 0) `Hspec.shouldBe` (1 / 0)
      test $ f (-1 / 0) `Hspec.shouldBe` (-1 / 0)

    -- Ratio

    Hspec.describe "Cast a (Ratio a)" $ do
      test $ Witch.cast @Integer @Rational 0 `Hspec.shouldBe` 0
      let f = Witch.cast @Int @(Ratio.Ratio Int)
      test $ f 0 `Hspec.shouldBe` 0

    Hspec.describe "TryCast (Ratio a) a" $ do
      test $ hush (Witch.tryCast @Rational @Integer 0) `Hspec.shouldBe` Just 0
      test $ hush (Witch.tryCast @Rational @Integer 0.5) `Hspec.shouldBe` Nothing
      let f = hush . Witch.tryCast @(Ratio.Ratio Int) @Int
      test $ f 0 `Hspec.shouldBe` Just 0
      test $ f 0.5 `Hspec.shouldBe` Nothing

    Hspec.describe "Cast Rational Float" $ do
      let f = Witch.cast @Rational @Float
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 0.5 `Hspec.shouldBe` 0.5
      test $ f (-0.5) `Hspec.shouldBe` (-0.5)

    Hspec.describe "Cast Rational Double" $ do
      let f = Witch.cast @Rational @Double
      test $ f 0 `Hspec.shouldBe` 0
      test $ f 0.5 `Hspec.shouldBe` 0.5
      test $ f (-0.5) `Hspec.shouldBe` (-0.5)

    -- Fixed

    Hspec.describe "Cast Integer (Fixed a)" $ do
      test $ Witch.cast @Integer @Fixed.Uni 1 `Hspec.shouldBe` 1
      let f = Witch.cast @Integer @Fixed.Deci
      test $ f 1 `Hspec.shouldBe` 0.1

    Hspec.describe "Cast (Fixed a) Integer" $ do
      test $ Witch.cast @Fixed.Uni @Integer 1 `Hspec.shouldBe` 1
      let f = Witch.cast @Fixed.Deci @Integer
      test $ f 1 `Hspec.shouldBe` 10

    -- Complex

    Hspec.describe "Cast a (Complex a)" $ do
      test $ Witch.cast @Double @(Complex.Complex Double) 1 `Hspec.shouldBe` 1
      let f = Witch.cast @Float @(Complex.Complex Float)
      test $ f 1 `Hspec.shouldBe` 1

    Hspec.describe "TryCast (Complex a) a" $ do
      test $ hush (Witch.tryCast @(Complex.Complex Double) @Double 1) `Hspec.shouldBe` Just 1
      test $ hush (Witch.tryCast @(Complex.Complex Double) @Double (0 Complex.:+ 1)) `Hspec.shouldBe` Nothing
      let f = hush . Witch.tryCast @(Complex.Complex Float) @Float
      test $ f 1 `Hspec.shouldBe` Just 1
      test $ f (0 Complex.:+ 1) `Hspec.shouldBe` Nothing

    -- NonEmpty

    Hspec.describe "TryCast [a] (NonEmpty a)" $ do
      let f = hush . Witch.tryCast @[Int] @(NonEmpty.NonEmpty Int)
      test $ f [] `Hspec.shouldBe` Nothing
      test $ f [1] `Hspec.shouldBe` Just (1 NonEmpty.:| [])
      test $ f [1, 2] `Hspec.shouldBe` Just (1 NonEmpty.:| [2])

    Hspec.describe "Cast (NonEmpty a) [a]" $ do
      let f = Witch.cast @(NonEmpty.NonEmpty Int) @[Int]
      test $ f (1 NonEmpty.:| []) `Hspec.shouldBe` [1]
      test $ f (1 NonEmpty.:| [2]) `Hspec.shouldBe` [1, 2]

    -- Set

    Hspec.describe "Cast [a] (Set a)" $ do
      let f = Witch.cast @[Char] @(Set.Set Char)
      test $ f [] `Hspec.shouldBe` Set.fromList []
      test $ f ['a'] `Hspec.shouldBe` Set.fromList ['a']
      test $ f ['a', 'b'] `Hspec.shouldBe` Set.fromList ['a', 'b']
      test $ f ['a', 'a'] `Hspec.shouldBe` Set.fromList ['a']

    Hspec.describe "Cast (Set a) [a]" $ do
      let f = Witch.cast @(Set.Set Char) @[Char]
      test $ f (Set.fromList []) `Hspec.shouldBe` []
      test $ f (Set.fromList ['a']) `Hspec.shouldBe` ['a']
      test $ f (Set.fromList ['a', 'b']) `Hspec.shouldBe` ['a', 'b']

    -- IntSet

    Hspec.describe "Cast [Int] IntSet" $ do
      let f = Witch.cast @[Int] @IntSet.IntSet
      test $ f [] `Hspec.shouldBe` IntSet.fromList []
      test $ f [1] `Hspec.shouldBe` IntSet.fromList [1]
      test $ f [1, 2] `Hspec.shouldBe` IntSet.fromList [1, 2]

    Hspec.describe "Cast IntSet [Int]" $ do
      let f = Witch.cast @IntSet.IntSet @[Int]
      test $ f (IntSet.fromList []) `Hspec.shouldBe` []
      test $ f (IntSet.fromList [1]) `Hspec.shouldBe` [1]
      test $ f (IntSet.fromList [1, 2]) `Hspec.shouldBe` [1, 2]

    -- Map

    Hspec.describe "Cast [(k, v)] (Map k v)" $ do
      let f = Witch.cast @[(Char, Int)] @(Map.Map Char Int)
      test $ f [] `Hspec.shouldBe` Map.empty
      test $ f [('a', 1)] `Hspec.shouldBe` Map.fromList [('a', 1)]
      test $ f [('a', 1), ('b', 2)] `Hspec.shouldBe` Map.fromList [('a', 1), ('b', 2)]
      test $ f [('a', 1), ('a', 2)] `Hspec.shouldBe` Map.fromList [('a', 2)]

    Hspec.describe "Cast (Map k v) [(k, v)]" $ do
      let f = Witch.cast @(Map.Map Char Int) @[(Char, Int)]
      test $ f Map.empty `Hspec.shouldBe` []
      test $ f (Map.fromList [('a', 1)]) `Hspec.shouldBe` [('a', 1)]
      test $ f (Map.fromList [('a', 1), ('b', 2)]) `Hspec.shouldBe` [('a', 1), ('b', 2)]

    -- IntMap

    Hspec.describe "Cast [(Int, v)] (IntMap v)" $ do
      let f = Witch.cast @[(Int, Char)] @(IntMap.IntMap Char)
      test $ f [] `Hspec.shouldBe` IntMap.fromList []
      test $ f [(1, 'a')] `Hspec.shouldBe` IntMap.fromList [(1, 'a')]
      test $ f [(1, 'a'), (2, 'b')] `Hspec.shouldBe` IntMap.fromList [(1, 'a'), (2, 'b')]
      test $ f [(1, 'a'), (1, 'b')] `Hspec.shouldBe` IntMap.fromList [(1, 'b')]

    Hspec.describe "Cast (IntMap v) [(Int, v)]" $ do
      let f = Witch.cast @(IntMap.IntMap Char) @[(Int, Char)]
      test $ f (IntMap.fromList []) `Hspec.shouldBe` []
      test $ f (IntMap.fromList [(1, 'a')]) `Hspec.shouldBe` [(1, 'a')]
      test $ f (IntMap.fromList [(1, 'a'), (2, 'b')]) `Hspec.shouldBe` [(1, 'a'), (2, 'b')]

    -- Seq

    Hspec.describe "Cast [a] (Seq a)" $ do
      let f = Witch.cast @[Int] @(Seq.Seq Int)
      test $ f [] `Hspec.shouldBe` Seq.fromList []
      test $ f [1] `Hspec.shouldBe` Seq.fromList [1]
      test $ f [1, 2] `Hspec.shouldBe` Seq.fromList [1, 2]

    Hspec.describe "Cast (Seq a) [a]" $ do
      let f = Witch.cast @(Seq.Seq Int) @[Int]
      test $ f (Seq.fromList []) `Hspec.shouldBe` []
      test $ f (Seq.fromList [1]) `Hspec.shouldBe` [1]
      test $ f (Seq.fromList [1, 2]) `Hspec.shouldBe` [1, 2]

    -- ByteString

    Hspec.describe "Cast [Word8] ByteString" $ do
      let f = Witch.cast @[Word.Word8] @ByteString.ByteString
      test $ f [] `Hspec.shouldBe` ByteString.pack []
      test $ f [0x00] `Hspec.shouldBe` ByteString.pack [0x00]
      test $ f [0x0f, 0xf0] `Hspec.shouldBe` ByteString.pack [0x0f, 0xf0]

    Hspec.describe "Cast ByteString [Word8]" $ do
      let f = Witch.cast @ByteString.ByteString @[Word.Word8]
      test $ f (ByteString.pack []) `Hspec.shouldBe` []
      test $ f (ByteString.pack [0x00]) `Hspec.shouldBe` [0x00]
      test $ f (ByteString.pack [0x0f, 0xf0]) `Hspec.shouldBe` [0x0f, 0xf0]

    Hspec.describe "Cast ByteString LazyByteString" $ do
      let f = Witch.cast @ByteString.ByteString @LazyByteString.ByteString
      test $ f (ByteString.pack []) `Hspec.shouldBe` LazyByteString.pack []
      test $ f (ByteString.pack [0x00]) `Hspec.shouldBe` LazyByteString.pack [0x00]
      test $ f (ByteString.pack [0x0f, 0xf0]) `Hspec.shouldBe` LazyByteString.pack [0x0f, 0xf0]

    Hspec.describe "Cast ByteString ShortByteString" $ do
      let f = Witch.cast @ByteString.ByteString @ShortByteString.ShortByteString
      test $ f (ByteString.pack []) `Hspec.shouldBe` ShortByteString.pack []
      test $ f (ByteString.pack [0x00]) `Hspec.shouldBe` ShortByteString.pack [0x00]
      test $ f (ByteString.pack [0x0f, 0xf0]) `Hspec.shouldBe` ShortByteString.pack [0x0f, 0xf0]

    Hspec.describe "TryCast ByteString Text" $ do
      let f = hush . Witch.tryCast @ByteString.ByteString @Text.Text
      test $ f (ByteString.pack []) `Hspec.shouldBe` Just (Text.pack "")
      test $ f (ByteString.pack [0x61]) `Hspec.shouldBe` Just (Text.pack "a")
      test $ f (ByteString.pack [0xff]) `Hspec.shouldBe` Nothing

    -- LazyByteString

    Hspec.describe "Cast [Word8] LazyByteString" $ do
      let f = Witch.cast @[Word.Word8] @LazyByteString.ByteString
      test $ f [] `Hspec.shouldBe` LazyByteString.pack []
      test $ f [0x00] `Hspec.shouldBe` LazyByteString.pack [0x00]
      test $ f [0x0f, 0xf0] `Hspec.shouldBe` LazyByteString.pack [0x0f, 0xf0]

    Hspec.describe "Cast LazyByteString [Word8]" $ do
      let f = Witch.cast @LazyByteString.ByteString @[Word.Word8]
      test $ f (LazyByteString.pack []) `Hspec.shouldBe` []
      test $ f (LazyByteString.pack [0x00]) `Hspec.shouldBe` [0x00]
      test $ f (LazyByteString.pack [0x0f, 0xf0]) `Hspec.shouldBe` [0x0f, 0xf0]

    Hspec.describe "Cast LazyByteString ByteString" $ do
      let f = Witch.cast @LazyByteString.ByteString @ByteString.ByteString
      test $ f (LazyByteString.pack []) `Hspec.shouldBe` ByteString.pack []
      test $ f (LazyByteString.pack [0x00]) `Hspec.shouldBe` ByteString.pack [0x00]
      test $ f (LazyByteString.pack [0x0f, 0xf0]) `Hspec.shouldBe` ByteString.pack [0x0f, 0xf0]

    Hspec.describe "TryCast LazyByteString LazyText" $ do
      let f = hush . Witch.tryCast @LazyByteString.ByteString @LazyText.Text
      test $ f (LazyByteString.pack []) `Hspec.shouldBe` Just (LazyText.pack "")
      test $ f (LazyByteString.pack [0x61]) `Hspec.shouldBe` Just (LazyText.pack "a")
      test $ f (LazyByteString.pack [0xff]) `Hspec.shouldBe` Nothing

    -- ShortByteString

    Hspec.describe "Cast [Word8] ShortByteString" $ do
      let f = Witch.cast @[Word.Word8] @ShortByteString.ShortByteString
      test $ f [] `Hspec.shouldBe` ShortByteString.pack []
      test $ f [0x00] `Hspec.shouldBe` ShortByteString.pack [0x00]
      test $ f [0x0f, 0xf0] `Hspec.shouldBe` ShortByteString.pack [0x0f, 0xf0]

    Hspec.describe "Cast ShortByteString [Word8]" $ do
      let f = Witch.cast @ShortByteString.ShortByteString @[Word.Word8]
      test $ f (ShortByteString.pack []) `Hspec.shouldBe` []
      test $ f (ShortByteString.pack [0x00]) `Hspec.shouldBe` [0x00]
      test $ f (ShortByteString.pack [0x0f, 0xf0]) `Hspec.shouldBe` [0x0f, 0xf0]

    Hspec.describe "Cast ShortByteString ByteString" $ do
      let f = Witch.cast @ShortByteString.ShortByteString @ByteString.ByteString
      test $ f (ShortByteString.pack []) `Hspec.shouldBe` ByteString.pack []
      test $ f (ShortByteString.pack [0x00]) `Hspec.shouldBe` ByteString.pack [0x00]
      test $ f (ShortByteString.pack [0x0f, 0xf0]) `Hspec.shouldBe` ByteString.pack [0x0f, 0xf0]

    -- Text

    Hspec.describe "Cast String Text" $ do
      let f = Witch.cast @String @Text.Text
      test $ f "" `Hspec.shouldBe` Text.pack ""
      test $ f "a" `Hspec.shouldBe` Text.pack "a"
      test $ f "ab" `Hspec.shouldBe` Text.pack "ab"

    Hspec.describe "Cast Text String" $ do
      let f = Witch.cast @Text.Text @String
      test $ f (Text.pack "") `Hspec.shouldBe` ""
      test $ f (Text.pack "a") `Hspec.shouldBe` "a"
      test $ f (Text.pack "ab") `Hspec.shouldBe` "ab"

    Hspec.describe "Cast Text LazyText" $ do
      let f = Witch.cast @Text.Text @LazyText.Text
      test $ f (Text.pack "") `Hspec.shouldBe` LazyText.pack ""
      test $ f (Text.pack "a") `Hspec.shouldBe` LazyText.pack "a"
      test $ f (Text.pack "ab") `Hspec.shouldBe` LazyText.pack "ab"

    Hspec.describe "Cast Text ByteString" $ do
      let f = Witch.cast @Text.Text @ByteString.ByteString
      test $ f (Text.pack "") `Hspec.shouldBe` ByteString.pack []
      test $ f (Text.pack "a") `Hspec.shouldBe` ByteString.pack [0x61]

    -- LazyText

    Hspec.describe "Cast String LazyText" $ do
      let f = Witch.cast @String @LazyText.Text
      test $ f "" `Hspec.shouldBe` LazyText.pack ""
      test $ f "a" `Hspec.shouldBe` LazyText.pack "a"
      test $ f "ab" `Hspec.shouldBe` LazyText.pack "ab"

    Hspec.describe "Cast LazyText String" $ do
      let f = Witch.cast @LazyText.Text @String
      test $ f (LazyText.pack "") `Hspec.shouldBe` ""
      test $ f (LazyText.pack "a") `Hspec.shouldBe` "a"
      test $ f (LazyText.pack "ab") `Hspec.shouldBe` "ab"

    Hspec.describe "Cast LazyText Text" $ do
      let f = Witch.cast @LazyText.Text @Text.Text
      test $ f (LazyText.pack "") `Hspec.shouldBe` Text.pack ""
      test $ f (LazyText.pack "a") `Hspec.shouldBe` Text.pack "a"
      test $ f (LazyText.pack "ab") `Hspec.shouldBe` Text.pack "ab"

    Hspec.describe "Cast LazyText LazyByteString" $ do
      let f = Witch.cast @LazyText.Text @LazyByteString.ByteString
      test $ f (LazyText.pack "") `Hspec.shouldBe` LazyByteString.pack []
      test $ f (LazyText.pack "a") `Hspec.shouldBe` LazyByteString.pack [0x61]

    -- TryCastException

    Hspec.describe "Cast (TryCastException s t0) (TryCastException s t1)" $ do
      Hspec.it "needs tests" Hspec.pending

    Hspec.describe "Cast (TryCastException s t) String" $ do
      test $ Witch.cast (Witch.TryCastException Nothing Nothing :: Witch.TryCastException (Maybe Bool) (Maybe Int)) `Hspec.shouldBe` "TryCastException @(Maybe Bool) @(Maybe Int) Nothing Nothing"
      let f = Witch.cast @(Witch.TryCastException Bool Int) @String
      test $ f (Witch.TryCastException False Nothing) `Hspec.shouldBe` "TryCastException @Bool @Int False Nothing"

    Hspec.describe "Cast (TryCastException s t) Text" $ do
      let f = Witch.cast @(Witch.TryCastException Bool Int) @Text.Text
      test $ f (Witch.TryCastException False Nothing) `Hspec.shouldBe` Text.pack "TryCastException @Bool @Int False Nothing"

    Hspec.describe "Cast (TryCastException s t) LazyText" $ do
      let f = Witch.cast @(Witch.TryCastException Bool Int) @LazyText.Text
      test $ f (Witch.TryCastException False Nothing) `Hspec.shouldBe` LazyText.pack "TryCastException @Bool @Int False Nothing"

test :: Hspec.Example a => a -> Hspec.SpecWith (Hspec.Arg a)
test = Hspec.it ""

untested :: Hspec.SpecWith a
untested = Hspec.runIO $ Exception.throwIO Untested

hush :: Either x a -> Maybe a
hush = either (const Nothing) Just

data Untested
  = Untested
  deriving (Eq, Show)

instance Exception.Exception Untested

newtype Name
  = Name String
  deriving (Eq, Show)

instance Witch.Cast Name String

instance Witch.Cast String Name