packages feed

yampa-test-0.14.12: tests/Test/FRP/Yampa/Conditional.hs

{-# LANGUAGE Arrows #-}
{-# LANGUAGE CPP    #-}
-- |
-- Description : Test cases for FRP.Yampa.Conditional
-- Copyright   : (c) Ivan Perez, 2014-2022
--               (c) Antony Courtney and Henrik Nilsson, Yale University, 2003-2004
-- Authors     : Antony Courtney, Henrik Nilsson, Ivan Perez
module Test.FRP.Yampa.Conditional
    ( tests
    )
  where

#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<*>))
import Data.Functor        ((<$>))
#endif
import Test.QuickCheck
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.QuickCheck (testProperty)

import FRP.Yampa as Yampa
import FRP.Yampa.LTLFuture  (TPred (Always, SP), evalT)
import FRP.Yampa.QuickCheck (uniDistStream)
import FRP.Yampa.Stream     (SignalSampleStream)

import TestsCommon

tests :: TestTree
tests = testGroup "Regression tests for FRP.Yampa.Conditional"
  [ testProperty "provided (1, fixed)" (property $ utils_t8 ~= utils_t8r)
  , testProperty "provided (2, fixed)" (property $ utils_t9 ~= utils_t9r)
  , testProperty "pause (qc)"          propPause
  ]

-- * Guards and automata-oriented combinators

utils_t8 :: [Double]
utils_t8 = take 50 $ embed (provided (even . floor) integral (constant (-1)))
                           (deltaEncode 0.1 input)
  where
    input = replicate 10 1
            ++ replicate 10 2
            ++ replicate 10 3
            ++ replicate 10 4
            ++ input

utils_t8r =
  [ -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0
  ,  0.0,  0.2,  0.4,  0.6,  0.8,  1.0,  1.2,  1.4,  1.6,  1.8
  , -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0
  ,  0.0,  0.4,  0.8,  1.2,  1.6,  2.0,  2.4,  2.8,  3.2,  3.6
  , -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0
  ]

utils_t9 :: [Double]
utils_t9 = take 50 $ embed (provided (odd . floor) integral (constant (-1)))
                           (deltaEncode 0.1 input)
  where
    input = replicate 10 1
            ++ replicate 10 2
            ++ replicate 10 3
            ++ replicate 10 4
            ++ input

utils_t9r =
  [  0.0,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9
  , -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0
  ,  0.0,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8,  2.1,  2.4,  2.7
  , -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0
  ,  0.0,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9
  ]

propPause :: Property
propPause =
    forAll initialValueG $ \initialValue ->
    forAll myStream $ evalT $
      -- The behavior of pause is always the same as some ideal behavior
      -- implemented by modelPause below. We give these auxiliary definitions
      -- names and pass initialValue as argument to facilitate debugging.
      Always $ SP $ (==) <$> sfPause initialValue <*> sfModelPause initialValue
  where
    myStream :: Gen (SignalSampleStream Float)
    myStream = uniDistStream

    initialValueG :: Gen Float
    initialValueG = arbitrary

    -- SF that uses the actual function being tested
    sfPause :: Float -> SF Float Float
    sfPause initialValue = pause initialValue (arr (odd . round)) integral

    -- Model SF that uses the actual function being tested
    sfModelPause :: Float -> SF Float Float
    sfModelPause initialValue =
      modelPause initialValue (arr (odd . round)) integral

    -- Model implementation of pause.
    modelPause :: b -> SF a Bool -> SF a b -> SF a b
    modelPause acc0 sf1 sf2 = proc (a) -> do
      rec c <- sf1 -< a

          -- Accumulator that is updated only when then condition is false.
          acc <- hold acc0 -< e

          -- When the condition is false, sf2 is turned on and executed,
          -- producing a new Event. Note that we need to put this in an
          -- ArrowCase block, we can't just run both and the decide whether we
          -- want to output the value or not based on the condition, because,
          -- in that case, the argument sf2 would still be executed and
          -- accumulate state.
          e <- if c then returnA -< NoEvent
                    else Event ^<< sf2 -< a

      returnA -< acc