packages feed

vty-ui-1.0: test/src/Tests/Tokenize.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}
module Tests.Tokenize where

import Data.Char ( isPrint )
import Control.Applicative ( (<$>), (<*>), pure )
import Test.QuickCheck

import Text.Trans.Tokenize

import Tests.Util

instance (Arbitrary a) => Arbitrary (Token a) where
    arbitrary = oneof [ Whitespace <$> ws <*> arbitrary
                      , Token <$> s <*> arbitrary
                      ]
        where
          ws = oneof [ pure " ", pure "\t" ]
          s = replicate <$> choose (1, 10) <*> pure 'a'

tokenGen :: Gen [[Token ()]]
tokenGen = listOf $ listOf arbitrary

lineGen :: Gen [Token ()]
lineGen = listOf1 arbitrary

stringGen :: Gen String
stringGen = listOf (arbitrary `suchThat` (\c -> isPrint c))

checkToken :: Token a -> Bool
checkToken (Whitespace s _) = all (`elem` " \t") s
checkToken (Token s _) = all (not . (`elem` " \t")) s

collapse :: [Token a] -> String
collapse = concat . map tokenString

tests :: [Property]
tests = [ label "tokenize: round trip test" $ property $ forAll tokenGen $
                    \ts -> serialize ts == (serialize $ tokenize (serialize ts) ())

        , label "tokenize: token contents consistent with constructors" $
                property $ forAll stringGen $
                    \s -> all (all checkToken) $ tokenize s undefined

        , label "tokenize: newlines handled properly" $ property $ forAll stringGen $
                    \s -> numNewlines s + 1 == (length $ tokenize s undefined)

        , label "tokenize: line truncation works" $ property $ forAll lineGen $
                    \ts -> forAll (arbitrary :: Gen (Positive Int)) $
                    \width -> let l = truncLine (fromIntegral width) ts
                              in length (collapse l) <= fromIntegral width

        -- wrapping: a single line wrapped should always result in
        -- lines that are no greater than the wrapping width, unless
        -- they have a single token.
        , label "tokenize: line-wrapping works" $ property $ forAll lineGen $
                    \ts -> forAll (choose (0, length ts + 10)) $
                    \width -> let ls = wrapLine w ts
                                  w = fromIntegral width
                                  f l = length (serialize [l]) <= w || length l == 1
                              in all f ls
        ]