packages feed

algo-s-0.1.0.0: specs/Data/Sample/AlgoSSpec.hs

{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}


module Data.Sample.AlgoSSpec where


import qualified Control.Foldl           as F
import           Data.Foldable
import qualified Data.List               as L
import           System.Random.MWC
import           Test.Hspec
import           Test.QuickCheck         hiding (sample)
import           Test.QuickCheck.Monadic

import           Data.Sample.AlgoS


toDouble :: Int -> Double
toDouble = fromIntegral

spec :: Spec
spec = do
    describe "sample" $ do
        it "should return the input if the list is <N." $
            property $ \(NonEmpty xs :: NonEmptyList Int) -> monadicIO $ do
                ss <- run . withSystemRandom . asGenIO $
                    sample (2 * length xs) xs
                assert $ ss == xs

        it "should return a sample of the list if the list is >=N." $
            property $ \(NonEmpty xs :: NonEmptyList Int) -> monadicIO $ do
                ss <- run . withSystemRandom . asGenIO $
                    sample (floor $ toDouble (length xs) / 2) xs
                assert $ length ss < length xs

        it "should maintain the order of the input." $
            property $ \(NonEmpty xs :: NonEmptyList Int) -> monadicIO $ do
                ss <- run . withSystemRandom . asGenIO $
                    sample (floor $ toDouble (length xs) / 2) $ L.sort xs
                assert . all (uncurry (<=)) . zip ss $ tail ss

    describe "sampleStep" $ do
        it "should return the input if the list is <N." $
            property $ \(NonEmpty xs :: NonEmptyList Int) -> monadicIO $ do
                ss <- run . withSystemRandom . asGenIO $ \g ->
                    F.foldM (sampleInit (2 * length xs) g) xs
                assert $ ss == xs

        it "should return a sample of the list if the list is >=N." $
            property $ \(NonEmpty xs :: NonEmptyList Int) -> monadicIO $ do
                ss <- run . withSystemRandom . asGenIO $ \g ->
                    F.foldM (sampleInit (floor $ toDouble (length xs) / 2) g) xs
                assert $ length ss < length xs

        it "should maintain the order of the input." $
            property $ \(NonEmpty xs :: NonEmptyList Int) -> monadicIO $ do
                ss <- run . withSystemRandom . asGenIO $ \g ->
                    F.foldM (sampleInit (floor $ toDouble (length xs)) g)
                        $ L.sort xs
                assert . all (uncurry (<=)) . zip ss $ tail ss

        it "should accept the input incrementally." $
            property $ \(NonEmpty xs :: NonEmptyList Int) -> monadicIO $ do
                ss <- run . withSystemRandom . asGenIO $ \g ->
                    let s = sampleInit (floor $ toDouble (length xs) / 2) g
                    in  sampleDone =<< foldlM sampleStep s (L.sort xs)
                assert $ length ss < length xs
                assert . all (uncurry (<=)) . zip ss $ tail ss