packages feed

postgresql-types-0.1: src/unit-tests/PostgresqlTypes/TimeSpec.hs

module PostgresqlTypes.TimeSpec (spec) where

import Data.Data (Proxy (Proxy))
import Data.Maybe
import qualified Data.Time as Time
import qualified PostgresqlTypes.Time as PgTime
import Test.Hspec
import Test.QuickCheck
import qualified UnitTests.Scripts as Scripts
import Prelude

spec :: Spec
spec = do
  describe "Show/Read laws" do
    Scripts.testShowRead (Proxy @PgTime.Time)

  describe "IsScalar laws" do
    Scripts.testIsScalar (Proxy @PgTime.Time)

  describe "Constructors" do
    describe "normalizeFromMicroseconds" do
      it "creates Time from microseconds" do
        let pgTime = PgTime.normalizeFromMicroseconds 43_200_000_000 -- noon
        PgTime.toMicroseconds pgTime `shouldBe` 43_200_000_000

      it "creates Time from zero (midnight)" do
        let pgTime = PgTime.normalizeFromMicroseconds 0
        PgTime.toMicroseconds pgTime `shouldBe` 0

    describe "normalizeFromTimeOfDay" do
      it "converts TimeOfDay to Time" do
        let tod = Time.TimeOfDay 12 30 45
            pgTime = PgTime.normalizeFromTimeOfDay tod
        PgTime.toTimeOfDay pgTime `shouldBe` tod

      it "handles midnight" do
        let tod = Time.TimeOfDay 0 0 0
            pgTime = PgTime.normalizeFromTimeOfDay tod
        PgTime.toTimeOfDay pgTime `shouldBe` tod

    describe "refineFromTimeOfDay" do
      it "accepts valid TimeOfDay" do
        let tod = Time.TimeOfDay 12 30 45
            result = PgTime.refineFromTimeOfDay tod
        result `shouldSatisfy` isJust
        fmap PgTime.toTimeOfDay result `shouldBe` Just tod

      it "accepts midnight" do
        let tod = Time.TimeOfDay 0 0 0
            result = PgTime.refineFromTimeOfDay tod
        result `shouldSatisfy` isJust

  describe "Accessors" do
    describe "toMicroseconds" do
      it "extracts microseconds value" do
        let pgTime = PgTime.normalizeFromMicroseconds 3661_000_000 -- 1 hour, 1 minute, 1 second
        PgTime.toMicroseconds pgTime `shouldBe` 3661_000_000

    describe "toTimeOfDay" do
      it "converts to TimeOfDay" do
        let pgTime = PgTime.normalizeFromMicroseconds 43_200_000_000 -- noon
            tod = PgTime.toTimeOfDay pgTime
        tod `shouldBe` Time.TimeOfDay 12 0 0

  describe "Property Tests" do
    it "roundtrips through toMicroseconds and normalizeFromMicroseconds" do
      property \(pgTime :: PgTime.Time) ->
        let micros = PgTime.toMicroseconds pgTime
            pgTime' = PgTime.normalizeFromMicroseconds micros
         in pgTime' === pgTime

    it "normalizeFromTimeOfDay is idempotent" do
      property \(tod :: Time.TimeOfDay) ->
        let normalized1 = PgTime.normalizeFromTimeOfDay tod
            normalized2 = PgTime.normalizeFromTimeOfDay (PgTime.toTimeOfDay normalized1)
         in normalized1 === normalized2