Explicitly import either asyncdispatch or chronos version

Reorganizes the code into separate versions for asyncdispatch and
chronos so that we no longer have to rely on hard-to-maintain code
that implicitly works with both asyncdispatch and chronos.

This is a backwards incompatible change.
This commit is contained in:
Mark Spanbroek 2023-12-21 10:01:45 +01:00 committed by markspanbroek
parent c9423b198f
commit 90c1b35b67
20 changed files with 126 additions and 99 deletions

View File

@ -1,3 +0,0 @@
import ./asynctest/unittest
export unittest

View File

@ -0,0 +1,10 @@
import std/asyncdispatch
import std/unittest
import ../private/asyncdispatch/eventually
import ../private/asyncdispatch/runasync
export asyncdispatch
export unittest except suite, test
export eventually
include ../private/suite

View File

@ -0,0 +1,10 @@
import std/asyncdispatch
import pkg/unittest2
import ../private/asyncdispatch/eventually
import ../private/asyncdispatch/runasync
export asyncdispatch
export unittest2 except suite, test
export eventually
include ../private/suite

View File

@ -0,0 +1,10 @@
import pkg/chronos
import std/unittest
import ../private/chronos/eventually
import ../private/chronos/unittest/runasync
export chronos
export unittest except suite, test
export eventually
include ../private/suite

View File

@ -0,0 +1,10 @@
import pkg/chronos
import pkg/unittest2
import ../private/chronos/eventually
import ../private/chronos/unittest2/runasync
export chronos
export unittest2 except suite, test
export eventually
include ../private/suite

View File

@ -1,19 +1,14 @@
import std/times except milliseconds
import std/asyncdispatch
import std/times
template eventually*(expression: untyped, timeout=5000): bool =
template sleep(millis: int): auto =
when compiles(await sleepAsync(millis.milliseconds)):
sleepAsync(millis.milliseconds) # chronos
else:
sleepAsync(millis) # asyncdispatch
proc eventually: Future[bool] {.async.} =
let endTime = getTime() + initDuration(milliseconds=timeout)
while not expression:
if endTime < getTime():
return false
await sleep(10)
await sleepAsync(10)
return true
await eventually()

View File

@ -0,0 +1,5 @@
import std/asyncdispatch
template runAsync*(body): untyped =
let asyncProc = proc {.async.} = body
waitFor asyncProc()

View File

@ -0,0 +1,13 @@
import pkg/chronos
template eventually*(expression: untyped, timeout=5000): bool =
proc eventually: Future[bool] {.async.} =
let endTime = Moment.now() + timeout.milliseconds
while not expression:
if endTime < Moment.now():
return false
await sleepAsync(10.milliseconds)
return true
await eventually()

View File

@ -0,0 +1,14 @@
import pkg/chronos
import pkg/chronos/config
when compiles(config.chronosHandleException): # detect chronos v4
template runAsync*(body): untyped =
let asyncProc = proc {.async: (raises: [Exception]).} = body
waitFor asyncProc()
else:
template runAsync*(body): untyped =
let asyncProc = proc {.async.} = body
waitFor asyncProc()

View File

@ -0,0 +1,5 @@
import pkg/chronos
template runAsync*(body): untyped =
let asyncProc = proc {.async.} = body
waitFor asyncProc()

View File

@ -0,0 +1,34 @@
template suite*(name, body) =
suite name:
let suiteproc = proc =
## Runs before all tests in the suite
template setupAll(setupAllBody) {.used.} =
runAsync setupAllBody
## Runs after all tests in the suite
template teardownAll(teardownAllBody) {.used.} =
template teardownAllIMPL: untyped {.inject.} =
runAsync teardownAllBody
template setup(setupBody) {.used.} =
setup:
runAsync setupBody
template teardown(teardownBody) {.used.} =
teardown:
let exception = getCurrentException()
runAsync teardownBody
setCurrentException(exception)
body
when declared(teardownAllIMPL):
teardownAllIMPL()
suiteproc()
template test*(name, body) =
test name:
runAsync body

View File

@ -1,58 +0,0 @@
template launderExceptions(body: typed) =
## Chronos V4 requires that all procs which raise Exception annotate it
## with {.async: (raises: [Exception]).}, but this construct does not
## exist in asyncdispatch. We therefore launder all real instances of
## Exception into CatchableError and make Chronos happy while not losing
## context information for the remainder of the exception types.
{.push warning[BareExcept]:off.}
try:
{.push warning[BareExcept]:on.}
body
{.pop.}
except Defect as ex:
raise ex
except CatchableError as ex:
raise ex
except Exception as ex:
raise newException(Defect, ex.msg, ex)
{.pop.}
template suite*(name, body) =
suite name:
let suiteproc = proc = # Avoids GcUnsafe2 warnings with chronos
## Runs before all tests in the suite
template setupAll(setupAllBody) {.used.} =
let b = proc {.async.} = launderExceptions: setupAllBody
waitFor b()
## Runs after all tests in the suite
template teardownAll(teardownAllBody) {.used.} =
template teardownAllIMPL: untyped {.inject.} =
let a = proc {.async.} = launderExceptions: teardownAllBody
waitFor a()
template setup(setupBody) {.used.} =
setup:
let asyncproc = proc {.async.} = launderExceptions: setupBody
waitFor asyncproc()
template teardown(teardownBody) {.used.} =
teardown:
let exception = getCurrentException()
let asyncproc = proc {.async.} = launderExceptions: teardownBody
waitFor asyncproc()
setCurrentException(exception)
body
when declared(teardownAllIMPL):
teardownAllIMPL()
suiteproc()
template test*(name, body) =
test name:
let asyncproc = proc {.async.} = launderExceptions: body
waitFor asyncproc()

View File

@ -1,7 +0,0 @@
import std/unittest
import ./eventually
export unittest except suite, test
export eventually
include ./templates

View File

@ -1,7 +0,0 @@
import pkg/unittest2
import ./eventually
export unittest2 except suite, test
export eventually
include ./templates

View File

@ -1,5 +1,4 @@
import pkg/asynctest
import pkg/chronos
import pkg/asynctest/chronos/unittest
include ../stdlib/testbody
include ../stdlib/testfail
include ../common/testbody
include ../common/testfail

View File

@ -1,5 +1,4 @@
import pkg/asynctest
import pkg/chronos
import pkg/asynctest/chronos/unittest
include ../stdlib/testbody
include ../stdlib/testfail
include ../common/testbody
include ../common/testfail

View File

@ -1,5 +1,4 @@
import std/asyncdispatch
import pkg/asynctest
import pkg/asynctest/asyncdispatch/unittest
include ./testbody
include ./testfail
include ../common/testbody
include ../common/testfail

View File

@ -1,5 +1,4 @@
import pkg/asynctest/unittest2
import pkg/chronos
import pkg/asynctest/asyncdispatch/unittest2
include ../stdlib/testbody
include ../stdlib/testfail
include ../common/testbody
include ../common/testfail