{-# LANGUAGE GADTs, PartialTypeSignatures #-}

module Tests_08(runTests, boolTests) where

import Template_08(number, evenListSum, 
  dig2intFold, dig2int, insertionSortRec, insertionSortFold, foldNested, nextRow, pascalsTriangle)
import Test.LeanCheck

-- Generic Setup 
data Test = forall a. Testable a => Test String String a

runTests = flip mapM_ tests
  (\ (Test ex name t) -> putStrLn ("running " ++ ex ++ "(" ++ name ++ ")" ++ "-tests") >> checkFor 1000 t)

-- Tests for this week 

-- 1.1
numberTest :: [Char] -> Bool
numberTest xs = let nxs = number xs 
  in map snd nxs == xs && checkNums 0 nxs
   where checkNums _ [] = True
         checkNums i ((j,_) : xs) = i == j && checkNums (i+1) xs

-- 1.2
evenListSumTest :: [Integer] -> Bool
evenListSumTest xs = evenListSum xs == elsRec 1 xs 
  where
   elsRec _ [] = 0
   elsRec i (x : xs)
     | even i = i^2 * x + elsRec (i+1) xs
     | otherwise = elsRec (i+1) xs

-- 2.1
dig2intTest :: [Integer] -> Bool
dig2intTest xs = dig2int xs == dig2intFold xs

-- 2.2
insertionSortTest :: [Integer] -> Bool
insertionSortTest xs = insertionSortRec xs == insertionSortFold xs

-- 2.3
foldNestedAdditionTest :: [[Integer]] -> Bool
foldNestedAdditionTest xs = foldNested (+) 0 xs == sum (concat xs)

foldNestedConcatTest :: [[String]] -> Bool
foldNestedConcatTest xs = foldNested (++) "" xs == concat (concat xs)

foldNestedReverseTest :: [[Int]] -> Bool
foldNestedReverseTest xs = foldNested (flip (:)) [] xs == reverse (concat xs)

-- 3.1
nextRowTest :: Integer -> Bool
nextRowTest n = n >= 1 ==> n <= 200 ==> nextRow (row n) == row (n + 1)
  where
    row n = [binomial (n - 1) k | k <- [0 .. (n - 1)]]
    binomial n k = product [n - k + 1 .. n] `div` product [1 .. k]

-- 3.2
pascalsTriangleTest :: Int -> Bool
pascalsTriangleTest n = n <= 200 ==> pascalsTriangle (fromIntegral n) == take n (iterate nextRow [1])


tests :: [Test]
tests = [
  Test "1.1" "number" numberTest,
  Test "1.2" "evenListSum" evenListSumTest,
  Test "2.1" "dig2int xs = dig2intFold xs" dig2intTest,
  Test "2.2" "insertionSortRec xs = insertionSortFold xs" insertionSortTest,
  Test "2.3" "foldNested (+) 0 xs == sum (concat xs)" foldNestedAdditionTest,
  Test "2.3" "foldNested (++) \"\" xs == concat (concat xs)" foldNestedConcatTest,
  Test "2.3" "foldNested (flip (:)) [] xs == reverse (concat xs)" foldNestedReverseTest,
  Test "3.1" "nextRow" nextRowTest,
  Test "3.2" "pascalsTriangle" pascalsTriangleTest
  ]

boolTests :: [((String,String), Bool)]
boolTests = map (\ (Test ex n t) -> ((ex,n), holds 1000 t)) tests