packages feed

zwirn-0.2.2.0: test/zwirn-core/Main.hs

{-# LANGUAGE MultiParamTypeClasses #-}

import Control.Monad
import Data.Bifunctor (first)
import Data.Functor.Identity
import qualified Data.List as L
import qualified Data.Map as Map
import qualified Data.Ratio as R
import Test.Tasty
import Test.Tasty.HUnit
import Zwirn.Core.Cord as Z
import Zwirn.Core.Core
import Zwirn.Core.Lib.Conditional
import Zwirn.Core.Lib.Cord
import Zwirn.Core.Lib.Core
import Zwirn.Core.Lib.Map
import Zwirn.Core.Lib.Modulate
import Zwirn.Core.Lib.Number
import Zwirn.Core.Lib.Random
import Zwirn.Core.Lib.Structure
import Zwirn.Core.Query
import Zwirn.Core.Time
import Zwirn.Core.Tree (Tree (..))
import Zwirn.Core.Types

main = defaultMain tests

tests :: TestTree
tests = testGroup "Tests" [unitTests]

queryFirst :: Cord () () a -> [(Time, a)]
queryFirst = findAllValuesWithTime (Time 0 1, Time 1 1) ()

queryN :: Rational -> Cord () () a -> [(Time, a)]
queryN n = findAllValuesWithTime (Time 0 1, Time n 1) ()

(@?~) :: (Show a, Eq a) => [(Time, a)] -> [(Time, a)] -> Assertion
(@?~) actual expected = unless (Prelude.and check && length actual == length expected) (assertFailure msg)
  where
    msg = "expected: " ++ show expected ++ "\n but got: " ++ show actual
    check = zipWith (\(a, v1) (b, v2) -> abs (a - b) < 0.01 && v1 == v2) expected actual

-- | should be used for signals
(~@?~) :: (Show a, Eq a, Fractional a, Ord a) => [(Time, a)] -> [(Time, a)] -> Assertion
(~@?~) actual expected = unless (Prelude.and check && length actual == length expected) (assertFailure msg)
  where
    msg = "expected: " ++ show expected ++ "\n but got: " ++ show actual
    check = zipWith (\(a, v1) (b, v2) -> abs (a - b) < 0.01 && (abs (v1 - v2) < 0.01)) expected actual

(%) :: Integer -> Integer -> Time
(%) x y = Time (x R.% y) (0 R.% 1)

simpleZwirn :: Cord () () Int
simpleZwirn = fastcat [pure 1, pure 2, pure 3, pure 4]

nestedZwirn :: Cord () () Int
nestedZwirn = fastcat [pure 10, pure 20, fastcat [pure 30, pure 40]]

veryNested :: Cord () () Int
veryNested = fastcat [simpleZwirn, nestedZwirn]

simpleCord :: Cord () () Int
simpleCord = stack [pure 10, simpleZwirn]

instance State Tree () () where
  beatsPerCycle = pure 8

unitTests =
  testGroup
    "Unit tests"
    [ testCase "pure for Zwirns" $
        queryFirst (pure 1 :: Cord () () Int) @?~ [(0, 1)],
      testCase "simple nesting" $
        queryFirst simpleZwirn @?~ [(0, 1), (1 % 4, 2), (1 % 2, 3), (3 % 4, 4)],
      testCase "more nesting" $
        queryFirst nestedZwirn @?~ [(0, 10), (1 % 3, 20), (2 % 3, 30), (5 % 6, 40)],
      testCase "very nested" $
        queryFirst veryNested @?~ [(0, 1), (1 % 8, 2), (2 % 8, 3), (3 % 8, 4), (1 % 2, 10), (4 % 6, 20), (5 % 6, 30), (11 % 12, 40)],
      testCase "reverse simple Zwirn" $
        queryFirst (rev simpleZwirn) @?~ [(0, 4), (1 % 4, 3), (1 % 2, 2), (3 % 4, 1)],
      testCase "reverse more nesting" $
        queryFirst (rev nestedZwirn) @?~ [(0, 40), (1 % 6, 30), (1 % 3, 20), (2 % 3, 10)],
      testCase "reverse inside" $
        queryFirst (fastcat [pure 100, rev simpleZwirn, pure 200, pure 300]) @?~ [(0, 100), (4 % 16, 4), (5 % 16, 3), (6 % 16, 2), (7 % 16, 1), (1 % 2, 200), (3 % 4, 300)],
      testCase "reverse reverse inside" $
        queryFirst (rev $ fastcat [pure 100, rev simpleZwirn, pure 200, pure 300]) @?~ [(0, 300), (1 % 4, 200), (8 % 16, 1), (9 % 16, 2), (10 % 16, 3), (11 % 16, 4), (3 % 4, 100)],
      testCase "squeezeJoin" $
        queryFirst (squeezeJoin $ fmap (const $ fastcat [pure 10, pure 20 :: Cord () () Int]) simpleZwirn) @?~ [(0, 10), (1 % 8, 20), (2 % 8, 10), (3 % 8, 20), (4 % 8, 10), (5 % 8, 20), (6 % 8, 10), (7 % 8, 20)],
      testCase "ply" $
        queryFirst (ply (pure 2) simpleZwirn) @?~ [(0, 1), (1 / 8, 1), (1 / 4, 2), (3 / 8, 2), (1 / 2, 3), (5 / 8, 3), (3 / 4, 4), (7 / 8, 4)],
      testCase "loop" $
        queryFirst (loop (pure 0.25) (pure 0.75) simpleZwirn) @?~ [(0, 2), (1 / 4, 3), (1 / 2, 2), (3 / 4, 3)],
      testCase "zoom rev" $
        queryFirst (zoom (pure 1) (pure 0) simpleZwirn) @?~ queryFirst (rev simpleZwirn),
      testCase "timeloop" $
        queryFirst (timeloop (pure 0.25) simpleZwirn) @?~ [(0, 1), (1 / 4, 1), (1 / 2, 1), (3 / 4, 1)],
      testCase "cat" $
        queryN 4 (cat (0.25, pure 1) (0.25, pure 2)) @?~ [(0, 1), (1 / 4, 2), (2, 1), (9 / 4, 2)],
      testCase "cyclecat" $
        queryN 3 (cyclecat [(1, pure 10), (2, slow (pure 2) $ pure 20)]) @?~ [(0, 10), (1, 20)],
      testCase "cyclecat 2" $
        queryN 2 (cyclecat [(0.5, pure 10), (1, pure 20), (0.5, pure 30)]) @?~ [(0, 10), (1 / 2, 20), (3 / 2, 30)],
      testCase "fastcyclecat" $
        queryFirst (fastcyclecat [(0.25, pure 1), (0.25, pure 2)]) @?~ [(0, 1), (1 / 4, 2), (1 / 2, 1), (3 / 4, 2)],
      testCase "fastcyclecat2" $
        queryFirst (fastcyclecat [(0.5, pure 1), (0.25, pure 2)]) @?~ [(0, 1), (1 / 2, 2), (3 / 4, 1)],
      testCase "euclid" $
        queryFirst (euclid (pure 3) (pure 8) (pure 1)) @?~ [(0, 1), (3 / 8, 1), (3 / 4, 1)],
      testCase "everyFor" $
        queryFirst (everyFor (pure 1) (pure 0.5) (pure $ fmap succ) simpleZwirn) @?~ [(0, 2), (1 / 4, 3), (1 / 2, 3), (3 / 4, 4)],
      testCase "everyFor 2" $
        queryN 2 (everyFor (pure 0.75) (pure 0.5) (pure $ fmap (const 100)) simpleZwirn) @?~ [(0, 100), (1 / 4, 100), (1 / 2, 3), (3 / 4, 100), (1, 100), (5 / 4, 2), (3 / 2, 100), (7 / 4, 100)],
      testCase "ifthen" $
        queryFirst (ifthen (fastcat [pure True, pure False]) (pure 10) (fastcat [pure 20, pure 30])) @?~ [(0, 10), (1 / 2, 30)],
      testCase "ifthen 2" $
        queryFirst (ifthen (fastcat [pure True, pure False]) simpleZwirn simpleZwirn) @?~ [(0, 1), (1 / 4, 2), (1 / 2, 3), (3 / 4, 4)],
      testCase "while" $
        queryFirst (while (fastcat [pure True, pure False]) (pure $ fmap succ) simpleZwirn) @?~ [(0, 2), (1 / 4, 3), (1 / 2, 3), (3 / 4, 4)],
      testCase "simpleCord" $
        queryFirst simpleCord @?~ [(0, 10), (0, 1), (1 / 4, 2), (1 / 2, 3), (3 / 4, 4)],
      testCase "enum cord" $
        queryFirst (enumFromToStack (pure 0) (pure 4)) @?~ [(0, 0), (0, 1), (0, 2), (0, 3)],
      testCase "zipApply" $
        queryFirst (zipApply (stack [pure $ fmap (+ 10), pure $ fmap (+ 100)]) (stack [fastcat [pure 1, pure 2], pure 3])) @?~ [(0 % 1, 11), (0 % 1, 103), (1 % 2, 12)],
      testCase "sine" $
        queryFirst (segment (pure 4) sine) ~@?~ [(0, 0.5), (1 / 4, 1), (1 / 2, 0.5), (3 / 4, 0)],
      testCase "rev sine" $
        queryFirst (segment (pure 4) $ rev sine) ~@?~ [(0, 0.5), (1 / 4, 0), (1 / 2, 0.5), (3 / 4, 1)],
      testCase "singleton" $
        queryFirst (singleton (pure "n") (fast (pure 2) $ pure 1)) @?~ [(0, Map.singleton "n" 1), (1 / 2, Map.singleton "n" 1)],
      testCase "union" $
        queryFirst (singleton (pure "n") (fast (pure 2) $ pure 1) `union` singleton (pure "s") (pure 1))
          @?~ [ (0, Map.singleton "n" 1 `Map.union` Map.singleton "s" 1),
                (1 / 2, Map.singleton "n" 1 `Map.union` Map.singleton "s" 1)
              ],
      testCase "fix" $
        queryFirst (fix (fastcat [pure "n"]) (pure $ const $ pure 10) (singleton (pure "n") (fast (pure 2) $ pure 1) `union` singleton (pure "s") (pure 1)))
          @?~ [ (0, Map.singleton "n" 10 `Map.union` Map.singleton "s" 1),
                (1 / 2, Map.singleton "n" 10 `Map.union` Map.singleton "s" 1)
              ],
      testCase "fix 2" $
        queryFirst (fix (fastcat [pure "n", pure "s"]) (pure $ const $ pure 10) (singleton (pure "n") (fast (pure 2) $ pure 1) `union` singleton (pure "s") (pure 1)))
          @?~ [ (0, Map.singleton "n" 10 `Map.union` Map.singleton "s" 1),
                (1 / 2, Map.singleton "n" 1 `Map.union` Map.singleton "s" 10)
              ],
      testCase "chunked" $
        queryFirst (chunked (pure "I:") (pure 1))
          @?~ [(0, 1), (1 / 4, 1), (3 / 8, 1), (1 / 2, 1), (3 / 4, 1), (7 / 8, 1)],
      testCase "chunked2" $
        queryFirst (fast (pure $ 5 / 8) $ chunked (pure "vi") (pure 1))
          @?~ [(1 / 5, 1), (2 / 5, 1), (3 / 5, 1), (4 / 5, 1)],
      testCase "chunked3" $
        queryFirst (chunked (pure "i~") (fastcat [pure 1, pure 2]))
          @?~ [(0, 1), (1 / 8, 1), (1 / 4, 1), (1 / 2, 2), (5 / 8, 2), (3 / 4, 2)],
      testCase "chunk" $
        queryFirst (chunk (pure "i~"))
          @?~ [(0, 0), (1 / 8, 1), (1 / 4, 2), (1 / 2, 0), (5 / 8, 1), (3 / 4, 2)],
      testCase "nested chunk" $
        queryFirst (slow (pure 2) $ chunked (pure "I[:]~") (pure 1))
          @?~ [(0, 1), (1 / 2, 1), (5 / 8, 1)],
      testCase "binary" $
        queryFirst (slow (pure 2) $ chunked (binary (pure 5)) (pure 1))
          @?~ [(0, 1), (1 / 2, 1), (3 / 4, 1)],
      testCase "christoffel" $
        queryFirst (chunked (christoffel (pure 3) (pure 5)) (pure 1))
          @?~ [(0, 1), (1 / 8, 1), (3 / 8, 1), (1 / 2, 1), (3 / 4, 1)],
      testCase "silence" $
        queryFirst (fastcat [silence, pure 2, silence, pure 4])
          @?~ [(1 / 4, 2), (3 / 4, 4)],
      testCase "everyBeat" $
        queryFirst (everyBeat (pure 4) (pure $ \x -> x + 1) simpleZwirn)
          @?~ [(0, 2), (1 / 4, 2), (1 / 2, 4), (3 / 4, 4)]
    ]