@@ -78,9 +78,13 @@ import Generics.SOP hiding (Shape)
7878import Test.QuickCheck as Exported hiding (Args , Result , function )
7979import qualified Test.QuickCheck as QC
8080
81+ import Data.Char (ord )
82+ import Data.Function (on )
8183import Data.List
8284import Data.Maybe
8385import Data.IORef
86+ import GHC.IO.Encoding (textEncodingName )
87+ import qualified System.IO as IO
8488import Type.Reflection
8589
8690-- | The default comparison of demands: exact equality
@@ -295,8 +299,16 @@ strictCheckSpecExact spec function =
295299 (putStrLn . head . lines ) (output result)
296300 case maybeExample of
297301 Nothing -> return ()
298- Just example ->
299- putStrLn (Prelude. uncurry displayCounterSpec example)
302+ Just example -> do
303+ unicode <- doesStdoutAcceptUnicode
304+ putStrLn (Prelude. uncurry (displayCounterSpec unicode) example)
305+
306+ doesStdoutAcceptUnicode :: IO Bool
307+ doesStdoutAcceptUnicode = do
308+ encoding <- IO. hGetEncoding IO. stdout
309+ case encoding of
310+ Nothing -> pure False
311+ Just enc -> pure (any (((==) `on` textEncodingName) enc) [IO. utf8, IO. utf8_bom, IO. utf16, IO. utf16le, IO. utf16be, IO. utf32, IO. utf32le, IO. utf32be])
300312
301313------------------------------------------------------------
302314-- An Evaluation is what we generate when StrictCheck-ing --
@@ -400,53 +412,94 @@ shrinkEvalWith
400412 T -> Nothing
401413 E pos -> Just pos
402414
415+ -- | If 'False' (unicode output is disabled), replace all non-ASCII characters with '?'.
416+ sanitize :: Bool -> String -> String
417+ sanitize True = id
418+ sanitize False = fmap (\ c -> if ord c < 128 then c else ' ?' )
403419
404420-- | Render a counter-example to a specification (that is, an 'Evaluation'
405- -- paired with some expected input demands it doesn't match) as a Unicode
406- -- box-drawing sketch
421+ -- paired with some expected input demands it doesn't match) as a
422+ -- box-drawing sketch (in Unicode or ASCII depending on whether the
423+ -- first argument is 'True' or 'False')
407424displayCounterSpec
408425 :: forall args result .
409426 (Shaped result , All Shaped args )
410- => Evaluation args result
427+ => Bool -- ^ 'True' to enable prettier Unicode output
428+ -> Evaluation args result
411429 -> NP Demand args
412430 -> String
413- displayCounterSpec (Evaluation inputs inputsD resultD) predictedInputsD =
414- beside inputBox (" " : " ───" : repeat " " ) resultBox
431+ displayCounterSpec unicode (Evaluation inputs inputsD resultD) predictedInputsD =
432+ sanitize unicode $
433+ beside inputBox (" " : threeDashes : repeat " " ) resultBox
415434 ++ (flip replicate ' ' $
416435 (2 `max` (subtract 2 $ (lineMax [inputString] `div` 2 ))))
417- ++ " 🡓 🡓 🡓 \n "
436+ ++ threeArrows
418437 ++ beside
419438 actualBox
420- (" " : " " : " ═╱═ " : repeat " " )
439+ (" " : " " : notEqual : repeat " " )
421440 predictedBox
422441 where
423- inputBox =
442+ threeDashes | unicode = " ───"
443+ | otherwise = " ---"
444+ threeArrows | unicode = " 🡓 🡓 🡓\n "
445+ | otherwise = " v v v\n "
446+ notEqual | unicode = " ═╱═ "
447+ | otherwise = " =/= "
448+ inputBox
449+ | unicode =
424450 box " ┌" ' ─' " ┐"
425451 " │" inputHeader " ├"
426452 " ├" ' ─' " ┤"
427453 " │" inputString " │"
428454 " └" ' ─' " ┘"
429-
430- resultBox =
455+ | otherwise =
456+ box " +" ' -' " +"
457+ " |" inputHeader " +"
458+ " +" ' -' " +"
459+ " |" inputString " |"
460+ " +" ' -' " +"
461+
462+ resultBox
463+ | unicode =
431464 box " ┌" ' ─' " ┐"
432465 " ┤" resultHeader " │"
433466 " ├" ' ─' " ┤"
434467 " │" resultString " │"
435468 " └" ' ─' " ┘"
436-
437- actualBox =
469+ | otherwise =
470+ box " +" ' -' " +"
471+ " +" resultHeader " |"
472+ " +" ' -' " +"
473+ " |" resultString " |"
474+ " +" ' -' " +"
475+
476+ actualBox
477+ | unicode =
438478 box " ┌" ' ─' " ┐"
439479 " │" actualHeader " │"
440480 " ├" ' ─' " ┤"
441481 " │" actualDemandString " │"
442482 " └" ' ─' " ┘"
443-
444- predictedBox =
483+ | otherwise =
484+ box " +" ' -' " +"
485+ " |" actualHeader " |"
486+ " +" ' -' " +"
487+ " |" actualDemandString " |"
488+ " +" ' -' " +"
489+
490+ predictedBox
491+ | unicode =
445492 box " ┌" ' ─' " ┐"
446493 " │" predictedHeader " │"
447494 " ├" ' ─' " ┤"
448495 " │" predictedDemandString " │"
449496 " └" ' ─' " ┘"
497+ | otherwise =
498+ box " +" ' -' " +"
499+ " |" predictedHeader " |"
500+ " +" ' -' " +"
501+ " |" predictedDemandString " |"
502+ " +" ' -' " +"
450503
451504 inputHeader = " Input" ++ plural
452505 resultHeader = " Demand on result"
@@ -511,4 +564,6 @@ displayCounterSpec (Evaluation inputs inputsD resultD) predictedInputsD =
511564 showNPWith' :: forall ys . All c ys => NP g ys -> String
512565 showNPWith' Nil = " "
513566 showNPWith' (y :* ys) =
514- " • " ++ display y ++ " \n " ++ showNPWith' ys
567+ bullet ++ display y ++ " \n " ++ showNPWith' ys
568+ bullet | unicode = " • "
569+ | otherwise = " * "
0 commit comments