Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ghc-auto-update for openSUSE:Factory 
checked in at 2024-12-20 23:10:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-auto-update (Old)
 and      /work/SRC/openSUSE:Factory/.ghc-auto-update.new.1881 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ghc-auto-update"

Fri Dec 20 23:10:06 2024 rev:20 rq:1231418 version:0.2.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-auto-update/ghc-auto-update.changes  
2024-11-12 19:20:37.345459271 +0100
+++ 
/work/SRC/openSUSE:Factory/.ghc-auto-update.new.1881/ghc-auto-update.changes    
    2024-12-20 23:10:16.135604696 +0100
@@ -1,0 +2,9 @@
+Tue Nov 19 20:58:13 UTC 2024 - Peter Simons <[email protected]>
+
+- Update auto-update to version 0.2.4.
+  Upstream has edited the change log file since the last release in
+  a non-trivial way, i.e. they did more than just add a new entry
+  at the top. You can review the file at:
+  http://hackage.haskell.org/package/auto-update-0.2.4/src/ChangeLog.md
+
+-------------------------------------------------------------------

Old:
----
  auto-update-0.2.2.tar.gz

New:
----
  auto-update-0.2.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ghc-auto-update.spec ++++++
--- /var/tmp/diff_new_pack.vHbE1Y/_old  2024-12-20 23:10:16.631625125 +0100
+++ /var/tmp/diff_new_pack.vHbE1Y/_new  2024-12-20 23:10:16.635625289 +0100
@@ -20,7 +20,7 @@
 %global pkgver %{pkg_name}-%{version}
 %bcond_with tests
 Name:           ghc-%{pkg_name}
-Version:        0.2.2
+Version:        0.2.4
 Release:        0
 Summary:        Efficiently run periodic, on-demand actions
 License:        MIT

++++++ auto-update-0.2.2.tar.gz -> auto-update-0.2.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/auto-update-0.2.2/ChangeLog.md 
new/auto-update-0.2.4/ChangeLog.md
--- old/auto-update-0.2.2/ChangeLog.md  2001-09-09 03:46:40.000000000 +0200
+++ new/auto-update-0.2.4/ChangeLog.md  2001-09-09 03:46:40.000000000 +0200
@@ -1,5 +1,19 @@
 # ChangeLog for auto-update
 
