bv-little-1.3.0: src/libs/Data/BitVector/LittleEndian/QuickCheck.hs
{-|
Copyright : © 2020 Alex Washburn
License : BSD-3-Clause
Maintainer : github@recursion.ninja
Stability : Stable
Exposes the 'Arbitrary' and 'CoArbitrary' instances for 'BitVector'.
-}
{-# Language Safe #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Data.BitVector.LittleEndian.QuickCheck
(
) where
import Data.BitVector.LittleEndian (BitVector)
import Data.BitVector.LittleEndian.Internal hiding (BitVector)
import Data.Bits
import Data.Monoid ()
import GHC.Natural
import Test.QuickCheck (Arbitrary(..), CoArbitrary(..), NonNegative(..), choose, suchThat, variant)
{-| @since 0.1.0 -}
instance Arbitrary BitVector where
-- Arbitrary instance distribution weighting:
-- - 2% = (maxBound :: Word)
-- - 2% = (maxBound :: Word) + 1
-- - 8% = all bits on
-- - 8% = all bits off
-- - 80% = any bit configuration
arbitrary = do
-- 1/25 chance of generating the boundary value at which the natural number
-- must use different Natural constructors: NatS# & NatJ#
n <- choose (0, 25 :: Word)
case n of
0 -> boundaryValue
1 -> allBitsOn
2 -> allBitsOn
3 -> allBitsOff
4 -> allBitsOff
_ -> anyBitValue
where
allBitsOn = genBitVector $ Just True
allBitsOff = genBitVector $ Just False
anyBitValue = genBitVector Nothing
boundaryValue = do
let numVal = maxBound :: Word
let dimVal = toEnum $ popCount numVal
let natVal = wordToNatural numVal
-- 50/50 change to generate above or below the constructor boundary
underBoundary <- arbitrary
let (lowerBound, naturalVal)
| underBoundary = (dimVal, natVal)
| otherwise = (dimVal + 1, natVal + 1)
widthVal <- (getNonNegative <$> arbitrary) `suchThat` (>= lowerBound)
pure $ BV widthVal naturalVal
genBitVector spec = do
dimVal <- getNonNegative <$> arbitrary
let upperBound = shiftL 1 dimVal
-- 1/5 chance all bits on or all bits off
natVal <- case spec of
Just False -> pure $ naturalFromInteger 0
Just True -> pure . naturalFromInteger $ upperBound - 1
Nothing ->
fmap naturalFromInteger $ (getNonNegative <$> arbitrary) `suchThat` (< upperBound)
pure $ BV (toEnum dimVal) natVal
{-| @since 0.1.0 -}
instance CoArbitrary BitVector where
coarbitrary bv = variant (dimension bv)