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"
This commit is contained in:
ivanbrennan 2020-09-18 11:20:50 -04:00
parent f06ee5e1ff
commit c5745b6299
No known key found for this signature in database
GPG Key ID: 79C3C47DC652EA54

75
tests/RotateSome.hs Normal file
View File

@ -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