content: import Data.List
  import Test.FitSpec
  
  
  ordered :: Ord a => [a] -> Bool
  ordered [] = True
  ordered [_] = True
  ordered (x:y:xs) = x <= y && ordered (y:xs)
  
  permutation :: Eq a => [a] -> [a] -> Bool
  []     `permutation` []    = True
  (_:_)  `permutation` []    = False
  []     `permutation` (_:_) = False
  (x:xs) `permutation` ys    = x `elem` ys  &&  xs `permutation` delete x ys
  
  count :: Eq a => a -> [a] -> Int
  count x = length . filter (==x)
  
  
  properties :: (Ord a, Show a, Listable a)
             => ([a] -> [a]) -> [Property]
  properties sort =
    [ property $ \xs ->          ordered (sort xs)
    , property $ \xs ->           length (sort xs) == length xs
    , property $ \x xs ->         elem x (sort xs) == elem x xs
    , property $ \x xs ->        count x (sort xs) == count x xs
    , property $ \xs ->   permutation xs (sort xs)
    , property $ \x xs ->       insert x (sort xs) == sort (x:xs)
    ]
  
  
  sargs :: Args
  sargs = args
    { names = ["sort xs"]
    , timeout  =    0
    , nMutants = 1000
    , nTests   = 1000
    }
  --, extraMutants = take 0
  --               . concat
  --               . lsmap (. sort)
  --               $ cons2 (\y ys -> (++ (y:ys))) -- prepend non-empty list
  --            \++/ cons2 (\y ys -> ((y:ys) ++)) -- append non-empty list
  
  type Ty a = [a] -> [a]
  
  main :: IO ()
  main = do
    as <- getArgsWith sargs
    let run f = reportWith as f properties
    case concat $ extra as of
      "bool"  -> run (sort :: Ty Bool)
      "bools" -> run (sort :: Ty [Bool])
      "int"   -> run (sort :: Ty Int)
      "i1"    -> run (sort :: Ty Int1)
      "i2"    -> run (sort :: Ty Int2)
      "i3"    -> run (sort :: Ty Int3)
      "w1"    -> run (sort :: Ty Word1)
      "w2"    -> run (sort :: Ty Word2)
      "w3"    -> run (sort :: Ty Word3)
      "unit"  -> run (sort :: Ty ())
      ""      -> run (sort :: Ty Word2)
      t       -> putStrLn $ "unknown type " ++ t
  
  -- This hack is only necessary when using sortCounter as a manual mutant
  instance Bounded a => Bounded [a] where
    minBound = []
    maxBound = repeat maxBound -- non terminating upper bound
  
  sortCounter :: (Bounded a, Ord a) => [a] -> [a]
  sortCounter = (++ [maxBound]) . sort
  