module Test.Calendar.Valid ( testValid, ) where import Data.Time import Data.Time.Calendar.Julian import Data.Time.Calendar.OrdinalDate import Data.Time.Calendar.WeekDate import Test.QuickCheck.Property import Test.Tasty import Test.Tasty.QuickCheck hiding (reason) validResult :: (Eq c, Show c, Eq t, Show t) => (s -> c) -> Bool -> (t -> c) -> (c -> t) -> (c -> Maybe t) -> s -> Result validResult sc valid toComponents fromComponents fromComponentsValid s = let c = sc s mt = fromComponentsValid c t' = fromComponents c c' = toComponents t' in if valid then case mt of Nothing -> rejected Just t -> if t' /= t then failed{reason = "'fromValid' gives " ++ show t ++ ", but 'from' gives " ++ show t'} else if c' /= c then failed { reason = "found valid, but converts " ++ show c ++ " -> " ++ show t' ++ " -> " ++ show c' } else succeeded else case mt of Nothing -> if c' /= c then succeeded else failed{reason = show c ++ " found invalid, but converts with " ++ show t'} Just _ -> rejected validTest :: (Arbitrary s, Show s, Eq c, Show c, Eq t, Show t) => String -> (s -> c) -> (t -> c) -> (c -> t) -> (c -> Maybe t) -> TestTree validTest name sc toComponents fromComponents fromComponentsValid = testGroup name [ testProperty "valid" $ property $ validResult sc True toComponents fromComponents fromComponentsValid , testProperty "invalid" $ property $ validResult sc False toComponents fromComponents fromComponentsValid ] toSundayStartWeek :: Day -> (Integer, Int, Int) toSundayStartWeek day = let (y, _) = toOrdinalDate day (w, d) = sundayStartWeek day in (y, w, d) toMondayStartWeek :: Day -> (Integer, Int, Int) toMondayStartWeek day = let (y, _) = toOrdinalDate day (w, d) = mondayStartWeek day in (y, w, d) newtype WYear = MkWYear Year deriving (Eq, Show) instance Arbitrary WYear where arbitrary = fmap MkWYear $ choose (-1000, 3000) newtype WMonthOfYear = MkWMonthOfYear MonthOfYear deriving (Eq, Show) instance Arbitrary WMonthOfYear where arbitrary = fmap MkWMonthOfYear $ choose (-5, 17) newtype WDayOfMonth = MkWDayOfMonth DayOfMonth deriving (Eq, Show) instance Arbitrary WDayOfMonth where arbitrary = fmap MkWDayOfMonth $ choose (-5, 35) newtype WDayOfYear = MkWDayOfYear DayOfYear deriving (Eq, Show) instance Arbitrary WDayOfYear where arbitrary = fmap MkWDayOfYear $ choose (-20, 400) newtype WWeekOfYear = MkWWeekOfYear WeekOfYear deriving (Eq, Show) instance Arbitrary WWeekOfYear where arbitrary = fmap MkWWeekOfYear $ choose (-5, 60) newtype WDayOfWeek = MkWDayOfWeek Int deriving (Eq, Show) instance Arbitrary WDayOfWeek where arbitrary = fmap MkWDayOfWeek $ choose (-5, 15) fromYMD :: (WYear, WMonthOfYear, WDayOfMonth) -> (Year, MonthOfYear, DayOfMonth) fromYMD (MkWYear y, MkWMonthOfYear ym, MkWDayOfMonth md) = (y, ym, md) fromYD :: (WYear, WDayOfYear) -> (Year, DayOfYear) fromYD (MkWYear y, MkWDayOfYear yd) = (y, yd) fromYWD :: (WYear, WWeekOfYear, WDayOfWeek) -> (Year, WeekOfYear, Int) fromYWD (MkWYear y, MkWWeekOfYear yw, MkWDayOfWeek wd) = (y, yw, wd) testValid :: TestTree testValid = testGroup "testValid" [ validTest "Gregorian" fromYMD toGregorian (\(y, m, d) -> fromGregorian y m d) (\(y, m, d) -> fromGregorianValid y m d) , validTest "OrdinalDate" fromYD toOrdinalDate (\(y, d) -> fromOrdinalDate y d) (\(y, d) -> fromOrdinalDateValid y d) , validTest "WeekDate" fromYWD toWeekDate (\(y, w, d) -> fromWeekDate y w d) (\(y, w, d) -> fromWeekDateValid y w d) , validTest "SundayStartWeek" fromYWD toSundayStartWeek (\(y, w, d) -> fromSundayStartWeek y w d) (\(y, w, d) -> fromSundayStartWeekValid y w d) , validTest "MondayStartWeek" fromYWD toMondayStartWeek (\(y, w, d) -> fromMondayStartWeek y w d) (\(y, w, d) -> fromMondayStartWeekValid y w d) , validTest "Julian" fromYMD toJulian (\(y, m, d) -> fromJulian y m d) (\(y, m, d) -> fromJulianValid y m d) ]