{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module UnitTests.Distribution.Client.ArbitraryInstances ( adjustSize, shortListOf, shortListOf1, arbitraryFlag, ShortToken(..), arbitraryShortToken, NonMEmpty(..), NoShrink(..), ) where import Data.Char import Data.List #if !MIN_VERSION_base(4,8,0) import Data.Monoid import Control.Applicative #endif import Control.Monad import Distribution.Version import Distribution.Types.VersionRange.Internal import Distribution.Types.Dependency import Distribution.Types.PackageVersionConstraint import Distribution.Types.UnqualComponentName import Distribution.Types.LibraryName import Distribution.Package import Distribution.System import Distribution.Verbosity import Distribution.Simple.Setup import Distribution.Simple.InstallDirs import Distribution.Utils.NubList import Distribution.Client.Types import Distribution.Client.IndexUtils.Timestamp import Test.QuickCheck adjustSize :: (Int -> Int) -> Gen a -> Gen a adjustSize adjust gen = sized (\n -> resize (adjust n) gen) shortListOf :: Int -> Gen a -> Gen [a] shortListOf bound gen = sized $ \n -> do k <- choose (0, (n `div` 2) `min` bound) vectorOf k gen shortListOf1 :: Int -> Gen a -> Gen [a] shortListOf1 bound gen = sized $ \n -> do k <- choose (1, 1 `max` ((n `div` 2) `min` bound)) vectorOf k gen newtype ShortToken = ShortToken { getShortToken :: String } deriving Show instance Arbitrary ShortToken where arbitrary = ShortToken <$> (shortListOf1 5 (choose ('#', '~')) `suchThat` (not . ("[]" `isPrefixOf`))) --TODO: [code cleanup] need to replace parseHaskellString impl to stop -- accepting Haskell list syntax [], ['a'] etc, just allow String syntax. -- Workaround, don't generate [] as this does not round trip. shrink (ShortToken cs) = [ ShortToken cs' | cs' <- shrink cs, not (null cs') ] arbitraryShortToken :: Gen String arbitraryShortToken = getShortToken <$> arbitrary instance Arbitrary Version where arbitrary = do branch <- shortListOf1 4 $ frequency [(3, return 0) ,(3, return 1) ,(2, return 2) ,(1, return 3)] return (mkVersion branch) where shrink ver = [ mkVersion branch' | branch' <- shrink (versionNumbers ver) , not (null branch') ] instance Arbitrary VersionRange where arbitrary = canonicaliseVersionRange <$> sized verRangeExp where verRangeExp n = frequency $ [ (2, return anyVersion) , (1, liftM thisVersion arbitrary) , (1, liftM laterVersion arbitrary) , (1, liftM orLaterVersion arbitrary) , (1, liftM orLaterVersion' arbitrary) , (1, liftM earlierVersion arbitrary) , (1, liftM orEarlierVersion arbitrary) , (1, liftM orEarlierVersion' arbitrary) , (1, liftM withinVersion arbitrary) , (2, liftM VersionRangeParens arbitrary) ] ++ if n == 0 then [] else [ (2, liftM2 unionVersionRanges verRangeExp2 verRangeExp2) , (2, liftM2 intersectVersionRanges verRangeExp2 verRangeExp2) ] where verRangeExp2 = verRangeExp (n `div` 2) orLaterVersion' v = unionVersionRanges (laterVersion v) (thisVersion v) orEarlierVersion' v = unionVersionRanges (earlierVersion v) (thisVersion v) canonicaliseVersionRange = fromVersionIntervals . toVersionIntervals instance Arbitrary PackageName where arbitrary = mkPackageName . intercalate "-" <$> shortListOf1 2 nameComponent where nameComponent = shortListOf1 5 (elements packageChars) `suchThat` (not . all isDigit) packageChars = filter isAlphaNum ['\0'..'\127'] instance Arbitrary Dependency where arbitrary = Dependency <$> arbitrary <*> arbitrary <*> fmap getNonMEmpty arbitrary instance Arbitrary PackageVersionConstraint where arbitrary = PackageVersionConstraint <$> arbitrary <*> arbitrary instance Arbitrary UnqualComponentName where -- same rules as package names arbitrary = packageNameToUnqualComponentName <$> arbitrary instance Arbitrary LibraryName where arbitrary = elements =<< sequenceA [ LSubLibName <$> arbitrary , pure LMainLibName ] instance Arbitrary OS where arbitrary = elements knownOSs instance Arbitrary Arch where arbitrary = elements knownArches instance Arbitrary Platform where arbitrary = Platform <$> arbitrary <*> arbitrary instance Arbitrary a => Arbitrary (Flag a) where arbitrary = arbitraryFlag arbitrary shrink NoFlag = [] shrink (Flag x) = NoFlag : [ Flag x' | x' <- shrink x ] arbitraryFlag :: Gen a -> Gen (Flag a) arbitraryFlag genA = sized $ \sz -> case sz of 0 -> pure NoFlag _ -> frequency [ (1, pure NoFlag) , (3, Flag <$> genA) ] instance (Arbitrary a, Ord a) => Arbitrary (NubList a) where arbitrary = toNubList <$> arbitrary shrink xs = [ toNubList [] | (not . null) (fromNubList xs) ] -- try empty, otherwise don't shrink as it can loop instance Arbitrary Verbosity where arbitrary = elements [minBound..maxBound] instance Arbitrary PathTemplate where arbitrary = toPathTemplate <$> arbitraryShortToken shrink t = [ toPathTemplate s | s <- shrink (fromPathTemplate t) , not (null s) ] newtype NonMEmpty a = NonMEmpty { getNonMEmpty :: a } deriving (Eq, Ord, Show) instance (Arbitrary a, Monoid a, Eq a) => Arbitrary (NonMEmpty a) where arbitrary = NonMEmpty <$> (arbitrary `suchThat` (/= mempty)) shrink (NonMEmpty x) = [ NonMEmpty x' | x' <- shrink x, x' /= mempty ] newtype NoShrink a = NoShrink { getNoShrink :: a } deriving (Eq, Ord, Show) instance Arbitrary a => Arbitrary (NoShrink a) where arbitrary = NoShrink <$> arbitrary shrink _ = [] instance Arbitrary Timestamp where arbitrary = (maybe (toEnum 0) id . epochTimeToTimestamp) <$> arbitrary instance Arbitrary IndexState where arbitrary = frequency [ (1, pure IndexStateHead) , (50, IndexStateTime <$> arbitrary) ] instance Arbitrary WriteGhcEnvironmentFilesPolicy where arbitrary = arbitraryBoundedEnum