{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE UnicodeSyntax #-} module Test.Tag (tests) where import Data.Function (on) import Test.Tasty (TestTree, testGroup) import Test.Tasty.QuickCheck (testProperty) import Test.QuickCheck import Test.QuickCheck.Instances.Text () import Plugin.GhcTags.Tag import Test.Tag.Generators tests :: TestTree tests = testGroup "Tag" [ testProperty "Ord:antisymmetry" ordAntiSymmetryProp , testProperty "Ord:reflexivity" (on ordReflexivityyProp getArbOrdTag) , testProperty "Ord:transitivity" (\a b c -> ordTransitiveProp (getArbOrdTag a) (getArbOrdTag b) (getArbOrdTag c)) , testProperty "Ord:Eq:consistency" (weakConsistency . getArbOrdTag) ] -- | Arbitrary instance with a high probability of gettings the same tags or files. newtype ArbOrdTag = ArbOrdTag { getArbOrdTag :: Tag } deriving Show instance Arbitrary ArbOrdTag where arbitrary = fmap ArbOrdTag $ Tag <$> elements (TagName `map` [ "find" , "Ord" , "Eq" , "hPut" ]) <*> genTagKind <*> elements (TagFile `map` [ "Main.hs" , "Lib.hs" ]) <*> frequency [ (8, Left . getPositive <$> arbitrary) , (1, Right . (wrap '/' . fixAddr) <$> genTextNonEmpty) , (1, Right . (wrap '?' . fixAddr) <$> genTextNonEmpty) ] <*> pure [] -- | Generate pairs of tags which are equal in the sense of `compare`. -- data EqTags = EqTags Tag Tag deriving Show instance Arbitrary EqTags where arbitrary = do x <- getArbOrdTag <$> arbitrary fieldsA <- listOf genField fieldsB <- listOf genField pure $ EqTags x { tagFields = fieldsA } x { tagFields = fieldsB } -- | Note that this property is weaker than required. There are unequal `Tag`s -- in the sense of `==`, which are considered equal by `compare`. -- ordAntiSymmetryProp :: EqTags -> Bool ordAntiSymmetryProp (EqTags a b) = a `compareTags` b == EQ -- We don't provide 'Ord' instance, since it's not compatible with 'compare', -- see 'weakConsistency'. -- (≤), (≥) :: Tag -> Tag -> Bool a ≤ b = a `compareTags` b /= GT a ≥ b = a `compareTags` b /= LT ordReflexivityyProp :: Tag -> Tag -> Bool ordReflexivityyProp a b = a ≤ b || a ≥ b ordTransitiveProp :: Tag -> Tag -> Tag -> Property ordTransitiveProp a b c = a ≤ b && b ≤ c || a ≥ b && b ≥ c ==> if | a ≤ b && b ≤ c -> a ≤ c | a ≥ b && b ≥ c -> a ≥ c | otherwise -> error "impossible happened" where -- | The -- -- prop> a == b ==> a `compare` b == EQ` -- -- But since 'Tag' is using derived 'Eq' instance, it is equivalent to weakConsistency :: Tag -> Bool weakConsistency a = a `compareTags` a == EQ