1{-# LANGUAGE MultiParamTypeClasses #-}
2{-# LANGUAGE FlexibleInstances #-}
3{- Generate some input bytes and delays between blocks of input bytes. Verify the events produced
8import Verify.Graphics.Vty.Output
10import Data.List (intersperse)
12import Graphics.Vty hiding (resize)
13import Graphics.Vty.Input.Events
14import Graphics.Vty.Input.Internal
15import Graphics.Vty.Input.Terminfo
17import Control.Applicative
18import Control.Concurrent
19import Control.Exception
20import Control.Lens ((^.))
26import System.Console.Terminfo
28import System.Posix.Terminal (openPseudoTerminal)
29import System.Posix.Types
32import Test.Framework.Providers.SmallCheck
35import Test.SmallCheck.Series
39-- processing a block of 16 chars is the largest I can do without taking too long to run the test.
46forEachOf :: (Show a, Testable m b) => [a] -> (a -> b) -> Property m
47forEachOf l = over (generate (\n -> take n l))
50 = Bytes String -- | input sequence encoded as a string. Regardless, the input is read a byte at a time.
51 | Delay Int -- | microsecond delay
54type InputSpec = [InputEvent]
56type ExpectedSpec = [Event]
58synthesizeInput :: InputSpec -> Fd -> IO ()
59synthesizeInput input outHandle = forM_ input f >> (void $ fdWrite outHandle "\xFFFD")
61 f (Bytes str) = void $ fdWrite outHandle str
62 f (Delay t) = threadDelay t
64minDetectableDelay :: Int
65minDetectableDelay = 4000
71testKeyDelay = minDetectableDelay * 4
73testEscSampleDelay :: Int
74testEscSampleDelay = minDetectableDelay * 2
76genEventsUsingIoActions :: Int -> IO () -> IO () -> IO ()
77genEventsUsingIoActions maxDuration inputAction outputAction = do
78 let maxDuration' = max minTimout maxDuration
79 readComplete <- newEmptyMVar
80 writeComplete <- newEmptyMVar
81 _ <- forkOS $ inputAction `finally` putMVar writeComplete ()
82 _ <- forkOS $ outputAction `finally` putMVar readComplete ()
83 Just () <- timeout maxDuration' $ takeMVar writeComplete
84 Just () <- timeout maxDuration' $ takeMVar readComplete
87compareEvents :: (Show a1, Show a, Eq a1) => a -> [a1] -> [a1] -> IO Bool
88compareEvents inputSpec expectedEvents outEvents = compareEvents' expectedEvents outEvents
90 compareEvents' [] [] = return True
91 compareEvents' [] outEvents' = do
92 printf "extra events %s\n" (show outEvents') :: IO ()
94 compareEvents' expectedEvents' [] = do
95 printf "events %s were not produced for input %s\n" (show expectedEvents') (show inputSpec) :: IO ()
96 printf "expected events %s\n" (show expectedEvents) :: IO ()
97 printf "received events %s\n" (show outEvents) :: IO ()
99 compareEvents' (e : expectedEvents') (o : outEvents')
100 | e == o = compareEvents' expectedEvents' outEvents'
102 printf "%s expected not %s for input %s\n" (show e) (show o) (show inputSpec) :: IO ()
103 printf "expected events %s\n" (show expectedEvents) :: IO ()
104 printf "received events %s\n" (show outEvents) :: IO ()
107assertEventsFromSynInput :: ClassifyTable -> InputSpec -> ExpectedSpec -> IO Bool
108assertEventsFromSynInput table inputSpec expectedEvents = do
109 let maxDuration = sum [t | Delay t <- inputSpec] + minDetectableDelay
110 event_count = length expectedEvents
111 (writeFd, readFd) <- openPseudoTerminal
112 (setTermAttr,_) <- attributeControl readFd
114 input <- initInputForFd def table readFd
115 eventsRef <- newIORef []
116 let writeWaitClose = do
117 synthesizeInput inputSpec writeFd
118 threadDelay minDetectableDelay
120 threadDelay minDetectableDelay
124 let readEvents = readLoop event_count
125 readLoop 0 = return ()
127 e <- readChan $ input^.eventChannel
128 modifyIORef eventsRef ((:) e)
130 genEventsUsingIoActions maxDuration writeWaitClose readEvents
131 outEvents <- reverse <$> readIORef eventsRef
132 compareEvents inputSpec expectedEvents outEvents
134newtype InputBlocksUsingTable event
135 = InputBlocksUsingTable ([(String,event)] -> [(String, event)])
137instance Show (InputBlocksUsingTable event) where
138 show (InputBlocksUsingTable _g) = "InputBlocksUsingTable"
140instance Monad m => Serial m (InputBlocksUsingTable event) where
142 n :: Int <- localDepth (const maxTableSize) series
143 return $ InputBlocksUsingTable $ \table -> concat (take n (selections table))
146 selections (x:xs) = let z = selections xs in [x] : (z ++ map ((:) x) z)
148verifyVisibleSynInputToEvent :: Property IO
149verifyVisibleSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) -> monadic $ do
150 let table = visibleChars
152 events = map snd inputSeq
153 keydowns = map (Bytes . fst) inputSeq
154 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
155 assertEventsFromSynInput universalTable input events
157verifyCapsSynInputToEvent :: Property IO
158verifyCapsSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) ->
159 forEachOf terminalsOfInterest $ \termName -> monadic $ do
160 term <- setupTerm termName
161 let table = capsClassifyTable term keysFromCapsTable
163 events = map snd inputSeq
164 keydowns = map (Bytes . fst) inputSeq
165 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
166 assertEventsFromSynInput table input events
168verifySpecialSynInputToEvent :: Property IO
169verifySpecialSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) -> monadic $ do
170 let table = specialSupportKeys
172 events = map snd inputSeq
173 keydowns = map (Bytes . fst) inputSeq
174 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
175 assertEventsFromSynInput universalTable input events
177verifyFullSynInputToEvent :: Property IO
178verifyFullSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) ->
179 forEachOf terminalsOfInterest $ \termName -> monadic $ do
180 term <- setupTerm termName
181 let table = classifyTableForTerm termName term
183 events = map snd inputSeq
184 keydowns = map (Bytes . fst) inputSeq
185 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
186 assertEventsFromSynInput table input events
188verifyFullSynInputToEvent_2x :: Property IO
189verifyFullSynInputToEvent_2x = forAll $ \(InputBlocksUsingTable gen) ->
190 forEachOf terminalsOfInterest $ \termName -> monadic $ do
191 term <- setupTerm termName
192 let table = classifyTableForTerm termName term
194 events = concatMap ((\s -> [s,s]) . snd) inputSeq
195 keydowns = map (Bytes . (\s -> s ++ s) . fst) inputSeq
196 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
197 assertEventsFromSynInput table input events
201 [ testProperty "synthesized typing of single visible chars translates to expected events"
202 verifyVisibleSynInputToEvent
203 , testProperty "synthesized typing of keys from capabilities tables translates to expected events"
204 verifyCapsSynInputToEvent
205 , testProperty "synthesized typing of hard coded special keys translates to expected events"
206 verifySpecialSynInputToEvent
207 , testProperty "synthesized typing of any key in the table translates to its paired event"
208 verifyFullSynInputToEvent
209 , testProperty "synthesized typing of 2x any key in the table translates to 2x paired event"
210 verifyFullSynInputToEvent_2x
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list