+## 0.2.4
+
+* Simple refactoring.
+
+## 0.2.3
+
+* [#996](https://github.com/yesodweb/wai/pull/996):
+  Refactored the `Control.Debounce` logic to not leak threads.
+* [#996](https://github.com/yesodweb/wai/pull/996):
+  Added extra `DebounceEdge` options for different types of debouncing.
+  * `LeadingMute`: Action on first trigger, and ignore any triggers during 
cooldown
+  * `TrailingDelay`: First trigger starts cooldown, and
+    triggers during cooldown extend the cooldown. Action when cooldown expires.
+
 ## 0.2.2
 
 * NewAPI: updateThreadName, reaperThreadName, debounceThreadName:
@@ -14,19 +28,19 @@
 
 * Creating Reaper.Internal to export Reaper constructor.
 * Hiding Reaper constructor.
-* Add `reaperModify` to the `Reaper` API, allowing workload modification 
outside
+* [#985](https://github.com/yesodweb/wai/pull/985):
+  Add `reaperModify` to the `Reaper` API, allowing workload modification 
outside
   of the main `reaperAction` loop.
-  [#985](https://github.com/yesodweb/wai/pull/985)
 
 ## 0.1.6
 
-* Add control of activation on leading vs. trailing edges for Control.Debounce
-  [#756](https://github.com/yesodweb/wai/pull/756)
+* [#756](https://github.com/yesodweb/wai/pull/756):
+  Add control of activation on leading vs. trailing edges for Control.Debounce
 
 ## 0.1.5
 
-* Using the Strict and StrictData language extensions for GHC >8.
-  [#752](https://github.com/yesodweb/wai/pull/752)
+* [#752](https://github.com/yesodweb/wai/pull/752):
+  Using the Strict and StrictData language extensions for GHC >8.
 
 ## 0.1.4.1
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/auto-update-0.2.2/Control/AutoUpdate.hs 
new/auto-update-0.2.4/Control/AutoUpdate.hs
--- old/auto-update-0.2.2/Control/AutoUpdate.hs 2001-09-09 03:46:40.000000000 
+0200
+++ new/auto-update-0.2.4/Control/AutoUpdate.hs 2001-09-09 03:46:40.000000000 
+0200
@@ -115,6 +115,11 @@
     --
     -- @since 0.1.0
     , updateThreadName :: String
+    -- ^ Label of the thread being forked.
+    --
+    -- Default: @"AutoUpdate"@
+    --
+    -- @since 0.2.2
     }
 
 -- | Generate an action which will either read from an automatically
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/auto-update-0.2.2/Control/Debounce/Internal.hs 
new/auto-update-0.2.4/Control/Debounce/Internal.hs
--- old/auto-update-0.2.2/Control/Debounce/Internal.hs  2001-09-09 
03:46:40.000000000 +0200
+++ new/auto-update-0.2.4/Control/Debounce/Internal.hs  2001-09-09 
03:46:40.000000000 +0200
@@ -5,19 +5,24 @@
     DebounceSettings (..),
     DebounceEdge (..),
     leadingEdge,
+    leadingMuteEdge,
     trailingEdge,
+    trailingDelayEdge,
     mkDebounceInternal,
 ) where
 
 import Control.Concurrent (forkIO)
 import Control.Concurrent.MVar (
     MVar,
-    takeMVar,
+    newEmptyMVar,
+    putMVar,
     tryPutMVar,
     tryTakeMVar,
  )
 import Control.Exception (SomeException, handle, mask_)
-import Control.Monad (forever, void)
+import Control.Monad (void, when)
+import GHC.Clock (getMonotonicTimeNSec)
+import GHC.Conc (atomically, newTVarIO, readTVar, readTVarIO, writeTVar)
 import GHC.Conc.Sync (labelThread)
 
 -- | Settings to control how debouncing should work.
@@ -49,10 +54,15 @@
     -- ^ Whether to perform the action on the leading edge or trailing edge of
     -- the timeout.
     --
-    -- Default: 'trailingEdge'.
+    -- Default: 'leadingEdge'.
     --
     -- @since 0.1.6
     , debounceThreadName :: String
+    -- ^ Label of the thread spawned when debouncing.
+    --
+    -- Default: @"Debounce"@.
+    --
+    -- @since 0.2.2
     }
 
 -- | Setting to control whether the action happens at the leading and/or 
trailing
@@ -64,42 +74,224 @@
       -- If the trigger happens again during the cooldown, wait until the end 
of the cooldown
       -- and then perform the action again, then enter a new cooldown period.
       Leading
+    | -- | Perform the action immediately, and then begin a cooldown period.
+      -- If the trigger happens again during the cooldown, it is ignored.
+      LeadingMute
     | -- | Start a cooldown period and perform the action when the period 
ends. If another trigger
       -- happens during the cooldown, it has no effect.
       Trailing
+    | -- | Start a cooldown period and perform the action when the period 
ends. If another trigger
+      -- happens during the cooldown, it restarts the cooldown again.
+      TrailingDelay
     deriving (Show, Eq)
 
 -- | Perform the action immediately, and then begin a cooldown period.
 -- If the trigger happens again during the cooldown, wait until the end of the 
cooldown
 -- and then perform the action again, then enter a new cooldown period.
 --
+-- Example of how this style debounce works:
+--
+-- > ! = function execution
+-- > . = cooldown period
+-- > X = debounced code execution
+-- >
+-- > !   !         !            !
+-- >  ....... ....... .......    .......
+-- > X       X       X          X
+--
 -- @since 0.1.6
 leadingEdge :: DebounceEdge
 leadingEdge = Leading
 
--- | Start a cooldown period and perform the action when the period ends. If 
another trigger
--- happens during the cooldown, it has no effect.
+-- | Perform the action immediately, and then begin a cooldown period.
+-- If the trigger happens again during the cooldown, it is ignored.
+--
+-- Example of how this style debounce works:
+--
+-- > ! = function execution
+-- > . = cooldown period
+-- > X = debounced code execution
+-- >
+-- > !   !      !     !
+-- >  .......    .......
+-- > X          X
+--
+-- @since 0.1.6
+leadingMuteEdge :: DebounceEdge
+leadingMuteEdge = LeadingMute
+
+-- | Start a cooldown period and perform the action when the period ends.
+-- If another trigger happens during the cooldown, it has no effect.
+--
+-- Example of how this style debounce works:
+--
+-- @
+-- ! = function execution
+-- . = cooldown period
+-- X = debounced code execution
+--
+-- !     !     !  !
+--  .......     .......
+--         X           X
+-- @
 --
 -- @since 0.1.6
 trailingEdge :: DebounceEdge
 trailingEdge = Trailing
 
+-- | Start a cooldown period and perform the action when the period ends.
+-- If another trigger happens during the cooldown, it restarts the cooldown 
again.
+--
+-- /N.B. If a trigger happens DURING the 'debounceAction' it starts a new 
cooldown./
+-- /So if the 'debounceAction' takes longer than the 'debounceFreq', it might 
run/
+-- /again before the previous action has ended./
+--
+-- Example of how this style debounce works:
+--
+-- @
+-- ! = function execution
+-- . = cooldown period
+-- X = debounced code execution
+--
+-- !           !  !    !
+--  .......     ...............
+--         X                   X
+-- @
+--
+-- @since 0.1.6
+trailingDelayEdge :: DebounceEdge
+trailingDelayEdge = TrailingDelay
+
 mkDebounceInternal
     :: MVar () -> (Int -> IO ()) -> DebounceSettings -> IO (IO ())
-mkDebounceInternal baton delayFn (DebounceSettings freq action edge name) = do
-    tid <- mask_ $ forkIO $ forever $ do
-        takeMVar baton
-        case edge of
-            Leading -> do
-                ignoreExc action
-                delayFn freq
-            Trailing -> do
-                delayFn freq
-                -- Empty the baton of any other activations during the interval
-                void $ tryTakeMVar baton
-                ignoreExc action
-    labelThread tid name
-    return $ void $ tryPutMVar baton ()
+mkDebounceInternal baton delayFn (DebounceSettings freq action edge name) =
+    case edge of
+        Leading -> leadingDebounce <$> newEmptyMVar
+        LeadingMute -> pure leadingMuteDebounce
+        Trailing -> pure trailingDebounce
+        TrailingDelay -> trailingDelayDebounce <$> newTVarIO minBound
+  where
+    -- LEADING
+    --
+    --   1) try take baton to start
+    --   2) succes -> empty trigger & start worker, failed -> fill trigger
+    --   3) worker do action
+    --   4) delay
+    --   5) try take trigger
+    --   6) success -> repeat action, failed -> put baton back
+    leadingDebounce trigger = do
+        -- 1)
+        success <- tryTakeMVar baton
+        case success of
+            -- 2)
+            Nothing -> void $ tryPutMVar trigger ()
+            Just () -> do
+                void $ tryTakeMVar trigger
+                forkAndLabel loop
+      where
+        loop = do
+            -- 3)
+            ignoreExc action
+            -- 4)
+            delayFn freq
+            -- 5)
+            isTriggered <- tryTakeMVar trigger
+            case isTriggered of
+                -- 6)
+                Nothing -> putMVar baton ()
+                Just () -> loop
+    -- LEADING MUTE
+    --
+    --   1) try take baton to start
+    --   2) success -> start worker, failed -> die
+    --   3) worker delay
+    --   4) do action
+    --   5) put baton back
+    leadingMuteDebounce = do
+        -- 1)
+        success <- tryTakeMVar baton
+        case success of
+            -- 2)
+            Nothing -> pure ()
+            Just () ->
+                forkAndLabel $ do
+                    -- 3)
+                    ignoreExc action
+                    -- 4)
+                    delayFn freq
+                    -- 5)
+                    putMVar baton ()
+    -- TRAILING
+    --
+    --   1) try take baton to start
+    --   2) success -> start worker, failed -> die
+    --   3) worker delay
+    --   4) do action
+    --   5) put baton back
+    trailingDebounce = do
+        -- 1)
+        success <- tryTakeMVar baton
+        case success of
+            -- 2)
+            Nothing -> pure ()
+            Just () ->
+                forkAndLabel $ do
+                    -- 3)
+                    delayFn freq
+                    -- 4)
+                    ignoreExc action
+                    -- 5)
+                    putMVar baton ()
+        -- TRAILING DELAY
+        --
+        --   1) get current time -> /now/
+        --   2) try take baton to start
+        --   3) success -> set time var to /now/ & start worker, failed -> 
update time var to /now/
+        --   4) worker waits minimum delay
+        --   5) check diff of time var with /now/
+        --   6) less -> wait the difference, same/more -> do action
+        --   7) after action, recheck if there was any trigger
+        --   8) put baton back
+    trailingDelayDebounce timeTVar = do
+        -- 1)
+        now <- getMonotonicTimeNSec
+        -- 2)
+        success <- tryTakeMVar baton
+        case success of
+            -- 3)
+            Nothing -> atomically $ do
+                oldTime <- readTVar timeTVar
+                when (oldTime < now) $ writeTVar timeTVar now
+            Just () -> do
+                atomically $ writeTVar timeTVar now
+                forkAndLabel $ loop freq
+      where
+        loop delay = do
+            -- 4)
+            delayFn delay
+            lastTrigger <- readTVarIO timeTVar
+            now <- getMonotonicTimeNSec
+            -- 5)
+            let diff = fromIntegral (now - lastTrigger) `div` 1000
+                shouldWait = diff < freq
+            if shouldWait
+                -- 6)
+                then loop $ freq - diff
+                else do
+                    ignoreExc action
+                    timeAfterAction <- readTVarIO timeTVar
+                    -- 7)
+                    let wasTriggered = timeAfterAction > now
+                    if wasTriggered
+                        then do
+                            updatedNow <- getMonotonicTimeNSec
+                            let newDiff = fromIntegral (updatedNow - 
timeAfterAction) `div` 1000
+                            loop $ freq - newDiff
+                        -- 8)
+                        else putMVar baton ()
+    forkAndLabel act = do
+        tid <- mask_ $ forkIO act
+        labelThread tid name
 
 ignoreExc :: IO () -> IO ()
 ignoreExc = handle $ \(_ :: SomeException) -> return ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/auto-update-0.2.2/Control/Debounce.hs 
