hodatime-0.1.1.1: tests/HodaTime/Calendar/GregorianTest.hs
{-# LANGUAGE FlexibleInstances #-}
module HodaTime.Calendar.GregorianTest
(
gregorianTests
)
where
import Test.Tasty
import Test.Tasty.QuickCheck as QC
import Test.Tasty.HUnit
import Data.Maybe (fromJust)
import Data.Time.Calendar (fromGregorianValid, toGregorian)
import HodaTime.Util
import Data.HodaTime.CalendarDate (day, monthl, month, year, next, previous, dayOfWeek)
import Data.HodaTime.Calendar.Gregorian (calendarDate, Month(..), DayOfWeek(..), Gregorian)
import qualified Data.HodaTime.Calendar.Gregorian as G
import qualified Data.HodaTime.Calendar.Iso as Iso
instance Arbitrary (Month Gregorian) where
arbitrary = do
x <- choose (0,11)
return $ toEnum x
instance Arbitrary (DayOfWeek Gregorian) where
arbitrary = do
x <- choose (0,6)
return $ toEnum x
gregorianTests :: TestTree
gregorianTests = testGroup "Gregorian Tests" [qcProps, unitTests]
qcProps :: TestTree
qcProps = testGroup "(checked by QuickCheck)" [constructorProps, lensProps]
unitTests :: TestTree
unitTests = testGroup "Unit tests" [constructorUnits, lensUnits]
constructorProps :: TestTree
constructorProps = testGroup "Constructor"
[
QC.testProperty "same dates as Data.Time" $ testConstructor
]
where
areSame Nothing Nothing = True
areSame (Just hdate) (Just date) =
let
(ty, tm, tday) = toGregorian date
in get day hdate == tday && (convertMonth . month $ hdate) == tm && get year hdate == (fromIntegral ty)
areSame _ _ = False
convertMonth = succ . fromEnum
testConstructor (Positive y) m (Positive d) = areSame (calendarDate d m y') (fromGregorianValid (fromIntegral y') (convertMonth m) d)
where
y' = 1900 + y
lensProps :: TestTree
lensProps = testGroup "Lens"
[
QC.testProperty "first day not changed by month math" $ testMonthAdd 1
,QC.testProperty "mid day not changed by month math" $ testMonthAdd 15
,QC.testProperty "dayOfWeek . next n dow $ date == dow" $ testNextDoW
,QC.testProperty "next n (dayOfWeek date) date == modify (+ n * 7) day date" $ testDirection next (+)
,QC.testProperty "previous n (dayOfWeek date) date == modify (- n * 7) day date" $ testDirection previous $ flip (-)
]
where
mkcd d m = fromJust . calendarDate d m
testMonthAdd d (Positive y) m add = y < 400 QC.==> get day (modify (+ add) monthl $ mkcd d m (y + 1900)) == d -- NOTE: We fix the year so we don't run out of tests
testNextDoW dow (Positive n) = (dayOfWeek . next n dow $ epochDay) == dow
testDirection dir adjust (Positive n) = dir n (dayOfWeek epochDay) epochDay == modify (adjust $ n * 7) day epochDay
epochDay = mkcd 1 March 2000
constructorUnits :: TestTree
constructorUnits = testGroup "Constructor"
[
testCase "CalendarDate 30 February 2000 is not a valid date" $ calendarDate 30 February 2000 @?= Nothing
,testCase "Gregorian.fromWeekDate 1 Sunday 2000 = 26.Dec.1999" $ G.fromWeekDate 1 Sunday 2000 @?= calendarDate 26 December 1999
,testCase "Gregorian.fromWeekDate 5 Sunday 2000 = 23.Jan.2000" $ G.fromWeekDate 5 Sunday 2000 @?= calendarDate 23 January 2000
,testCase "Iso.fromWeekDate 1 Sunday 2000 = 9.Jan.2000" $ Iso.fromWeekDate 1 Sunday 2000 @?= calendarDate 9 January 2000
,testCase "Iso.fromWeekDate 5 Sunday 2000 = 6.Feb.2000" $ Iso.fromWeekDate 5 Sunday 2000 @?= calendarDate 6 February 2000
]
lensUnits :: TestTree
lensUnits = testGroup "Lens"
[
testCase "31-January-2000 + 2M == 31-March-2000" $ modify (+2) monthl <$> janEnd @?= calendarDate 31 March 2000
,testCase "31-January-2000 + 1M == 29-February-2000" $ modify (+1) monthl <$> janEnd @?= calendarDate 29 February 2000
,testCase "29-February-2000 + 1Y == 28-February-2001" $ modify (+1) year <$> leapFeb @?= calendarDate 28 February 2001
,testCase "31-December-2000 + 1D == 1-January-2001" $ modify (+1) day <$> endYear @?= calendarDate 1 January 2001
]
where
janEnd = calendarDate 31 January 2000
leapFeb = calendarDate 29 February 2000
endYear = calendarDate 31 December 2000