packages feed

machinecell-4.0.0: test/Types/BasicSpec.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}

module
    Types.BasicSpec
where

import qualified Control.Arrow.Machine as P

import Control.Arrow.Machine hiding (filter, source)
import Control.Applicative
import qualified Control.Category as Cat
import Control.Arrow
import Control.Monad.State
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Identity (Identity, runIdentity)
import Debug.Trace
import Test.Hspec
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck (Arbitrary, arbitrary, oneof, frequency, sized)

import Common.RandomProc


spec =
  do
    it "is stream transducer." $
      do
        let
          process = repeatedly $
            do
              x <- await
              yield x
              yield (x + 1)

          resultA = run process [1,2,4]

        resultA `shouldBe` [1, 2, 2, 3, 4, 5]

    let
        -- 入力1度につき同じ値を2回出力する
        doubler = repeatedly $
                  do {x <- await; yield x; yield x}
        -- 入力値をStateのリストの先頭にPushする副作用を行い、同じ値を出力する
        pusher = repeatedlyT $
                 do {x <- await; lift $ modify (x:); yield x}

    it "has stop state" $
      let
          -- 一度だけ入力をそのまま出力し、すぐに停止する
          onlyOnce = construct $ await >>= yield

          x = stateProc (doubler >>> pusher >>> onlyOnce) [3, 3]
        in
          -- 最後尾のMachineが停止した時点で処理を停止するが、
          -- 既にa2が出力した値の副作用は処理する
          x `shouldBe` ([3], [3, 3])

    it "has side-effect" $
      let
          incl = evMap (+1)

          -- doublerで信号が2つに分岐する。
          -- このとき、副作用は1つ目の信号について末尾まで
          -- -> 二つ目の信号について分岐点から末尾まで ...
          -- の順で処理される。
          a = pusher >>> doubler >>> incl >>> pusher >>> incl >>> pusher

          x = stateProc a [1000]
        in
          x `shouldBe` ([1002, 1002], reverse [1000,1001,1002,1001,1002])

    it "never spoils any FEED" $
      let
          counter = construct $ counterDo 1
          counterDo n =
            do
              x <- await
              yield $ n * 100 + x
              counterDo (n+1)
          x = stateProc (doubler >>> doubler >>> counter) [1,2]
        in
          fst x `shouldBe` [101, 201, 301, 401, 502, 602, 702, 802]

    prop "each path can have independent number of events" $ \l ->
      let
          split2' = fmap fst &&& fmap snd
          gen = arr (fmap $ \x -> [x, x]) >>> fork >>> arr split2'
          r1 = run (gen >>> arr fst) (l::[(Int, [Int])])
          r2 = run (gen >>> second (fork >>> repeatedly (await >>= yield)) >>> arr fst)
               (l::[(Int, [Int])])
        in
          r1 == r2

    it "is lazy for individual input values" $
      do
        let l = run Cat.id (take 10 $ repeat undefined)
        length l `shouldBe` 10

{-
    it "is lazy for inpurt stream" $
      do
        let l = take 10 $ run Cat.id (repeat undefined)
        length l `shouldBe` 10
-}