packages feed

antikythera-0.1.0.0: test/Spec.hs

module Main (main) where

import Control.Antikythera
import Data.Time
import Data.Time.Format.ISO8601 (ISO8601, iso8601ParseM, iso8601Show)
import GHC.Exts (IsList (fromList))
import GHC.IO (unsafePerformIO)
import Test.Hspec

main :: IO ()
main = hspec spec

spec :: Spec
spec =
  describe "Antikythera" $ do
    let testFor :: (ISO8601 a) => Periodicity a -> String -> Maybe String
        testFor p x = iso8601Show <$> p.nextPeriod (time x)
        time :: (ISO8601 a) => String -> a
        time = unsafePerformIO . iso8601ParseM
    describe "nextPeriod" $ do
      describe "ZonedTime" $ do
        describe "every 5 minutes" $ do
          let t = testFor @ZonedTime $ every 5 minute
          it "non overflowing" $
            t "2025-03-15T18:50:50+01:00" `shouldBe` Just "2025-03-15T18:55:00+01:00"
          it "overflowing hour" $
            t "2025-03-15T18:56:50+01:00" `shouldBe` Just "2025-03-15T19:00:00+01:00"
          it "overflowing day" $
            t "2025-03-15T23:56:50+01:00" `shouldBe` Just "2025-03-16T00:00:00+01:00"
          it "overflowing month" $
            t "2025-03-31T23:56:50+01:00" `shouldBe` Just "2025-04-01T00:00:00+01:00"
          it "overflowing year" $
            t "2025-12-31T23:56:50+01:00" `shouldBe` Just "2026-01-01T00:00:00+01:00"
        describe "at 5 minutes" $ do
          let t = testFor @ZonedTime $ at 5 minute
          it "non overflowing" $
            t "2025-03-15T18:01:50+01:00" `shouldBe` Just "2025-03-15T18:05:00+01:00"
          it "overflowing hour" $
            t "2025-03-15T18:56:50+01:00" `shouldBe` Just "2025-03-15T19:05:00+01:00"
          it "overflowing day" $
            t "2025-03-15T23:56:50+01:00" `shouldBe` Just "2025-03-16T00:05:00+01:00"
          it "overflowing month" $
            t "2025-03-31T23:56:50+01:00" `shouldBe` Just "2025-04-01T00:05:00+01:00"
          it "overflowing year" $
            t "2025-12-31T23:56:50+01:00" `shouldBe` Just "2026-01-01T00:05:00+01:00"
        describe "ats 5,35 minutes" $ do
          let t = testFor @ZonedTime $ ats (fromList [5, 35]) minute
          it "non overflowing (5)" $
            t "2025-03-15T18:01:50+01:00" `shouldBe` Just "2025-03-15T18:05:00+01:00"
          it "non overflowing (35)" $
            t "2025-03-15T18:11:50+01:00" `shouldBe` Just "2025-03-15T18:35:00+01:00"
          it "overflowing hour" $
            t "2025-03-15T18:56:50+01:00" `shouldBe` Just "2025-03-15T19:05:00+01:00"
          it "overflowing day" $
            t "2025-03-15T23:56:50+01:00" `shouldBe` Just "2025-03-16T00:05:00+01:00"
          it "overflowing month" $
            t "2025-03-31T23:56:50+01:00" `shouldBe` Just "2025-04-01T00:05:00+01:00"
          it "overflowing year" $
            t "2025-12-31T23:56:50+01:00" `shouldBe` Just "2026-01-01T00:05:00+01:00"
        describe "at 5 hour" $ do
          let t = testFor @ZonedTime $ at 5 hour
          it "non overflowing" $
            t "2025-03-15T02:01:50+01:00" `shouldBe` Just "2025-03-15T05:00:00+01:00"
          it "overflowing day" $
            t "2025-03-15T23:56:50+01:00" `shouldBe` Just "2025-03-16T05:00:00+01:00"
          it "overflowing month" $
            t "2025-03-31T23:56:50+01:00" `shouldBe` Just "2025-04-01T05:00:00+01:00"
          it "overflowing year" $
            t "2025-12-31T23:56:50+01:00" `shouldBe` Just "2026-01-01T05:00:00+01:00"
        describe "at Sunday (weekday)" $ do
          let t = testFor @ZonedTime $ at Sunday weekDay
          it "non overflowing" $
            t "2025-03-15T02:01:50+01:00" `shouldBe` Just "2025-03-16T00:00:00+01:00"
          it "overflowing week" $
            t "2025-03-17T23:56:50+01:00" `shouldBe` Just "2025-03-23T00:00:00+01:00"
          it "overflowing month" $
            t "2025-03-31T23:56:50+01:00" `shouldBe` Just "2025-04-06T00:00:00+01:00"
          it "overflowing year" $
            t "2025-12-31T23:56:50+01:00" `shouldBe` Just "2026-01-04T00:00:00+01:00"
        describe "at 5 month" $ do
          let t = testFor @ZonedTime $ at 5 month
          it "non overflowing" $
            t "2025-03-15T02:01:50+01:00" `shouldBe` Just "2025-05-01T00:00:00+01:00"
          it "overflowing year" $
            t "2025-12-31T23:56:50+01:00" `shouldBe` Just "2026-05-01T00:00:00+01:00"
        describe "at 2026 year" $ do
          let t = testFor @ZonedTime $ at 2026 year
          it "non overflowing" $
            t "2025-03-15T02:01:50+01:00" `shouldBe` Just "2026-01-01T00:00:00+01:00"
        describe "at 5 hour .|| at 5 minute" $ do
          let t = testFor @ZonedTimeWrapped (at 5 hour .|| at 5 minute)
          it "non overflowing (minute)" $
            t "2025-03-15T02:01:50+01:00" `shouldBe` Just "2025-03-15T02:05:00+01:00"
          it "non overflowing (hour)" $
            t "2025-03-15T04:06:50+01:00" `shouldBe` Just "2025-03-15T05:00:00+01:00"
          it "overflowing day" $
            t "2025-03-15T23:56:50+01:00" `shouldBe` Just "2025-03-16T00:05:00+01:00"
        describe "at 5 hour .&& at 5 minute" $ do
          let t = testFor @ZonedTimeWrapped (at 5 hour .&& at 5 minute)
          it "non overflowing" $
            t "2025-03-15T02:01:50+01:00" `shouldBe` Just "2025-03-15T05:05:00+01:00"
          it "overflowing day" $
            t "2025-03-15T23:56:50+01:00" `shouldBe` Just "2025-03-16T05:05:00+01:00"
      describe "ZonedTime" $ do
        describe "at 5 hour .&& sinceInclusive" $ do
          let t = testFor @UTCTime (at 5 hour .&& sinceInclusive (addUTCTime nominalDay) (time "2025-03-15T04:05:00Z"))
          it "non overflowing" $
            t "2025-03-15T02:01:50Z" `shouldBe` Just "2025-03-15T05:00:00Z"
          it "overflowing day (at)" $
            t "2025-03-15T23:56:50Z" `shouldBe` Just "2025-03-16T05:00:00Z"
          it "overflowing day (sinceInclusive)" $
            t "2025-03-14T23:56:50Z" `shouldBe` Just "2025-03-15T05:00:00Z"
        describe "at 5 hour .&& untilInclusive" $ do
          let t = testFor @UTCTime (at 5 hour .&& untilInclusive (addUTCTime nominalDay) (time "2025-03-17T04:05:00Z"))
          it "non overflowing" $
            t "2025-03-15T02:01:50Z" `shouldBe` Just "2025-03-15T05:00:00Z"
          it "overflowing day (at)" $
            t "2025-03-15T23:56:50Z" `shouldBe` Just "2025-03-16T05:00:00Z"
          it "overflowing day (untilInclusive)" $
            t "2025-03-16T23:56:50Z" `shouldBe` Nothing
    describe "Utils" $ do
      describe "nextPeriods" $ do
        describe "at 5 hour .&& untilInclusive" $ do
          it "before the deadline" $ do
            let p = at 5 hour .&& untilInclusive (addUTCTime nominalDay) (time "2025-03-17T04:05:00Z")
            (iso8601Show <$> nextPeriods p (time "2025-03-15T02:01:50Z"))
              `shouldBe` ["2025-03-15T05:00:00Z", "2025-03-16T05:00:00Z"]
          it "after the deadline" $ do
            let p = at 5 hour .&& untilInclusive (addUTCTime nominalDay) (time "2025-03-17T04:05:00Z")
            (iso8601Show <$> nextPeriods p (time "2025-03-18T02:01:50Z"))
              `shouldBe` []