-- Derived from @primitive@ package. {-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_GHC -fno-warn-orphans #-} import Control.Monad (when, unless) import Data.Array.Byte (ByteArray) import Data.Function (on) import Data.Proxy (Proxy(..)) import Data.Semigroup (Semigroup(..), stimesMonoid) import Data.Word (Word8) import GHC.Exts (IsList(..)) import Language.Haskell.TH.Syntax (lift) import Test.QuickCheck.Classes.Base (eqLaws, ordLaws, monoidLaws, showLaws, isListLaws, semigroupLaws, semigroupMonoidLaws, Laws(..)) import Test.Tasty (defaultMain, testGroup, TestTree) import Test.Tasty.QuickCheck (testProperty, Arbitrary(..), (===), Property, NonNegative(..), property) main :: IO () main = do testByteArray defaultMain $ testGroup "ByteArray" [ testProperty "equality" byteArrayEqProp , testProperty "reflexivity" byteArrayReflexivityProp , testProperty "compare" byteArrayCompareProp , lawsToTest (eqLaws (Proxy :: Proxy ByteArray)) , lawsToTest (ordLaws (Proxy :: Proxy ByteArray)) , lawsToTest (monoidLaws (Proxy :: Proxy ByteArray)) , lawsToTest (showLaws (Proxy :: Proxy ByteArray)) , lawsToTest (isListLaws (Proxy :: Proxy ByteArray)) , lawsToTest (semigroupLaws (Proxy :: Proxy ByteArray)) , lawsToTest (semigroupMonoidLaws (Proxy :: Proxy ByteArray)) , testProperty "stimes" byteArrayStimesProp , testProperty "lift" byteArrayLiftProp ] byteArrayCompareProp :: [Word8] -> [Word8] -> Property byteArrayCompareProp xs ys = compareLengthFirst xs ys === compare (mkByteArray xs) (mkByteArray ys) byteArrayEqProp :: [Word8] -> [Word8] -> Property byteArrayEqProp xs ys = (compareLengthFirst xs ys == EQ) === (mkByteArray xs == mkByteArray ys) byteArrayReflexivityProp :: [Word8] -> Property byteArrayReflexivityProp xs = property $ let ba = mkByteArray xs in ba == ba && compare ba ba == EQ compareLengthFirst :: [Word8] -> [Word8] -> Ordering compareLengthFirst xs ys = (compare `on` length) xs ys <> compare xs ys byteArrayStimesProp :: NonNegative Int -> ByteArray -> Property byteArrayStimesProp (NonNegative n) xs = stimes n xs === stimesMonoid n xs byteArrayLiftProp :: Property byteArrayLiftProp = let ba = mkByteArray [0,1,2,3,4,5] in ba === $(lift (fromList [0,1,2,3,4,5] :: ByteArray)) lawsToTest :: Laws -> TestTree lawsToTest (Laws name pairs) = testGroup name (map (uncurry testProperty) pairs) testByteArray :: IO () testByteArray = do let arr1 = mkByteArray ([0xde, 0xad, 0xbe, 0xef] :: [Word8]) arr2 = mkByteArray ([0xde, 0xad, 0xbe, 0xef] :: [Word8]) arr3 = mkByteArray ([0xde, 0xad, 0xbe, 0xee] :: [Word8]) arr4 = mkByteArray ([0xde, 0xad, 0xbe, 0xdd] :: [Word8]) arr5 = mkByteArray ([0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xdd] :: [Word8]) arr6 = mkByteArray ([0xde, 0xad, 0x00, 0x01, 0xb0] :: [Word8]) when (show arr1 /= "[0xde, 0xad, 0xbe, 0xef]") $ fail $ "ByteArray Show incorrect: " ++ show arr1 when (show arr6 /= "[0xde, 0xad, 0x00, 0x01, 0xb0]") $ fail $ "ByteArray Show incorrect: " ++ show arr6 unless (arr1 > arr3) $ fail $ "ByteArray Ord incorrect" unless (arr1 == arr2) $ fail $ "ByteArray Eq incorrect" unless (mappend arr1 arr4 == arr5) $ fail $ "ByteArray Monoid mappend incorrect" unless (mappend arr1 (mappend arr3 arr4) == mappend (mappend arr1 arr3) arr4) $ fail $ "ByteArray Monoid mappend not associative" unless (mconcat [arr1, arr2, arr3, arr4, arr5] == (arr1 <> arr2 <> arr3 <> arr4 <> arr5)) $ fail $ "ByteArray Monoid mconcat incorrect" unless (stimes (3 :: Int) arr4 == (arr4 <> arr4 <> arr4)) $ fail $ "ByteArray Semigroup stimes incorrect" instance Arbitrary ByteArray where arbitrary = mkByteArray <$> arbitrary mkByteArray :: [Word8] -> ByteArray mkByteArray = fromList