xmonad-contrib/tests/RotateSome.hs
ivanbrennan c5745b6299
add RotateSome property tests
Verify that rotateSome behaves as expected and never fails to pattern
match.

In order to run these tests, I ran a custom script:

  scripts/run-tests.sh tests/RotateSome.hs

where the script contained the following:

  set -eu

  toplevel=$(git rev-parse --show-toplevel)
  XMONAD="${XMONAD:-$toplevel/../xmonad}"
  main=$(realpath -e "$1")

  instances_target="$XMONAD/tests/Instances.hs"
  instances_symlink="$toplevel/tests/Instances.hs"

  properties_target="$XMONAD/tests/Properties"
  properties_symlink="$toplevel/tests/Properties"

  utils_target="$XMONAD/tests/Utils.hs"
  utils_symlink="$toplevel/tests/Utils.hs"

  trap "
      rm '$instances_symlink' '$utils_symlink' '$properties_symlink' || true
  " EXIT INT QUIT TERM

  ln -s "$instances_target" "$instances_symlink"
  ln -s "$properties_target" "$properties_symlink"
  ln -s "$utils_target" "$utils_symlink"

  runghc -DTESTING \
      -i"$toplevel" \
      -i"$toplevel/tests" \
      "$main"
2020-09-18 11:31:50 -04:00

76 lines
2.3 KiB
Haskell

{-# 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