Skip to content

Commit

Permalink
yampa-test: Test FRP.Yampa.Random.occasionally. Refs #248.
Browse files Browse the repository at this point in the history
This commit introduces a quickcheck-based unit test for the function
FRP.Yampa.Random.occasionally.

[ci skip]
  • Loading branch information
ivanperez-keera committed Jan 29, 2023
1 parent b15854f commit 38655c6
Showing 1 changed file with 66 additions and 3 deletions.
69 changes: 66 additions & 3 deletions yampa-test/tests/Test/FRP/Yampa/Random.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ import Test.QuickCheck hiding (once, sample)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.QuickCheck (testProperty)

import FRP.Yampa (embed, noise, noiseR, second)
import FRP.Yampa (DTime, Event (..), embed, isEvent, noise, noiseR,
occasionally, second)
import FRP.Yampa.QuickCheck (Distribution (DistRandom), generateStream)
import FRP.Yampa.Stream (SignalSampleStream)

tests :: TestTree
tests = testGroup "Regression tests for FRP.Yampa.Random"
[ testProperty "noise (0, qc)" propNoise
, testProperty "noiseR (0, qc)" propNoiseR
[ testProperty "noise (0, qc)" propNoise
, testProperty "noiseR (0, qc)" propNoiseR
, testProperty "occasionally (0, qc)" propOccasionally
]

-- * Noise (i.e. random signal generators) and stochastic processes
Expand Down Expand Up @@ -104,6 +106,67 @@ propNoiseR =
isInRange :: Ord a => a -> (a, a) -> Bool
isInRange x (minB, maxB) = minB <= x && x <= maxB

propOccasionally :: Property
propOccasionally =
forAll genDt $ \avgDt ->
forAll genOutput $ \b ->
forAll genSeed $ \seed ->

-- We pass avgDt / 10 as max time delta to myStream to ensure that the
-- stream produces frequent samples.
forAll (myStream (avgDt / 10)) $ \stream ->

-- True if all events in the output contain the value 'b',
-- the number of events produced is roughtly as expected.
let output =
embed (occasionally (mkStdGen seed) avgDt b) (structure stream)

-- Difference between the number of samples produced and expected
diffNumSamples = abs (actualOcurrences - expectedOccurrences)
actualOcurrences = length $ filter isEvent output
expectedOccurrences = round (streamTime / avgDt)
streamTime = sum $ map fst $ snd stream

in all (== Event b) (filter isEvent output) && diffNumSamples < margin

where

-- Generator: Input stream.
--
-- We provide a number of samples; otherwise, deviations might not indicate
-- lack of randomness for the signal function.
--
-- We also provide the max dt and ensure that samples are
myStream :: DTime -> Gen (SignalSampleStream ())
myStream maxDT =
generateStream
DistRandom
(Nothing, (Just maxDT))
(Just (Left numSamples))

-- Generator: Random generator seed
genDt :: Gen Double
genDt = fmap getPositive arbitrary

-- Generator: Random generator seed
genSeed :: Gen Int
genSeed = arbitrary

-- Generator: Random value generator
genOutput :: Gen Int
genOutput = arbitrary

-- Constant: Number of samples in the stream used for testing.
--
-- This number has to be high; numbers 100 or below will likely not work.
numSamples :: Int
numSamples = 400

-- Constant: Max difference accepted between actual occurrences and
-- expected occurrences
margin :: Int
margin = round (fromIntegral numSamples * 0.05)

-- * Auxiliary definitions

-- | Check whether a list of values exhibits randomness.
Expand Down

0 comments on commit 38655c6

Please sign in to comment.