Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/y-taka-23/time-machine
A Haskell library to mock the current time. ⏰
https://github.com/y-taka-23/time-machine
haskell monad testing
Last synced: 3 months ago
JSON representation
A Haskell library to mock the current time. ⏰
- Host: GitHub
- URL: https://github.com/y-taka-23/time-machine
- Owner: y-taka-23
- License: bsd-3-clause
- Created: 2017-10-12T14:18:35.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2018-05-01T06:28:06.000Z (over 6 years ago)
- Last Synced: 2024-10-01T15:44:09.743Z (3 months ago)
- Topics: haskell, monad, testing
- Language: Haskell
- Homepage: http://hackage.haskell.org/package/time-machine
- Size: 15.6 KB
- Stars: 17
- Watchers: 2
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
time-machine
============[![Build Status](https://travis-ci.org/y-taka-23/time-machine.svg?branch=master)](https://travis-ci.org/y-taka-23/time-machine)
[![Hackage](https://img.shields.io/hackage/v/time-machine.svg)](https://hackage.haskell.org/package/time-machine)A library to mock the current time and relevant `IO` functions
by using a type class.
You can get the great command of the current time in UTC,
time zones, and the speed of time.```haskell
module Main whereimport Control.Monad.TimeMachine
import Control.Monad.Trans ( liftIO )main :: IO ()
main = backTo (the future) $ do
t <- getCurrentTime
liftIO . putStrLn $ "We are at " ++ show t-- We are at 1985-10-26 08:24:00.035889 UTC
```As you know, time-dependent `IO` actions are extremely hard to test.
Assume, for example, the following simple action.
It should return `"Good morning"` only in the morning,
thus the results of its unit tests are fatally fragile.```haskell
getGreeting :: IO String
getGreeting = do
t <- getCurrentTime
if utctDayTime t <= 12 * 60 * 60
then return "Good morning"
else return "Hello"
```This library aims to make such actions testable with minimal changes.
Actually what you have to do is just:1. Use `MonadTime` type class instead of `IO`
1. Wrap `IO` actions in `liftIO` if necessaryHere is the testable version of `getGreeting`.
You can see that nothing is changed excepting the signature.```haskell
getGreeting :: (MonadTime m) => m String
getGreeting = do
t <- getCurrentTime
if utctDayTime t <= 12 * 60 * 60
then return "Good morning"
else return "Hello"
```Examples
--------### Mocking the Current Time
`travelTo` changes the result of `getCurrentTime` and relevant actions.
Other than pointing the target `UTCTime` explicitly,
you have two ways to determine how to mock the current time.
This library provides a small DSL to construct the destinations of your time travels.```haskell
-- By a date-time according to your local time zone
main = travelTo (oct 26 1985 am 1 24) $ do
getCurrentTime >>= (liftIO . print)
``````haskell
-- By a relative date
main = travelTo (3 `days` ago) $ do
getCurrentTime >>= (liftIO . print)
```For more detail,
see the [document](https://hackage.haskell.org/package/time-machine).### Mocking Time Zones
`jumpTo` switch the time zone which is used for calculating the local time.
By this function, you can test time-zone-sensitive actions.```haskell
import qualified Data.Time.Zones as TZmain = jumpTo "Asia/Shanghai" $ do
t <- getCurrentTime
tz <- loadLocalTZ
liftIO . print $ TZ.timeZoneForUTCTime tz t -- CST
```### Mocking the Speed of Time
`accelerate` changes the speed of time.
In the following example, time flies 60 times faster than the real.```haskell
main = accelerate (x 60) $ do
getCurrentTime >>= (liftIO . print) -- (*)
liftIO . threadDelay $ 1000 * 1000 -- wait a second
getCurrentTime >>= (liftIO . print) -- around a minute after (*)
```Moreover, as a special case of `accelerate`, `halt` stops the time.
That is remarkably useful to fix the point of time during your tests.```haskell
main = halt $ do
getCurrentTime >>= (liftIO . print) -- (*)
liftIO . threadDelay $ 1000 * 1000 -- wait a second
getCurrentTime >>= (liftIO . print) -- exactly same as (*)
```Installation
------------The project is managed by Stack, so you can install it simply:
```console
$ git clone https://github.com/y-taka-23/time-machine.git
$ cd time-machine
$ stack install
```License
-------This project is released under the BSD 3-clause license.
For more details, see [LICENSE](./LICENSE) file.