module Test.Framework.Tests.Runners.ThreadPool (tests) where

import Test.Framework.Runners.ThreadPool

import Test.HUnit ( (@=?), Test(TestCase, TestLabel), Assertion )

import System.Random ( getStdGen, Random(randomRs) )

import Control.Concurrent ( threadDelay )


tests :: [Test]
tests = [TestLabel "ThreadPool.executeOnPool preserves order"                         (TestCase test_execute_preserves_order),
         TestLabel "ThreadPool.executeOnPool preserves order even with delays"        (TestCase test_execute_preserves_order_even_with_delay),
         TestLabel "ThreadPool.executeOnPool input list can depend on previous items" (TestCase test_execute_schedules_lazily)]

test_execute_preserves_order :: Assertion
test_execute_preserves_order = do
    let input = [1..1000] :: [Int]
    output <- executeOnPool 4 $ map return input
    input @=? output

test_execute_preserves_order_even_with_delay :: Assertion
test_execute_preserves_order_even_with_delay = do
    gen <- getStdGen
    let -- Execute 100 actions with a random delay of up to 50ms each
        input = [1..100] :: [Int]
        actions = zipWith (\n delay -> threadDelay delay >> return n) input (randomRs (0, 50000) gen)
    output <- executeOnPool 4 actions
    input @=? output

test_execute_schedules_lazily :: Assertion
test_execute_schedules_lazily = mdo
    ~(first_output:rest) <- executeOnPool 4 $ return 10 : (return 20) : replicate first_output (return 99) :: IO [Int]
    [10, 20] ++ (replicate 10 99) @=? (first_output:rest)
