Cabal-2.4.0.0: tests/UnitTests/Distribution/SPDX.hs
{-# OPTIONS_GHC -fno-warn-orphans -fno-warn-deprecations #-}
module UnitTests.Distribution.SPDX (spdxTests) where
import Distribution.Compat.Prelude.Internal
import Prelude ()
import Distribution.SPDX
import Distribution.Parsec.Class (eitherParsec)
import Distribution.Pretty (prettyShow)
import Test.Tasty
import Test.Tasty.QuickCheck
spdxTests :: [TestTree]
spdxTests =
[ testProperty "LicenseId roundtrip" licenseIdRoundtrip
, testProperty "LicenseExceptionId roundtrip" licenseExceptionIdRoundtrip
, testProperty "LicenseRef roundtrip" licenseRefRoundtrip
, testProperty "SimpleLicenseExpression roundtrip" simpleLicenseExpressionRoundtrip
, testProperty "LicenseExpression roundtrip" licenseExpressionRoundtrip
, testProperty "isAcceptableLicense l = True" shouldAcceptProp
, testProperty "isAcceptableLicense l = False" shouldRejectProp
]
licenseIdRoundtrip :: LicenseId -> Property
licenseIdRoundtrip x =
counterexample (prettyShow x) $
Right x === eitherParsec (prettyShow x)
licenseExceptionIdRoundtrip :: LicenseExceptionId -> Property
licenseExceptionIdRoundtrip x =
counterexample (prettyShow x) $
Right x === eitherParsec (prettyShow x)
licenseRefRoundtrip :: LicenseRef -> Property
licenseRefRoundtrip x =
counterexample (prettyShow x) $
Right x === eitherParsec (prettyShow x)
simpleLicenseExpressionRoundtrip :: SimpleLicenseExpression -> Property
simpleLicenseExpressionRoundtrip x =
counterexample (prettyShow x) $
Right x === eitherParsec (prettyShow x)
licenseExpressionRoundtrip :: LicenseExpression -> Property
licenseExpressionRoundtrip x =
counterexample (prettyShow x) $
Right (reassoc x) === eitherParsec (prettyShow x)
-- Parser produces right biased trees of and/or expressions
reassoc :: LicenseExpression -> LicenseExpression
reassoc (EOr a b) = case reassoc a of
EOr x y -> EOr x (reassoc (EOr y b))
x -> EOr x (reassoc b)
reassoc (EAnd a b) = case reassoc a of
EAnd x y -> EAnd x (reassoc (EAnd y b))
x -> EAnd x (reassoc b)
reassoc l = l
-------------------------------------------------------------------------------
-- isAcceptableLicence
-------------------------------------------------------------------------------
shouldAccept :: [License]
shouldAccept = map License
[ simpleLicenseExpression GPL_2_0_only
, simpleLicenseExpression GPL_2_0_or_later
, simpleLicenseExpression BSD_2_Clause
, simpleLicenseExpression BSD_3_Clause
, simpleLicenseExpression MIT
, simpleLicenseExpression ISC
, simpleLicenseExpression MPL_2_0
, simpleLicenseExpression Apache_2_0
, simpleLicenseExpression CC0_1_0
, simpleLicenseExpression BSD_4_Clause `EOr` simpleLicenseExpression MIT
]
shouldReject :: [License]
shouldReject = map License
[ simpleLicenseExpression BSD_4_Clause
, simpleLicenseExpression BSD_4_Clause `EAnd` simpleLicenseExpression MIT
]
-- | A sketch of what Hackage could accept
--
-- * NONE is rejected
--
-- * "or later" syntax (+ postfix) is rejected
--
-- * "WITH exc" exceptions are rejected
--
-- * There should be a way to interpert license as (conjunction of)
-- OSI-accepted licenses or CC0
--
isAcceptableLicense :: License -> Bool
isAcceptableLicense NONE = False
isAcceptableLicense (License expr) = goExpr expr
where
goExpr (EAnd a b) = goExpr a && goExpr b
goExpr (EOr a b) = goExpr a || goExpr b
goExpr (ELicense _ (Just _)) = False -- Don't allow exceptions
goExpr (ELicense s Nothing) = goSimple s
goSimple (ELicenseRef _) = False -- don't allow referenced licenses
goSimple (ELicenseIdPlus _) = False -- don't allow + licenses (use GPL-3.0-or-later e.g.)
goSimple (ELicenseId CC0_1_0) = True -- CC0 isn't OSI approved, but we allow it as "PublicDomain", this is eg. PublicDomain in http://hackage.haskell.org/package/string-qq-0.0.2/src/LICENSE
goSimple (ELicenseId lid) = licenseIsOsiApproved lid -- allow only OSI approved licenses.
shouldAcceptProp :: Property
shouldAcceptProp = conjoin $
map (\l -> counterexample (prettyShow l) (isAcceptableLicense l)) shouldAccept
shouldRejectProp :: Property
shouldRejectProp = conjoin $
map (\l -> counterexample (prettyShow l) (not $ isAcceptableLicense l)) shouldReject
-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------
instance Arbitrary LicenseId where
arbitrary = elements $ licenseIdList LicenseListVersion_3_2
instance Arbitrary LicenseExceptionId where
arbitrary = elements $ licenseExceptionIdList LicenseListVersion_3_2
instance Arbitrary LicenseRef where
arbitrary = mkLicenseRef' <$> ids' <*> ids
where
ids = listOf1 $ elements $ ['a'..'z'] ++ ['A' .. 'Z'] ++ ['0'..'9'] ++ "_-"
ids' = oneof [ pure Nothing, Just <$> ids ]
instance Arbitrary SimpleLicenseExpression where
arbitrary = oneof
[ ELicenseId <$> arbitrary
, ELicenseIdPlus <$> arbitrary
, ELicenseRef <$> arbitrary
]
instance Arbitrary LicenseExpression where
arbitrary = sized arb
where
arb n
| n <= 0 = ELicense <$> arbitrary <*> pure Nothing
| otherwise = oneof
[ ELicense <$> arbitrary <*> arbitrary
, EAnd <$> arbA <*> arbB
, EOr <$> arbA <*> arbB
]
where
m = n `div` 2
arbA = arb m
arbB = arb (n - m)
shrink (EAnd a b) = a : b : map (uncurry EAnd) (shrink (a, b))
shrink (EOr a b) = a : b : map (uncurry EOr) (shrink (a, b))
shrink _ = []