packages feed

gambler-0.4.1.0: test/Spec/Shortcut.hs

module Spec.Shortcut where

import Fold.Shortcut

import Test.Hspec

import Control.Applicative (pure, (<$>), (<*>), liftA2)
import Data.Bool (Bool (..))
import Data.Function ((&), flip)
import Data.List ((++))
import Data.Maybe (Maybe (Just, Nothing))
import Data.Ord (Ord (..))
import Prelude (Integer, undefined, odd)

import qualified Data.Char as Char

spec :: SpecWith ()
spec = describe "ShortcutFold" do

    it "Applicative" do
        let x = do
                  a <- length
                  b <- find Char.isLetter
                  c <- elementIndex 'x'
                  d <- elementIndex 'y'
                  e <- last
                  pure (a, b, c, d, e)
        run x ("1234xyz" ++ undefined) `shouldBe` (6, Just 'x', Just 4, Just 5, Just 'y')

    describe "first" do
        it "gets the first item" do
            shouldBe @(Maybe Integer) (run first [5, 4, 3]) (Just 5)
        it "is lazy" do
            shouldBe @(Maybe Integer) (run first (5 : undefined)) (Just 5)
        it "returns Nothing for []" do
            shouldBe @(Maybe Integer) (run first []) Nothing
        it "is tenacious" do
            shouldBe ((run ((,) <$> length <*> first)) "abc") (1, Just 'a')

    describe "endpoint functions" do
        describe "first" do
            it "gets the first item" do
                run first ([5, 4, 3] :: [Integer]) `shouldBe` Just 5
            it "returns Nothing with no input" do
                run first ([] :: [Integer]) `shouldBe` Nothing
            it "is lazy" do
                run first (5 : undefined :: [Integer]) `shouldBe` Just 5

    describe "null" do
        it "True for []" do
            run null ([] :: [Integer]) `shouldBe` True
        it "False for anything else" do
            run null ([1] :: [Integer]) `shouldBe` False
            run null ([1,2] :: [Integer]) `shouldBe` False
            run null ([1,2,3] :: [Integer]) `shouldBe` False

    describe "and" do
        it "True for []" do
            run and [] `shouldBe` True
        it "True for [True, ...]" do
            run and [True] `shouldBe` True
            run and [True,True] `shouldBe` True
            run and [True,True,True] `shouldBe` True
        it "False for anything else" do
            run and [False] `shouldBe` False
            run and [False,True] `shouldBe` False
            run and [True,False] `shouldBe` False
        it "is lazy" do
            run and (False : undefined) `shouldBe` False

    describe "or" do
        it "False for []" do
            run or [] `shouldBe` False
        it "False for [False, ...]" do
            run or [False] `shouldBe` False
            run or [False,False] `shouldBe` False
            run or [False,False,False] `shouldBe` False
        it "True for anything else" do
            run or [True] `shouldBe` True
            run or [False,True] `shouldBe` True
            run or [True,False] `shouldBe` True
        it "is lazy" do
            run or (True : undefined) `shouldBe` True

    describe "duplicate" do
        it "lets a fold run in two phases" do
            let a, b, c :: [Integer]
                a = [1,2,3]
                b = [4,7,12,15]
                c = a ++ b
                f = find (>= 10)
            (f & duplicate & flip run a & flip run b) `shouldBe` (run f c)
        it "preserves laziness" do
            let a, b :: [Integer]
                a = 1 : 15 : undefined
                b = undefined
                f = find (>= 10)
            (f & duplicate & flip run a & flip run b) `shouldBe` Just 15

    describe "repeatedly" do
        it "can find an item in a list of lists" do
            let a, b, c :: [Integer]
                a = [2, 8, 6]
                b = [12, 4, 5, 16]
                c = [4, 18, 20]
            run (repeatedly run (find odd)) [a, b, c]
                `shouldBe` Just 5
        it "preserves laziness" do
            let a, b, c :: [Integer]
                a = [2, 8, 6]
                b = 12 : 4 : 5 : undefined
                c = undefined
            run (repeatedly run (find odd)) [a, b, c]
                `shouldBe` Just 5
        it "works within an Applicative combination with another 'repeatedly'" do
            let a, b, c :: [Integer]
                a = [2, 8, 6]
                b = 12 : 4 : 5 : undefined
                c = undefined
                f = liftA2 (,) (repeatedly run (find odd)) (repeatedly run (find (> 5)))
            run f [a, b, c]
                `shouldBe` (Just 5, Just 8)
        it "works on an Applicative combination of 'repeatedly's" do
            let a, b, c :: [Integer]
                a = [2, 8, 6]
                b = 12 : 4 : 5 : undefined
                c = undefined
                f = liftA2 (,) (find odd) (find (> 5))
            run (repeatedly run f) [a, b, c]
                `shouldBe` (Just 5, Just 8)
        it "works within an Applicative combination with something ambivalent" do
            let a, b, c :: [Integer]
                a = [2, 8, 6]
                b = 12 : 4 : 5 : undefined
                c = undefined
                f = liftA2 (,) (find odd) length
            run (repeatedly run f) [a, b, c]
                `shouldBe` (Just 5, 6)