regexchar-0.9.0.12: src/Grecce/Test/QC/RepeatableMetaChar.hs
{-
Copyright (C) 2010-2015 Dr. Alistair Ward
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-}
{- |
[@AUTHOR@] Dr. Alistair Ward
[@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines tests based on it.
-}
module Grecce.Test.QC.RepeatableMetaChar(
-- * Types
-- ** Data-types
-- RepeatableMetaChar,
-- ** Type-synonyms
-- Testable,
-- * Functions
-- deconstruct,
quickChecks
) where
import qualified Data.Maybe
import Grecce.Test.QC.MetaChar()
import qualified RegExChar.MetaChar as MetaChar
import qualified RegExDot.Consumer
import qualified RegExDot.ConsumptionBounds
import qualified RegExDot.ConsumptionProfile
import qualified RegExDot.Repeatable
import qualified Test.QuickCheck
import qualified ToolShed.SelfValidate
import qualified ToolShed.Test.ReversibleIO
-- | A specialised instance, required to instantiate 'Test.QuickCheck.Arbitrary'.
newtype RepeatableMetaChar = MkRepeatableMetaChar (RegExDot.Repeatable.Repeatable MetaChar.MetaChar) deriving (Eq, Read, Show)
-- | Accessor.
deconstruct :: RepeatableMetaChar -> RegExDot.Repeatable.Repeatable MetaChar.MetaChar
deconstruct (MkRepeatableMetaChar repeatableMetaChar) = repeatableMetaChar
instance ToolShed.SelfValidate.SelfValidator RepeatableMetaChar where
getErrors = ToolShed.SelfValidate.getErrors . deconstruct
instance RegExDot.Consumer.Consumer RepeatableMetaChar where
consumptionProfile = RegExDot.Consumer.consumptionProfile . deconstruct
starHeight = RegExDot.Consumer.starHeight . deconstruct
instance Test.QuickCheck.Arbitrary RepeatableMetaChar where
arbitrary = do
metaChar <- Test.QuickCheck.arbitrary
fewest <- Test.QuickCheck.elements [0 .. 9] -- Could be more, but this is an adequate test.
most <- Test.QuickCheck.oneof [return Nothing, Just `fmap` Test.QuickCheck.elements [max fewest 1 .. 9]]
isGreedy <- Test.QuickCheck.arbitrary
let
repetitionBounds :: RegExDot.Repeatable.RepetitionBounds
repetitionBounds = (fewest, most)
return {-to Gen-monad-} . MkRepeatableMetaChar $ RegExDot.Repeatable.MkRepeatable {
RegExDot.Repeatable.base = metaChar,
RegExDot.Repeatable.repetitionBounds = repetitionBounds,
RegExDot.Repeatable.isGreedy = RegExDot.Repeatable.hasPreciseBounds repetitionBounds || isGreedy -- Only specify 'non-greedy' where space exists.
}
type Testable = RepeatableMetaChar -> Test.QuickCheck.Property
-- | Defines invariant properties, which must hold for any 'RepeatableMetaChar'.
quickChecks :: (Testable -> IO ()) -> IO ()
quickChecks checker = checker `mapM_` [prop_consumptionProfile, prop_io, prop_isValid, prop_starHeight] where
prop_consumptionProfile, prop_io, prop_isValid, prop_starHeight :: Testable
prop_consumptionProfile r = Test.QuickCheck.label "prop_consumptionProfile" $ Data.Maybe.maybe True (>= minData) maybeMaxData && b == RegExDot.Consumer.getHasSpecificRequirement (RegExDot.Repeatable.base $ deconstruct r) where RegExDot.ConsumptionProfile.MkConsumptionProfile {
RegExDot.ConsumptionProfile.consumptionBounds = (minData, maybeMaxData),
RegExDot.ConsumptionProfile.hasSpecificRequirement = b
} = RegExDot.Consumer.consumptionProfile r
prop_io (MkRepeatableMetaChar r) = Test.QuickCheck.label "prop_io" $ ToolShed.Test.ReversibleIO.isReversible r
prop_isValid r = Test.QuickCheck.label "prop_isValid" $ ToolShed.SelfValidate.isValid r
prop_starHeight (MkRepeatableMetaChar r) = Test.QuickCheck.label "prop_starHeight" $ RegExDot.Consumer.starHeight r == if RegExDot.ConsumptionBounds.isPrecise (RegExDot.Consumer.getConsumptionBounds r) then 0 else 1