packages feed

cron-0.3.2: test/System/Test/Cron/Parser.hs

{-# LANGUAGE OverloadedStrings #-}
module System.Test.Cron.Parser (tests) where
-- TODO: this *should* just work with {-# OPTIONS_GHC -F -pgmF hspec-discover #-}


-------------------------------------------------------------------------------
import           Data.Attoparsec.Text (Parser, parseOnly)
import           Data.Text            (Text)
-------------------------------------------------------------------------------
import           SpecHelper
import           System.Cron
import           System.Cron.Parser
-------------------------------------------------------------------------------


tests :: TestTree
tests = testGroup "System.Cron.Parser"
  [ describeCronSchedule
  , describeCronScheduleLoose
  , describeCrontab
  , describeCrontabEntry
  ]

describeCronSchedule :: TestTree
describeCronSchedule = testGroup "cronSchedule"
  [
    testCase "parses all stars" $
    assertSuccessfulParse "* * * * *"
                          stars

  , testCase "parses specific values" $
    assertSuccessfulParse "1 2 3 * *"
                           stars { minute      = Minutes (SpecificField 1),
                                   hour        = Hours (SpecificField 2),
                                   dayOfMonth  = DaysOfMonth (SpecificField 3) }

  , testCase "parses list values" $
    assertSuccessfulParse "* * 3,4 * *"
                           stars { dayOfMonth  = DaysOfMonth (ListField [SpecificField 3,
                                                                         SpecificField 4]) }

  , testCase "parses range values" $
    assertSuccessfulParse "* * 3-4 * *"
                           stars { dayOfMonth  = DaysOfMonth (RangeField 3 4) }

  , testCase "parses step values" $
    assertSuccessfulParse "*/2 * 2-10/4 * *"
                          stars { minute     = Minutes (StepField Star 2),
                                  dayOfMonth  = DaysOfMonth (StepField (RangeField 2 10) 4) }

  , testCase "refuses to parse recursive steps" $
    assertFailedParse "*/2/3 * * * *"

  , testCase "refuses to parse sparse lists" $
    assertFailedParse "1,,2 * * * *"

  , testCase "refuses too few fields" $
    assertFailedParse "* * * *"

  , testCase "refuses too many fields" $
    assertFailedParse "* * * * * *"

  , testCase "refuses extraneous input" $
    assertFailedParse "* * * * *    wat is this"

  , testCase "parses @hourly" $
    assertSuccessfulParse "@hourly" hourly

  , testCase "parses @daily" $
    assertSuccessfulParse "@daily" daily

  , testCase "parses @monthly" $
    assertSuccessfulParse "@monthly" monthly

  , testCase "parses @yearly" $
    assertSuccessfulParse "@yearly" yearly

  , testCase "parses ranges at the last field" $
    assertSuccessfulParse "* * * * 3-4"
                           stars { dayOfWeek  = DaysOfWeek (RangeField 3 4) }
  , testCase "parses lists at the last field" $
    assertSuccessfulParse "* * * * 3,4"
                           stars { dayOfWeek  = DaysOfWeek (ListField [SpecificField 3,
                                                                       SpecificField 4]) }
  , testCase "parses steps at the last field" $
    assertSuccessfulParse "* * * * */4"
                           stars { dayOfWeek  = DaysOfWeek (StepField Star 4) }
  , testCase "parses a sunday as 7" $
    assertSuccessfulParse "* * * * 7"
                           stars { dayOfWeek  = DaysOfWeek (SpecificField 7) }
  , testCase "parses a sunday as 0" $
    assertSuccessfulParse "* * * * 0"
                           stars { dayOfWeek  = DaysOfWeek (SpecificField 0) }
  , testCase "parses another example" $
    assertSuccessfulParse "1-59/2 * * * *"
                          stars { minute     = Minutes (StepField (RangeField 1 59) 2) }

  ]
  where assertSuccessfulParse = assertParse cronSchedule
        assertFailedParse = assertNoParse cronSchedule

describeCronScheduleLoose :: TestTree
describeCronScheduleLoose = testGroup "cronScheduleLoose"
  [
    testCase "is okay with extaneous input" $
    assertSuccessfulParse "* * * * * *"
                          stars
  ]
  where assertSuccessfulParse = assertParse cronScheduleLoose

describeCrontab :: TestTree
describeCrontab = testGroup "crontab"
  [
    testCase "parses an empty input" $
    assertSuccessfulParse ""
                          (Crontab [])

  , testCase "parses whitespace" $
    assertSuccessfulParse "        "
                          (Crontab [])

  , testCase "parses a single line" $
    assertSuccessfulParse "        "
                          (Crontab [])

  , testCase "ignores comments" $
    assertSuccessfulParse "# comment"
                          (Crontab [])

  , testCase "ignores comments with leading whitespace" $
    assertSuccessfulParse "    # comment"
                          (Crontab [])

  , testCase "parses comments interspersed with actual commands" $
    assertSuccessfulParse "#comment here\nFOO=BAR\n  #another\n* * * * * do stuff"
                          (Crontab [envSet, entry])
  ]
  where assertSuccessfulParse = assertParse crontab

describeCrontabEntry :: TestTree
describeCrontabEntry = testGroup "crontabEntry"
  [
    testCase "parses an environment variable assignment" $
    assertSuccessfulParse "FOO=BAR"
                          envSet

  , testCase "parses an environment variable with whitespace at the front" $
    assertSuccessfulParse "  FOO=BAR"
                          envSet

  , testCase "parses an environment variable with whitespace in the middle" $
    assertSuccessfulParse "  FOO =   BAR"
                          envSet

  , testCase "parses a command" $
    assertSuccessfulParse "* * * * * do stuff"
                          entry

  , testCase "parses a command with any amount of whitespace inbetween" $
    assertSuccessfulParse "* * * * *      do stuff"
                          entry

  , testCase "parses a command with whitespace at the front" $
    assertSuccessfulParse "  * * * * *      do stuff"
                          entry
  ]
  where assertSuccessfulParse = assertParse crontabEntry

assertParse :: (Eq a, Show a)
               => Parser a
               -> Text
               -> a
               -> Assertion
assertParse parser txt expected = parsed @?= Right expected
  where parsed = parseOnly parser txt

--assertNoParse :: Parser a -> Text -> b
assertNoParse :: (Eq a, Show a)
                 => Parser a
                 -> Text
                 -> Assertion
assertNoParse parser txt = isLeft (parseOnly parser txt) @?= True

envSet :: CrontabEntry
envSet = EnvVariable "FOO" "BAR"

entry :: CrontabEntry
entry = CommandEntry stars "do stuff"

stars :: CronSchedule
stars = CronSchedule (Minutes Star)
                     (Hours Star)
                     (DaysOfMonth Star)
                     (Months Star)
                     (DaysOfWeek Star)