packages feed

tslib-0.1.4: tests/basicUTimeTest.hs

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Main  where

import Control.Lens
import Data.Time
import Data.UTime
import Data.TimeSeries.UTime
import Data.TimeSeries.Class
import qualified Data.TimeSeries.Boxed as TSB
import qualified Data.TimeSeries.Storable as TSS
import Test.Hspec
import Test.HUnit

ut :: Integer -> Int -> Int -> DiffTime -> UTime
ut y m d dt = toUTime $ UTCTime (fromGregorian y m d) dt

t1, t12, t2, t23, t3, tOld, tFar :: UTime
tOld = ut 1900 01 01 0
t1 = ut 2014 05 05 0
t12 = ut 2014 05 20 3600
t2 = ut 2014 06 15 0
t23 = ut 2014 06 20 28800
t3 = ut 2014 07 01 0
tFar = ut 2024 07 07 43200

exAbstract :: TSeries ts Int => ts Int
exAbstract = fromUnsortedPairList [(t1, 10), (t3, 30), (t2, 20)]

ex2Abstract :: TSeries ts Int => ts Int
ex2Abstract = fromUnsortedPairList [(t12, 12), (t2, 2), (t23, 23)]

exDoubleAbstract :: (TSeries ts Int, TSeries ts Double) => ts Double
exDoubleAbstract = exAbstract & tsTraversed %~ fromIntegral

emptyAbstract :: TSeries ts Double => ts Double
emptyAbstract = fromSortedPairList []

type TSeriesTestable ts a = (TSeries ts a, Show (ts a), Eq (ts a))

mainAbstract :: forall ts. ( TSeriesTestable ts Double
                           , TSeriesTestable ts Int
                           , TSeriesTestable ts Bool) => ts Double -> Spec
mainAbstract _witness = do
  let ex = exAbstract :: ts Int
      ex2 = ex2Abstract :: ts Int
      exDouble = exDoubleAbstract :: ts Double
      empty = emptyAbstract :: ts Double

  describe "fromUnsortedPairList" $ do
    it "sorts" $ do
      [(t1, 10), (t2, 20), (t3, 30)] @=? toPairList ex

  describe "tsLength" $ do
    it "0 on empty" $ do
      0 @=? tsLength empty
    it "3 on example" $ do
      3 @=? tsLength ex

  describe "tsRange" $ do
    it "Nothing on empty" $ do
      Nothing @=? tsRange empty
    it "(t1,t3) on example" $ do
      Just (t1,t3) @=? tsRange ex

  describe "firstAfter" $ do
    it "Nothing on far" $ do
      Nothing @=? firstAfter ex tFar
    it "exact" $ do
      Just (t2,20) @=? firstAfter ex t2
    it "t2 on t12" $ do
      Just (t2,20) @=? firstAfter ex t12
    it "first on old" $ do
      Just (t1, 10) @=? firstAfter ex tOld

  describe "lastBefore" $ do
    it "Nothing on old" $ do
      Nothing @=? lastBefore ex tOld
    it "exact" $ do
      Just (t2,20) @=? lastBefore ex t2
    it "t1 on t12" $ do
      Just (t1,10) @=? lastBefore ex t12
    it "last on far" $ do
      Just (t3, 30) @=? lastBefore ex tFar

  let roundToTwoDigits :: Maybe (UTime, Double) -> Maybe (UTime, Int)
      roundToTwoDigits = fmap (mapSnd (round . (* 100)))
        where
          mapSnd f (a, b) = (a, f b)

  let interp1 t = interpolateAt interpolateLinear exDouble t
  describe "interpolateAt with interpolateLinear" $ do
    it "exact" $ do
      Just (t1,10.0) @=? interp1 t1
    it "Nothing on old" $ do
      Nothing @=? interp1 tOld
    it "Nothing on far" $ do
      Nothing @=? interp1 tFar
    it "interpolates" $ do
      roundToTwoDigits (Just (t23, 20 + 10/3)) @=? (roundToTwoDigits $ interp1 t23)

  let interp2 t = interpolateAt extendInterpolateLinear exDouble t
  describe "interpolateAt with extendInterpolateLinear" $ do
    it "exact" $ do
      Just (t1,10.0) @=? interp2 t1
    it "extends on old" $ do
      Just (tOld, 10) @=? interp2 tOld
    it "extends on far" $ do
      Just (tFar, 30) @=? interp2 tFar
    it "interpolates" $ do
      roundToTwoDigits (Just (t23, 20 + 10/3)) @=? (roundToTwoDigits $ interp2 t23)

  describe "tsMergeWith" $ do
    it "empty with empty on the right" $ do
      empty @=? tsMergeWith undefined ex empty
    it "empty with empty on the left" $ do
      empty @=? tsMergeWith undefined empty ex
    it "equates with itself" $ do
      fromSortedPairList [(t1,True), (t2, True), (t3, True)]
      @=? tsMergeWith (const (==)) ex ex

  describe "tsMerge" $ do
    it "does it right" $ do
      fromSortedPairList [(t1, 20), (t12, -12), (t2, 18), (t23, -23), (t3, 60)]
      @=? tsMerge
        (TSMerge (const $ Just . (2*)) (const $ Just . negate) (\_ a b -> Just (a - b)))
        ex ex2

main :: IO ()
main = hspec $ do
  describe "Boxed" $ mainAbstract (undefined :: TSB.TSeries Double)
  describe "Storable" $ mainAbstract (undefined :: TSS.TSeries Double)