File: Progress.hs

package info (click to toggle)
haskell-shake 0.13.2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 888 kB
  • ctags: 127
  • sloc: haskell: 6,388; makefile: 35; ansic: 25; sh: 2
file content (75 lines) | stat: -rw-r--r-- 2,656 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
{-# LANGUAGE DeriveDataTypeable #-}

module Examples.Test.Progress(main) where

import Development.Shake.Progress
import Development.Shake.Classes
import Examples.Util
import qualified Control.Exception as E
import Data.IORef
import Data.Monoid
import Data.Char


main = shaken test $ \args obj -> return ()


-- | Given a list of todo times, get out a list of how long is predicted
prog = progEx 10000000000000000

data MyException = MyException deriving (Show, Typeable)
instance E.Exception MyException


progEx :: Double -> [Double] -> IO [Double]
progEx mxDone todo = do
    let resolution = 10000 -- Use resolution to get extra detail on the numbers
    let done = scanl (+) 0 $ map (min mxDone . max 0) $ zipWith (-) todo (tail todo)
    pile <- newIORef $ tail $ zipWith (\t d -> mempty{timeBuilt=d*resolution,timeTodo=(t*resolution,0)}) todo done
    let get = do a <- readIORef pile
                 case a of
                     [] -> E.throw MyException
                     x:xs -> do writeIORef pile xs; return x

    out <- newIORef []
    let put x = do let (mins,secs) = break (== 'm') $ takeWhile (/= '(') x
                   let f x = let y = filter isDigit x in if null y then 0/0 else read y
                   modifyIORef out (++ [(if null secs then f mins else f mins * 60 + f secs) / resolution])
    -- we abort by killing the thread, but then catch the abort and resume normally
    E.catch (progressDisplayTester resolution put get) $ \MyException -> return ()
    fmap (take $ length todo) $ readIORef out


test build obj = do
    -- perfect functions should match perfectly
    xs <- prog [10,9..1]
    drop 2 xs === [8,7..1]
    xs <- prog $ map (*5) [10,9..1]
    drop 2 xs === [8,7..1]
    xs <- prog $ map (*0.2) [10,9..1]
    let dp3 x = fromIntegral (round $ x * 1000 :: Int) / 1000
    map dp3 (drop 2 xs) === [8,7..1]

    -- The properties below this line could be weakened

    -- increasing functions can't match
    xs <- prog [5,6,7]
    last xs === 7

    -- the first value must be plausible, or missing
    xs <- prog [187]
    assert (isNaN $ head xs) "No first value"

    -- desirable properties, could be weakened
    xs <- progEx 2 $ 100:map (*2) [10,9..1]
    drop 5 xs === [6,5..1]
    xs <- progEx 1 $ [10,9,100,8,7,6,5,4,3,2,1]
    assert (all (<= 1.5) $ map abs $ zipWith (-) (drop 5 xs) [6,5..1]) "Close"

    -- if no progress is made, don't keep the time going up
    xs <- prog [10,9,8,7,7,7,7,7]
    drop 5 xs === [7,7,7]

    -- if the work rate changes, should somewhat reflect that
    xs <- prog [10,9,8,7,6.5,6,5.5,5]
    assert (last xs > 7.1) "Some discounting (factor=0 would give 7)"