packages feed

regexchar-0.9.0.14: src-test/Grecce/Test/QuickCheck/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.QuickCheck.RepeatableMetaChar(
-- * Constants
	results,
-- * Types
-- ** Data-types
--	RepeatableMetaChar(..),
-- ** Type-synonyms
--	Testable
) where

import qualified	Data.Maybe
import			Grecce.Test.QuickCheck.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 {
	deconstruct	:: RegExDot.Repeatable.Repeatable MetaChar.MetaChar
} deriving (Eq, Read, Show)

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

-- | The constant test-results for this data-type.
results :: IO [Test.QuickCheck.Result]
results	= sequence [
	Test.QuickCheck.quickCheckResult prop_consumptionProfile,
	Test.QuickCheck.quickCheckResult prop_io,
	Test.QuickCheck.quickCheckResult prop_isValid,
	Test.QuickCheck.quickCheckResult prop_starHeight,
	Test.QuickCheck.quickCheckResult prop_read
 ] 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

	prop_read :: String -> Test.QuickCheck.Property
	prop_read garbage	= Test.QuickCheck.label "prop_read" $ case (reads garbage :: [(RepeatableMetaChar, String)]) of
		[_]	-> True
		_	-> True	-- Unless the read-implementation throws an exception.