diff --git a/tests/RotateSome.hs b/tests/RotateSome.hs new file mode 100644 index 00000000..6ca3b9bb --- /dev/null +++ b/tests/RotateSome.hs @@ -0,0 +1,75 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE FlexibleInstances #-} + +module RotateSome where + +import Test.QuickCheck (Arbitrary, Gen, arbitrary, choose, listOf, quickCheck) +import Utils (applyN) +import XMonad.StackSet (Stack (Stack), down, focus, integrate, up) +import XMonad.Actions.RotateSome (rotateSome) + +instance Arbitrary (Stack Int) where + arbitrary = do + foc <- arbNat + ups <- listOf arbNat + downs <- listOf arbNat + pure (Stack foc ups downs) + +arbNat :: Gen Int +arbNat = fmap abs arbitrary + +newtype Divisor = Divisor Int deriving Show +instance Arbitrary Divisor where + arbitrary = Divisor <$> choose (1, 5) + +isMultOf :: Int -> Int -> Bool +x `isMultOf` n = (x `rem` n) == 0 + +-- Total number of elements does not change. +prop_rotate_some_length (Divisor d) (stk :: Stack Int) = + length (integrate stk) == length (integrate $ rotateSome (`isMultOf` d) stk) + +-- Applying rotateSome N times completes a cycle, where N is the number of +-- elements that satisfy the predicate. +prop_rotate_some_cycle (Divisor d) (stk :: Stack Int) = + stk == applyN (Just n) (rotateSome (`isMultOf` d)) stk + where + n = length $ filter (`isMultOf` d) (integrate stk) + +-- Elements that do not satisfy the predicate remain anchored in place. +prop_rotate_some_anchors (Divisor d) (stk :: Stack Int) = + all check $ + zip + (integrate stk) + (integrate $ rotateSome (`isMultOf` d) stk) + where + check (before, after) = (before `isMultOf` d) || before == after + +-- Elements that satisfy the predicate rotate by one position. +prop_rotate_some_rotate (Divisor d) (stk :: Stack Int) = + drop 1 before ++ take 1 before == after + where + before = filter p (integrate stk) + after = filter p (integrate $ rotateSome p stk) + p = (`isMultOf` d) + +-- Focus position is preserved. +prop_rotate_some_focus (Divisor d) (stk :: Stack Int) = + length (up stk) == length (up $ rotateSome (`isMultOf` d) stk) + +main :: IO () +main = do + putStrLn "Testing rotateSome length" + quickCheck prop_rotate_some_length + + putStrLn "Testing rotateSome cycle" + quickCheck prop_rotate_some_cycle + + putStrLn "Testing rotateSome anchors" + quickCheck prop_rotate_some_anchors + + putStrLn "Testing rotateSome rotate" + quickCheck prop_rotate_some_rotate + + putStrLn "Testing rotateSome focus" + quickCheck prop_rotate_some_focus