forked from haskell-webdriver/haskell-webdriver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
QuickCheck.hs
109 lines (91 loc) · 3.8 KB
/
QuickCheck.hs
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS -fwarn-unused-imports #-}
module QuickCheck where
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Data.Function
import Data.List as List
import Prelude hiding ((++))
import Test.QuickCheck as QC
--import Test.QuickCheck.Property as QC
import Test.WebDriver
import Test.WebDriver.Session
--import Test.WebDriver.Config
import qualified Data.Text as ST
import qualified Data.Array as AR
config :: WDConfig
config = defaultConfig
main :: IO ()
main = do
runSession config . finallyClose $ do
session <- getSession
openPage "about:blank"
liftIO . quickCheck $ prop_cutArray session
-- | some javascript function i want to test (included in this haskell
-- module for convenience; usually it would more likely be located in
-- the test target).
cutArrayJS :: [ST.Text]
cutArrayJS = "// Array Remove - By John Resig (MIT Licensed)" :
"function cutArray(a, from, to) {" :
" var rest = a.slice((to || from) + 1 || a.length);" :
" a.length = from < 0 ? a.length + from : from;" :
" a.push.apply(a, rest);" :
" return a;" :
"};" :
[]
-- | reference implementation in haskell
cutArray :: CutArray -> [Int]
cutArray (CutArray i a _) | abs(a) > (length i - 1) = error "cutArray: a out of bounds!"
cutArray (CutArray i _ (Just b)) | abs(b) > (length i - 1) = error "cutArray: b out of bounds!"
cutArray (CutArray i a (Just b)) | a * b < 0 = error ("cutArray: a and b must have same sign! " ++ show (a, b))
cutArray (CutArray i a (Just b)) | abs(b) < abs(a) = error ("cutArray: negative range! " ++ show (a, b))
cutArray (CutArray i a b) = f i a b
where
f i a Nothing = f i a (Just a)
f i a (Just b) = if a >= 0
then take a i ++ drop (b + 1) i
else reverse (f (reverse i) (-b - 1) (Just (-a - 1)))
-- | data type with input for cutArray
data CutArray = CutArray [Int] Int (Maybe Int)
deriving (Eq, Show)
_a_range ar = (1 - length ar, length ar - 1)
_b_range ar a = if a >= 0
then (a, length ar - 1)
else (1 - length ar, a)
-- | arbitrary *valid* inputs for 'CutArray'.
instance Arbitrary CutArray where
arbitrary = do
ar <- (:) <$> arbitrary <*> arbitrary
let ar' = map (`mod` (1000 :: Int)) ar -- (avoid int overflows in js)
a <- choose (_a_range ar)
b <- frequency [(20, pure Nothing), (80, Just <$> choose (_b_range ar a))]
return $ CutArray ar' a b
shrink (CutArray ar a b) = filter (\ (CutArray ar a b) ->
AR.inRange (_a_range ar) a &&
maybe True (AR.inRange (_b_range ar a)) b
) $
CutArray <$> shrink ar <*> shrink a <*> shrink b
-- | the quickcheck property
prop_cutArray :: WDSession -> CutArray -> QC.Property
prop_cutArray session tc = ioProperty $ runWD session $ wd_cutArray tc
-- | the underlying property in the web driver monad.
wd_cutArray :: CutArray -> WD Bool
wd_cutArray tc@(CutArray arrayIn a b) = do
liftIO $ print tc
let arrayOutShould :: [Int] = cutArray tc
arrayOutActually :: [Int] <- callff arrayIn a b
return $ arrayOutShould == arrayOutActually
where
callff :: [Int] -> Int -> Maybe Int -> WD [Int]
callff arrayIn a b = executeJS [JSArg arrayIn, JSArg a, JSArg b] . ST.intercalate "\n" $
"var arrayIn = arguments[0];" :
"var a = arguments[1];" :
"var b = arguments[2];" :
"" :
-- "console.log([arrayIn, a, b].toString());" :
cutArrayJS ++
"" :
"return cutArray(arrayIn, a, b);" :
[]