new/auto-update-0.2.4/Control/Debounce.hs
--- old/auto-update-0.2.2/Control/Debounce.hs   2001-09-09 03:46:40.000000000 
+0200
+++ new/auto-update-0.2.4/Control/Debounce.hs   2001-09-09 03:46:40.000000000 
+0200
@@ -23,23 +23,27 @@
 --
 -- @since 0.1.2
 module Control.Debounce (
-    -- * Type
+    -- * Creation
+    mkDebounce,
+
+    -- * Settings
     DI.DebounceSettings,
     defaultDebounceSettings,
 
-    -- * Accessors
+    -- ** Accessors
     DI.debounceFreq,
     DI.debounceAction,
     DI.debounceEdge,
     DI.debounceThreadName,
+
+    -- ** Edge types
     DI.leadingEdge,
+    DI.leadingMuteEdge,
     DI.trailingEdge,
-
-    -- * Creation
-    mkDebounce,
+    DI.trailingDelayEdge,
 ) where
 
-import Control.Concurrent (newEmptyMVar, threadDelay)
+import Control.Concurrent (newMVar, threadDelay)
 import qualified Control.Debounce.Internal as DI
 
 -- | Default value for creating a 'DebounceSettings'.
@@ -56,8 +60,11 @@
 
 -- | Generate an action which will trigger the debounced action to be 
