{-# OPTIONS_GHC -Wno-error=overflowed-literals #-}

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

import qualified Control.Exception as Exception
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.Either as Either
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.Time as Time
import qualified Data.Time.Clock.POSIX as Time
import qualified Data.Time.Clock.System as Time
import qualified Data.Time.Clock.TAI as Time
import qualified Data.Word as Word
import qualified Numeric.Natural as Natural
import Test.HUnit (Test(TestCase), assertBool, runTestTTAndExit, (~:), (~?=))
import qualified Witch

main :: IO ()
main =
  runTestTTAndExit
    $ "Witch"
    ~: [ "From"
         ~: ["from" ~: [Witch.from (1 :: Int.Int8) ~?= (1 :: Int.Int16)]]
       , "TryFrom"
         ~: [ "tryFrom"
                ~: let f = hush . Witch.tryFrom @Int.Int16 @Int.Int8
                   in [f 1 ~?= Just 1, f 128 ~?= Nothing]
            ]
       , "Utility"
         ~: [ "as" ~: [Witch.as @Int.Int8 1 ~?= 1]
            , "from" ~: [Witch.from @Int.Int8 1 ~?= (1 :: Int.Int16)]
            , "into" ~: [Witch.into @Int.Int16 (1 :: Int.Int8) ~?= 1]
            , "over" ~: [Witch.over @Int.Int8 (+ 1) (Age 1) ~?= Age 2]
            , "via"
              ~: [Witch.via @Int.Int16 (1 :: Int.Int8) ~?= (1 :: Int.Int32)]
            , "tryFrom"
              ~: [hush (Witch.tryFrom @Int.Int16 1) ~?= Just (1 :: Int.Int8)]
            , "tryInto"
              ~: [hush (Witch.tryInto @Int.Int8 (1 :: Int.Int16)) ~?= Just 1]
            , "tryVia"
              ~: let f = Witch.tryVia @Int.Int16 @Int.Int32 @Int.Int8
                 in
                   [ hush (f 1) ~?= Just 1
                   , hush (f 128) ~?= Nothing
                   , hush (f 32768) ~?= Nothing
                   ]
            , "unsafeFrom"
              ~: let f = Witch.unsafeFrom @Int.Int16 @Int.Int8
                 in
                   [ f 1 ~?= 1
                   , TestCase $ do
                     result <-
                       Exception.try @Exception.SomeException
                       . Exception.evaluate
                       $ f 128
                     assertBool (show result) $ Either.isLeft result
                   ]
            , "unsafeInto"
              ~: [Witch.unsafeInto @Int.Int8 (1 :: Int.Int16) ~?= 1]
            ]
       , "Lift"
         ~: [ "liftedFrom"
              ~: [($$(Witch.liftedFrom (1 :: Int.Int16)) :: Int.Int8) ~?= 1]
            , "liftedInto"
              ~: [$$(Witch.liftedInto @Int.Int8 (1 :: Int.Int16)) ~?= 1]
            ]
       , "TryFromException"
         ~: [ "show"
                ~: [ show (Witch.TryFromException @Int @Int 0 Nothing)
                     ~?= "TryFromException @Int @Int 0 Nothing"
                   , show
                       (Witch.TryFromException @(Seq.Seq Int) @(Seq.Seq Int)
                         (Seq.fromList [])
                         (Just (Exception.toException Exception.Overflow))
                       )
                     ~?= "TryFromException @(Seq Int) @(Seq Int) (fromList []) (Just arithmetic overflow)"
                   ]
            ]
       , "Instances"
         ~: [ "From a a" ~: let f = Witch.from @Int @Int in [f 0 ~?= 0]

    -- Int8
            , "From Int8 Int16"
              ~: let f = Witch.from @Int.Int8 @Int.Int16
                 in [f 0 ~?= 0, f 127 ~?= 127, f (-128) ~?= (-128)]
            , "From Int8 Int32"
              ~: let f = Witch.from @Int.Int8 @Int.Int32
                 in [f 0 ~?= 0, f 127 ~?= 127, f (-128) ~?= (-128)]
            , "From Int8 Int64"
              ~: let f = Witch.from @Int.Int8 @Int.Int64
                 in [f 0 ~?= 0, f 127 ~?= 127, f (-128) ~?= (-128)]
            , "From Int8 Int"
              ~: let f = Witch.from @Int.Int8 @Int
                 in [f 0 ~?= 0, f 127 ~?= 127, f (-128) ~?= (-128)]
            , "From Int8 Integer"
              ~: let f = Witch.from @Int.Int8 @Integer
                 in [f 0 ~?= 0, f 127 ~?= 127, f (-128) ~?= (-128)]
            , "TryFrom Int8 Word8"
              ~: let f = hush . Witch.tryFrom @Int.Int8 @Word.Word8
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f (-1) ~?= Nothing]
            , "TryFrom Int8 Word16"
              ~: let f = hush . Witch.tryFrom @Int.Int8 @Word.Word16
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f (-1) ~?= Nothing]
            , "TryFrom Int8 Word32"
              ~: let f = hush . Witch.tryFrom @Int.Int8 @Word.Word32
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f (-1) ~?= Nothing]
            , "TryFrom Int8 Word64"
              ~: let f = hush . Witch.tryFrom @Int.Int8 @Word.Word64
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f (-1) ~?= Nothing]
            , "TryFrom Int8 Word"
              ~: let f = hush . Witch.tryFrom @Int.Int8 @Word
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f (-1) ~?= Nothing]
            , "TryFrom Int8 Natural"
              ~: let f = hush . Witch.tryFrom @Int.Int8 @Natural.Natural
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f (-1) ~?= Nothing]
            , "From Int8 Float"
              ~: let f = Witch.from @Int.Int8 @Float
                 in [f 0 ~?= 0, f 127 ~?= 127, f (-128) ~?= (-128)]
            , "From Int8 Double"
              ~: let f = Witch.from @Int.Int8 @Double
                 in [f 0 ~?= 0, f 127 ~?= 127, f (-128) ~?= (-128)]

    -- Int16
            , "TryFrom Int16 Int8"
              ~: let f = hush . Witch.tryFrom @Int.Int16 @Int.Int8
                 in
                   [ f 0 ~?= Just 0
                   , f 127 ~?= Just 127
                   , f 128 ~?= Nothing
                   , f (-128) ~?= Just (-128)
                   , f (-129) ~?= Nothing
                   ]
            , "From Int16 Int32"
              ~: let f = Witch.from @Int.Int16 @Int.Int32
                 in [f 0 ~?= 0, f 32767 ~?= 32767, f (-32768) ~?= (-32768)]
            , "From Int16 Int64"
              ~: let f = Witch.from @Int.Int16 @Int.Int64
                 in [f 0 ~?= 0, f 32767 ~?= 32767, f (-32768) ~?= (-32768)]
            , "From Int16 Int"
              ~: let f = Witch.from @Int.Int16 @Int
                 in [f 0 ~?= 0, f 32767 ~?= 32767, f (-32768) ~?= (-32768)]
            , "From Int16 Integer"
              ~: let f = Witch.from @Int.Int16 @Integer
                 in [f 0 ~?= 0, f 32767 ~?= 32767, f (-32768) ~?= (-32768)]
            , "TryFrom Int16 Word8"
              ~: let f = hush . Witch.tryFrom @Int.Int16 @Word.Word8
                 in
                   [ f 0 ~?= Just 0
                   , f 255 ~?= Just 255
                   , f 256 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int16 Word16"
              ~: let f = hush . Witch.tryFrom @Int.Int16 @Word.Word16
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f (-1) ~?= Nothing]
            , "TryFrom Int16 Word32"
              ~: let f = hush . Witch.tryFrom @Int.Int16 @Word.Word32
                 in
                   [f 0 ~?= Just 0, f 32767 ~?= Just 32767, f (-1) ~?= Nothing]
            , "TryFrom Int16 Word64"
              ~: let f = hush . Witch.tryFrom @Int.Int16 @Word.Word64
                 in
                   [f 0 ~?= Just 0, f 32767 ~?= Just 32767, f (-1) ~?= Nothing]
            , "TryFrom Int16 Word"
              ~: let f = hush . Witch.tryFrom @Int.Int16 @Word
                 in
                   [f 0 ~?= Just 0, f 32767 ~?= Just 32767, f (-1) ~?= Nothing]
            , "TryFrom Int16 Natural"
              ~: let f = hush . Witch.tryFrom @Int.Int16 @Natural.Natural
                 in
                   [f 0 ~?= Just 0, f 32767 ~?= Just 32767, f (-1) ~?= Nothing]
            , "From Int16 Float"
              ~: let f = Witch.from @Int.Int16 @Float
                 in [f 0 ~?= 0, f 32767 ~?= 32767, f (-32768) ~?= (-32768)]
            , "From Int16 Double"
              ~: let f = Witch.from @Int.Int16 @Double
                 in [f 0 ~?= 0, f 32767 ~?= 32767, f (-32768) ~?= (-32768)]

    -- Int32
            , "TryFrom Int32 Int8"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Int.Int8
                 in
                   [ f 0 ~?= Just 0
                   , f 127 ~?= Just 127
                   , f 128 ~?= Nothing
                   , f (-128) ~?= Just (-128)
                   , f (-129) ~?= Nothing
                   ]
            , "TryFrom Int32 Int16"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   , f (-32768) ~?= Just (-32768)
                   , f (-32769) ~?= Nothing
                   ]
            , "From Int32 Int64"
              ~: let f = Witch.from @Int.Int32 @Int.Int64
                 in
                   [ f 0 ~?= 0
                   , f 2147483647 ~?= 2147483647
                   , f (-2147483648) ~?= (-2147483648)
                   ]
            , "TryFrom Int32 Int"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Int
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f (-2147483648) ~?= Just (-2147483648)
                   ]
            , "From Int32 Integer"
              ~: let f = Witch.from @Int.Int32 @Integer
                 in
                   [ f 0 ~?= 0
                   , f 2147483647 ~?= 2147483647
                   , f (-2147483648) ~?= (-2147483648)
                   ]
            , "TryFrom Int32 Word8"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Word.Word8
                 in
                   [ f 0 ~?= Just 0
                   , f 255 ~?= Just 255
                   , f 256 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int32 Word16"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int32 Word32"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int32 Word64"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Word.Word64
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int32 Word"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Word
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int32 Natural"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Natural.Natural
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int32 Float"
              ~: let f = hush . Witch.tryFrom @Int.Int32 @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   ]
            , "From Int32 Double"
              ~: let f = Witch.from @Int.Int32 @Double
                 in
                   [ f 0 ~?= 0
                   , f 2147483647 ~?= 2147483647
                   , f (-2147483648) ~?= (-2147483648)
                   ]

    -- Int64
            , "TryFrom Int64 Int8"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Int.Int8
                 in
                   [ f 0 ~?= Just 0
                   , f 127 ~?= Just 127
                   , f 128 ~?= Nothing
                   , f (-128) ~?= Just (-128)
                   , f (-129) ~?= Nothing
                   ]
            , "TryFrom Int64 Int16"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   , f (-32768) ~?= Just (-32768)
                   , f (-32769) ~?= Nothing
                   ]
            , "TryFrom Int64 Int32"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f 2147483648 ~?= Nothing
                   , f (-2147483648) ~?= Just (-2147483648)
                   , f (-2147483649) ~?= Nothing
                   ]
            , "TryFrom Int64 Int"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Int
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 9223372036854775807
                         then f 9223372036854775807
                           ~?= Just 9223372036854775807
                         else f (fromIntegral x) ~?= Just x
                   , let x = minBound :: Int
                     in
                       if toInteger x <= (-9223372036854775808)
                         then f (-9223372036854775808)
                           ~?= Just (-9223372036854775808)
                         else f (fromIntegral x) ~?= Just x
                   ]
            , "From Int64 Integer"
              ~: let f = Witch.from @Int.Int64 @Integer
                 in
                   [ f 0 ~?= 0
                   , f 9223372036854775807 ~?= 9223372036854775807
                   , f (-9223372036854775808) ~?= (-9223372036854775808)
                   ]
            , "TryFrom Int64 Word8"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Word.Word8
                 in
                   [ f 0 ~?= Just 0
                   , f 255 ~?= Just 255
                   , f 256 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int64 Word16"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int64 Word32"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int64 Word64"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Word.Word64
                 in
                   [ f 0 ~?= Just 0
                   , f 9223372036854775807 ~?= Just 9223372036854775807
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int64 Word"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Word
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 9223372036854775807
                         then f 9223372036854775807
                           ~?= Just 9223372036854775807
                         else f (fromIntegral x) ~?= Just x
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int64 Natural"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Natural.Natural
                 in
                   [ f 0 ~?= Just 0
                   , f 9223372036854775807 ~?= Just 9223372036854775807
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int64 Float"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   ]
            , "TryFrom Int64 Double"
              ~: let f = hush . Witch.tryFrom @Int.Int64 @Double
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   , f (-9007199254740991) ~?= Just (-9007199254740991)
                   , f (-9007199254740992) ~?= Nothing
                   ]

    -- Int
            , "TryFrom Int Int8"
              ~: let f = hush . Witch.tryFrom @Int @Int.Int8
                 in
                   [ f 0 ~?= Just 0
                   , f 127 ~?= Just 127
                   , f 128 ~?= Nothing
                   , f (-128) ~?= Just (-128)
                   , f (-129) ~?= Nothing
                   ]
            , "TryFrom Int Int16"
              ~: let f = hush . Witch.tryFrom @Int @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   , f (-32768) ~?= Just (-32768)
                   , f (-32769) ~?= Nothing
                   ]
            , "TryFrom Int Int32"
              ~: let f = hush . Witch.tryFrom @Int @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 2147483648
                         then f 2147483648 ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   , f (-2147483648) ~?= Just (-2147483648)
                   , let x = minBound :: Int
                     in
                       if toInteger x <= (-2147483649)
                         then f (-2147483649) ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   ]
            , "From Int Int64"
              ~: let f = Witch.from @Int @Int.Int64
                 in
                   [ f 0 ~?= 0
                   , f maxBound ~?= fromIntegral (maxBound :: Int)
                   , f minBound ~?= fromIntegral (minBound :: Int)
                   ]
            , "From Int Integer"
              ~: let f = Witch.from @Int @Integer
                 in
                   [ f 0 ~?= 0
                   , f maxBound ~?= fromIntegral (maxBound :: Int)
                   , f minBound ~?= fromIntegral (minBound :: Int)
                   ]
            , "TryFrom Int Word8"
              ~: let f = hush . Witch.tryFrom @Int @Word.Word8
                 in
                   [ f 0 ~?= Just 0
                   , f 255 ~?= Just 255
                   , f 256 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int Word16"
              ~: let f = hush . Witch.tryFrom @Int @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int Word32"
              ~: let f = hush . Witch.tryFrom @Int @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 4294967295
                         then f 4294967295 ~?= Just 4294967295
                         else f x ~?= Just (fromIntegral x)
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 4294967296
                         then f 4294967296 ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int Word64"
              ~: let f = hush . Witch.tryFrom @Int @Word.Word64
                 in
                   [ f 0 ~?= Just 0
                   , f maxBound ~?= Just (fromIntegral (maxBound :: Int))
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int Word"
              ~: let f = hush . Witch.tryFrom @Int @Word
                 in
                   [ f 0 ~?= Just 0
                   , f maxBound ~?= Just (fromIntegral (maxBound :: Int))
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int Natural"
              ~: let f = hush . Witch.tryFrom @Int @Natural.Natural
                 in
                   [ f 0 ~?= Just 0
                   , f maxBound ~?= Just (fromIntegral (maxBound :: Int))
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Int Float"
              ~: let f = hush . Witch.tryFrom @Int @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   ]
            , "TryFrom Int Double"
              ~: let f = hush . Witch.tryFrom @Int @Double
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 9007199254740991
                         then f 9007199254740991 ~?= Just 9007199254740991
                         else f x ~?= Just (fromIntegral x)
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 9007199254740992
                         then f 9007199254740992 ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   , let x = minBound :: Int
                     in
                       if toInteger x <= (-9007199254740991)
                         then f (-9007199254740991)
                           ~?= Just (-9007199254740991)
                         else f x ~?= Just (fromIntegral x)
                   , let x = minBound :: Int
                     in
                       if toInteger x <= (-9007199254740992)
                         then f (-9007199254740992) ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   ]

    -- Integer
            , "TryFrom Integer Int8"
              ~: let f = hush . Witch.tryFrom @Integer @Int.Int8
                 in
                   [ f 0 ~?= Just 0
                   , f 127 ~?= Just 127
                   , f 128 ~?= Nothing
                   , f (-128) ~?= Just (-128)
                   , f (-129) ~?= Nothing
                   ]
            , "TryFrom Integer Int16"
              ~: let f = hush . Witch.tryFrom @Integer @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   , f (-32768) ~?= Just (-32768)
                   , f (-32769) ~?= Nothing
                   ]
            , "TryFrom Integer Int32"
              ~: let f = hush . Witch.tryFrom @Integer @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f 2147483648 ~?= Nothing
                   , f (-2147483648) ~?= Just (-2147483648)
                   , f (-2147483649) ~?= Nothing
                   ]
            , "TryFrom Integer Int64"
              ~: let f = hush . Witch.tryFrom @Integer @Int.Int64
                 in
                   [ f 0 ~?= Just 0
                   , f 9223372036854775807 ~?= Just 9223372036854775807
                   , f 9223372036854775808 ~?= Nothing
                   , f (-9223372036854775808) ~?= Just (-9223372036854775808)
                   , f (-9223372036854775809) ~?= Nothing
                   ]
            , "TryFrom Integer Int"
              ~: let f = hush . Witch.tryFrom @Integer @Int
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int in f (fromIntegral x) ~?= Just x
                   , let x = toInteger (maxBound :: Int) + 1
                     in f x ~?= Nothing
                   , let x = minBound :: Int in f (fromIntegral x) ~?= Just x
                   , let x = toInteger (minBound :: Int) - 1
                     in f x ~?= Nothing
                   ]
            , "TryFrom Integer Word8"
              ~: let f = hush . Witch.tryFrom @Integer @Word.Word8
                 in
                   [ f 0 ~?= Just 0
                   , f 255 ~?= Just 255
                   , f 256 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Integer Word16"
              ~: let f = hush . Witch.tryFrom @Integer @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Integer Word32"
              ~: let f = hush . Witch.tryFrom @Integer @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 4294967295 ~?= Just 4294967295
                   , f 4294967296 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Integer Word64"
              ~: let f = hush . Witch.tryFrom @Integer @Word.Word64
                 in
                   [ f 0 ~?= Just 0
                   , f 18446744073709551615 ~?= Just 18446744073709551615
                   , f 18446744073709551616 ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Integer Word"
              ~: let f = hush . Witch.tryFrom @Integer @Word
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Word in f (fromIntegral x) ~?= Just x
                   , let x = toInteger (maxBound :: Word) + 1
                     in f x ~?= Nothing
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Integer Natural"
              ~: let f = hush . Witch.tryFrom @Integer @Natural.Natural
                 in
                   [ f 0 ~?= Just 0
                   , f 18446744073709551616 ~?= Just 18446744073709551616
                   , f (-1) ~?= Nothing
                   ]
            , "TryFrom Integer Float"
              ~: let f = hush . Witch.tryFrom @Integer @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   ]
            , "TryFrom Integer Double"
              ~: let f = hush . Witch.tryFrom @Integer @Double
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   , f (-9007199254740991) ~?= Just (-9007199254740991)
                   , f (-9007199254740992) ~?= Nothing
                   ]

    -- Word8
            , "From Word8 Word16"
              ~: let f = Witch.from @Word.Word8 @Word.Word16
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Word32"
              ~: let f = Witch.from @Word.Word8 @Word.Word32
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Word64"
              ~: let f = Witch.from @Word.Word8 @Word.Word64
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Word"
              ~: let f = Witch.from @Word.Word8 @Word
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Natural"
              ~: let f = Witch.from @Word.Word8 @Natural.Natural
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "TryFrom Word8 Int8"
              ~: let f = hush . Witch.tryFrom @Word.Word8 @Int.Int8
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f 128 ~?= Nothing]
            , "From Word8 Int16"
              ~: let f = Witch.from @Word.Word8 @Int.Int16
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Int32"
              ~: let f = Witch.from @Word.Word8 @Int.Int32
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Int64"
              ~: let f = Witch.from @Word.Word8 @Int.Int64
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Int"
              ~: let f = Witch.from @Word.Word8 @Int
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Integer"
              ~: let f = Witch.from @Word.Word8 @Integer
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Float"
              ~: let f = Witch.from @Word.Word8 @Float
                 in [f 0 ~?= 0, f 255 ~?= 255]
            , "From Word8 Double"
              ~: let f = Witch.from @Word.Word8 @Double
                 in [f 0 ~?= 0, f 255 ~?= 255]

    -- Word16
            , "TryFrom Word16 Word8"
              ~: let f = hush . Witch.tryFrom @Word.Word16 @Word.Word8
                 in [f 0 ~?= Just 0, f 255 ~?= Just 255, f 256 ~?= Nothing]
            , "From Word16 Word32"
              ~: let f = Witch.from @Word.Word16 @Word.Word32
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Word64"
              ~: let f = Witch.from @Word.Word16 @Word.Word64
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Word"
              ~: let f = Witch.from @Word.Word16 @Word
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Natural"
              ~: let f = Witch.from @Word.Word16 @Natural.Natural
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "TryFrom Word16 Int8"
              ~: let f = hush . Witch.tryFrom @Word.Word16 @Int.Int8
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f 128 ~?= Nothing]
            , "TryFrom Word16 Int16"
              ~: let f = hush . Witch.tryFrom @Word.Word16 @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   ]
            , "From Word16 Int32"
              ~: let f = Witch.from @Word.Word16 @Int.Int32
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Int64"
              ~: let f = Witch.from @Word.Word16 @Int.Int64
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Int"
              ~: let f = Witch.from @Word.Word16 @Int
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Integer"
              ~: let f = Witch.from @Word.Word16 @Integer
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Float"
              ~: let f = Witch.from @Word.Word16 @Float
                 in [f 0 ~?= 0, f 65535 ~?= 65535]
            , "From Word16 Double"
              ~: let f = Witch.from @Word.Word16 @Double
                 in [f 0 ~?= 0, f 65535 ~?= 65535]

    -- Word32
            , "TryFrom Word32 Word8"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Word.Word8
                 in [f 0 ~?= Just 0, f 255 ~?= Just 255, f 256 ~?= Nothing]
            , "TryFrom Word32 Word16"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   ]
            , "From Word32 Word64"
              ~: let f = Witch.from @Word.Word32 @Word.Word64
                 in [f 0 ~?= 0, f 4294967295 ~?= 4294967295]
            , "TryFrom Word32 Word"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Word
                 in [f 0 ~?= Just 0, f 4294967295 ~?= Just 4294967295]
            , "From Word32 Natural"
              ~: let f = Witch.from @Word.Word32 @Natural.Natural
                 in [f 0 ~?= 0, f 4294967295 ~?= 4294967295]
            , "TryFrom Word32 Int8"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Int.Int8
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f 128 ~?= Nothing]
            , "TryFrom Word32 Int16"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   ]
            , "TryFrom Word32 Int32"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f 2147483648 ~?= Nothing
                   ]
            , "From Word32 Int64"
              ~: let f = Witch.from @Word.Word32 @Int.Int64
                 in [f 0 ~?= 0, f 4294967295 ~?= 4294967295]
            , "TryFrom Word32 Int"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Int
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 4294967295
                         then f 4294967295 ~?= Just 4294967295
                         else f (fromIntegral x) ~?= Just x
                   ]
            , "From Word32 Integer"
              ~: let f = Witch.from @Word.Word32 @Integer
                 in [f 0 ~?= 0, f 4294967295 ~?= 4294967295]
            , "TryFrom Word32 Float"
              ~: let f = hush . Witch.tryFrom @Word.Word32 @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   ]
            , "From Word32 Double"
              ~: let f = Witch.from @Word.Word32 @Double
                 in [f 0 ~?= 0, f 4294967295 ~?= 4294967295]

    -- Word64
            , "TryFrom Word64 Word8"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Word.Word8
                 in [f 0 ~?= Just 0, f 255 ~?= Just 255, f 256 ~?= Nothing]
            , "TryFrom Word64 Word16"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   ]
            , "TryFrom Word64 Word32"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 4294967295 ~?= Just 4294967295
                   , f 4294967296 ~?= Nothing
                   ]
            , "TryFrom Word64 Word"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Word
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 18446744073709551615
                         then f 18446744073709551615
                           ~?= Just 18446744073709551615
                         else f (fromIntegral x) ~?= Just x
                   ]
            , "From Word64 Natural"
              ~: let f = Witch.from @Word.Word64 @Natural.Natural
                 in
                   [f 0 ~?= 0, f 18446744073709551615 ~?= 18446744073709551615]
            , "TryFrom Word64 Int8"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Int.Int8
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f 128 ~?= Nothing]
            , "TryFrom Word64 Int16"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   ]
            , "TryFrom Word64 Int32"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f 2147483648 ~?= Nothing
                   ]
            , "TryFrom Word64 Int64"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Int.Int64
                 in
                   [ f 0 ~?= Just 0
                   , f 9223372036854775807 ~?= Just 9223372036854775807
                   , f 9223372036854775808 ~?= Nothing
                   ]
            , "TryFrom Word64 Int"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Int
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       hush (Witch.tryFrom @Word.Word64 @Int (fromIntegral x))
                         ~?= Just x
                   , let x = fromIntegral (maxBound :: Int) + 1 :: Word.Word64
                     in hush (Witch.tryFrom @Word.Word64 @Int x) ~?= Nothing
                   ]
            , "From Word64 Integer"
              ~: let f = Witch.from @Word.Word64 @Integer
                 in
                   [f 0 ~?= 0, f 18446744073709551615 ~?= 18446744073709551615]
            , "TryFrom Word64 Float"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   ]
            , "TryFrom Word64 Double"
              ~: let f = hush . Witch.tryFrom @Word.Word64 @Double
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   ]

    -- Word
            , "TryFrom Word Word8"
              ~: let f = hush . Witch.tryFrom @Word @Word.Word8
                 in [f 0 ~?= Just 0, f 255 ~?= Just 255, f 256 ~?= Nothing]
            , "TryFrom Word Word16"
              ~: let f = hush . Witch.tryFrom @Word @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   ]
            , "TryFrom Word Word32"
              ~: let f = hush . Witch.tryFrom @Word @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 4294967295 ~?= Just 4294967295
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 4294967296
                         then f 4294967296 ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   ]
            , "From Word Word64"
              ~: let f = Witch.from @Word @Word.Word64
                 in [f 0 ~?= 0, f maxBound ~?= fromIntegral (maxBound :: Word)]
            , "From Word Natural"
              ~: let f = Witch.from @Word @Natural.Natural
                 in [f 0 ~?= 0, f maxBound ~?= fromIntegral (maxBound :: Word)]
            , "TryFrom Word Int8"
              ~: let f = hush . Witch.tryFrom @Word @Int.Int8
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f 128 ~?= Nothing]
            , "TryFrom Word Int16"
              ~: let f = hush . Witch.tryFrom @Word @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   ]
            , "TryFrom Word Int32"
              ~: let f = hush . Witch.tryFrom @Word @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f 2147483648 ~?= Nothing
                   ]
            , "TryFrom Word Int64"
              ~: let f = hush . Witch.tryFrom @Word @Int.Int64
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 9223372036854775807
                         then f 9223372036854775807
                           ~?= Just 9223372036854775807
                         else f x ~?= Just (fromIntegral x)
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 9223372036854775808
                         then f 9223372036854775808 ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   ]
            , "TryFrom Word Int"
              ~: let f = hush . Witch.tryFrom @Word @Int
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       hush (Witch.tryFrom @Word @Int (fromIntegral x))
                         ~?= Just x
                   , let x = fromIntegral (maxBound :: Int) + 1 :: Word
                     in hush (Witch.tryFrom @Word @Int x) ~?= Nothing
                   ]
            , "From Word Integer"
              ~: let f = Witch.from @Word @Integer
                 in [f 0 ~?= 0, f maxBound ~?= fromIntegral (maxBound :: Word)]
            , "TryFrom Word Float"
              ~: let f = hush . Witch.tryFrom @Word @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   ]
            , "TryFrom Word Double"
              ~: let f = hush . Witch.tryFrom @Word @Double
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 9007199254740991
                         then f 9007199254740991 ~?= Just 9007199254740991
                         else f x ~?= Just (fromIntegral x)
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 9007199254740992
                         then f 9007199254740992 ~?= Nothing
                         else f x ~?= Just (fromIntegral x)
                   ]

    -- Natural
            , "TryFrom Natural Word8"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Word.Word8
                 in [f 0 ~?= Just 0, f 255 ~?= Just 255, f 256 ~?= Nothing]
            , "TryFrom Natural Word16"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   ]
            , "TryFrom Natural Word32"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 4294967295 ~?= Just 4294967295
                   , f 4294967296 ~?= Nothing
                   ]
            , "TryFrom Natural Word64"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Word.Word64
                 in
                   [ f 0 ~?= Just 0
                   , f 18446744073709551615 ~?= Just 18446744073709551615
                   , f 18446744073709551616 ~?= Nothing
                   ]
            , "TryFrom Natural Word"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Word
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Word
                     in
                       hush
                           (Witch.tryFrom @Natural.Natural @Word
                             (fromIntegral x)
                           )
                         ~?= Just x
                   , let
                       x =
                         fromIntegral (maxBound :: Word) + 1 :: Natural.Natural
                     in
                       hush (Witch.tryFrom @Natural.Natural @Word x)
                         ~?= Nothing
                   ]
            , "TryFrom Natural Int8"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Int.Int8
                 in [f 0 ~?= Just 0, f 127 ~?= Just 127, f 128 ~?= Nothing]
            , "TryFrom Natural Int16"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   ]
            , "TryFrom Natural Int32"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f 2147483648 ~?= Nothing
                   ]
            , "TryFrom Natural Int64"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Int.Int64
                 in
                   [ f 0 ~?= Just 0
                   , f 9223372036854775807 ~?= Just 9223372036854775807
                   , f 9223372036854775808 ~?= Nothing
                   ]
            , "TryFrom Natural Int"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Int
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       hush
                           (Witch.tryFrom @Natural.Natural @Int
                             (fromIntegral x)
                           )
                         ~?= Just x
                   , let
                       x =
                         fromIntegral (maxBound :: Int) + 1 :: Natural.Natural
                     in
                       hush (Witch.tryFrom @Natural.Natural @Int x) ~?= Nothing
                   ]
            , "From Natural Integer"
              ~: let f = Witch.from @Natural.Natural @Integer
                 in [f 0 ~?= 0, f 9223372036854775808 ~?= 9223372036854775808]
            , "TryFrom Natural Float"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Float
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   ]
            , "TryFrom Natural Double"
              ~: let f = hush . Witch.tryFrom @Natural.Natural @Double
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   ]

    -- Float
            , "TryFrom Float Int8"
              ~: let f = hush . Witch.tryFrom @Float @Int.Int8
                 in
                   [ f 0 ~?= Just 0
                   , f 127 ~?= Just 127
                   , f 128 ~?= Nothing
                   , f (-128) ~?= Just (-128)
                   , f (-129) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Int16"
              ~: let f = hush . Witch.tryFrom @Float @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   , f (-32768) ~?= Just (-32768)
                   , f (-32769) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Int32"
              ~: let f = hush . Witch.tryFrom @Float @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Int64"
              ~: let f = hush . Witch.tryFrom @Float @Int.Int64
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Int"
              ~: let f = hush . Witch.tryFrom @Float @Int
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Integer"
              ~: let f = hush . Witch.tryFrom @Float @Integer
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (-16777215) ~?= Just (-16777215)
                   , f (-16777216) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Word8"
              ~: let f = hush . Witch.tryFrom @Float @Word.Word8
                 in
                   [ f 0 ~?= Just 0
                   , f 255 ~?= Just 255
                   , f 256 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Word16"
              ~: let f = hush . Witch.tryFrom @Float @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Word32"
              ~: let f = hush . Witch.tryFrom @Float @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Word64"
              ~: let f = hush . Witch.tryFrom @Float @Word.Word64
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Word"
              ~: let f = hush . Witch.tryFrom @Float @Word
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Natural"
              ~: let f = hush . Witch.tryFrom @Float @Natural.Natural
                 in
                   [ f 0 ~?= Just 0
                   , f 16777215 ~?= Just 16777215
                   , f 16777216 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Float Rational"
              ~: let f = hush . Witch.tryFrom @Float @Rational
                 in
                   [ f 0 ~?= Just 0
                   , f (-0) ~?= Just 0
                   , f 0.5 ~?= Just 0.5
                   , f (-0.5) ~?= Just (-0.5)
                   , f 16777215 ~?= Just 16777215
                   , f (-16777215) ~?= Just (-16777215)
                   , f 16777216 ~?= Just 16777216
                   , f (-16777216) ~?= Just (-16777216)
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   , f 0.1 ~?= Just 0.1
                   , f (-0.1) ~?= Just (-0.1)
                   ]
            , "From Float Double"
              ~: let f = Witch.from @Float @Double
                 in
                   [ f 0 ~?= 0
                   , f 0.5 ~?= 0.5
                   , f (-0.5) ~?= (-0.5)
                   , TestCase
                     $ let x = f (0 / 0) in assertBool (show x) $ isNaN x
                   , f (1 / 0) ~?= (1 / 0)
                   , f (-1 / 0) ~?= (-1 / 0)
                   ]

    -- Double
            , "TryFrom Double Int8"
              ~: let f = hush . Witch.tryFrom @Double @Int.Int8
                 in
                   [ f 0 ~?= Just 0
                   , f 127 ~?= Just 127
                   , f 128 ~?= Nothing
                   , f (-128) ~?= Just (-128)
                   , f (-129) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Int16"
              ~: let f = hush . Witch.tryFrom @Double @Int.Int16
                 in
                   [ f 0 ~?= Just 0
                   , f 32767 ~?= Just 32767
                   , f 32768 ~?= Nothing
                   , f (-32768) ~?= Just (-32768)
                   , f (-32769) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Int32"
              ~: let f = hush . Witch.tryFrom @Double @Int.Int32
                 in
                   [ f 0 ~?= Just 0
                   , f 2147483647 ~?= Just 2147483647
                   , f 2147483648 ~?= Nothing
                   , f (-2147483648) ~?= Just (-2147483648)
                   , f (-2147483649) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Int64"
              ~: let f = hush . Witch.tryFrom @Double @Int.Int64
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   , f (-9007199254740991) ~?= Just (-9007199254740991)
                   , f (-9007199254740992) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Int"
              ~: let f = hush . Witch.tryFrom @Double @Int
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Int
                     in
                       if toInteger x >= 9007199254740991
                         then f 9007199254740991 ~?= Just 9007199254740991
                         else f (fromIntegral x) ~?= Just x
                   , f 9007199254740992 ~?= Nothing
                   , let x = minBound :: Int
                     in
                       if toInteger x <= (-9007199254740991)
                         then f (-9007199254740991)
                           ~?= Just (-9007199254740991)
                         else f (fromIntegral x) ~?= Just x
                   , f (-9007199254740992) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Integer"
              ~: let f = hush . Witch.tryFrom @Double @Integer
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   , f (-9007199254740991) ~?= Just (-9007199254740991)
                   , f (-9007199254740992) ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Word8"
              ~: let f = hush . Witch.tryFrom @Double @Word.Word8
                 in
                   [ f 0 ~?= Just 0
                   , f 255 ~?= Just 255
                   , f 256 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Word16"
              ~: let f = hush . Witch.tryFrom @Double @Word.Word16
                 in
                   [ f 0 ~?= Just 0
                   , f 65535 ~?= Just 65535
                   , f 65536 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Word32"
              ~: let f = hush . Witch.tryFrom @Double @Word.Word32
                 in
                   [ f 0 ~?= Just 0
                   , f 4294967295 ~?= Just 4294967295
                   , f 4294967296 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Word64"
              ~: let f = hush . Witch.tryFrom @Double @Word.Word64
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Word"
              ~: let f = hush . Witch.tryFrom @Double @Word
                 in
                   [ f 0 ~?= Just 0
                   , let x = maxBound :: Word
                     in
                       if toInteger x >= 9007199254740991
                         then f 9007199254740991 ~?= Just 9007199254740991
                         else f (fromIntegral x) ~?= Just x
                   , f 9007199254740992 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Natural"
              ~: let f = hush . Witch.tryFrom @Double @Natural.Natural
                 in
                   [ f 0 ~?= Just 0
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f 9007199254740992 ~?= Nothing
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   ]
            , "TryFrom Double Rational"
              ~: let f = hush . Witch.tryFrom @Double @Rational
                 in
                   [ f 0 ~?= Just 0
                   , f (-0) ~?= Just 0
                   , f 0.5 ~?= Just 0.5
                   , f (-0.5) ~?= Just (-0.5)
                   , f 9007199254740991 ~?= Just 9007199254740991
                   , f (-9007199254740991) ~?= Just (-9007199254740991)
                   , f 9007199254740992 ~?= Just 9007199254740992
                   , f (-9007199254740992) ~?= Just (-9007199254740992)
                   , f (0 / 0) ~?= Nothing
                   , f (1 / 0) ~?= Nothing
                   , f (-1 / 0) ~?= Nothing
                   , f 0.1 ~?= Just 0.1
                   , f (-0.1) ~?= Just (-0.1)
                   ]
            , "From Double Float"
              ~: let f = Witch.from @Double @Float
                 in
                   [ f 0 ~?= 0
                   , f 0.5 ~?= 0.5
                   , f (-0.5) ~?= (-0.5)
                   , TestCase
                     $ let x = f (0 / 0) in assertBool (show x) $ isNaN x
                   , f (1 / 0) ~?= (1 / 0)
                   , f (-1 / 0) ~?= (-1 / 0)
                   ]

    -- Ratio
            , "From a (Ratio a)"
              ~: let f = Witch.from @Int @(Ratio.Ratio Int)
                 in [Witch.from @Integer @Rational 0 ~?= 0, f 0 ~?= 0]
            , "TryFrom (Ratio a) a"
              ~: let f = hush . Witch.tryFrom @(Ratio.Ratio Int) @Int
                 in
                   [ hush (Witch.tryFrom @Rational @Integer 0) ~?= Just 0
                   , hush (Witch.tryFrom @Rational @Integer 0.5) ~?= Nothing
                   , f 0 ~?= Just 0
                   , f 0.5 ~?= Nothing
                   ]
            , "From Rational Float"
              ~: let f = Witch.from @Rational @Float
                 in
                   [ f 0 ~?= 0
                   , f 0.5 ~?= 0.5
                   , f (-0.5) ~?= (-0.5)
                   , f 0.1 ~?= 0.1
                   , f (-0.1) ~?= (-0.1)
                   ]
            , "From Rational Double"
              ~: let f = Witch.from @Rational @Double
                 in
                   [ f 0 ~?= 0
                   , f 0.5 ~?= 0.5
                   , f (-0.5) ~?= (-0.5)
                   , f 0.1 ~?= 0.1
                   , f (-0.1) ~?= (-0.1)
                   ]
            , "TryFrom Rational (Fixed a)"
              ~: let f = hush . Witch.tryFrom @Rational @Fixed.Deci
                 in
                   [ hush (Witch.tryFrom @Rational @Fixed.Uni 1) ~?= Just 1
                   , hush (Witch.tryFrom @Rational @Fixed.Uni 1.2) ~?= Nothing
                   , f 0.1 ~?= Just 0.1
                   , f 1.2 ~?= Just 1.2
                   , f 12.3 ~?= Just 12.3
                   , f 0.12 ~?= Nothing
                   ]

    -- Fixed
            , "From Integer (Fixed a)"
              ~: let f = Witch.from @Integer @Fixed.Deci
                 in
                   [ Witch.from @Integer @Fixed.Uni 1 ~?= 1
                   , f 1 ~?= 0.1
                   , f 10 ~?= 1
                   , f 120 ~?= 12
                   ]
            , "From (Fixed a) Integer"
              ~: let f = Witch.from @Fixed.Deci @Integer
                 in
                   [ Witch.from @Fixed.Uni @Integer 1 ~?= 1
                   , f 0.1 ~?= 1
                   , f 1 ~?= 10
                   , f 12 ~?= 120
                   ]
            , "From (Fixed a) Rational"
              ~: let f = Witch.from @Fixed.Deci @Rational
                 in
                   [ Witch.from @Fixed.Uni @Rational 1 ~?= 1
                   , f 0.1 ~?= 0.1
                   , f 1 ~?= 1
                   , f 12 ~?= 12
                   ]

    -- Complex
            , "From a (Complex a)"
              ~: let f = Witch.from @Float @(Complex.Complex Float)
                 in
                   [ Witch.from @Double @(Complex.Complex Double) 1 ~?= 1
                   , f 1 ~?= 1
                   ]
            , "TryFrom (Complex a) a"
              ~: let f = hush . Witch.tryFrom @(Complex.Complex Float) @Float
                 in
                   [ hush (Witch.tryFrom @(Complex.Complex Double) @Double 1)
                     ~?= Just 1
                   , hush
                       (Witch.tryFrom @(Complex.Complex Double) @Double
                         (0 Complex.:+ 1)
                       )
                     ~?= Nothing
                   , f 1 ~?= Just 1
                   , f (0 Complex.:+ 1) ~?= Nothing
                   ]

    -- NonEmpty
            , "TryFrom [a] (NonEmpty a)"
              ~: let f = hush . Witch.tryFrom @[Int] @(NonEmpty.NonEmpty Int)
                 in
                   [ f [] ~?= Nothing
                   , f [1] ~?= Just (1 NonEmpty.:| [])
                   , f [1, 2] ~?= Just (1 NonEmpty.:| [2])
                   ]
            , "From (NonEmpty a) [a]"
              ~: let f = Witch.from @(NonEmpty.NonEmpty Int) @[Int]
                 in
                   [ f (1 NonEmpty.:| []) ~?= [1]
                   , f (1 NonEmpty.:| [2]) ~?= [1, 2]
                   ]

    -- Set
            , "From [a] (Set a)"
              ~: let f = Witch.from @[Char] @(Set.Set Char)
                 in
                   [ f [] ~?= Set.fromList []
                   , f ['a'] ~?= Set.fromList ['a']
                   , f ['a', 'b'] ~?= Set.fromList ['a', 'b']
                   , f ['a', 'a'] ~?= Set.fromList ['a']
                   ]
            , "From (Set a) [a]"
              ~: let f = Witch.from @(Set.Set Char) @[Char]
                 in
                   [ f (Set.fromList []) ~?= []
                   , f (Set.fromList ['a']) ~?= ['a']
                   , f (Set.fromList ['a', 'b']) ~?= ['a', 'b']
                   ]

    -- IntSet
            , "From [Int] IntSet"
              ~: let f = Witch.from @[Int] @IntSet.IntSet
                 in
                   [ f [] ~?= IntSet.fromList []
                   , f [1] ~?= IntSet.fromList [1]
                   , f [1, 2] ~?= IntSet.fromList [1, 2]
                   ]
            , "From IntSet [Int]"
              ~: let f = Witch.from @IntSet.IntSet @[Int]
                 in
                   [ f (IntSet.fromList []) ~?= []
                   , f (IntSet.fromList [1]) ~?= [1]
                   , f (IntSet.fromList [1, 2]) ~?= [1, 2]
                   ]

    -- Map
            , "From [(k, v)] (Map k v)"
              ~: let f = Witch.from @[(Char, Int)] @(Map.Map Char Int)
                 in
                   [ f [] ~?= Map.empty
                   , f [('a', 1)] ~?= Map.fromList [('a', 1)]
                   , f [('a', 1), ('b', 2)]
                     ~?= Map.fromList [('a', 1), ('b', 2)]
                   , f [('a', 1), ('a', 2)] ~?= Map.fromList [('a', 2)]
                   ]
            , "From (Map k v) [(k, v)]"
              ~: let f = Witch.from @(Map.Map Char Int) @[(Char, Int)]
                 in
                   [ f Map.empty ~?= []
                   , f (Map.fromList [('a', 1)]) ~?= [('a', 1)]
                   , f (Map.fromList [('a', 1), ('b', 2)])
                     ~?= [('a', 1), ('b', 2)]
                   ]

    -- IntMap
            , "From [(Int, v)] (IntMap v)"
              ~: let f = Witch.from @[(Int, Char)] @(IntMap.IntMap Char)
                 in
                   [ f [] ~?= IntMap.fromList []
                   , f [(1, 'a')] ~?= IntMap.fromList [(1, 'a')]
                   , f [(1, 'a'), (2, 'b')]
                     ~?= IntMap.fromList [(1, 'a'), (2, 'b')]
                   , f [(1, 'a'), (1, 'b')] ~?= IntMap.fromList [(1, 'b')]
                   ]
            , "From (IntMap v) [(Int, v)]"
              ~: let f = Witch.from @(IntMap.IntMap Char) @[(Int, Char)]
                 in
                   [ f (IntMap.fromList []) ~?= []
                   , f (IntMap.fromList [(1, 'a')]) ~?= [(1, 'a')]
                   , f (IntMap.fromList [(1, 'a'), (2, 'b')])
                     ~?= [(1, 'a'), (2, 'b')]
                   ]

    -- Seq
            , "From [a] (Seq a)"
              ~: let f = Witch.from @[Int] @(Seq.Seq Int)
                 in
                   [ f [] ~?= Seq.fromList []
                   , f [1] ~?= Seq.fromList [1]
                   , f [1, 2] ~?= Seq.fromList [1, 2]
                   ]
            , "From (Seq a) [a]"
              ~: let f = Witch.from @(Seq.Seq Int) @[Int]
                 in
                   [ f (Seq.fromList []) ~?= []
                   , f (Seq.fromList [1]) ~?= [1]
                   , f (Seq.fromList [1, 2]) ~?= [1, 2]
                   ]

    -- ByteString
            , "From [Word8] ByteString"
              ~: let f = Witch.from @[Word.Word8] @ByteString.ByteString
                 in
                   [ f [] ~?= ByteString.pack []
                   , f [0x00] ~?= ByteString.pack [0x00]
                   , f [0x0f, 0xf0] ~?= ByteString.pack [0x0f, 0xf0]
                   ]
            , "From ByteString [Word8]"
              ~: let f = Witch.from @ByteString.ByteString @[Word.Word8]
                 in
                   [ f (ByteString.pack []) ~?= []
                   , f (ByteString.pack [0x00]) ~?= [0x00]
                   , f (ByteString.pack [0x0f, 0xf0]) ~?= [0x0f, 0xf0]
                   ]
            , "From ByteString LazyByteString"
              ~: let
                   f =
                     Witch.from @ByteString.ByteString
                       @LazyByteString.ByteString
                 in
                   [ f (ByteString.pack []) ~?= LazyByteString.pack []
                   , f (ByteString.pack [0x00]) ~?= LazyByteString.pack [0x00]
                   , f (ByteString.pack [0x0f, 0xf0])
                     ~?= LazyByteString.pack [0x0f, 0xf0]
                   ]
            , "From ByteString ShortByteString"
              ~: let
                   f =
                     Witch.from @ByteString.ByteString
                       @ShortByteString.ShortByteString
                 in
                   [ f (ByteString.pack []) ~?= ShortByteString.pack []
                   , f (ByteString.pack [0x00]) ~?= ShortByteString.pack [0x00]
                   , f (ByteString.pack [0x0f, 0xf0])
                     ~?= ShortByteString.pack [0x0f, 0xf0]
                   ]
            , "TryFrom ByteString Text"
              ~: let
                   f = hush . Witch.tryFrom @ByteString.ByteString @Text.Text
                 in
                   [ f (ByteString.pack []) ~?= Just (Text.pack "")
                   , f (ByteString.pack [0x61]) ~?= Just (Text.pack "a")
                   , f (ByteString.pack [0xff]) ~?= Nothing
                   ]
            , "TryFrom ByteString LazyText"
              ~: let
                   f =
                     hush . Witch.tryFrom @ByteString.ByteString @LazyText.Text
                 in
                   [ f (ByteString.pack []) ~?= Just (LazyText.pack "")
                   , f (ByteString.pack [0x61]) ~?= Just (LazyText.pack "a")
                   , f (ByteString.pack [0xff]) ~?= Nothing
                   ]
            , "TryFrom ByteString String"
              ~: let f = hush . Witch.tryFrom @ByteString.ByteString @String
                 in
                   [ f (ByteString.pack []) ~?= Just ""
                   , f (ByteString.pack [0x61]) ~?= Just "a"
                   , f (ByteString.pack [0xff]) ~?= Nothing
                   ]

    -- LazyByteString
            , "From [Word8] LazyByteString"
              ~: let f = Witch.from @[Word.Word8] @LazyByteString.ByteString
                 in
                   [ f [] ~?= LazyByteString.pack []
                   , f [0x00] ~?= LazyByteString.pack [0x00]
                   , f [0x0f, 0xf0] ~?= LazyByteString.pack [0x0f, 0xf0]
                   ]
            , "From LazyByteString [Word8]"
              ~: let f = Witch.from @LazyByteString.ByteString @[Word.Word8]
                 in
                   [ f (LazyByteString.pack []) ~?= []
                   , f (LazyByteString.pack [0x00]) ~?= [0x00]
                   , f (LazyByteString.pack [0x0f, 0xf0]) ~?= [0x0f, 0xf0]
                   ]
            , "From LazyByteString ByteString"
              ~: let
                   f =
                     Witch.from @LazyByteString.ByteString
                       @ByteString.ByteString
                 in
                   [ f (LazyByteString.pack []) ~?= ByteString.pack []
                   , f (LazyByteString.pack [0x00]) ~?= ByteString.pack [0x00]
                   , f (LazyByteString.pack [0x0f, 0xf0])
                     ~?= ByteString.pack [0x0f, 0xf0]
                   ]
            , "TryFrom LazyByteString LazyText"
              ~: let
                   f =
                     hush
                       . Witch.tryFrom @LazyByteString.ByteString
                         @LazyText.Text
                 in
                   [ f (LazyByteString.pack []) ~?= Just (LazyText.pack "")
                   , f (LazyByteString.pack [0x61])
                     ~?= Just (LazyText.pack "a")
                   , f (LazyByteString.pack [0xff]) ~?= Nothing
                   ]
            , "TryFrom LazyByteString Text"
              ~: let
                   f =
                     hush . Witch.tryFrom @LazyByteString.ByteString @Text.Text
                 in
                   [ f (LazyByteString.pack []) ~?= Just (Text.pack "")
                   , f (LazyByteString.pack [0x61]) ~?= Just (Text.pack "a")
                   , f (LazyByteString.pack [0xff]) ~?= Nothing
                   ]
            , "TryFrom LazyByteString String"
              ~: let
                   f = hush . Witch.tryFrom @LazyByteString.ByteString @String
                 in
                   [ f (LazyByteString.pack []) ~?= Just ""
                   , f (LazyByteString.pack [0x61]) ~?= Just "a"
                   , f (LazyByteString.pack [0xff]) ~?= Nothing
                   ]

    -- ShortByteString
            , "From [Word8] ShortByteString"
              ~: let
                   f =
                     Witch.from @[Word.Word8] @ShortByteString.ShortByteString
                 in
                   [ f [] ~?= ShortByteString.pack []
                   , f [0x00] ~?= ShortByteString.pack [0x00]
                   , f [0x0f, 0xf0] ~?= ShortByteString.pack [0x0f, 0xf0]
                   ]
            , "From ShortByteString [Word8]"
              ~: let
                   f =
                     Witch.from @ShortByteString.ShortByteString @[Word.Word8]
                 in
                   [ f (ShortByteString.pack []) ~?= []
                   , f (ShortByteString.pack [0x00]) ~?= [0x00]
                   , f (ShortByteString.pack [0x0f, 0xf0]) ~?= [0x0f, 0xf0]
                   ]
            , "From ShortByteString ByteString"
              ~: let
                   f =
                     Witch.from @ShortByteString.ShortByteString
                       @ByteString.ByteString
                 in
                   [ f (ShortByteString.pack []) ~?= ByteString.pack []
                   , f (ShortByteString.pack [0x00]) ~?= ByteString.pack [0x00]
                   , f (ShortByteString.pack [0x0f, 0xf0])
                     ~?= ByteString.pack [0x0f, 0xf0]
                   ]

    -- Text
            , "From Text LazyText"
              ~: let f = Witch.from @Text.Text @LazyText.Text
                 in
                   [ f (Text.pack "") ~?= LazyText.pack ""
                   , f (Text.pack "a") ~?= LazyText.pack "a"
                   , f (Text.pack "ab") ~?= LazyText.pack "ab"
                   ]
            , "From Text ByteString"
              ~: let f = Witch.from @Text.Text @ByteString.ByteString
                 in
                   [ f (Text.pack "") ~?= ByteString.pack []
                   , f (Text.pack "a") ~?= ByteString.pack [0x61]
                   ]
            , "From Text LazyByteString"
              ~: let f = Witch.from @Text.Text @LazyByteString.ByteString
                 in
                   [ f (Text.pack "") ~?= LazyByteString.pack []
                   , f (Text.pack "a") ~?= LazyByteString.pack [0x61]
                   ]

    -- LazyText
            , "From LazyText Text"
              ~: let f = Witch.from @LazyText.Text @Text.Text
                 in
                   [ f (LazyText.pack "") ~?= Text.pack ""
                   , f (LazyText.pack "a") ~?= Text.pack "a"
                   , f (LazyText.pack "ab") ~?= Text.pack "ab"
                   ]
            , "From LazyText LazyByteString"
              ~: let f = Witch.from @LazyText.Text @LazyByteString.ByteString
                 in
                   [ f (LazyText.pack "") ~?= LazyByteString.pack []
                   , f (LazyText.pack "a") ~?= LazyByteString.pack [0x61]
                   ]
            , "From LazyText ByteString"
              ~: let f = Witch.from @LazyText.Text @ByteString.ByteString
                 in
                   [ f (LazyText.pack "") ~?= ByteString.pack []
                   , f (LazyText.pack "a") ~?= ByteString.pack [0x61]
                   ]

    -- String
            , "From String Text"
              ~: let f = Witch.from @String @Text.Text
                 in
                   [ f "" ~?= Text.pack ""
                   , f "a" ~?= Text.pack "a"
                   , f "ab" ~?= Text.pack "ab"
                   ]
            , "From Text String"
              ~: let f = Witch.from @Text.Text @String
                 in
                   [ f (Text.pack "") ~?= ""
                   , f (Text.pack "a") ~?= "a"
                   , f (Text.pack "ab") ~?= "ab"
                   ]
            , "From String LazyText"
              ~: let f = Witch.from @String @LazyText.Text
                 in
                   [ f "" ~?= LazyText.pack ""
                   , f "a" ~?= LazyText.pack "a"
                   , f "ab" ~?= LazyText.pack "ab"
                   ]
            , "From LazyText String"
              ~: let f = Witch.from @LazyText.Text @String
                 in
                   [ f (LazyText.pack "") ~?= ""
                   , f (LazyText.pack "a") ~?= "a"
                   , f (LazyText.pack "ab") ~?= "ab"
                   ]
            , "From String ByteString"
              ~: let f = Witch.from @String @ByteString.ByteString
                 in
                   [ f "" ~?= ByteString.pack []
                   , f "a" ~?= ByteString.pack [0x61]
                   ]
            , "From String LazyByteString"
              ~: let f = Witch.from @String @LazyByteString.ByteString
                 in
                   [ f "" ~?= LazyByteString.pack []
                   , f "a" ~?= LazyByteString.pack [0x61]
                   ]

    -- Day
            , "From Integer Day"
              ~: let f = Witch.from @Integer @Time.Day
                 in [f 0 ~?= Time.ModifiedJulianDay 0]
            , "From Day Integer"
              ~: let f = Witch.from @Time.Day @Integer
                 in [f (Time.ModifiedJulianDay 0) ~?= 0]

    -- DayOfWeek
            , "From Day DayOfWeek"
              ~: let f = Witch.from @Time.Day @Time.DayOfWeek
                 in [f (Time.ModifiedJulianDay 0) ~?= Time.Wednesday]

    -- UniversalTime
            , "From Rational UniversalTime"
              ~: let f = Witch.from @Rational @Time.UniversalTime
                 in [f 0 ~?= Time.ModJulianDate 0]
            , "From UniversalTime Rational"
              ~: let f = Witch.from @Time.UniversalTime @Rational
                 in [f (Time.ModJulianDate 0) ~?= 0]

    -- DiffTime
            , "From Pico DiffTime"
              ~: let f = Witch.from @Fixed.Pico @Time.DiffTime in [f 0 ~?= 0]
            , "From DiffTime Pico"
              ~: let f = Witch.from @Time.DiffTime @Fixed.Pico in [f 0 ~?= 0]

    -- NominalDiffTime
            , "From Pico NominalDiffTime"
              ~: let f = Witch.from @Fixed.Pico @Time.NominalDiffTime
                 in [f 0 ~?= 0]
            , "From NominalDiffTime Pico"
              ~: let f = Witch.from @Time.NominalDiffTime @Fixed.Pico
                 in [f 0 ~?= 0]

    -- POSIXTime
            , "From SystemTime POSIXTime"
              ~: let f = Witch.from @Time.SystemTime @Time.POSIXTime
                 in [f (Time.MkSystemTime 0 0) ~?= 0]
            , "From UTCTime POSIXTime"
              ~: let f = Witch.from @Time.UTCTime @Time.POSIXTime
                 in [f unixEpoch ~?= 0]
            , "From POSIXTime UTCTime"
              ~: let f = Witch.from @Time.POSIXTime @Time.UTCTime
                 in [f 0 ~?= unixEpoch]

    -- SystemTime
            , "From UTCTime SystemTime"
              ~: let f = Witch.from @Time.UTCTime @Time.SystemTime
                 in [f unixEpoch ~?= Time.MkSystemTime 0 0]
            , "From SystemTime AbsoluteTime"
              ~: let f = Witch.from @Time.SystemTime @Time.AbsoluteTime
                 in [f (Time.MkSystemTime (-3506716800) 0) ~?= Time.taiEpoch]
            , "From SystemTime UTCTime"
              ~: let f = Witch.from @Time.SystemTime @Time.UTCTime
                 in [f (Time.MkSystemTime 0 0) ~?= unixEpoch]

    -- TimeOfDay
            , "From DiffTime TimeOfDay"
              ~: let f = Witch.from @Time.DiffTime @Time.TimeOfDay
                 in [f 0 ~?= Time.TimeOfDay 0 0 0]
            , "From Rational TimeOfDay"
              ~: let f = Witch.from @Rational @Time.TimeOfDay
                 in [f 0 ~?= Time.TimeOfDay 0 0 0]
            , "From TimeOfDay DiffTime"
              ~: let f = Witch.from @Time.TimeOfDay @Time.DiffTime
                 in [f (Time.TimeOfDay 0 0 0) ~?= 0]
            , "From TimeOfDay Rational"
              ~: let f = Witch.from @Time.TimeOfDay @Rational
                 in [f (Time.TimeOfDay 0 0 0) ~?= 0]

    -- CalendarDiffTime
            , "From CalendarDiffDays CalendarDiffTime"
              ~: let
                   f =
                     Witch.from @Time.CalendarDiffDays @Time.CalendarDiffTime
                 in
                   [ f (Time.CalendarDiffDays 0 0)
                       ~?= Time.CalendarDiffTime 0 0
                   ]
            , "From NominalDiffTime CalendarDiffTime"
              ~: let
                   f = Witch.from @Time.NominalDiffTime @Time.CalendarDiffTime
                 in [f 0 ~?= Time.CalendarDiffTime 0 0]

    -- ZonedTime
            , "From ZonedTime UTCTime"
              ~: let f = Witch.from @Time.ZonedTime @Time.UTCTime
                 in
                   [ f
                         (Time.ZonedTime
                           (Time.LocalTime
                             (Time.ModifiedJulianDay 0)
                             (Time.TimeOfDay 0 0 0)
                           )
                           Time.utc
                         )
                       ~?= Time.UTCTime (Time.ModifiedJulianDay 0) 0
                   ]
            ]
       ]

unixEpoch :: Time.UTCTime
unixEpoch = Time.UTCTime (Time.ModifiedJulianDay 40587) 0

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

newtype Age
  = Age Int.Int8
  deriving (Eq, Show)

instance Witch.From Age Int.Int8

instance Witch.From Int.Int8 Age


module Statistics.FastBayes where

import Statistics.FastBayes.Linear()