uuid-types-1.0.5: tests/TestUUID.hs
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
import Data.Binary (encode)
import qualified Data.ByteString.Char8 as BC8
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BL8
import Data.Char (ord)
import Data.Functor ((<$>))
import qualified Data.UUID.Types as U
import Data.Word
import Foreign (alloca, castPtr, peek, poke,
sizeOf)
import GHC.ByteOrder (ByteOrder(..), targetByteOrder)
import System.IO.Unsafe (unsafePerformIO)
import Test.QuickCheck (Arbitrary (arbitrary), choose)
import Test.Tasty (TestTree, defaultMain, testGroup)
import Test.Tasty.HUnit (assertBool, testCase, (@=?), (@?=))
import Test.Tasty.QuickCheck (testProperty)
-- orphan
instance Arbitrary U.UUID where
-- the UUID random instance ignores bounds
arbitrary = choose (U.nil, U.nil)
type Test = TestTree
test_null :: Test
test_null =
testCase "nil is null" $
assertBool "" (U.null U.nil)
test_nil :: Test
test_nil = testGroup "nil" [
testCase "nil string" $ U.toString U.nil @?= "00000000-0000-0000-0000-000000000000",
testCase "nil bytes" $ U.toByteString U.nil @?= BL.pack (replicate 16 0)
]
test_lift :: Test
test_lift = testCase "TH.Lift" $ do
let uuid = U.fromWords64 123456789 987654321
uuid @?= $( [| uuid |] )
test_conv :: Test
test_conv = testGroup "conversions" [
testCase "conv bytes to string" $
maybe "" (U.toString) (U.fromByteString b16) @?= s16,
testCase "conv string to bytes" $
maybe BL.empty (U.toByteString) (U.fromString s16) @?= b16
]
where b16 = BL.pack [1..16]
s16 = "01020304-0506-0708-090a-0b0c0d0e0f10"
-- | Test fromByteString with a fixed-input.
test_fromByteString :: Test
test_fromByteString =
testCase "UUID fromByteString" $
Just inputUUID @=?
U.fromByteString (BL8.pack "\xa5\xca\x85\x66\xd9\xc5\x48\x35\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2")
-- | Test fromWords with a fixed-input
test_fromWords :: Test
test_fromWords =
testCase "UUID fromWords" $
inputUUID @=? U.fromWords 0xa5ca8566 0xd9c54835 0x99c8e1f1 0x3e73b5e2
test_Storeable :: Test
test_Storeable =
testCase "UUID Storeable(poke)" $
case targetByteOrder of
LittleEndian -> BC8.pack "\x66\x85\xca\xa5\xc5\xd9\x35\x48\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2" @=? pokeAsBS inputUUID
BigEndian -> BC8.pack "\xa5\xca\x85\x66\xd9\xc5\x48\x35\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2" @=? pokeAsBS inputUUID
where
pokeAsBS :: U.UUID -> BC8.ByteString
pokeAsBS uuid = unsafePerformIO $ do
alloca $ \ptr -> do
poke ptr uuid
BC8.packCStringLen (castPtr ptr, sizeOf uuid)
test_Binary :: Test
test_Binary =
testCase "UUID Binary(encode)" $
(BL8.pack "\xa5\xca\x85\x66\xd9\xc5\x48\x35\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2") @=? encode inputUUID
inputUUID :: U.UUID
inputUUID = read "a5ca8566-d9c5-4835-99c8-e1f13e73b5e2"
prop_stringRoundTrip :: Test
prop_stringRoundTrip = testProperty "String round trip" stringRoundTrip
where stringRoundTrip :: U.UUID -> Bool
stringRoundTrip u = maybe False (== u) $ U.fromString (U.toString u)
prop_byteStringRoundTrip :: Test
prop_byteStringRoundTrip = testProperty "ByteString round trip" byteStringRoundTrip
where byteStringRoundTrip :: U.UUID -> Bool
byteStringRoundTrip u = maybe False (== u)
$ U.fromByteString (U.toByteString u)
prop_stringLength :: Test
prop_stringLength = testProperty "String length" stringLength
where stringLength :: U.UUID -> Bool
stringLength u = length (U.toString u) == 36
prop_byteStringLength :: Test
prop_byteStringLength = testProperty "ByteString length" byteStringLength
where byteStringLength :: U.UUID -> Bool
byteStringLength u = BL.length (U.toByteString u) == 16
prop_randomsDiffer :: Test
prop_randomsDiffer = testProperty "Randoms differ" randomsDiffer
where randomsDiffer :: (U.UUID, U.UUID) -> Bool
randomsDiffer (u1, u2) = u1 /= u2
prop_randomNotNull :: Test
prop_randomNotNull = testProperty "Random not null" randomNotNull
where randomNotNull :: U.UUID -> Bool
randomNotNull = not. U.null
prop_readShowRoundTrip :: Test
prop_readShowRoundTrip = testProperty "Read/Show round-trip" prop
where -- we're using 'Maybe UUID' to add a bit of
-- real-world complexity.
prop :: U.UUID -> Bool
prop uuid = read (show (Just uuid)) == Just uuid
-- Mostly going to test for wrong UUIDs
fromASCIIBytes_fromString1 :: String -> Bool
fromASCIIBytes_fromString1 s =
if all (\c -> ord c < 256) s
then U.fromString s == U.fromASCIIBytes (BC8.pack s)
else True
fromASCIIBytes_fromString2 :: U.UUID -> Bool
fromASCIIBytes_fromString2 (U.toString -> s) =
U.fromString s == U.fromASCIIBytes (BC8.pack s)
toASCIIBytes_toString :: U.UUID -> Bool
toASCIIBytes_toString uuid =
U.toString uuid == BC8.unpack (U.toASCIIBytes uuid)
fromASCIIBytes_toASCIIBytes :: U.UUID -> Bool
fromASCIIBytes_toASCIIBytes (BC8.pack . U.toString -> bs) =
Just bs == (U.toASCIIBytes <$> U.fromASCIIBytes bs)
toASCIIBytes_fromASCIIBytes :: U.UUID -> Bool
toASCIIBytes_fromASCIIBytes uuid =
Just uuid == U.fromASCIIBytes (U.toASCIIBytes uuid)
toWords_fromWords :: U.UUID -> Bool
toWords_fromWords uuid =
uuid == myUncurry4 U.fromWords (U.toWords uuid)
fromWords_toWords :: (Word32, Word32, Word32, Word32) -> Bool
fromWords_toWords wds =
wds == U.toWords (myUncurry4 U.fromWords wds)
myUncurry4 :: (x1 -> x2 -> x3 -> x4 -> y) -> (x1, x2, x3, x4) -> y
myUncurry4 f (a,b,c,d) = f a b c d
prop_storableRoundTrip :: Test
prop_storableRoundTrip =
testProperty "Storeable round-trip" $ unsafePerformIO . prop
where
prop :: U.UUID -> IO Bool
prop uuid =
alloca $ \ptr -> do
poke ptr uuid
uuid2 <- peek ptr
return $ uuid == uuid2
main :: IO ()
main = do
defaultMain $
testGroup "tests" $
concat $
[ [
test_null,
test_nil,
test_lift,
test_conv,
test_fromByteString,
test_fromWords,
test_Storeable,
test_Binary
]
, [ prop_stringRoundTrip,
prop_readShowRoundTrip,
prop_byteStringRoundTrip,
prop_storableRoundTrip,
prop_stringLength,
prop_byteStringLength,
prop_randomsDiffer,
prop_randomNotNull
]
, [ testProperty "fromASCIIBytes_fromString1" fromASCIIBytes_fromString1
, testProperty "fromASCIIBytes_fromString2" fromASCIIBytes_fromString2
, testProperty "fromASCIIBytes_toString" toASCIIBytes_toString
, testProperty "fromASCIIBytes_toASCIIBytes" fromASCIIBytes_toASCIIBytes
, testProperty "toASCIIBytes_fromASCIIBytes" toASCIIBytes_fromASCIIBytes
, testProperty "toWords_fromWords" toWords_fromWords
, testProperty "fromWords_toWords" fromWords_toWords
]
]