diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad2b582d..18cedc03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,29 +77,23 @@ jobs: - name: test run: cabal v2-test ${{ matrix.versions.args }} --enable-tests --enable-benchmarks all -ormolu: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Detect and switch to current branch - run: | - BRANCH_NAME=$(git branch --show-current || echo "${{ github.ref_name }}") - git checkout "$BRANCH_NAME" - - - uses: haskell-actions/run-ormolu@v17 - with: - mode: inplace - pattern: | - src/**/*.hs - tidal-core/src/**/*.hs - tidal-link/src/**/*.hs - tidal-parse/src/**/*.hs - tidal-listener/src/**/*.hs - - - name: apply ormolu formatting - uses: stefanzweifel/git-auto-commit-action@v4 - if: ${{ always() }} - with: - commit_message: automated ormolu reformatting - branch: ${{ github.head_ref || github.ref_name }} + ormolu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: haskell-actions/run-ormolu@v17 + with: + mode: inplace + pattern: | + src/**/*.hs + tidal-core/src/**/*.hs + tidal-link/src/**/*.hs + tidal-parse/src/**/*.hs + tidal-listener/src/**/*.hs + - name: apply ormolu formatting + uses: stefanzweifel/git-auto-commit-action@v4 + if: ${{ always() }} + with: + commit_message: automated ormolu reformatting + branch: ${{ github.head_ref || github.ref_name }} diff --git a/src/Sound/Tidal/Stream/Types.hs b/src/Sound/Tidal/Stream/Types.hs index e5e29a47..211fec52 100644 --- a/src/Sound/Tidal/Stream/Types.hs +++ b/src/Sound/Tidal/Stream/Types.hs @@ -80,4 +80,4 @@ type PlayMap = Map.Map PatId PlayState -- tickArc :: Arc, -- tickNudge :: Double -- } --- deriving Show \ No newline at end of file +-- deriving Show diff --git a/stack.yaml b/stack.yaml index a5d98f5b..df1c3e94 100644 --- a/stack.yaml +++ b/stack.yaml @@ -10,3 +10,6 @@ packages: extra-deps: - hosc-0.21 - haskellish-0.3.2.2 + - hspec-2.11.9 + - hspec-core-2.11.9 + - hspec-discover-2.11.9 diff --git a/test/Sound/Tidal/StreamTest.hs b/test/Sound/Tidal/StreamTest.hs index 81d4c10c..9d86706a 100644 --- a/test/Sound/Tidal/StreamTest.hs +++ b/test/Sound/Tidal/StreamTest.hs @@ -6,9 +6,9 @@ import qualified Data.Map.Strict as M import qualified Sound.Osc.Fd as O import Sound.Tidal.Pattern import Sound.Tidal.Stream -import Test.Microspec +import Test.Hspec -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Stream" $ do describe "toDatum" $ do diff --git a/test/Test.hs b/test/Test.hs index f0ecbbe6..8fd5ae8c 100644 --- a/test/Test.hs +++ b/test/Test.hs @@ -1,8 +1,8 @@ {-# LANGUAGE OverloadedStrings #-} import Sound.Tidal.StreamTest -import Test.Microspec +import Test.Hspec main :: IO () -main = microspec $ do +main = hspec $ do Sound.Tidal.StreamTest.run diff --git a/test/TestUtils.hs b/test/TestUtils.hs index 6662a8af..a9378973 100644 --- a/test/TestUtils.hs +++ b/test/TestUtils.hs @@ -7,7 +7,7 @@ module TestUtils where import Data.List (sort) import qualified Data.Map.Strict as Map import Sound.Tidal.Context -import Test.Microspec +import Test.Hspec import Prelude hiding ((*>), (<*)) class TolerantEq a where @@ -33,13 +33,13 @@ instance TolerantEq (Event ValueMap) where (Event _ w p x) ~== (Event _ w' p' x') = w == w' && p == p' && x ~== x' -- | Compare the events of two patterns using the given arc -compareP :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Property +compareP :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Expectation compareP a p p' = sort (queryArc (stripContext p) a) `shouldBe` sort (queryArc (stripContext p') a) -- | Like @compareP@, but tries to 'defragment' the events -comparePD :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Property +comparePD :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Expectation comparePD a p p' = sort (defragParts $ queryArc (stripContext p) a) `shouldBe` sort (defragParts $ queryArc (stripContext p') a) @@ -56,4 +56,4 @@ stripContext :: Pattern a -> Pattern a stripContext = setContext $ Context [] firstCycleValues :: Pattern a -> [a] -firstCycleValues pat = map value $ queryArc pat (Arc 0 1) \ No newline at end of file +firstCycleValues pat = map value $ queryArc pat (Arc 0 1) diff --git a/tidal-core/src/Sound/Tidal/Scales.hs b/tidal-core/src/Sound/Tidal/Scales.hs index c8a5e54c..84de7c44 100644 --- a/tidal-core/src/Sound/Tidal/Scales.hs +++ b/tidal-core/src/Sound/Tidal/Scales.hs @@ -308,7 +308,7 @@ getScale table sp p = noteInScale (fromMaybe [0] $ lookup scaleName table) n ) <$> p - <* sp + <* sp where octave s x = x `div` length s noteInScale s x = (s !!! x) + fromIntegral (12 * octave s x) @@ -337,7 +337,7 @@ getScaleMod table sp f p = noteInScale (uniq $ f $ fromMaybe [0] $ lookup scaleName table) n ) <$> p - <* sp + <* sp where octave s x = x `div` length s noteInScale s x = (s !!! x) + fromIntegral (12 * octave s x) diff --git a/tidal-core/test/Sound/Tidal/ChordsTest.hs b/tidal-core/test/Sound/Tidal/ChordsTest.hs index 1df860e4..92ebf260 100644 --- a/tidal-core/test/Sound/Tidal/ChordsTest.hs +++ b/tidal-core/test/Sound/Tidal/ChordsTest.hs @@ -3,11 +3,11 @@ module Sound.Tidal.ChordsTest where import Sound.Tidal.Pattern -import Test.Microspec +import Test.Hspec import TestUtils import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Chords" $ do describe "chord" $ do diff --git a/tidal-core/test/Sound/Tidal/ControlTest.hs b/tidal-core/test/Sound/Tidal/ControlTest.hs index a6f0e52a..ad1902a1 100644 --- a/tidal-core/test/Sound/Tidal/ControlTest.hs +++ b/tidal-core/test/Sound/Tidal/ControlTest.hs @@ -6,11 +6,11 @@ import Sound.Tidal.Control import Sound.Tidal.Core import Sound.Tidal.Params import Sound.Tidal.Pattern -import Test.Microspec +import Test.Hspec import TestUtils import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Control" $ do describe "echo" $ do diff --git a/tidal-core/test/Sound/Tidal/CoreTest.hs b/tidal-core/test/Sound/Tidal/CoreTest.hs index 89bc0a06..e76782f9 100644 --- a/tidal-core/test/Sound/Tidal/CoreTest.hs +++ b/tidal-core/test/Sound/Tidal/CoreTest.hs @@ -5,21 +5,15 @@ module Sound.Tidal.CoreTest where import Data.List (sort) import qualified Data.Map as Map import Data.Ratio -import Sound.Tidal.Control as C import Sound.Tidal.Core as C -import Sound.Tidal.Params as C -import Sound.Tidal.ParseBP as C import Sound.Tidal.Pattern as C -import Sound.Tidal.Scales as C -import Sound.Tidal.Show as C -import Sound.Tidal.Simple as C -import Sound.Tidal.Stepwise as C import Sound.Tidal.UI as C -import Test.Microspec +import Test.Hspec +import Test.Hspec.QuickCheck import TestUtils import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Core" $ do describe "Elemental patterns" $ do @@ -29,23 +23,23 @@ run = let inNormalRange pat t = (y >= 0) && (y <= 1) where y = sampleOf pat t - it "sine" $ inNormalRange sine - it "cosine" $ inNormalRange cosine - it "saw" $ inNormalRange saw - it "isaw" $ inNormalRange isaw - it "tri" $ inNormalRange tri - it "square" $ inNormalRange square + prop "sine" $ inNormalRange sine + prop "cosine" $ inNormalRange cosine + prop "saw" $ inNormalRange saw + prop "isaw" $ inNormalRange isaw + prop "tri" $ inNormalRange tri + prop "square" $ inNormalRange square describe "have correctly-scaled bipolar variants" $ do let areCorrectlyScaled pat pat2 t = (y * 2 - 1) ~== y2 where y = sampleOf pat t y2 = sampleOf pat2 t - it "sine" $ areCorrectlyScaled sine sine2 - it "cosine" $ areCorrectlyScaled cosine cosine2 - it "saw" $ areCorrectlyScaled saw saw2 - it "isaw" $ areCorrectlyScaled isaw isaw2 - it "tri" $ areCorrectlyScaled tri tri2 - it "square" $ areCorrectlyScaled square square2 + prop "sine" $ areCorrectlyScaled sine sine2 + prop "cosine" $ areCorrectlyScaled cosine cosine2 + prop "saw" $ areCorrectlyScaled saw saw2 + prop "isaw" $ areCorrectlyScaled isaw isaw2 + prop "tri" $ areCorrectlyScaled tri tri2 + prop "square" $ areCorrectlyScaled square square2 describe "append" $ it "can switch between the cycles from two pures" $ do @@ -80,30 +74,28 @@ run = (cat [rev a, rev b, rev c]) describe "fastCat" $ do - it "can switch between the cycles from three pures inside one cycle" $ do - it "1" $ - queryArc (fastCat [pure "a", pure "b", pure "c"]) (Arc 0 1) - `shouldBe` fmap - toEvent - [ (((0, 1 / 3), (0, 1 / 3)), "a" :: String), - (((1 / 3, 2 / 3), (1 / 3, 2 / 3)), "b"), - (((2 / 3, 1), (2 / 3, 1)), "c") - ] - it "5/3" $ - queryArc (fastCat [pure "a", pure "b", pure "c"]) (Arc 0 (5 / 3)) - `shouldBe` fmap - toEvent - [ (((0, 1 / 3), (0, 1 / 3)), "a" :: String), - (((1 / 3, 2 / 3), (1 / 3, 2 / 3)), "b"), - (((2 / 3, 1), (2 / 3, 1)), "c"), - (((1, 4 / 3), (1, 4 / 3)), "a"), - (((4 / 3, 5 / 3), (4 / 3, 5 / 3)), "b") - ] - it "works with zero-length queries" $ do - it "0" $ + it "can switch between the cycles from three pures inside one cycle (1)" $ do + queryArc (fastCat [pure "a", pure "b", pure "c"]) (Arc 0 1) + `shouldBe` fmap + toEvent + [ (((0, 1 / 3), (0, 1 / 3)), "a" :: String), + (((1 / 3, 2 / 3), (1 / 3, 2 / 3)), "b"), + (((2 / 3, 1), (2 / 3, 1)), "c") + ] + it "can switch between the cycles from three pures inside one cycle (5/3)" $ do + queryArc (fastCat [pure "a", pure "b", pure "c"]) (Arc 0 (5 / 3)) + `shouldBe` fmap + toEvent + [ (((0, 1 / 3), (0, 1 / 3)), "a" :: String), + (((1 / 3, 2 / 3), (1 / 3, 2 / 3)), "b"), + (((2 / 3, 1), (2 / 3, 1)), "c"), + (((1, 4 / 3), (1, 4 / 3)), "a"), + (((4 / 3, 5 / 3), (4 / 3, 5 / 3)), "b") + ] + it "works with zero-length queries (0)" $ do queryArc (fastCat [pure "a", pure "b"]) (Arc 0 0) `shouldBe` fmap toEvent [(((0, 0.5), (0, 0)), "a" :: String)] - it "1/3" $ + it "works with zero-length queries (1/3)" $ do queryArc (fastCat [pure "a", pure "b"]) (Arc (1 % 3) (1 % 3)) `shouldBe` fmap toEvent [(((0, 0.5), (1 % 3, 1 % 3)), "a" :: String)] @@ -123,17 +115,16 @@ run = b = "4 [5, 5] 6 7" :: Pattern Int c = "7 8 9 10" :: Pattern Int d = "7 [8, 9] 10 11" :: Pattern Int - it "creates silence when" $ do - it "first argument silent" $ - comparePD - (Arc 0 1) - (silence |>| a) - silence - it "second argument silent" $ - comparePD - (Arc 0 1) - (a |>| silence) - silence + it "creates silence when first argument silent" $ + comparePD + (Arc 0 1) + (silence |>| a) + silence + it "creates silence when second argument silent" $ + comparePD + (Arc 0 1) + (a |>| silence) + silence it "creates the same pattern when left argument has the same structure" $ comparePD (Arc 0 1) @@ -193,22 +184,21 @@ run = (Arc 0 1) (fast 1 x) x - it "mutes, when there is" $ do - it "silence in first argument" $ - comparePD - (Arc 0 1) - (fast silence x) - silence - it "silence in second argument" $ - comparePD - (Arc 0 1) - (fast x silence :: Pattern Time) - silence - it "speedup by 0" $ - comparePD - (Arc 0 1) - (fast 0 x) - silence + it "it mutes, when there is silence in first argument" $ + comparePD + (Arc 0 1) + (fast silence x) + silence + it "it mute, when there is silence in second argument" $ + comparePD + (Arc 0 1) + (fast x silence :: Pattern Time) + silence + it "it mute, when there is speedup by 0" $ + comparePD + (Arc 0 1) + (fast 0 x) + silence it "is reciprocal to slow" $ comparePD (Arc 0 1) @@ -233,22 +223,21 @@ run = (Arc 0 10) (slow 1 x) x - it "mutes, when there is" $ do - it "silence in first argument" $ - comparePD - (Arc 0 10) - (slow silence x) - silence - it "silence in second argument" $ - comparePD - (Arc 0 10) - (slow x silence :: Pattern Time) - silence - it "speedup by 0" $ - comparePD - (Arc 0 10) - (slow 0 x) - silence + it "mutes, when there is silence in first argument" $ + comparePD + (Arc 0 10) + (slow silence x) + silence + it "mutes, when there is silence in second argument" $ + comparePD + (Arc 0 10) + (slow x silence :: Pattern Time) + silence + it "mutes, when it is speedup by 0" $ + comparePD + (Arc 0 10) + (slow 0 x) + silence it "is reciprocal to fast" $ comparePD (Arc 0 10) @@ -291,16 +280,17 @@ run = (((0.5, 0.75), (0.5, 0.75)), 8) ] + describe "saw goes from 0 up to 1 every cycle" $ do + it "0" $ + queryArc saw (Arc 0 0) `shouldBe` [Event (Context []) Nothing (Arc 0 0) 0 :: Event Double] + it "0.25" $ + queryArc saw (Arc 0.25 0.25) `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) 0.25 :: Event Double] + it "0.5" $ + queryArc saw (Arc 0.5 0.5) `shouldBe` [Event (Context []) Nothing (Arc 0.5 0.5) 0.5 :: Event Double] + it "0.75" $ + queryArc saw (Arc 0.75 0.75) `shouldBe` [Event (Context []) Nothing (Arc 0.75 0.75) 0.75 :: Event Double] + describe "saw" $ do - it "goes from 0 up to 1 every cycle" $ do - it "0" $ - queryArc saw (Arc 0 0) `shouldBe` [Event (Context []) Nothing (Arc 0 0) 0 :: Event Double] - it "0.25" $ - queryArc saw (Arc 0.25 0.25) `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) 0.25 :: Event Double] - it "0.5" $ - queryArc saw (Arc 0.5 0.5) `shouldBe` [Event (Context []) Nothing (Arc 0.5 0.5) 0.5 :: Event Double] - it "0.75" $ - queryArc saw (Arc 0.75 0.75) `shouldBe` [Event (Context []) Nothing (Arc 0.75 0.75) 0.75 :: Event Double] it "can be added to" $ map value (queryArc ((+ 1) <$> saw) (Arc 0.5 0.5)) `shouldBe` [1.5 :: Float] it "works on the left of <*>" $ @@ -313,16 +303,15 @@ run = Event (Context []) Nothing (Arc 0.5 0.75) 3, Event (Context []) Nothing (Arc 0.75 1) 3 ] - it "can be reversed" $ do - it "works with whole cycles" $ - queryArc (rev saw) (Arc 0 1) - `shouldBe` [Event (Context []) Nothing (Arc 0 1) 0 :: Event Double] - it "works with half cycles" $ - queryArc (rev saw) (Arc 0.5 1) - `shouldBe` [Event (Context []) Nothing (Arc 0.5 1) 0 :: Event Double] - it "works with inset points" $ - queryArc (rev saw) (Arc 0.25 0.25) - `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) 0.75 :: Event Double] + it "works with whole cycles" $ + queryArc (rev saw) (Arc 0 1) + `shouldBe` [Event (Context []) Nothing (Arc 0 1) 0 :: Event Double] + it "works with half cycles" $ + queryArc (rev saw) (Arc 0.5 1) + `shouldBe` [Event (Context []) Nothing (Arc 0.5 1) 0 :: Event Double] + it "works with inset points" $ + queryArc (rev saw) (Arc 0.25 0.25) + `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) 0.75 :: Event Double] describe "tri" $ do it "goes from 0 up to 1 and back every cycle" $ diff --git a/tidal-core/test/Sound/Tidal/ExceptionsTest.hs b/tidal-core/test/Sound/Tidal/ExceptionsTest.hs index 2c81afd7..5dba5a8c 100644 --- a/tidal-core/test/Sound/Tidal/ExceptionsTest.hs +++ b/tidal-core/test/Sound/Tidal/ExceptionsTest.hs @@ -7,10 +7,10 @@ import Control.DeepSeq import Control.Exception import Data.Typeable () import Sound.Tidal.Pattern -import Test.Microspec +import Test.Hspec import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "NFData, forcing and catching exceptions" $ do describe "instance NFData (Pattern a)" $ do @@ -18,43 +18,6 @@ run = evaluate (rnf (Pattern undefined Nothing Nothing :: Pattern ())) `shouldThrow` anyException --- copied from http://hackage.haskell.org/package/hspec-expectations-0.8.2/docs/src/Test-Hspec-Expectations.html#shouldThrow - -shouldThrow :: (Exception e) => IO a -> Selector e -> Microspec () -action `shouldThrow` p = prop "shouldThrow" $ - monadicIO $ do - r <- Test.Microspec.run $ try action - case r of - Right _ -> - -- "finished normally, but should throw exception: " ++ exceptionType - Test.Microspec.assert False - Left e -> - -- "threw exception that did not meet expectation") - Test.Microspec.assert $ p e - -shouldNotThrow :: (Exception e) => IO a -> Selector e -> Microspec () -action `shouldNotThrow` p = prop "shouldNotThrow" $ - monadicIO $ do - r <- Test.Microspec.run $ try action - case r of - Right _ -> Test.Microspec.assert True - Left e -> Test.Microspec.assert $ p e - --- a string repsentation of the expected exception's type -{- -exceptionType = (show . typeOf . instanceOf) p - where - instanceOf :: Selector a -> a - instanceOf _ = error "Test.Hspec.Expectations.shouldThrow: broken Typeable instance" --} - --- | --- A @Selector@ is a predicate; it can simultaneously constrain the type and --- value of an exception. -type Selector a = (a -> Bool) - -anyException :: Selector SomeException -anyException = const True anyErrorCall :: Selector ErrorCall anyErrorCall = const True diff --git a/tidal-core/test/Sound/Tidal/ParamsTest.hs b/tidal-core/test/Sound/Tidal/ParamsTest.hs index facff2c1..2656d823 100644 --- a/tidal-core/test/Sound/Tidal/ParamsTest.hs +++ b/tidal-core/test/Sound/Tidal/ParamsTest.hs @@ -5,10 +5,10 @@ module Sound.Tidal.ParamsTest where import Sound.Tidal.Core import Sound.Tidal.Params import Sound.Tidal.Pattern -import Test.Microspec +import Test.Hspec import TestUtils -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Params" $ do describe "VF params" $ do diff --git a/tidal-core/test/Sound/Tidal/ParseTest.hs b/tidal-core/test/Sound/Tidal/ParseTest.hs index 6eebef98..bf07528f 100644 --- a/tidal-core/test/Sound/Tidal/ParseTest.hs +++ b/tidal-core/test/Sound/Tidal/ParseTest.hs @@ -4,14 +4,13 @@ module Sound.Tidal.ParseTest where import Control.Exception import Sound.Tidal.Core -import Sound.Tidal.ExceptionsTest (anyException, shouldThrow, shouldNotThrow) import Sound.Tidal.Pattern import Sound.Tidal.UI (_degradeBy) -import Test.Microspec +import Test.Hspec import TestUtils import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Parse" $ do describe "parseBP_E" $ do @@ -342,14 +341,15 @@ run = ("a a |b b b|c c c c" :: Pattern String) ("[a a|b b b|c c c c]" :: Pattern String) it "'|' in list first" $ do - evaluate ("1 2@3|4|-|5!6|[7!8 9] 10 . 11 12*2 13!2 . 1@1" :: Pattern String) - `shouldNotThrow` anyException + compareP + (Arc 0 1) + ("a|b b" :: Pattern String) + ("[a|b b]" :: Pattern String) it "'|' in list last" $ do - evaluate ("12@1|23@1|12|[1 3!21]" :: Pattern String) - `shouldNotThrow` anyException - it "toplevel '|'" $ do - evaluate ("121|23@1|12|[1 321]" :: Pattern String) - `shouldNotThrow` anyException + compareP + (Arc 0 1) + ("a b|c" :: Pattern String) + ("[a b|c]" :: Pattern String) it "list is same as stack" $ do compareP (Arc 0 1) diff --git a/tidal-core/test/Sound/Tidal/PatternTest.hs b/tidal-core/test/Sound/Tidal/PatternTest.hs index 9e6bfe18..56bad230 100644 --- a/tidal-core/test/Sound/Tidal/PatternTest.hs +++ b/tidal-core/test/Sound/Tidal/PatternTest.hs @@ -7,75 +7,56 @@ import Data.Ratio import Sound.Tidal.Core import Sound.Tidal.Pattern import Sound.Tidal.UI -import Test.Microspec +import Test.Hspec import TestUtils import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Pattern" $ do describe "Arc" $ do it "Arc is a Functor: Apply a given function to the start and end values of an Arc" $ do let res = fmap (+ 1) (Arc 3 5) - property $ ((Arc 4 6) :: Arc) === res - - {- - describe "Event" $ do - it "(Bifunctor) first: Apply a function to the Arc elements: whole and part" $ do - let res = Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5 :: Event (Context []) Int - f = (+1) - property $ - first f res === - Event (Context []) (Just $ Arc 2 3) (Arc 4 5) 5 - it "(Bifunctor) second: Apply a function to the event element" $ do - let res = Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5 :: Event (Context []) Int - f = (+1) - property $ - second f res === - Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 6-} + res `shouldBe` ((Arc 4 6) :: Arc) describe "whole" $ do it "returns the whole Arc in an Event" $ do - property $ (Just $ Arc 1 2) === whole (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int) + (Just $ Arc 1 2) `shouldBe` whole (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int) describe "part" $ do it "returns the part Arc in an Event" $ do - property $ (Arc 3 4) === part (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int) + (Arc 3 4) `shouldBe` part (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5 :: Event Int) describe "value" $ do it "returns the event value in an Event" $ do - property $ 5 === value (Event (Context []) (Just $ Arc (1 :: Rational) 2) (Arc 3 4) (5 :: Int)) + 5 `shouldBe` value (Event (Context []) (Just $ Arc (1 :: Rational) 2) (Arc 3 4) (5 :: Int)) describe "wholeStart" $ do it "retrieve the onset of an event: the start of the whole Arc" $ do - property $ 1 === wholeStart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) + 1 `shouldBe` wholeStart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) describe "eventHasOnset" $ do it "return True when the start values of the two arcs in an event are equal" $ do let ev = (Event (Context []) (Just $ Arc 1 2) (Arc 1 3) (4 :: Int)) - property $ True === eventHasOnset ev + True `shouldBe` eventHasOnset ev it "return False when the start values of the two arcs in an event are not equal" $ do let ev = (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) - property $ False === eventHasOnset ev + False `shouldBe` eventHasOnset ev describe "pure" $ do it "fills a whole cycle" $ do - property $ queryArc (pure 0) (Arc 0 1) === [(Event (Context []) (Just $ Arc 0 1) (Arc 0 1) (0 :: Int))] + queryArc (pure 0) (Arc 0 1) `shouldBe` [(Event (Context []) (Just $ Arc 0 1) (Arc 0 1) (0 :: Int))] it "returns the part of an pure that you ask for, preserving the whole" $ do - property $ queryArc (pure 0) (Arc 0.25 0.75) === [(Event (Context []) (Just $ Arc 0 1) (Arc 0.25 0.75) (0 :: Int))] + queryArc (pure 0) (Arc 0.25 0.75) `shouldBe` [(Event (Context []) (Just $ Arc 0 1) (Arc 0.25 0.75) (0 :: Int))] it "gives correct fragments when you go over cycle boundaries" $ do - property $ - queryArc (pure 0) (Arc 0.25 1.25) - === [ (Event (Context []) (Just $ Arc 0 1) (Arc 0.25 1) (0 :: Int)), - (Event (Context []) (Just $ Arc 1 2) (Arc 1 1.25) 0) - ] + queryArc (pure 0) (Arc 0.25 1.25) + `shouldBe` [ (Event (Context []) (Just $ Arc 0 1) (Arc 0.25 1) (0 :: Int)), + (Event (Context []) (Just $ Arc 1 2) (Arc 1 1.25) 0)] it "works with zero-length queries" $ do - it "0" $ - queryArc (pure "a") (Arc 0 0) - `shouldBe` fmap toEvent [(((0, 1), (0, 0)), "a" :: String)] - it "1/3" $ - queryArc (pure "a") (Arc (1 % 3) (1 % 3)) - `shouldBe` fmap toEvent [(((0, 1), (1 % 3, 1 % 3)), "a" :: String)] + queryArc (pure "a") (Arc 0 0) + `shouldBe` fmap toEvent [(((0, 1), (0, 0)), "a" :: String)] + queryArc (pure "a") (Arc (1 % 3) (1 % 3)) + `shouldBe` fmap toEvent [(((0, 1), (1 % 3, 1 % 3)), "a" :: String)] describe "_fastGap" $ do it "copes with cross-cycle queries" $ do @@ -105,22 +86,20 @@ run = (((0.5, 1), (0.5, 1)), 9) ] it "can take structure from the both sides" $ do - it "one" $ - queryArc ((fastCat [pure (+ 1), pure (+ 2)]) <*> (fastCat [pure 7, pure 8])) (Arc 0 1) - `shouldBe` fmap - toEvent - [ (((0, 0.5), (0, 0.5)), 8 :: Int), - (((0.5, 1), (0.5, 1)), 10) - ] - it "two" $ - queryArc ((fastCat [pure (+ 1), pure (+ 2), pure (+ 3)]) <*> (fastCat [pure 7, pure 8])) (Arc 0 1) - `shouldBe` fmap - toEvent - [ (((0 % 1, 1 % 3), (0 % 1, 1 % 3)), 8 :: Int), - (((1 % 3, 1 % 2), (1 % 3, 1 % 2)), 9), - (((1 % 2, 2 % 3), (1 % 2, 2 % 3)), 10), - (((2 % 3, 1 % 1), (2 % 3, 1 % 1)), 11) - ] + queryArc ((fastCat [pure (+ 1), pure (+ 2)]) <*> (fastCat [pure 7, pure 8])) (Arc 0 1) + `shouldBe` fmap + toEvent + [ (((0, 0.5), (0, 0.5)), 8 :: Int), + (((0.5, 1), (0.5, 1)), 10) + ] + queryArc ((fastCat [pure (+ 1), pure (+ 2), pure (+ 3)]) <*> (fastCat [pure 7, pure 8])) (Arc 0 1) + `shouldBe` fmap + toEvent + [ (((0 % 1, 1 % 3), (0 % 1, 1 % 3)), 8 :: Int), + (((1 % 3, 1 % 2), (1 % 3, 1 % 2)), 9), + (((1 % 2, 2 % 3), (1 % 2, 2 % 3)), 10), + (((2 % 3, 1 % 1), (2 % 3, 1 % 1)), 11) + ] it "obeys pure id <*> v = v" $ do let v = (fastCat [fastCat [pure 7, pure 8], pure 9]) :: Pattern Int queryArc ((pure id <*> v)) (Arc 0 5) `shouldBe` queryArc v (Arc 0 5) @@ -155,10 +134,9 @@ run = (((0, 1), (0.5, 1)), 9 :: Int) ] - describe "*>" $ do - it "can apply a pattern of values to a pattern of functions" $ do - it "works within cycles" $ queryArc ((pure (+ 1)) *> (pure 3)) (Arc 0 1) `shouldBe` fmap toEvent [(((0, 1), (0, 1)), 4 :: Int)] - it "works across cycles" $ queryArc ((pure (+ 1)) *> (slow 2 $ pure 3)) (Arc 0 1) `shouldBe` fmap toEvent [(((0, 2), (0, 1)), 4 :: Int)] + describe "*> can apply a pattern of values to a pattern of functions" $ do + it "works within cycles" $ queryArc ((pure (+ 1)) *> (pure 3)) (Arc 0 1) `shouldBe` fmap toEvent [(((0, 1), (0, 1)), 4 :: Int)] + it "works across cycles" $ queryArc ((pure (+ 1)) *> (slow 2 $ pure 3)) (Arc 0 1) `shouldBe` fmap toEvent [(((0, 2), (0, 1)), 4 :: Int)] it "doesn't take structure from the left" $ do queryArc (pure (+ 1) *> (fastCat [pure 7, pure 8])) (Arc 0 1) `shouldBe` fmap @@ -169,29 +147,24 @@ run = describe "arcCycles" $ do it "leaves a unit cycle intact" $ do - it "(0,1)" $ arcCycles (Arc 0 1) `shouldBe` [(Arc 0 1)] - it "(3,4)" $ arcCycles (Arc 3 4) `shouldBe` [(Arc 3 4)] + arcCycles (Arc 0 1) `shouldBe` [(Arc 0 1)] + arcCycles (Arc 3 4) `shouldBe` [(Arc 3 4)] it "splits a cycle at cycle boundaries" $ do - it "(0,1.1)" $ arcCycles (Arc 0 1.1) `shouldBe` [(Arc 0 1), (Arc 1 1.1)] - it "(1,2,1)" $ arcCycles (Arc 1 2.1) `shouldBe` [(Arc 1 2), (Arc 2 2.1)] - it "(3 + (1%3),5.1)" $ - arcCycles (Arc (3 + (1 % 3)) 5.1) `shouldBe` [(Arc (3 + (1 % 3)) 4), (Arc 4 5), (Arc 5 5.1)] + arcCycles (Arc 0 1.1) `shouldBe` [(Arc 0 1), (Arc 1 1.1)] + arcCycles (Arc 1 2.1) `shouldBe` [(Arc 1 2), (Arc 2 2.1)] + arcCycles (Arc (3 + (1 % 3)) 5.1) `shouldBe` [(Arc (3 + (1 % 3)) 4), (Arc 4 5), (Arc 5 5.1)] describe "unwrap" $ do it "preserves inner structure" $ do - it "one" $ - (queryArc (unwrap $ pure (fastCat [pure "a", pure ("b" :: String)])) (Arc 0 1)) - `shouldBe` (queryArc (fastCat [pure "a", pure "b"]) (Arc 0 1)) - it "two" $ - (queryArc (unwrap $ pure (fastCat [pure "a", pure "b", fastCat [pure "c", pure ("d" :: String)]])) (Arc 0 1)) - `shouldBe` (queryArc (fastCat [pure "a", pure "b", fastCat [pure "c", pure "d"]]) (Arc 0 1)) + (queryArc (unwrap $ pure (fastCat [pure "a", pure ("b" :: String)])) (Arc 0 1)) + `shouldBe` (queryArc (fastCat [pure "a", pure "b"]) (Arc 0 1)) + (queryArc (unwrap $ pure (fastCat [pure "a", pure "b", fastCat [pure "c", pure ("d" :: String)]])) (Arc 0 1)) + `shouldBe` (queryArc (fastCat [pure "a", pure "b", fastCat [pure "c", pure "d"]]) (Arc 0 1)) it "preserves outer structure" $ do - it "one" $ - (queryArc (unwrap $ fastCat [pure $ pure "a", pure $ pure ("b" :: String)]) (Arc 0 1)) - `shouldBe` (queryArc (fastCat [pure "a", pure "b"]) (Arc 0 1)) - it "two" $ - (queryArc (unwrap $ fastCat [pure $ pure "a", pure $ pure "b", fastCat [pure $ pure "c", pure $ pure ("d" :: String)]]) (Arc 0 1)) - `shouldBe` (queryArc (fastCat [pure "a", pure "b", fastCat [pure "c", pure "d"]]) (Arc 0 1)) + (queryArc (unwrap $ fastCat [pure $ pure "a", pure $ pure ("b" :: String)]) (Arc 0 1)) + `shouldBe` (queryArc (fastCat [pure "a", pure "b"]) (Arc 0 1)) + (queryArc (unwrap $ fastCat [pure $ pure "a", pure $ pure "b", fastCat [pure $ pure "c", pure $ pure ("d" :: String)]]) (Arc 0 1)) + `shouldBe` (queryArc (fastCat [pure "a", pure "b", fastCat [pure "c", pure "d"]]) (Arc 0 1)) it "gives events whole/part timespans that are an intersection of that of inner and outer events" $ do let a = fastCat [pure "a", pure "b"] b = fastCat [pure "c", pure "d", pure "e"] @@ -247,22 +220,18 @@ run = describe "rotR" $ do it "works over two cycles" $ - property $ - comparePD (Arc 0 2) (0.25 ~> pure "a") (0.25 `rotR` pure ("a" :: String)) + comparePD (Arc 0 2) (0.25 ~> pure "a") (0.25 `rotR` pure ("a" :: String)) it "works over one cycle" $ - property $ - compareP (Arc 0 1) (0.25 ~> pure "a") (0.25 `rotR` pure ("a" :: String)) + compareP (Arc 0 1) (0.25 ~> pure "a") (0.25 `rotR` pure ("a" :: String)) it "works with zero width queries" $ - property $ - compareP (Arc 0 0) (0.25 ~> pure "a") (0.25 `rotR` pure ("a" :: String)) + compareP (Arc 0 0) (0.25 ~> pure "a") (0.25 `rotR` pure ("a" :: String)) describe "comparePD" $ do it "allows split events to be compared" $ - property $ - comparePD - (Arc 0 2) - (splitQueries $ _slow 2 $ pure ("a" :: String)) - (_slow 2 $ pure "a") + comparePD + (Arc 0 2) + (splitQueries $ _slow 2 $ pure ("a" :: String)) + (_slow 2 $ pure "a") describe "controlI" $ do it "can retrieve values from state" $ @@ -271,290 +240,283 @@ run = describe "wholeStart" $ do it "retrieve first element of a tuple, inside first element of a tuple, inside the first of another" $ do - property $ 1 === wholeStart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) + 1 `shouldBe` wholeStart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) describe "wholeStop" $ do it "retrieve the end time from the first Arc in an Event" $ do - property $ 2 === wholeStop (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) + 2 `shouldBe` wholeStop (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) describe "eventPartStart" $ do it "retrieve the start time of the second Arc in an Event" $ do - property $ 3 === eventPartStart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) + 3 `shouldBe` eventPartStart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) describe "eventPartStop" $ do it "retrieve the end time of the second Arc in an Event" $ do - property $ 4 === eventPartStop (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) + 4 `shouldBe` eventPartStop (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) describe "eventPart" $ do it "retrieve the second Arc in an Event" $ do - property $ Arc 3 4 === eventPart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) + Arc 3 4 `shouldBe` eventPart (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) describe "eventValue" $ do it "retrieve the second value from a tuple" $ do - property $ 5 === eventValue (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) + 5 `shouldBe` eventValue (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) describe "eventHasOnset" $ do it "return True when the start values of the two arcs in an event are equal" $ do let ev = (Event (Context []) (Just $ Arc 1 2) (Arc 1 3) (4 :: Int)) - property $ True === eventHasOnset ev + True `shouldBe` eventHasOnset ev it "return False when the start values of the two arcs in an event are not equal" $ do let ev = (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) - property $ False === eventHasOnset ev + False `shouldBe` eventHasOnset ev describe "sam" $ do it "start of a cycle, round down time value" $ do let res = sam (3.4 :: Time) - property $ (3.0 :: Time) === res + (3.0 :: Time) `shouldBe` res describe "nextSam" $ do it "the end point of the current cycle, and start of the next" $ do let res = nextSam (3.4 :: Time) - property $ (4.0 :: Time) === res + (4.0 :: Time) `shouldBe` res describe "arcCycles" $ do it "if start time is greater than end time return empty list" $ do let res = arcCycles (Arc 2.3 2.1) - property $ [] === res + [] `shouldBe` res it "if start time is equal to end time return empty list" $ do let res = arcCycles (Arc 3 3) - property $ [] === res + [] `shouldBe` res it "if start and end time round down to same value return list of (start, end)" $ do let res = arcCycles (Arc 2.1 2.3) - property $ [(Arc 2.1 2.3)] === res + [(Arc 2.1 2.3)] `shouldBe` res it "if start time is less than end time and start time does not round down to same value as end time" $ do let res = arcCycles (Arc 2.1 3.3) - property $ [(Arc 2.1 3.0), (Arc 3.0 3.3)] === res + [(Arc 2.1 3.0), (Arc 3.0 3.3)] `shouldBe` res describe "arcCyclesZW" $ do it "if start and end time are equal return list of (start, end)" $ do let res = arcCyclesZW (Arc 2.5 2.5) - property $ [(Arc 2.5 2.5)] === res + [(Arc 2.5 2.5)] `shouldBe` res it "if start and end time are not equal call arcCycles (start, end) with same rules as above" $ do let res = arcCyclesZW (Arc 2.3 2.1) - property $ [] === res + [] `shouldBe` res it "if start time is less than end time" $ do let res = arcCyclesZW (Arc 2.1 2.3) - property $ [(Arc 2.1 2.3)] === res + [(Arc 2.1 2.3)] `shouldBe` res it "if start time is greater than end time" $ do let res = arcCyclesZW (Arc 2.1 3.3) - property $ [(Arc 2.1 3.0), (Arc 3.0 3.3)] === res + [(Arc 2.1 3.0), (Arc 3.0 3.3)] `shouldBe` res describe "mapCycle" $ do it "Apply a function to the Arc values minus the start value rounded down (sam'), adding both results to sam' to obtain the new Arc value" $ do let res = mapCycle (* 2) (Arc 3.3 5) - property $ ((Arc 3.6 7.0) :: Arc) === res + ((Arc 3.6 7.0) :: Arc) `shouldBe` res describe "toTime" $ do it "Convert a number of type Real to a Time value of type Rational, Int test" $ do let res = toTime (3 :: Int) - property $ (3 % 1 :: Time) === res + (3 % 1 :: Time) `shouldBe` res it "Convert a number of type Double to a Time value of type Rational" $ do let res = toTime (3.2 :: Double) - property $ (3602879701896397 % 1125899906842624 :: Time) === res + (3602879701896397 % 1125899906842624 :: Time) `shouldBe` res describe "cyclePos" $ do it "Subtract a Time value from its value rounded down (the start of the cycle)" $ do let res = cyclePos 2.6 - property $ (0.6 :: Time) === res + (0.6 :: Time) `shouldBe` res it "If no difference between a given Time and the start of the cycle" $ do let res = cyclePos 2 - property $ (0.0 :: Time) === res + (0.0 :: Time) `shouldBe` res describe "isIn" $ do it "Check given Time is inside a given Arc value, Time is greater than start and less than end Arc values" $ do let res = isIn (Arc 2.0 2.8) 2.5 - property $ True === res + True `shouldBe` res it "Given Time is equal to the Arc start value" $ do let res = isIn (Arc 2.0 2.8) 2.0 - property $ True === res + True `shouldBe` res it "Given Time is less than the Arc start value" $ do let res = isIn (Arc 2.0 2.8) 1.4 - property $ False === res + False `shouldBe` res it "Given Time is greater than the Arc end value" $ do let res = isIn (Arc 2.0 2.8) 3.2 - property $ False === res + False `shouldBe` res describe "onsetIn" $ do it "If the beginning of an Event is within a given Arc, same rules as 'isIn'" $ do let res = onsetIn (Arc 2.0 2.8) (Event (Context []) (Just $ Arc 2.2 2.7) (Arc 3.3 3.8) (5 :: Int)) - property $ True === res + True `shouldBe` res it "Beginning of Event is equal to beggining of given Arc" $ do let res = onsetIn (Arc 2.0 2.8) (Event (Context []) (Just $ Arc 2.0 2.7) (Arc 3.3 3.8) (5 :: Int)) - property $ True === res + True `shouldBe` res it "Beginning of an Event is less than the start of the Arc" $ do let res = onsetIn (Arc 2.0 2.8) (Event (Context []) (Just $ Arc 1.2 1.7) (Arc 3.3 3.8) (5 :: Int)) - property $ False === res + False `shouldBe` res it "Start of Event is greater than the start of the given Arc" $ do let res = onsetIn (Arc 2.0 2.8) (Event (Context []) (Just $ Arc 3.1 3.5) (Arc 4.0 4.6) (5 :: Int)) - property $ False === res + False `shouldBe` res describe "subArc" $ do it "Checks if an Arc is within another, returns Just (max $ (fst a1) (fst a2), min $ (snd a1) (snd a2)) if so, otherwise Nothing" $ do let res = subArc (Arc 2.1 2.4) (Arc 2.4 2.8) - property $ Nothing === res + Nothing `shouldBe` res it "if max (fst arc1) (fst arc2) <= min (snd arc1) (snd arc2) return Just (max (fst arc1) (fst arc2), min...)" $ do let res = subArc (Arc 2 2.8) (Arc 2.4 2.9) - property $ Just (Arc 2.4 2.8) === res + Just (Arc 2.4 2.8) `shouldBe` res describe "timeToCycleArc" $ do it "given a Time value return the Arc in which it resides" $ do let res = timeToCycleArc 2.2 - property $ (Arc 2.0 3.0) === res + (Arc 2.0 3.0) `shouldBe` res describe "cyclesInArc" $ do it "Return a list of cycles in a given arc, if start is greater than end return empty list" $ do let res = cyclesInArc (Arc 2.4 2.2) - property $ ([] :: [Int]) === res + ([] :: [Int]) `shouldBe` res it "If start value of Arc is equal to end value return list with start value rounded down" $ do let res = cyclesInArc (Arc 2.4 2.4) - property $ ([2] :: [Int]) === res + ([2] :: [Int]) `shouldBe` res it "if start of Arc is less than end return list of start rounded down to end rounded up minus one" $ do let res = cyclesInArc (Arc 2.2 4.5) - property $ ([2, 3, 4] :: [Int]) === res + ([2, 3, 4] :: [Int]) `shouldBe` res describe "cycleArcsInArc" $ do it "generates a list of Arcs based on the cycles found within a given a Arc" $ do let res = cycleArcsInArc (Arc 2.2 4.5) - property $ [(Arc 2.0 3.0), (Arc 3.0 4.0), (Arc 4.0 5.0)] === res + [(Arc 2.0 3.0), (Arc 3.0 4.0), (Arc 4.0 5.0)] `shouldBe` res describe "isAdjacent" $ do it "if the given Events are adjacent parts of the same whole" $ do let res = isAdjacent (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Context []) (Just $ Arc 1 2) (Arc 4 3) (5 :: Int)) - property $ True === res + True `shouldBe` res it "if first Arc of of first Event is not equal to first Arc of second Event" $ do let res = isAdjacent (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Context []) (Just $ Arc 7 8) (Arc 4 3) (5 :: Int)) - property $ False === res + False `shouldBe` res it "if the value of the first Event does not equal the value of the second Event" $ do let res = isAdjacent (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Context []) (Just $ Arc 1 2) (Arc 4 3) (6 :: Int)) - property $ False === res + False `shouldBe` res it "second value of second Arc of first Event not equal to first value of second Arc in second Event..." $ do let res = isAdjacent (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5) (Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)) - property $ False === res + False `shouldBe` res describe "defragParts" $ do it "if empty list with no events return empty list" $ do let res = defragParts ([] :: [Event Int]) - property $ [] === res + [] `shouldBe` res it "if list consists of only one Event return it as is" $ do let res = defragParts [(Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int))] - property $ [Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)] === res + [Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)] `shouldBe` res it "if list contains adjacent Events return list with Parts combined" $ do let res = defragParts [(Event (Context []) (Just $ Arc 1 2) (Arc 3 4) (5 :: Int)), (Event (Context []) (Just $ Arc 1 2) (Arc 4 3) (5 :: Int))] - property $ [(Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5)] === res + [(Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5)] `shouldBe` res it "if list contains more than one Event none of which are adjacent, return List as is" $ do let res = defragParts [(Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5), (Event (Context []) (Just $ Arc 7 8) (Arc 4 3) (5 :: Int))] - property $ [Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5, Event (Context []) (Just $ Arc 7 8) (Arc 4 3) (5 :: Int)] === res + [Event (Context []) (Just $ Arc 1 2) (Arc 3 4) 5, Event (Context []) (Just $ Arc 7 8) (Arc 4 3) (5 :: Int)] `shouldBe` res describe "sect" $ do it "take two Arcs and return - Arc (max of two starts) (min of two ends)" $ do let res = sect (Arc 2.2 3) (Arc 2 2.9) - property $ Arc 2.2 2.9 == res + Arc 2.2 2.9 == res describe "hull" $ do it "take two Arcs anre return - Arc (min of two starts) (max of two ends)" $ do let res = hull (Arc 2.2 3) (Arc 2 2.9) - property $ Arc 2 3 == res + Arc 2 3 == res describe "withResultArc" $ do it "apply given function to the Arcs" $ do let p = withResultArc (+ 5) (stripContext $ fast "1 2" "3 4" :: Pattern Int) let res = queryArc p (Arc 0 1) - property $ res === fmap toEvent [(((5, 11 % 2), (5, 11 % 2)), 3), (((11 % 2, 23 % 4), (11 % 2, 23 % 4)), 3), (((23 % 4, 6), (23 % 4, 6)), 4)] + res `shouldBe` fmap toEvent [(((5, 11 % 2), (5, 11 % 2)), 3), (((11 % 2, 23 % 4), (11 % 2, 23 % 4)), 3), (((23 % 4, 6), (23 % 4, 6)), 4)] describe "applyFIS" $ do it "apply Float function when value of type VF" $ do let res = applyFIS (+ 1) (+ 1) (++ "1") (VF 1) - property $ (VF 2.0) === res + (VF 2.0) `shouldBe` res it "apply Int function when value of type VI" $ do let res = applyFIS (+ 1) (+ 1) (++ "1") (VI 1) - property $ (VI 2) === res + (VI 2) `shouldBe` res it "apply String function when value of type VS" $ do let res = applyFIS (+ 1) (+ 1) (++ "1") (VS "1") - property $ (VS "11") === res + (VS "11") `shouldBe` res describe "fNum2" $ do it "apply Int function for two Int values" $ do let res = fNum2 (+) (+) (VI 2) (VI 3) - property $ (VI 5) === res + (VI 5) `shouldBe` res it "apply float function when given two float values" $ do let res = fNum2 (+) (+) (VF 2) (VF 3) - property $ (VF 5.0) === res + (VF 5.0) `shouldBe` res it "apply float function when one float and one int value given" $ do let res = fNum2 (+) (+) (VF 2) (VI 3) - property $ (VF 5.0) === res + (VF 5.0) `shouldBe` res describe "getI" $ do it "get Just value when Int value is supplied" $ do let res = getI (VI 3) - property $ (Just 3) === res + (Just 3) `shouldBe` res it "get floored value when float value is supplied" $ do let res = getI (VF 3.5) - property $ (Just 3) === res + (Just 3) `shouldBe` res it "get if String value is supplied" $ do let res = getI (VS "3") - property $ Nothing === res + Nothing `shouldBe` res describe "getF" $ do it "get Just value when Float value is supplied" $ do let res = getF (VF 3) - property $ (Just 3.0) === res + (Just 3.0) `shouldBe` res it "get converted value if Int value is supplied" $ do let res = getF (VI 3) - property $ (Just 3.0) === res + (Just 3.0) `shouldBe` res describe "getS" $ do it "get Just value when String value is supplied" $ do let res = getS (VS "Tidal") - property $ (Just "Tidal") === res + (Just "Tidal") `shouldBe` res it "get Nothing if Int value is not supplied" $ do let res = getS (VI 3) - property $ Nothing === res + Nothing `shouldBe` res describe "filterValues" $ do it "remove Events above given threshold" $ do let fil = filterValues (< 2) $ fastCat [pure 1, pure 2, pure 3] :: Pattern Time let res = queryArc fil (Arc 0.5 1.5) - property $ fmap toEvent [(((1, 4 % 3), (1, 4 % 3)), 1 % 1)] === res + fmap toEvent [(((1, 4 % 3), (1, 4 % 3)), 1 % 1)] `shouldBe` res it "remove Events below given threshold" $ do let fil = filterValues (> 2) $ fastCat [pure 1, pure 2, pure 3] :: Pattern Time let res = queryArc fil (Arc 0.5 1.5) - property $ fmap toEvent [(((2 % 3, 1), (2 % 3, 1)), 3 % 1)] === res + fmap toEvent [(((2 % 3, 1), (2 % 3, 1)), 3 % 1)] `shouldBe` res describe "filterWhen" $ do it "filter below given threshold" $ do let fil = filterWhen (< 0.5) $ struct "t*4" $ (tri :: Pattern Double) + 1 let res = queryArc fil (Arc 0.5 1.5) - property $ [] === res + [] `shouldBe` res it "filter above given threshold" $ do let fil = stripContext $ filterWhen (> 0.5) $ struct "t*4" $ (tri :: Pattern Double) + 1 let res = queryArc fil (Arc 0.5 1.5) - property $ fmap toEvent [(((3 % 4, 1), (3 % 4, 1)), 1.5), (((1, 5 % 4), (1, 5 % 4)), 1), (((5 % 4, 3 % 2), (5 % 4, 3 % 2)), 1.5)] === res + fmap toEvent [(((3 % 4, 1), (3 % 4, 1)), 1.5), (((1, 5 % 4), (1, 5 % 4)), 1), (((5 % 4, 3 % 2), (5 % 4, 3 % 2)), 1.5)] `shouldBe` res describe "compressArc" $ do it "return empty if start time is greater than end time" $ do let res = queryArc (compressArc (Arc 0.8 0.1) (fast "1 2" "3 4" :: Pattern Time)) (Arc 1 2) - property $ [] === res + [] `shouldBe` res it "return empty if start time or end time are greater than 1" $ do let res = queryArc (compressArc (Arc 0.1 2) (fast "1 2" "3 4" :: Pattern Time)) (Arc 1 2) - property $ [] === res + [] `shouldBe` res it "return empty if start or end are less than zero" $ do let res = queryArc (compressArc (Arc (-0.8) 0.1) (fast "1 2" "3 4" :: Pattern Time)) (Arc 1 2) - property $ [] === res + [] `shouldBe` res it "otherwise compress difference between start and end values of Arc" $ do let p = fast "1 2" "3 4" :: Pattern Time let res = queryArc (stripContext $ compressArc (Arc 0.2 0.8) p) (Arc 0 1) let expected = fmap toEvent [(((1 % 5, 1 % 2), (1 % 5, 1 % 2)), 3 % 1), (((1 % 2, 13 % 20), (1 % 2, 13 % 20)), 3 % 1), (((13 % 20, 4 % 5), (13 % 20, 4 % 5)), 4 % 1)] - property $ expected === res - --- pending "Sound.Tidal.Pattern.eventL" $ do --- it "succeeds if the first event 'whole' is shorter" $ do --- property $ eventL (Event (Context []) (Just $ Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 1.1)) "x") --- it "fails if the events are the same length" $ do --- property $ not $ eventL (Event (Context []) (Just $ Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 1)) "x") --- it "fails if the second event is shorter" $ do --- property $ not $ eventL (Event (Context []) (Just $ Arc 0,0),(Arc 0 1)),"x") (((0 0) (Arc 0 0.5)) "x") + expected `shouldBe` res + diff --git a/tidal-core/test/Sound/Tidal/ScalesTest.hs b/tidal-core/test/Sound/Tidal/ScalesTest.hs index c91f2aa3..734e0a58 100644 --- a/tidal-core/test/Sound/Tidal/ScalesTest.hs +++ b/tidal-core/test/Sound/Tidal/ScalesTest.hs @@ -4,11 +4,11 @@ module Sound.Tidal.ScalesTest where import Sound.Tidal.Pattern import Sound.Tidal.Scales -import Test.Microspec +import Test.Hspec import TestUtils import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Scales" $ do describe "scale" $ do diff --git a/tidal-core/test/Sound/Tidal/StepwiseTest.hs b/tidal-core/test/Sound/Tidal/StepwiseTest.hs index eab344bb..b5921b08 100644 --- a/tidal-core/test/Sound/Tidal/StepwiseTest.hs +++ b/tidal-core/test/Sound/Tidal/StepwiseTest.hs @@ -14,16 +14,11 @@ import Sound.Tidal.Pattern ) import Sound.Tidal.Stepwise (expand, stepcat, stepdrop, steptake) import Sound.Tidal.UI (inv, iter, linger, segment) -import Test.Microspec - ( MTestable (describe), - Microspec, - it, - shouldBe, - ) +import Test.Hspec import TestUtils (compareP, firstCycleValues) import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Stepwise" $ do describe "stepcat" $ do @@ -42,124 +37,14 @@ run = compareP (Arc 0 8) (stepdrop "0 1 2 3" ("a b c d" :: Pattern Char)) "a b c d a b c a b a" it "can pattern reverse drops" $ do compareP (Arc 0 8) (stepdrop "0 -1 -2 -3" ("a b c d" :: Pattern Char)) "a b c d b c d c d d" - describe "tactus" $ do - it "is correctly preserved/calculated through transformations" $ do - it "linger" $ (firstCycleValues <$> tactus (linger 4 "a b c" :: Pattern Char)) `shouldBe` Just [3] - it "iter" $ (firstCycleValues <$> tactus (iter 4 "a b c" :: Pattern Char)) `shouldBe` Just [3] - it "fast" $ (firstCycleValues <$> tactus (fast 4 "a b c" :: Pattern Char)) `shouldBe` Just [3] - it "hurry" $ (firstCycleValues <$> tactus (hurry 4 $ sound "a b c")) `shouldBe` Just [3] - it "rev" $ (firstCycleValues <$> tactus (rev "a b c" :: Pattern Char)) `shouldBe` Just [3] - it "segment" $ (firstCycleValues <$> tactus (segment 10 "a" :: Pattern Char)) `shouldBe` Just [10] - it "invert" $ (firstCycleValues <$> tactus (inv "1 0 1" :: Pattern Bool)) `shouldBe` Just [3] - it "chop" $ (firstCycleValues <$> tactus (chop 3 $ sound "a b")) `shouldBe` Just [6] - it "chop" $ (firstCycleValues <$> tactus (striate 3 $ sound "a b")) `shouldBe` Just [6] + describe "tactus is correctly preserved/calculated through transformations" $ do + it "linger" $ (firstCycleValues <$> tactus (linger 4 "a b c" :: Pattern Char)) `shouldBe` Just [3] + it "iter" $ (firstCycleValues <$> tactus (iter 4 "a b c" :: Pattern Char)) `shouldBe` Just [3] + it "fast" $ (firstCycleValues <$> tactus (fast 4 "a b c" :: Pattern Char)) `shouldBe` Just [3] + it "hurry" $ (firstCycleValues <$> tactus (hurry 4 $ sound "a b c")) `shouldBe` Just [3] + it "rev" $ (firstCycleValues <$> tactus (rev "a b c" :: Pattern Char)) `shouldBe` Just [3] + it "segment" $ (firstCycleValues <$> tactus (segment 10 "a" :: Pattern Char)) `shouldBe` Just [10] + it "invert" $ (firstCycleValues <$> tactus (inv "1 0 1" :: Pattern Bool)) `shouldBe` Just [3] + it "chop" $ (firstCycleValues <$> tactus (chop 3 $ sound "a b")) `shouldBe` Just [6] + it "chop" $ (firstCycleValues <$> tactus (striate 3 $ sound "a b")) `shouldBe` Just [6] --- expect(sequence({ s: 'bev' }, { s: 'amenbreak' }).chop(4).tactus).toStrictEqual(Fraction(8)); --- expect(sequence({ s: 'bev' }, { s: 'amenbreak' }).striate(4).tactus).toStrictEqual(Fraction(8)); --- expect(sequence({ s: 'bev' }, { s: 'amenbreak' }).slice(4, sequence(0, 1, 2, 3)).tactus).toStrictEqual( --- Fraction(4), --- ); --- expect(sequence({ s: 'bev' }, { s: 'amenbreak' }).splice(4, sequence(0, 1, 2, 3)).tactus).toStrictEqual( --- Fraction(4), --- ); --- expect(sequence({ n: 0 }, { n: 1 }, { n: 2 }).chop(4).tactus).toStrictEqual(Fraction(12)); --- expect( --- pure((x) => x + 1) --- .setTactus(3) --- .appBoth(pure(1).setTactus(2)).tactus, --- ).toStrictEqual(Fraction(6)); --- expect( --- pure((x) => x + 1) --- .setTactus(undefined) --- .appBoth(pure(1).setTactus(2)).tactus, --- ).toStrictEqual(Fraction(2)); --- expect( --- pure((x) => x + 1) --- .setTactus(3) --- .appBoth(pure(1).setTactus(undefined)).tactus, --- ).toStrictEqual(Fraction(3)); --- expect(stack(fastcat(0, 1, 2), fastcat(3, 4)).tactus).toStrictEqual(Fraction(6)); --- expect(stack(fastcat(0, 1, 2), fastcat(3, 4).setTactus(undefined)).tactus).toStrictEqual(Fraction(3)); --- expect(stackLeft(fastcat(0, 1, 2, 3), fastcat(3, 4)).tactus).toStrictEqual(Fraction(4)); --- expect(stackRight(fastcat(0, 1, 2), fastcat(3, 4)).tactus).toStrictEqual(Fraction(3)); --- // maybe this should double when they are either all even or all odd --- expect(stackCentre(fastcat(0, 1, 2), fastcat(3, 4)).tactus).toStrictEqual(Fraction(3)); --- expect(fastcat(0, 1).ply(3).tactus).toStrictEqual(Fraction(6)); --- expect(fastcat(0, 1).setTactus(undefined).ply(3).tactus).toStrictEqual(undefined); --- expect(fastcat(0, 1).fast(3).tactus).toStrictEqual(Fraction(2)); --- expect(fastcat(0, 1).setTactus(undefined).fast(3).tactus).toStrictEqual(undefined); --- }); --- }); --- describe('stepcat', () => { --- it('can cat', () => { --- expect(sameFirst(stepcat(fastcat(0, 1, 2, 3), fastcat(4, 5)), fastcat(0, 1, 2, 3, 4, 5))); --- expect(sameFirst(stepcat(pure(1), pure(2), pure(3)), fastcat(1, 2, 3))); --- }); --- it('calculates undefined tactuses as the average', () => { --- expect(sameFirst(stepcat(pure(1), pure(2), pure(3).setTactus(undefined)), fastcat(1, 2, 3))); --- }); --- }); --- describe('taper', () => { --- it('can taper', () => { --- expect(sameFirst(sequence(0, 1, 2, 3, 4).taper(1, 5), sequence(0, 1, 2, 3, 4, 0, 1, 2, 3, 0, 1, 2, 0, 1, 0))); --- }); --- it('can taper backwards', () => { --- expect(sameFirst(sequence(0, 1, 2, 3, 4).taper(-1, 5), sequence(0, 0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 4))); --- }); --- }); --- describe('increase and decrease', () => { --- it('can increase from the left', () => { --- expect(sameFirst(sequence(0, 1, 2, 3, 4).increase(2), sequence(0, 1))); --- }); --- it('can decrease to the left', () => { --- expect(sameFirst(sequence(0, 1, 2, 3, 4).decrease(2), sequence(0, 1, 2))); --- }); --- it('can increase from the right', () => { --- expect(sameFirst(sequence(0, 1, 2, 3, 4).increase(-2), sequence(3, 4))); --- }); --- it('can decrease to the right', () => { --- expect(sameFirst(sequence(0, 1, 2, 3, 4).decrease(-2), sequence(2, 3, 4))); --- }); --- it('can decrease nothing', () => { --- expect(sameFirst(pure('a').decrease(0), pure('a'))); --- }); --- it('can decrease nothing, repeatedly', () => { --- expect(sameFirst(pure('a').decrease(0, 0), fastcat('a', 'a'))); --- for (var i = 0; i < 100; ++i) { --- expect(sameFirst(pure('a').decrease(...Array(i).fill(0)), fastcat(...Array(i).fill('a')))); --- } --- }); --- }); --- describe('expand', () => { --- it('can expand four things in half', () => { --- expect( --- sameFirst(sequence(0, 1, 2, 3).expand(1, 0.5), stepcat(sequence(0, 1, 2, 3), sequence(0, 1, 2, 3).expand(0.5))), --- ); --- }); --- it('can expand five things in half', () => { --- expect( --- sameFirst( --- sequence(0, 1, 2, 3, 4).expand(1, 0.5), --- stepcat(sequence(0, 1, 2, 3, 4), sequence(0, 1, 2, 3, 4).expand(0.5)), --- ), --- ); --- }); --- }); --- describe('stepJoin', () => { --- it('can join a pattern with a tactus of 2', () => { --- expect( --- sameFirst( --- sequence(pure(pure('a')), pure(pure('b').setTactus(2))).stepJoin(), --- stepcat(pure('a'), pure('b').setTactus(2)), --- ), --- ); --- }); --- it('can join a pattern with a tactus of 0.5', () => { --- expect( --- sameFirst( --- sequence(pure(pure('a')), pure(pure('b').setTactus(0.5))).stepJoin(), --- stepcat(pure('a'), pure('b').setTactus(0.5)), --- ), --- ); --- }); --- }); \ No newline at end of file diff --git a/tidal-core/test/Sound/Tidal/UITest.hs b/tidal-core/test/Sound/Tidal/UITest.hs index 7cd1aade..418d2820 100644 --- a/tidal-core/test/Sound/Tidal/UITest.hs +++ b/tidal-core/test/Sound/Tidal/UITest.hs @@ -10,11 +10,11 @@ import Sound.Tidal.Params import Sound.Tidal.ParseBP import Sound.Tidal.Pattern import Sound.Tidal.UI -import Test.Microspec +import Test.Hspec import TestUtils import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.UI" $ do describe "_chop" $ do @@ -29,8 +29,7 @@ run = (slow 2 $ _chop 2 $ s (pure "a")) (begin (pure 0) # end (pure 0.5) # (s (pure "a"))) it "can chop a chop" $ - property $ - compareTol (Arc 0 1) (_chop 6 $ s $ pure "a") (_chop 2 $ _chop 3 $ s $ pure "a") + compareTol (Arc 0 1) (_chop 6 $ s $ pure "a") (_chop 2 $ _chop 3 $ s $ pure "a") describe "segment" $ do it "can turn a single event into multiple events" $ do @@ -104,39 +103,35 @@ run = in compareP overTimeSpan testMe expectedResult describe "rand" $ do - it "generates a (pseudo-)random number between zero & one" $ do - it "at the start of a cycle" $ - (queryArc rand (Arc 0 0)) `shouldBe` [Event (Context []) Nothing (Arc 0 0) (0 :: Float)] - it "at 1/4 of a cycle" $ - (queryArc rand (Arc 0.25 0.25)) - `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) (0.6295689214020967 :: Float)] - it "at 3/4 of a cycle" $ - (queryArc rand (Arc 0.75 0.75)) + it "it generates a (pseudo-)random number between 0 and 1 at the start of a cycle" $ + (queryArc rand (Arc 0 0)) `shouldBe` [Event (Context []) Nothing (Arc 0 0) (0 :: Float)] + it "it generates a (pseudo-)random number between 0 and 1 at 1/4 of a cycle" $ + (queryArc rand (Arc 0.25 0.25)) + `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) (0.6295689214020967 :: Float)] + it "it generates a (pseudo-)random number between 0 and 1 at 3/4 of a cycle" $ + (queryArc rand (Arc 0.75 0.75)) `shouldBe` [Event (Context []) Nothing (Arc 0.75 0.75) (0.20052618719637394 :: Float)] describe "irand" $ do - it "generates a (pseudo-random) integer between zero & i" $ do - it "at the start of a cycle" $ - (queryArc (irand 10) (Arc 0 0)) `shouldBe` [Event (Context []) Nothing (Arc 0 0) (0 :: Int)] - it "at 1/4 of a cycle" $ - (queryArc (irand 10) (Arc 0.25 0.25)) `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) (6 :: Int)] - it "is patternable" $ - (queryArc (irand "10 2") (Arc 0 1)) - `shouldBe` [ Event (Context [((1, 1), (3, 1))]) Nothing (Arc 0 0.5) (6 :: Int), - Event (Context [((4, 1), (5, 1))]) Nothing (Arc 0.5 1) (0 :: Int) - ] + -- it "generates a (pseudo-random) integer between zero & i" $ do + it "at the start of a cycle" $ + (queryArc (irand 10) (Arc 0 0)) `shouldBe` [Event (Context []) Nothing (Arc 0 0) (0 :: Int)] + it "at 1/4 of a cycle" $ + (queryArc (irand 10) (Arc 0.25 0.25)) `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) (6 :: Int)] + it "is patternable" $ + (queryArc (irand "10 2") (Arc 0 1)) + `shouldBe` [ Event (Context [((1, 1), (3, 1))]) Nothing (Arc 0 0.5) (6 :: Int), + Event (Context [((4, 1), (5, 1))]) Nothing (Arc 0.5 1) (0 :: Int) + ] describe "normal" $ do - it "produces values within [0,1] in a bell curve" $ do - it "at the start of a cycle" $ - queryArc normal (Arc 0 0.1) - `shouldBe` [Event (Context []) Nothing (Arc 0 0.1) (0.4614205864457064 :: Double)] - it "at 1/4 of a cycle" $ - queryArc normal (Arc 0.25 0.25) - `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) (0.5 :: Double)] - it "at 3/4 of a cycle" $ - queryArc normal (Arc 0.75 0.75) - `shouldBe` [Event (Context []) Nothing (Arc 0.75 0.75) (0.5 :: Double)] + it "produces values within [0,1] in a bell curve at different parts of a cycle" $ do + queryArc normal (Arc 0 0.1) + `shouldBe` [Event (Context []) Nothing (Arc 0 0.1) (0.4614205864457064 :: Double)] + queryArc normal (Arc 0.25 0.25) + `shouldBe` [Event (Context []) Nothing (Arc 0.25 0.25) (0.5 :: Double)] + queryArc normal (Arc 0.75 0.75) + `shouldBe` [Event (Context []) Nothing (Arc 0.75 0.75) (0.5 :: Double)] describe "range" $ do describe "scales a pattern to the supplied range" $ do @@ -174,19 +169,16 @@ run = describe "rot" $ do it "rotates values in a pattern irrespective of structure" $ - property $ comparePD (Arc 0 2) (rot 1 "a ~ b c" :: Pattern String) ("b ~ c a" :: Pattern String) it "works with negative values" $ - property $ comparePD (Arc 0 2) (rot (-1) "a ~ b c" :: Pattern String) ("c ~ a b" :: Pattern String) it "works with complex patterns" $ - property $ comparePD (Arc 0 2) (rot (1) "a ~ [b [c ~ d]] [e ]" :: Pattern String) @@ -296,42 +288,40 @@ run = (cat ["1 1" :: Pattern Int, "2 [3 3] 4" :: Pattern Int, "3 [5 5] 7" :: Pattern Int]) describe "euclid" $ do - it "matches examples in Toussaint's paper" $ do - sequence_ $ - map - (\(a, b) -> it b $ compareP (Arc 0 1) a (parseBP_E b)) - ( [ (euclid 1 2 "x", "x ~"), - (euclid 1 3 "x", "x ~ ~"), - (euclid 1 4 "x", "x ~ ~ ~"), - (euclid 4 12 "x", "x ~ ~ x ~ ~ x ~ ~ x ~ ~"), - (euclid 2 5 "x", "x ~ x ~ ~"), - -- (euclid 3 4 "x", "x ~ x x"), -- Toussaint is wrong.. - (euclid 3 4 "x", "x x x ~"), -- correction - (euclid 3 5 "x", "x ~ x ~ x"), - (euclid 3 7 "x", "x ~ x ~ x ~ ~"), - (euclid 3 8 "x", "x ~ ~ x ~ ~ x ~"), - (euclid 4 7 "x", "x ~ x ~ x ~ x"), - (euclid 4 9 "x", "x ~ x ~ x ~ x ~ ~"), - (euclid 4 11 "x", "x ~ ~ x ~ ~ x ~ ~ x ~"), - -- (euclid 5 6 "x", "x ~ x x x x"), -- Toussaint is wrong.. - (euclid 5 6 "x", "x x x x x ~"), -- correction - (euclid 5 7 "x", "x ~ x x ~ x x"), - (euclid 5 8 "x", "x ~ x x ~ x x ~"), - (euclid 5 9 "x", "x ~ x ~ x ~ x ~ x"), - (euclid 5 11 "x", "x ~ x ~ x ~ x ~ x ~ ~"), - (euclid 5 12 "x", "x ~ ~ x ~ x ~ ~ x ~ x ~"), - -- (euclid 5 16 "x", "x ~ ~ x ~ ~ x ~ ~ x ~ ~ x ~ ~ ~ ~"), -- Toussaint is wrong.. - (euclid 5 16 "x", "x ~ ~ x ~ ~ x ~ ~ x ~ ~ x ~ ~ ~"), -- correction - -- (euclid 7 8 "x", "x ~ x x x x x x"), -- Toussaint is wrong.. - (euclid 7 8 "x", "x x x x x x x ~"), -- Correction - (euclid 7 12 "x", "x ~ x x ~ x ~ x x ~ x ~"), - (euclid 7 16 "x", "x ~ ~ x ~ x ~ x ~ ~ x ~ x ~ x ~"), - (euclid 9 16 "x", "x ~ x x ~ x ~ x ~ x x ~ x ~ x ~"), - (euclid 11 24 "x", "x ~ ~ x ~ x ~ x ~ x ~ x ~ ~ x ~ x ~ x ~ x ~ x ~"), - (euclid 13 24 "x", "x ~ x x ~ x ~ x ~ x ~ x ~ x x ~ x ~ x ~ x ~ x ~") - ] :: - [(Pattern String, String)] - ) + describe "matches examples in Toussaint's paper" $ do + mapM_ (\(a, b) -> it b $ compareP (Arc 0 1) a (parseBP_E b)) + ( [ (euclid 1 2 "x", "x ~"), + (euclid 1 3 "x", "x ~ ~"), + (euclid 1 4 "x", "x ~ ~ ~"), + (euclid 4 12 "x", "x ~ ~ x ~ ~ x ~ ~ x ~ ~"), + (euclid 2 5 "x", "x ~ x ~ ~"), + -- (euclid 3 4 "x", "x ~ x x"), -- Toussaint is wrong.. + (euclid 3 4 "x", "x x x ~"), -- correction + (euclid 3 5 "x", "x ~ x ~ x"), + (euclid 3 7 "x", "x ~ x ~ x ~ ~"), + (euclid 3 8 "x", "x ~ ~ x ~ ~ x ~"), + (euclid 4 7 "x", "x ~ x ~ x ~ x"), + (euclid 4 9 "x", "x ~ x ~ x ~ x ~ ~"), + (euclid 4 11 "x", "x ~ ~ x ~ ~ x ~ ~ x ~"), + -- (euclid 5 6 "x", "x ~ x x x x"), -- Toussaint is wrong.. + (euclid 5 6 "x", "x x x x x ~"), -- correction + (euclid 5 7 "x", "x ~ x x ~ x x"), + (euclid 5 8 "x", "x ~ x x ~ x x ~"), + (euclid 5 9 "x", "x ~ x ~ x ~ x ~ x"), + (euclid 5 11 "x", "x ~ x ~ x ~ x ~ x ~ ~"), + (euclid 5 12 "x", "x ~ ~ x ~ x ~ ~ x ~ x ~"), + -- (euclid 5 16 "x", "x ~ ~ x ~ ~ x ~ ~ x ~ ~ x ~ ~ ~ ~"), -- Toussaint is wrong.. + (euclid 5 16 "x", "x ~ ~ x ~ ~ x ~ ~ x ~ ~ x ~ ~ ~"), -- correction + -- (euclid 7 8 "x", "x ~ x x x x x x"), -- Toussaint is wrong.. + (euclid 7 8 "x", "x x x x x x x ~"), -- Correction + (euclid 7 12 "x", "x ~ x x ~ x ~ x x ~ x ~"), + (euclid 7 16 "x", "x ~ ~ x ~ x ~ x ~ ~ x ~ x ~ x ~"), + (euclid 9 16 "x", "x ~ x x ~ x ~ x ~ x x ~ x ~ x ~"), + (euclid 11 24 "x", "x ~ ~ x ~ x ~ x ~ x ~ x ~ ~ x ~ x ~ x ~ x ~ x ~"), + (euclid 13 24 "x", "x ~ x x ~ x ~ x ~ x ~ x ~ x x ~ x ~ x ~ x ~ x ~") + ] :: + [(Pattern String, String)] + ) it "can be called with a negative first value to give the inverse" $ do compareP (Arc 0 1) diff --git a/tidal-core/test/Sound/Tidal/UtilsTest.hs b/tidal-core/test/Sound/Tidal/UtilsTest.hs index acca534d..c8720347 100644 --- a/tidal-core/test/Sound/Tidal/UtilsTest.hs +++ b/tidal-core/test/Sound/Tidal/UtilsTest.hs @@ -3,52 +3,51 @@ module Sound.Tidal.UtilsTest where import Sound.Tidal.Utils -import Test.Microspec +import Test.Hspec import Prelude hiding ((*>), (<*)) -run :: Microspec () +run :: Spec run = describe "Sound.Tidal.Utils" $ do - describe "delta" $ do - it "subtracts the second element of a tuple from the first" $ do - property $ delta (3, 10) === (7 :: Int) + it "subtracts the second element of a tuple from the first" $ do + delta (3, 10) `shouldBe` (7 :: Int) - describe "applies function to both elements of tuple" $ do - let res = mapBoth (+ 1) (2, 5) - property $ ((3, 6) :: (Int, Int)) === res + it "applies function to both elements of tuple" $ do + let res = mapBoth (+ 1) (2, 5) + res `shouldBe` ((3, 6) :: (Int, Int)) - describe "apply function to first element of tuple" $ do - let res = mapFst (+ 1) (2, 5) - property $ ((3, 5) :: (Int, Int)) === res + it "apply function to first element of tuple" $ do + let res = mapFst (+ 1) (2, 5) + res `shouldBe` ((3, 5) :: (Int, Int)) - describe "apply function to second element of tuple" $ do - let res = mapSnd (+ 1) (2, 5) - property $ ((2, 6) :: (Int, Int)) === res + it "apply function to second element of tuple" $ do + let res = mapSnd (+ 1) (2, 5) + res `shouldBe` ((2, 6) :: (Int, Int)) - describe "return midpoint between first and second tuple value" $ do - let res = mid (2, 5) - property $ (3.5 :: Double) === res + it "return midpoint between first and second tuple value" $ do + let res = mid (2, 5) + res `shouldBe` (3.5 :: Double) - describe "return of two lists, with unique values to each list" $ do - let res = removeCommon [1, 2, 5, 7, 12, 16] [2, 3, 4, 5, 15, 16] - property $ (([1, 7, 12], [3, 4, 15]) :: ([Int], [Int])) === res + it "return of two lists, with unique values to each list" $ do + let res = removeCommon [1, 2, 5, 7, 12, 16] [2, 3, 4, 5, 15, 16] + res `shouldBe` (([1, 7, 12], [3, 4, 15]) :: ([Int], [Int])) - describe "wrap around indexing" $ do - let res = (!!!) [1 .. 5] 7 - property $ (3 :: Int) === res + it "wrap around indexing" $ do + let res = (!!!) [1 .. 5] 7 + res `shouldBe` (3 :: Int) - describe "safe list indexing" $ do - let res = nth 2 ([] :: [Int]) - property $ Nothing === res + it "safe list indexing" $ do + let res = nth 2 ([] :: [Int]) + res `shouldBe` Nothing - describe "list accumulation with given list elements" $ do - let res = accumulate ([1 .. 5] :: [Int]) - property $ [1, 3, 6, 10, 15] === res + it "list accumulation with given list elements" $ do + let res = accumulate ([1 .. 5] :: [Int]) + res `shouldBe` [1, 3, 6, 10, 15] - describe "index elements in list" $ do - let res = enumerate ['a', 'b', 'c'] - property $ [(0, 'a'), (1, 'b'), (2, 'c')] === res + it "index elements in list" $ do + let res = enumerate ['a', 'b', 'c'] + res `shouldBe` [(0, 'a'), (1, 'b'), (2, 'c')] - describe "split list by given pred" $ do - let res = wordsBy (== ':') "bd:3" - property $ ["bd", "3"] === res + it "split list by given pred" $ do + let res = wordsBy (== ':') "bd:3" + res `shouldBe` ["bd", "3"] diff --git a/tidal-core/test/Test.hs b/tidal-core/test/Test.hs index 1ec154b2..769fc7c3 100644 --- a/tidal-core/test/Test.hs +++ b/tidal-core/test/Test.hs @@ -11,10 +11,10 @@ import Sound.Tidal.ScalesTest import Sound.Tidal.StepwiseTest import Sound.Tidal.UITest import Sound.Tidal.UtilsTest -import Test.Microspec +import Test.Hspec main :: IO () -main = microspec $ do +main = hspec $ do Sound.Tidal.CoreTest.run Sound.Tidal.ParseTest.run Sound.Tidal.ParamsTest.run diff --git a/tidal-core/test/TestUtils.hs b/tidal-core/test/TestUtils.hs index 74f43cc4..a2aee530 100644 --- a/tidal-core/test/TestUtils.hs +++ b/tidal-core/test/TestUtils.hs @@ -19,7 +19,7 @@ import Sound.Tidal.Stepwise as C import Sound.Tidal.UI as C import Prelude hiding ((*>), (<*)) -import Test.Microspec +import Test.Hspec import Prelude hiding ((*>), (<*)) class TolerantEq a where @@ -45,13 +45,13 @@ instance TolerantEq (Event ValueMap) where (Event _ w p x) ~== (Event _ w' p' x') = w == w' && p == p' && x ~== x' -- | Compare the events of two patterns using the given arc -compareP :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Property +compareP :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Expectation compareP a p p' = sort (queryArc (stripContext p) a) `shouldBe` sort (queryArc (stripContext p') a) -- | Like @compareP@, but tries to 'defragment' the events -comparePD :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Property +comparePD :: (Ord a, Show a) => Arc -> Pattern a -> Pattern a -> Expectation comparePD a p p' = sort (defragParts $ queryArc (stripContext p) a) `shouldBe` sort (defragParts $ queryArc (stripContext p') a) @@ -68,4 +68,4 @@ stripContext :: Pattern a -> Pattern a stripContext = setContext $ Context [] firstCycleValues :: Pattern a -> [a] -firstCycleValues pat = map value $ queryArc pat (Arc 0 1) \ No newline at end of file +firstCycleValues pat = map value $ queryArc pat (Arc 0 1) diff --git a/tidal-core/tidal-core.cabal b/tidal-core/tidal-core.cabal index 05145deb..1cb03f89 100644 --- a/tidal-core/tidal-core.cabal +++ b/tidal-core/tidal-core.cabal @@ -70,7 +70,7 @@ test-suite tests build-depends: base >=4 && <5, - microspec >=0.2.0.1, + hspec >=2.11.9, containers, tidal-core, deepseq diff --git a/tidal-parse/src/Sound/Tidal/Parse.hs b/tidal-parse/src/Sound/Tidal/Parse.hs index e381dadd..a8823324 100644 --- a/tidal-parse/src/Sound/Tidal/Parse.hs +++ b/tidal-parse/src/Sound/Tidal/Parse.hs @@ -13,19 +13,16 @@ import Data.Char import Data.List (dropWhileEnd) import qualified Data.Text import Language.Haskellish as Haskellish - -import Sound.Tidal.ParseBP (Enumerable, Parseable, parseBP) - -import Sound.Tidal.UI as T import Sound.Tidal.Chords as T import Sound.Tidal.Control as T import Sound.Tidal.Core as T import Sound.Tidal.Params as T +import Sound.Tidal.Parse.TH +import Sound.Tidal.ParseBP (Enumerable, Parseable, parseBP) import Sound.Tidal.Pattern as T import Sound.Tidal.Scales as T import Sound.Tidal.Simple as T - -import Sound.Tidal.Parse.TH +import Sound.Tidal.UI as T type H = Haskellish () diff --git a/tidal-parse/test/Sound/Tidal/TidalParseTest.hs b/tidal-parse/test/Sound/Tidal/TidalParseTest.hs index 7ab41f37..91d8055b 100644 --- a/tidal-parse/test/Sound/Tidal/TidalParseTest.hs +++ b/tidal-parse/test/Sound/Tidal/TidalParseTest.hs @@ -17,21 +17,21 @@ import Sound.Tidal.Scales () import Sound.Tidal.Show () import Sound.Tidal.Simple () -import Test.Microspec hiding (run) +import Test.Hspec stripContext :: Pattern a -> Pattern a stripContext = setContext $ Context [] -parsesTo :: String -> ControlPattern -> Property +parsesTo :: String -> ControlPattern -> Expectation parsesTo str p = x `shouldBe` y where x = query . stripContext <$> parseTidal str <*> Right (State (Arc 0 16) Map.empty) y = Right $ queryArc (stripContext p) (Arc 0 16) -causesParseError :: String -> Property +causesParseError :: String -> Expectation causesParseError str = isLeft (parseTidal str :: Either String ControlPattern) `shouldBe` True -run :: Microspec () +run :: Spec run = describe "parseTidal" $ do it "parses the empty string as silence" $ diff --git a/tidal-parse/test/Test.hs b/tidal-parse/test/Test.hs index 3931b24e..75793f3d 100644 --- a/tidal-parse/test/Test.hs +++ b/tidal-parse/test/Test.hs @@ -1,8 +1,8 @@ {-# LANGUAGE OverloadedStrings #-} import Sound.Tidal.TidalParseTest -import Test.Microspec +import Test.Hspec main :: IO () -main = microspec $ do +main = hspec $ do Sound.Tidal.TidalParseTest.run diff --git a/tidal-parse/tidal-parse.cabal b/tidal-parse/tidal-parse.cabal index 04f106a2..b4e7368a 100644 --- a/tidal-parse/tidal-parse.cabal +++ b/tidal-parse/tidal-parse.cabal @@ -50,7 +50,7 @@ test-suite tests other-modules: Sound.Tidal.TidalParseTest build-depends: base ==4.* - , microspec >= 0.2.0.1 + , hspec >=2.11.9 , containers < 0.8 , tidal-parse , tidal-core diff --git a/tidal.cabal b/tidal.cabal index 2f4ab74c..a34f5377 100644 --- a/tidal.cabal +++ b/tidal.cabal @@ -74,7 +74,7 @@ test-suite tests TestUtils build-depends: base >=4 && <5, - microspec >=0.2.0.1, + hspec >=2.11.9, hosc >=0.21 && <0.22, containers, parsec,