css-parser-0.0.1: test/CssParser/Test/Arbitrary.hs
{-# OPTIONS_GHC -fconstraint-solver-iterations=24 #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
module CssParser.Test.Arbitrary
( module X
, pack
, module CssParser.Test.Arbitrary
)where
import Data.List qualified as L
import Data.HashSet ( fromList, member, HashSet )
import Data.Text (pack, tails, inits)
import Data.Text qualified as T
import CssParser.At.MediaQuery ( MediaType )
import CssParser.Prelude as X
import CssParser.Show ( CssShow(toCssText), CslNe(..), Embraced(..), SslNe(..) )
import Test.QuickCheck as X
import Test.QuickCheck.Gen as X
import Test.QuickCheck.Instances as X ()
import Test.QuickCheck.Arbitrary.Generic as X
enumDomain :: forall a. (Enum a, Bounded a) => [a]
enumDomain = enumFromTo (minBound @a) (maxBound @a)
arbitraryLetter :: Gen Char
arbitraryLetter = elements [ 'a' .. 'z' ]
arbitraryHex :: Gen Char
arbitraryHex = elements $ ['0' .. '9'] <> [ 'a' .. 'f' ] <> [ 'A' .. 'F' ]
arbitraryWord :: Gen Text
arbitraryWord = pack <$> listOf1 arbitraryLetter
keywords :: HashSet Text
keywords = fromList $! initL <> fmap toTxt (enumDomain @MediaType)
where
toTxt = toStrict . toCssText
initL =
T.words "not of or and only src false true from to url x y d r"
<>
T.words "cx cy rx ry is dir odd even open min max clamp calc"
arbitraryIdent :: Gen Text
arbitraryIdent = do
i <- arbitraryText fl nl
if i `member` keywords
then pure $ i <> "_"
else pure i
where
fl = ['a' .. 'z'] <> "_"
nl = fl <> ['-', '0' .. '9']
arbitraryText :: String -> String -> Gen Text
arbitraryText fl nl = do
fc <- elements fl
pack . (fc :) <$> listOf (elements nl)
shrinkText :: Text -> [Text]
shrinkText = liftA2 (zipWith (<>)) inits (tails . T.drop 1)
shrinkIdent :: Text -> [Text]
shrinkIdent t
| T.length t < 2 = []
| otherwise = L.filter isGood $ shrinkText t
where
isGood s = s `isMissing` keywords &&
(case T.uncons s of
Nothing -> False
Just (l, _) -> isLetter l || l == '_')
isMissing a b = not (a `member` b)
instance Arbitrary a => Arbitrary (Embraced a) where
arbitrary = Embraced <$> arbitrary
shrink (Embraced a) = Embraced <$> shrink a
instance Arbitrary a => Arbitrary (CslNe a) where
arbitrary = CslNe <$> arbitrary
shrink (CslNe a) = CslNe <$> shrink a
instance Arbitrary a => Arbitrary (SslNe a) where
arbitrary = SslNe <$> arbitrary
shrink (SslNe a) = SslNe <$> shrink a