nonempty-vector-0.3: test/Test/Data/Vector/NonEmpty/Accessors.hs
-- |
-- Module : Test.Data.Vector.NonEmpty.Accessors
-- Copyright : (c) 2019-2026 Emily Pillmore
-- License : BSD-style
--
-- Maintainer : Emily Pillmore <emilypi@cohomolo.gy>
-- Stability : experimental
-- Portability : non-portable
--
-- Properties for length information, indexing, and slicing.
--
module Test.Data.Vector.NonEmpty.Accessors
( tests
) where
import Data.Functor.Identity (Identity(..))
import qualified Data.List as List
import qualified Data.Vector as V
import Data.Vector.NonEmpty (NonEmptyVector)
import qualified Data.Vector.NonEmpty as NEV
import Test.Data.Vector.NonEmpty.Util
import Test.QuickCheck
import Test.Tasty
import Test.Tasty.QuickCheck
tests :: TestTree
tests = testGroup "Accessors"
[ testGroup "Length information"
[ testProperty "prop_length" prop_length
]
, testGroup "Indexing"
[ testProperty "prop_head" prop_head
, testProperty "prop_last" prop_last
, testProperty "prop_index" prop_index
, testProperty "prop_index_out_of_bounds" prop_index_out_of_bounds
, testProperty "prop_index_maybe" prop_index_maybe
, testProperty "prop_unsafeIndex" prop_unsafeIndex
]
, testGroup "Monadic indexing"
[ testProperty "prop_headM" prop_headM
, testProperty "prop_lastM" prop_lastM
, testProperty "prop_indexM" prop_indexM
, testProperty "prop_indexM_out_of_bounds" prop_indexM_out_of_bounds
, testProperty "prop_unsafeIndexM" prop_unsafeIndexM
]
, testGroup "Slicing"
[ testProperty "prop_tail" prop_tail
, testProperty "prop_init" prop_init
, testProperty "prop_uncons" prop_uncons
, testProperty "prop_unsnoc" prop_unsnoc
, testProperty "prop_slice" prop_slice
, testProperty "prop_slice_out_of_bounds" prop_slice_out_of_bounds
, testProperty "prop_take" prop_take
, testProperty "prop_drop" prop_drop
, testProperty "prop_splitAt" prop_splitAt
, testProperty "prop_unsafeSlice" prop_unsafeSlice
, testProperty "prop_unsafeTake" prop_unsafeTake
, testProperty "prop_unsafeDrop" prop_unsafeDrop
]
]
-- ---------------------------------------------------------------------- --
-- Length information
prop_length :: NonEmptyVector Int -> Property
prop_length v = NEV.length v === List.length (elems v)
-- ---------------------------------------------------------------------- --
-- Indexing
prop_head :: NonEmptyVector Int -> Property
prop_head v = [NEV.head v] === List.take 1 (elems v)
prop_last :: NonEmptyVector Int -> Property
prop_last v = [NEV.last v] === List.take 1 (List.reverse (elems v))
prop_index :: NonEmptyVector Int -> Property
prop_index v = forAll (genIndex v) $ \i ->
Just (v NEV.! i) === lookupList i (elems v)
prop_index_out_of_bounds :: NonEmptyVector Int -> Property
prop_index_out_of_bounds v = forAll (genOutOfBounds v) $ \i ->
throws (v NEV.! i)
prop_index_maybe :: NonEmptyVector Int -> Int -> Property
prop_index_maybe v i = v NEV.!? i === lookupList i (elems v)
prop_unsafeIndex :: NonEmptyVector Int -> Property
prop_unsafeIndex v = forAll (genIndex v) $ \i ->
Just (NEV.unsafeIndex v i) === lookupList i (elems v)
-- ---------------------------------------------------------------------- --
-- Monadic indexing
prop_headM :: NonEmptyVector Int -> Property
prop_headM v = [runIdentity (NEV.headM v)] === List.take 1 (elems v)
prop_lastM :: NonEmptyVector Int -> Property
prop_lastM v =
[runIdentity (NEV.lastM v)] === List.take 1 (List.reverse (elems v))
prop_indexM :: NonEmptyVector Int -> Property
prop_indexM v = forAll (genIndex v) $ \i ->
Just (runIdentity (NEV.indexM v i)) === lookupList i (elems v)
prop_indexM_out_of_bounds :: NonEmptyVector Int -> Property
prop_indexM_out_of_bounds v = forAll (genOutOfBounds v) $ \i ->
throws (runIdentity (NEV.indexM v i))
prop_unsafeIndexM :: NonEmptyVector Int -> Property
prop_unsafeIndexM v = forAll (genIndex v) $ \i ->
Just (runIdentity (NEV.unsafeIndexM v i)) === lookupList i (elems v)
-- ---------------------------------------------------------------------- --
-- Slicing
prop_tail :: NonEmptyVector Int -> Property
prop_tail v = V.toList (NEV.tail v) === List.drop 1 (elems v)
prop_init :: NonEmptyVector Int -> Property
prop_init v =
V.toList (NEV.init v) === List.take (List.length as - 1) as
where
as = elems v
prop_uncons :: NonEmptyVector Int -> Property
prop_uncons v = ([a], V.toList as) === List.splitAt 1 (elems v)
where
(a, as) = NEV.uncons v
prop_unsnoc :: NonEmptyVector Int -> Property
prop_unsnoc v =
(V.toList as, [a]) === List.splitAt (List.length (elems v) - 1) (elems v)
where
(as, a) = NEV.unsnoc v
prop_slice :: NonEmptyVector Int -> Property
prop_slice v = forAll (genSlice v) $ \(i, m) ->
V.toList (NEV.slice i m v) === List.take m (List.drop i (elems v))
prop_slice_out_of_bounds :: NonEmptyVector Int -> Property
prop_slice_out_of_bounds v = forAll genBadSlice $ \(i, m) ->
throws (V.toList (NEV.slice i m v))
where
n = NEV.length v
genBadSlice = oneof
[ (,) <$> choose (-10, -1) <*> choose (0, n)
, (,) <$> choose (0, n) <*> choose (-10, -1)
, do
i <- choose (0, n)
m <- choose (n - i + 1, n - i + 10)
pure (i, m)
]
prop_take :: Int -> NonEmptyVector Int -> Property
prop_take n v = V.toList (NEV.take n v) === List.take n (elems v)
prop_drop :: Int -> NonEmptyVector Int -> Property
prop_drop n v = V.toList (NEV.drop n v) === List.drop n (elems v)
prop_splitAt :: Int -> NonEmptyVector Int -> Property
prop_splitAt n v =
(V.toList as, V.toList bs) === List.splitAt n (elems v)
where
(as, bs) = NEV.splitAt n v
prop_unsafeSlice :: NonEmptyVector Int -> Property
prop_unsafeSlice v = forAll (genSlice v) $ \(i, m) ->
V.toList (NEV.unsafeSlice i m v) === List.take m (List.drop i (elems v))
prop_unsafeTake :: NonEmptyVector Int -> Property
prop_unsafeTake v = forAll (choose (0, NEV.length v)) $ \n ->
V.toList (NEV.unsafeTake n v) === List.take n (elems v)
prop_unsafeDrop :: NonEmptyVector Int -> Property
prop_unsafeDrop v = forAll (choose (0, NEV.length v)) $ \n ->
V.toList (NEV.unsafeDrop n v) === List.drop n (elems v)