packages feed

mediabus-0.4.0.0: specs/Data/MediaBus/Media/SyncStreamSpec.hs

module Data.MediaBus.Media.SyncStreamSpec
  ( spec
  ) where

import Control.Lens
import Control.Monad.State
import Data.Function
import Data.MediaBus
import Debug.Trace
import Test.Hspec
import Test.QuickCheck

newtype FakePayload = FP
  { fakeDuration :: Ticks64At8000
  } deriving (Eq, Show, Num, Arbitrary, Ord)

instance HasDuration FakePayload where
  getDuration = view (to fakeDuration . nominalDiffTime)

spec :: Spec
spec =
  describe "setSequenceNumberAndTimestamp" $ do
    it "increases the sequence number by one (only) for each frame" $
      let prop :: (NonEmptyList (SyncStream () () FakePayload)) -> Bool
          prop (NonEmpty inStr) =
            let expectedLastSeqNum =
                  let isNext (MkStream (Next _)) = True
                      isNext _ = False
                  in max 0 (fromIntegral (length (filter isNext inStr)) - 1)
                actualLastSeqNum =
                  let outStr =
                        let z :: (SeqNum16, Ticks64At8000)
                            z = (0, 0)
                        in evalState
                             (mapM
                                (state . setSequenceNumberAndTimestamp)
                                inStr)
                             z
                  in case last outStr of
                       MkStream (Next f) -> f ^. seqNum
                       MkStream (Start f) -> max 0 (f ^. seqNum - 1)
            in expectedLastSeqNum == actualLastSeqNum
      in property prop
    it "increases the sequence number monotonic" $
      let prop :: (NonEmptyList (SyncStream () () FakePayload)) -> Bool
          prop (NonEmpty inStr) =
            let seqNumDiffs =
                  let outFrames =
                        let isNext (MkStream (Next _)) = True
                            isNext _ = False
                            outStr =
                              let z :: (SeqNum16, Ticks64At8000)
                                  z = (0, 0)
                              in evalState
                                   (mapM
                                      (state . setSequenceNumberAndTimestamp)
                                      inStr)
                                   z
                        in filter isNext outStr
                  in zipWith ((-) `on` (view seqNum)) (drop 1 outFrames) outFrames
            in all (== 1) seqNumDiffs
      in property prop
    it "increases the timestamps by the duration of each frame" $
      let prop :: (NonEmptyList (SyncStream () () FakePayload)) -> Bool
          prop (NonEmpty inStr) =
            let isNext (MkStream (Next _)) = True
                isNext _ = False
                outFrames :: [Stream () SeqNum16 Ticks64At8000 () FakePayload]
                outFrames =
                  let outStr =
                        let z :: (SeqNum16, Ticks64At8000)
                            z = (0, MkTicks 0)
                        in evalState
                             (mapM
                                (state . setSequenceNumberAndTimestamp)
                                inStr)
                             z
                  in filter isNext outStr
                timestamps = map (view timestamp) outFrames
                expectedTimestamps :: [Ticks64At8000]
                expectedTimestamps =
                  let inFramesWithoutLast =
                        (filter isNext inStr)
                      inDurations =
                        map (view (from nominalDiffTime) . getDuration)
                        inFramesWithoutLast

                  in scanl (+) 0 inDurations
            in if and (zipWith (==) timestamps expectedTimestamps)
                 then True
                 else traceShow ( timestamps
                                , expectedTimestamps
                                , outFrames) False
      in property prop