performed.
 --
+-- /N.B. The generated action will always immediately return, regardless of 
the 'debounceFreq',/
+-- /as the debounced action (and the delay\/cooldown) is always performed in a 
separate thread./
+--
 -- @since 0.1.2
 mkDebounce :: DI.DebounceSettings -> IO (IO ())
 mkDebounce settings = do
-    baton <- newEmptyMVar
+    baton <- newMVar ()
     DI.mkDebounceInternal baton threadDelay settings
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/auto-update-0.2.2/Control/Reaper.hs 
new/auto-update-0.2.4/Control/Reaper.hs
--- old/auto-update-0.2.2/Control/Reaper.hs     2001-09-09 03:46:40.000000000 
+0200
+++ new/auto-update-0.2.4/Control/Reaper.hs     2001-09-09 03:46:40.000000000 
+0200
@@ -96,6 +96,11 @@
     --
     -- @since 0.1.1
     , reaperThreadName :: String
+    -- ^ Label of the thread spawned by the reaper.
+    --
+    -- Default: @"Reaper"@.
+    --
+    -- @since 0.2.2
     }
 
 -- | Default @ReaperSettings@ value, biased towards having a list of work
@@ -202,8 +207,12 @@
     !merge <- reaperAction wl
     -- Merging the left jobs and new jobs.
     -- If there is no jobs, this thread finishes.
-    next <- atomicModifyIORef' stateRef (check merge)
-    next
+    cont <- atomicModifyIORef' stateRef (check merge)
+    if cont
+        then
+            reaper settings stateRef tidRef
+        else
+            writeIORef tidRef Nothing
   where
     swapWithEmpty NoReaper = error "Control.Reaper.reaper: unexpected NoReaper 
