packages feed

tslib-0.1.4: tests/basicTest.hs

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

module Main  where

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

t1, t12, t2, t23, t3, tOld, tFar :: UTCTime
tOld = UTCTime (fromGregorian 1900 01 01) 0
t1 = UTCTime (fromGregorian 2014 05 05) 0
t12 = UTCTime (fromGregorian 2014 05 20) 3600
t2 = UTCTime (fromGregorian 2014 06 15) 0
t23 = UTCTime (fromGregorian 2014 06 20) 28800
t3 = UTCTime (fromGregorian 2014 07 01) 0
tFar = UTCTime (fromGregorian 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 "tsLookup with AtOrAfter" $ do
    let lookup' t = tsLookup ex (AtOrAfter t)
    it "Nothing on far" $ do
      Nothing @=? lookup' tFar
    it "exact" $ do
      Just (t2,20) @=? lookup' t2
    it "t2 on t12" $ do
      Just (t2,20) @=? lookup' t12
    it "first on old" $ do
      Just (t1, 10) @=? lookup' tOld

  describe "tsLookup with AtOrBefore" $ do
    let lookup' t = tsLookup ex (AtOrBefore t)
    it "Nothing on old" $ do
      Nothing @=? lookup' tOld
    it "exact" $ do
      Just (t2,20) @=? lookup' t2
    it "t1 on t12" $ do
      Just (t1,10) @=? lookup' t12
    it "last on far" $ do
      Just (t3, 30) @=? lookup' tFar

  let roundToTwoDigits :: Maybe (UTCTime, Double) -> Maybe (UTCTime, 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)