diff --git a/.gitignore b/.gitignore index 780dce2..951e399 100644 --- a/.gitignore +++ b/.gitignore @@ -52,9 +52,16 @@ Icon .VolumeIcon.icns .com.apple.timemachine.donotpresent + # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk + + +# Coveralls + +/shc +/shc-* diff --git a/.travis.yml b/.travis.yml index a229c2f..c14c608 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,58 +36,38 @@ matrix: # We grab the appropriate GHC and cabal-install versions from hvr's PPA. See: # https://github.com/hvr/multi-ghc-travis - # - env: BUILD=cabal GHCVER=7.6.3 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7 - # compiler: ": #GHC 7.6.3" - # addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - env: BUILD=cabal GHCVER=7.8.4 CABALVER=1.18 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 7.8.4" - addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 7.10.3" - addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - env: BUILD=cabal GHCVER=8.0.1 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7 - compiler: ": #GHC 8.0.1" - addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - - # Build with the newest GHC and cabal-install. This is an accepted failure, - # see below. - # - env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7 - # compiler: ": #GHC HEAD" - # addons: {apt: {packages: [cabal-install-head,ghc-head,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - # The Stack builds. We can pass in arbitrary Stack arguments via the ARGS + # For the Stack builds we can pass in arbitrary Stack arguments via the ARGS # variable, such as using --stack-yaml to point to a different file. - # - env: BUILD=stack ARGS="" - # compiler: ": #stack default" - # addons: {apt: {packages: [libgmp-dev]}} - - - env: BUILD=stack GHCVER=7.8.4 STACK_YAML=stack-7.8.yaml - compiler: ": #stack 7.8.4" - addons: {apt: {packages: [libgmp-dev]}} + # Linux/stack - env: BUILD=stack GHCVER=7.10.3 STACK_YAML=stack-7.10.yaml compiler: ": #stack 7.10.3" addons: {apt: {packages: [libgmp-dev]}} + - env: BUILD=stack GHCVER=7.8.4 STACK_YAML=stack-7.8.yaml + compiler: ": #stack 7.8.4" + addons: {apt: {packages: [libgmp-dev]}} + - env: BUILD=stack GHCVER=8.0.1 STACK_YAML=stack-8.0.yaml compiler: ": #stack 8.0.1" addons: {apt: {packages: [libgmp-dev]}} - # Nightly builds are allowed to fail - # - env: BUILD=stack ARGS="--resolver nightly" - # compiler: ": #stack nightly" - # addons: {apt: {packages: [libgmp-dev]}} + # Linux/cabal + + - env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 7.10.3" + addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + - env: BUILD=cabal GHCVER=7.8.4 CABALVER=1.18 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 7.8.4" + addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + - env: BUILD=cabal GHCVER=8.0.1 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 8.0.1" + addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} - # Build on macOS in addition to Linux - # - env: BUILD=stack ARGS="" - # compiler: ": #stack default osx" - # os: osx - # Travis includes an macOS which is incompatible with GHC 7.8.4 - #- env: BUILD=stack ARGS="--resolver lts-2" - # compiler: ": #stack 7.8.4 osx" - # os: osx + # macOS (stack) - env: BUILD=stack STACK_YAML=stack-7.10.yaml compiler: ": #stack 7.10.3 osx" @@ -97,14 +77,11 @@ matrix: compiler: ": #stack 8.0.1 osx" os: osx - # - env: BUILD=stack ARGS="--resolver nightly" - # compiler: ": #stack nightly osx" - # os: osx - allow_failures: - env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7 - env: BUILD=stack ARGS="--resolver nightly" + before_install: # Using compiler above sets CC to an invalid value, so unset it - unset CC @@ -183,6 +160,8 @@ script: ;; esac set +ex + after_script: - travis_retry curl -L https://github.com/rubik/stack-hpc-coveralls/releases/download/v0.0.4.0/shc-linux-x64-$GHCVER.tar.bz2 | tar -xj - - ./shc regex re-tests + - | + [ "$BUILD" == stack -a "$GHCVER" == 7.10.3 ] && ./shc --partial-coverage regex re-gen-modules-test re-include-test re-nginx-log-processor-test re-pp-test re-tests re-tutorial-test diff --git a/README.md b/README.md index 4f2f621..1b05bf5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Hackage](https://img.shields.io/hackage/v/regex.svg)](https://hackage.haskell.org/package/regex) [![BSD3 License](http://img.shields.io/badge/license-BSD3-brightgreen.svg)](https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29) -[![Un*x build](https://img.shields.io/travis/iconnect/regex.svg?label=Linux%2FmacOS)](https://hackage.haskell.org/package/regex) +[![Un*x build](https://img.shields.io/travis/iconnect/regex.svg?label=Linux%2FmacOS)](https://travis-ci.org/iconnect/regex) [![Windows build](https://img.shields.io/appveyor/ci/engineerirngirisconnectcouk/regex.svg?label=Windows)](https://ci.appveyor.com/project/engineerirngirisconnectcouk/regex/branch/master) [![Coverage](https://img.shields.io/coveralls/iconnect/regex.svg)](https://coveralls.io/github/iconnect/regex?branch=master) diff --git a/Text/RE/Internal/PreludeMacros.hs b/Text/RE/Internal/PreludeMacros.hs index f6a0adb..de8ecd7 100644 --- a/Text/RE/Internal/PreludeMacros.hs +++ b/Text/RE/Internal/PreludeMacros.hs @@ -8,6 +8,7 @@ module Text.RE.Internal.PreludeMacros , MacroDescriptor(..) , RegexSource(..) , PreludeMacro(..) + , presentPreludeMacro , preludeMacros , preludeMacroTable , preludeMacroSummary @@ -142,7 +143,7 @@ natural_macro rty env pm = Just $ run_tests rty parseInteger samples env pm { _md_source = "[0-9]+" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseInteger" , _md_description = "a string of one or more decimal digits" } @@ -170,7 +171,7 @@ natural_hex_macro rty env pm = Just $ run_tests rty parseHex samples env pm { _md_source = "[0-9a-fA-F]+" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseHex" , _md_description = "a string of one or more hexadecimal digits" } @@ -198,7 +199,7 @@ integer_macro rty env pm = Just $ run_tests rty parseInteger samples env pm { _md_source = "-?[0-9]+" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseInteger" , _md_description = "a decimal integer" } @@ -226,7 +227,7 @@ decimal_macro rty env pm = Just $ run_tests rty parseDouble samples env pm { _md_source = "-?[0-9]+(?:\\.[0-9]+)?" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseInteger" , _md_description = "a decimal integer" } @@ -267,7 +268,7 @@ string_macro rty@TDFA env pm = { _md_source = "\"(?:[^\"\\]+|\\\\[\\\"])*\"" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseString" , _md_description = "a double-quote string, with simple \\ escapes for \\s and \"s" } @@ -298,7 +299,7 @@ string_simple_macro rty env pm = { _md_source = "\"[^\"[:cntrl:]]*\"" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseSimpleString" , _md_description = "a decimal integer" } @@ -331,7 +332,7 @@ id_macro rty env pm = { _md_source = "_*[a-zA-Z][a-zA-Z0-9_]*" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Nothing , _md_description = "a standard C-style alphanumeric identifier (with _s)" } @@ -369,7 +370,7 @@ id'_macro rty env pm = { _md_source = "_*[a-zA-Z][a-zA-Z0-9_']*" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Nothing , _md_description = "a standard Haskell-style alphanumeric identifier (with '_'s and '''s)" } @@ -410,7 +411,7 @@ date_macro rty env pm = { _md_source = "[0-9]{4}-[0-9]{2}-[0-9]{2}" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseDate" , _md_description = "a YYYY-MM-DD format date" } @@ -442,7 +443,7 @@ date_slashes_macro rty env pm = { _md_source = "[0-9]{4}/[0-9]{2}/[0-9]{2}" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseSlashesDate" , _md_description = "a YYYY/MM/DD format date" } @@ -474,7 +475,7 @@ time_macro rty env pm = { _md_source = "[0-9]{2}:[0-9]{2}:[0-9]{2}(?:[.][0-9]+)?" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseTimeOfDay" , _md_description = "a HH:MM:SS[.Q+]" } @@ -507,7 +508,7 @@ timezone_macro rty env pm = { _md_source = "(?:Z|[+-][0-9]{2}:?[0-9]{2})" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseTimeZone" , _md_description = "an IOS-8601 TZ specification" } @@ -538,7 +539,7 @@ datetime_macro rty env pm = Just $ run_tests rty parseDateTime samples env pm { _md_source = "@{%date}[ T]@{%time}(?:@{%timezone}| UTC)?" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseDateTime" , _md_description = "ISO-8601 format date and time + simple variants" } @@ -572,7 +573,7 @@ datetime_8601_macro rty env pm = { _md_source = "@{%date}T@{%time}@{%timezone}" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseDateTime8601" , _md_description = "YYYY-MM-DDTHH:MM:SS[.Q*](Z|[+-]HHMM) format date and time" } @@ -599,7 +600,7 @@ datetime_clf_macro rty env pm = { _md_source = re , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseDateTimeCLF" , _md_description = "Common Log Format date+time: %d/%b/%Y:%H:%M:%S %z" } @@ -638,7 +639,7 @@ shortmonth_macro rty env pm = intercalate "|" $ elems shortMonthArray , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseShortMonth" , _md_description = "three letter month name: Jan-Dec" } @@ -671,7 +672,7 @@ address_ipv4_macros rty env pm = { _md_source = "[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseSeverity" , _md_description = "an a.b.c.d IPv4 address" } @@ -707,7 +708,7 @@ syslog_severity_macro rty env pm = { _md_source = re , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Just "parseSeverity" , _md_description = "syslog severity keyword (debug-emerg)" } @@ -764,7 +765,7 @@ email_simple_macro rty env pm = { _md_source = "[a-zA-Z0-9%_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9.-]+" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Nothing , _md_description = "an email address" } @@ -793,7 +794,7 @@ url_macro rty env pm = { _md_source = "([hH][tT][tT][pP][sS]?|[fF][tT][pP])://[^[:space:]/$.?#].[^[:space:]]*" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = test_stub pm + , _md_test_results = [] , _md_parser = Nothing , _md_description = "a URL" } @@ -829,10 +830,6 @@ url_macro rty env pm = , "http://##/" ] -test_stub :: PreludeMacro -> [TestResult] -test_stub pm = - error $ "test_stub: tests missing: " ++ presentPreludeMacro pm - run_tests :: (Eq a,Show a) => RegexType -> (String->Maybe a) diff --git a/Text/RE/Internal/QQ.hs b/Text/RE/Internal/QQ.hs index b502e0f..5d43193 100644 --- a/Text/RE/Internal/QQ.hs +++ b/Text/RE/Internal/QQ.hs @@ -1,21 +1,26 @@ +{-# LANGUAGE DeriveDataTypeable #-} + module Text.RE.Internal.QQ where +import Control.Exception +import Data.Typeable import Language.Haskell.TH.Quote +data QQFailure = + QQFailure + { _qqf_context :: String + , _qqf_component :: String + } + deriving (Show,Typeable) + +instance Exception QQFailure where + qq0 :: String -> QuasiQuoter -qq0 nm = +qq0 ctx = QuasiQuoter - { quoteExp = const $ error $ oops "an expression" - , quotePat = const $ error $ oops "a pattern" - , quoteType = const $ error $ oops "a type" - , quoteDec = const $ error $ oops "a declaration" + { quoteExp = const $ throw $ QQFailure ctx "expression" + , quotePat = const $ throw $ QQFailure ctx "pattern" + , quoteType = const $ throw $ QQFailure ctx "type" + , quoteDec = const $ throw $ QQFailure ctx "declaration" } - where - oops sc = unwords - [ "`" - , nm - , "` QuasiQuoter has been used in" - , sc - , "context but it should be used in an expresion context." - ] diff --git a/Text/RE/Options.lhs b/Text/RE/Options.lhs index 3da69fd..2923177 100644 --- a/Text/RE/Options.lhs +++ b/Text/RE/Options.lhs @@ -17,10 +17,10 @@ import Language.Haskell.TH.Syntax \begin{code} data Options_ r c e = Options - { _options_mode :: Mode - , _options_macs :: Macros r - , _options_comp :: c - , _options_exec :: e + { _options_mode :: !Mode + , _options_macs :: !(Macros r) + , _options_comp :: !c + , _options_exec :: !e } deriving (Show) \end{code} diff --git a/Text/RE/PCRE/RE.hs b/Text/RE/PCRE/RE.hs index 242569e..7f63094 100644 --- a/Text/RE/PCRE/RE.hs +++ b/Text/RE/PCRE/RE.hs @@ -79,10 +79,10 @@ regexType = PCRE data RE = RE - { _re_options :: Options - , _re_source :: String - , _re_cnames :: CaptureNames - , _re_regex :: Regex + { _re_options :: !Options + , _re_source :: !String + , _re_cnames :: !CaptureNames + , _re_regex :: !Regex } reOptions :: RE -> Options @@ -178,8 +178,6 @@ compileRegex_ os re_s = uncurry mk <$> compileRegex' os re_s , _re_regex = rex } - Options{..} = os - re' :: Maybe SimpleRegexOptions -> QuasiQuoter re' mb = case mb of Nothing -> diff --git a/Text/RE/TDFA/RE.hs b/Text/RE/TDFA/RE.hs index c04c48b..2f3076f 100644 --- a/Text/RE/TDFA/RE.hs +++ b/Text/RE/TDFA/RE.hs @@ -78,10 +78,10 @@ regexType = TDFA data RE = RE - { _re_options :: Options - , _re_source :: String - , _re_cnames :: CaptureNames - , _re_regex :: Regex + { _re_options :: !Options + , _re_source :: !String + , _re_cnames :: !CaptureNames + , _re_regex :: !Regex } reOptions :: RE -> Options @@ -174,8 +174,6 @@ compileRegex_ os re_s = uncurry mk <$> compileRegex' os re_s , _re_regex = rx } - Options{..} = os - re' :: Maybe SimpleRegexOptions -> QuasiQuoter re' mb = case mb of Nothing -> diff --git a/Text/RE/TestBench.lhs b/Text/RE/TestBench.lhs index d8fd9fd..7c84b80 100644 --- a/Text/RE/TestBench.lhs +++ b/Text/RE/TestBench.lhs @@ -23,7 +23,7 @@ module Text.RE.TestBench , formatMacroSources , formatMacroSource , testMacroDescriptors - , regexSource +-- , regexSource ) where import Data.Array @@ -49,7 +49,7 @@ Types data RegexType = TDFA -- the TDFA back end | PCRE -- the PCRE back end - deriving (Eq,Ord,Show) + deriving (Bounded,Enum,Eq,Ord,Show) -- | do we need the captures in the RE or whould they be stripped out -- where possible @@ -66,12 +66,12 @@ type MacroEnv = HML.HashMap MacroID MacroDescriptor -- description data MacroDescriptor = MacroDescriptor - { _md_source :: RegexSource -- ^ the RE - , _md_samples :: [String] -- ^ some sample matches - , _md_counter_samples :: [String] -- ^ some sample non-matches - , _md_test_results :: [TestResult] -- ^ validation test results - , _md_parser :: Maybe FunctionID -- ^ WA, the parser function - , _md_description :: String -- ^ summary comment + { _md_source :: !RegexSource -- ^ the RE + , _md_samples :: ![String] -- ^ some sample matches + , _md_counter_samples :: ![String] -- ^ some sample non-matches + , _md_test_results :: ![TestResult] -- ^ validation test results + , _md_parser :: !(Maybe FunctionID) -- ^ WA, the parser function + , _md_description :: !String -- ^ summary comment } deriving (Show) diff --git a/docs/index.md b/docs/index.md index c25b4c4..2c52836 100644 --- a/docs/index.md +++ b/docs/index.md @@ -50,7 +50,7 @@ Loading up the Tutorial into ghci ```bash cabal unpack regex cd regex-* -cabal configure --enable-tests +cabal configure cabal repl examples/re-tutorial ``` diff --git a/examples/re-nginx-log-processor.lhs b/examples/re-nginx-log-processor.lhs index 66edaad..d59ff6f 100644 --- a/examples/re-nginx-log-processor.lhs +++ b/examples/re-nginx-log-processor.lhs @@ -298,7 +298,7 @@ user_macro env mid = { _md_source = "(?:-|[^[:space:]]+)" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = def_test_results + , _md_test_results = [] , _md_parser = Just "parse_user" , _md_description = "a user ident (per RFC1413)" } @@ -321,7 +321,7 @@ pid_tid_macro env mid = { _md_source = "(?:@{%natural})#(?:@{%natural}):" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = def_test_results + , _md_test_results = [] , _md_parser = Just "parse_pid_tid" , _md_description = "#:" } @@ -346,7 +346,7 @@ access_macro env mid = { _md_source = access_re , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = def_test_results + , _md_test_results = [] , _md_parser = Just "parse_a" , _md_description = "an Nginx access log file line" } @@ -379,7 +379,7 @@ access_deg_macro env mid = { _md_source = " - \\[\\] \"\" \"\" \"\" \"\"" , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = def_test_results + , _md_test_results = [] , _md_parser = Nothing , _md_description = "a degenerate Nginx access log file line" } @@ -401,7 +401,7 @@ error_macro env mid = { _md_source = error_re , _md_samples = map fst samples , _md_counter_samples = counter_samples - , _md_test_results = def_test_results + , _md_test_results = [] , _md_parser = Just "parse_e" , _md_description = "an Nginx error log file line" } @@ -430,9 +430,6 @@ error_macro env mid = [ "" , "foo" ] - -def_test_results :: [TestResult] -def_test_results = error "def_test_results" \end{code} \begin{code} diff --git a/examples/re-tests.lhs b/examples/re-tests.lhs index 5b68d42..7d72741 100644 --- a/examples/re-tests.lhs +++ b/examples/re-tests.lhs @@ -2,28 +2,46 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE TemplateHaskell #-} module Main (main) where import Control.Applicative +import Control.Exception import Data.Array import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as LBS -import Data.Foldable +import qualified Data.Foldable as F +import Data.Maybe import Data.Monoid import qualified Data.Sequence as S import Data.String import qualified Data.Text as T import qualified Data.Text.Lazy as LT +import Language.Haskell.TH.Quote import Test.Tasty import Test.Tasty.HUnit +import qualified Text.Regex.PCRE as PCRE_ +import qualified Text.Regex.TDFA as TDFA_ import Text.RE import Text.RE.Internal.NamedCaptures -import qualified Text.RE.PCRE as PCRE -import Text.RE.TDFA as TDFA +import Text.RE.Internal.PreludeMacros +import Text.RE.Internal.QQ +import qualified Text.RE.PCRE as PCRE +import Text.RE.TDFA as TDFA import Text.RE.TestBench -import Text.RE.TDFA.String() +import qualified Text.RE.PCRE.String as P_ST +import qualified Text.RE.PCRE.ByteString as P_BS +import qualified Text.RE.PCRE.ByteString.Lazy as PLBS +import qualified Text.RE.PCRE.Sequence as P_SQ + +import qualified Text.RE.TDFA.String as T_ST +import qualified Text.RE.TDFA.ByteString as T_BS +import qualified Text.RE.TDFA.ByteString.Lazy as TLBS +import qualified Text.RE.TDFA.Sequence as T_SQ +import qualified Text.RE.TDFA.Text as T_TX +import qualified Text.RE.TDFA.Text.Lazy as TLTX main :: IO () @@ -35,6 +53,8 @@ main = defaultMain $ , replace_tests , options_tests , namedCapturesTestTree + , many_tests + , misc_tests ] prelude_tests :: TestTree @@ -199,7 +219,7 @@ replace_tests = testGroup "Replace" let ms = S.fromList str =~ regex_ :: Matches (S.Seq Char) f = \_ (Location i j) Capture{..} -> Just $ S.fromList $ "(" <> show i <> ":" <> show_co j <> ":" <> - toList capturedText <> ")" + F.toList capturedText <> ")" r = replaceAllCaptures' ALL f ms assertEqual "replaceAllCaptures'" r $ S.fromList "(0:0:(0:1:a) (0:2:bbbb)) (1:0:(1:1:aa) (1:2:b))" @@ -254,4 +274,168 @@ options_tests = testGroup "Simple Options" ] where s = "0a\nbb\nFe\nA5" :: String + +many_tests :: TestTree +many_tests = testGroup "Many Tests" + [ testCase "PCRE a" $ test (PCRE.*=~) (PCRE.?=~) (PCRE.=~) (PCRE.=~~) matchOnce matchMany id re_pcre + , testCase "PCRE ByteString" $ test (P_BS.*=~) (P_BS.?=~) (P_BS.=~) (P_BS.=~~) matchOnce matchMany B.pack re_pcre + , testCase "PCRE ByteString.Lazy" $ test (PLBS.*=~) (PLBS.?=~) (PLBS.=~) (PLBS.=~~) matchOnce matchMany LBS.pack re_pcre + , testCase "PCRE Sequence" $ test (P_SQ.*=~) (P_SQ.?=~) (P_SQ.=~) (P_SQ.=~~) matchOnce matchMany S.fromList re_pcre + , testCase "PCRE String" $ test (P_ST.*=~) (P_ST.?=~) (P_ST.=~) (P_ST.=~~) matchOnce matchMany id re_pcre + , testCase "TDFA a" $ test (TDFA.*=~) (TDFA.?=~) (TDFA.=~) (TDFA.=~~) matchOnce matchMany id re_tdfa + , testCase "TDFA ByteString" $ test (T_BS.*=~) (T_BS.?=~) (T_BS.=~) (T_BS.=~~) matchOnce matchMany B.pack re_tdfa + , testCase "TDFA ByteString.Lazy" $ test (TLBS.*=~) (TLBS.?=~) (TLBS.=~) (TLBS.=~~) matchOnce matchMany LBS.pack re_tdfa + , testCase "TDFA Sequence" $ test (T_SQ.*=~) (T_SQ.?=~) (T_SQ.=~) (T_SQ.=~~) matchOnce matchMany S.fromList re_tdfa + , testCase "TDFA String" $ test (T_ST.*=~) (T_ST.?=~) (T_ST.=~) (T_ST.=~~) matchOnce matchMany id re_tdfa + , testCase "TDFA Text" $ test (T_TX.*=~) (T_TX.?=~) (T_TX.=~) (T_TX.=~~) matchOnce matchMany T.pack re_tdfa + , testCase "TDFA Text.Lazy" $ test (TLTX.*=~) (TLTX.?=~) (TLTX.=~) (TLTX.=~~) matchOnce matchMany LT.pack re_tdfa + ] + where + test :: (Show s,Eq s) + => (s->r->Matches s) + -> (s->r->Match s) + -> (s->r->Matches s) + -> (s->r->Maybe(Match s)) + -> (r->s->Match s) + -> (r->s->Matches s) + -> (String->s) + -> r + -> Assertion + test (%*=~) (%?=~) (%=~) (%=~~) mo mm inj r = do + 2 @=? countMatches mtchs + Just txt' @=? matchedText mtch + mtchs @=? mtchs' + mb_mtch @=? Just mtch + mtch @=? mtch'' + mtchs @=? mtchs'' + where + mtchs = txt %*=~ r + mtch = txt %?=~ r + mtchs' = txt %=~ r + mb_mtch = txt %=~~ r + mtch'' = mo r txt + mtchs'' = mm r txt + + txt = inj "2016-01-09 2015-12-5 2015-10-05" + txt' = inj "2016-01-09" + + re_pcre = fromMaybe oops $ PCRE.compileRegex () "[0-9]{4}-[0-9]{2}-[0-9]{2}" + re_tdfa = fromMaybe oops $ TDFA.compileRegex () "[0-9]{4}-[0-9]{2}-[0-9]{2}" + + oops = error "many_tests" + +misc_tests :: TestTree +misc_tests = testGroup "Miscelaneous Tests" + [ testGroup "QQ" + [ qq_tc "expression" quoteExp + , qq_tc "pattern" quotePat + , qq_tc "type" quoteType + , qq_tc "declaration" quoteDec + ] + , testGroup "PreludeMacros" + [ valid_string "preludeMacroTable" preludeMacroTable + , valid_macro "preludeMacroSummary" preludeMacroSummary + , valid_string "preludeMacroSources" preludeMacroSources + , valid_macro "preludeMacroSource" preludeMacroSource + ] + , testGroup "RE" + [ valid_res TDFA + [ TDFA.re + , TDFA.reMS + , TDFA.reMI + , TDFA.reBS + , TDFA.reBI + , TDFA.reMultilineSensitive + , TDFA.reMultilineInsensitive + , TDFA.reBlockSensitive + , TDFA.reBlockInsensitive + , TDFA.re_ + ] + , testCase "TDFA.regexType" $ TDFA @=? TDFA.regexType + , testCase "TDFA.reOptions" $ Simple @=? _options_mode (TDFA.reOptions tdfa_re) + , testCase "TDFA.makeOptions md" $ Block @=? _options_mode (makeOptions Block :: Options_ TDFA.RE TDFA_.CompOption TDFA_.ExecOption) + , testCase "TDFA.preludeTestsFailing" $ [] @=? TDFA.preludeTestsFailing + , ne_string "TDFA.preludeTable" TDFA.preludeTable + , ne_string "TDFA.preludeSources" TDFA.preludeSources + , testGroup "TDFA.preludeSummary" + [ ne_string (presentPreludeMacro pm) $ TDFA.preludeSummary pm + | pm <- tdfa_prelude_macros + ] + , testGroup "TDFA.preludeSource" + [ ne_string (presentPreludeMacro pm) $ TDFA.preludeSource pm + | pm <- tdfa_prelude_macros + ] + , valid_res PCRE + [ PCRE.re + , PCRE.reMS + , PCRE.reMI + , PCRE.reBS + , PCRE.reBI + , PCRE.reMultilineSensitive + , PCRE.reMultilineInsensitive + , PCRE.reBlockSensitive + , PCRE.reBlockInsensitive + , PCRE.re_ + ] + , testCase "PCRE.regexType" $ PCRE @=? PCRE.regexType + , testCase "PCRE.reOptions" $ Simple @=? _options_mode (PCRE.reOptions pcre_re) + , testCase "PCRE.makeOptions md" $ Block @=? _options_mode (makeOptions Block :: Options_ PCRE.RE PCRE_.CompOption PCRE_.ExecOption) + , testCase "PCRE.preludeTestsFailing" $ [] @=? PCRE.preludeTestsFailing + , ne_string "PCRE.preludeTable" PCRE.preludeTable + , ne_string "PCRE.preludeTable" PCRE.preludeSources + , testGroup "PCRE.preludeSummary" + [ ne_string (presentPreludeMacro pm) $ PCRE.preludeSummary pm + | pm <- pcre_prelude_macros + ] + , testGroup "PCRE.preludeSource" + [ ne_string (presentPreludeMacro pm) $ PCRE.preludeSource pm + | pm <- pcre_prelude_macros + ] + ] + ] + where + tdfa_re = fromMaybe oops $ TDFA.compileRegex () ".*" + pcre_re = fromMaybe oops $ PCRE.compileRegex () ".*" + + oops = error "misc_tests" + +qq_tc :: String -> (QuasiQuoter->String->a) -> TestTree +qq_tc sc prj = testCase sc $ + try tst >>= either hdl (const $ assertFailure "qq0") + where + tst :: IO () + tst = prj (qq0 "qq_tc") "" `seq` return () + + hdl :: QQFailure -> IO () + hdl qqf = do + "qq_tc" @=? _qqf_context qqf + sc @=? _qqf_component qqf + +valid_macro :: String -> (RegexType->PreludeMacro->String) -> TestTree +valid_macro label f = testGroup label + [ valid_string (presentPreludeMacro pm) (flip f pm) + | pm<-[minBound..maxBound] + ] + +valid_string :: String -> (RegexType->String) -> TestTree +valid_string label f = testGroup label + [ ne_string (show rty) $ f rty + | rty<-[TDFA] -- until PCRE has a binding for all macros + ] + +ne_string :: String -> String -> TestTree +ne_string label s = + testCase label $ assertBool "non-empty string" $ length s > 0 + +-- just evaluating quasi quoters to HNF for now -- they +-- being tested everywhere [re|...|] (etc.) calculations +-- are bings used but HPC isn't measuring this +valid_res :: RegexType -> [QuasiQuoter] -> TestTree +valid_res rty = testCase (show rty) . foldr seq (return ()) + +pcre_prelude_macros :: [PreludeMacro] +pcre_prelude_macros = filter (/= PM_string) [minBound..maxBound] + +tdfa_prelude_macros :: [PreludeMacro] +tdfa_prelude_macros = [minBound..maxBound] \end{code} diff --git a/regex.cabal b/regex.cabal index ffca989..0e3789f 100644 --- a/regex.cabal +++ b/regex.cabal @@ -23,11 +23,11 @@ Cabal-version: >= 1.16 Source-repository head type: git - location: git://github.com/iconnect/regex.git + location: https://github.com/iconnect/regex.git Source-Repository this Type: git - Location: git://github.com/iconnect/regex.git + Location: https://github.com/iconnect/regex.git Tag: 0.0.0.1 Library @@ -37,6 +37,8 @@ Library Text.RE.CaptureID Text.RE.Edit Text.RE.Internal.NamedCaptures + Text.RE.Internal.PreludeMacros + Text.RE.Internal.QQ Text.RE.IsRegex Text.RE.LineNo Text.RE.Options @@ -63,8 +65,6 @@ Library Other-modules: Text.RE.Internal.AddCaptureNames - Text.RE.Internal.PreludeMacros - Text.RE.Internal.QQ Build-depends: array >= 0.4 , @@ -115,30 +115,30 @@ Executable re-gen-modules text >= 1.2.1.3 -Executable re-include +Test-Suite re-gen-modules-test + type: exitcode-stdio-1.0 Hs-Source-Dirs: examples - Main-is: re-include.lhs + Main-is: re-gen-modules.lhs Default-Language: Haskell2010 GHC-Options: -Wall -fwarn-tabs - Other-modules: - TestKit - Build-depends: regex , + array >= 0.4 , bytestring >= 0.10.2.0 , base >= 4 && < 5 , directory >= 1.2.1.0 , + regex-base >= 0.93.2 , + regex-tdfa >= 1.2.0 , shelly >= 1.6.1.2 , text >= 1.2.1.3 -Test-Suite re-include-test - type: exitcode-stdio-1.0 +Executable re-include Hs-Source-Dirs: examples Main-is: re-include.lhs @@ -154,31 +154,31 @@ Test-Suite re-include-test Build-depends: regex , bytestring >= 0.10.2.0 , - base >= 4 , + base >= 4 && < 5 , directory >= 1.2.1.0 , shelly >= 1.6.1.2 , text >= 1.2.1.3 -Test-Suite re-gen-modules-test +Test-Suite re-include-test type: exitcode-stdio-1.0 Hs-Source-Dirs: examples - Main-is: re-gen-modules.lhs + Main-is: re-include.lhs Default-Language: Haskell2010 GHC-Options: -Wall -fwarn-tabs + Other-modules: + TestKit + Build-depends: regex , - array >= 0.4 , bytestring >= 0.10.2.0 , - base >= 4 && < 5 , + base >= 4 , directory >= 1.2.1.0 , - regex-base >= 0.93.2 , - regex-tdfa >= 1.2.0 , shelly >= 1.6.1.2 , text >= 1.2.1.3 @@ -306,10 +306,49 @@ Test-Suite re-tests regex-pcre-builtin >= 0.94.4.8.8.35 , tasty >= 0.10.1.2 , tasty-hunit >= 0.9.2 , + template-haskell >= 2.7 , text >= 1.2.1.3 -Test-Suite re-tutorial +Executable re-tutorial + Hs-Source-Dirs: examples . + + Main-is: re-tutorial.lhs + + Other-modules: + TestKit + + Default-Language: Haskell2010 + Default-Extensions: QuasiQuotes + GHC-Options: + -Wall + -fwarn-tabs + + Build-depends: + regex , + array >= 0.4 , + bytestring >= 0.10.2.0 , + base >= 4 && < 5 , + containers >= 0.4 , + directory >= 1.2.1.0 , + hashable >= 1.2.3.3 , + heredoc >= 0.2.0.0 , + regex-base >= 0.93.2 , + regex-tdfa >= 1.2.1 , + regex-tdfa-text >= 1.0.0.3 , + regex-pcre-builtin >= 0.94.4.8.8.35 , + shelly >= 1.6.1.2 , + smallcheck >= 1.1.1 , + tasty >= 0.10.1.2 , + tasty-hunit >= 0.9.2 , + tasty-smallcheck >= 0.8.0.1 , + template-haskell >= 2.7 , + transformers >= 0.2.2 , + text >= 1.2.1.3 , + time >= 1.5.0.1 , + unordered-containers >= 0.2.5.1 + +Test-Suite re-tutorial-test type: exitcode-stdio-1.0 Hs-Source-Dirs: examples . diff --git a/save/travis.yml b/save/travis.yml new file mode 100644 index 0000000..ff13124 --- /dev/null +++ b/save/travis.yml @@ -0,0 +1,197 @@ +# This is the complex Travis configuration, which is intended for use +# on open source libraries which need compatibility across multiple GHC +# versions, must work with cabal-install, and should be +# cross-platform. For more information and other options, see: +# +# https://docs.haskellstack.org/en/stable/travis_ci/ +# +# Copy these contents into the root directory of your Github project in a file +# named .travis.yml + +# Use new container infrastructure to enable caching +sudo: false + +# Do not choose a language; we provide our own build tools. +language: generic + +# Caching so the next build will be fast too. +cache: + directories: + - $HOME/.ghc + - $HOME/.cabal + - $HOME/.stack + +# The different configurations we want to test. We have BUILD=cabal which uses +# cabal-install, and BUILD=stack which uses Stack. More documentation on each +# of those below. +# +# We set the compiler values here to tell Travis to use a different +# cache file per set of arguments. +# +# If you need to have different apt packages for each combination in the +# matrix, you can use a line such as: +# addons: {apt: {packages: [libfcgi-dev,libgmp-dev]}} +matrix: + include: + # We grab the appropriate GHC and cabal-install versions from hvr's PPA. See: + # https://github.com/hvr/multi-ghc-travis + + + # The Stack builds. We can pass in arbitrary Stack arguments via the ARGS + # variable, such as using --stack-yaml to point to a different file. + + # - env: BUILD=stack ARGS="" + # compiler: ": #stack default" + # addons: {apt: {packages: [libgmp-dev]}} + + - env: BUILD=stack GHCVER=7.10.3 STACK_YAML=stack-7.10.yaml + compiler: ": #stack 7.10.3" + addons: {apt: {packages: [libgmp-dev]}} + + - env: BUILD=stack GHCVER=7.8.4 STACK_YAML=stack-7.8.yaml + compiler: ": #stack 7.8.4" + addons: {apt: {packages: [libgmp-dev]}} + + - env: BUILD=stack GHCVER=8.0.1 STACK_YAML=stack-8.0.yaml + compiler: ": #stack 8.0.1" + addons: {apt: {packages: [libgmp-dev]}} + + + # Nightly builds are allowed to fail + # - env: BUILD=stack ARGS="--resolver nightly" + # compiler: ": #stack nightly" + # addons: {apt: {packages: [libgmp-dev]}} + + # Build on macOS in addition to Linux + # - env: BUILD=stack ARGS="" + # compiler: ": #stack default osx" + # os: osx + + + # - env: BUILD=cabal GHCVER=7.6.3 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7 + # compiler: ": #GHC 7.6.3" + # addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + + - env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 7.10.3" + addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + - env: BUILD=cabal GHCVER=7.8.4 CABALVER=1.18 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 7.8.4" + addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + - env: BUILD=cabal GHCVER=8.0.1 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7 + compiler: ": #GHC 8.0.1" + addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + + # Build with the newest GHC and cabal-install. This is an accepted failure, + # see below. + # - env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7 + # compiler: ": #GHC HEAD" + # addons: {apt: {packages: [cabal-install-head,ghc-head,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}} + + + # Travis includes an macOS which is incompatible with GHC 7.8.4 + #- env: BUILD=stack ARGS="--resolver lts-2" + # compiler: ": #stack 7.8.4 osx" + # os: osx + + - env: BUILD=stack STACK_YAML=stack-7.10.yaml + compiler: ": #stack 7.10.3 osx" + os: osx + + - env: BUILD=stack STACK_YAML=stack-8.0.yaml + compiler: ": #stack 8.0.1 osx" + os: osx + + # - env: BUILD=stack ARGS="--resolver nightly" + # compiler: ": #stack nightly osx" + # os: osx + + + allow_failures: + - env: BUILD=cabal GHCVER=head CABALVER=head HAPPYVER=1.19.5 ALEXVER=3.1.7 + - env: BUILD=stack ARGS="--resolver nightly" + + +before_install: +# Using compiler above sets CC to an invalid value, so unset it +- unset CC + +# We want to always allow newer versions of packages when building on GHC HEAD +- CABALARGS="" +- if [ "x$GHCVER" = "xhead" ]; then CABALARGS=--allow-newer; fi + +# Download and unpack the stack executable +- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.local/bin:/opt/alex/$ALEXVER/bin:/opt/happy/$HAPPYVER/bin:$HOME/.cabal/bin:$PATH +- mkdir -p ~/.local/bin +- | + if [ `uname` = "Darwin" ] + then + travis_retry curl --insecure -L https://www.stackage.org/stack/osx-x86_64 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin + else + travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' + fi + + # Use the more reliable S3 mirror of Hackage + mkdir -p $HOME/.cabal + echo 'remote-repo: hackage.haskell.org:http://hackage.fpcomplete.com/' > $HOME/.cabal/config + echo 'remote-repo-cache: $HOME/.cabal/packages' >> $HOME/.cabal/config + + if [ "$CABALVER" != "1.16" ] + then + echo 'jobs: $ncpus' >> $HOME/.cabal/config + fi + +install: +- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" +- if [ -f configure.ac ]; then autoreconf -i; fi +- | + set -ex + case "$BUILD" in + stack) + stack --no-terminal --install-ghc $ARGS test --coverage --bench --only-dependencies + ;; + cabal) + cabal --version + travis_retry cabal update + + # Get the list of packages from the stack.yaml file + PACKAGES=$(stack --install-ghc query locals | grep '^ *path' | sed 's@^ *path:@@') + + cabal install --only-dependencies --enable-tests --enable-benchmarks --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS $PACKAGES + ;; + esac + set +ex + +script: +- | + set -ex + case "$BUILD" in + stack) + stack --no-terminal $ARGS test --bench --coverage --no-run-benchmarks --haddock --no-haddock-deps + ;; + cabal) + cabal install --enable-tests --enable-benchmarks --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS $PACKAGES + + ORIGDIR=$(pwd) + for dir in $PACKAGES + do + cd $dir + cabal check || [ "$CABALVER" == "1.16" ] + cabal sdist + PKGVER=$(cabal info . | awk '{print $2;exit}') + SRC_TGZ=$PKGVER.tar.gz + cd dist + tar zxfv "$SRC_TGZ" + cd "$PKGVER" + cabal configure --enable-tests + cabal build + cd $ORIGDIR + done + ;; + esac + set +ex + +after_script: + - travis_retry curl -L https://github.com/rubik/stack-hpc-coveralls/releases/download/v0.0.4.0/shc-linux-x64-$GHCVER.tar.bz2 | tar -xj + - | + [ "$BUILD" == stack -a "$GHCVER" == 7.10.3 ] && ./shc --partial-coverage regex re-gen-modules-test re-include-test re-nginx-log-processor-test re-pp-test re-tests re-tutorial-test