(1)"
     swapWithEmpty (Workload wl) = (Workload reaperEmpty, wl)
@@ -211,9 +220,9 @@
     check _ NoReaper = error "Control.Reaper.reaper: unexpected NoReaper (2)"
     check merge (Workload wl)
         -- If there is no job, reaper is terminated.
-        | reaperNull wl' = (NoReaper, writeIORef tidRef Nothing)
+        | reaperNull wl' = (NoReaper, False)
         -- If there are jobs, carry them out.
-        | otherwise = (Workload wl', reaper settings stateRef tidRef)
+        | otherwise = (Workload wl', True)
       where
         wl' = merge wl
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/auto-update-0.2.2/auto-update.cabal 
new/auto-update-0.2.4/auto-update.cabal
--- old/auto-update-0.2.2/auto-update.cabal     2001-09-09 03:46:40.000000000 
+0200
+++ new/auto-update-0.2.4/auto-update.cabal     2001-09-09 03:46:40.000000000 
+0200
@@ -1,5 +1,5 @@
 name:                auto-update
-version:             0.2.2
+version:             0.2.4
 synopsis:            Efficiently run periodic, on-demand actions
 description:         API docs and the README are available at 
<http://www.stackage.org/package/auto-update>.
 homepage:            https://github.com/yesodweb/wai
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/auto-update-0.2.2/test/Control/DebounceSpec.hs 
new/auto-update-0.2.4/test/Control/DebounceSpec.hs
--- old/auto-update-0.2.2/test/Control/DebounceSpec.hs  2001-09-09 
03:46:40.000000000 +0200
+++ new/auto-update-0.2.4/test/Control/DebounceSpec.hs  2001-09-09 
03:46:40.000000000 +0200
@@ -1,14 +1,33 @@
+{-# LANGUAGE NumericUnderscores #-}
 module Control.DebounceSpec (main, spec) where
 
-import Control.Concurrent
-import Control.Debounce
+import Control.Concurrent (
+    MVar,
+    newEmptyMVar,
+    takeMVar,
+    putMVar,
+    newMVar,
+    threadDelay,
+    tryReadMVar,
+ )
+import Control.Debounce (
+    DebounceSettings(..),
+    leadingEdge,
+    leadingMuteEdge,
+    trailingEdge,
+    trailingDelayEdge,
+    defaultDebounceSettings,
+ )
 import qualified Control.Debounce.Internal as DI
-import Control.Monad
+import Control.Monad (void)
 import Control.Monad.Catch
-import Control.Retry
-import Data.IORef
-import Test.HUnit.Lang
-import Test.Hspec
+import Control.Retry (recovering, constantDelay, limitRetries)
+import Data.IORef (IORef, readIORef, newIORef, modifyIORef)
+import Data.Word (Word64)
+import GHC.Clock (getMonotonicTime)
+import Test.Hspec (Spec, describe, it, shouldReturn, hspec)
+import Test.HUnit (assertBool)
+import Test.HUnit.Lang (HUnitFailure (HUnitFailure))
 
 spec :: Spec
 spec = describe "mkDebounce" $ do
@@ -43,6 +62,39 @@
             returnFromWait
             pause
             readIORef ref `shouldReturn` 2
+    describe "LeadingMute edge" $ do
+        it "works for a single event" $ do
+            (ref, debounced, _baton, returnFromWait) <- getDebounce 
leadingMuteEdge
+
+            debounced
+            waitUntil 5 $ readIORef ref `shouldReturn` 1
+
+            returnFromWait
+            pause
+            readIORef ref `shouldReturn` 1
+
+            -- Try another round
+            debounced
+            waitUntil 5 $ readIORef ref `shouldReturn` 2
+
+            returnFromWait
+            pause
+            readIORef ref `shouldReturn` 2
+
+        it "works for multiple events" $ do
+            (ref, debounced, baton, returnFromWait) <- getDebounce 
leadingMuteEdge
+
+            debounced
+            waitForBatonToBeTaken baton
+            debounced
+            pause
+            debounced
+            waitUntil 5 $ readIORef ref `shouldReturn` 1
+            debounced
+
+            returnFromWait
+            pause
+            readIORef ref `shouldReturn` 1
 
     describe "Trailing edge" $ do
         it "works for a single event" $ do
@@ -50,7 +102,7 @@
 
             debounced
             pause
-            waitUntil 5 $ readIORef ref `shouldReturn` 0
+            readIORef ref `shouldReturn` 0
 
             returnFromWait
             waitUntil 5 $ readIORef ref `shouldReturn` 1
@@ -70,11 +122,54 @@
             waitForBatonToBeTaken baton
             debounced
             pause
-            waitUntil 5 $ readIORef ref `shouldReturn` 0
+            readIORef ref `shouldReturn` 0
 
             returnFromWait
             waitUntil 5 $ readIORef ref `shouldReturn` 1
 
+    describe "TrailingDelay edge" $ do
+        it "works for a single event" $ do
+            (ref, debounced, _baton, _returnFromWait) <- getDebounce' True 
trailingDelayEdge
+
+            debounced
+            readIORef ref `shouldReturn` 0
+
+            waitUntil 1 $ readIORef ref `shouldReturn` 1
+
+            -- Try another round
+            debounced
+            readIORef ref `shouldReturn` 1
+
+            waitUntil 1 $ readIORef ref `shouldReturn` 2
+
+        it "works for multiple events" $ do
+            (ref, debounced, _baton, _returnFromWait) <- getDebounce' True 
trailingDelayEdge
+
+            start <- getMonotonicTime
+
+            debounced
+            readIORef ref `shouldReturn` 0
+            -- Asserts at end check that this timing gets added to the 
cooldown time
+            threadDelay 500_000
+
+            readIORef ref `shouldReturn` 0
+            before2nd <- getMonotonicTime
+            debounced
+            readIORef ref `shouldReturn` 0
+            threadDelay 500_000
+
+            readIORef ref `shouldReturn` 0
+            threadDelay 250_000
+
+            readIORef ref `shouldReturn` 0
+
+            waitUntil 1 $ readIORef ref `shouldReturn` 1
+            end <- getMonotonicTime
+            assertBool "Took less than 1 sec after retrigger" $
+                end - before2nd > 1
+            assertBool "Took less than 1.5 sec total" $
+                end - start > 1.5
+
 -- | Make a controllable delay function
 getWaitAction :: IO (p -> IO (), IO ())
 getWaitAction = do
@@ -83,22 +178,28 @@
     let returnFromWait = putMVar waitVar ()
     return (waitAction, returnFromWait)
 
--- | Get a debounce system with access to the internals for testing
 getDebounce :: DI.DebounceEdge -> IO (IORef Int, IO (), MVar (), IO ())
-getDebounce edge = do
+getDebounce = getDebounce' False
+
+-- | Get a debounce system with access to the internals for testing
+getDebounce' :: Bool -> DI.DebounceEdge -> IO (IORef Int, IO (), MVar (), IO 
())
+getDebounce' useThreadDelay edge = do
     ref <- newIORef 0
     let action = modifyIORef ref (+ 1)
 
-    (waitAction, returnFromWait) <- getWaitAction
+    (waitAction, returnFromWait) <-
+        if useThreadDelay
+            then pure (threadDelay, pure ())
+            else getWaitAction
 
-    baton <- newEmptyMVar
+    baton <- newMVar ()
 
     debounced <-
         DI.mkDebounceInternal
             baton
             waitAction
             defaultDebounceSettings
-                { debounceFreq = 5000000 -- unused
+                { debounceFreq = 1_000_000 -- !!! used in 'TrailingDelay' test
                 , debounceAction = action
                 , debounceEdge = edge
                 }
@@ -107,14 +208,16 @@
 
 -- | Pause briefly (100ms)
 pause :: IO ()
-pause = threadDelay 100000
+pause = threadDelay 100_000
 
 waitForBatonToBeTaken :: MVar () -> IO ()
-waitForBatonToBeTaken baton = waitUntil 5 $ tryReadMVar baton `shouldReturn` 
Nothing
+waitForBatonToBeTaken baton =
+    waitUntil 5 $ tryReadMVar baton `shouldReturn` Nothing
 
 -- | Wait up to n seconds for an action to complete without throwing an 
HUnitFailure
 waitUntil :: Int -> IO a -> IO ()
-waitUntil n action = recovering policy [handler] (\_status -> void action)
+waitUntil n action =
+    recovering policy [handler] (\_status -> void action)
   where
     policy = constantDelay 1000 `mappend` limitRetries (n * 1000) -- 1ms * n * 
1000 tries = n seconds
     handler _status = Handler (\HUnitFailure{} -> return True)

Reply via email to