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 Graphics.Vty hiding (resize)
11import Graphics.Vty.Input.Events
12import Graphics.Vty.Input.Loop
13import Graphics.Vty.Input.Terminfo
15import Control.Applicative
16import Control.Concurrent
17import Control.Exception
18import Control.Lens ((^.))
23import Data.List (intersperse, reverse, nubBy)
25import System.Console.Terminfo
27import System.Posix.Terminal (openPseudoTerminal)
28import System.Posix.Types
31import Test.Framework.Providers.SmallCheck
34import Test.SmallCheck.Series
38-- processing a block of 16 chars is the largest I can do without taking too long to run the test.
45forEachOf :: (Show a, Testable m b) => [a] -> (a -> b) -> Property m
46forEachOf l = over (generate (\n -> take n l))
49 = Bytes String -- | input sequence encoded as a string. Regardless, the input is read a byte at a time.
50 | Delay Int -- | microsecond delay
53type InputSpec = [InputEvent]
55type ExpectedSpec = [Event]
57synthesizeInput :: InputSpec -> Fd -> IO ()
58synthesizeInput input outHandle = forM_ input f >> (void $ fdWrite outHandle "\xFFFD")
60 f (Bytes str) = void $ fdWrite outHandle str
61 f (Delay t) = threadDelay t
63minDetectableDelay :: Int
64minDetectableDelay = 4000
70testKeyDelay = minDetectableDelay * 4
72testEscSampleDelay :: Int
73testEscSampleDelay = minDetectableDelay * 2
75genEventsUsingIoActions :: Int -> IO () -> IO () -> IO ()
76genEventsUsingIoActions maxDuration inputAction outputAction = do
77 let maxDuration' = max minTimout maxDuration
78 readComplete <- newEmptyMVar
79 writeComplete <- newEmptyMVar
80 _ <- forkOS $ inputAction `finally` putMVar writeComplete ()
81 _ <- forkOS $ outputAction `finally` putMVar readComplete ()
82 Just () <- timeout maxDuration' $ takeMVar writeComplete
83 Just () <- timeout maxDuration' $ takeMVar readComplete
86compareEvents :: (Show a1, Show a, Eq a1) => a -> [a1] -> [a1] -> IO Bool
87compareEvents inputSpec expectedEvents outEvents = compareEvents' expectedEvents outEvents
89 compareEvents' [] [] = return True
90 compareEvents' [] outEvents' = do
91 printf "extra events %s\n" (show outEvents') :: IO ()
93 compareEvents' expectedEvents' [] = do
94 printf "events %s were not produced for input %s\n" (show expectedEvents') (show inputSpec) :: IO ()
95 printf "expected events %s\n" (show expectedEvents) :: IO ()
96 printf "received events %s\n" (show outEvents) :: IO ()
98 compareEvents' (e : expectedEvents') (o : outEvents')
99 | e == o = compareEvents' expectedEvents' outEvents'
101 printf "%s expected not %s for input %s\n" (show e) (show o) (show inputSpec) :: IO ()
102 printf "expected events %s\n" (show expectedEvents) :: IO ()
103 printf "received events %s\n" (show outEvents) :: IO ()
106assertEventsFromSynInput :: ClassifyMap -> InputSpec -> ExpectedSpec -> IO Bool
107assertEventsFromSynInput table inputSpec expectedEvents = do
108 let maxDuration = sum [t | Delay t <- inputSpec] + minDetectableDelay
109 eventCount = length expectedEvents
110 (writeFd, readFd) <- openPseudoTerminal
111 (setTermAttr,_) <- attributeControl readFd
113 input <- initInputForFd def "dummy" table readFd
114 eventsRef <- newIORef []
115 let writeWaitClose = do
116 synthesizeInput inputSpec writeFd
117 threadDelay minDetectableDelay
119 threadDelay minDetectableDelay
123 let readEvents = readLoop eventCount
124 readLoop 0 = return ()
126 e <- readChan $ input^.eventChannel
127 modifyIORef eventsRef ((:) e)
129 genEventsUsingIoActions maxDuration writeWaitClose readEvents
130 outEvents <- reverse <$> readIORef eventsRef
131 compareEvents inputSpec expectedEvents outEvents
133newtype InputBlocksUsingTable event
134 = InputBlocksUsingTable ([(String,event)] -> [(String, event)])
136instance Show (InputBlocksUsingTable event) where
137 show (InputBlocksUsingTable _g) = "InputBlocksUsingTable"
139instance Monad m => Serial m (InputBlocksUsingTable event) where
141 n :: Int <- localDepth (const maxTableSize) series
142 return $ InputBlocksUsingTable $ \raw_table ->
143 let table = reverse $ nubBy (\(s0,_) (s1,_) -> s0 == s1) $ reverse raw_table
144 in concat (take n (selections table))
147 selections (x:xs) = let z = selections xs in [x] : (z ++ map ((:) x) z)
149verifyVisibleSynInputToEvent :: Property IO
150verifyVisibleSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) -> monadic $ do
151 let table = visibleChars
153 events = map snd inputSeq
154 keydowns = map (Bytes . fst) inputSeq
155 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
156 assertEventsFromSynInput universalTable input events
158verifyCapsSynInputToEvent :: Property IO
159verifyCapsSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) ->
160 forEachOf terminalsOfInterest $ \termName -> monadic $ do
161 term <- setupTerm termName
162 let table = capsClassifyMap term keysFromCapsTable
164 events = map snd inputSeq
165 keydowns = map (Bytes . fst) inputSeq
166 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
167 assertEventsFromSynInput table input events
169verifySpecialSynInputToEvent :: Property IO
170verifySpecialSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) -> monadic $ do
171 let table = specialSupportKeys
173 events = map snd inputSeq
174 keydowns = map (Bytes . fst) inputSeq
175 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
176 assertEventsFromSynInput universalTable input events
178verifyFullSynInputToEvent :: Property IO
179verifyFullSynInputToEvent = forAll $ \(InputBlocksUsingTable gen) ->
180 forEachOf terminalsOfInterest $ \termName -> monadic $ do
181 term <- setupTerm termName
182 let table = classifyMapForTerm termName term
184 events = map snd inputSeq
185 keydowns = map (Bytes . fst) inputSeq
186 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
187 assertEventsFromSynInput table input events
189verifyFullSynInputToEvent_2x :: Property IO
190verifyFullSynInputToEvent_2x = forAll $ \(InputBlocksUsingTable gen) ->
191 forEachOf terminalsOfInterest $ \termName -> monadic $ do
192 term <- setupTerm termName
193 let table = classifyMapForTerm termName term
195 events = concatMap ((\s -> [s,s]) . snd) inputSeq
196 keydowns = map (Bytes . (\s -> s ++ s) . fst) inputSeq
197 input = intersperse (Delay testKeyDelay) keydowns ++ [Delay testKeyDelay]
198 assertEventsFromSynInput table input events
202 [ testProperty "synthesized typing of single visible chars translates to expected events"
203 verifyVisibleSynInputToEvent
204 , testProperty "synthesized typing of keys from capabilities tables translates to expected events"
205 verifyCapsSynInputToEvent
206 , testProperty "synthesized typing of hard coded special keys translates to expected events"
207 verifySpecialSynInputToEvent
208 , testProperty "synthesized typing of any key in the table translates to its paired event"
209 verifyFullSynInputToEvent
210 , testProperty "synthesized typing of 2x any key in the table translates to 2x paired event"
211 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