Skip to content

Commit 91a23d5

Browse files
committed
feat: add tests for location of wait call annotation
1 parent e84ad66 commit 91a23d5

3 files changed

Lines changed: 41 additions & 5 deletions

File tree

Control/Concurrent/Async.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ module Control.Concurrent.Async (
185185
-- ** Linking
186186
link, linkOnly, link2, link2Only, ExceptionInLinkedThread(..),
187187

188+
-- ** Exception annotations
189+
AsyncWaitLocation(..)
190+
188191
) where
189192

190193
import Control.Concurrent.Async.Internal

Control/Concurrent/Async/Internal.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,12 @@ rethrowIO' e =
265265
rethrowIO' = throwIO
266266
#endif
267267

268-
#if MIN_VERSION_base(4,21,0)
269268
-- | An exception annotation which stores the callstack of a 'wait',
270269
-- 'waitBoth', 'waitEither' call.
271270
data AsyncWaitLocation = AsyncWaitLocation CallStack
272271
deriving (Show)
273272

273+
#if MIN_VERSION_base(4,21,0)
274274
instance ExceptionAnnotation AsyncWaitLocation where
275275
displayExceptionAnnotation (AsyncWaitLocation callstack) = "AsyncWaitLocation " <> prettyCallStack callstack
276276

test/test-async.hs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ import Data.Maybe
2323

2424
import Prelude hiding (catch)
2525
#if MIN_VERSION_base(4,21,0)
26-
import Control.Exception.Annotation (ExceptionAnnotation(..))
27-
import Control.Exception.Context (displayExceptionContext, getExceptionAnnotations)
28-
import Control.Exception.Backtrace (Backtraces, displayBacktraces)
26+
import Control.Exception.Annotation
27+
import Control.Exception.Context
28+
import Control.Exception.Backtrace
2929
#endif
3030
import GHC.Stack (HasCallStack)
31+
import Debug.Trace
3132

3233
main = defaultMain tests
3334

@@ -631,7 +632,39 @@ exception_rethrow = [
631632
wait a,
632633
testCase "withAsync inside" $ compareTwoExceptions $ \action -> do
633634
withAsync doForever $ \a -> do
634-
action
635+
action,
636+
637+
testCase "withAsync does not wrap with WhileHandling and contain an asyncWaitLocation" $ do
638+
-- This test is fragile. It checks that when calling `wait` on an async,
639+
-- we end up with at least two interesting annotations: the backtrace
640+
-- which shows the localisation of the exception thrown in the async, and
641+
-- an AsyncWaitLocation which shows the location of the wait call.
642+
--
643+
-- It also checks that no other annotation are provided (for example, a
644+
-- "WhileHandling")
645+
--
646+
-- However, this can change in future GHC version, for example, new
647+
-- annotations may be added, or Backtraces may change its type / name.
648+
-- Also, depending on the build configuration, maybe there will have
649+
-- other backtraces (such as DWARF or IPE, ...)
650+
e <- tryWithContext $ do
651+
withAsync (throwIO Exc) $ \async -> do
652+
wait async
653+
case e of
654+
Right () -> fail "should have raised an exception"
655+
Left (ExceptionWithContext (ExceptionContext annotations) Exc) -> do
656+
assertEqual "Only two annotations" (length annotations) 2
657+
assertBool "Has AsyncWaitLocation annotation" (any isAsyncWaitLocation annotations)
658+
assertBool "Has Backtraces annotation" (any isBacktraces annotations)
635659
]
660+
661+
isAsyncWaitLocation (SomeExceptionAnnotation ann) = case cast ann of
662+
Just (AsyncWaitLocation _) -> True
663+
_ -> traceShow (typeOf ann) False
664+
665+
isBacktraces (SomeExceptionAnnotation ann) = case cast ann of
666+
Just (_ :: Backtraces) -> True
667+
_ -> False
668+
636669
#endif
637670

0 commit comments

Comments
 (0)