summary refs log tree commit diff stats
path: root/tests/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'tests/stdlib')
-rw-r--r--tests/stdlib/concurrency/atomicSample.nim9
-rw-r--r--tests/stdlib/concurrency/tatomic_import.nim11
-rw-r--r--tests/stdlib/concurrency/tatomics.nim637
-rw-r--r--tests/stdlib/concurrency/tatomics_size.nim21
-rw-r--r--tests/stdlib/config.nims5
-rw-r--r--tests/stdlib/genericstrformat.nim16
-rw-r--r--tests/stdlib/mgenast.nim57
-rw-r--r--tests/stdlib/mimportutils.nim38
-rw-r--r--tests/stdlib/mintsets.nim11
-rw-r--r--tests/stdlib/mstackframes.nim38
-rw-r--r--tests/stdlib/nre/captures.nim47
-rw-r--r--tests/stdlib/nre/escape.nim4
-rw-r--r--tests/stdlib/nre/find.nim12
-rw-r--r--tests/stdlib/nre/init.nim10
-rw-r--r--tests/stdlib/nre/match.nim14
-rw-r--r--tests/stdlib/nre/misc.nim10
-rw-r--r--tests/stdlib/nre/replace.nim14
-rw-r--r--tests/stdlib/nre/split.nim14
-rw-r--r--tests/stdlib/osproctest.nim8
-rw-r--r--tests/stdlib/somesql.sql2
-rw-r--r--tests/stdlib/t10231.nim16
-rw-r--r--tests/stdlib/t14139.nim10
-rw-r--r--tests/stdlib/t15663.nim9
-rw-r--r--tests/stdlib/t19304.nim7
-rw-r--r--tests/stdlib/t20023.nim10
-rw-r--r--tests/stdlib/t21251.nim6
-rw-r--r--tests/stdlib/t21406.nim7
-rw-r--r--tests/stdlib/t21564.nim32
-rw-r--r--tests/stdlib/t7686.nim10
-rw-r--r--tests/stdlib/t8925.nim16
-rw-r--r--tests/stdlib/t9754.nim6
-rw-r--r--tests/stdlib/talgorithm.nim275
-rw-r--r--tests/stdlib/tarithmetics.nim50
-rw-r--r--tests/stdlib/tasynchttpserver.nim121
-rw-r--r--tests/stdlib/tasynchttpserver_transferencoding.nim91
-rw-r--r--tests/stdlib/tbase64.nim63
-rw-r--r--tests/stdlib/tbitops.nim435
-rw-r--r--tests/stdlib/tbitops.nim.cfg2
-rw-r--r--tests/stdlib/tbitops2.nim168
-rw-r--r--tests/stdlib/tbitops2.nim.cfg2
-rw-r--r--tests/stdlib/tbitops_utils.nim19
-rw-r--r--tests/stdlib/tbug5382.nim11
-rw-r--r--tests/stdlib/tcasts.nim26
-rw-r--r--tests/stdlib/tcgi.nim31
-rw-r--r--tests/stdlib/tclosures.nim47
-rw-r--r--tests/stdlib/tcmdline.nim13
-rw-r--r--tests/stdlib/tcomplex.nim115
-rw-r--r--tests/stdlib/tcookies.nim22
-rw-r--r--tests/stdlib/tcount.nim29
-rw-r--r--tests/stdlib/tcputime.nim13
-rw-r--r--tests/stdlib/tcritbits.nim91
-rw-r--r--tests/stdlib/tcstring.nim93
-rw-r--r--tests/stdlib/tcstrutils.nim39
-rw-r--r--tests/stdlib/tdb.nim0
-rw-r--r--tests/stdlib/tdb.nims1
-rw-r--r--tests/stdlib/tdb_mysql.nim0
-rw-r--r--tests/stdlib/tdecls.nim50
-rw-r--r--tests/stdlib/tdecode_helpers.nim27
-rw-r--r--tests/stdlib/tdeques.nim243
-rw-r--r--tests/stdlib/tdiff.nim75
-rw-r--r--tests/stdlib/tdistros_detect.nim16
-rw-r--r--tests/stdlib/tdochelpers.nim221
-rw-r--r--tests/stdlib/techo.nim3
-rw-r--r--tests/stdlib/teditdistance.nim45
-rw-r--r--tests/stdlib/tencodings.nim107
-rw-r--r--tests/stdlib/tenumerate.nim24
-rw-r--r--tests/stdlib/tenumutils.nim49
-rw-r--r--tests/stdlib/tenvvars.nim162
-rw-r--r--tests/stdlib/testequivalence.nim14
-rw-r--r--tests/stdlib/texitprocs.nim22
-rw-r--r--tests/stdlib/tfdleak.nim152
-rw-r--r--tests/stdlib/tfdleak_multiple.nim31
-rw-r--r--tests/stdlib/tfenv.nim8
-rw-r--r--tests/stdlib/tfilesanddirs.nim36
-rw-r--r--tests/stdlib/tformat.nim12
-rw-r--r--tests/stdlib/tfrexp1.nim23
-rw-r--r--tests/stdlib/tgenast.nim274
-rw-r--r--tests/stdlib/tgetaddrinfo.nim38
-rw-r--r--tests/stdlib/tgetfileinfo.nim38
-rw-r--r--tests/stdlib/tgetprotobyname.nim19
-rw-r--r--tests/stdlib/tglobs.nim25
-rw-r--r--tests/stdlib/thashes.nim250
-rw-r--r--tests/stdlib/theapqueue.nim106
-rw-r--r--tests/stdlib/thighlite.nim45
-rw-r--r--tests/stdlib/thtmlparser.nim159
-rw-r--r--tests/stdlib/thtmlparser2813.nim45
-rw-r--r--tests/stdlib/thtmlparser2814.nim44
-rw-r--r--tests/stdlib/thttpclient.nim118
-rw-r--r--tests/stdlib/thttpclient_ssl.nim150
-rw-r--r--tests/stdlib/thttpclient_ssl_cert.pem29
-rw-r--r--tests/stdlib/thttpclient_ssl_key.pem52
-rw-r--r--tests/stdlib/thttpclient_standalone.nim59
-rw-r--r--tests/stdlib/thttpcore.nim117
-rw-r--r--tests/stdlib/timportutils.nim151
-rw-r--r--tests/stdlib/tintsets.nim6
-rw-r--r--tests/stdlib/tio.nim94
-rw-r--r--tests/stdlib/tisolation.nim135
-rw-r--r--tests/stdlib/tjsbigints.nim46
-rw-r--r--tests/stdlib/tjson.nim382
-rw-r--r--tests/stdlib/tjsonexternproc.nim8
-rw-r--r--tests/stdlib/tjsonmacro.nim286
-rw-r--r--tests/stdlib/tjsonmacro_reject.nim4
-rw-r--r--tests/stdlib/tjsonmacro_reject2.nim21
-rw-r--r--tests/stdlib/tjsontestsuite.nim4
-rw-r--r--tests/stdlib/tjsonutils.nim476
-rw-r--r--tests/stdlib/tlists.nim297
-rw-r--r--tests/stdlib/tlocks.nim7
-rw-r--r--tests/stdlib/tlwip.nim30
-rw-r--r--tests/stdlib/tmacros.nim349
-rw-r--r--tests/stdlib/tmarshal.nim246
-rw-r--r--tests/stdlib/tmarshalsegfault.nim54
-rw-r--r--tests/stdlib/tmath.nim545
-rw-r--r--tests/stdlib/tmath2.nim85
-rw-r--r--tests/stdlib/tmemfiles1.nim7
-rw-r--r--tests/stdlib/tmemfiles2.nim15
-rw-r--r--tests/stdlib/tmemlines.nim6
-rw-r--r--tests/stdlib/tmemlinesBuf.nim11
-rw-r--r--tests/stdlib/tmemmapstreams.nim6
-rw-r--r--tests/stdlib/tmemslices.nim8
-rw-r--r--tests/stdlib/tmersenne.nim13
-rw-r--r--tests/stdlib/tmget.nim27
-rw-r--r--tests/stdlib/tmimetypes.nim28
-rw-r--r--tests/stdlib/tmisc_issues.nim39
-rw-r--r--tests/stdlib/tmitems.nim32
-rw-r--r--tests/stdlib/tmonotimes.nim22
-rw-r--r--tests/stdlib/tnativesockets.nim34
-rw-r--r--tests/stdlib/tnet.nim77
-rw-r--r--tests/stdlib/tnet_ll.nim94
-rw-r--r--tests/stdlib/tnetbind.nim25
-rw-r--r--tests/stdlib/tnetconnect.nim30
-rw-r--r--tests/stdlib/tnetdial.nim9
-rw-r--r--tests/stdlib/tnilecho.nim2
-rw-r--r--tests/stdlib/tnre.nim20
-rw-r--r--tests/stdlib/tntpath.nim50
-rw-r--r--tests/stdlib/tobjectdollar.nim14
-rw-r--r--tests/stdlib/toids.nim15
-rw-r--r--tests/stdlib/topenssl.nim46
-rw-r--r--tests/stdlib/toptions.nim207
-rw-r--r--tests/stdlib/torderedtable.nim18
-rw-r--r--tests/stdlib/tos.nim916
-rw-r--r--tests/stdlib/tos_unc.nim11
-rw-r--r--tests/stdlib/tosenv.nim163
-rw-r--r--tests/stdlib/toserrors.nim9
-rw-r--r--tests/stdlib/tosproc.nim316
-rw-r--r--tests/stdlib/tosprocterminate.nim35
-rw-r--r--tests/stdlib/tpackedsets.nim265
-rw-r--r--tests/stdlib/tparscfg.nim69
-rw-r--r--tests/stdlib/tparsecfg.nim149
-rw-r--r--tests/stdlib/tparsecsv.nim36
-rw-r--r--tests/stdlib/tparseipv6.nim95
-rw-r--r--tests/stdlib/tparsesql.nim123
-rw-r--r--tests/stdlib/tparseuints.nim16
-rw-r--r--tests/stdlib/tparseutils.nim112
-rw-r--r--tests/stdlib/tparsopt.nim12
-rw-r--r--tests/stdlib/tpathnorm.nim36
-rw-r--r--tests/stdlib/tpaths.nim238
-rw-r--r--tests/stdlib/tpegs.nim350
-rw-r--r--tests/stdlib/tpermutations.nim19
-rw-r--r--tests/stdlib/tposix.nim74
-rw-r--r--tests/stdlib/tprelude.nim16
-rw-r--r--tests/stdlib/tquit.nim6
-rw-r--r--tests/stdlib/trandom.nim310
-rw-r--r--tests/stdlib/trat_float.nim9
-rw-r--r--tests/stdlib/trat_init.nim14
-rw-r--r--tests/stdlib/trationals.nim117
-rw-r--r--tests/stdlib/tre.nim122
-rw-r--r--tests/stdlib/treadln.nim23
-rw-r--r--tests/stdlib/tregex.nim6
-rw-r--r--tests/stdlib/tregistry.nim16
-rw-r--r--tests/stdlib/treguse.nim27
-rw-r--r--tests/stdlib/treloop.nim9
-rw-r--r--tests/stdlib/trepr.nim349
-rw-r--r--tests/stdlib/trepr2.nim32
-rw-r--r--tests/stdlib/trlocks.nim14
-rw-r--r--tests/stdlib/tropes.nim104
-rw-r--r--tests/stdlib/trst.nim1994
-rw-r--r--tests/stdlib/trstgen.nim1587
-rw-r--r--tests/stdlib/tsegfaults.nim29
-rw-r--r--tests/stdlib/tsequtils.nim547
-rw-r--r--tests/stdlib/tsetutils.nim49
-rw-r--r--tests/stdlib/tsharedlist.nim49
-rw-r--r--tests/stdlib/tsharedtable.nim90
-rw-r--r--tests/stdlib/tsince.nim32
-rw-r--r--tests/stdlib/tsinglylinkedring.nim29
-rw-r--r--tests/stdlib/tsocketstreams.nim65
-rw-r--r--tests/stdlib/tsortcall.nim66
-rw-r--r--tests/stdlib/tsplit.nim20
-rw-r--r--tests/stdlib/tsplit2.nim19
-rw-r--r--tests/stdlib/tsqlitebindatas.nim0
-rw-r--r--tests/stdlib/tsqlparser.nim3
-rw-r--r--tests/stdlib/tssl.nim138
-rw-r--r--tests/stdlib/tssl.nims5
-rw-r--r--tests/stdlib/tstackframes.nim34
-rw-r--r--tests/stdlib/tstaticos.nim8
-rw-r--r--tests/stdlib/tstats.nim61
-rw-r--r--tests/stdlib/tstdlib_issues.nim110
-rw-r--r--tests/stdlib/tstdlib_various.nim240
-rw-r--r--tests/stdlib/tstrbasics.nim103
-rw-r--r--tests/stdlib/tstreams.nim112
-rw-r--r--tests/stdlib/tstreams2.nim13
-rw-r--r--tests/stdlib/tstreams3.nim10
-rw-r--r--tests/stdlib/tstrformat.nim640
-rw-r--r--tests/stdlib/tstrformatlineinfo.nim8
-rw-r--r--tests/stdlib/tstrimpl.nim12
-rw-r--r--tests/stdlib/tstring.nim199
-rw-r--r--tests/stdlib/tstrmiscs.nim27
-rw-r--r--tests/stdlib/tstrscans.nim288
-rw-r--r--tests/stdlib/tstrset.nim16
-rw-r--r--tests/stdlib/tstrtabs.nim109
-rw-r--r--tests/stdlib/tstrtabs.nims5
-rw-r--r--tests/stdlib/tstrtabs2.nim32
-rw-r--r--tests/stdlib/tstrutil.nim306
-rw-r--r--tests/stdlib/tstrutils.nim913
-rw-r--r--tests/stdlib/tsugar.nim310
-rw-r--r--tests/stdlib/tsums.nim27
-rw-r--r--tests/stdlib/tsysrand.nim34
-rw-r--r--tests/stdlib/tsystem.nim200
-rw-r--r--tests/stdlib/ttables.nim316
-rw-r--r--tests/stdlib/ttasks.nim561
-rw-r--r--tests/stdlib/ttempfiles.nim51
-rw-r--r--tests/stdlib/tterminal.nim7
-rw-r--r--tests/stdlib/tterminal_12759.nim11
-rw-r--r--tests/stdlib/tterminal_15874.nim8
-rw-r--r--tests/stdlib/ttestutils.nim40
-rw-r--r--tests/stdlib/tthreadpool.nim14
-rw-r--r--tests/stdlib/ttimes.nim817
-rw-r--r--tests/stdlib/ttypeinfo.nim93
-rw-r--r--tests/stdlib/ttypeinfo.nims1
-rw-r--r--tests/stdlib/ttypetraits.nim94
-rw-r--r--tests/stdlib/tunicode.nim228
-rw-r--r--tests/stdlib/tunidecode.nim9
-rw-r--r--tests/stdlib/tunittest.nim126
-rw-r--r--tests/stdlib/tunittest_error.nim22
-rw-r--r--tests/stdlib/tunittestpass.nim20
-rw-r--r--tests/stdlib/tunittesttemplate.nim25
-rw-r--r--tests/stdlib/tunixsocket.nim35
-rw-r--r--tests/stdlib/turi.nim323
-rw-r--r--tests/stdlib/tuserlocks.nim21
-rw-r--r--tests/stdlib/tvarargs.nim18
-rw-r--r--tests/stdlib/tvarints.nim73
-rw-r--r--tests/stdlib/tvmutils.nim31
-rw-r--r--tests/stdlib/tvolatile.nim15
-rw-r--r--tests/stdlib/twalker.nim13
-rw-r--r--tests/stdlib/twchartoutf8.nim7
-rw-r--r--tests/stdlib/twith.nim44
-rw-r--r--tests/stdlib/twordwrap.nim48
-rw-r--r--tests/stdlib/twrapnils.nim224
-rw-r--r--tests/stdlib/twrongstattype.nim14
-rw-r--r--tests/stdlib/txmlgen.nim12
-rw-r--r--tests/stdlib/txmltree.nim131
-rw-r--r--tests/stdlib/tyield.nim258
-rw-r--r--tests/stdlib/unixsockettest.nim26
-rw-r--r--tests/stdlib/uselocks.nim5
253 files changed, 23849 insertions, 2482 deletions
diff --git a/tests/stdlib/concurrency/atomicSample.nim b/tests/stdlib/concurrency/atomicSample.nim
new file mode 100644
index 000000000..d56d867df
--- /dev/null
+++ b/tests/stdlib/concurrency/atomicSample.nim
@@ -0,0 +1,9 @@
+import atomics
+
+type
+  AtomicWithGeneric*[T] = object
+    value: Atomic[T]
+
+proc initAtomicWithGeneric*[T](value: T): AtomicWithGeneric[T] =
+  result.value.store(value)
+
diff --git a/tests/stdlib/concurrency/tatomic_import.nim b/tests/stdlib/concurrency/tatomic_import.nim
new file mode 100644
index 000000000..e8faaae20
--- /dev/null
+++ b/tests/stdlib/concurrency/tatomic_import.nim
@@ -0,0 +1,11 @@
+import atomicSample
+
+block crossFileObjectContainingAGenericWithAComplexObject:
+  discard initAtomicWithGeneric[string]("foo")
+
+block crossFileObjectContainingAGenericWithAnInteger:
+  discard initAtomicWithGeneric[int](1)
+  discard initAtomicWithGeneric[int8](1)
+  discard initAtomicWithGeneric[int16](1)
+  discard initAtomicWithGeneric[int32](1)
+  discard initAtomicWithGeneric[int64](1)
diff --git a/tests/stdlib/concurrency/tatomics.nim b/tests/stdlib/concurrency/tatomics.nim
new file mode 100644
index 000000000..08f2e7d3e
--- /dev/null
+++ b/tests/stdlib/concurrency/tatomics.nim
@@ -0,0 +1,637 @@
+discard """
+  # test C with -d:nimUseCppAtomics as well to check nothing breaks
+  matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
+  targets: "c cpp"
+"""
+
+# test atomic operations
+
+import std/[atomics, bitops]
+import std/assertions
+
+
+type
+  Object = object
+    val: int
+
+
+# Atomic operations for trivial objects
+
+
+block trivialLoad:
+  var location: Atomic[int]
+  location.store(1)
+  doAssert location.load == 1
+  location.store(2)
+  doAssert location.load(moRelaxed) == 2
+  location.store(3)
+  doAssert location.load(moAcquire) == 3
+
+
+block trivialStore:
+  var location: Atomic[int]
+  location.store(1)
+  doAssert location.load == 1
+  location.store(2, moRelaxed)
+  doAssert location.load == 2
+  location.store(3, moRelease)
+  doAssert location.load == 3
+
+
+block trivialExchange:
+  var location: Atomic[int]
+  location.store(1)
+  doAssert location.exchange(2) == 1
+  doAssert location.exchange(3, moRelaxed) == 2
+  doAssert location.exchange(4, moAcquire) == 3
+  doAssert location.exchange(5, moRelease) == 4
+  doAssert location.exchange(6, moAcquireRelease) == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchange(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchange(expected, 3, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchange(expected, 4, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchange(expected, 5, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchange(expected, 6, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchange(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 3, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 4, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 5, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 6, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+block trivialCompareExchangeSuccessFailureDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchange(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchange(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchange(expected, 5, moRelease, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeSuccessFailureDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 5, moRelease, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+block trivialCompareExchangeWeakDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchangeWeak(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchangeWeak(expected, 3, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchangeWeak(expected, 4, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchangeWeak(expected, 5, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeWeakDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchangeWeak(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 3, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 4, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 5, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+block trivialCompareExchangeWeakSuccessFailureDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchangeWeak(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchangeWeak(expected, 5, moRelease, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeWeakSuccessFailureDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 5, moRelease, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+# Atomic operations for non-trivial objects
+
+
+block objectLoad:
+  var location: Atomic[Object]
+  location.store(Object(val: 1))
+  doAssert location.load == Object(val: 1)
+  location.store(Object(val: 2))
+  doAssert location.load(moRelaxed) == Object(val: 2)
+  location.store(Object(val: 3))
+  doAssert location.load(moAcquire) == Object(val: 3)
+
+
+block objectStore:
+  var location: Atomic[Object]
+  location.store(Object(val: 1))
+  doAssert location.load == Object(val: 1)
+  location.store(Object(val: 2), moRelaxed)
+  doAssert location.load == Object(val: 2)
+  location.store(Object(val: 3), moRelease)
+  doAssert location.load == Object(val: 3)
+
+
+block objectExchange:
+  var location: Atomic[Object]
+  location.store(Object(val: 1))
+  doAssert location.exchange(Object(val: 2)) == Object(val: 1)
+  doAssert location.exchange(Object(val: 3), moRelaxed) == Object(val: 2)
+  doAssert location.exchange(Object(val: 4), moAcquire) == Object(val: 3)
+  doAssert location.exchange(Object(val: 5), moRelease) == Object(val: 4)
+  doAssert location.exchange(Object(val: 6), moAcquireRelease) == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchange(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchange(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchange(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchange(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchange(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+block objectCompareExchangeSuccessFailureDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchange(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeSuccessFailureDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+block objectCompareExchangeWeakDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchangeWeak(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeWeakDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchangeWeak(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+block objectCompareExchangeWeakSuccessFailureDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeWeakSuccessFailureDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+# Numerical operations
+
+
+block fetchAdd:
+  var location: Atomic[int]
+  doAssert location.fetchAdd(1) == 0
+  doAssert location.fetchAdd(1, moRelaxed) == 1
+  doAssert location.fetchAdd(1, moRelease) == 2
+  doAssert location.load == 3
+
+
+block fetchSub:
+  var location: Atomic[int]
+  doAssert location.fetchSub(1) == 0
+  doAssert location.fetchSub(1, moRelaxed) == -1
+  doAssert location.fetchSub(1, moRelease) == -2
+  doAssert location.load == -3
+
+
+block fetchAnd:
+  var location: Atomic[int]
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchAnd(j) == i)
+      doAssert(location.load == i.bitand(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchAnd(j, moRelaxed) == i)
+      doAssert(location.load == i.bitand(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchAnd(j, moRelease) == i)
+      doAssert(location.load == i.bitand(j))
+
+
+block fetchOr:
+  var location: Atomic[int]
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchOr(j) == i)
+      doAssert(location.load == i.bitor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchOr(j, moRelaxed) == i)
+      doAssert(location.load == i.bitor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchOr(j, moRelease) == i)
+      doAssert(location.load == i.bitor(j))
+
+
+block fetchXor:
+  var location: Atomic[int]
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchXor(j) == i)
+      doAssert(location.load == i.bitxor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchXor(j, moRelaxed) == i)
+      doAssert(location.load == i.bitxor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchXor(j, moRelease) == i)
+      doAssert(location.load == i.bitxor(j))
+
+
+block atomicInc:
+  var location: Atomic[int]
+  location.atomicInc
+  doAssert location.load == 1
+  location.atomicInc(1)
+  doAssert location.load == 2
+  location += 1
+  doAssert location.load == 3
+
+
+block atomicDec:
+  var location: Atomic[int]
+  location.atomicDec
+  doAssert location.load == -1
+  location.atomicDec(1)
+  doAssert location.load == -2
+  location -= 1
+  doAssert location.load == -3
+
+
+# Flag operations
+
+
+block testAndSet:
+  var location: AtomicFlag
+  doAssert not location.testAndSet
+  doAssert location.testAndSet
+  doAssert location.testAndSet
+  location.clear()
+  doAssert not location.testAndSet(moRelaxed)
+  doAssert location.testAndSet(moRelaxed)
+  doAssert location.testAndSet(moRelaxed)
+  location.clear()
+  doAssert not location.testAndSet(moRelease)
+  doAssert location.testAndSet(moRelease)
+  doAssert location.testAndSet(moRelease)
+
+
+block clear:
+  var location: AtomicFlag
+  discard location.testAndSet
+  location.clear
+  doAssert not location.testAndSet
+  location.clear(moRelaxed)
+  doAssert not location.testAndSet
+  location.clear(moRelease)
+  doAssert not location.testAndSet
+
+block: # bug #18844
+  when not defined(cpp): # cpp pending pr #18836
+    type
+      Deprivation = object of RootObj
+        memes: Atomic[int]
+      Zoomer = object
+        dopamine: Deprivation
+
+    block:
+      var x = Deprivation()
+      var y = Zoomer()
+      doAssert x.memes.load == 0
+      doAssert y.dopamine.memes.load == 0
+
+    block:
+      var x: Deprivation
+      var y: Zoomer
+      doAssert x.memes.load == 0
+      doAssert y.dopamine.memes.load == 0
diff --git a/tests/stdlib/concurrency/tatomics_size.nim b/tests/stdlib/concurrency/tatomics_size.nim
new file mode 100644
index 000000000..f64adb308
--- /dev/null
+++ b/tests/stdlib/concurrency/tatomics_size.nim
@@ -0,0 +1,21 @@
+discard """
+  # test C with -d:nimUseCppAtomics as well to check nothing breaks
+  matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
+  targets: "c cpp"
+"""
+import std/atomics
+import std/assertions
+
+block testSize: # issue 12726
+  type
+    Node = ptr object
+      # works
+      next: Atomic[pointer]
+      f:AtomicFlag
+    MyChannel = object
+      # type not defined completely
+      back: Atomic[ptr int]
+      f: AtomicFlag
+  static:
+    doAssert sizeof(Node) == sizeof(pointer)
+    doAssert sizeof(MyChannel) == sizeof(pointer) * 2
diff --git a/tests/stdlib/config.nims b/tests/stdlib/config.nims
new file mode 100644
index 000000000..dffae2812
--- /dev/null
+++ b/tests/stdlib/config.nims
@@ -0,0 +1,5 @@
+switch("styleCheck", "usages")
+switch("styleCheck", "error")
+switch("define", "nimPreviewSlimSystem")
+switch("define", "nimPreviewCstringConversion")
+switch("define", "nimPreviewProcConversion")
diff --git a/tests/stdlib/genericstrformat.nim b/tests/stdlib/genericstrformat.nim
new file mode 100644
index 000000000..0446f3269
--- /dev/null
+++ b/tests/stdlib/genericstrformat.nim
@@ -0,0 +1,16 @@
+# from issue #7632
+# imported and used in tstrformat
+
+import strformat
+
+proc fails*(a: static[int]): string =
+  &"formatted {a:2}"
+
+proc fails2*[N: static[int]](a: int): string =
+  &"formatted {a:2}"
+
+proc works*(a: int): string =
+  &"formatted {a:2}"
+
+proc fails0*(a: int or uint): string =
+  &"formatted {a:2}"
diff --git a/tests/stdlib/mgenast.nim b/tests/stdlib/mgenast.nim
new file mode 100644
index 000000000..b0904847e
--- /dev/null
+++ b/tests/stdlib/mgenast.nim
@@ -0,0 +1,57 @@
+import std/genasts
+import std/macros
+
+# Using a enum instead of, say, int, to make apparent potential bugs related to
+# forgetting converting to NimNode via newLit, see bug #9607
+
+type Foo* = enum kfoo0, kfoo1, kfoo2, kfoo3, kfoo4
+
+proc myLocalPriv(): auto = kfoo1
+proc myLocalPriv2(): auto = kfoo1
+macro bindme2*(): untyped =
+  genAst: myLocalPriv()
+macro bindme3*(): untyped =
+  ## myLocalPriv must be captured explicitly
+  genAstOpt({kDirtyTemplate}, myLocalPriv): myLocalPriv()
+
+macro bindme4*(): untyped =
+  ## calling this won't compile because `myLocalPriv` isn't captured
+  genAstOpt({kDirtyTemplate}): myLocalPriv()
+
+macro bindme5UseExpose*(): untyped =
+  genAst: myLocalPriv2()
+
+macro bindme5UseExposeFalse*(): untyped =
+  genAstOpt({kDirtyTemplate}): myLocalPriv2()
+
+# example from bug #7889
+from std/streams import newStringStream, readData, writeData
+
+macro bindme6UseExpose*(): untyped =
+  genAst:
+    var tst = "sometext"
+    var ss = newStringStream("anothertext")
+    when defined(gcArc) or defined(gcOrc):
+      prepareMutation(tst)
+    writeData(ss, tst[0].addr, 2)
+    discard readData(ss, tst[0].addr, 2)
+
+macro bindme6UseExposeFalse*(): untyped =
+  ## with `kDirtyTemplate`, requires passing all referenced symbols
+  ## which can be tedious
+  genAstOpt({kDirtyTemplate}, newStringStream, writeData, readData):
+    var tst = "sometext"
+    var ss = newStringStream("anothertext")
+    when defined(gcArc) or defined(gcOrc):
+      prepareMutation(tst)
+    writeData(ss, tst[0].addr, 2)
+    discard readData(ss, tst[0].addr, 2)
+
+
+proc locafun1(): auto = "in locafun1"
+proc locafun2(): auto = "in locafun2"
+# locafun3 in caller scope only
+macro mixinExample*(): untyped =
+  genAst:
+    mixin locafun1
+    (locafun1(), locafun2(), locafun3())
diff --git a/tests/stdlib/mimportutils.nim b/tests/stdlib/mimportutils.nim
new file mode 100644
index 000000000..678d9ec02
--- /dev/null
+++ b/tests/stdlib/mimportutils.nim
@@ -0,0 +1,38 @@
+type
+  A* = object
+    a0*: int
+    ha1: float
+  B = object
+    b0*: int
+    hb1: float
+  C* = ref object
+    c0: int
+    hc1: float
+  D* = ptr object
+    d0: int
+    hd1: float
+  PA* = ref A
+  PtA* = ptr A
+  E*[T] = object
+    he1: int
+  FSub[T1, T2] = object
+    h3: T1
+    h4: T2
+  F*[T1, T2] = ref FSub[T1, T2]
+  G*[T] = ref E[T]
+  H3*[T] = object
+    h5: T
+  H2*[T] = H3[T]
+  H1*[T] = ref H2[T]
+  H*[T] = H1[T]
+
+  Pity[T] = object
+    a: T
+  PityRef*[T] = ref Pity[T]
+  Hope*[T] = ref object
+    a: T
+
+type BAalias* = typeof(B.default)
+  # typeof is not a transparent abstraction, creates a `tyAlias`
+
+proc initB*(): B = B()
diff --git a/tests/stdlib/mintsets.nim b/tests/stdlib/mintsets.nim
new file mode 100644
index 000000000..98786e9ba
--- /dev/null
+++ b/tests/stdlib/mintsets.nim
@@ -0,0 +1,11 @@
+import std/intsets
+import std/assertions
+
+proc test1*[]() =
+  let a = initIntSet()
+  doAssert len(a) == 0
+
+proc test2*[]() =
+  var a = initIntSet()
+  var b = initIntSet()
+  a.incl b
diff --git a/tests/stdlib/mstackframes.nim b/tests/stdlib/mstackframes.nim
new file mode 100644
index 000000000..f3daa1437
--- /dev/null
+++ b/tests/stdlib/mstackframes.nim
@@ -0,0 +1,38 @@
+import std/stackframes
+
+
+
+# line 5
+var count = 0
+
+proc main1(n: int) =
+  setFrameMsg $("main1", n)
+  if n > 0:
+    main1(n-1)
+
+proc main2(n: int) =
+  count.inc
+  setFrameMsg $("main2", n, count)
+  proc bar() =
+    setFrameMsg $("bar ",)
+    if n < 3: raise newException(CatchableError, "on purpose")
+  bar()
+  main2(n-1)
+
+proc main() =
+  var z = 0
+  setFrameMsg "\n  z: " & $z, prefix = ""
+  # multiple calls inside a frame are possible
+  z.inc
+  setFrameMsg "\n  z: " & $z, prefix = ""
+  try:
+    main2(5)
+  except CatchableError:
+    main1(10) # goes deep and then unwinds; sanity check to ensure `setFrameMsg` from inside
+              # `main1` won't invalidate the stacktrace; if StackTraceEntry.frameMsg
+              # were a reference instead of a copy, this would fail.
+    let e = getCurrentException()
+    let trace = e.getStackTrace
+    echo trace
+
+main()
diff --git a/tests/stdlib/nre/captures.nim b/tests/stdlib/nre/captures.nim
index 19c344a8d..acc141baf 100644
--- a/tests/stdlib/nre/captures.nim
+++ b/tests/stdlib/nre/captures.nim
@@ -1,59 +1,64 @@
 import unittest, optional_nonstrict
 include nre
 
-suite "captures":
-  test "map capture names to numbers":
+block: # captures
+  block: # map capture names to numbers
     check(getNameToNumberTable(re("(?<v1>1(?<v2>2(?<v3>3))(?'v4'4))()")) ==
       { "v1" : 0, "v2" : 1, "v3" : 2, "v4" : 3 }.toTable())
 
-  test "capture bounds are correct":
+  block: # capture bounds are correct
     let ex1 = re("([0-9])")
     check("1 23".find(ex1).matchBounds == 0 .. 0)
-    check("1 23".find(ex1).captureBounds[0].get == 0 .. 0)
+    check("1 23".find(ex1).captureBounds[0] == 0 .. 0)
     check("1 23".find(ex1, 1).matchBounds == 2 .. 2)
     check("1 23".find(ex1, 3).matchBounds == 3 .. 3)
 
     let ex2 = re("()()()()()()()()()()([0-9])")
-    check("824".find(ex2).captureBounds[0].get == 0 .. -1)
-    check("824".find(ex2).captureBounds[10].get == 0 .. 0)
+    check("824".find(ex2).captureBounds[0] == 0 .. -1)
+    check("824".find(ex2).captureBounds[10] == 0 .. 0)
 
     let ex3 = re("([0-9]+)")
-    check("824".find(ex3).captureBounds[0].get == 0 .. 2)
+    check("824".find(ex3).captureBounds[0] == 0 .. 2)
 
-  test "named captures":
+  block: # named captures
     let ex1 = "foobar".find(re("(?<foo>foo)(?<bar>bar)"))
     check(ex1.captures["foo"] == "foo")
     check(ex1.captures["bar"] == "bar")
 
     let ex2 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check("foo" in ex2.captureBounds)
     check(ex2.captures["foo"] == "foo")
-    check(ex2.captures["bar"] == nil)
+    check(not ("bar" in ex2.captures))
+    expect KeyError:
+        discard ex2.captures["bar"]
 
-  test "named capture bounds":
+  block: # named capture bounds
     let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex1.captureBounds["foo"] == some(0..2))
-    check(ex1.captureBounds["bar"] == none(Slice[int]))
+    check("foo" in ex1.captureBounds)
+    check(ex1.captureBounds["foo"] == 0..2)
+    check(not ("bar" in ex1.captures))
+    expect KeyError:
+        discard ex1.captures["bar"]
 
-  test "capture count":
+  block: # capture count
     let ex1 = re("(?<foo>foo)(?<bar>bar)?")
     check(ex1.captureCount == 2)
     check(ex1.captureNameId == {"foo" : 0, "bar" : 1}.toTable())
 
-  test "named capture table":
+  block: # named capture table
     let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex1.captures.toTable == {"foo" : "foo", "bar" : nil}.toTable())
-    check(ex1.captureBounds.toTable == {"foo" : some(0..2), "bar" : none(Slice[int])}.toTable())
-    check(ex1.captures.toTable("") == {"foo" : "foo", "bar" : ""}.toTable())
+    check(ex1.captures.toTable == {"foo" : "foo"}.toTable())
+    check(ex1.captureBounds.toTable == {"foo" : 0..2}.toTable())
 
     let ex2 = "foobar".find(re("(?<foo>foo)(?<bar>bar)?"))
     check(ex2.captures.toTable == {"foo" : "foo", "bar" : "bar"}.toTable())
 
-  test "capture sequence":
+  block: # capture sequence
     let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex1.captures.toSeq == @["foo", nil])
+    check(ex1.captures.toSeq == @[some("foo"), none(string)])
     check(ex1.captureBounds.toSeq == @[some(0..2), none(Slice[int])])
-    check(ex1.captures.toSeq("") == @["foo", ""])
+    check(ex1.captures.toSeq(some("")) == @[some("foo"), some("")])
 
     let ex2 = "foobar".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex2.captures.toSeq == @["foo", "bar"])
+    check(ex2.captures.toSeq == @[some("foo"), some("bar")])
 
diff --git a/tests/stdlib/nre/escape.nim b/tests/stdlib/nre/escape.nim
index db5e8a001..5e7dc0c0e 100644
--- a/tests/stdlib/nre/escape.nim
+++ b/tests/stdlib/nre/escape.nim
@@ -1,7 +1,7 @@
 import nre, unittest
 
-suite "escape strings":
-  test "escape strings":
+block: # escape strings
+  block: # escape strings
     check("123".escapeRe() == "123")
     check("[]".escapeRe() == r"\[\]")
     check("()".escapeRe() == r"\(\)")
diff --git a/tests/stdlib/nre/find.nim b/tests/stdlib/nre/find.nim
index caa953ff4..7e7555d73 100644
--- a/tests/stdlib/nre/find.nim
+++ b/tests/stdlib/nre/find.nim
@@ -3,23 +3,23 @@ import nre except toSeq
 import optional_nonstrict
 import times, strutils
 
-suite "find":
-  test "find text":
+block: # find
+  block: # find text
     check("3213a".find(re"[a-z]").match == "a")
     check(toSeq(findIter("1 2 3 4 5 6 7 8 ", re" ")).map(
       proc (a: RegexMatch): string = a.match
     ) == @[" ", " ", " ", " ", " ", " ", " ", " "])
 
-  test "find bounds":
+  block: # find bounds
     check(toSeq(findIter("1 2 3 4 5 ", re" ")).map(
       proc (a: RegexMatch): Slice[int] = a.matchBounds
     ) == @[1..1, 3..3, 5..5, 7..7, 9..9])
 
-  test "overlapping find":
+  block: # overlapping find
     check("222".findAll(re"22") == @["22"])
     check("2222".findAll(re"22") == @["22", "22"])
 
-  test "len 0 find":
+  block: # len 0 find
     check("".findAll(re"\ ") == newSeq[string]())
     check("".findAll(re"") == @[""])
     check("abc".findAll(re"") == @["", "", "", ""])
@@ -27,7 +27,7 @@ suite "find":
     check("word\r\lword".findAll(re"(*ANYCRLF)(?m)$") == @["", ""])
     check("слово слово".findAll(re"(*U)\b") == @["", "", "", ""])
 
-  test "bail early":
+  block: # bail early
     ## we expect nothing to be found and we should be bailing out early which means that
     ## the timing difference between searching in small and large data should be well
     ## within a tolerance margin
diff --git a/tests/stdlib/nre/init.nim b/tests/stdlib/nre/init.nim
index 26e668104..f0c8e0a00 100644
--- a/tests/stdlib/nre/init.nim
+++ b/tests/stdlib/nre/init.nim
@@ -1,12 +1,12 @@
 import unittest
 include nre
 
-suite "Test NRE initialization":
-  test "correct initialization":
+block: # Test NRE initialization
+  block: # correct initialization
     check(re("[0-9]+") != nil)
     check(re("(?i)[0-9]+") != nil)
 
-  test "options":
+  block: # options
     check(extractOptions("(*NEVER_UTF)") ==
           ("", pcre.NEVER_UTF, true))
     check(extractOptions("(*UTF8)(*ANCHORED)(*UCP)z") ==
@@ -19,14 +19,14 @@ suite "Test NRE initialization":
     check(extractOptions("(*LIMIT_MATCH=6)(*ANCHORED)z") ==
           ("(*LIMIT_MATCH=6)z", pcre.ANCHORED, true))
 
-  test "incorrect options":
+  block: # incorrect options
     for s in ["CR", "(CR", "(*CR", "(*abc)", "(*abc)CR",
               "(?i)",
               "(*LIMIT_MATCH=5", "(*NO_AUTO_POSSESS=5)"]:
       let ss = s & "(*NEVER_UTF)"
       check(extractOptions(ss) == (ss, 0, true))
 
-  test "invalid regex":
+  block: # invalid regex
     expect(SyntaxError): discard re("[0-9")
     try:
       discard re("[0-9")
diff --git a/tests/stdlib/nre/match.nim b/tests/stdlib/nre/match.nim
index 38ee5214b..7e09a4b2f 100644
--- a/tests/stdlib/nre/match.nim
+++ b/tests/stdlib/nre/match.nim
@@ -1,18 +1,18 @@
 include nre, unittest, optional_nonstrict
 
-suite "match":
-  test "upper bound must be inclusive":
+block: # match
+  block: # upper bound must be inclusive
     check("abc".match(re"abc", endpos = -1) == none(RegexMatch))
     check("abc".match(re"abc", endpos = 1) == none(RegexMatch))
     check("abc".match(re"abc", endpos = 2) != none(RegexMatch))
 
-  test "match examples":
+  block: # match examples
     check("abc".match(re"(\w)").captures[0] == "a")
     check("abc".match(re"(?<letter>\w)").captures["letter"] == "a")
     check("abc".match(re"(\w)\w").captures[-1] == "ab")
-    check("abc".match(re"(\w)").captureBounds[0].get == 0 .. 0)
-    check("abc".match(re"").captureBounds[-1].get == 0 .. -1)
-    check("abc".match(re"abc").captureBounds[-1].get == 0 .. 2)
+    check("abc".match(re"(\w)").captureBounds[0] == 0 .. 0)
+    check("abc".match(re"").captureBounds[-1] == 0 .. -1)
+    check("abc".match(re"abc").captureBounds[-1] == 0 .. 2)
 
-  test "match test cases":
+  block: # match test cases
     check("123".match(re"").matchBounds == 0 .. -1)
diff --git a/tests/stdlib/nre/misc.nim b/tests/stdlib/nre/misc.nim
index f4a88b639..b7df08ee9 100644
--- a/tests/stdlib/nre/misc.nim
+++ b/tests/stdlib/nre/misc.nim
@@ -1,13 +1,13 @@
 import unittest, nre, strutils, optional_nonstrict
 
-suite "Misc tests":
-  test "unicode":
+block: # Misc tests
+  block: # unicode
     check("".find(re"(*UTF8)").match == "")
     check("перевірка".replace(re"(*U)\w", "") == "")
 
-  test "empty or non-empty match":
-    check("abc".findall(re"|.").join(":") == ":a::b::c:")
-    check("abc".findall(re".|").join(":") == "a:b:c:")
+  block: # empty or non-empty match
+    check("abc".findAll(re"|.").join(":") == ":a::b::c:")
+    check("abc".findAll(re".|").join(":") == "a:b:c:")
 
     check("abc".replace(re"|.", "x") == "xxxxxxx")
     check("abc".replace(re".|", "x") == "xxxx")
diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim
index 516fd4328..5cf659f21 100644
--- a/tests/stdlib/nre/replace.nim
+++ b/tests/stdlib/nre/replace.nim
@@ -1,13 +1,13 @@
 include nre
 import unittest
 
-suite "replace":
-  test "replace with 0-length strings":
+block: # replace
+  block: # replace with 0-length strings
     check("".replace(re"1", proc (v: RegexMatch): string = "1") == "")
     check(" ".replace(re"", proc (v: RegexMatch): string = "1") == "1 1")
     check("".replace(re"", proc (v: RegexMatch): string = "1") == "1")
 
-  test "regular replace":
+  block: # regular replace
     check("123".replace(re"\d", "foo") == "foofoofoo")
     check("123".replace(re"(\d)", "$1$1") == "112233")
     check("123".replace(re"(\d)(\d)", "$1$2") == "123")
@@ -15,6 +15,8 @@ suite "replace":
     check("123".replace(re"(?<foo>\d)(\d)", "$foo$#$#") == "1123")
     check("123".replace(re"(?<foo>\d)(\d)", "${foo}$#$#") == "1123")
 
-  test "replacing missing captures should throw instead of segfaulting":
-    expect ValueError: discard "ab".replace(re"(a)|(b)", "$1$2")
-    expect ValueError: discard "b".replace(re"(a)?(b)", "$1$2")
+  block: # replacing missing captures should throw instead of segfaulting
+    expect IndexDefect: discard "ab".replace(re"(a)|(b)", "$1$2")
+    expect IndexDefect: discard "b".replace(re"(a)?(b)", "$1$2")
+    expect KeyError: discard "b".replace(re"(a)?", "${foo}")
+    expect KeyError: discard "b".replace(re"(?<foo>a)?", "${foo}")
diff --git a/tests/stdlib/nre/split.nim b/tests/stdlib/nre/split.nim
index 9d57ea7d8..3cd57bb82 100644
--- a/tests/stdlib/nre/split.nim
+++ b/tests/stdlib/nre/split.nim
@@ -1,8 +1,8 @@
 import unittest, strutils
 include nre
 
-suite "string splitting":
-  test "splitting strings":
+block: # string splitting
+  block: # splitting strings
     check("1 2 3 4 5 6 ".split(re" ") == @["1", "2", "3", "4", "5", "6", ""])
     check("1  2  ".split(re(" ")) == @["1", "", "2", "", ""])
     check("1 2".split(re(" ")) == @["1", "2"])
@@ -10,22 +10,22 @@ suite "string splitting":
     check("".split(re"foo") == @[""])
     check("9".split(re"\son\s") == @["9"])
 
-  test "captured patterns":
+  block: # captured patterns
     check("12".split(re"(\d)") == @["", "1", "", "2", ""])
 
-  test "maxsplit":
+  block: # maxsplit
     check("123".split(re"", maxsplit = 2) == @["1", "23"])
     check("123".split(re"", maxsplit = 1) == @["123"])
     check("123".split(re"", maxsplit = -1) == @["1", "2", "3"])
 
-  test "split with 0-length match":
+  block: # split with 0-length match
     check("12345".split(re("")) == @["1", "2", "3", "4", "5"])
     check("".split(re"") == newSeq[string]())
     check("word word".split(re"\b") == @["word", " ", "word"])
     check("word\r\lword".split(re"(*ANYCRLF)(?m)$") == @["word", "\r\lword"])
     check("слово слово".split(re"(*U)(\b)") == @["", "слово", "", " ", "", "слово", ""])
 
-  test "perl split tests":
+  block: # perl split tests
     check("forty-two"                    .split(re"")      .join(",") == "f,o,r,t,y,-,t,w,o")
     check("forty-two"                    .split(re"", 3)   .join(",") == "f,o,rty-two")
     check("split this string"            .split(re" ")     .join(",") == "split,this,string")
@@ -47,7 +47,7 @@ suite "string splitting":
     check(""                             .split(re"")      .len       == 0)
     check(":"                            .split(re"")      .len       == 1)
 
-  test "start position":
+  block: # start position
     check("abc".split(re"", start = 1) == @["b", "c"])
     check("abc".split(re"", start = 2) == @["c"])
     check("abc".split(re"", start = 3) == newSeq[string]())
diff --git a/tests/stdlib/osproctest.nim b/tests/stdlib/osproctest.nim
new file mode 100644
index 000000000..8c4fba9ba
--- /dev/null
+++ b/tests/stdlib/osproctest.nim
@@ -0,0 +1,8 @@
+# This is test program for the osproc module.
+
+import os
+
+echo getCurrentDir()
+
+for i in 1..paramCount():
+  echo paramStr(i)
diff --git a/tests/stdlib/somesql.sql b/tests/stdlib/somesql.sql
index 285f93cec..74afcbab0 100644
--- a/tests/stdlib/somesql.sql
+++ b/tests/stdlib/somesql.sql
@@ -295,4 +295,4 @@ create table anon207(
   anon209 varchar(30) not null,
   anon204 varchar(30) default null,
   anon70 int not null  references anon40(anon41));
-
+select * from anon207 where anon41 in (1, 2, 3);
diff --git a/tests/stdlib/t10231.nim b/tests/stdlib/t10231.nim
new file mode 100644
index 000000000..3d09721aa
--- /dev/null
+++ b/tests/stdlib/t10231.nim
@@ -0,0 +1,16 @@
+discard """
+  targets: "cpp"
+  action: run
+  exitcode: 0
+"""
+
+import os
+import std/assertions
+
+# consider moving this inside tosproc (taking care that it's for cpp mode)
+
+if paramCount() == 0:
+  # main process
+  doAssert execShellCmd(getAppFilename().quoteShell & " test") == 1
+else:
+  quit 1
diff --git a/tests/stdlib/t14139.nim b/tests/stdlib/t14139.nim
new file mode 100644
index 000000000..866bdb45f
--- /dev/null
+++ b/tests/stdlib/t14139.nim
@@ -0,0 +1,10 @@
+import std/heapqueue
+import std/assertions
+
+var test_queue : HeapQueue[int]
+
+test_queue.push(7)
+test_queue.push(3)
+test_queue.push(9)
+let i = test_queue.pushpop(10)
+doAssert i == 3
diff --git a/tests/stdlib/t15663.nim b/tests/stdlib/t15663.nim
new file mode 100644
index 000000000..8e8bfd9a8
--- /dev/null
+++ b/tests/stdlib/t15663.nim
@@ -0,0 +1,9 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  output: "Test"
+"""
+
+import std/widestrs
+
+let ws = newWideCString("Test")
+echo ws
diff --git a/tests/stdlib/t19304.nim b/tests/stdlib/t19304.nim
new file mode 100644
index 000000000..5e8795ac5
--- /dev/null
+++ b/tests/stdlib/t19304.nim
@@ -0,0 +1,7 @@
+import times
+
+type DjangoDateTime* = distinct DateTime
+
+# proc toTime*(x: DjangoDateTime): Time  {.borrow.} # <-- works
+proc format*(x: DjangoDateTime, f: TimeFormat,
+    loc: DateTimeLocale = DefaultLocale): string {.borrow.}
diff --git a/tests/stdlib/t20023.nim b/tests/stdlib/t20023.nim
new file mode 100644
index 000000000..8f12f8993
--- /dev/null
+++ b/tests/stdlib/t20023.nim
@@ -0,0 +1,10 @@
+import std/[tables, hashes, assertions]
+
+
+let t = ()
+var a = toTable({t:t})
+del(a,t)
+let b = default(typeof(a))
+
+doAssert a==b , "tables are not equal"
+doAssert hash(a) == hash(b), "table hashes are not equal"
diff --git a/tests/stdlib/t21251.nim b/tests/stdlib/t21251.nim
new file mode 100644
index 000000000..4402e9b7e
--- /dev/null
+++ b/tests/stdlib/t21251.nim
@@ -0,0 +1,6 @@
+import std / [tables, sets, sharedtables]
+
+var shared: SharedTable[int, int]
+shared.init
+
+shared[1] = 1
diff --git a/tests/stdlib/t21406.nim b/tests/stdlib/t21406.nim
new file mode 100644
index 000000000..86bf7b0c7
--- /dev/null
+++ b/tests/stdlib/t21406.nim
@@ -0,0 +1,7 @@
+import std/[times, strformat]
+import std/assertions
+
+let aTime = getTime()
+doAssert fmt"{aTime}" == $aTime
+let aNow = now()
+doAssert fmt"{aNow}" == $aNow
diff --git a/tests/stdlib/t21564.nim b/tests/stdlib/t21564.nim
new file mode 100644
index 000000000..0a5777d12
--- /dev/null
+++ b/tests/stdlib/t21564.nim
@@ -0,0 +1,32 @@
+discard """
+targets: "c js"
+"""
+
+import bitops
+import std/assertions
+
+proc main() =
+  block: # bug #21564
+    # tesk `bitops.bitsliced` patch
+    doAssert(0x17.bitsliced(4..7) == 0x01)
+    doAssert(0x17.bitsliced(0..3) == 0x07)
+
+  block:
+    # test in-place `bitops.bitslice`
+    var t = 0x12F4
+    t.bitslice(4..7)
+
+    doAssert(t == 0xF)
+
+  block:
+    # test `bitops.toMask` patch via bitops.masked
+    doAssert(0x12FFFF34.masked(8..23) == 0x00FFFF00)
+
+  block: # bug #22687
+    var a: uint8 = 0b1111_1111
+    doAssert a.bitsliced(4..7).int == 15
+
+main()
+
+static:
+  main()
diff --git a/tests/stdlib/t7686.nim b/tests/stdlib/t7686.nim
new file mode 100644
index 000000000..9902cfcb5
--- /dev/null
+++ b/tests/stdlib/t7686.nim
@@ -0,0 +1,10 @@
+import std/strutils
+import std/assertions
+
+type
+  MyEnum = enum
+    A,
+    a
+
+doAssert parseEnum[MyEnum]("A") == A
+doAssert parseEnum[MyEnum]("a") == a
diff --git a/tests/stdlib/t8925.nim b/tests/stdlib/t8925.nim
new file mode 100644
index 000000000..c55e93e73
--- /dev/null
+++ b/tests/stdlib/t8925.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "type mismatch between pattern '$$i' (position: 1) and HourRange var 'hour'"
+  file: "strscans.nim"
+"""
+
+import strscans
+
+type
+  HourRange = range[0..23]
+
+var
+  hour: HourRange
+  timeStr: string
+
+if scanf(timeStr, "$i", hour):
+  discard
diff --git a/tests/stdlib/t9754.nim b/tests/stdlib/t9754.nim
new file mode 100644
index 000000000..971b5a8fb
--- /dev/null
+++ b/tests/stdlib/t9754.nim
@@ -0,0 +1,6 @@
+discard """
+  joinable: false
+"""
+
+import tmarshal
+import tparsesql
\ No newline at end of file
diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim
new file mode 100644
index 000000000..e2024df0c
--- /dev/null
+++ b/tests/stdlib/talgorithm.nim
@@ -0,0 +1,275 @@
+discard """
+  targets: "c js"
+  matrix: "--mm:refc; --mm:orc"
+  output:'''@["3", "2", "1"]
+'''
+"""
+#12928,10456
+
+import std/[sequtils, algorithm, json, sugar]
+import std/assertions
+
+proc test() = 
+  try: 
+    let info = parseJson("""
+    {"a": ["1", "2", "3"]}
+    """)
+    let prefixes = info["a"].getElems().mapIt(it.getStr()).sortedByIt(it).reversed()
+    echo prefixes
+  except:
+    discard
+
+test()
+
+block:
+  # Tests for lowerBound
+  var arr = @[1, 2, 3, 5, 6, 7, 8, 9]
+  doAssert arr.lowerBound(0) == 0
+  doAssert arr.lowerBound(4) == 3
+  doAssert arr.lowerBound(5) == 3
+  doAssert arr.lowerBound(10) == 8
+  arr = @[1, 5, 10]
+  doAssert arr.lowerBound(4) == 1
+  doAssert arr.lowerBound(5) == 1
+  doAssert arr.lowerBound(6) == 2
+  # Tests for isSorted
+  var srt1 = [1, 2, 3, 4, 4, 4, 4, 5]
+  var srt2 = ["iello", "hello"]
+  var srt3 = [1.0, 1.0, 1.0]
+  var srt4: seq[int]
+  doAssert srt1.isSorted(cmp) == true
+  doAssert srt2.isSorted(cmp) == false
+  doAssert srt3.isSorted(cmp) == true
+  doAssert srt4.isSorted(cmp) == true
+  var srtseq = newSeq[int]()
+  doAssert srtseq.isSorted(cmp) == true
+  # Tests for reversed
+  var arr1 = @[0, 1, 2, 3, 4]
+  doAssert arr1.reversed() == @[4, 3, 2, 1, 0]
+  for i in 0 .. high(arr1):
+    doAssert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)]
+    doAssert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i]
+
+block:
+  var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+  let list2 = list.rotatedLeft(1 ..< 9, 3)
+  let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10]
+
+  doAssert list.rotateLeft(1 ..< 9, 3) == 6
+  doAssert list == expected
+  doAssert list2 == @expected
+
+  var s0, s1, s2, s3, s4, s5 = "xxxabcdefgxxx"
+
+  doAssert s0.rotateLeft(3 ..< 10, 3) == 7
+  doAssert s0 == "xxxdefgabcxxx"
+  doAssert s1.rotateLeft(3 ..< 10, 2) == 8
+  doAssert s1 == "xxxcdefgabxxx"
+  doAssert s2.rotateLeft(3 ..< 10, 4) == 6
+  doAssert s2 == "xxxefgabcdxxx"
+  doAssert s3.rotateLeft(3 ..< 10, -3) == 6
+  doAssert s3 == "xxxefgabcdxxx"
+  doAssert s4.rotateLeft(3 ..< 10, -10) == 6
+  doAssert s4 == "xxxefgabcdxxx"
+  doAssert s5.rotateLeft(3 ..< 10, 11) == 6
+  doAssert s5 == "xxxefgabcdxxx"
+
+  block product:
+    doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
+    doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
+    doAssert product(@[@[1, 2]]) == @[@[1, 2]], "a simple case of one element"
+    doAssert product(@[@[1, 2], @[3, 4]]) == @[@[2, 4], @[1, 4], @[2, 3], @[1,
+        3]], "two elements"
+    doAssert product(@[@[1, 2], @[3, 4], @[5, 6]]) == @[@[2, 4, 6], @[1, 4, 6],
+        @[2, 3, 6], @[1, 3, 6], @[2, 4, 5], @[1, 4, 5], @[2, 3, 5], @[1, 3, 5]], "three elements"
+    doAssert product(@[@[1, 2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
+
+  block lowerBound:
+    doAssert lowerBound([1, 2, 4], 3, system.cmp[int]) == 2
+    doAssert lowerBound([1, 2, 2, 3], 4, system.cmp[int]) == 4
+    doAssert lowerBound([1, 2, 3, 10], 11) == 4
+
+  block upperBound:
+    doAssert upperBound([1, 2, 4], 3, system.cmp[int]) == 2
+    doAssert upperBound([1, 2, 2, 3], 3, system.cmp[int]) == 4
+    doAssert upperBound([1, 2, 3, 5], 3) == 3
+
+  block fillEmptySeq:
+    var s = newSeq[int]()
+    s.fill(0)
+
+  block testBinarySearch:
+    var noData: seq[int]
+    doAssert binarySearch(noData, 7) == -1
+    let oneData = @[1]
+    doAssert binarySearch(oneData, 1) == 0
+    doAssert binarySearch(oneData, 7) == -1
+    let someData = @[1, 3, 4, 7]
+    doAssert binarySearch(someData, 1) == 0
+    doAssert binarySearch(someData, 7) == 3
+    doAssert binarySearch(someData, -1) == -1
+    doAssert binarySearch(someData, 5) == -1
+    doAssert binarySearch(someData, 13) == -1
+    let moreData = @[1, 3, 5, 7, 4711]
+    doAssert binarySearch(moreData, -1) == -1
+    doAssert binarySearch(moreData, 1) == 0
+    doAssert binarySearch(moreData, 5) == 2
+    doAssert binarySearch(moreData, 6) == -1
+    doAssert binarySearch(moreData, 4711) == 4
+    doAssert binarySearch(moreData, 4712) == -1
+
+# merge
+proc main() =
+  block:
+    var x = @[1, 7, 8, 11, 21, 33, 45, 99]
+    var y = @[6, 7, 9, 12, 57, 66]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged == sorted(x & y)
+
+  block:
+    var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3]
+    var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13]
+
+    var merged: seq[int]
+    merged.merge(x, y, (x, y) => -system.cmp(x, y))
+    doAssert merged.isSorted((x, y) => -system.cmp(x, y))
+    doAssert merged == sorted(x & y, SortOrder.Descending)
+
+  block:
+    var x: seq[int] = @[]
+    var y = @[1]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.isSorted(SortOrder.Descending)
+    doAssert merged == @[1]
+
+  block:
+    var x = [1, 3, 5, 5, 7]
+    var y: seq[int] = @[]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged == @x
+
+  block:
+    var x = [1, 3, 5, 5, 7]
+    var y: seq[int] = @[]
+
+    var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34]
+    merged.merge(x, y)
+    doAssert merged == @[1, 2, 3, 5, 6, 56, 99, 2, 34, 1, 3, 5, 5, 7]
+
+
+  block:
+    var x: array[0, int]
+    var y = [1, 4, 6, 7, 9]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged == @y
+
+  block:
+    var x: array[0, int]
+    var y: array[0, int]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.len == 0
+
+  block:
+    var x: array[0, int]
+    var y: array[0, int]
+
+    var merged: seq[int] = @[99, 99, 99]
+    merged.setLen(0)
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.len == 0
+
+  block:
+    var x: seq[int]
+    var y: seq[int]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.len == 0
+
+  block:
+    type
+      Record = object
+        id: int
+    
+    proc r(id: int): Record =
+      Record(id: id)
+
+    proc cmp(x, y: Record): int =
+      if x.id == y.id: return 0
+      if x.id < y.id: return -1
+      result = 1
+
+    var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)]
+    var y = @[r(4), r(7), r(12), r(13), r(77), r(99)]
+
+    var merged: seq[Record] = @[]
+    merged.merge(x, y, cmp)
+    doAssert merged.isSorted(cmp)
+    doAssert merged.len == 12
+
+  block:
+    type
+      Record = object
+        id: int
+    
+    proc r(id: int): Record =
+      Record(id: id)
+
+    proc ascendingCmp(x, y: Record): int =
+      if x.id == y.id: return 0
+      if x.id < y.id: return -1
+      result = 1
+
+    proc descendingCmp(x, y: Record): int =
+      if x.id == y.id: return 0
+      if x.id < y.id: return 1
+      result = -1
+
+    var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)]
+    var y = @[r(4), r(7), r(12), r(13), r(77), r(99)]
+
+    var merged: seq[Record]
+    merged.setLen(0)
+    merged.merge(x, y, ascendingCmp)
+    doAssert merged.isSorted(ascendingCmp)
+    doAssert merged == sorted(x & y, ascendingCmp)
+
+    reverse(x)
+    reverse(y)
+
+    merged.setLen(0)
+    merged.merge(x, y, descendingCmp)
+    doAssert merged.isSorted(descendingCmp)
+    doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending)
+
+    reverse(x)
+    reverse(y)
+    merged.setLen(0)
+    merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y))
+    doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y))
+    doAssert merged == sorted(x & y, ascendingCmp)
+
+
+  var x: seq[(int, int)]
+  x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0])
+  doAssert x == @[(1, 1), (1, 2)]
+
+static: main()
+main()
diff --git a/tests/stdlib/tarithmetics.nim b/tests/stdlib/tarithmetics.nim
new file mode 100644
index 000000000..0a6dd1fcf
--- /dev/null
+++ b/tests/stdlib/tarithmetics.nim
@@ -0,0 +1,50 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+import std/assertions
+# TODO: in future work move existing arithmetic tests (tests/arithm/*) into this file
+# FYI https://github.com/nim-lang/Nim/pull/17767
+
+template main =
+  # put all arithmetic tests
+
+  block tshr:
+    block: # Signed types
+      let
+        a1 = -3
+        a2 = -2
+        b1 = -4'i8
+        b2 = 1'i8
+        c1 = -5'i16
+        c2 = 1'i16
+        d1 = -7i32
+        d2 = 1'i32
+        e1 = -9'i64
+        e2 = 1'i64
+      doAssert a1 shr a2 == -1
+      doAssert b1 shr b2 == -2
+      doAssert c1 shr c2 == -3
+      doAssert d1 shr d2 == -4
+      doAssert e1 shr e2 == -5
+
+    block: # Unsigned types
+      let
+        a1 = 3'u
+        a2 = 2'u
+        b1 = 2'u8
+        b2 = 1'u8
+        c1 = 5'u16
+        c2 = 1'u16
+        d1 = 6'u32
+        d2 = 1'u32
+        e1 = 8'u64
+        e2 = 1'u64
+      doAssert a1 shr a2 == 0
+      doAssert b1 shr b2 == 1
+      doAssert c1 shr c2 == 2
+      doAssert d1 shr d2 == 3
+      doAssert e1 shr e2 == 4
+
+static: main()
+main()
diff --git a/tests/stdlib/tasynchttpserver.nim b/tests/stdlib/tasynchttpserver.nim
new file mode 100644
index 000000000..5a7e2da40
--- /dev/null
+++ b/tests/stdlib/tasynchttpserver.nim
@@ -0,0 +1,121 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  exitcode: 0
+  output: "OK"
+  disabled: false
+"""
+
+import strutils
+from net import TimeoutError
+import std/assertions
+
+import httpclient, asynchttpserver, asyncdispatch, asyncfutures
+
+template runTest(
+    handler: proc (request: Request): Future[void] {.gcsafe.},
+    request: proc (server: AsyncHttpServer): Future[AsyncResponse],
+    test: proc (response: AsyncResponse, body: string): Future[void]) =
+
+  let server = newAsyncHttpServer()
+
+  discard server.serve(Port(64123), handler)
+
+  let
+    response = waitFor(request(server))
+    body = waitFor(response.body)
+
+  discard test(response, body)
+
+proc test200() {.async.} =
+  proc handler(request: Request) {.async.} =
+    await request.respond(Http200, "Hello World, 200")
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http200)
+    doAssert(body == "Hello World, 200")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "16")
+
+  runTest(handler, request, test)
+
+proc test404() {.async.} =
+  proc handler(request: Request) {.async.} =
+    await request.respond(Http404, "Hello World, 404")
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http404)
+    doAssert(body == "Hello World, 404")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "16")
+
+  runTest(handler, request, test)
+
+proc testCustomEmptyHeaders() {.async.} =
+  proc handler(request: Request) {.async.} =
+    await request.respond(Http200, "Hello World, 200", newHttpHeaders())
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http200)
+    doAssert(body == "Hello World, 200")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "16")
+
+  runTest(handler, request, test)
+
+proc testCustomContentLength() {.async.} =
+  proc handler(request: Request) {.async.} =
+    let headers = newHttpHeaders()
+    headers["Content-Length"] = "0"
+    await request.respond(Http200, "Hello World, 200", headers)
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http200)
+    doAssert(body == "")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "0")
+    doAssert contentLength(response) == 0 # bug #22778
+
+  runTest(handler, request, test)
+
+waitFor(test200())
+waitFor(test404())
+waitFor(testCustomEmptyHeaders())
+waitFor(testCustomContentLength())
+
+echo "OK"
diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim
new file mode 100644
index 000000000..886ba0f33
--- /dev/null
+++ b/tests/stdlib/tasynchttpserver_transferencoding.nim
@@ -0,0 +1,91 @@
+discard """
+  matrix: "--mm:arc; --mm:arc -d:danger; --mm:refc"
+  disabled: "freebsd"
+"""
+
+import httpclient, asynchttpserver, asyncdispatch, asyncfutures
+import net
+
+import std/asyncnet
+import std/nativesockets
+import std/assertions
+
+const postBegin = """
+POST / HTTP/1.1
+Transfer-Encoding:chunked
+
+"""
+
+template genTest(input, expected: string) =
+  proc handler(request: Request, future: Future[bool]) {.async, gcsafe.} =
+    doAssert(request.body == expected)
+    doAssert(request.headers.hasKey("Transfer-Encoding"))
+    doAssert(not request.headers.hasKey("Content-Length"))
+    future.complete(true)
+    await request.respond(Http200, "Good")
+
+  proc sendData(data: string, port: Port) {.async.} =
+    var socket = newSocket()
+    defer: socket.close()
+
+    socket.connect("127.0.0.1", port)
+    socket.send(data)
+
+  proc runTest(): Future[bool] {.async.} =
+    var handlerFuture = newFuture[bool]("runTest")
+    let data = postBegin & input
+    let server = newAsyncHttpServer()
+    server.listen(Port(0))
+
+    proc wrapper(request: Request): Future[void] {.gcsafe, closure.} =
+      handler(request, handlerFuture)
+    
+    asyncCheck sendData(data, server.getPort)
+    asyncCheck server.acceptRequest(wrapper)
+    doAssert await handlerFuture
+    
+    server.close()
+    return true
+
+  doAssert waitFor runTest()
+
+block:
+  const expected = "hello=world"
+  const input = ("b\r\n" &
+                 "hello=world\r\n" &
+                 "0\r\n" &
+                 "\r\n")
+  genTest(input, expected)
+block:
+  const expected = "hello encoding"
+  const input = ("e\r\n" &
+                 "hello encoding\r\n" &
+                 "0\r\n" &
+                 "\r\n")
+  genTest(input, expected)
+block:
+  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
+  const expected = "MozillaDeveloperNetwork"
+  const input = ("7\r\n" &
+                "Mozilla\r\n" &
+                "9\r\n" &
+                "Developer\r\n" &
+                "7\r\n" &
+                "Network\r\n" &
+                "0\r\n" &
+                "\r\n")
+  genTest(input, expected)
+block:
+  # https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+  const expected = "Wikipedia in \r\n\r\nchunks."
+  const input = ("4\r\n" &
+                "Wiki\r\n" &
+                "6\r\n" &
+                "pedia \r\n" &
+                "E\r\n" &
+                "in \r\n" &
+                "\r\n" &
+                "chunks.\r\n" &
+                "0\r\n" &
+                "\r\n")
+  genTest(input, expected)
diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim
new file mode 100644
index 000000000..c3bfb818e
--- /dev/null
+++ b/tests/stdlib/tbase64.nim
@@ -0,0 +1,63 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+import std/assertions
+import std/base64
+
+template main() =
+  doAssert encode("a") == "YQ=="
+  doAssert encode("Hello World") == "SGVsbG8gV29ybGQ="
+  doAssert encode("leasure.") == "bGVhc3VyZS4="
+  doAssert encode("easure.") == "ZWFzdXJlLg=="
+  doAssert encode("asure.") == "YXN1cmUu"
+  doAssert encode("sure.") == "c3VyZS4="
+  doAssert encode([1,2,3]) == "AQID"
+  doAssert encode(['h','e','y']) == "aGV5"
+
+  doAssert encode("") == ""
+  doAssert decode("") == ""
+
+  doAssert decode(" ") == ""
+
+  const testInputExpandsTo76 = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
+  const testInputExpands = "++++++++++++++++++++++++++++++"
+  const longText = """Man is distinguished, not only by his reason, but by this
+    singular passion from other animals, which is a lust of the mind,
+    that by a perseverance of delight in the continued and indefatigable
+    generation of knowledge, exceeds the short vehemence of any carnal
+    pleasure."""
+  const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
+                 "asure.", longText, testInputExpandsTo76, testInputExpands]
+
+  doAssert encodeMime("foobarbaz", lineLen=4) == "Zm9v\r\nYmFy\r\nYmF6"
+  doAssert decode("Zm9v\r\nYmFy\r\nYmF6") == "foobarbaz"
+
+  for t in items(tests):
+    doAssert decode(encode(t)) == t
+    doAssert decode(encodeMime(t, lineLen=40)) == t
+    doAssert decode(encodeMime(t, lineLen=76)) == t
+
+  doAssertRaises(ValueError): discard decode("SGVsbG\x008gV29ybGQ=")
+
+  block base64urlSafe:
+    doAssert encode("c\xf7>", safe = true) == "Y_c-"
+    doAssert encode("c\xf7>", safe = false) == "Y/c+" # Not a nice URL :(
+    doAssert decode("Y/c+") == decode("Y_c-")
+    # Output must not change with safe=true
+    doAssert encode("Hello World", safe = true) == "SGVsbG8gV29ybGQ="
+    doAssert encode("leasure.", safe = true)  == "bGVhc3VyZS4="
+    doAssert encode("easure.", safe = true) == "ZWFzdXJlLg=="
+    doAssert encode("asure.", safe = true) == "YXN1cmUu"
+    doAssert encode("sure.", safe = true) == "c3VyZS4="
+    doAssert encode([1,2,3], safe = true) == "AQID"
+    doAssert encode(['h','e','y'], safe = true) == "aGV5"
+    doAssert encode("", safe = true) == ""
+    doAssert encode("the quick brown dog jumps over the lazy fox", safe = true) == "dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA=="
+
+func mainNoSideEffects() = main()
+
+static: main()
+main()
+static: mainNoSideEffects()
+mainNoSideEffects()
diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim
index 8301256c4..3ecab2c64 100644
--- a/tests/stdlib/tbitops.nim
+++ b/tests/stdlib/tbitops.nim
@@ -1,9 +1,12 @@
 discard """
-  file: "tbitops.nim"
-  output: "OK"
+  nimout: "OK"
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+OK
+'''
 """
 import bitops
-
+import std/assertions
 
 proc main() =
   const U8 = 0b0011_0010'u8
@@ -16,98 +19,123 @@ proc main() =
   const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
   const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
   const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
+  const U64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'u64
+  const I64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'i64
+
+  doAssert (U8 and U8) == bitand(U8,U8)
+  doAssert (I8 and I8) == bitand(I8,I8)
+  doAssert (U16 and U16) == bitand(U16,U16)
+  doAssert (I16 and I16) == bitand(I16,I16)
+  doAssert (U32 and U32) == bitand(U32,U32)
+  doAssert (I32 and I32) == bitand(I32,I32)
+  doAssert (U64A and U64B) == bitand(U64A,U64B)
+  doAssert (I64A and I64B) == bitand(I64A,I64B)
+  doAssert (U64A and U64B and U64C) == bitand(U64A,U64B,U64C)
+  doAssert (I64A and I64B and I64C) == bitand(I64A,I64B,I64C)
+
+  doAssert (U8 or U8) == bitor(U8,U8)
+  doAssert (I8 or I8) == bitor(I8,I8)
+  doAssert (U16 or U16) == bitor(U16,U16)
+  doAssert (I16 or I16) == bitor(I16,I16)
+  doAssert (U32 or U32) == bitor(U32,U32)
+  doAssert (I32 or I32) == bitor(I32,I32)
+  doAssert (U64A or U64B) == bitor(U64A,U64B)
+  doAssert (I64A or I64B) == bitor(I64A,I64B)
+  doAssert (U64A or U64B or U64C) == bitor(U64A,U64B,U64C)
+  doAssert (I64A or I64B or I64C) == bitor(I64A,I64B,I64C)
+
+  doAssert (U8 xor U8) == bitxor(U8,U8)
+  doAssert (I8 xor I8) == bitxor(I8,I8)
+  doAssert (U16 xor U16) == bitxor(U16,U16)
+  doAssert (I16 xor I16) == bitxor(I16,I16)
+  doAssert (U32 xor U32) == bitxor(U32,U32)
+  doAssert (I32 xor I32) == bitxor(I32,I32)
+  doAssert (U64A xor U64B) == bitxor(U64A,U64B)
+  doAssert (I64A xor I64B) == bitxor(I64A,I64B)
+  doAssert (U64A xor U64B xor U64C) == bitxor(U64A,U64B,U64C)
+  doAssert (I64A xor I64B xor I64C) == bitxor(I64A,I64B,I64C)
+
+  doAssert not(U8) == bitnot(U8)
+  doAssert not(I8) == bitnot(I8)
+  doAssert not(U16) == bitnot(U16)
+  doAssert not(I16) == bitnot(I16)
+  doAssert not(U32) == bitnot(U32)
+  doAssert not(I32) == bitnot(I32)
+  doAssert not(U64A) == bitnot(U64A)
+  doAssert not(I64A) == bitnot(I64A)
+
+  doAssert U64A.fastLog2 == 62
+  doAssert I64A.fastLog2 == 62
+  doAssert U64A.countLeadingZeroBits == 1
+  doAssert I64A.countLeadingZeroBits == 1
+  doAssert U64A.countTrailingZeroBits == 0
+  doAssert I64A.countTrailingZeroBits == 0
+  doAssert U64A.firstSetBit == 1
+  doAssert I64A.firstSetBit == 1
+  doAssert U64A.parityBits == 1
+  doAssert I64A.parityBits == 1
+  doAssert U64A.countSetBits == 29
+  doAssert I64A.countSetBits == 29
+  doAssert U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64
+  doAssert U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64
 
-  doAssert( U64A.fastLog2 == 62)
-  doAssert( I64A.fastLog2 == 62)
-  doAssert( U64A.countLeadingZeroBits == 1)
-  doAssert( I64A.countLeadingZeroBits == 1)
-  doAssert( U64A.countTrailingZeroBits == 0)
-  doAssert( I64A.countTrailingZeroBits == 0)
-  doAssert( U64A.firstSetBit == 1)
-  doAssert( I64A.firstSetBit == 1)
-  doAssert( U64A.parityBits == 1)
-  doAssert( I64A.parityBits == 1)
-  doAssert( U64A.countSetBits == 29)
-  doAssert( I64A.countSetBits == 29)
-  doAssert( U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64)
-  doAssert( U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64)
-
-  doAssert( U64B.firstSetBit == 36)
-  doAssert( I64B.firstSetBit == 36)
-
-  doAssert( U32.fastLog2 == 31)
-  doAssert( I32.fastLog2 == 31)
-  doAssert( U32.countLeadingZeroBits == 0)
-  doAssert( I32.countLeadingZeroBits == 0)
-  doAssert( U32.countTrailingZeroBits == 4)
-  doAssert( I32.countTrailingZeroBits == 4)
-  doAssert( U32.firstSetBit == 5)
-  doAssert( I32.firstSetBit == 5)
-  doAssert( U32.parityBits == 0)
-  doAssert( I32.parityBits == 0)
-  doAssert( U32.countSetBits == 16)
-  doAssert( I32.countSetBits == 16)
-  doAssert( U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32)
-  doAssert( U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32)
-
-  doAssert( U16.fastLog2 == 13)
-  doAssert( I16.fastLog2 == 13)
-  doAssert( U16.countLeadingZeroBits == 2)
-  doAssert( I16.countLeadingZeroBits == 2)
-  doAssert( U16.countTrailingZeroBits == 3)
-  doAssert( I16.countTrailingZeroBits == 3)
-  doAssert( U16.firstSetBit == 4)
-  doAssert( I16.firstSetBit == 4)
-  doAssert( U16.parityBits == 0)
-  doAssert( I16.parityBits == 0)
-  doAssert( U16.countSetBits == 6)
-  doAssert( I16.countSetBits == 6)
-  doAssert( U16.rotateLeftBits(12) == 0b10000010_01110010'u16)
-  doAssert( U16.rotateRightBits(12) == 0b01110010_10000010'u16)
-
-  doAssert( U8.fastLog2 == 5)
-  doAssert( I8.fastLog2 == 5)
-  doAssert( U8.countLeadingZeroBits == 2)
-  doAssert( I8.countLeadingZeroBits == 2)
-  doAssert( U8.countTrailingZeroBits == 1)
-  doAssert( I8.countTrailingZeroBits == 1)
-  doAssert( U8.firstSetBit == 2)
-  doAssert( I8.firstSetBit == 2)
-  doAssert( U8.parityBits == 1)
-  doAssert( I8.parityBits == 1)
-  doAssert( U8.countSetBits == 3)
-  doAssert( I8.countSetBits == 3)
-  doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
-  doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
-
-  static :
-    # test bitopts at compile time with vm
-    doAssert( U8.fastLog2 == 5)
-    doAssert( I8.fastLog2 == 5)
-    doAssert( U8.countLeadingZeroBits == 2)
-    doAssert( I8.countLeadingZeroBits == 2)
-    doAssert( U8.countTrailingZeroBits == 1)
-    doAssert( I8.countTrailingZeroBits == 1)
-    doAssert( U8.firstSetBit == 2)
-    doAssert( I8.firstSetBit == 2)
-    doAssert( U8.parityBits == 1)
-    doAssert( I8.parityBits == 1)
-    doAssert( U8.countSetBits == 3)
-    doAssert( I8.countSetBits == 3)
-    doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
-    doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
+  doAssert U64B.firstSetBit == 36
+  doAssert I64B.firstSetBit == 36
 
+  doAssert U32.fastLog2 == 31
+  doAssert I32.fastLog2 == 31
+  doAssert U32.countLeadingZeroBits == 0
+  doAssert I32.countLeadingZeroBits == 0
+  doAssert U32.countTrailingZeroBits == 4
+  doAssert I32.countTrailingZeroBits == 4
+  doAssert U32.firstSetBit == 5
+  doAssert I32.firstSetBit == 5
+  doAssert U32.parityBits == 0
+  doAssert I32.parityBits == 0
+  doAssert U32.countSetBits == 16
+  doAssert I32.countSetBits == 16
+  doAssert U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32
+  doAssert U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32
 
+  doAssert U16.fastLog2 == 13
+  doAssert I16.fastLog2 == 13
+  doAssert U16.countLeadingZeroBits == 2
+  doAssert I16.countLeadingZeroBits == 2
+  doAssert U16.countTrailingZeroBits == 3
+  doAssert I16.countTrailingZeroBits == 3
+  doAssert U16.firstSetBit == 4
+  doAssert I16.firstSetBit == 4
+  doAssert U16.parityBits == 0
+  doAssert I16.parityBits == 0
+  doAssert U16.countSetBits == 6
+  doAssert I16.countSetBits == 6
+  doAssert U16.rotateLeftBits(12) == 0b10000010_01110010'u16
+  doAssert U16.rotateRightBits(12) == 0b01110010_10000010'u16
+
+  doAssert U8.fastLog2 == 5
+  doAssert I8.fastLog2 == 5
+  doAssert U8.countLeadingZeroBits == 2
+  doAssert I8.countLeadingZeroBits == 2
+  doAssert U8.countTrailingZeroBits == 1
+  doAssert I8.countTrailingZeroBits == 1
+  doAssert U8.firstSetBit == 2
+  doAssert I8.firstSetBit == 2
+  doAssert U8.parityBits == 1
+  doAssert I8.parityBits == 1
+  doAssert U8.countSetBits == 3
+  doAssert I8.countSetBits == 3
+  doAssert U8.rotateLeftBits(3) == 0b10010001'u8
+  doAssert U8.rotateRightBits(3) == 0b0100_0110'u8
 
   template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) =
-    doAssert( ffunc(0'u8) == expected)
-    doAssert( ffunc(0'i8) == expected)
-    doAssert( ffunc(0'u16) == expected)
-    doAssert( ffunc(0'i16) == expected)
-    doAssert( ffunc(0'u32) == expected)
-    doAssert( ffunc(0'i32) == expected)
-    doAssert( ffunc(0'u64) == expected)
-    doAssert( ffunc(0'i64) == expected)
+    doAssert ffunc(0'u8) == expected
+    doAssert ffunc(0'i8) == expected
+    doAssert ffunc(0'u16) == expected
+    doAssert ffunc(0'i16) == expected
+    doAssert ffunc(0'u32) == expected
+    doAssert ffunc(0'i32) == expected
+    doAssert ffunc(0'u64) == expected
+    doAssert ffunc(0'i64) == expected
 
   template test_undefined(ffunc: untyped; expected: int) =
     test_undefined_impl(ffunc, expected, false)
@@ -124,45 +152,200 @@ proc main() =
     test_undefined(fastLog2, -1)
 
     # check for undefined behavior with rotate by zero.
-    doAssert( U8.rotateLeftBits(0) == U8)
-    doAssert( U8.rotateRightBits(0) == U8)
-    doAssert( U16.rotateLeftBits(0) == U16)
-    doAssert( U16.rotateRightBits(0) == U16)
-    doAssert( U32.rotateLeftBits(0) == U32)
-    doAssert( U32.rotateRightBits(0) == U32)
-    doAssert( U64A.rotateLeftBits(0) == U64A)
-    doAssert( U64A.rotateRightBits(0) == U64A)
+    doAssert U8.rotateLeftBits(0) == U8
+    doAssert U8.rotateRightBits(0) == U8
+    doAssert U16.rotateLeftBits(0) == U16
+    doAssert U16.rotateRightBits(0) == U16
+    doAssert U32.rotateLeftBits(0) == U32
+    doAssert U32.rotateRightBits(0) == U32
+    doAssert U64A.rotateLeftBits(0) == U64A
+    doAssert U64A.rotateRightBits(0) == U64A
 
     # check for undefined behavior with rotate by integer width.
-    doAssert( U8.rotateLeftBits(8) == U8)
-    doAssert( U8.rotateRightBits(8) == U8)
-    doAssert( U16.rotateLeftBits(16) == U16)
-    doAssert( U16.rotateRightBits(16) == U16)
-    doAssert( U32.rotateLeftBits(32) == U32)
-    doAssert( U32.rotateRightBits(32) == U32)
-    doAssert( U64A.rotateLeftBits(64) == U64A)
-    doAssert( U64A.rotateRightBits(64) == U64A)
-
-    static:    # check for undefined behavior with rotate by zero.
-      doAssert( U8.rotateLeftBits(0) == U8)
-      doAssert( U8.rotateRightBits(0) == U8)
-      doAssert( U16.rotateLeftBits(0) == U16)
-      doAssert( U16.rotateRightBits(0) == U16)
-      doAssert( U32.rotateLeftBits(0) == U32)
-      doAssert( U32.rotateRightBits(0) == U32)
-      doAssert( U64A.rotateLeftBits(0) == U64A)
-      doAssert( U64A.rotateRightBits(0) == U64A)
-
-      # check for undefined behavior with rotate by integer width.
-      doAssert( U8.rotateLeftBits(8) == U8)
-      doAssert( U8.rotateRightBits(8) == U8)
-      doAssert( U16.rotateLeftBits(16) == U16)
-      doAssert( U16.rotateRightBits(16) == U16)
-      doAssert( U32.rotateLeftBits(32) == U32)
-      doAssert( U32.rotateRightBits(32) == U32)
-      doAssert( U64A.rotateLeftBits(64) == U64A)
-      doAssert( U64A.rotateRightBits(64) == U64A)
+    doAssert U8.rotateLeftBits(8) == U8
+    doAssert U8.rotateRightBits(8) == U8
+    doAssert U16.rotateLeftBits(16) == U16
+    doAssert U16.rotateRightBits(16) == U16
+    doAssert U32.rotateLeftBits(32) == U32
+    doAssert U32.rotateRightBits(32) == U32
+    doAssert U64A.rotateLeftBits(64) == U64A
+    doAssert U64A.rotateRightBits(64) == U64A
+
+  block:
+    # basic mask operations (mutating)
+    var v: uint8
+    v.setMask(0b1100_0000)
+    v.setMask(0b0000_1100)
+    doAssert v == 0b1100_1100
+    v.flipMask(0b0101_0101)
+    doAssert v == 0b1001_1001
+    v.clearMask(0b1000_1000)
+    doAssert v == 0b0001_0001
+    v.clearMask(0b0001_0001)
+    doAssert v == 0b0000_0000
+    v.setMask(0b0001_1110)
+    doAssert v == 0b0001_1110
+    v.mask(0b0101_0100)
+    doAssert v == 0b0001_0100
+  block:
+    # basic mask operations (non-mutating)
+    let v = 0b1100_0000'u8
+    doAssert v.masked(0b0000_1100) == 0b0000_0000
+    doAssert v.masked(0b1000_1100) == 0b1000_0000
+    doAssert v.setMasked(0b0000_1100) == 0b1100_1100
+    doAssert v.setMasked(0b1000_1110) == 0b1100_1110
+    doAssert v.flipMasked(0b1100_1000) == 0b0000_1000
+    doAssert v.flipMasked(0b0000_1100) == 0b1100_1100
+    let t = 0b1100_0110'u8
+    doAssert t.clearMasked(0b0100_1100) == 0b1000_0010
+    doAssert t.clearMasked(0b1100_0000) == 0b0000_0110
+  block:
+    # basic bitslice opeartions
+    let a = 0b1111_1011'u8
+    doAssert a.bitsliced(0 .. 3) == 0b1011
+    doAssert a.bitsliced(2 .. 3) == 0b10
+    doAssert a.bitsliced(4 .. 7) == 0b1111
+
+    # same thing, but with exclusive ranges.
+    doAssert a.bitsliced(0 ..< 4) == 0b1011
+    doAssert a.bitsliced(2 ..< 4) == 0b10
+    doAssert a.bitsliced(4 ..< 8) == 0b1111
+
+    # mutating
+    var b = 0b1111_1011'u8
+    b.bitslice(1 .. 3)
+    doAssert b == 0b101
+
+    # loop test:
+    let c = 0b1111_1111'u8
+    for i in 0 .. 7:
+      doAssert c.bitsliced(i .. 7) == c shr i
+  block:
+    # bitslice versions of mask operations (mutating)
+    var a = 0b1100_1100'u8
+    let b = toMask[uint8](2 .. 3)
+    a.mask(b)
+    doAssert a == 0b0000_1100
+    a.setMask(4 .. 7)
+    doAssert a == 0b1111_1100
+    a.flipMask(1 .. 3)
+    doAssert a == 0b1111_0010
+    a.flipMask(2 .. 4)
+    doAssert a == 0b1110_1110
+    a.clearMask(2 .. 4)
+    doAssert a == 0b1110_0010
+    a.mask(0 .. 3)
+    doAssert a == 0b0000_0010
+
+    # composition of mask from slices:
+    let c = bitor(toMask[uint8](2 .. 3), toMask[uint8](5 .. 7))
+    doAssert c == 0b1110_1100'u8
+  block:
+    # bitslice versions of mask operations (non-mutating)
+    let a = 0b1100_1100'u8
+    doAssert a.masked(toMask[uint8](2 .. 3)) == 0b0000_1100
+    doAssert a.masked(2 .. 3) == 0b0000_1100
+    doAssert a.setMasked(0 .. 3) == 0b1100_1111
+    doAssert a.setMasked(3 .. 4) == 0b1101_1100
+    doAssert a.flipMasked(0 .. 3) == 0b1100_0011
+    doAssert a.flipMasked(0 .. 7) == 0b0011_0011
+    doAssert a.flipMasked(2 .. 3) == 0b1100_0000
+    doAssert a.clearMasked(2 .. 3) == 0b1100_0000
+    doAssert a.clearMasked(3 .. 6) == 0b1000_0100
+  block:
+    # single bit operations
+    var v: uint8
+    v.setBit(0)
+    doAssert v == 0x0000_0001
+    v.setBit(1)
+    doAssert v == 0b0000_0011
+    v.flipBit(7)
+    doAssert v == 0b1000_0011
+    v.clearBit(0)
+    doAssert v == 0b1000_0010
+    v.flipBit(1)
+    doAssert v == 0b1000_0000
+    doAssert v.testBit(7)
+    doAssert not v.testBit(6)
+  block:
+    # multi bit operations
+    var v: uint8
+    v.setBits(0, 1, 7)
+    doAssert v == 0b1000_0011
+    v.flipBits(2, 3)
+    doAssert v == 0b1000_1111
+    v.clearBits(7, 0, 1)
+    doAssert v == 0b0000_1100
+  block:
+    # signed
+    var v: int8
+    v.setBit(7)
+    doAssert v == -128
+  block:
+    var v: uint64
+    v.setBit(63)
+    doAssert v == 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000'u64
+
+  block:
+    proc testReverseBitsInvo(x: SomeUnsignedInt) =
+      doAssert reverseBits(reverseBits(x)) == x
+
+    proc testReverseBitsPerType(x, reversed: uint64) =
+      doAssert reverseBits(x) == reversed
+      doAssert reverseBits(cast[uint32](x)) == cast[uint32](reversed shr 32)
+      doAssert reverseBits(cast[uint32](x shr 16)) == cast[uint32](reversed shr 16)
+      doAssert reverseBits(cast[uint16](x)) == cast[uint16](reversed shr 48)
+      doAssert reverseBits(cast[uint8](x)) == cast[uint8](reversed shr 56)
+
+      testReverseBitsInvo(x)
+      testReverseBitsInvo(cast[uint32](x))
+      testReverseBitsInvo(cast[uint16](x))
+      testReverseBitsInvo(cast[uint8](x))
+
+    proc testReverseBitsRefl(x, reversed: uint64) =
+      testReverseBitsPerType(x, reversed)
+      testReverseBitsPerType(reversed, x)
+
+    proc testReverseBitsShift(d, b: uint64) =
+      var
+        x = d
+        y = b
+
+      for i in 1..64:
+        testReverseBitsRefl(x, y)
+        x = x shl 1
+        y = y shr 1
+
+    proc testReverseBits(d, b: uint64) =
+      testReverseBitsShift(d, b)
+
+    testReverseBits(0x0u64, 0x0u64)
+    testReverseBits(0xffffffffffffffffu64, 0xffffffffffffffffu64)
+    testReverseBits(0x0123456789abcdefu64, 0xf7b3d591e6a2c480u64)
+    testReverseBits(0x5555555555555555u64, 0xaaaaaaaaaaaaaaaau64)
+    testReverseBits(0x5555555500000001u64, 0x80000000aaaaaaaau64)
+    testReverseBits(0x55555555aaaaaaaau64, 0x55555555aaaaaaaau64)
+    testReverseBits(0xf0f0f0f00f0f0f0fu64, 0xf0f0f0f00f0f0f0fu64)
+    testReverseBits(0x181881810ff00916u64, 0x68900ff081811818u64)
 
   echo "OK"
 
+  # bug #7587
+  doAssert popcount(0b11111111'i8) == 8
+
+block: # not ready for vm because exception is compile error
+  try:
+    var v: uint32
+    var i = 32
+    v.setBit(i)
+    doAssert false
+  except RangeDefect:
+    discard
+  except:
+    doAssert false
+
+
 main()
+static:
+  # test everything on vm as well
+  main()
diff --git a/tests/stdlib/tbitops.nim.cfg b/tests/stdlib/tbitops.nim.cfg
index f0d7668a7..013e8d38e 100644
--- a/tests/stdlib/tbitops.nim.cfg
+++ b/tests/stdlib/tbitops.nim.cfg
@@ -1 +1 @@
--d:noUndefinedBitOps
+-d:noUndefinedBitOpts
diff --git a/tests/stdlib/tbitops2.nim b/tests/stdlib/tbitops2.nim
deleted file mode 100644
index 31952316c..000000000
--- a/tests/stdlib/tbitops2.nim
+++ /dev/null
@@ -1,168 +0,0 @@
-discard """
-  file: "tbitops.nim"
-  output: "OK"
-"""
-import bitops
-
-
-proc main() =
-  const U8 = 0b0011_0010'u8
-  const I8 = 0b0011_0010'i8
-  const U16 = 0b00100111_00101000'u16
-  const I16 = 0b00100111_00101000'i16
-  const U32 = 0b11010101_10011100_11011010_01010000'u32
-  const I32 = 0b11010101_10011100_11011010_01010000'i32
-  const U64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64
-  const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
-  const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
-  const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
-
-  doAssert( U64A.fastLog2 == 62)
-  doAssert( I64A.fastLog2 == 62)
-  doAssert( U64A.countLeadingZeroBits == 1)
-  doAssert( I64A.countLeadingZeroBits == 1)
-  doAssert( U64A.countTrailingZeroBits == 0)
-  doAssert( I64A.countTrailingZeroBits == 0)
-  doAssert( U64A.firstSetBit == 1)
-  doAssert( I64A.firstSetBit == 1)
-  doAssert( U64A.parityBits == 1)
-  doAssert( I64A.parityBits == 1)
-  doAssert( U64A.countSetBits == 29)
-  doAssert( I64A.countSetBits == 29)
-  doAssert( U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64)
-  doAssert( U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64)
-
-  doAssert( U64B.firstSetBit == 36)
-  doAssert( I64B.firstSetBit == 36)
-
-  doAssert( U32.fastLog2 == 31)
-  doAssert( I32.fastLog2 == 31)
-  doAssert( U32.countLeadingZeroBits == 0)
-  doAssert( I32.countLeadingZeroBits == 0)
-  doAssert( U32.countTrailingZeroBits == 4)
-  doAssert( I32.countTrailingZeroBits == 4)
-  doAssert( U32.firstSetBit == 5)
-  doAssert( I32.firstSetBit == 5)
-  doAssert( U32.parityBits == 0)
-  doAssert( I32.parityBits == 0)
-  doAssert( U32.countSetBits == 16)
-  doAssert( I32.countSetBits == 16)
-  doAssert( U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32)
-  doAssert( U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32)
-
-  doAssert( U16.fastLog2 == 13)
-  doAssert( I16.fastLog2 == 13)
-  doAssert( U16.countLeadingZeroBits == 2)
-  doAssert( I16.countLeadingZeroBits == 2)
-  doAssert( U16.countTrailingZeroBits == 3)
-  doAssert( I16.countTrailingZeroBits == 3)
-  doAssert( U16.firstSetBit == 4)
-  doAssert( I16.firstSetBit == 4)
-  doAssert( U16.parityBits == 0)
-  doAssert( I16.parityBits == 0)
-  doAssert( U16.countSetBits == 6)
-  doAssert( I16.countSetBits == 6)
-  doAssert( U16.rotateLeftBits(12) == 0b10000010_01110010'u16)
-  doAssert( U16.rotateRightBits(12) == 0b01110010_10000010'u16)
-
-  doAssert( U8.fastLog2 == 5)
-  doAssert( I8.fastLog2 == 5)
-  doAssert( U8.countLeadingZeroBits == 2)
-  doAssert( I8.countLeadingZeroBits == 2)
-  doAssert( U8.countTrailingZeroBits == 1)
-  doAssert( I8.countTrailingZeroBits == 1)
-  doAssert( U8.firstSetBit == 2)
-  doAssert( I8.firstSetBit == 2)
-  doAssert( U8.parityBits == 1)
-  doAssert( I8.parityBits == 1)
-  doAssert( U8.countSetBits == 3)
-  doAssert( I8.countSetBits == 3)
-  doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
-  doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
-
-  static :
-    # test bitopts at compile time with vm
-    doAssert( U8.fastLog2 == 5)
-    doAssert( I8.fastLog2 == 5)
-    doAssert( U8.countLeadingZeroBits == 2)
-    doAssert( I8.countLeadingZeroBits == 2)
-    doAssert( U8.countTrailingZeroBits == 1)
-    doAssert( I8.countTrailingZeroBits == 1)
-    doAssert( U8.firstSetBit == 2)
-    doAssert( I8.firstSetBit == 2)
-    doAssert( U8.parityBits == 1)
-    doAssert( I8.parityBits == 1)
-    doAssert( U8.countSetBits == 3)
-    doAssert( I8.countSetBits == 3)
-    doAssert( U8.rotateLeftBits(3) == 0b10010001'u8)
-    doAssert( U8.rotateRightBits(3) == 0b0100_0110'u8)
-
-
-
-  template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) =
-    doAssert( ffunc(0'u8) == expected)
-    doAssert( ffunc(0'i8) == expected)
-    doAssert( ffunc(0'u16) == expected)
-    doAssert( ffunc(0'i16) == expected)
-    doAssert( ffunc(0'u32) == expected)
-    doAssert( ffunc(0'i32) == expected)
-    doAssert( ffunc(0'u64) == expected)
-    doAssert( ffunc(0'i64) == expected)
-
-  template test_undefined(ffunc: untyped; expected: int) =
-    test_undefined_impl(ffunc, expected, false)
-    static:
-      test_undefined_impl(ffunc, expected, true)
-
-  when defined(noUndefinedBitOpts):
-    # check for undefined behavior with zero.
-    test_undefined(countSetBits, 0)
-    test_undefined(parityBits, 0)
-    test_undefined(firstSetBit, 0)
-    test_undefined(countLeadingZeroBits, 0)
-    test_undefined(countTrailingZeroBits, 0)
-    test_undefined(fastLog2, -1)
-
-    # check for undefined behavior with rotate by zero.
-    doAssert( U8.rotateLeftBits(0) == U8)
-    doAssert( U8.rotateRightBits(0) == U8)
-    doAssert( U16.rotateLeftBits(0) == U16)
-    doAssert( U16.rotateRightBits(0) == U16)
-    doAssert( U32.rotateLeftBits(0) == U32)
-    doAssert( U32.rotateRightBits(0) == U32)
-    doAssert( U64A.rotateLeftBits(0) == U64A)
-    doAssert( U64A.rotateRightBits(0) == U64A)
-
-    # check for undefined behavior with rotate by integer width.
-    doAssert( U8.rotateLeftBits(8) == U8)
-    doAssert( U8.rotateRightBits(8) == U8)
-    doAssert( U16.rotateLeftBits(16) == U16)
-    doAssert( U16.rotateRightBits(16) == U16)
-    doAssert( U32.rotateLeftBits(32) == U32)
-    doAssert( U32.rotateRightBits(32) == U32)
-    doAssert( U64A.rotateLeftBits(64) == U64A)
-    doAssert( U64A.rotateRightBits(64) == U64A)
-
-    static:    # check for undefined behavior with rotate by zero.
-      doAssert( U8.rotateLeftBits(0) == U8)
-      doAssert( U8.rotateRightBits(0) == U8)
-      doAssert( U16.rotateLeftBits(0) == U16)
-      doAssert( U16.rotateRightBits(0) == U16)
-      doAssert( U32.rotateLeftBits(0) == U32)
-      doAssert( U32.rotateRightBits(0) == U32)
-      doAssert( U64A.rotateLeftBits(0) == U64A)
-      doAssert( U64A.rotateRightBits(0) == U64A)
-
-      # check for undefined behavior with rotate by integer width.
-      doAssert( U8.rotateLeftBits(8) == U8)
-      doAssert( U8.rotateRightBits(8) == U8)
-      doAssert( U16.rotateLeftBits(16) == U16)
-      doAssert( U16.rotateRightBits(16) == U16)
-      doAssert( U32.rotateLeftBits(32) == U32)
-      doAssert( U32.rotateRightBits(32) == U32)
-      doAssert( U64A.rotateLeftBits(64) == U64A)
-      doAssert( U64A.rotateRightBits(64) == U64A)
-
-  echo "OK"
-
-main()
diff --git a/tests/stdlib/tbitops2.nim.cfg b/tests/stdlib/tbitops2.nim.cfg
deleted file mode 100644
index e1cb77e82..000000000
--- a/tests/stdlib/tbitops2.nim.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
--d:noIntrinsicsBitOpts
--d:noUndefinedBitOps
diff --git a/tests/stdlib/tbitops_utils.nim b/tests/stdlib/tbitops_utils.nim
new file mode 100644
index 000000000..e3f96fecc
--- /dev/null
+++ b/tests/stdlib/tbitops_utils.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/bitops_utils
+import std/assertions
+
+template chk(a, b) =
+  let a2 = castToUnsigned(a)
+  doAssert a2 == b
+  doAssert type(a2) is type(b)
+  doAssert type(b) is type(a2)
+
+chk 1'i8, 1'u8
+chk -1'i8, 255'u8
+chk 1'u8, 1'u8
+chk 1'u, 1'u
+chk -1, cast[uint](-1)
+chk -1'i64, cast[uint64](-1)
diff --git a/tests/stdlib/tbug5382.nim b/tests/stdlib/tbug5382.nim
deleted file mode 100644
index c86656d32..000000000
--- a/tests/stdlib/tbug5382.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-discard """
-  output: '''
-02
-'''
-"""
-import re
-
-let regexp = re"^\/([0-9]{2})\.html$"
-var matches: array[1, string]
-discard "/02.html".find(regexp, matches)
-echo matches[0]
diff --git a/tests/stdlib/tcasts.nim b/tests/stdlib/tcasts.nim
new file mode 100644
index 000000000..e01c7e940
--- /dev/null
+++ b/tests/stdlib/tcasts.nim
@@ -0,0 +1,26 @@
+import std/[strutils]
+import std/[assertions, objectdollar]
+
+# bug #19101
+type
+  Small = object
+    a: int
+
+  Big = object
+    a, b, c, d: int
+
+proc main =
+  var
+    n = 1'i8
+    f = 2.0
+    s = Small(a: 1)
+    b = Big(a: 12345, b: 23456, c: 34567, d: 45678)
+
+  doAssert $cast[int](f).toBin(64) == "0100000000000000000000000000000000000000000000000000000000000000"
+  f = cast[float](n)
+  doAssert $cast[int](f).toBin(64) == "0000000000000000000000000000000000000000000000000000000000000001"
+
+  doAssert $b == "(a: 12345, b: 23456, c: 34567, d: 45678)"
+  b = cast[Big](s)
+  doAssert $b == "(a: 1, b: 0, c: 0, d: 0)"
+main()
diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim
new file mode 100644
index 000000000..ef39450da
--- /dev/null
+++ b/tests/stdlib/tcgi.nim
@@ -0,0 +1,31 @@
+discard """

+  matrix: "--mm:refc; --mm:orc"

+"""

+

+import std/unittest

+import std/[cgi, strtabs, sugar]

+import std/assertions

+

+block: # Test cgi module

+  const queryString = "foo=bar&фу=бар&checked=✓&list=1,2,3&with_space=text%20with%20space"

+

+  block: # test query parsing with readData

+    let parsedQuery = readData(queryString)

+

+    check parsedQuery["foo"] == "bar"

+    check parsedQuery["фу"] == "бар"

+    check parsedQuery["checked"] == "✓"

+    check parsedQuery["list"] == "1,2,3"

+    check parsedQuery["with_space"] == "text with space"

+

+    expect KeyError:

+      discard parsedQuery["not_existing_key"]

+

+# bug #15369

+let queryString = "a=1&b=0&c=3&d&e&a=5&a=t%20e%20x%20t&e=http%3A%2F%2Fw3schools.com%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab"

+

+doAssert collect(for pair in decodeData(queryString): pair) ==

+  @[("a", "1"), ("b", "0"), ("c", "3"),

+    ("d", ""),("e", ""), ("a", "5"), ("a", "t e x t"),

+  ("e", "http://w3schools.com/my test.asp?name=ståle&car=saab")

+]

diff --git a/tests/stdlib/tclosures.nim b/tests/stdlib/tclosures.nim
new file mode 100644
index 000000000..84b033fa8
--- /dev/null
+++ b/tests/stdlib/tclosures.nim
@@ -0,0 +1,47 @@
+discard """
+  targets: "c js"
+"""
+
+import std/assertions
+
+block: # bug #4299
+  proc scopeProc() =
+    proc normalProc() =
+      discard
+
+    proc genericProc[T]() =
+      normalProc()
+
+    genericProc[string]()
+
+  scopeProc()
+
+block: # bug #12492
+  proc foo() =
+    var i = 0
+    proc bar() =
+      inc i
+
+    bar()
+    doAssert i == 1
+
+  foo()
+  static:
+    foo()
+
+block: # bug #10849
+  type
+    Generic[T] = ref object
+      getState: proc(): T
+
+  proc newGeneric[T](): Generic[T] =
+    var state: T
+
+    proc getState[T](): T =
+      state
+
+    Generic[T](getState: getState)
+
+  let g = newGeneric[int]()
+  let state = g.getState()
+  doAssert state == 0
diff --git a/tests/stdlib/tcmdline.nim b/tests/stdlib/tcmdline.nim
new file mode 100644
index 000000000..8b428900b
--- /dev/null
+++ b/tests/stdlib/tcmdline.nim
@@ -0,0 +1,13 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+  joinable: false
+"""
+
+import std/os
+import std/assertions
+
+var params = paramCount()
+doAssert params == 0
+doAssert paramStr(0).len > 0
+doAssert commandLineParams().len == 0
diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim
new file mode 100644
index 000000000..ca83314b9
--- /dev/null
+++ b/tests/stdlib/tcomplex.nim
@@ -0,0 +1,115 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[complex, math]
+import std/assertions
+
+proc `=~`[T](x, y: Complex[T]): bool =
+  result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6
+
+proc `=~`[T](x: Complex[T]; y: T): bool =
+  result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6
+
+let
+  z: Complex64 = complex(0.0, 0.0)
+  oo: Complex64 = complex(1.0, 1.0)
+  a: Complex64 = complex(1.0, 2.0)
+  b: Complex64 = complex(-1.0, -2.0)
+  m1: Complex64 = complex(-1.0, 0.0)
+  i: Complex64 = complex(0.0, 1.0)
+  one: Complex64 = complex(1.0, 0.0)
+  tt: Complex64 = complex(10.0, 20.0)
+  ipi: Complex64 = complex(0.0, -PI)
+
+doAssert(a/2.0 =~ complex(0.5, 1.0))
+doAssert(a == a)
+doAssert((a-a) == z)
+doAssert((a+b) == z)
+doAssert((a+b) =~ 0.0)
+doAssert((a/b) == m1)
+doAssert((1.0/a) =~ complex(0.2, -0.4))
+doAssert((a*b) == complex(3.0, -4.0))
+doAssert(10.0*a == tt)
+doAssert(a*10.0 == tt)
+doAssert(tt/10.0 == a)
+doAssert(oo+(-1.0) == i)
+doAssert( (-1.0)+oo == i)
+doAssert(abs(oo) == sqrt(2.0))
+doAssert(conjugate(a) == complex(1.0, -2.0))
+doAssert(sqrt(m1) == i)
+doAssert(exp(ipi) =~ m1)
+
+doAssert(pow(a, b) =~ complex(-3.72999124927876, -1.68815826725068))
+doAssert(pow(z, a) =~ complex(0.0, 0.0))
+doAssert(pow(z, z) =~ complex(1.0, 0.0))
+doAssert(pow(a, one) =~ a)
+doAssert(pow(a, m1) =~ complex(0.2, -0.4))
+doAssert(pow(a, 2.0) =~ complex(-3.0, 4.0))
+doAssert(pow(a, 2) =~ complex(-3.0, 4.0))
+doAssert(not(pow(a, 2.0) =~ a))
+
+doAssert(ln(a) =~ complex(0.804718956217050, 1.107148717794090))
+doAssert(log10(a) =~ complex(0.349485002168009, 0.480828578784234))
+doAssert(log2(a) =~ complex(1.16096404744368, 1.59727796468811))
+
+doAssert(sin(a) =~ complex(3.16577851321617, 1.95960104142161))
+doAssert(cos(a) =~ complex(2.03272300701967, -3.05189779915180))
+doAssert(tan(a) =~ complex(0.0338128260798967, 1.0147936161466335))
+doAssert(cot(a) =~ 1.0 / tan(a))
+doAssert(sec(a) =~ 1.0 / cos(a))
+doAssert(csc(a) =~ 1.0 / sin(a))
+doAssert(arcsin(a) =~ complex(0.427078586392476, 1.528570919480998))
+doAssert(arccos(a) =~ complex(1.14371774040242, -1.52857091948100))
+doAssert(arctan(a) =~ complex(1.338972522294494, 0.402359478108525))
+doAssert(arccot(a) =~ complex(0.2318238045004031, -0.402359478108525))
+doAssert(arcsec(a) =~ complex(1.384478272687081, 0.3965682301123288))
+doAssert(arccsc(a) =~ complex(0.1863180541078155, -0.3965682301123291))
+
+doAssert(cosh(a) =~ complex(-0.642148124715520, 1.068607421382778))
+doAssert(sinh(a) =~ complex(-0.489056259041294, 1.403119250622040))
+doAssert(tanh(a) =~ complex(1.1667362572409199, -0.243458201185725))
+doAssert(sech(a) =~ 1.0 / cosh(a))
+doAssert(csch(a) =~ 1.0 / sinh(a))
+doAssert(coth(a) =~ 1.0 / tanh(a))
+doAssert(arccosh(a) =~ complex(1.528570919480998, 1.14371774040242))
+doAssert(arcsinh(a) =~ complex(1.469351744368185, 1.06344002357775))
+doAssert(arctanh(a) =~ complex(0.173286795139986, 1.17809724509617))
+doAssert(arcsech(a) =~ arccosh(1.0/a))
+doAssert(arccsch(a) =~ arcsinh(1.0/a))
+doAssert(arccoth(a) =~ arctanh(1.0/a))
+
+doAssert(phase(a) == 1.1071487177940904)
+let t = polar(a)
+doAssert(rect(t.r, t.phi) =~ a)
+doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817))
+
+doAssert(almostEqual(a, a + complex(1e-16, 1e-16)))
+doAssert(almostEqual(a, a + complex(2e-15, 2e-15), unitsInLastPlace = 5))
+
+
+let
+  i64: Complex32 = complex(0.0f, 1.0f)
+  a64: Complex32 = 2.0f*i64 + 1.0.float32
+  b64: Complex32 = complex(-1.0'f32, -2.0'f32)
+
+doAssert(a64 == a64)
+doAssert(a64 == -b64)
+doAssert(a64 + b64 =~ 0.0'f32)
+doAssert(not(pow(a64, b64) =~ a64))
+doAssert(pow(a64, 0.5f) =~ sqrt(a64))
+doAssert(pow(a64, 2) =~ complex(-3.0'f32, 4.0'f32))
+doAssert(sin(arcsin(b64)) =~ b64)
+doAssert(cosh(arccosh(a64)) =~ a64)
+
+doAssert(phase(a64) - 1.107149f < 1e-6)
+let t64 = polar(a64)
+doAssert(rect(t64.r, t64.phi) =~ a64)
+doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f))
+doAssert(sizeof(a64) == 8)
+doAssert(sizeof(a) == 16)
+
+doAssert 123.0.im + 456.0 == complex64(456, 123)
+
+let localA = complex(0.1'f32)
+doAssert localA.im is float32
diff --git a/tests/stdlib/tcookies.nim b/tests/stdlib/tcookies.nim
new file mode 100644
index 000000000..3ff0f3bae
--- /dev/null
+++ b/tests/stdlib/tcookies.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+
+import std/[cookies, times, strtabs]
+import std/assertions
+
+let expire = fromUnix(0) + 1.seconds
+
+let theCookies = [
+  setCookie("test", "value", expire),
+  setCookie("test", "value", expire.local),
+  setCookie("test", "value", expire.utc)
+]
+let expected = "Set-Cookie: test=value; Expires=Thu, 01 Jan 1970 00:00:01 GMT"
+doAssert theCookies == [expected, expected, expected]
+
+let table = parseCookies("uid=1; kp=2")
+doAssert table["uid"] == "1"
+doAssert table["kp"] == "2"
diff --git a/tests/stdlib/tcount.nim b/tests/stdlib/tcount.nim
deleted file mode 100644
index ce1d14b6c..000000000
--- a/tests/stdlib/tcount.nim
+++ /dev/null
@@ -1,29 +0,0 @@
-discard """
-  output: '''1
-2
-3
-4
-5
-done'''
-"""
-
-# bug #1845, #2224
-
-var arr = [3,2,1,5,4]
-
-# bubble sort
-for i in low(arr)..high(arr):
-  for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeError]
-    if arr[i] > arr[j]:
-      let tmp = arr[i]
-      arr[i] = arr[j]
-      arr[j] = tmp
-
-for i in low(arr)..high(arr):
-  echo arr[i]
-
-# check this terminates:
-for x in countdown('\255', '\0'):
-  discard
-
-echo "done"
diff --git a/tests/stdlib/tcputime.nim b/tests/stdlib/tcputime.nim
deleted file mode 100644
index 2fc46ee64..000000000
--- a/tests/stdlib/tcputime.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-
-import times, os
-
-var e = epochTime()
-var c = cpuTime()
-
-os.sleep(1500)
-
-e = epochTime() - e
-c = cpuTime() - c
-
-echo "epochTime: ", e, " cpuTime: ", c
-
diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim
index 8280ec881..e6282f045 100644
--- a/tests/stdlib/tcritbits.nim
+++ b/tests/stdlib/tcritbits.nim
@@ -1,28 +1,89 @@
 discard """
-  output: '''abc
-def
-definition
-prefix
-xyz
-def
-definition'''
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
 """
 
-import critbits
+import std/[sequtils,critbits]
+import std/assertions
 
-when isMainModule:
-  var r: TCritBitTree[void]
+template main =
+  var r: CritBitTree[void]
   r.incl "abc"
   r.incl "xyz"
   r.incl "def"
   r.incl "definition"
   r.incl "prefix"
+  r.incl "foo"
+
   doAssert r.contains"def"
-  #r.del "def"
 
-  for w in r.items:
-    echo w
+  r.excl "def"
+  doAssert r.missingOrExcl("foo") == false
+  doAssert "foo" notin toSeq(r.items)
+
+  doAssert r.missingOrExcl("foo") == true
+
+  doAssert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
+
+  doAssert toSeq(r.itemsWithPrefix("de")) == @["definition"]
+  var c = CritBitTree[int]()
+
+  c.inc("a")
+  doAssert c["a"] == 1
+
+  c.inc("a", 4)
+  doAssert c["a"] == 5
+
+  c.inc("a", -5)
+  doAssert c["a"] == 0
+
+  c.inc("b", 2)
+  doAssert c["b"] == 2
+
+  c.inc("c", 3)
+  doAssert c["c"] == 3
+
+  c.inc("a", 1)
+  doAssert c["a"] == 1
+
+  var cf = CritBitTree[float]()
+
+  cf.incl("a", 1.0)
+  doAssert cf["a"] == 1.0
+
+  cf.incl("b", 2.0)
+  doAssert cf["b"] == 2.0
+
+  cf.incl("c", 3.0)
+  doAssert cf["c"] == 3.0
+
+  doAssert cf.len == 3
+  cf.excl("c")
+  doAssert cf.len == 2
+
+  var cb: CritBitTree[string]
+  cb.incl("help", "help")
+  for k in cb.keysWithPrefix("helpp"):
+    doAssert false, "there is no prefix helpp"
+
+  block: # bug #14339
+    var strings: CritBitTree[int]
+    discard strings.containsOrIncl("foo", 3)
+    doAssert strings["foo"] == 3
 
-  for w in r.itemsWithPrefix("de"):
-    echo w
+  block tcritbitsToString:
+    block:
+      var t: CritBitTree[int]
+      t["a"] = 1
+      doAssert $t == """{"a": 1}"""
+    block:
+      var t: CritBitTree[string]
+      t["a"] = "1"
+      doAssert $t == """{"a": "1"}"""
+    block:
+      var t: CritBitTree[char]
+      t["a"] = '1'
+      doAssert $t == """{"a": '1'}"""
 
+main()
+static: main()
diff --git a/tests/stdlib/tcstring.nim b/tests/stdlib/tcstring.nim
new file mode 100644
index 000000000..d7fdd7738
--- /dev/null
+++ b/tests/stdlib/tcstring.nim
@@ -0,0 +1,93 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+from std/sugar import collect
+from stdtest/testutils import whenRuntimeJs, whenVMorJs
+import std/assertions
+
+template testMitems() =
+  block:
+    var a = "abc"
+    var b = a.cstring
+    let s = collect:
+      for bi in mitems(b):
+        if bi == 'b': bi = 'B'
+        bi
+    whenRuntimeJs:
+      discard # xxx mitems should give CT error instead of @['\x00', '\x00', '\x00']
+    do:
+      doAssert s == @['a', 'B', 'c']
+
+  block:
+    var a = "abc\0def"
+    var b = a.cstring
+    let s = collect:
+      for bi in mitems(b):
+        if bi == 'b': bi = 'B'
+        bi
+    whenRuntimeJs:
+      discard # ditto
+    do:
+      doAssert s == @['a', 'B', 'c']
+
+proc mainProc() =
+  testMitems()
+
+template main() =
+  block: # bug #13859
+    let str = "abc".cstring
+    doAssert len(str).int8 == 3
+    doAssert len(str).int16 == 3
+    doAssert len(str).int32 == 3
+    var str2 = "cde".cstring
+    doAssert len(str2).int8 == 3
+    doAssert len(str2).int16 == 3
+    doAssert len(str2).int32 == 3
+
+    const str3 = "abc".cstring
+    doAssert len(str3).int32 == 3
+    doAssert len("abc".cstring).int16 == 3
+    doAssert len("abc".cstring).float32 == 3.0
+
+  block: # bug #17159
+    block:
+      var a = "abc"
+      var b = a.cstring
+      doAssert $(b, ) == """("abc",)"""
+      let s = collect:
+        for bi in b: bi
+      doAssert s == @['a', 'b', 'c']
+
+    block:
+      var a = "abc\0def"
+      var b = a.cstring
+      let s = collect:
+        for bi in b: bi
+      whenRuntimeJs:
+        doAssert $(b, ) == """("abc\x00def",)"""
+        doAssert s == @['a', 'b', 'c', '\x00', 'd', 'e', 'f']
+      do:
+        doAssert $(b, ) == """("abc",)"""
+        doAssert s == @['a', 'b', 'c']
+
+  block:
+    when defined(gcArc): # xxx SIGBUS
+      discard
+    else:
+      mainProc()
+    when false: # xxx bug vm: Error: unhandled exception: 'node' is not accessible using discriminant 'kind' of type 'TFullReg' [FieldDefect]
+      testMitems()
+
+  block: # bug #13321: [codegen] --gc:arc does not properly emit cstring, results in SIGSEGV
+    let a = "hello".cstring
+    doAssert $a == "hello"
+    doAssert $a[0] == "h"
+    doAssert $a[4] == "o"
+    whenVMorJs: discard # xxx this should work in vm, refs https://github.com/timotheecour/Nim/issues/619
+    do:
+      doAssert a[a.len] == '\0'
+
+static: main()
+main()
diff --git a/tests/stdlib/tcstrutils.nim b/tests/stdlib/tcstrutils.nim
new file mode 100644
index 000000000..e73b2b681
--- /dev/null
+++ b/tests/stdlib/tcstrutils.nim
@@ -0,0 +1,39 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/cstrutils
+import std/assertions
+
+proc main() =
+  let s = cstring "abcdef"
+  doAssert s.startsWith("a")
+  doAssert not s.startsWith("b")
+  doAssert s.endsWith("f")
+  doAssert not s.endsWith("a")
+  doAssert s.startsWith("")
+  doAssert s.endsWith("")
+
+  let a = cstring "abracadabra"
+  doAssert a.startsWith("abra")
+  doAssert not a.startsWith("bra")
+  doAssert a.endsWith("abra")
+  doAssert not a.endsWith("dab")
+  doAssert a.startsWith("")
+  doAssert a.endsWith("")
+
+  doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0
+  doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0
+  doAssert cmpIgnoreCase(cstring "Foo5", "foo4") > 0
+
+  doAssert cmpIgnoreStyle(cstring "foo_bar", "FooBar") == 0
+  doAssert cmpIgnoreStyle(cstring "foo_bar_5", "FooBar4") > 0
+
+  doAssert cmpIgnoreCase(cstring "", cstring "") == 0
+  doAssert cmpIgnoreCase(cstring "", cstring "Hello") < 0
+  doAssert cmpIgnoreCase(cstring "wind", cstring "") > 0
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tdb.nim b/tests/stdlib/tdb.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/stdlib/tdb.nim
diff --git a/tests/stdlib/tdb.nims b/tests/stdlib/tdb.nims
new file mode 100644
index 000000000..d31d0b26f
--- /dev/null
+++ b/tests/stdlib/tdb.nims
@@ -0,0 +1 @@
+--styleCheck:off
\ No newline at end of file
diff --git a/tests/stdlib/tdb_mysql.nim b/tests/stdlib/tdb_mysql.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/stdlib/tdb_mysql.nim
diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim
new file mode 100644
index 000000000..42dc646f2
--- /dev/null
+++ b/tests/stdlib/tdecls.nim
@@ -0,0 +1,50 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+import std/assertions
+import std/decls
+
+template fun() =
+  var s = @[10,11,12]
+  var a {.byaddr.} = s[0]
+  a+=100
+  doAssert s == @[110,11,12]
+  doAssert a is int
+  var b {.byaddr.}: int = s[0]
+  doAssert a.addr == b.addr
+
+  {.push warningAsError[ImplicitTemplateRedefinition]: on.}
+  # in the future ImplicitTemplateRedefinition will be an error anyway
+  doAssert not compiles(block:
+    # redeclaration not allowed
+    var foo = 0
+    var foo {.byaddr.} = s[0])
+
+  doAssert not compiles(block:
+    # ditto
+    var foo {.byaddr.} = s[0]
+    var foo {.byaddr.} = s[0])
+  {.pop.}
+
+  block:
+    var b {.byaddr.} = s[1] # redeclaration ok in sub scope
+    b = 123
+
+  doAssert s == @[110,123,12]
+
+  b = b * 10
+  doAssert s == @[1100,123,12]
+
+  doAssert not compiles(block:
+    var b2 {.byaddr.}: float = s[2])
+
+  doAssert compiles(block:
+    var b2 {.byaddr.}: int = s[2])
+
+proc fun2() = fun()
+fun()
+fun2()
+static: fun2()
+when false: # pending bug #13887
+  static: fun()
diff --git a/tests/stdlib/tdecode_helpers.nim b/tests/stdlib/tdecode_helpers.nim
new file mode 100644
index 000000000..1c0735e05
--- /dev/null
+++ b/tests/stdlib/tdecode_helpers.nim
@@ -0,0 +1,27 @@
+import std/private/decode_helpers
+import std/assertions
+
+block:
+  var i = 0
+  let c = decodePercent("%t9", i)
+  doAssert (i, c) == (0, '%')
+
+block:
+  var i = 0
+  let c = decodePercent("19", i)
+  doAssert (i, c) == (0, '%')
+
+block:
+  var i = 0
+  let c = decodePercent("%19", i)
+  doAssert (i, c) == (2, '\x19')
+
+block:
+  var i = 0
+  let c = decodePercent("%A9", i)
+  doAssert (i, c) == (2, '\xA9')
+
+block:
+  var i = 0
+  let c = decodePercent("%Aa", i)
+  doAssert (i, c) == (2, '\xAA')
diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim
new file mode 100644
index 000000000..39ff996d1
--- /dev/null
+++ b/tests/stdlib/tdeques.nim
@@ -0,0 +1,243 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/deques
+from std/sequtils import toSeq
+import std/assertions
+
+block:
+  proc index(self: Deque[int], idx: Natural): int =
+    self[idx]
+
+  proc main =
+    var testDeque = initDeque[int]()
+    testDeque.addFirst(1)
+    doAssert testDeque.index(0) == 1
+
+  main()
+
+block:
+  var d = initDeque[int]()
+  d.addLast(1)
+  doAssert $d == "[1]"
+block:
+  var d = initDeque[string]()
+  d.addLast("1")
+  doAssert $d == """["1"]"""
+block:
+  var d = initDeque[char]()
+  d.addLast('1')
+  doAssert $d == "['1']"
+
+block:
+  var deq = initDeque[int](1)
+  deq.addLast(4)
+  deq.addFirst(9)
+  deq.addFirst(123)
+  var first = deq.popFirst()
+  deq.addLast(56)
+  doAssert(deq.peekLast() == 56)
+  deq.addLast(6)
+  doAssert(deq.peekLast() == 6)
+  var second = deq.popFirst()
+  deq.addLast(789)
+  doAssert(deq.peekLast() == 789)
+
+  doAssert first == 123
+  doAssert second == 9
+  doAssert($deq == "[4, 56, 6, 789]")
+  doAssert deq == [4, 56, 6, 789].toDeque
+
+  doAssert deq[0] == deq.peekFirst and deq.peekFirst == 4
+  #doAssert deq[^1] == deq.peekLast and deq.peekLast == 789
+  deq[0] = 42
+  deq[deq.len - 1] = 7
+
+  doAssert 6 in deq and 789 notin deq
+  doAssert deq.find(6) >= 0
+  doAssert deq.find(789) < 0
+
+  block:
+    var d = initDeque[int](1)
+    d.addLast 7
+    d.addLast 8
+    d.addLast 10
+    d.addFirst 5
+    d.addFirst 2
+    d.addFirst 1
+    d.addLast 20
+    d.shrink(fromLast = 2)
+    doAssert($d == "[1, 2, 5, 7, 8]")
+    d.shrink(2, 1)
+    doAssert($d == "[5, 7]")
+    d.shrink(2, 2)
+    doAssert d.len == 0
+
+  for i in -2 .. 10:
+    if i in deq:
+      doAssert deq.contains(i) and deq.find(i) >= 0
+    else:
+      doAssert(not deq.contains(i) and deq.find(i) < 0)
+
+  when compileOption("boundChecks"):
+    try:
+      echo deq[99]
+      doAssert false
+    except IndexDefect:
+      discard
+
+    try:
+      doAssert deq.len == 4
+      for i in 0 ..< 5: deq.popFirst()
+      doAssert false
+    except IndexDefect:
+      discard
+
+  # grabs some types of resize error.
+  deq = initDeque[int]()
+  for i in 1 .. 4: deq.addLast i
+  deq.popFirst()
+  deq.popLast()
+  for i in 5 .. 8: deq.addFirst i
+  doAssert $deq == "[8, 7, 6, 5, 2, 3]"
+
+  # Similar to proc from the documentation example
+  proc foo(a, b: Positive) = # assume random positive values for `a` and `b`.
+    var deq = initDeque[int]()
+    doAssert deq.len == 0
+    for i in 1 .. a: deq.addLast i
+
+    if b < deq.len: # checking before indexed access.
+      doAssert deq[b] == b + 1
+
+    # The following two lines don't need any checking on access due to the logic
+    # of the program, but that would not be the case if `a` could be 0.
+    doAssert deq.peekFirst == 1
+    doAssert deq.peekLast == a
+
+    while deq.len > 0: # checking if the deque is empty
+      doAssert deq.popFirst() > 0
+
+  #foo(0,0)
+  foo(8, 5)
+  foo(10, 9)
+  foo(1, 1)
+  foo(2, 1)
+  foo(1, 5)
+  foo(3, 2)
+
+import std/sets
+
+block t13310:
+  proc main() =
+    var q = initDeque[HashSet[int16]](2)
+    q.addFirst([1'i16].toHashSet)
+    q.addFirst([2'i16].toHashSet)
+    q.addFirst([3'i16].toHashSet)
+    doAssert $q == "[{3}, {2}, {1}]"
+
+  static:
+    main()
+
+
+proc main() =
+  block:
+    let a = [10, 20, 30].toDeque
+    doAssert toSeq(a.pairs) == @[(0, 10), (1, 20), (2, 30)]
+
+  block:
+    let q = [7, 9].toDeque
+    doAssert 7 in q
+    doAssert q.contains(7)
+    doAssert 8 notin q
+
+  block:
+    let a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.peekFirst == 10
+    doAssert len(a) == 5
+
+  block:
+    let a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.peekLast == 50
+    doAssert len(a) == 5
+
+  block:
+    var a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.popFirst == 10
+    doAssert $a == "[20, 30, 40, 50]"
+
+  block:
+    var a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.popLast == 50
+    doAssert $a == "[10, 20, 30, 40]"
+
+  block:
+    var a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    clear(a)
+    doAssert len(a) == 0
+
+  block: # bug #21278
+    var a = [10, 20, 30, 40].toDeque
+
+    a.shrink(fromFirst = 0, fromLast = 1)
+    doAssert $a == "[10, 20, 30]"
+
+  block:
+    var a, b: Deque[int]
+    for i in 1 .. 256:
+      a.addLast(i)
+    for i in 1 .. 255:
+      a.popLast
+    b.addLast(1)
+    doAssert a == b
+
+  block:
+    # Issue 23275
+    # Test `==`.
+    block:
+      var a, b = initDeque[int]()
+      doAssert a == b
+      doAssert a.hash == b.hash
+      a.addFirst(1)
+      doAssert a != b
+      doAssert a.hash != b.hash
+      b.addLast(1)
+      doAssert a == b
+      doAssert a.hash == b.hash
+      a.popFirst
+      b.popLast
+      doAssert a == b
+      doAssert a.hash == b.hash
+      a.addLast 2
+      doAssert a != b
+      doAssert a.hash != b.hash
+      b.addFirst 2
+      doAssert a == b
+      doAssert a.hash == b.hash
+
+    block:
+      var a, b = initDeque[int]()
+      for i in countDown(100, 1):
+        a.addFirst(i)
+      for i in 1..100:
+        b.addLast(i)
+      doAssert a == b
+      for i in 1..99:
+        a.popLast
+      let a1 = [1].toDeque
+      doAssert a == a1
+      doAssert a.hash == a1.hash
+      var c = initDeque[int]()
+      c.addLast(1)
+      doAssert a == c
+      doAssert a.hash == c.hash
+
+static: main()
+main()
diff --git a/tests/stdlib/tdiff.nim b/tests/stdlib/tdiff.nim
new file mode 100644
index 000000000..132f7120b
--- /dev/null
+++ b/tests/stdlib/tdiff.nim
@@ -0,0 +1,75 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import experimental/diff
+import std/strutils
+import std/assertions
+
+proc testHelper(f: seq[Item]): string =
+  for it in f:
+    result.add(
+      $it.deletedA & "." & $it.insertedB & "." & $it.startA & "." & $it.startB & "*"
+    )
+
+proc main() =
+  var a, b: string
+
+  # Diff Self Test
+  # test all changes
+  a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n')
+  b = "0,1,2,3,4,5,6,7,8,9".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "12.10.0.0*",
+    "all-changes test failed.")
+  # test all same
+  a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n')
+  b = a
+  doAssert(testHelper(diffText(a, b)) ==
+    "",
+    "all-same test failed.")
+
+  # test snake
+  a = "a,b,c,d,e,f".replace(',', '\n')
+  b = "b,c,d,e,f,x".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "1.0.0.0*0.1.6.5*",
+    "snake test failed.")
+
+  # 2002.09.20 - repro
+  a = "c1,a,c2,b,c,d,e,g,h,i,j,c3,k,l".replace(',', '\n')
+  b = "C1,a,C2,b,c,d,e,I1,e,g,h,i,j,C3,k,I2,l".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "1.1.0.0*1.1.2.2*0.2.7.7*1.1.11.13*0.1.13.15*",
+    "repro20020920 test failed.")
+
+  # 2003.02.07 - repro
+  a = "F".replace(',', '\n')
+  b = "0,F,1,2,3,4,5,6,7".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "0.1.0.0*0.7.1.2*",
+    "repro20030207 test failed.")
+
+  # Muegel - repro
+  a = "HELLO\nWORLD"
+  b = "\n\nhello\n\n\n\nworld\n"
+  doAssert(testHelper(diffText(a, b)) ==
+    "2.8.0.0*",
+    "repro20030409 test failed.")
+
+  # test some differences
+  a = "a,b,-,c,d,e,f,f".replace(',', '\n')
+  b = "a,b,x,c,e,f".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "1.1.2.2*1.0.4.4*1.0.7.6*",
+    "some-changes test failed.")
+
+  # test one change within long chain of repeats
+  a = "a,a,a,a,a,a,a,a,a,a".replace(',', '\n')
+  b = "a,a,a,a,-,a,a,a,a,a".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "0.1.4.4*1.0.9.10*",
+    "long chain of repeats test failed.")
+main()
+static: main()
diff --git a/tests/stdlib/tdistros_detect.nim b/tests/stdlib/tdistros_detect.nim
new file mode 100644
index 000000000..1176c8993
--- /dev/null
+++ b/tests/stdlib/tdistros_detect.nim
@@ -0,0 +1,16 @@
+import std/[assertions, distros]
+
+when defined(windows):
+    doAssert detectOs(Windows) == true
+    doAssert detectOs(Linux) == false
+    doAssert detectOs(MacOSX) == false
+
+when defined(linux):
+    doAssert detectOs(Linux) == true
+    doAssert detectOs(Windows) == false
+    doAssert detectOs(MacOSX) == false
+
+when defined(macosx):
+    doAssert detectOs(MacOSX) == true
+    doAssert detectOs(Windows) == false
+    doAssert detectOs(Linux) == false
diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim
new file mode 100644
index 000000000..4d532b5d0
--- /dev/null
+++ b/tests/stdlib/tdochelpers.nim
@@ -0,0 +1,221 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+
+[Suite] Integration with Nim
+'''
+"""
+
+# tests for dochelpers.nim module
+
+import ../../lib/packages/docutils/[rstast, rst, dochelpers]
+import unittest
+import std/assertions
+
+proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
+                    arg: string) =
+  doAssert msgkind == mwBrokenLink
+
+proc fromRst(text: string): LangSymbol =
+  let r = rstParse(text, "-input-", LineRstInit, ColRstInit,
+                   {roNimFile},
+                   msgHandler=testMsgHandler)
+  assert r.node.kind == rnRstRef
+  result = toLangSymbol(r.node)
+
+proc fromMd(text: string): LangSymbol =
+  let r = rstParse(text, "-input-", LineRstInit, ColRstInit,
+                   {roPreferMarkdown, roSupportMarkdown, roNimFile},
+                   msgHandler=testMsgHandler)
+  assert r.node.kind == rnPandocRef
+  assert r.node.len == 2
+  # this son is the target:
+  assert r.node.sons[1].kind == rnInner
+  result = toLangSymbol(r.node.sons[1])
+
+suite "Integration with Nim":
+  test "simple symbol parsing (shortest form)":
+    let expected = LangSymbol(symKind: "", name: "g")
+    check "g_".fromRst == expected
+    check "[g]".fromMd == expected
+    # test also alternative syntax variants of Pandoc Markdown:
+    check "[g][]".fromMd == expected
+    check "[this symbol][g]".fromMd == expected
+
+  test "simple symbol parsing (group of words)":
+    #let input1 = "`Y`_".rstParseTest
+    let expected1 = LangSymbol(symKind: "", name: "Y")
+    check "`Y`_".fromRst == expected1
+    check "[Y]".fromMd == expected1
+
+    # this means not a statement 'type', it's a backticked identifier `type`:
+    let expected2 = LangSymbol(symKind: "", name: "type")
+    check "`type`_".fromRst == expected2
+    check "[type]".fromMd == expected2
+
+    let expected3 = LangSymbol(symKind: "", name: "[]")
+    check "`[]`_".fromRst == expected3
+    # Markdown syntax for this case is NOT [[]]
+    check "[`[]`]".fromMd == expected3
+
+    let expected4 = LangSymbol(symKind: "", name: "Xyz")
+    check "`X Y Z`_".fromRst == expected4
+    check "[X Y Z]".fromMd == expected4
+
+  test "simple proc parsing":
+    let expected = LangSymbol(symKind: "proc", name: "f")
+    check "`proc f`_".fromRst == expected
+    check "[proc f]".fromMd == expected
+
+  test "another backticked name":
+    let expected = LangSymbol(symKind: "template", name: "type")
+    check """`template \`type\``_""".fromRst == expected
+    # no backslash in Markdown:
+    check """[template `type`]""".fromMd == expected
+
+  test "simple proc parsing with parameters":
+    let expected = LangSymbol(symKind: "proc", name: "f",
+                              parametersProvided: true)
+    check "`proc f*()`_".fromRst == expected
+    check "`proc f()`_".fromRst == expected
+    check "[proc f*()]".fromMd == expected
+    check "[proc f()]".fromMd == expected
+
+  test "symbol parsing with 1 parameter":
+    let expected = LangSymbol(symKind: "", name: "f",
+                              parameters: @[("G[int]", "")],
+                              parametersProvided: true)
+    check "`f(G[int])`_".fromRst == expected
+    check "[f(G[int])]".fromMd == expected
+
+  test "more proc parsing":
+    let input1 = "`proc f[T](x:G[T]):M[T]`_".fromRst
+    let input2 = "`proc f[ T ] ( x: G [T] ): M[T]`_".fromRst
+    let input3 = "`proc f*[T](x: G[T]): M[T]`_".fromRst
+    let expected = LangSymbol(symKind: "proc",
+                              name: "f",
+                              generics: "[T]",
+                              parameters: @[("x", "G[T]")],
+                              parametersProvided: true,
+                              outType: "M[T]")
+    check(input1 == expected)
+    check(input2 == expected)
+    check(input3 == expected)
+
+  test "advanced proc parsing with Nim identifier normalization":
+    let inputRst = """`proc binarySearch*[T, K](a: openarray[T]; key: K;
+                       cmp: proc (x: T; y: K): int)`_"""
+    let inputMd = """[proc binarySearch*[T, K](a: openarray[T]; key: K;
+                       cmp: proc (x: T; y: K): int)]"""
+    let expected = LangSymbol(symKind: "proc",
+                              name: "binarysearch",
+                              generics: "[T,K]",
+                              parameters: @[
+                                ("a", "openarray[T]"),
+                                ("key", "K"),
+                                ("cmp", "proc(x:T;y:K):int")],
+                              parametersProvided: true,
+                              outType: "")
+    check(inputRst.fromRst == expected)
+    check(inputMd.fromMd == expected)
+
+  test "the same without proc":
+    let input = """`binarySearch*[T, K](a: openarray[T]; key: K;
+                    cmp: proc (x: T; y: K): int {.closure.})`_"""
+    let expected = LangSymbol(symKind: "",
+                              name: "binarysearch",
+                              generics: "[T,K]",
+                              parameters: @[
+                                ("a", "openarray[T]"),
+                                ("key", "K"),
+                                ("cmp", "proc(x:T;y:K):int")],
+                              parametersProvided: true,
+                              outType: "")
+    check(input.fromRst == expected)
+    let inputMd = """[binarySearch*[T, K](a: openarray[T]; key: K;
+                      cmp: proc (x: T; y: K): int {.closure.})]"""
+    check(inputMd.fromMd == expected)
+
+  test "operator $ with and without backticks":
+    let input1 = """`func \`$\`*[T](a: \`open Array\`[T]): string`_"""
+    let input1md = "[func `$`*[T](a: `open Array`[T]): string]"
+    let input2 = """`func $*[T](a: \`open Array\`[T]): string`_"""
+    let input2md = "[func $*[T](a: `open Array`[T]): string]"
+    let expected = LangSymbol(symKind: "func",
+                              name: "$",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]")],
+                              parametersProvided: true,
+                              outType: "string")
+    check input1.fromRst == expected
+    check input2.fromRst == expected
+    check input1md.fromMd == expected
+    check input2md.fromMd == expected
+
+  test "operator [] with and without backticks":
+    let input1 = """`func \`[]\`[T](a: \`open Array\`[T], idx: int): T`_"""
+    let input1md = "[func `[]`[T](a: `open Array`[T], idx: int): T]"
+    let input2 = """`func [][T](a: \`open Array\`[T], idx: int): T`_"""
+    let input2md = "[func [][T](a: `open Array`[T], idx: int): T]"
+    let expected = LangSymbol(symKind: "func",
+                              name: "[]",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]"),
+                                            ("idx", "int")],
+                              parametersProvided: true,
+                              outType: "T")
+    check input1.fromRst == expected
+    check input2.fromRst == expected
+    check input1md.fromMd == expected
+    check input2md.fromMd == expected
+
+  test "postfix symbol specifier #1":
+    let input = "`walkDir iterator`_"
+    let inputMd = "[walkDir iterator]"
+    let expected = LangSymbol(symKind: "iterator",
+                              name: "walkdir")
+    check input.fromRst == expected
+    check inputMd.fromMd == expected
+
+  test "postfix symbol specifier #2":
+    let input1 = """`\`[]\`[T](a: \`open Array\`[T], idx: int): T func`_"""
+    let input1md = "[`[]`[T](a: `open Array`[T], idx: int): T func]"
+    let input2 = """`[][T](a: \`open Array\`[T], idx: int): T func`_"""
+    # note again that ` is needed between 1st and second [
+    let input2md = "[`[]`[T](a: `open Array`[T], idx: int): T func]"
+    let expected = LangSymbol(symKind: "func",
+                              name: "[]",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]"),
+                                            ("idx", "int")],
+                              parametersProvided: true,
+                              outType: "T")
+    check input1.fromRst == expected
+    check input2.fromRst == expected
+    check input1md.fromMd == expected
+    check input2md.fromMd == expected
+
+  test "type of type":
+    let inputRst = "`CopyFlag enum`_"
+    let inputMd = "[CopyFlag enum]"
+    let expected = LangSymbol(symKind: "type",
+                              symTypeKind: "enum",
+                              name: "Copyflag")
+    check inputRst.fromRst == expected
+    check inputMd.fromMd == expected
+
+  test "prefixed module":
+    let inputRst = "`module std / paths`_"
+    let inputMd = "[module std / paths]"
+    let expected = LangSymbol(symKind: "module",
+                              name: "std/paths")
+    check inputRst.fromRst == expected
+    check inputMd.fromMd == expected
+
+  test "postfixed module":
+    let inputRst = "`std / paths module`_"
+    let inputMd = "[std / paths module]"
+    let expected = LangSymbol(symKind: "module",
+                              name: "std/paths")
+    check inputRst.fromRst == expected
+    check inputMd.fromMd == expected
diff --git a/tests/stdlib/techo.nim b/tests/stdlib/techo.nim
deleted file mode 100644
index 9cef9205f..000000000
--- a/tests/stdlib/techo.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-# Simplest Nim program
-
-echo "Hello, World!"
diff --git a/tests/stdlib/teditdistance.nim b/tests/stdlib/teditdistance.nim
new file mode 100644
index 000000000..14ba6df97
--- /dev/null
+++ b/tests/stdlib/teditdistance.nim
@@ -0,0 +1,45 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/editdistance
+import std/assertions
+
+doAssert editDistance("", "") == 0
+doAssert editDistance("kitten", "sitting") == 3 # from Wikipedia
+doAssert editDistance("flaw", "lawn") == 2 # from Wikipedia
+
+doAssert editDistance("привет", "превет") == 1
+doAssert editDistance("Åge", "Age") == 1
+# editDistance, one string is longer in bytes, but shorter in rune length
+# first string: 4 bytes, second: 6 bytes, but only 3 runes
+doAssert editDistance("aaaa", "×××") == 4
+
+block veryLongStringEditDistanceTest:
+  const cap = 256
+  var
+    s1 = newStringOfCap(cap)
+    s2 = newStringOfCap(cap)
+  while len(s1) < cap:
+    s1.add 'a'
+  while len(s2) < cap:
+    s2.add 'b'
+  doAssert editDistance(s1, s2) == cap
+
+block combiningCodePointsEditDistanceTest:
+  const s = "A\xCC\x8Age"
+  doAssert editDistance(s, "Age") == 1
+
+doAssert editDistanceAscii("", "") == 0
+doAssert editDistanceAscii("kitten", "sitting") == 3 # from Wikipedia
+doAssert editDistanceAscii("flaw", "lawn") == 2 # from Wikipedia
+
+
+doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3)
+doAssert(editDistance("prefix__hallo_suffix", "prefix") == 14)
+doAssert(editDistance("prefix__hallo_suffix", "suffix") == 14)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2)
+doAssert(editDistance("main", "malign") == 2)
\ No newline at end of file
diff --git a/tests/stdlib/tencodings.nim b/tests/stdlib/tencodings.nim
new file mode 100644
index 000000000..2f4daaba3
--- /dev/null
+++ b/tests/stdlib/tencodings.nim
@@ -0,0 +1,107 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/encodings
+import std/assertions
+
+var fromGBK = open("utf-8", "gbk")
+var toGBK = open("gbk", "utf-8")
+
+var fromGB2312 = open("utf-8", "gb2312")
+var toGB2312 = open("gb2312", "utf-8")
+
+
+block:
+  let data = "\215\237\186\243\178\187\214\170\204\236\212\218\203\174\163\172\194\250\180\178\208\199\195\206\209\185\208\199\186\211"
+  doAssert fromGBK.convert(data) == "醉后不知天在水,满床星梦压星河"
+
+block:
+  let data = "万两黄金容易得,知心一个也难求"
+  doAssert toGBK.convert(data) == "\205\242\193\189\187\198\189\240\200\221\210\215\181\195\163\172\214\170\208\196\210\187\184\246\210\178\196\209\199\243"
+
+
+block:
+  let data = "\215\212\208\197\200\203\201\250\182\254\176\217\196\234\163\172\187\225\181\177\203\174\187\247\200\253\199\167\192\239"
+  doAssert fromGB2312.convert(data) == "自信人生二百年,会当水击三千里"
+
+block:
+  let data = "谁怕?一蓑烟雨任平生"
+  doAssert toGB2312.convert(data) == "\203\173\197\194\163\191\210\187\203\242\209\204\211\234\200\206\198\189\201\250"
+
+
+when defined(windows):
+  block should_throw_on_unsupported_conversions:
+    let original = "some string"
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-8", "utf-32")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-8", "unicodeFFFE")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-8", "utf-32BE")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "unicodeFFFE", "utf-8")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-32", "utf-8")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-32BE", "utf-8")
+
+  block should_convert_from_utf16_to_utf8:
+    let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест"
+    let result = convert(original, "utf-8", "utf-16")
+    doAssert(result == "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82")
+
+  block should_convert_from_utf16_to_win1251:
+    let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "тест"
+    let result = convert(original, "windows-1251", "utf-16")
+    doAssert(result == "\xf2\xe5\xf1\xf2")
+
+  block should_convert_from_win1251_to_koi8r:
+    let original = "\xf2\xe5\xf1\xf2" # win1251 test string "тест"
+    let result = convert(original, "koi8-r", "windows-1251")
+    doAssert(result == "\xd4\xc5\xd3\xd4")
+
+  block should_convert_from_koi8r_to_win1251:
+    let original = "\xd4\xc5\xd3\xd4" # koi8r test string "тест"
+    let result = convert(original, "windows-1251", "koi8-r")
+    doAssert(result == "\xf2\xe5\xf1\xf2")
+
+  block should_convert_from_utf8_to_win1251:
+    let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест"
+    let result = convert(original, "windows-1251", "utf-8")
+    doAssert(result == "\xf2\xe5\xf1\xf2")
+
+  block should_convert_from_utf8_to_utf16:
+    let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "тест"
+    let result = convert(original, "utf-16", "utf-8")
+    doAssert(result == "\x42\x04\x35\x04\x41\x04\x42\x04")
+
+  block should_handle_empty_string_for_any_conversion:
+    let original = ""
+    var result = convert(original, "utf-16", "utf-8")
+    doAssert(result == "")
+    result = convert(original, "utf-8", "utf-16")
+    doAssert(result == "")
+    result = convert(original, "windows-1251", "koi8-r")
+    doAssert(result == "")
+
+
+block:
+  let
+    orig = "öäüß"
+    cp1252 = convert(orig, "CP1252", "UTF-8")
+    ibm850 = convert(cp1252, "ibm850", "CP1252")
+    current = getCurrentEncoding()
+  doAssert orig == "\195\182\195\164\195\188\195\159"
+  doAssert ibm850 == "\148\132\129\225"
+  doAssert convert(ibm850, current, "ibm850") == orig
+
+block: # fixes about #23481
+  doAssertRaises EncodingError:
+    discard open(destEncoding="this is a invalid enc")
diff --git a/tests/stdlib/tenumerate.nim b/tests/stdlib/tenumerate.nim
new file mode 100644
index 000000000..2789ebe3a
--- /dev/null
+++ b/tests/stdlib/tenumerate.nim
@@ -0,0 +1,24 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/enumerate
+import std/assertions
+
+let a = @[1, 3, 5, 7]
+
+block:
+  var res: seq[(int, int)]
+  for i, x in enumerate(a):
+    res.add (i, x)
+  doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)]
+block:
+  var res: seq[(int, int)]
+  for (i, x) in enumerate(a.items):
+    res.add (i, x)
+  doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)]
+block:
+  var res: seq[(int, int)]
+  for i, x in enumerate(3, a):
+    res.add (i, x)
+  doAssert res == @[(3, 1), (4, 3), (5, 5), (6, 7)]
diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim
new file mode 100644
index 000000000..2662a660d
--- /dev/null
+++ b/tests/stdlib/tenumutils.nim
@@ -0,0 +1,49 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/enumutils
+from std/sequtils import toSeq
+import std/assertions
+
+template main =
+  block: # items
+    type A = enum a0 = 2, a1 = 4, a2
+    type B[T] = enum b0 = 2, b1 = 4
+    doAssert A.toSeq == [a0, a1, a2]
+    doAssert B[float].toSeq == [B[float].b0, B[float].b1]
+
+  block: # symbolName
+    block:
+      type A2 = enum a20, a21, a22
+      doAssert $a21 == "a21"
+      doAssert a21.symbolName == "a21"
+      proc `$`(a: A2): string = "foo"
+      doAssert $a21 == "foo"
+      doAssert a21.symbolName == "a21"
+      var a = a22
+      doAssert $a == "foo"
+      doAssert a.symbolName == "a22"
+
+    type B = enum
+      b0 = (10, "kb0")
+      b1 = "kb1"
+      b2
+    let b = B.low
+    doAssert b.symbolName == "b0"
+    doAssert $b == "kb0"
+    static: doAssert B.high.symbolName == "b2"
+
+  block:
+    type
+      Color = enum
+        Red = "red", Yellow = "yellow", Blue = "blue"
+
+    var s = Red
+    doAssert symbolName(s) == "Red"
+    var x: range[Red..Blue] = Yellow
+    doAssert symbolName(x) == "Yellow"
+
+static: main()
+main()
diff --git a/tests/stdlib/tenvvars.nim b/tests/stdlib/tenvvars.nim
new file mode 100644
index 000000000..1a07f02b8
--- /dev/null
+++ b/tests/stdlib/tenvvars.nim
@@ -0,0 +1,162 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+  targets: "c js cpp"
+"""
+
+import std/envvars
+from std/sequtils import toSeq
+import stdtest/testutils
+import std/[assertions]
+
+when not defined(js):
+  import std/typedthreads
+
+# "LATIN CAPITAL LETTER AE" in UTF-8 (0xc386)
+const unicodeUtf8 = "\xc3\x86"
+
+template main =
+  block: # delEnv, existsEnv, getEnv, envPairs
+    for val in ["val", "", unicodeUtf8]: # ensures empty val works too
+      const key = "NIM_TESTS_TOSENV_KEY"
+      doAssert not existsEnv(key)
+
+      putEnv(key, "tempval")
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == "tempval"
+
+      putEnv(key, val) # change a key that already exists
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == val
+
+      doAssert (key, val) in toSeq(envPairs())
+      delEnv(key)
+      doAssert (key, val) notin toSeq(envPairs())
+      doAssert not existsEnv(key)
+      delEnv(key) # deleting an already deleted env var
+      doAssert not existsEnv(key)
+
+    block:
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == ""
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " "
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval"
+
+    whenVMorJs: discard # xxx improve
+    do:
+      doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE"))
+      doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE"))
+      doAssert not existsEnv("")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT")
+
+static: main()
+main()
+
+when defined(windows):
+  import std/widestrs
+  proc c_wgetenv(env: WideCString): WideCString {.importc: "_wgetenv", header: "<stdlib.h>".}
+proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
+
+when not defined(js) and not defined(nimscript):
+  block: # bug #18533
+    var thr: Thread[void]
+    proc threadFunc {.thread.} = putEnv("foo", "fooVal2")
+
+    putEnv("foo", "fooVal1")
+    doAssert getEnv("foo") == "fooVal1"
+    createThread(thr, threadFunc)
+    joinThreads(thr)
+    when defined(windows):
+      doAssert getEnv("foo") == $c_wgetenv("foo".newWideCString)
+    else:
+      doAssert getEnv("foo") == $c_getenv("foo".cstring)
+
+    doAssertRaises(OSError): delEnv("foo=bar")
+
+when defined(windows) and not defined(nimscript):
+  import std/encodings
+
+  proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "<stdlib.h>".}
+  proc c_wputenv(env: WideCString): int32 {.importc: "_wputenv", header: "<stdlib.h>".}
+
+  block: # Bug #20083
+    # These test that `getEnv`, `putEnv` and `existsEnv` handle Unicode
+    # characters correctly. This means that module X in the process calling the
+    # CRT environment variable API will get the correct string. Raw CRT API
+    # calls below represent module X.
+
+    # Getting an env. var. with unicode characters returns the correct UTF-8
+    # encoded string.
+    block:
+      const envName = "twin_envvars1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Putting an env. var. with unicode characters gives the correct UTF-16
+    # encoded string from low-level routine.
+    block:
+      const envName = "twin_envvars2"
+      putEnv(envName, unicodeUtf8)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters is retrieved correctly
+    block:
+      const envName = unicodeUtf8 & "1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Env. name containing Unicode characters is set correctly
+    block:
+      const envName = unicodeUtf8 & "2"
+      putEnv(envName, unicodeUtf8)
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters and empty value is set correctly
+    block:
+      const envName = unicodeUtf8 & "3"
+      putEnv(envName, "")
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == ""
+
+    # It's hard to test on Windows code pages, because there is no "change
+    # a process' locale" API.
+    if getCurrentEncoding(true) == "windows-1252":
+      const
+        unicodeAnsi = "\xc6" # `unicodeUtf8` in `windows-1252` encoding
+
+      # Test that env. var. ANSI API has correct encoding
+      block:
+        const
+          envName = unicodeUtf8 & "4"
+          envNameAnsi = unicodeAnsi & "4"
+        putEnv(envName, unicodeUtf8)
+        doAssert $c_getenv(envNameAnsi.cstring) == unicodeAnsi
+
+      block:
+        const
+          envName = unicodeUtf8 & "5"
+          envNameAnsi = unicodeAnsi & "5"
+        doAssert c_putenv((envNameAnsi & "=" & unicodeAnsi).cstring) == 0
+        doAssert getEnv(envName) == unicodeUtf8
+
+      # Env. name containing Unicode characters and empty value is set correctly;
+      # and, if env. name. characters cannot be represented in codepage, don't
+      # raise an error.
+      #
+      # `win_setenv.nim` converts UTF-16 to ANSI when setting empty env. var. The
+      # windows-1250 locale has no representation of `abreveUtf8` below, so the
+      # conversion will fail, but this must not be fatal. It is expected that the
+      # routine ignores updating MBCS environment (`environ` global) and carries
+      # on.
+      block:
+        const
+          # "LATIN SMALL LETTER A WITH BREVE" in UTF-8
+          abreveUtf8 = "\xc4\x83"
+          envName = abreveUtf8 & "6"
+        putEnv(envName, "")
+        doAssert existsEnv(envName)
+        doAssert $c_wgetenv(envName.newWideCString) == ""
+        doAssert getEnv(envName) == ""
diff --git a/tests/stdlib/testequivalence.nim b/tests/stdlib/testequivalence.nim
deleted file mode 100644
index 7acaad340..000000000
--- a/tests/stdlib/testequivalence.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-discard """
-  output: ''''''
-"""
-import sets
-
-doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "equivalent or subset")
-doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3]), "equivalent or subset")
-doAssert((not(toSet(@[1,2,3]) <= toSet(@[1,2]))), "equivalent or subset")
-doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "strict subset")
-doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2,3]))), "strict subset")
-doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2]))), "strict subset")
-doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2,3,4]))), "==")
-doAssert(toSet(@[1,2,3]) == toSet(@[1,2,3]), "==")
-doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2]))), "==")
diff --git a/tests/stdlib/texitprocs.nim b/tests/stdlib/texitprocs.nim
new file mode 100644
index 000000000..ea29d8f58
--- /dev/null
+++ b/tests/stdlib/texitprocs.nim
@@ -0,0 +1,22 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+targets: "c cpp js"
+output: '''
+ok4
+ok3
+ok2
+ok1
+'''
+"""
+
+import std/exitprocs
+
+proc fun1() {.noconv.} = echo "ok1"
+proc fun2() = echo "ok2"
+proc fun3() {.noconv.} = echo "ok3"
+proc fun4() = echo "ok4"
+
+addExitProc(fun1)
+addExitProc(fun2)
+addExitProc(fun3)
+addExitProc(fun4)
diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim
new file mode 100644
index 000000000..272a7507c
--- /dev/null
+++ b/tests/stdlib/tfdleak.nim
@@ -0,0 +1,152 @@
+discard """
+  exitcode: 0
+  output: ""
+  matrix: "; -d:nimInheritHandles; --mm:refc"
+  joinable: false
+"""
+
+import os, osproc, strutils, nativesockets, net, selectors, memfiles,
+       asyncdispatch, asyncnet
+
+import std/[assertions, syncio]
+
+when defined(windows):
+  import winlean
+
+  # Note: Windows 10-only API
+  proc compareObjectHandles(first, second: Handle): WINBOOL
+                           {.stdcall, dynlib: "kernelbase",
+                             importc: "CompareObjectHandles".}
+else:
+  import posix
+
+proc leakCheck(f: AsyncFD | int | FileHandle | SocketHandle, msg: string,
+               expectLeak = defined(nimInheritHandles)) =
+  var args = @[$f.int, msg, $expectLeak]
+
+  when defined(windows):
+    var refFd: Handle
+    # NOTE: This function shouldn't be used to duplicate sockets,
+    #       as this function may mess with the socket internal refcounting.
+    #       but due to the lack of type segmentation in the stdlib for
+    #       Windows (AsyncFD can be a file or a socket), we will have to
+    #       settle with this.
+    #
+    #       Now, as a poor solution for the refcounting problem, we just
+    #       simply let the duplicated handle leak. This should not interfere
+    #       with the test since new handles can't occupy the slot held by
+    #       the leaked ones.
+    if duplicateHandle(getCurrentProcess(), f.Handle,
+                       getCurrentProcess(), addr refFd,
+                       0, 1, DUPLICATE_SAME_ACCESS) == 0:
+      raiseOSError osLastError(), "Couldn't create the reference handle"
+    args.add $refFd
+
+  discard startProcess(
+    getAppFilename(),
+    args = args,
+    options = {poParentStreams}
+  ).waitForExit
+
+proc isValidHandle(f: int): bool =
+  ## Check if a handle is valid. Requires OS-native handles.
+  when defined(windows):
+    var flags: DWORD
+    result = getHandleInformation(f.Handle, addr flags) != 0
+  else:
+    result = fcntl(f.cint, F_GETFD) != -1
+
+proc main() =
+  if paramCount() == 0:
+    # Parent process
+    let f = syncio.open("__test_fdleak", fmReadWrite)
+    defer: close f
+
+    leakCheck(f.getOsFileHandle, "system.open()")
+
+    doAssert f.reopen("__test_fdleak2", fmReadWrite), "reopen failed"
+
+    leakCheck(f.getOsFileHandle, "reopen")
+
+    let sock = createNativeSocket()
+    defer: close sock
+    leakCheck(sock, "createNativeSocket()")
+    if sock.setInheritable(not defined(nimInheritHandles)):
+      leakCheck(sock, "createNativeSocket()", not defined(nimInheritHandles))
+    else:
+      raiseOSError osLastError()
+
+    let server = newSocket()
+    defer: close server
+    server.bindAddr(address = "127.0.0.1")
+    server.listen()
+    let (_, port) = server.getLocalAddr
+
+    leakCheck(server.getFd, "newSocket()")
+
+    let client = newSocket()
+    defer: close client
+    client.connect("127.0.0.1", port)
+
+    var input: Socket
+    server.accept(input)
+
+    leakCheck(input.getFd, "accept()")
+
+    # ioselectors_select doesn't support returning a handle.
+    when not defined(windows):
+      let selector = newSelector[int]()
+      leakCheck(selector.getFd, "selector()", false)
+
+    var mf = memfiles.open("__test_fdleak3", fmReadWrite, newFileSize = 1)
+    defer: close mf
+    when defined(windows):
+      leakCheck(mf.mapHandle, "memfiles.open().mapHandle", false)
+    else:
+      leakCheck(mf.handle, "memfiles.open().handle", false)
+
+    let sockAsync = createAsyncNativeSocket()
+    defer: closeSocket sockAsync
+    leakCheck(sockAsync, "createAsyncNativeSocket()")
+    if sockAsync.setInheritable(not defined(nimInheritHandles)):
+      leakCheck(sockAsync, "createAsyncNativeSocket()", not defined(nimInheritHandles))
+    else:
+      raiseOSError osLastError()
+
+    let serverAsync = newAsyncSocket()
+    defer: close serverAsync
+    serverAsync.bindAddr(address = "127.0.0.1")
+    serverAsync.listen()
+    let (_, portAsync) = serverAsync.getLocalAddr
+
+    leakCheck(serverAsync.getFd, "newAsyncSocket()")
+
+    let clientAsync = newAsyncSocket()
+    defer: close clientAsync
+    waitFor clientAsync.connect("127.0.0.1", portAsync)
+
+    let inputAsync = waitFor serverAsync.accept()
+
+    leakCheck(inputAsync.getFd, "accept() async")
+  else:
+    let
+      fd = parseInt(paramStr 1)
+      expectLeak = parseBool(paramStr 3)
+      msg = (if expectLeak: "not " else: "") & "leaked " & paramStr 2
+    let validHandle =
+      when defined(windows):
+        # On Windows, due to the use of winlean, causes the program to open
+        # a handle to the various dlls that's loaded. This handle might
+        # collide with the handle sent for testing.
+        #
+        # As a walkaround, we pass an another handle that's purposefully leaked
+        # as a reference so that we can verify whether the "leaked" handle
+        # is the right one.
+        let refFd = parseInt(paramStr 4)
+        fd.isValidHandle and compareObjectHandles(fd, refFd) != 0
+      else:
+        fd.isValidHandle
+    if expectLeak xor validHandle:
+      echo msg
+
+when isMainModule: main()
diff --git a/tests/stdlib/tfdleak_multiple.nim b/tests/stdlib/tfdleak_multiple.nim
new file mode 100644
index 000000000..c26681217
--- /dev/null
+++ b/tests/stdlib/tfdleak_multiple.nim
@@ -0,0 +1,31 @@
+discard """
+joinable: false
+"""
+
+import os, osproc, strutils
+import std/assertions
+
+const Iterations = 200
+
+proc testFdLeak() =
+  var count = 0
+  let
+    test = getAppDir() / "tfdleak"
+    exe = test.addFileExt(ExeExt).quoteShell
+    options = ["", "-d:nimInheritHandles"]
+  for opt in options:
+    let
+      run = "nim c $1 $2" % [opt, quoteShell test]
+      (output, status) = execCmdEx run
+    doAssert status == 0, "Test complination failed:\n$1\n$2" % [run, output]
+    for i in 1..Iterations:
+      let (output, status) = execCmdEx exe
+      doAssert status == 0, "Execution of " & exe & " failed"
+      if "leaked" in output:
+        count.inc
+    doAssert count == 0, "Leaked " & $count & " times"
+
+when defined(windows):
+  # tfdleak was only flaky for windows (and for netbsd, there is still a bug)
+  # note that this test is quite slow, 87 sec on windows.
+  testFdLeak()
diff --git a/tests/stdlib/tfenv.nim b/tests/stdlib/tfenv.nim
new file mode 100644
index 000000000..a486b8a9d
--- /dev/null
+++ b/tests/stdlib/tfenv.nim
@@ -0,0 +1,8 @@
+import std/fenv
+import std/assertions
+
+
+func is_significant(x: float): bool =
+  x > minimumPositiveValue(float) and x < maximumPositiveValue(float)
+
+doAssert is_significant(10.0)
diff --git a/tests/stdlib/tfilesanddirs.nim b/tests/stdlib/tfilesanddirs.nim
new file mode 100644
index 000000000..a1920d4f2
--- /dev/null
+++ b/tests/stdlib/tfilesanddirs.nim
@@ -0,0 +1,36 @@
+import std/[paths, files, dirs, appdirs]
+
+from stdtest/specialpaths import buildDir
+import std/[syncio, assertions]
+
+block fileOperations:
+  let files = @[Path"these.txt", Path"are.x", Path"testing.r", Path"files.q"]
+  let dirs = @[Path"some", Path"created", Path"test", Path"dirs"]
+
+  let dname = Path"__really_obscure_dir_name"
+
+  createDir(dname.Path)
+  doAssert dirExists(Path(dname))
+ 
+  # Test creating files and dirs
+  for dir in dirs:
+    createDir(Path(dname/dir))
+    doAssert dirExists(Path(dname/dir))
+
+  for file in files:
+    let fh = open(string(dname/file), fmReadWrite) # createFile
+    fh.close()
+    doAssert fileExists(Path(dname/file))
+
+block: # getCacheDir
+  doAssert getCacheDir().dirExists
+
+block: # moveFile
+  let tempDir = getTempDir() / Path("D20221022T151608")
+  createDir(tempDir)
+  defer: removeDir(tempDir)
+
+block: # moveDir
+  let tempDir = getTempDir() / Path("D20220609T161443")
+  createDir(tempDir)
+  defer: removeDir(tempDir)
diff --git a/tests/stdlib/tformat.nim b/tests/stdlib/tformat.nim
deleted file mode 100644
index 160ab0fd5..000000000
--- a/tests/stdlib/tformat.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-discard """
-  file: "tformat.nim"
-  output: "Hi Andreas! How do you feel, Rumpf?"
-"""
-# Tests the new format proc (including the & and &= operators)
-
-import strutils
-
-echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])
-#OUT Hi Andreas! How do you feel, Rumpf?
-
-
diff --git a/tests/stdlib/tfrexp1.nim b/tests/stdlib/tfrexp1.nim
index c6bb2b38c..aa734ddac 100644
--- a/tests/stdlib/tfrexp1.nim
+++ b/tests/stdlib/tfrexp1.nim
@@ -1,13 +1,16 @@
 discard """
-  targets: "js c c++"
-  output: '''ok'''
+  matrix: "--mm:refc; --mm:orc"
+  targets: "js c cpp"
 """
 
-import math
-import strformat
+import std/math
+import std/assertions
 
 const manualTest = false
 
+when manualTest:
+  import strformat
+
 proc frexp_test(lo, hi, step: float64) =
   var exp: int
   var frac: float64
@@ -39,6 +42,14 @@ when manualTest:
 
   frexp_test(-1000.0, 1000.0, 0.0125)
 else:
-  frexp_test(-1000000.0, 1000000.0, 0.125)
+  frexp_test(-200000.0, 200000.0, 0.125)
+
+
+doAssert frexp(8.0) == (0.5, 4)
+doAssert frexp(-8.0) == (-0.5, 4)
+doAssert frexp(0.0) == (0.0, 0)
 
-echo "ok"
+block:
+  var x: int
+  doAssert frexp(5.0, x) == 0.625
+  doAssert x == 3
diff --git a/tests/stdlib/tgenast.nim b/tests/stdlib/tgenast.nim
new file mode 100644
index 000000000..d99c9312e
--- /dev/null
+++ b/tests/stdlib/tgenast.nim
@@ -0,0 +1,274 @@
+discard """
+  matrix: "--mm:orc; --mm:refc"
+"""
+
+# xxx also test on js
+
+import std/genasts
+import std/macros
+from std/strformat import `&`
+import std/assertions
+import ./mgenast
+
+proc main =
+  block:
+    macro bar(x0: static Foo, x1: Foo, x2: Foo, xignored: Foo): untyped =
+      let s0 = "not captured!"
+      let s1 = "not captured!"
+      let xignoredLocal = kfoo4
+
+      # newLit optional:
+      let x3 = newLit kfoo4
+      let x3b = kfoo4
+
+      result = genAstOpt({kDirtyTemplate}, s1=true, s2="asdf", x0, x1=x1, x2, x3, x3b):
+        doAssert not declared(xignored)
+        doAssert not declared(xignoredLocal)
+        (s1, s2, s0, x0, x1, x2, x3, x3b)
+
+    let s0 = "caller scope!"
+
+    doAssert bar(kfoo1, kfoo2, kfoo3, kfoo4) ==
+      (true, "asdf", "caller scope!", kfoo1, kfoo2, kfoo3, kfoo4, kfoo4)
+
+  block:
+    # doesn't have limitation mentioned in https://github.com/nim-lang/RFCs/issues/122#issue-401636535
+    macro abc(name: untyped): untyped =
+      result = genAst(name):
+        type name = object
+
+    abc(Bar)
+    doAssert Bar.default == Bar()
+
+  block:
+    # backticks parser limitations / ambiguities not are an issue with `genAst`:
+    # (#10326 #9745 are fixed but `quote do` still has underlying ambiguity issue
+    # with backticks)
+    type Foo = object
+      a: int
+
+    macro m1(): untyped =
+      # result = quote do: # Error: undeclared identifier: 'a1'
+      result = genAst:
+        template `a1=`(x: var Foo, val: int) =
+          x.a = val
+
+    m1()
+    var x0: Foo
+    x0.a1 = 10
+    doAssert x0 == Foo(a: 10)
+
+  block:
+    # avoids bug #7375
+    macro fun(b: static[bool], b2: bool): untyped =
+      result = newStmtList()
+    macro foo(c: bool): untyped =
+      var b = false
+      result = genAst(b, c):
+        fun(b, c)
+
+    foo(true)
+
+  block:
+    # avoids bug #7589
+    # since `==` works with genAst, the problem goes away
+    macro foo2(): untyped =
+      # result = quote do: # Error: '==' cannot be passed to a procvar
+      result = genAst:
+        `==`(3,4)
+    doAssert not foo2()
+
+  block:
+    # avoids bug #7726
+    # expressions such as `a.len` are just passed as arguments to `genAst`, and
+    # caller scope is not polluted with definitions such as `let b = newLit a.len`
+    macro foo(): untyped =
+      let a = @[1, 2, 3, 4, 5]
+      result = genAst(a, b = a.len): # shows 2 ways to get a.len
+        (a.len, b)
+    doAssert foo() == (5, 5)
+
+  block:
+    # avoids bug #9607
+    proc fun1(info:LineInfo): string = "bar1"
+    proc fun2(info:int): string = "bar2"
+
+    macro bar2(args: varargs[untyped]): untyped =
+      let info = args.lineInfoObj
+      let fun1 = bindSym"fun1" # optional; we can remove this and also the
+      # capture of fun1, as show in next example
+      result = genAst(info, fun1):
+        (fun1(info), fun2(info.line))
+    doAssert bar2() == ("bar1", "bar2")
+
+    macro bar3(args: varargs[untyped]): untyped =
+      let info = args.lineInfoObj
+      result = genAst(info):
+        (fun1(info), fun2(info.line))
+    doAssert bar3() == ("bar1", "bar2")
+
+    macro bar(args: varargs[untyped]): untyped =
+      let info = args.lineInfoObj
+      let fun1 = bindSym"fun1"
+      let fun2 = bindSym"fun2"
+      result = genAstOpt({kDirtyTemplate}, info):
+        (fun1(info), fun2(info.line))
+    doAssert bar() == ("bar1", "bar2")
+
+  block:
+    # example from bug #7889 works
+    # after changing method call syntax to regular call syntax; this is a
+    # limitation described in bug #7085
+    # note that `quote do` would also work after that change in this example.
+    doAssert bindme2() == kfoo1
+    doAssert bindme3() == kfoo1
+    doAssert not compiles(bindme4()) # correctly gives Error: undeclared identifier: 'myLocalPriv'
+    proc myLocalPriv2(): auto = kfoo2
+    doAssert bindme5UseExpose() == kfoo1
+
+    # example showing hijacking behavior when using `kDirtyTemplate`
+    doAssert bindme5UseExposeFalse() == kfoo2
+      # local `myLocalPriv2` hijacks symbol `mgenast.myLocalPriv2`. In most
+      # use cases this is probably not what macro writer intends as it's
+      # surprising; hence `kDirtyTemplate` is not the default.
+
+    when nimvm: # disabled because `newStringStream` is used
+      discard
+    else:
+      bindme6UseExpose()
+      bindme6UseExposeFalse()
+
+  block:
+    macro mbar(x3: Foo, x3b: static Foo): untyped =
+      var x1=kfoo3
+      var x2=newLit kfoo3
+      var x4=kfoo3
+      var xLocal=kfoo3
+
+      proc funLocal(): auto = kfoo4
+
+      result = genAst(x1, x2, x3, x4):
+        # local x1 overrides remote x1
+        when false:
+          # one advantage of using `kDirtyTemplate` is that these would hold:
+          doAssert not declared xLocal
+          doAssert not compiles(echo xLocal)
+          # however, even without it, we at least correctly generate CT error
+          # if trying to use un-captured symbol; this correctly gives:
+          # Error: internal error: environment misses: xLocal
+          echo xLocal
+
+        proc foo1(): auto =
+          # note that `funLocal` is captured implicitly, according to hygienic
+          # template rules; with `kDirtyTemplate` it would not unless
+          # captured in `genAst` capture list explicitly
+          (a0: xRemote, a1: x1, a2: x2, a3: x3, a4: x4, a5: funLocal())
+
+      return result
+
+    proc main()=
+      var xRemote=kfoo1
+      var x1=kfoo2
+      mbar(kfoo4, kfoo4)
+      doAssert foo1() == (a0: kfoo1, a1: kfoo3, a2: kfoo3, a3: kfoo4, a4: kfoo3, a5: kfoo4)
+
+    main()
+
+  block:
+    # With `kDirtyTemplate`, the example from #8220 works.
+    # See https://nim-lang.github.io/Nim/strformat.html#limitations for
+    # an explanation of why {.dirty.} is needed.
+    macro foo(): untyped =
+      result = genAstOpt({kDirtyTemplate}):
+        let bar = "Hello, World"
+        &"Let's interpolate {bar} in the string"
+    doAssert foo() == "Let's interpolate Hello, World in the string"
+
+
+  block: # nested application of genAst
+    macro createMacro(name, obj, field: untyped): untyped =
+      result = genAst(obj = newDotExpr(obj, field), lit = 10, name, field):
+        # can't reuse `result` here, would clash
+        macro name(arg: untyped): untyped =
+          genAst(arg2=arg): # somehow `arg2` rename is needed
+            (obj, astToStr(field), lit, arg2)
+
+    var x = @[1, 2, 3]
+    createMacro foo, x, len
+    doAssert (foo 20) == (3, "len", 10, 20)
+
+  block: # test with kNoNewLit
+    macro bar(): untyped =
+      let s1 = true
+      template boo(x): untyped =
+        fun(x)
+      result = genAstOpt({kNoNewLit}, s1=newLit(s1), s1b=s1): (s1, s1b)
+    doAssert bar() == (true, 1)
+
+  block: # sanity check: check passing `{}` also works
+    macro bar(): untyped =
+      result = genAstOpt({}, s1=true): s1
+    doAssert bar() == true
+
+  block: # test passing function and type symbols
+    proc z1(): auto = 41
+    type Z4 = type(1'i8)
+    macro bar(Z1: typedesc): untyped =
+      proc z2(): auto = 42
+      proc z3[T](a: T): auto = 43
+      let Z2 = genAst():
+        type(true)
+      let z4 = genAst():
+        proc myfun(): auto = 44
+        myfun
+      type Z3 = type(1'u8)
+      result = genAst(z4, Z1, Z2):
+        # z1, z2, z3, Z3, Z4 are captured automatically
+        # z1, z2, z3 can optionally be specified in capture list
+        (z1(), z2(), z3('a'), z4(), $Z1, $Z2, $Z3, $Z4)
+    type Z1 = type('c')
+    doAssert bar(Z1) == (41, 42, 43, 44, "char", "bool", "uint8", "int8")
+
+  block: # fix bug #11986
+    proc foo(): auto =
+      var s = { 'a', 'b' }
+      # var n = quote do: `s` # would print {97, 98}
+      var n = genAst(s): s
+      n.repr
+    static: doAssert foo() == "{'a', 'b'}"
+
+  block: # also from #11986
+    macro foo(): untyped =
+      var s = { 'a', 'b' }
+      # quote do:
+      #   let t = `s`
+      #   $typeof(t) # set[range 0..65535(int)]
+      genAst(s):
+        let t = s
+        $typeof(t)
+    doAssert foo() == "set[char]"
+
+  block:
+    macro foo(): untyped =
+      type Foo = object
+      template baz2(a: int): untyped = a*10
+      macro baz3(a: int): untyped = newLit 13
+      result = newStmtList()
+
+      result.add genAst(Foo, baz2, baz3) do: # shows you can pass types, templates etc
+        var x: Foo
+        $($typeof(x), baz2(3), baz3(4))
+
+      let ret = genAst() do: # shows you don't have to, since they're inject'd
+        var x: Foo
+        $($typeof(x), baz2(3), baz3(4))
+    doAssert foo() == """("Foo", 30, 13)"""
+
+  block: # illustrates how symbol visiblity can be controlled precisely using `mixin`
+    proc locafun1(): auto = "in locafun1 (caller scope)" # this will be used because of `mixin locafun1` => explicit hijacking is ok
+    proc locafun2(): auto = "in locafun2 (caller scope)" # this won't be used => no hijacking
+    proc locafun3(): auto = "in locafun3 (caller scope)"
+    doAssert mixinExample() == ("in locafun1 (caller scope)", "in locafun2", "in locafun3 (caller scope)")
+
+static: main()
+main()
diff --git a/tests/stdlib/tgetaddrinfo.nim b/tests/stdlib/tgetaddrinfo.nim
new file mode 100644
index 000000000..3a90034c8
--- /dev/null
+++ b/tests/stdlib/tgetaddrinfo.nim
@@ -0,0 +1,38 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  exitcode: 0
+  output: ""
+"""
+
+# bug: https://github.com/nim-lang/Nim/issues/10198
+
+import nativesockets
+import std/assertions
+
+block DGRAM_UDP:
+  let aiList = getAddrInfo("127.0.0.1", 999.Port, AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+  doAssert aiList != nil
+  doAssert aiList.ai_addr != nil
+  doAssert aiList.ai_addrlen.SockLen == sizeof(Sockaddr_in).SockLen
+  doAssert aiList.ai_next == nil
+  freeAddrInfo aiList
+
+when defined(posix) and not defined(haiku) and not defined(freebsd) and not defined(openbsd) and not defined(netbsd):
+
+  block RAW_ICMP:
+    # the port will be ignored
+    let aiList = getAddrInfo("127.0.0.1", 999.Port, AF_INET, SOCK_RAW, IPPROTO_ICMP)
+    doAssert aiList != nil
+    doAssert aiList.ai_addr != nil
+    doAssert aiList.ai_addrlen.SockLen == sizeof(Sockaddr_in).SockLen
+    doAssert aiList.ai_next == nil
+    freeAddrInfo aiList
+
+  block RAW_ICMPV6:
+    # the port will be ignored
+    let aiList = getAddrInfo("::1", 999.Port, AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)
+    doAssert aiList != nil
+    doAssert aiList.ai_addr != nil
+    doAssert aiList.ai_addrlen.SockLen == sizeof(Sockaddr_in6).SockLen
+    doAssert aiList.ai_next == nil
+    freeAddrInfo aiList
diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim
index 019c2eb7f..ae1480a4c 100644
--- a/tests/stdlib/tgetfileinfo.nim
+++ b/tests/stdlib/tgetfileinfo.nim
@@ -1,8 +1,11 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
   output: "pcDir\npcFile\npcLinkToDir\npcLinkToFile\n"
+  joinable: false
 """
 
 import os, strutils
+import std/[syncio, assertions]
 # Cases
 #  1 - String : Existing File : Symlink true
 #  2 - String : Existing File : Symlink false
@@ -14,13 +17,13 @@ import os, strutils
 #  8 - Handle : Invalid Handle
 
 proc genBadFileName(limit = 100): string =
-    ## Generates a filename of a nonexistant file.
+    ## Generates a filename of a nonexistent file.
     ## Returns "" if generation fails.
     result = "a"
     var hitLimit = true
 
     for i in 0..100:
-      if existsFile(result):
+      if fileExists(result):
         result.add("a")
       else:
         hitLimit = false
@@ -77,8 +80,8 @@ proc testGetFileInfo =
   # Case 6 and 8
   block:
     let
-      testFile: TFile = nil
-      testHandle = TFileHandle(-1)
+      testFile: File = nil
+      testHandle = FileHandle(-1)
     try:
       discard getFileInfo(testFile)
       echo("Handle : Invalid File : Failure")
@@ -125,10 +128,37 @@ proc testGetFileInfo =
       echo pcLinkToDir
       echo pcLinkToFile
 
+    doAssert dirInfo.isSpecial == false
+    doAssert fileInfo.isSpecial == false
+    when defined(posix):
+      doAssert linkDirInfo.isSpecial == false
+      doAssert linkFileInfo.isSpecial == false
+
     removeDir(dirPath)
     removeFile(filePath)
     when defined(posix):
       removeFile(linkDirPath)
       removeFile(linkFilePath)
 
+  # Test that `isSpecial` is set correctly
+  block:
+    when defined(posix):
+      let
+        tmp = getTempDir()
+        fifoPath     = tmp / "test-fifo"
+        linkFifoPath = tmp / "test-link-fifo"
+
+      doAssert execShellCmd("mkfifo " & fifoPath) == 0
+      createSymlink(fifoPath, linkFifoPath)
+
+      let
+        fifoInfo = getFileInfo(fifoPath)
+        linkFifoInfo = getFileInfo(linkFifoPath)
+
+      doAssert fifoInfo.isSpecial == true
+      doAssert linkFifoInfo.isSpecial == true
+
+      removeFile(fifoPath)
+      removeFile(linkFifoPath)
+
 testGetFileInfo()
diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim
new file mode 100644
index 000000000..1fc060ffe
--- /dev/null
+++ b/tests/stdlib/tgetprotobyname.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import nativesockets
+import std/assertions
+
+doAssert getProtoByName("ipv6") == 41
+doAssert getProtoByName("tcp") == 6
+doAssert getProtoByName("udp") == 17
+doAssert getProtoByName("icmp") == 1
+doAssert getProtoByName("ipv6-icmp") == 58
+
+when defined(windows):
+  doAssertRaises(OSError):
+    discard getProtoByName("raw")
+
+doAssertRaises(OSError):
+  discard getProtoByName("Error")
diff --git a/tests/stdlib/tglobs.nim b/tests/stdlib/tglobs.nim
new file mode 100644
index 000000000..4aa21992c
--- /dev/null
+++ b/tests/stdlib/tglobs.nim
@@ -0,0 +1,25 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/globs
+import std/assertions
+
+template main =
+  when defined(windows):
+    doAssert nativeToUnixPath("C:") == "/C"
+    doAssert nativeToUnixPath(r"D:\") == "/D/"
+    doAssert nativeToUnixPath(r"E:\a") == "/E/a"
+    doAssert nativeToUnixPath(r"E:\a1\") == "/E/a1/"
+    doAssert nativeToUnixPath(r"E:\a1\bc") == "/E/a1/bc"
+    doAssert nativeToUnixPath(r"\a1\bc") == "/a1/bc"
+    doAssert nativeToUnixPath(r"a1\bc") == "a1/bc"
+    doAssert nativeToUnixPath("a1") == "a1"
+    doAssert nativeToUnixPath("") == ""
+    doAssert nativeToUnixPath(".") == "."
+    doAssert nativeToUnixPath("..") == ".."
+    doAssert nativeToUnixPath(r"..\") == "../"
+    doAssert nativeToUnixPath(r"..\..\.\") == "../.././"
+
+static: main()
+main()
diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim
index c442b43fb..4555fbcb3 100644
--- a/tests/stdlib/thashes.nim
+++ b/tests/stdlib/thashes.nim
@@ -1,8 +1,242 @@
-import unittest
-import hashes
-
-suite "hashes":
-  suite "hashing":
-    test "0.0 and -0.0 should have the same hash value":
-      var dummy = 0.0
-      check hash(dummy) == hash(-dummy)
+discard """
+  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:on; --backend:c -d:nimStringHash2; --backend:cpp -d:nimStringHash2; --backend:js -d:nimStringHash2"
+"""
+
+import std/hashes
+from stdtest/testutils import disableVm, whenVMorJs
+import std/assertions
+
+when not defined(js) and not defined(cpp):
+  block:
+    var x = 12
+    iterator hello(): int {.closure.} =
+      yield x
+
+    discard hash(hello)
+
+block hashes:
+  block hashing:
+    var dummy = 0.0
+    doAssert hash(dummy) == hash(-dummy)
+
+  # "VM and runtime should make the same hash value (hashIdentity)"
+  block:
+    const hi123 = hashIdentity(123)
+    doAssert hashIdentity(123) == hi123
+
+  # "VM and runtime should make the same hash value (hashWangYi1)"
+  block:
+    const wy123 = hashWangYi1(123)
+    doAssert wy123 != 0
+    doAssert hashWangYi1(123) == wy123
+    const wyNeg123 = hashWangYi1(-123)
+    doAssert wyNeg123 != 0
+    when not defined(js): # TODO: fixme it doesn't work for JS
+      doAssert hashWangYi1(-123) == wyNeg123
+
+
+  # "hashIdentity value incorrect at 456"
+  block:
+    doAssert hashIdentity(456) == 456
+
+  # "hashWangYi1 value incorrect at 456"
+  block:
+    when Hash.sizeof < 8:
+      doAssert hashWangYi1(456) == 1293320666
+    else:
+      doAssert hashWangYi1(456) == -6421749900419628582
+
+template jsNoInt64: untyped =
+  when defined js:
+    when compiles(compileOption("jsbigint64")):
+      when not compileOption("jsbigint64"): true
+      else: false
+    else: false
+  else: false
+const sHash2 = (when defined(nimStringHash2) or jsNoInt64(): true else: false)
+
+block empty:
+  const emptyStrHash = # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
+    when sHash2: 0 else: cast[Hash](-7286425919675154353i64)
+  var
+    a = ""
+    b = newSeq[char]()
+    c = newSeq[int]()
+    d = cstring""
+    e = "abcd"
+  doAssert hash(a) == emptyStrHash
+  doAssert hash(b) == emptyStrHash
+  doAssert hash(c) == 0
+  doAssert hash(d) == emptyStrHash
+  doAssert hashIgnoreCase(a) == 0
+  doAssert hashIgnoreStyle(a) == 0
+  doAssert hash(e, 3, 2) == emptyStrHash
+
+block sameButDifferent:
+  doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13)
+  doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234")
+  doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234")
+  doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234")
+
+block smallSize: # no multibyte hashing
+  let
+    xx = @['H', 'i']
+    ii = @[72'u8, 105]
+    ss = "Hi"
+  doAssert hash(xx) == hash(ii)
+  doAssert hash(xx) == hash(ss)
+  doAssert hash(xx) == hash(xx, 0, xx.high)
+  doAssert hash(ss) == hash(ss, 0, ss.high)
+
+block largeSize: # longer than 4 characters
+  let
+    xx = @['H', 'e', 'l', 'l', 'o']
+    xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's']
+    ssl = "Helloweens"
+  doAssert hash(xxl) == hash(ssl)
+  doAssert hash(xxl) == hash(xxl, 0, xxl.high)
+  doAssert hash(ssl) == hash(ssl, 0, ssl.high)
+  doAssert hash(xx) == hash(xxl, 0, 4)
+  doAssert hash(xx) == hash(ssl, 0, 4)
+  doAssert hash(xx, 0, 3) == hash(xxl, 0, 3)
+  doAssert hash(xx, 0, 3) == hash(ssl, 0, 3)
+
+proc main() =
+  doAssert hash(0.0) == hash(0)
+  # bug #16061
+  when not sHash2: # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
+    doAssert hash(cstring"abracadabra") == cast[Hash](-1119910118870047694i64)
+  else:
+    doAssert hash(cstring"abracadabra") == 97309975
+  doAssert hash(cstring"abracadabra") == hash("abracadabra")
+
+  when sizeof(int) == 8 or defined(js):
+    block:
+      var s: seq[Hash]
+      for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]:
+        let b = hash(a)
+        doAssert b notin s
+        s.add b
+    when defined(js):
+      doAssert hash(0.345602) == 2035867618
+      doAssert hash(234567.45) == -20468103
+      doAssert hash(-9999.283456) == -43247422
+      doAssert hash(84375674.0) == 707542256
+    else:
+      doAssert hash(0.345602) == 387936373221941218
+      doAssert hash(234567.45) == -8179139172229468551
+      doAssert hash(-9999.283456) == 5876943921626224834
+      doAssert hash(84375674.0) == 1964453089107524848
+  else:
+    doAssert hash(0.345602) != 0
+    doAssert hash(234567.45) != 0
+    doAssert hash(-9999.283456) != 0
+    doAssert hash(84375674.0) != 0
+
+  block: # bug #16555
+    proc fn(): auto =
+      # avoids hardcoding values
+      var a = "abc\0def"
+      var b = a.cstring
+      result = (hash(a), hash(b))
+      doAssert result[0] != result[1]
+    when not defined(js):
+      doAssert fn() == static(fn())
+    else:
+      # xxx this is a tricky case; consistency of hashes for cstring's containing
+      # '\0\' matters for c backend but less for js backend since such strings
+      # are much less common in js backend; we make vm for js backend consistent
+      # with c backend instead of js backend because FFI code (or other) could
+      # run at CT, expecting c semantics.
+      discard
+
+  block: # hash(object)
+    type
+      Obj = object
+        x: int
+        y: string
+      Obj2[T] = object
+        x: int
+        y: string
+      Obj3 = object
+        x: int
+        y: string
+      Obj4 = object
+        case t: bool
+        of false:
+          x: int
+        of true:
+          y: int
+        z: int
+      Obj5 = object
+        case t: bool
+        of false:
+          x: int
+        of true:
+          y: int
+        z: int
+
+    proc hash(a: Obj2): Hash = hash(a.x)
+    proc hash(a: Obj3): Hash = hash((a.x,))
+    proc hash(a: Obj5): Hash =
+      case a.t
+      of false: hash(a.x)
+      of true: hash(a.y)
+
+    doAssert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2"))
+    doAssert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
+    doAssert hash(Obj2[float](x: 520, y: "Nim")) != hash(Obj2[float](x: 521, y: "Nim2"))
+    doAssert hash(Obj3(x: 520, y: "Nim")) == hash(Obj3(x: 520, y: "Nim2"))
+
+    doAssert hash(Obj4(t: false, x: 1)) == hash(Obj4(t: false, x: 1))
+    doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: false, x: 2))
+    doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: true, y: 1))
+
+    doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: false, x: 2))
+    doAssert hash(Obj5(t: false, x: 1)) == hash(Obj5(t: true, y: 1))
+    doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2))
+
+  block: # hash(ref|ptr|pointer)
+    var a: array[10, uint8]
+    # disableVm:
+    whenVMorJs:
+      # pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417
+      discard
+    do:
+      doAssert a[0].addr.hash != a[1].addr.hash
+      doAssert cast[pointer](a[0].addr).hash == a[0].addr.hash
+
+  block: # hash(ref)
+    type A = ref object
+      x: int
+    let a = A(x: 3)
+    disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer
+      let ha = a.hash
+      doAssert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`.
+      a.x = 4
+      doAssert ha == a.hash # the hash only depends on the address
+
+  block: # hash(proc)
+    proc fn(a: int): auto = a*2
+    doAssert fn isnot "closure"
+    doAssert fn is (proc)
+    const fn2 = fn
+    let fn3 = fn
+    whenVMorJs: discard
+    do:
+      doAssert hash(fn2) == hash(fn)
+      doAssert hash(fn3) == hash(fn)
+
+  block: # hash(closure)
+    proc outer() =
+      var a = 0
+      proc inner() = a.inc
+      doAssert inner is "closure"
+      let inner2 = inner
+      whenVMorJs: discard
+      do:
+        doAssert hash(inner2) == hash(inner)
+    outer()
+
+static: main()
+main()
diff --git a/tests/stdlib/theapqueue.nim b/tests/stdlib/theapqueue.nim
new file mode 100644
index 000000000..afb09c7e3
--- /dev/null
+++ b/tests/stdlib/theapqueue.nim
@@ -0,0 +1,106 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/heapqueue
+import std/assertions
+
+proc toSortedSeq[T](h: HeapQueue[T]): seq[T] =
+  var tmp = h
+  result = @[]
+  while tmp.len > 0:
+    result.add(pop(tmp))
+
+proc heapProperty[T](h: HeapQueue[T]): bool =
+  for k in 0 .. h.len - 2: # the last element is always a leaf
+    let left = 2 * k + 1
+    if left < h.len and h[left] < h[k]:
+      return false
+    let right = left + 1
+    if right < h.len and h[right] < h[k]:
+      return false
+  true
+
+template main() =
+  block: # simple sanity test
+    var heap = initHeapQueue[int]()
+    let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
+    for item in data:
+      push(heap, item)
+    doAssert(heap == data.toHeapQueue)
+    doAssert(heap[0] == 0)
+    doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+
+  block: # test del
+    var heap = initHeapQueue[int]()
+    let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
+    for item in data: push(heap, item)
+
+    heap.del(0)
+    doAssert(heap[0] == 1)
+
+    heap.del(heap.find(7))
+    doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9])
+
+    heap.del(heap.find(5))
+    doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9])
+
+    heap.del(heap.find(6))
+    doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9])
+
+    heap.del(heap.find(2))
+    doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9])
+
+    doAssert(heap.find(2) == -1)
+
+  block: # test del last
+    var heap = initHeapQueue[int]()
+    let data = [1, 2, 3]
+    for item in data: push(heap, item)
+
+    heap.del(2)
+    doAssert(heap.toSortedSeq == @[1, 2])
+
+    heap.del(1)
+    doAssert(heap.toSortedSeq == @[1])
+
+    heap.del(0)
+    doAssert(heap.toSortedSeq == @[])
+
+  block: # testing the heap proeprty
+    var heap = [1, 4, 2, 5].toHeapQueue
+    doAssert heapProperty(heap)
+
+    heap.push(42)
+    doAssert heapProperty(heap)
+    heap.push(0)
+    doAssert heapProperty(heap)
+    heap.push(3)
+    doAssert heapProperty(heap)
+    heap.push(3)
+    doAssert heapProperty(heap)
+
+    # [0, 3, 1, 4, 42, 2, 3, 5]
+
+    discard heap.pop()
+    doAssert heapProperty(heap)
+    discard heap.pop()
+    doAssert heapProperty(heap)
+
+    heap.del(2)
+    doAssert heapProperty(heap)
+
+    # [2, 3, 5, 4, 42]
+
+    discard heap.replace(12)
+    doAssert heapProperty(heap)
+    discard heap.replace(1)
+    doAssert heapProperty(heap)
+
+    discard heap.pushpop(2)
+    doAssert heapProperty(heap)
+    discard heap.pushpop(0)
+    doAssert heapProperty(heap)
+
+static: main()
+main()
diff --git a/tests/stdlib/thighlite.nim b/tests/stdlib/thighlite.nim
new file mode 100644
index 000000000..0cd334254
--- /dev/null
+++ b/tests/stdlib/thighlite.nim
@@ -0,0 +1,45 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import unittest, strutils
+import ../../lib/packages/docutils/highlite
+import std/objectdollar
+
+block: # Nim tokenizing
+  test "string literals and escape seq":
+    check("\"ok1\\nok2\\nok3\"".tokenize(langNim) ==
+       @[("\"ok1", gtStringLit), ("\\n", gtEscapeSequence), ("ok2", gtStringLit),
+         ("\\n", gtEscapeSequence), ("ok3\"", gtStringLit)
+      ])
+    check("\"\"\"ok1\\nok2\\nok3\"\"\"".tokenize(langNim) ==
+       @[("\"\"\"ok1\\nok2\\nok3\"\"\"", gtLongStringLit)
+      ])
+
+  test "whitespace at beginning of line is preserved":
+    check("  discard 1".tokenize(langNim) ==
+       @[("  ", gtWhitespace), ("discard", gtKeyword), (" ", gtWhitespace),
+         ("1", gtDecNumber)
+       ])
+
+block: # Cmd (shell) tokenizing
+  test "cmd with dollar and output":
+    check(
+      dedent"""
+        $ nim c file.nim
+        out: file [SuccessX]"""
+        .tokenize(langConsole) ==
+      @[("$ ", gtPrompt), ("nim", gtProgram),
+        (" ", gtWhitespace), ("c", gtOption), (" ", gtWhitespace),
+        ("file.nim", gtIdentifier), ("\n", gtWhitespace),
+        ("out: file [SuccessX]", gtProgramOutput)
+      ])
+
+block: # bug #21232
+  let code = "/"
+  var toknizr: GeneralTokenizer
+
+  initGeneralTokenizer(toknizr, code)
+
+  getNextToken(toknizr, langC)
+  check $toknizr == """(kind: gtOperator, start: 0, length: 1, buf: "/", pos: 1, state: gtEof, lang: langC)"""
diff --git a/tests/stdlib/thtmlparser.nim b/tests/stdlib/thtmlparser.nim
new file mode 100644
index 000000000..853a1c0cc
--- /dev/null
+++ b/tests/stdlib/thtmlparser.nim
@@ -0,0 +1,159 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+  output: '''
+true
+https://example.com/test?format=jpg&name=orig##
+https://example.com/test?format=jpg&name=orig##text
+https://example.com/test?format=jpg##text
+'''
+"""
+import htmlparser
+import xmltree
+import strutils
+from streams import newStringStream
+import std/assertions
+
+block t2813:
+  const
+    html = """
+    <html>
+      <head>
+        <title>Test</title>
+      </head>
+      <body>
+        <table>
+          <thead>
+            <tr><td>A</td></tr>
+            <tr><td>B</td></tr>
+          </thead>
+          <tbody>
+            <tr><td></td>A<td></td></tr>
+            <tr><td></td>B<td></td></tr>
+            <tr><td></td>C<td></td></tr>
+          </tbody>
+          <tfoot>
+            <tr><td>A</td></tr>
+          </tfoot>
+        </table>
+      </body>
+    </html>
+    """
+  var errors: seq[string] = @[]
+  let tree = parseHtml(newStringStream(html), "test.html", errors)
+  doAssert errors.len == 0 # Errors: </thead> expected,...
+
+  var len = tree.findAll("tr").len # len = 6
+  var rows: seq[XmlNode] = @[]
+  for n in tree.findAll("table"):
+    n.findAll("tr", rows)  # len = 2
+    break
+  doAssert tree.findAll("tr").len == rows.len
+
+
+block t2814:
+  ## builds the two cases below and test that
+  ## ``//[dd,li]`` has "<p>that</p>" as children
+  ##
+  ##  <dl>
+  ##    <dt>this</dt>
+  ##    <dd>
+  ##      <p>that</p>
+  ##    </dd>
+  ##  </dl>
+
+  ##
+  ## <ul>
+  ##   <li>
+  ##     <p>that</p>
+  ##   </li>
+  ## </ul>
+  for ltype in [["dl","dd"], ["ul","li"]]:
+    let desc_item = if ltype[0]=="dl": "<dt>this</dt>" else: ""
+    let item = "$1<$2><p>that</p></$2>" % [desc_item, ltype[1]]
+    let list = """ <$1>
+     $2
+  </$1> """ % [ltype[0], item]
+
+    var errors : seq[string] = @[]
+    let parseH = parseHtml(newStringStream(list),"statichtml", errors =errors)
+
+    if $parseH.findAll(ltype[1])[0].child("p") != "<p>that</p>":
+      echo "case " & ltype[0] & " failed !"
+      quit(2)
+  echo "true"
+
+block t6154:
+  let foo = """
+  <!DOCTYPE html>
+  <html>
+      <head>
+        <title> foobar </title>
+      </head>
+      <body>
+        <p class=foo id=bar></p>
+        <p something=&#9;foo&#9;bar&#178;></p>
+        <p something=  &#9;foo&#9;bar&#178; foo  =bloo></p>
+        <p class="foo2" id="bar2"></p>
+        <p wrong= ></p>
+        <p data-foo data-bar="correct!" enabled  ></p>
+        <p quux whatever></p>
+      </body>
+  </html>
+  """
+
+  var errors: seq[string] = @[]
+  let html = parseHtml(newStringStream(foo), "statichtml", errors=errors)
+  doAssert "statichtml(11, 18) Error: attribute value expected" in errors
+  let ps = html.findAll("p")
+  doAssert ps.len == 7
+
+  doAssert ps[0].attrsLen == 2
+  doAssert ps[0].attr("class") == "foo"
+  doAssert ps[0].attr("id") == "bar"
+  doAssert ps[0].len == 0
+
+  doAssert ps[1].attrsLen == 1
+  doAssert ps[1].attr("something") == "\tfoo\tbar²"
+  doAssert ps[1].len == 0
+
+  doAssert ps[2].attrsLen == 2
+  doAssert ps[2].attr("something") == "\tfoo\tbar²"
+  doAssert ps[2].attr("foo") == "bloo"
+  doAssert ps[2].len == 0
+
+  doAssert ps[3].attrsLen == 2
+  doAssert ps[3].attr("class") == "foo2"
+  doAssert ps[3].attr("id") == "bar2"
+  doAssert ps[3].len == 0
+
+  doAssert ps[4].attrsLen == 1
+  doAssert ps[4].attr("wrong") == ""
+
+  doAssert ps[5].attrsLen == 3
+  doAssert ps[5].attr("data-foo") == ""
+  doAssert ps[5].attr("data-bar") == "correct!"
+  doAssert ps[5].attr("enabled") == ""
+  doAssert ps[5].len == 0
+
+  doAssert ps[6].attrsLen == 2
+  doAssert ps[6].attr("quux") == ""
+  doAssert ps[6].attr("whatever") == ""
+  doAssert ps[6].len == 0
+
+# bug #11713, #1034
+var content = """
+# with &
+<img src="https://example.com/test?format=jpg&name=orig" alt="">
+<img src="https://example.com/test?format=jpg&name=orig" alt="text">
+
+# without &
+<img src="https://example.com/test?format=jpg" alt="text">
+"""
+
+var
+  stream = newStringStream(content)
+  body = parseHtml(stream)
+
+for y in body.findAll("img"):
+  echo y.attr("src"), "##", y.attr("alt")
diff --git a/tests/stdlib/thtmlparser2813.nim b/tests/stdlib/thtmlparser2813.nim
deleted file mode 100644
index 4b04bc3f0..000000000
--- a/tests/stdlib/thtmlparser2813.nim
+++ /dev/null
@@ -1,45 +0,0 @@
-discard """
-  output: "@[]"
-"""
-import htmlparser
-import xmltree
-from streams import newStringStream
-
-const
-  html = """
-  <html>
-    <head>
-      <title>Test</title>
-    </head>
-    <body>
-      <table>
-        <thead>
-          <tr><td>A</td></tr>
-          <tr><td>B</td></tr>
-        </thead>
-        <tbody>
-          <tr><td></td>A<td></td></tr>
-          <tr><td></td>B<td></td></tr>
-          <tr><td></td>C<td></td></tr>
-        </tbody>
-        <tfoot>
-          <tr><td>A</td></tr>
-        </tfoot>
-      </table>
-    </body>
-  </html>
-  """
-var errors: seq[string] = @[]
-
-let tree = parseHtml(newStringStream(html), "test.html", errors)
-
-echo errors # Errors: </thead> expected,...
-
-var len = tree.findAll("tr").len # len = 6
-
-var rows: seq[XmlNode] = @[]
-for n in tree.findAll("table"):
-  n.findAll("tr", rows)  # len = 2
-  break
-
-assert tree.findAll("tr").len == rows.len
diff --git a/tests/stdlib/thtmlparser2814.nim b/tests/stdlib/thtmlparser2814.nim
deleted file mode 100644
index 968d390f1..000000000
--- a/tests/stdlib/thtmlparser2814.nim
+++ /dev/null
@@ -1,44 +0,0 @@
-discard """
-  output: true
-"""
-import htmlparser
-import xmltree
-import strutils
-from streams import newStringStream
-
-
-## builds the two cases below and test that
-## ``//[dd,li]`` has "<p>that</p>" as children
-##
-##  <dl>
-##    <dt>this</dt>
-##    <dd>
-##      <p>that</p>
-##    </dd>
-##  </dl>
-
-##
-## <ul>
-##   <li>
-##     <p>that</p>
-##   </li>
-## </ul>
-
-
-for ltype in [["dl","dd"], ["ul","li"]]:
-  let desc_item = if ltype[0]=="dl": "<dt>this</dt>" else: ""
-  let item = "$1<$2><p>that</p></$2>" % [desc_item, ltype[1]]
-  let list = """ <$1>
-   $2
-</$1> """ % [ltype[0], item]
-
-  var errors : seq[string] = @[]
-
-  let parseH = parseHtml(newStringStream(list),"statichtml", errors =errors)
-
-  if $parseH.findAll(ltype[1])[0].child("p") != "<p>that</p>":
-    echo "case " & ltype[0] & " failed !"
-    quit(2)
-
-
-echo "true"
diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim
index fff02722a..0bd479670 100644
--- a/tests/stdlib/thttpclient.nim
+++ b/tests/stdlib/thttpclient.nim
@@ -1,33 +1,65 @@
 discard """
   cmd: "nim c --threads:on -d:ssl $file"
-  exitcode: 0
-  output: "OK"
-  disabled: "travis"
-  disabled: "appveyor"
+  disabled: "openbsd"
+  disabled: "freebsd"
+  disabled: "windows"
 """
 
+#[
+disabled: see https://github.com/timotheecour/Nim/issues/528
+]#
+
 import strutils
 from net import TimeoutError
 
 import nativesockets, os, httpclient, asyncdispatch
 
+import std/[assertions, syncio]
+from stdtest/testutils import enableRemoteNetworking
+
 const manualTests = false
 
+proc makeIPv6HttpServer(hostname: string, port: Port,
+    message: string): AsyncFD =
+  let fd = createNativeSocket(AF_INET6)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, AF_INET6)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+
+  var serverFd = fd.AsyncFD
+  register(serverFd)
+  result = serverFd
+
+  proc onAccept(fut: Future[AsyncFD]) {.gcsafe.} =
+    if not fut.failed:
+      let clientFd = fut.read()
+      clientFd.send(message).callback = proc() =
+        clientFd.closeSocket()
+      serverFd.accept().callback = onAccept
+  serverFd.accept().callback = onAccept
+
 proc asyncTest() {.async.} =
   var client = newAsyncHttpClient()
-  var resp = await client.request("http://example.com/")
+  var resp = await client.request("http://example.com/", HttpGet)
   doAssert(resp.code.is2xx)
   var body = await resp.body
   body = await resp.body # Test caching
   doAssert("<title>Example Domain</title>" in body)
 
   resp = await client.request("http://example.com/404")
-  doAssert(resp.code.is4xx)
-  doAssert(resp.code == Http404)
-  doAssert(resp.status == Http404)
+  doAssert(resp.code.is4xx or resp.code.is5xx)
+  doAssert(resp.code == Http404 or resp.code == Http500)
+  doAssert(resp.status == $Http404 or resp.status == $Http500)
 
-  resp = await client.request("https://google.com/")
-  doAssert(resp.code.is2xx or resp.code.is3xx)
+  when false: # occasionally does not give success code 
+    resp = await client.request("https://google.com/")
+    doAssert(resp.code.is2xx or resp.code.is3xx)
 
   # getContent
   try:
@@ -46,7 +78,7 @@ proc asyncTest() {.async.} =
     data["output"] = "soap12"
     data["uploaded_file"] = ("test.html", "text/html",
       "<html><head></head><body><p>test</p></body></html>")
-    resp = await client.post("http://validator.w3.org/check", multipart=data)
+    resp = await client.post("http://validator.w3.org/check", multipart = data)
     doAssert(resp.code.is2xx)
 
   # onProgressChanged
@@ -58,6 +90,16 @@ proc asyncTest() {.async.} =
     await client.downloadFile("http://speedtest-ams2.digitalocean.com/100mb.test",
                               "100mb.test")
 
+  # HTTP/1.1 without Content-Length - issue #10726
+  var serverFd = makeIPv6HttpServer("::1", Port(18473),
+     "HTTP/1.1 200 \c\L" &
+     "\c\L" &
+     "Here comes reply")
+  resp = await client.request("http://[::1]:18473/")
+  body = await resp.body
+  doAssert(body == "Here comes reply")
+  serverFd.closeSocket()
+
   client.close()
 
   # Proxy test
@@ -68,17 +110,18 @@ proc asyncTest() {.async.} =
 
 proc syncTest() =
   var client = newHttpClient()
-  var resp = client.request("http://example.com/")
+  var resp = client.request("http://example.com/", HttpGet)
   doAssert(resp.code.is2xx)
   doAssert("<title>Example Domain</title>" in resp.body)
 
   resp = client.request("http://example.com/404")
-  doAssert(resp.code.is4xx)
-  doAssert(resp.code == Http404)
-  doAssert(resp.status == Http404)
+  doAssert(resp.code.is4xx or resp.code.is5xx)
+  doAssert(resp.code == Http404 or resp.code == Http500)
+  doAssert(resp.status == $Http404 or resp.status == $Http500)
 
-  resp = client.request("https://google.com/")
-  doAssert(resp.code.is2xx or resp.code.is3xx)
+  when false: # occasionally does not give success code
+    resp = client.request("https://google.com/")
+    doAssert(resp.code.is2xx or resp.code.is3xx)
 
   # getContent
   try:
@@ -96,7 +139,7 @@ proc syncTest() =
     data["output"] = "soap12"
     data["uploaded_file"] = ("test.html", "text/html",
       "<html><head></head><body><p>test</p></body></html>")
-    resp = client.post("http://validator.w3.org/check", multipart=data)
+    resp = client.post("http://validator.w3.org/check", multipart = data)
     doAssert(resp.code.is2xx)
 
   # onProgressChanged
@@ -110,6 +153,12 @@ proc syncTest() =
 
   client.close()
 
+  # SIGSEGV on HEAD body read: issue #16743
+  block:
+    let client = newHttpClient()
+    let resp = client.head("http://httpbin.org/head")
+    doAssert(resp.body == "")
+
   when false:
     # Disabled for now because it causes troubles with AppVeyor
     # Timeout test.
@@ -122,40 +171,17 @@ proc syncTest() =
     except:
       doAssert false, "TimeoutError should have been raised."
 
-proc makeIPv6HttpServer(hostname: string, port: Port): AsyncFD =
-  let fd = newNativeSocket(AF_INET6)
-  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
-  var aiList = getAddrInfo(hostname, port, AF_INET6)
-  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
-    freeAddrInfo(aiList)
-    raiseOSError(osLastError())
-  freeAddrInfo(aiList)
-  if listen(fd) != 0:
-    raiseOSError(osLastError())
-  setBlocking(fd, false)
-
-  var serverFd = fd.AsyncFD
-  register(serverFd)
-  result = serverFd
-
-  proc onAccept(fut: Future[AsyncFD]) {.gcsafe.} =
-    if not fut.failed:
-      let clientFd = fut.read()
-      clientFd.send("HTTP/1.1 200 OK\r\LContent-Length: 0\r\LConnection: Closed\r\L\r\L").callback = proc() =
-        clientFd.closeSocket()
-      serverFd.accept().callback = onAccept
-  serverFd.accept().callback = onAccept
-
 proc ipv6Test() =
   var client = newAsyncHttpClient()
-  let serverFd = makeIPv6HttpServer("::1", Port(18473))
+  let serverFd = makeIPv6HttpServer("::1", Port(18473),
+    "HTTP/1.1 200 OK\r\LContent-Length: 0\r\LConnection: Closed\r\L\r\L")
   var resp = waitFor client.request("http://[::1]:18473/")
   doAssert(resp.status == "200 OK")
   serverFd.closeSocket()
   client.close()
 
-syncTest()
-waitFor(asyncTest())
 ipv6Test()
 
-echo "OK"
+when enableRemoteNetworking:
+  syncTest()
+  waitFor(asyncTest())
diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim
new file mode 100644
index 000000000..6b963f029
--- /dev/null
+++ b/tests/stdlib/thttpclient_ssl.nim
@@ -0,0 +1,150 @@
+discard """
+  cmd: "nim $target --mm:refc -d:ssl $options $file"
+  disabled: "openbsd"
+"""
+
+#            Nim - Basic SSL integration tests
+#        (c) Copyright 2018 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## Warning: this test performs local networking.
+## Test with:
+## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim
+
+
+from stdtest/testutils import disableSSLTesting
+
+when not defined(windows) and not disableSSLTesting():
+  # Disabled on Windows due to old OpenSSL version
+  import std/[formatfloat, syncio]
+  import
+    httpclient,
+    net,
+    openssl,
+    os,
+    strutils,
+    threadpool,
+    times,
+    unittest
+
+  # bogus self-signed certificate
+  const
+    certFile = "tests/stdlib/thttpclient_ssl_cert.pem"
+    keyFile = "tests/stdlib/thttpclient_ssl_key.pem"
+
+  proc log(msg: string) =
+    when defined(ssldebug):
+      echo "    [" & $epochTime() & "] " & msg
+    # FIXME
+    echo "    [" & $epochTime() & "] " & msg
+    discard
+
+  proc runServer(port: Port): bool {.thread.} =
+    ## Run a trivial HTTPS server in a {.thread.}
+    ## Exit after serving one request
+
+    var socket = newSocket()
+    socket.setSockOpt(OptReusePort, true)
+    socket.bindAddr(port)
+
+    var ctx = newContext(certFile=certFile, keyFile=keyFile)
+
+    ##  Handle one connection
+    socket.listen()
+
+    var client: Socket
+    var address = ""
+
+    log "server: ready"
+    socket.acceptAddr(client, address)
+    log "server: incoming connection"
+
+    var ssl: SslPtr = SSL_new(ctx.context)
+    discard SSL_set_fd(ssl, client.getFd())
+    log "server: accepting connection"
+    ErrClearError()
+    if SSL_accept(ssl) <= 0:
+      ERR_print_errors_fp(stderr)
+    else:
+      const reply = "HTTP/1.0 200 OK\r\nServer: test\r\nContent-type: text/html\r\nContent-Length: 0\r\n\r\n"
+      log "server: sending reply"
+      discard SSL_write(ssl, reply.cstring, reply.len)
+
+    log "server: receiving a line"
+    let line = client.recvLine()
+    log "server: received $# bytes" % $line.len
+    log "closing"
+    SSL_free(ssl)
+    close(client)
+    close(socket)
+    log "server: exited"
+
+
+  suite "SSL self signed certificate check":
+
+    test "TCP socket":
+      const port = 12347.Port
+      let t = spawn runServer(port)
+      sleep(100)
+      var sock = newSocket()
+      var ctx = newContext()
+      ctx.wrapSocket(sock)
+      try:
+        log "client: connect"
+        sock.connect("127.0.0.1", port)
+        fail()
+      except:
+        let msg = getCurrentExceptionMsg()
+        check(msg.contains("certificate verify failed"))
+
+    test "HttpClient default: no check":
+      const port = 12345.Port
+      let t = spawn runServer(port)
+      sleep(100)
+
+      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyNone))
+      try:
+        log "client: connect"
+        discard client.getContent("https://127.0.0.1:12345")
+      except:
+        let msg = getCurrentExceptionMsg()
+        log "client: unexpected exception: " & msg
+        fail()
+
+    test "HttpClient with CVerifyPeer":
+      const port = 12346.Port
+      let t = spawn runServer(port)
+      sleep(100)
+
+      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer))
+      try:
+        log "client: connect"
+        discard client.getContent("https://127.0.0.1:12346")
+        log "getContent should have raised an exception"
+        fail()
+      except:
+        let msg = getCurrentExceptionMsg()
+        log "client: exception: " & msg
+        # SSL_shutdown:shutdown while in init
+        if not (msg.contains("alert number 48") or
+          msg.contains("certificate verify failed")):
+          echo "CVerifyPeer exception: " & msg
+          check(false)
+
+    test "HttpClient with CVerifyPeerUseEnvVars":
+      const port = 12346.Port
+      let t = spawn runServer(port)
+      sleep(100)
+
+      putEnv("SSL_CERT_FILE", getCurrentDir() / certFile)
+      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeerUseEnvVars))
+      try:
+        log "client: connect"
+        discard client.getContent("https://127.0.0.1:12346")
+      except:
+        let msg = getCurrentExceptionMsg()
+        log "client: exception: " & msg
+        log "getContent should not have raised an exception"
+        fail()
diff --git a/tests/stdlib/thttpclient_ssl_cert.pem b/tests/stdlib/thttpclient_ssl_cert.pem
new file mode 100644
index 000000000..f15c15c52
--- /dev/null
+++ b/tests/stdlib/thttpclient_ssl_cert.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFCTCCAvGgAwIBAgIURYQOmGzeh3Vy7Gk6Go4uAPwcNwAwDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MDEyMzAwMTgzNFoXDTQ2MDYw
+OTAwMTgzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAzoEVEl7yqY+RqIagXDD4JB7LyONDvh8aJvBMnJVBgjaL
+JdkfQjvPGUzUkEbU5nc6u7lqFxzEv7hXrssQCB7TwJwfS2PT1Rj14IFlYPyw4DEe
+P1RVS/awurtv3jwumarVl7LR+IQfo59kJ/P8jZt8H3HscDbyhXcHeOWI6q+XlfdV
+mTUJVvABdUuOiIFjgfFVTpo+CKxy7c5caRDK7g1s9xB1/M9PUfJvHY1WrBWFOZf0
+Bl8iwn+ahuxfIVqsFL9leqLykgi1f4L20p7RaAK95TXCo3CszZm4Fsw9zhzkjoU7
+2h0nuYl197LZvRs3u/JJjzZERmsfVPIs5BtO8/MN1MvRn6hIGU5Q3kOVWqWxSkSl
+njrf+uwUdn/24uSCnygNeDuJzwW/2q4N9YI3oovqNIGpkT3FbAm7UKwI4lwhwmqw
+7WH+92ELj0BinmsMMRPD2OqvK+vzLVqwUIQkYug+Hjys6QGXMlrL0krrj7XOKSc3
+SvZa4j0S/Y5CKkw5xuZXxITsdaV6hGi3d/kuT+1ttOSfIIXJXDEiu4pYRfziKU1a
+8EhHMEajEi6ueLw7QmEPVx398erRwiUuP2y43yZ4mwVwvN3i5jlVztl4XsglDmQ+
+hahstVdMMA34K2rK0U8q8YjdYm+z99NmGEPYrS6Qnpr1xrICN83FOWFI0k7ttyMC
+AwEAAaNTMFEwHQYDVR0OBBYEFLqMY6eP3h3gu+ANs77xDBRnElxyMB8GA1UdIwQY
+MBaAFLqMY6eP3h3gu+ANs77xDBRnElxyMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBAJS+wyy0r+tVAlCa6V/xxlCDtW9n6L2nsqJXEjME0VvwGs3m
+ima68LyTQJqCSjjxSotaNOYKzUu4vRA3JssV+fUDR+NpmhpRuM74XmO05HUQkp9U
+dBEHyXp2aRQ9LSdvHo5D+RW+J4sHFb3PbU8NPx/t5Dg7il92S2QJQz1jNl+Nezc6
+2O8Vt1YbvWXfqM47URTpnQbWoo38pI44AgAuW3QagucKWsyounmhx65XcdtLn99g
+oZt496pU+hBpYu/IpXuBKNC4FvOrXTWAPkAbbYP39UFyiKwIyTosK+qdbhBlt1xi
+bBPn6N1W9L2BvUwM8fEB/qBuR9UfcMsIYJsWbbXMfyeF6lbaP7xD01rm+yU5PMMI
+Co40abixMntz4J3T2ixdCptf0He1U/UegOHwG1ZGgQzvOG6qI/xkNktDaSA75KR7
+BvPV1CmZC4ovVo1L4STrwnoRz5J49PNOHi9Okj9zJ99H7nsmsK16oxpIYkYHJWn+
+45jpG8SlDp7oev1OGGk/z+ZOTz+LcNxyvsRQVN8w5zNmjCSWiGqz+UUgppCZg8qd
+ECWokNQ5Lr20t1whynrX5bH0l887WPCQmm5VduRoyKFGhCRBSzcCtowSpiwZglUk
+CV0jgFKoteItdzZgsND5I1GaNOxZlnK3wN4H0pgZv7HlW6SP1OYd2Y67waJ7
+-----END CERTIFICATE-----
diff --git a/tests/stdlib/thttpclient_ssl_key.pem b/tests/stdlib/thttpclient_ssl_key.pem
new file mode 100644
index 000000000..6ab04122c
--- /dev/null
+++ b/tests/stdlib/thttpclient_ssl_key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDOgRUSXvKpj5Go
+hqBcMPgkHsvI40O+Hxom8EyclUGCNosl2R9CO88ZTNSQRtTmdzq7uWoXHMS/uFeu
+yxAIHtPAnB9LY9PVGPXggWVg/LDgMR4/VFVL9rC6u2/ePC6ZqtWXstH4hB+jn2Qn
+8/yNm3wfcexwNvKFdwd45Yjqr5eV91WZNQlW8AF1S46IgWOB8VVOmj4IrHLtzlxp
+EMruDWz3EHX8z09R8m8djVasFYU5l/QGXyLCf5qG7F8hWqwUv2V6ovKSCLV/gvbS
+ntFoAr3lNcKjcKzNmbgWzD3OHOSOhTvaHSe5iXX3stm9Gze78kmPNkRGax9U8izk
+G07z8w3Uy9GfqEgZTlDeQ5VapbFKRKWeOt/67BR2f/bi5IKfKA14O4nPBb/arg31
+gjeii+o0gamRPcVsCbtQrAjiXCHCarDtYf73YQuPQGKeawwxE8PY6q8r6/MtWrBQ
+hCRi6D4ePKzpAZcyWsvSSuuPtc4pJzdK9lriPRL9jkIqTDnG5lfEhOx1pXqEaLd3
++S5P7W205J8ghclcMSK7ilhF/OIpTVrwSEcwRqMSLq54vDtCYQ9XHf3x6tHCJS4/
+bLjfJnibBXC83eLmOVXO2XheyCUOZD6FqGy1V0wwDfgrasrRTyrxiN1ib7P302YY
+Q9itLpCemvXGsgI3zcU5YUjSTu23IwIDAQABAoICAQCdR60/57cUs/dxjs/2R4nH
+IPl/ELEYzeGCRMVlATz6qwZCFmN7c8ghceX32SrwOWEvd2G5Jr0ndIS76YdVV/1Z
+ls8zAV5m0HL8wjDvtKYWqvJps5afm80w+++RKO8pNPcnahgIGsFqQszqrSbux7y6
+ym8VbJQ8WNMFHnWwoXpnyxCT9tQdNgE2UAzIJRwf7SpXCp0yx/1k6CZ0E0ksFGeo
+qQ3kNhUoyegdbvfTazSkD/rZG36C+uM73i36Xm/wAXKN/CuaVC3AZ4QMGNBPUr9F
+IzQSfY/vrCOMoZR1NoZRkmJqlogaBPsnZD34jRFfAYNLIz7PD2m2rhjIx4/Tt4wQ
+5mUwga9ud0ly5wSzswudw07mTYtsLbWrUn6QdFxSwbQ0tXh9PJrqCSJDmYIptuu/
+6zjg8hQLg7y37xMDMCdKtviHx+ndVpW3StTwB/z7lDA6yuYY6nYN0dJTJS3qQheo
+maPG4Xf4FBcD4Is73BjBCf3QR6WIv0ZOG3/GZ1OqLRrPg1u/3UJkpa4LE/6qNUxf
+zdBZSPyQZExBvOqdklEI+1OcqofmWq2n7Amct45buDbFryehEhfJ1HHtkXkTEsut
+azfQeaGem/jKxcTD+1bWs/Q5Nn+QFfKr0NFjXSLoITWQkgQD1qISw3DC72jYXlsm
+S4CmCDW1dHZlmWZq+Mh34QKCAQEA+2JFRa1yYZ0tPt88sOjJYyw9yUxB9Nv9cKrs
+kdkhKHKevF+0BUbRLfp9bod+Wlv66pgQi6ZGKkGD7lCam/3FIBlmmiG8AOoXdoGy
+t17XCzlYy348mnHra2X+JBAN51ivPemdlGZShLbNMkGdL1khtjHL9vSr1KgFn3F/
+8nstVQ9nzHTCK0HWpBGn/EK3dd8lcYZDd7Fcgjz7E3xQDz/XZt0HMwwGaLnQ1L7T
+glIyeNdqLBp4v0NT6L1AAk5rQJONo57AepblwacYhoW9mR5K0bm/BMo5+xwMtYz9
+69ZuMNW8qdaWrzeEsxM1PDbcOoVqChF10w0Ih/MkhKGpN/GxUQKCAQEA0kvWUkEK
+1BBhwGyuKrMnUC3jnQ36KpsjlryMUArdjS2gVBztGW2p2CUWasEgZdxpwQmnqKyz
+4hcZaU/JUleutTI5raxzju4Ve87c+koOiamhw/zaiLCpLn2j0Rh2qxp7QvPPRO0V
+1MN347wjCTx/5/j8WffgWqWfqdrd8JheKal/OHlTZA3DG77FIVnUyov8Np+lTd1x
+NpWr/AOreZlMBq/X/kmWCe+fP901fGdi3cdsKcJcdLPv9KFciSjBlAlaLMnBgLWo
+RrIuNxdH3dRX4rzBSpdNq72n8NaH+A10eoXrlC4eWLo7vRSTe4WRgUAIbhVifnJk
+z4B5FqC/aVgkMwKCAQEAtq983h0lcbDy76z2Ay65I/xDzqU/jX3OGfHtSDS+NxHN
+L+JxBiCn5b0TKJ8JAQu1NoVaCNLGTPEdurQTF+f9OM2c1chMQ3HbqUCqKz6eEscT
+M5dC3Y6KYptVbMnKAOVfPSQoY29U6qOaTbqHS6B/slNQAeFfeoS8yVmHfSVtFVLD
+wT7c2OjY3pUCOn4Vq3CGWpETOMnJC9DbOhbua5aeqF9aWwuTIMpg7CrdtOidS1pp
+CzIVrBF2yj22ZbatlNlmZpD5Gl3NDMWtOh25Yqwz/WP6YLXCGy4QQmP7KEfF/nFl
+0RtkmGNFaYo89sx7kX/hRv3XXZAsMfhOAqElQ8W+cQKCAQAdL/lnIS/njv6CPpNN
+yd/C+RuGSNJX54BhA3pWAawOVC7Ufc9KoDXakgsydeuRN65V5IkomA+/aYVVYIWI
+sDLHY1kuCalgRRsmO+fftTefU7PoB8gtAJf6o+WAt+yAgwRonn4+Csnk5dxV917F
+gWgfQieENSsmaaZnZME5C2zGS4gkxnIUiPRzfV7O6jDmi9dNnYrL69gyw0NDjx7V
+mbk7lFxeJsh0SJXJv2IVCiRms68HfLpoWDENuvek8cssSMADR11cB9p7NW/Epa6L
+01T/W0NYnvdgxsnwW1Yzz2pDNyMjReNgXTi9XYW6tyci0UhaPw2Ujzv+sM4dneHz
+NRCRAoIBAHqXaeC1uTGSzfLvRz81ifgDRP8H9L1HLt7ZWL6XMp1ph+P6yYFXM4JK
+WeP3cdKO/kQOD/fLuhYT92T2hHEadT8CQqpsBMQt29Zlm4oYWHB7ERiZqaGX3/T0
+U1TlL0WxthoHPY2HwA6pmDTmUzDk3tFlgk+XOmLsDacBdC6EsFwA+tyEPVxmkb0J
+H+j7D4NxwysAyWCB9fWU1FV+JJJel+nz88i7Gb8uJ+kSktnFxjv/G9p+OkDYlaUt
+j8lc6LOuNOA9M7XT1BIKpZytnSVtwZWkMmu23OLMM/d07tPJYtHIa92On7XKBPc2
+6THbQsJpR5AalTVvXs3X1RnCLnHiNYg=
+-----END PRIVATE KEY-----
diff --git a/tests/stdlib/thttpclient_standalone.nim b/tests/stdlib/thttpclient_standalone.nim
new file mode 100644
index 000000000..2f432eede
--- /dev/null
+++ b/tests/stdlib/thttpclient_standalone.nim
@@ -0,0 +1,59 @@
+discard """
+  cmd: "nim c --threads:on $file"
+"""
+
+import asynchttpserver, httpclient, asyncdispatch, strutils, net
+
+import std/assertions
+
+block: # bug #16436
+  proc startServer(): AsyncHttpServer =
+    result = newAsyncHttpServer()
+    result.listen(Port(0))
+
+  proc processRequest(server: AsyncHttpServer) {.async.} =
+    proc cb(req: Request) {.async.} =
+      let headers = { "Content-length": "15"} # Provide invalid content-length
+      await req.respond(Http200, "Hello World", headers.newHttpHeaders())
+
+    await server.acceptRequest(cb)
+
+  proc runClient(port: Port) {.async.} =
+    let c = newAsyncHttpClient(headers = {"Connection": "close"}.newHttpHeaders)
+    discard await c.getContent("http://127.0.0.1:" & $port)
+    doAssert false, "should fail earlier"
+
+  let server = startServer()
+  asyncCheck processRequest(server)
+  let port = server.getPort()
+  doAssertRaises(ProtocolError):
+    waitFor runClient(port)
+
+block: # bug #14794 (And test for presence of content-length header when using postContent)
+  proc startServer(): AsyncHttpServer =
+    result = newAsyncHttpServer()
+    result.listen(Port(0))
+
+  proc runServer(server: AsyncHttpServer) {.async.} =
+    proc cb(req: Request) {.async.} =
+      doAssert(req.body.endsWith(httpNewLine), "Multipart body does not end with a newline.")
+      # this next line is probably not required because asynchttpserver does not call
+      # the callback when there is no content-length header.  It instead errors with 
+      # Error: unhandled exception: 411 Length Required
+      # Added for good measure in case the server becomes more permissive.
+      doAssert(req.headers.hasKey("content-length"), "Content-Length header is not present.")
+      asyncCheck req.respond(Http200, "OK")
+
+    await server.acceptRequest(cb)
+
+  proc runClient(port: Port) {.async.} =
+    let c = newAsyncHttpClient()
+    let data = newMultipartData()
+    data.add("file.txt", "This is intended to be an example text file.\r\nThis would be the second line.\r\n")
+    discard await c.postContent("http://127.0.0.1:" & $port, multipart = data)
+    c.close()
+
+  let server = startServer()
+  let port = server.getPort()
+  asyncCheck runServer(server)
+  waitFor runClient(port)
diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim
index 9f99df93a..93e7d85c6 100644
--- a/tests/stdlib/thttpcore.nim
+++ b/tests/stdlib/thttpcore.nim
@@ -1,28 +1,103 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
 
-import unittest
+import httpcore, strutils
+import std/assertions
 
-import httpcore
+block:
+  block HttpCode:
+    doAssert $Http418 == "418 I'm a teapot"
+    doAssert Http418.is4xx() == true
+    doAssert Http418.is2xx() == false
 
-suite "httpcore":
-
-  test "HttpCode":
-    assert $Http418 == "418 I'm a teapot"
-    assert Http418.is4xx() == true
-    assert Http418.is2xx() == false
-
-  test "headers":
+  block headers:
     var h = newHttpHeaders()
-    assert h.len == 0
+    doAssert h.len == 0
     h.add("Cookie", "foo")
-    assert h.len == 1
-    assert h.hasKey("cooKIE")
-    assert h["Cookie"] == "foo"
-    assert h["cookie"] == "foo"
+    doAssert h.len == 1
+    doAssert h.hasKey("cooKIE")
+    doAssert h["Cookie"] == "foo"
+    doAssert h["cookie"] == "foo"
     h["cookie"] = @["bar", "x"]
-    assert h["Cookie"] == "bar"
-    assert h["Cookie", 1] == "x"
-    assert h["Cookie"].contains("BaR") == true
-    assert h["Cookie"].contains("X") == true
-    assert "baR" in h["cookiE"]
+    doAssert h["Cookie"] == "bar"
+    doAssert h["Cookie", 1] == "x"
+    doAssert h["Cookie"].contains("BaR") == true
+    doAssert h["Cookie"].contains("X") == true
+    doAssert "baR" in h["cookiE"]
     h.del("coOKie")
-    assert h.len == 0
+    doAssert h.len == 0
+
+    # Test that header constructor works with repeated values
+    let h1 = newHttpHeaders({"a": "1", "a": "2", "A": "3"})
+
+    doAssert seq[string](h1["a"]).join(",") == "1,2,3"
+
+  block test_cookies_with_comma:
+    doAssert parseHeader("cookie: foo, bar") ==  ("cookie", @["foo, bar"])
+    doAssert parseHeader("cookie: foo, bar, prologue") == ("cookie", @["foo, bar, prologue"])
+    doAssert parseHeader("cookie: foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"])
+
+    doAssert parseHeader("cookie:   foo, bar") ==  ("cookie", @["foo, bar"])
+    doAssert parseHeader("cookie:  foo, bar, prologue") == ("cookie", @["foo, bar, prologue"])
+    doAssert parseHeader("cookie:   foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"])
+
+    doAssert parseHeader("Cookie: foo, bar") == (key: "Cookie", value: @["foo, bar"])
+    doAssert parseHeader("Cookie: foo, bar, prologue") == (key: "Cookie", value: @["foo, bar, prologue"])
+    doAssert parseHeader("Cookie: foo, bar, prologue, starlight") == (key: "Cookie", value: @["foo, bar, prologue, starlight"])
+
+    doAssert parseHeader("Accept: foo, bar") == (key: "Accept", value: @["foo", "bar"])
+    doAssert parseHeader("Accept: foo, bar, prologue") == (key: "Accept", value: @["foo", "bar", "prologue"])
+    doAssert parseHeader("Accept: foo, bar, prologue, starlight") == (key: "Accept", value: @["foo", "bar", "prologue", "starlight"])
+
+  block add_empty_sequence_to_HTTP_headers:
+    block:
+      var headers = newHttpHeaders()
+      headers["empty"] = @[]
+
+      doAssert not headers.hasKey("empty")
+
+    block:
+      var headers = newHttpHeaders()
+      headers["existing"] = "true"
+      headers["existing"] = @[]
+
+      doAssert not headers.hasKey("existing")
+
+    block:
+      var headers = newHttpHeaders()
+      headers["existing"] = @["true"]
+      headers["existing"] = @[]
+
+      doAssert not headers.hasKey("existing")
+
+    block:
+      var headers = newHttpHeaders()
+      headers["existing"] = @[]
+      headers["existing"] = @["true"]
+      doAssert headers.hasKey("existing")
+
+block:
+  var test = newHttpHeaders()
+  test["Connection"] = @["Upgrade", "Close"]
+  doAssert test["Connection", 0] == "Upgrade"
+  doAssert test["Connection", 1] == "Close"
+  test.add("Connection", "Test")
+  doAssert test["Connection", 2] == "Test"
+  doAssert "upgrade" in test["Connection"]
+
+  # Bug #5344.
+  doAssert parseHeader("foobar: ") == ("foobar", @[""])
+  let (key, value) = parseHeader("foobar: ")
+  test = newHttpHeaders()
+  test[key] = value
+  doAssert test["foobar"] == ""
+
+  doAssert parseHeader("foobar:") == ("foobar", @[""])
+
+  block: # test title case
+    var testTitleCase = newHttpHeaders(titleCase=true)
+    testTitleCase.add("content-length", "1")
+    doAssert testTitleCase.hasKey("Content-Length")
+    for key, val in testTitleCase:
+        doAssert key == "Content-Length"
diff --git a/tests/stdlib/timportutils.nim b/tests/stdlib/timportutils.nim
new file mode 100644
index 000000000..672092282
--- /dev/null
+++ b/tests/stdlib/timportutils.nim
@@ -0,0 +1,151 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[importutils, assertions]
+import stdtest/testutils
+import mimportutils
+
+template main =
+  block: # privateAccess
+    assertAll:
+      var a: A
+      var b = initB() # B is private
+      compiles(a.a0)
+      compiles(b.b0)
+      not compiles(a.ha1)
+      not compiles(b.hb1)
+
+    block:
+      assertAll:
+        privateAccess A
+        compiles(a.ha1)
+        a.ha1 == 0.0
+        not compiles(a.hb1)
+        privateAccess b.typeof
+        b.hb1 = 3
+        type B2 = b.typeof
+        let b2 = B2(b0: 4, hb1: 5)
+        b.hb1 == 3
+        b2 == B2(b0: 4, hb1: 5)
+
+    assertAll:
+      not compiles(a.ha1)
+      not compiles(b.hb1)
+
+    block:
+      assertAll:
+        not compiles(C(c0: 1, hc1: 2))
+        privateAccess C
+        let c = C(c0: 1, hc1: 2)
+        c.hc1 == 2
+
+    block:
+      assertAll:
+        not compiles(E[int](he1: 1))
+        privateAccess E[int]
+        var e = E[int](he1: 1)
+        e.he1 == 1
+        e.he1 = 2
+        e.he1 == 2
+        e.he1 += 3
+        e.he1 == 5
+        # xxx caveat: this currently compiles but in future, we may want
+        # to make `privateAccess E[int]` only affect a specific instantiation;
+        # note that `privateAccess E` does work to cover all instantiations.
+        var e2 = E[float](he1: 1)
+
+    block:
+      assertAll:
+        not compiles(E[int](he1: 1))
+        privateAccess E
+        var e = E[int](he1: 1)
+        e.he1 == 1
+
+    block:
+      assertAll:
+        not compiles(F[int, int](h3: 1))
+        privateAccess F[int, int]
+        var e = F[int, int](h3: 1)
+        e.h3 == 1
+
+    block:
+      assertAll:
+        not compiles(F[int, int](h3: 1))
+        privateAccess F[int, int].default[].typeof
+        var e = F[int, int](h3: 1)
+        e.h3 == 1
+
+    block:
+      assertAll:
+        var a = G[int]()
+        var b = a.addr
+        privateAccess b.type
+        discard b.he1
+        discard b[][].he1
+
+    block:
+      assertAll:
+        privateAccess H[int]
+        var a = H[int](h5: 2)
+
+    block:
+      assertAll:
+        privateAccess PA
+        var pa = PA(a0: 1, ha1: 2)
+        pa.ha1 == 2
+        pa.ha1 = 3
+        pa.ha1 == 3
+
+    block:
+      assertAll:
+        var b = BAalias()
+        not compiles(b.hb1)
+        privateAccess BAalias
+        discard b.hb1
+
+    block:
+      assertAll:
+        var a = A(a0: 1)
+        var a2 = a.addr
+        not compiles(a2.ha1)
+        privateAccess PtA
+        a2.type is PtA
+        a2.ha1 = 2
+        a2.ha1 == 2
+        a.ha1 = 3
+        a2.ha1 == 3
+
+    block:
+      disableVm:
+        assertAll:
+          var a = A.create()
+          defer: dealloc(a)
+          a is PtA
+          a.typeof is PtA
+          not compiles(a.ha1)
+          privateAccess a.typeof
+          a.ha1 = 2
+          a.ha1 == 2
+          a[].ha1 = 3
+          a.ha1 == 3
+
+    block:
+      disableVm:
+        assertAll:
+          var a = A.create()
+          defer: dealloc(a)
+          privateAccess PtA
+          a.ha1 == 0
+
+    block:
+      privateAccess PityRef
+      let x = PityRef[int](a: 1)  # works
+      doAssert x.a == 1
+
+      privateAccess Hope
+      let y = Hope[int](a: 1)
+      doAssert y.a == 1
+
+static: main()
+main()
diff --git a/tests/stdlib/tintsets.nim b/tests/stdlib/tintsets.nim
new file mode 100644
index 000000000..191ef117e
--- /dev/null
+++ b/tests/stdlib/tintsets.nim
@@ -0,0 +1,6 @@
+import ./mintsets
+
+block: # bug https://github.com/nim-lang/Nim/pull/15564#issuecomment-729878104
+  # related to bug #11167
+  test1()
+  test2()
diff --git a/tests/stdlib/tio.nim b/tests/stdlib/tio.nim
index 28e1881e8..80a119763 100644
--- a/tests/stdlib/tio.nim
+++ b/tests/stdlib/tio.nim
@@ -1,40 +1,60 @@
 discard """
-  output: '''9
-b = false
-123456789
-Second readLine raised an exception
-123456789
-'''
+  matrix: "--mm:refc; --mm:orc"
 """
-# bug #5349
-import os
 
-# test the file-IO
-
-const fn = "file9char.txt"
-
-writeFile(fn, "123456789")
-
-var f = open(fn)
-echo getFileSize(f)
-
-var line = newString(10)
-try:
-  let b = readLine(f, line)
-  echo "b = ", b
-except:
-  echo "First readLine raised an exception"
-
-echo line
-
-try:
-  line = readLine(f)
-  let b = readLine(f, line)
-  echo "b = ", b
-except:
-  echo "Second readLine raised an exception"
-
-echo line
-f.close()
-
-removeFile(fn)
+# xxx move to here other tests that belong here; io is a proper module
+
+import std/os
+from stdtest/specialpaths import buildDir
+import std/[assertions, syncio]
+
+block: # readChars
+  let file = buildDir / "D20201118T205105.txt"
+  let s = "he\0l\0lo"
+  writeFile(file, s)
+  defer: removeFile(file)
+  let f = open(file)
+  defer: close(f)
+  let n = f.getFileInfo.blockSize
+  var buf = newString(n)
+  template fn =
+    let n2 = f.readChars(buf)
+    doAssert n2 == s.len
+    doAssert buf[0..<n2] == s
+  fn()
+  setFilePos(f, 0)
+  fn()
+
+  block:
+    setFilePos(f, 0)
+    var s2: string
+    let nSmall = 2
+    for ai in buf.mitems: ai = '\0'
+    var n2s: seq[int]
+    while true:
+      let n2 = f.readChars(toOpenArray(buf, 0, nSmall-1))
+      # xxx: maybe we could support: toOpenArray(buf, 0..nSmall)
+      n2s.add n2
+      s2.add buf[0..<n2]
+      if n2 == 0:
+        break
+    doAssert n2s == @[2,2,2,1,0]
+    doAssert s2 == s
+
+
+import std/strutils
+
+block: # bug #21273
+  let FILE = buildDir / "D20220119T134305.txt"
+
+  let hex = "313632313920313632343720313632353920313632363020313632393020323035363520323037323120323131353020323239393820323331303520323332313020323332343820323332363820"
+
+
+  writeFile FILE, parseHexStr(hex)
+
+  doAssert readFile(FILE).toHex == hex
+
+  let f = open(FILE)
+  var s = newString(80)
+  while f.readLine(s):
+    doAssert s.toHex == hex
diff --git a/tests/stdlib/tisolation.nim b/tests/stdlib/tisolation.nim
new file mode 100644
index 000000000..18b83ea2e
--- /dev/null
+++ b/tests/stdlib/tisolation.nim
@@ -0,0 +1,135 @@
+discard """
+  targets: "c cpp"
+  matrix: "--gc:refc; --gc:orc"
+"""
+
+import std/[isolation, json]
+import std/[assertions, objectdollar]
+
+
+proc main(moveZeroesOut: static bool) =
+  block:
+    type
+      Empty = ref object
+
+
+    var x = isolate(Empty())
+    discard extract(x)
+
+  block: # string literals
+    var data = isolate("string")
+    doAssert data.extract == "string"
+    if moveZeroesOut:
+      doAssert data.extract == ""
+
+  block: # string literals
+    var data = isolate("")
+    doAssert data.extract == ""
+    if moveZeroesOut:
+      doAssert data.extract == ""
+
+  block:
+    var src = "string"
+    var data = isolate(move src)
+    doAssert data.extract == "string"
+    if moveZeroesOut:
+      doAssert src.len == 0
+
+  block: # int literals
+    var data = isolate(1)
+    doAssert data.extract == 1
+    if moveZeroesOut:
+      doAssert data.extract == 0
+
+  block: # float literals
+    var data = isolate(1.6)
+    doAssert data.extract == 1.6
+    if moveZeroesOut:
+      doAssert data.extract == 0.0
+
+  block:
+    var data = isolate(@["1", "2"])
+    doAssert data.extract == @["1", "2"]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var data = isolate(@["1", "2", "3", "4", "5"])
+    doAssert data.extract == @["1", "2", "3", "4", "5"]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var data = isolate(@["", ""])
+    doAssert data.extract == @["", ""]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var src = @["1", "2"]
+    var data = isolate(move src)
+    doAssert data.extract == @["1", "2"]
+    if moveZeroesOut:
+      doAssert src.len == 0
+
+  block:
+    var data = isolate(@[1, 2])
+    doAssert data.extract == @[1, 2]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var data = isolate(["1", "2"])
+    doAssert data.extract == ["1", "2"]
+    if moveZeroesOut:
+      doAssert data.extract == ["", ""]
+
+  block:
+    var data = isolate([1, 2])
+    doAssert data.extract == [1, 2]
+    if moveZeroesOut:
+      doAssert data.extract == [0, 0]
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var data = isolate(Test(id: 12))
+    doAssert data.extract.id == 12
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var src = Test(id: 12)
+    var data = isolate(src)
+    doAssert data.extract.id == 12
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var src = Test(id: 12)
+    var data = isolate(move src)
+    doAssert data.extract.id == 12
+
+  block:
+    type
+      Test = ref object
+        id: int
+
+    var data = isolate(Test(id: 12))
+    doAssert data.extract.id == 12
+
+  block:
+    var x: seq[Isolated[JsonNode]]
+    x.add isolate(newJString("1234"))
+
+    doAssert $x == """@[(value: "1234")]"""
+
+
+static: main(moveZeroesOut = false)
+main(moveZeroesOut = true)
diff --git a/tests/stdlib/tjsbigints.nim b/tests/stdlib/tjsbigints.nim
new file mode 100644
index 000000000..29b0ac3e7
--- /dev/null
+++ b/tests/stdlib/tjsbigints.nim
@@ -0,0 +1,46 @@
+discard """
+  targets: "js"
+"""
+
+import std/[jsbigints, assertions]
+
+
+let big1: JsBigInt = big"2147483647"
+let big2: JsBigInt = big"666"
+var big3: JsBigInt = big"2"
+
+doAssert big3 == big"2"
+doAssert (big3 xor big2) == big"664"
+doAssert (big"555" and big"2") == big"2"
+doAssert (big"555" or big"2") == big"555"
+doAssert (big1 mod big2) == big"613"
+doAssert -big1 == big"-2147483647"
+doAssert big1 div big2 == big"3224449"
+doAssert big1 + big2 == big"2147484313"
+doAssert big1 - big2 == big"2147482981"
+doAssert big1 shl big3 == big"8589934588"
+doAssert big1 shr big3 == big"536870911"
+doAssert big1 * big2 == big"1430224108902"
+doAssert $big1 == "2147483647n"
+doAssert big1.toCstring(10) == "2147483647".cstring
+doAssert big2 ** big3 == big(443556)
+var huge = big"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
+huge.inc
+huge = huge + -999999999999999999999999999999999999999999999999999999999999999999999999999999999999999'big
+doAssert huge == big"1"
+var list: seq[JsBigInt]
+for i in big"0" .. big"5":
+  doAssert i is JsBigInt
+  list.add i
+doAssert list == @[big"0", big"1", big"2", big"3", big"4", big"5"]
+list = @[]
+for i in big"0" ..< big"5":
+  doAssert i is JsBigInt
+  list.add i
+doAssert list == @[big"0", big"1", big"2", big"3", big"4"]
+
+block:
+  let b = 2'big
+  doAssert -b ** 3'big == -8'big
+  doAssert -b ** big"2" == big"4" # not -4 because of precedence
+  doAssert -big"3" == big"-3"
diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim
new file mode 100644
index 000000000..e425501f6
--- /dev/null
+++ b/tests/stdlib/tjson.nim
@@ -0,0 +1,382 @@
+discard """
+  matrix: "; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
+"""
+
+
+#[
+Note: Macro tests are in tests/stdlib/tjsonmacro.nim
+]#
+
+import std/[json,parsejson,strutils]
+import std/private/jsutils
+from std/math import isNaN
+when not defined(js):
+  import std/streams
+import stdtest/testutils
+from std/fenv import epsilon
+import std/[assertions, objectdollar]
+
+proc testRoundtrip[T](t: T, expected: string) =
+  # checks that `T => json => T2 => json2` is such that json2 = json
+  let j = %t
+  doAssert $j == expected, $j
+  doAssert %(j.to(T)) == j
+
+proc testRoundtripVal[T](t: T, expected: string) =
+  # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T`
+  # note that this isn't always possible, e.g. for pointer-like types or nans
+  let j = %t
+  doAssert $j == expected, $j
+  let j2 = ($j).parseJson
+  doAssert $j2 == expected, $(j2, t)
+  let t2 = j2.to(T)
+  doAssert t2 == t
+  doAssert $(%* t2) == expected # sanity check, because -0.0 = 0.0 but their json representation differs
+
+let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
+# nil passthrough
+doAssert(testJson{"doesnt_exist"}{"anything"}.isNil)
+testJson{["e", "f"]} = %true
+doAssert(testJson["e"]["f"].bval)
+
+# make sure UTF-16 decoding works.
+doAssert(testJson["c"].str == "🎃")
+doAssert(testJson["d"].str == "æ")
+
+# make sure no memory leek when parsing invalid string
+let startMemory = getOccupiedMem()
+for i in 0 .. 10000:
+  try:
+    discard parseJson"""{ invalid"""
+  except:
+    discard
+# memory diff should less than 4M
+doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024)
+
+
+# test `$`
+let stringified = $testJson
+let parsedAgain = parseJson(stringified)
+doAssert(parsedAgain["b"].str == "asd")
+
+parsedAgain["abc"] = %5
+doAssert parsedAgain["abc"].num == 5
+
+# Bounds checking
+when compileOption("boundChecks"):
+  try:
+    let a = testJson["a"][9]
+    doAssert(false, "IndexDefect not thrown")
+  except IndexDefect:
+    discard
+  try:
+    let a = testJson["a"][-1]
+    doAssert(false, "IndexDefect not thrown")
+  except IndexDefect:
+    discard
+  try:
+    doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")
+  except:
+    doAssert(false, "IndexDefect thrown for valid index")
+
+doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}")
+doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
+doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
+doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
+
+# Generator:
+var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
+doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+var j2 = %*
+  [
+    {
+      "name": "John",
+      "age": 30
+    },
+    {
+      "name": "Susan",
+      "age": 31
+    }
+  ]
+doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+var name = "John"
+let herAge = 30
+const hisAge = 31
+
+var j3 = %*
+  [ {"name": "John"
+    , "age": herAge
+    }
+  , {"name": "Susan"
+    , "age": hisAge
+    }
+  ]
+doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+var j4 = %*{"test": nil}
+doAssert j4 == %{"test": newJNull()}
+
+let seqOfNodes = @[%1, %2]
+let jSeqOfNodes = %seqOfNodes
+doAssert(jSeqOfNodes[1].num == 2)
+
+type MyObj = object
+  a, b: int
+  s: string
+  f32: float32
+  f64: float64
+  next: ref MyObj
+var m: MyObj
+m.s = "hi"
+m.a = 5
+let jMyObj = %m
+doAssert(jMyObj["a"].num == 5)
+doAssert(jMyObj["s"].str == "hi")
+
+# Test loading of file.
+when not defined(js):
+  var parsed = parseFile("tests/testdata/jsontest.json")
+
+  try:
+    discard parsed["key2"][12123]
+    doAssert(false)
+  except IndexDefect: doAssert(true)
+
+  var parsed2 = parseFile("tests/testdata/jsontest2.json")
+  doAssert(parsed2{"repository", "description"}.str ==
+      "IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+
+doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
+doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887
+doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\""
+doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0014\"" # for #7887
+
+# Test with extra data
+when not defined(js):
+  try:
+    discard parseJson("123 456")
+    doAssert(false)
+  except JsonParsingError:
+    doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
+
+  try:
+    discard parseFile("tests/testdata/jsonwithextradata.json")
+    doAssert(false)
+  except JsonParsingError:
+    doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
+
+# bug #6438
+doAssert($ %*[] == "[]")
+doAssert($ %*{} == "{}")
+
+doAssert(not compiles(%{"error": "No messages"}))
+
+# bug #9111
+block:
+  type
+    Bar = string
+    Foo = object
+      a: int
+      b: Bar
+
+  let
+    js = """{"a": 123, "b": "abc"}""".parseJson
+    foo = js.to Foo
+
+  doAssert(foo.b == "abc")
+
+# Generate constructors for range[T] types
+block:
+  type
+    Q1 = range[0'u8 .. 50'u8]
+    Q2 = range[0'u16 .. 50'u16]
+    Q3 = range[0'u32 .. 50'u32]
+    Q4 = range[0'i8 .. 50'i8]
+    Q5 = range[0'i16 .. 50'i16]
+    Q6 = range[0'i32 .. 50'i32]
+    Q7 = range[0'f32 .. 50'f32]
+    Q8 = range[0'f64 .. 50'f64]
+    Q9 = range[0 .. 50]
+
+    X = object
+      m1: Q1
+      m2: Q2
+      m3: Q3
+      m4: Q4
+      m5: Q5
+      m6: Q6
+      m7: Q7
+      m8: Q8
+      m9: Q9
+
+  let obj = X(
+    m1: Q1(42),
+    m2: Q2(42),
+    m3: Q3(42),
+    m4: Q4(42),
+    m5: Q5(42),
+    m6: Q6(42),
+    m7: Q7(42),
+    m8: Q8(42),
+    m9: Q9(42)
+  )
+
+  doAssert(obj == to(%obj, type(obj)))
+
+  when not defined(js):
+    const fragments = """[1,2,3] {"hi":3} 12 [] """
+    var res = ""
+    for x in parseJsonFragments(newStringStream(fragments)):
+      res.add($x)
+      res.add " "
+    doAssert res == fragments
+
+
+# test isRefSkipDistinct
+type
+  MyRef = ref object
+  MyObject = object
+  MyDistinct = distinct MyRef
+  MyOtherDistinct = distinct MyRef
+
+var x0: ref int
+var x1: MyRef
+var x2: MyObject
+var x3: MyDistinct
+var x4: MyOtherDistinct
+
+doAssert isRefSkipDistinct(x0)
+doAssert isRefSkipDistinct(x1)
+doAssert not isRefSkipDistinct(x2)
+doAssert isRefSkipDistinct(x3)
+doAssert isRefSkipDistinct(x4)
+
+
+doAssert isRefSkipDistinct(ref int)
+doAssert isRefSkipDistinct(MyRef)
+doAssert not isRefSkipDistinct(MyObject)
+doAssert isRefSkipDistinct(MyDistinct)
+doAssert isRefSkipDistinct(MyOtherDistinct)
+
+let x = parseJson("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999")
+
+doAssert x.kind == JString
+
+block: # bug #15835
+  type
+    Foo = object
+      ii*: int
+      data*: JsonNode
+
+  block:
+    const jt = """{"ii": 123, "data": ["some", "data"]}"""
+    let js = parseJson(jt)
+    discard js.to(Foo)
+
+  block:
+    const jt = """{"ii": 123}"""
+    let js = parseJson(jt)
+    doAssertRaises(KeyError):
+      echo js.to(Foo)
+
+type
+  ContentNodeKind* = enum
+    P,
+    Br,
+    Text,
+  ContentNode* = object
+    case kind*: ContentNodeKind
+    of P: pChildren*: seq[ContentNode]
+    of Br: nil
+    of Text: textStr*: string
+
+let mynode = ContentNode(kind: P, pChildren: @[
+  ContentNode(kind: Text, textStr: "mychild"),
+  ContentNode(kind: Br)
+])
+
+doAssert $mynode == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])"""
+
+let jsonNode = %*mynode
+doAssert $jsonNode == """{"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]}"""
+doAssert $jsonNode.to(ContentNode) == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])"""
+
+block: # bug #17383
+  testRoundtrip(int32.high): "2147483647"
+  testRoundtrip(uint32.high): "4294967295"
+  when int.sizeof == 4:
+    testRoundtrip(int.high): "2147483647"
+    testRoundtrip(uint.high): "4294967295"
+  else:
+    testRoundtrip(int.high): "9223372036854775807"
+    testRoundtrip(uint.high): "18446744073709551615"
+  whenJsNoBigInt64: discard
+  do:
+    testRoundtrip(int64.high): "9223372036854775807"
+    testRoundtrip(uint64.high): "18446744073709551615"
+
+block: # bug #18007
+  testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+  # pending https://github.com/nim-lang/Nim/issues/18025 use:
+  # testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0])
+  let inf = float32(Inf)
+  testRoundtrip([float32(NaN), inf, -inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+  when not defined(js): # because of Infinity vs inf
+    testRoundtripVal([inf, -inf, 0.0, -0.0, 1.0]): """["inf","-inf",0.0,-0.0,1.0]"""
+  let a = parseJson($(%NaN)).to(float)
+  doAssert a.isNaN
+
+  whenRuntimeJs: discard # refs bug #18009
+  do:
+    testRoundtripVal(0.0): "0.0"
+    testRoundtripVal(-0.0): "-0.0"
+
+block: # bug #15397, bug #13196
+  testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002"
+  testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568"
+
+block:
+  let a = "18446744073709551615"
+  let b = a.parseJson
+  doAssert b.kind == JString
+  let c = $b
+  when defined(js):
+    doAssert c == "18446744073709552000"
+  else:
+    doAssert c == "18446744073709551615"
+
+block:
+  let a = """
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+"""
+
+  when not defined(js):
+    try:
+      discard parseJson(a)
+    except JsonParsingError:
+      doAssert getCurrentExceptionMsg().contains("] expected")
diff --git a/tests/stdlib/tjsonexternproc.nim b/tests/stdlib/tjsonexternproc.nim
index ec90e580d..1091d72cd 100644
--- a/tests/stdlib/tjsonexternproc.nim
+++ b/tests/stdlib/tjsonexternproc.nim
@@ -1,5 +1,11 @@
+discard """
+output: '''
+{"data":[1]}
+'''
+"""
+
 # Test case for https://github.com/nim-lang/Nim/issues/6385
 
 import mjsonexternproc
 # import json
-foo(1)
\ No newline at end of file
+foo(1)
diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim
index f13d2e5cb..5a1b4b294 100644
--- a/tests/stdlib/tjsonmacro.nim
+++ b/tests/stdlib/tjsonmacro.nim
@@ -1,28 +1,45 @@
 discard """
-  file: "tjsonmacro.nim"
   output: ""
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
 """
-import json, strutils, options, tables
 
-when isMainModule:
+import json, strutils, options, tables
+import std/assertions
+
+# The definition of the `%` proc needs to be here, since the `% c` calls below
+# can only find our custom `%` proc for `Pix` if defined in global scope.
+type
+  Pix = tuple[x, y: uint8, ch: uint16]
+proc `%`(p: Pix): JsonNode =
+  result = %* { "x" : % p.x,
+                "y" : % p.y,
+                "ch" : % p.ch }
+
+proc testJson() =
   # Tests inspired by own use case (with some additional tests).
   # This should succeed.
   type
     Point[T] = object
       x, y: T
 
-    ReplayEventKind* = enum
+    ReplayEventKind = enum
       FoodAppeared, FoodEaten, DirectionChanged
 
-    ReplayEvent* = object
+    ReplayEvent = object
       time*: float
       case kind*: ReplayEventKind
       of FoodAppeared, FoodEaten:
         foodPos*: Point[float]
+        case subKind*: bool
+        of true:
+          it: int
+        of false:
+          ot: float
       of DirectionChanged:
         playerPos*: float
 
-    Replay* = ref object
+    Replay = ref object
       events*: seq[ReplayEvent]
       test: int
       test2: string
@@ -34,13 +51,15 @@ when isMainModule:
       ReplayEvent(
         time: 1.2345,
         kind: FoodEaten,
-        foodPos: Point[float](x: 5.0, y: 1.0)
+        foodPos: Point[float](x: 5.0, y: 1.0),
+        subKind: true,
+        it: 7
       )
     ],
     test: 18827361,
     test2: "hello world",
     test3: true,
-    testNil: nil
+    testNil: "nil"
   )
 
   let node = %x
@@ -53,7 +72,7 @@ when isMainModule:
   doAssert y.test == 18827361
   doAssert y.test2 == "hello world"
   doAssert y.test3
-  doAssert y.testNil.isNil
+  doAssert y.testNil == "nil"
 
   # Test for custom object variants (without an enum) and with an else branch.
   block:
@@ -91,7 +110,7 @@ when isMainModule:
     doAssert result.other == node["other"].getBiggestInt()
 
   # TODO: Test object variant with set in of branch.
-  # TODO: Should we support heterogenous arrays?
+  # TODO: Should we support heterogeneous arrays?
 
   # Tests that verify the error messages for invalid data.
   block:
@@ -242,7 +261,7 @@ when isMainModule:
         colors: array[2, BirdColor]
 
     var red = BirdColor(name: "red", rgb: [1.0, 0.0, 0.0])
-    var blue = Birdcolor(name: "blue", rgb: [0.0, 0.0, 1.0])
+    var blue = BirdColor(name: "blue", rgb: [0.0, 0.0, 1.0])
     var b = Bird(age: 3, height: 1.734, name: "bardo", colors: [red, blue])
     let jnode = %b
     let data = jnode.to(Bird)
@@ -278,24 +297,26 @@ when isMainModule:
     doAssert parsed.color == Red
 
   block:
-    type
-      Car = object
-        engine: tuple[name: string, capacity: float]
-        model: string
+    when not defined(js):
+      # disable on js because of #12492
+      type
+        Car = object
+          engine: tuple[name: string, capacity: float]
+          model: string
 
-    let j = """
-      {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"}
-    """
+      let j = """
+        {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"}
+      """
 
-    var i = 0
-    proc mulTest: JsonNode =
-      i.inc()
-      return parseJson(j)
+      var i = 0
+      proc mulTest(): JsonNode =
+        inc i
+        return parseJson(j)
 
-    let parsed = mulTest().to(Car)
-    doAssert parsed.engine.name == "V8"
+      let parsed = mulTest().to(Car)
+      doAssert parsed.engine.name == "V8"
 
-    doAssert i == 1
+      doAssert i == 1
 
   block:
     # Option[T] support!
@@ -337,7 +358,7 @@ when isMainModule:
         n2: Option[int]
         n3: Option[string]
         n4: Option[bool]
-        
+
     var j0 = parseJson("""{"n1": 1, "n2": null, "n3": null, "n4": null}""")
     let j0Deser = j0.to(Obj)
     doAssert j0Deser.n1 == 1
@@ -411,10 +432,219 @@ when isMainModule:
     doAssert dataDeser.a == 1
     doAssert dataDeser.f == 6
     doAssert dataDeser.i == 9.9'f32
-  
+
   # deserialize directly into a table
   block:
     let s = """{"a": 1, "b": 2}"""
     let t = parseJson(s).to(Table[string, int])
     doAssert t["a"] == 1
-    doAssert t["b"] == 2
\ No newline at end of file
+    doAssert t["b"] == 2
+
+  block:
+    # bug #8037
+    type
+      Apple = distinct string
+      String = distinct Apple
+      Email = distinct string
+      MyList = distinct seq[int]
+      MyYear = distinct Option[int]
+      MyTable = distinct Table[string, int]
+      MyArr = distinct array[3, float]
+      MyRef = ref object
+        name: string
+      MyObj = object
+        color: int
+      MyDistRef = distinct MyRef
+      MyDistObj = distinct MyObj
+      Toot = object
+        name*: String
+        email*: Email
+        list: MyList
+        year: MyYear
+        dict: MyTable
+        arr: MyArr
+        person: MyDistRef
+        distfruit: MyDistObj
+        dog: MyRef
+        fruit: MyObj
+        emails: seq[String]
+
+    var tJson = parseJson("""
+      {
+        "name":"Bongo",
+        "email":"bongo@bingo.com",
+        "list": [11,7,15],
+        "year": 1975,
+        "dict": {"a": 1, "b": 2},
+        "arr": [1.0, 2.0, 7.0],
+        "person": {"name": "boney"},
+        "dog": {"name": "honey"},
+        "fruit": {"color": 10},
+        "distfruit": {"color": 11},
+        "emails": ["abc", "123"]
+      }
+    """)
+
+    var t = to(tJson, Toot)
+    doAssert string(t.name) == "Bongo"
+    doAssert string(t.email) == "bongo@bingo.com"
+    doAssert seq[int](t.list) == @[11,7,15]
+    doAssert Option[int](t.year).get() == 1975
+    doAssert Table[string,int](t.dict)["a"] == 1
+    doAssert Table[string,int](t.dict)["b"] == 2
+    doAssert array[3, float](t.arr) == [1.0,2.0,7.0]
+
+    doAssert MyRef(t.person).name == "boney"
+    doAssert MyObj(t.distfruit).color == 11
+    doAssert t.dog.name == "honey"
+    doAssert t.fruit.color == 10
+    doAssert seq[string](t.emails) == @["abc", "123"]
+
+    block test_table:
+      var y = parseJson("""{"a": 1, "b": 2, "c": 3}""")
+      var u = y.to(MyTable)
+      var v = y.to(Table[string, int])
+      doAssert Table[string, int](u)["a"] == 1
+      doAssert Table[string, int](u)["b"] == 2
+      doAssert Table[string, int](u)["c"] == 3
+      doAssert v["a"] == 1
+
+    block primitive_string:
+      const kApple = "apple"
+      var u = newJString(kApple)
+      var v = u.to(Email)
+      var w = u.to(Apple)
+      var x = u.to(String)
+      doAssert string(v) == kApple
+      doAssert string(w) == kApple
+      doAssert string(x) == kApple
+
+    block test_option:
+      var u = newJInt(1137)
+      var v = u.to(MyYear)
+      var w = u.to(Option[int])
+      doAssert Option[int](v).get() == 1137
+      doAssert w.get() == 1137
+
+    block test_object:
+      var u = parseJson("""{"color": 987}""")
+      var v = u.to(MyObj)
+      var w = u.to(MyDistObj)
+      doAssert v.color == 987
+      doAssert MyObj(w).color == 987
+
+    block test_ref_object:
+      var u = parseJson("""{"name": "smith"}""")
+      var v = u.to(MyRef)
+      var w = u.to(MyDistRef)
+      doAssert v.name == "smith"
+      doAssert MyRef(w).name == "smith"
+
+  block:
+    # bug #12015
+    type
+      Cluster = object
+        works: tuple[x, y: uint8, ch: uint16] # working
+        fails: Pix # previously broken
+
+    let data = (x: 123'u8, y: 53'u8, ch: 1231'u16)
+    let c = Cluster(works: data, fails: data)
+    let cFromJson = (% c).to(Cluster)
+    doAssert c == cFromJson
+
+  block:
+    # bug related to #12015
+    type
+      PixInt = tuple[x, y, ch: int]
+      SomePix = Pix | PixInt
+      Cluster[T: SomePix] = seq[T]
+      ClusterObject[T: SomePix] = object
+        data: Cluster[T]
+      RecoEvent[T: SomePix] = object
+        cluster: seq[ClusterObject[T]]
+
+    let data = @[(x: 123'u8, y: 53'u8, ch: 1231'u16)]
+    var c = RecoEvent[Pix](cluster: @[ClusterObject[Pix](data: data)])
+    let cFromJson = (% c).to(RecoEvent[Pix])
+    doAssert c == cFromJson
+
+
+  block:
+    # ref objects with cycles.
+    type
+      Misdirection = object
+        cycle: Cycle
+
+      Cycle = ref object
+        foo: string
+        cycle: Misdirection
+
+    let data = """
+      {"cycle": null}
+    """
+
+    let dataParsed = parseJson(data)
+    let dataDeser = to(dataParsed, Misdirection)
+
+  block:
+    # ref object from #12316
+    type
+      Foo = ref Bar
+      Bar = object
+
+    discard "null".parseJson.to Foo
+
+  block:
+    # named array #12289
+    type Vec = array[2, int]
+    let arr = "[1,2]".parseJson.to Vec
+    doAssert arr == [1,2]
+
+  block:
+    # test error message in exception
+
+    type
+      MyType = object
+        otherMember: string
+        member: MySubType
+
+      MySubType = object
+        somethingElse: string
+        list: seq[MyData]
+
+      MyData = object
+        value: int
+
+    let jsonNode = parseJson("""
+      {
+        "otherMember": "otherValue",
+        "member": {
+          "somethingElse": "something",
+          "list": [{"value": 1}, {"value": 2}, {}]
+        }
+      }
+    """)
+
+    try:
+      let tmp = jsonNode.to(MyType)
+      doAssert false, "this should be unreachable"
+    except KeyError:
+      doAssert getCurrentExceptionMsg().contains ".member.list[2].value"
+
+  block:
+    # Enum indexed array test
+    type Test = enum
+      one, two, three, four, five
+    let a = [
+      one: 300,
+      two: 20,
+      three: 10,
+      four: 0,
+      five: -10
+    ]
+    doAssert (%* a).to(a.typeof) == a
+
+
+testJson()
+static:
+  testJson()
diff --git a/tests/stdlib/tjsonmacro_reject.nim b/tests/stdlib/tjsonmacro_reject.nim
index 00506449f..ada365d7d 100644
--- a/tests/stdlib/tjsonmacro_reject.nim
+++ b/tests/stdlib/tjsonmacro_reject.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "Use a named tuple instead of: (string, float)"
   file: "tjsonmacro_reject.nim"
   line: 11
-  errormsg: "Use a named tuple instead of: (string, float)"
 """
 
 import json
@@ -15,4 +15,4 @@ let j = """
   {"engine": {"name": "V8", "capacity": 5.5}, model: "Skyline"}
 """
 let parsed = parseJson(j)
-echo(to(parsed, Car))
\ No newline at end of file
+echo(to(parsed, Car))
diff --git a/tests/stdlib/tjsonmacro_reject2.nim b/tests/stdlib/tjsonmacro_reject2.nim
deleted file mode 100644
index b01153553..000000000
--- a/tests/stdlib/tjsonmacro_reject2.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-discard """
-  file: "tjsonmacro_reject2.nim"
-  line: 10
-  errormsg: "The `to` macro does not support ref objects with cycles."
-"""
-import json
-
-type
-  Misdirection = object
-    cycle: Cycle
-
-  Cycle = ref object
-    foo: string
-    cycle: Misdirection
-
-let data = """
-  {"cycle": null}
-"""
-
-let dataParsed = parseJson(data)
-let dataDeser = to(dataParsed, Cycle)
\ No newline at end of file
diff --git a/tests/stdlib/tjsontestsuite.nim b/tests/stdlib/tjsontestsuite.nim
index 06f783a73..db31963fd 100644
--- a/tests/stdlib/tjsontestsuite.nim
+++ b/tests/stdlib/tjsontestsuite.nim
@@ -1,3 +1,7 @@
+discard """
+disabled: true
+"""
+
 ## JSON tests based on https://github.com/nst/JSONTestSuite
 
 import unittest,
diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim
new file mode 100644
index 000000000..9acf4c9e5
--- /dev/null
+++ b/tests/stdlib/tjsonutils.nim
@@ -0,0 +1,476 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/jsonutils
+import std/json
+from std/math import isNaN, signbit
+from std/fenv import epsilon
+from stdtest/testutils import whenRuntimeJs
+import std/[assertions, objectdollar]
+
+proc testRoundtrip[T](t: T, expected: string) =
+  # checks that `T => json => T2 => json2` is such that json2 = json
+  let j = t.toJson
+  doAssert $j == expected, "\n" & $j & "\n" & expected
+  doAssert j.jsonTo(T).toJson == j
+  var t2: T
+  t2.fromJson(j)
+  doAssert t2.toJson == j
+
+proc testRoundtripVal[T](t: T, expected: string) =
+  # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T`
+  # note that this isn't always possible, e.g. for pointer-like types.
+  let j = t.toJson
+  let j2 = $j
+  doAssert j2 == expected, j2
+  let j3 = j2.parseJson
+  let t2 = j3.jsonTo(T)
+  doAssert t2 == t
+  doAssert $t2.toJson == j2 # still needed, because -0.0 = 0.0 but their json representation differs
+
+import tables, sets, algorithm, sequtils, options, strtabs
+from strutils import contains
+
+type Foo = ref object
+  id: int
+
+proc `==`(a, b: Foo): bool =
+  a.id == b.id
+
+type MyEnum = enum me0, me1 = "me1Alt", me2, me3, me4
+
+proc `$`(a: MyEnum): string =
+  # putting this here pending https://github.com/nim-lang/Nim/issues/13747
+  if a == me2: "me2Modif"
+  else: system.`$`(a)
+
+template fn() =
+  block: # toJson, jsonTo
+    type Foo = distinct float
+    testRoundtrip('x', """120""")
+    when not defined(js):
+      testRoundtrip(cast[pointer](12345)): """12345"""
+      when nimvm:
+        discard
+        # bugs:
+        # Error: unhandled exception: 'intVal' is not accessible using discriminant 'kind' of type 'TNode' [
+        # Error: VM does not support 'cast' from tyNil to tyPointer
+      else:
+        testRoundtrip(pointer(nil)): """0"""
+        testRoundtrip(cast[pointer](nil)): """0"""
+
+    # refs bug #9423
+    testRoundtrip(Foo(1.5)): """1.5"""
+
+  block: # OrderedTable
+    testRoundtrip({"z": "Z", "y": "Y"}.toOrderedTable): """{"z":"Z","y":"Y"}"""
+    doAssert toJson({"z": 10, "": 11}.newTable).`$`.contains """"":11""" # allows hash to change
+    testRoundtrip({"z".cstring: 1, "".cstring: 2}.toOrderedTable): """{"z":1,"":2}"""
+    testRoundtrip({"z": (f1: 'f'), }.toTable): """{"z":{"f1":102}}"""
+
+  block: # StringTable
+    testRoundtrip({"name": "John", "city": "Monaco"}.newStringTable): """{"mode":"modeCaseSensitive","table":{"city":"Monaco","name":"John"}}"""
+
+  block: # complex example
+    let t = {"z": "Z", "y": "Y"}.newStringTable
+    type A = ref object
+      a1: string
+    let a = (1.1, "fo", 'x', @[10,11], [true, false], [t,newStringTable()], [0'i8,3'i8], -4'i16, (foo: 0.5'f32, bar: A(a1: "abc"), bar2: A.default, cstring1: "foo", cstring2: "", cstring3: cstring(nil)))
+    testRoundtrip(a):
+      """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null,"cstring1":"foo","cstring2":"","cstring3":null}]"""
+
+  block:
+    # edge case when user defined `==` doesn't handle `nil` well, e.g.:
+    # https://github.com/nim-lang/nimble/blob/63695f490728e3935692c29f3d71944d83bb1e83/src/nimblepkg/version.nim#L105
+    testRoundtrip(@[Foo(id: 10), nil]): """[{"id":10},null]"""
+
+  block: # enum
+    type Foo = enum f1, f2, f3, f4, f5
+    type Bar = enum b1, b2, b3, b4
+    let a = [f2: b2, f3: b3, f4: b4]
+    doAssert b2.ord == 1 # explains the `1`
+    testRoundtrip(a): """[1,2,3]"""
+
+  block: # JsonNode
+    let a = ((1, 2.5, "abc").toJson, (3, 4.5, "foo"))
+    testRoundtripVal(a): """[[1,2.5,"abc"],[3,4.5,"foo"]]"""
+
+    block:
+      template toInt(a): untyped = cast[int](a)
+
+      let a = 3.toJson
+      let b = (a, a)
+
+      let c1 = b.toJson
+      doAssert c1[0].toInt == a.toInt
+      doAssert c1[1].toInt == a.toInt
+
+      let c2 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsCopy))
+      doAssert c2[0].toInt != a.toInt
+      doAssert c2[1].toInt != c2[0].toInt
+      doAssert c2[1] == c2[0]
+
+      let c3 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsObject))
+      doAssert $c3 == """[{"isUnquoted":false,"kind":2,"num":3},{"isUnquoted":false,"kind":2,"num":3}]"""
+
+  block: # ToJsonOptions
+    let a = (me1, me2)
+    doAssert $a.toJson() == "[1,2]"
+    doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumSymbol)) == """["me1","me2"]"""
+    doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumString)) == """["me1Alt","me2Modif"]"""
+
+  block: # set
+    type Foo = enum f1, f2, f3, f4, f5
+    type Goo = enum g1 = 10, g2 = 15, g3 = 17, g4
+    let a = ({f1, f3}, {1'u8, 7'u8}, {'0'..'9'}, {123'u16, 456, 789, 1121, 1122, 1542}, {g2, g3})
+    testRoundtrip(a): """[[0,2],[1,7],[48,49,50,51,52,53,54,55,56,57],[123,456,789,1121,1122,1542],[15,17]]"""
+
+  block: # bug #17383
+    block:
+      let a = (int32.high, uint32.high)
+      testRoundtrip(a): "[2147483647,4294967295]"
+    when int.sizeof > 4:
+      block:
+        let a = (int64.high, uint64.high)
+        testRoundtrip(a): "[9223372036854775807,18446744073709551615]"
+    block:
+      let a = (int.high, uint.high)
+      when int.sizeof == 4:
+        testRoundtrip(a): "[2147483647,4294967295]"
+      else:
+        testRoundtrip(a): "[9223372036854775807,18446744073709551615]"
+
+  block: # bug #18007
+    testRoundtrip((NaN, Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+    testRoundtrip((float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+    testRoundtripVal((Inf, -Inf, 0.0, -0.0, 1.0)): """["inf","-inf",0.0,-0.0,1.0]"""
+    doAssert ($NaN.toJson).parseJson.jsonTo(float).isNaN
+
+  block: # bug #18009; unfixable unless we change parseJson (which would have overhead),
+         # but at least we can guarantee that the distinction between 0.0 and -0.0 is preserved.
+    let a = (0, 0.0, -0.0, 0.5, 1, 1.0)
+    testRoundtripVal(a): "[0,0.0,-0.0,0.5,1,1.0]"
+    let a2 = $($a.toJson).parseJson
+    whenRuntimeJs:
+      doAssert a2 == "[0,0,-0.0,0.5,1,1]"
+    do:
+      doAssert a2 == "[0,0.0,-0.0,0.5,1,1.0]"
+    let b = a2.parseJson.jsonTo(type(a))
+    doAssert not b[1].signbit
+    doAssert b[2].signbit
+    doAssert not b[3].signbit
+
+  block: # bug #15397, bug #13196
+    let a = 0.1
+    let x = 0.12345678901234567890123456789
+    let b = (a + 0.2, 0.3, x)
+    testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]"
+
+    testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568"
+    testRoundtripVal(epsilon(float64)): "2.220446049250313e-16"
+    testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002"
+
+  block: # case object
+    type Foo = object
+      x0: float
+      case t1: bool
+      of true: z1: int8
+      of false: z2: uint16
+      x1: string
+    testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}"""
+    testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+    type PFoo = ref Foo
+    testRoundtrip(PFoo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+
+  block: # ref case object
+    type Foo = ref object
+      x0: float
+      case t1: bool
+      of true: z1: int8
+      of false: z2: uint16
+      x1: string
+    testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}"""
+    testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+
+  block: # generic case object
+    type Foo[T] = ref object
+      x0: float
+      case t1: bool
+      of true: z1: int8
+      of false: z2: uint16
+      x1: string
+    testRoundtrip(Foo[float](t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}"""
+    testRoundtrip(Foo[int](x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+    # sanity check: nesting inside a tuple
+    testRoundtrip((Foo[int](x0: 1.5, t1: false, z2: 6), "foo")): """[{"x0":1.5,"t1":false,"z2":6,"x1":""},"foo"]"""
+
+  block: # case object: 2 discriminants, `when` branch, range discriminant
+    type Foo[T] = object
+      case t1: bool
+      of true:
+        z1: int8
+      of false:
+        z2: uint16
+      when T is float:
+        case t2: range[0..3]
+        of 0: z3: int8
+        of 2,3: z4: uint16
+        else: discard
+    testRoundtrip(Foo[float](t1: true, z1: 5, t2: 3, z4: 12)): """{"t1":true,"z1":5,"t2":3,"z4":12}"""
+    testRoundtrip(Foo[int](t1: false, z2: 7)): """{"t1":false,"z2":7}"""
+    # pending https://github.com/nim-lang/Nim/issues/14698, test with `type Foo[T] = ref object`
+
+  block: # bug: pass opt params in fromJson
+    type Foo = object
+      a: int
+      b: string
+      c: float
+    type Bar = object
+      foo: Foo
+      boo: string
+    var f: seq[Foo]
+    try:
+      fromJson(f, parseJson """[{"b": "bbb"}]""")
+      doAssert false
+    except ValueError:
+      doAssert true
+    fromJson(f, parseJson """[{"b": "bbb"}]""", Joptions(allowExtraKeys: true, allowMissingKeys: true))
+    doAssert f == @[Foo(a: 0, b: "bbb", c: 0.0)]
+    var b: Bar
+    fromJson(b, parseJson """{"foo": {"b": "bbb"}}""", Joptions(allowExtraKeys: true, allowMissingKeys: true))
+    doAssert b == Bar(foo: Foo(a: 0, b: "bbb", c: 0.0))
+    block: # jsonTo with `opt`
+      let b2 = """{"foo": {"b": "bbb"}}""".parseJson.jsonTo(Bar,  Joptions(allowExtraKeys: true, allowMissingKeys: true))
+      doAssert b2 == Bar(foo: Foo(a: 0, b: "bbb", c: 0.0))
+
+  block testHashSet:
+    testRoundtrip(HashSet[string]()): "[]"
+    testRoundtrip([""].toHashSet): """[""]"""
+    testRoundtrip(["one"].toHashSet): """["one"]"""
+
+    var s: HashSet[string]
+    fromJson(s, parseJson("""["one","two"]"""))
+    doAssert s == ["one", "two"].toHashSet
+
+    let jsonNode = toJson(s)
+    doAssert jsonNode.elems.mapIt(it.str).sorted == @["one", "two"]
+
+  block testOrderedSet:
+    testRoundtrip(["one", "two", "three"].toOrderedSet):
+      """["one","two","three"]"""
+
+  block testOption:
+    testRoundtrip(some("test")): "\"test\""
+    testRoundtrip(none[string]()): "null"
+    testRoundtrip(some(42)): "42"
+    testRoundtrip(none[int]()): "null"
+
+  block testStrtabs:
+    testRoundtrip(newStringTable(modeStyleInsensitive)):
+      """{"mode":"modeStyleInsensitive","table":{}}"""
+
+    testRoundtrip(
+      newStringTable("name", "John", "surname", "Doe", modeCaseSensitive)):
+        """{"mode":"modeCaseSensitive","table":{"name":"John","surname":"Doe"}}"""
+
+  block testJoptions:
+    type
+      AboutLifeUniverseAndEverythingElse = object
+        question: string
+        answer: int
+
+    block testExceptionOnExtraKeys:
+      var guide: AboutLifeUniverseAndEverythingElse
+      let json = parseJson(
+        """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""")
+      doAssertRaises ValueError, fromJson(guide, json)
+      doAssertRaises ValueError,
+                     fromJson(guide, json, Joptions(allowMissingKeys: true))
+
+      type
+        A = object
+          a1,a2,a3: int
+      var a: A
+      let j = parseJson("""{"a3": 1, "a4": 2}""")
+      doAssertRaises ValueError,
+                     fromJson(a, j, Joptions(allowMissingKeys: true))
+
+    block testExceptionOnMissingKeys:
+      var guide: AboutLifeUniverseAndEverythingElse
+      let json = parseJson("""{"answer":42}""")
+      doAssertRaises ValueError, fromJson(guide, json)
+      doAssertRaises ValueError,
+                     fromJson(guide, json, Joptions(allowExtraKeys: true))
+
+    block testAllowExtraKeys:
+      var guide: AboutLifeUniverseAndEverythingElse
+      let json = parseJson(
+        """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""")
+      fromJson(guide, json, Joptions(allowExtraKeys: true))
+      doAssert guide == AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 42)
+
+      block refObject: #bug 17986
+        type A = ref object
+          case is_a: bool
+          of true:
+            a: int
+          else:
+            b: int
+
+        var a = A()
+        fromJson(a, """{"is_a": true, "a":1, "extra_key": 1}""".parseJson, Joptions(allowExtraKeys: true))
+        doAssert $a[] == "(is_a: true, a: 1)"
+
+    block testAllowMissingKeys:
+      var guide = AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 54)
+      let json = parseJson("""{"answer":42}""")
+      fromJson(guide, json, Joptions(allowMissingKeys: true))
+      doAssert guide == AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 42)
+
+    block testAllowExtraAndMissingKeys:
+      var guide = AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 54)
+      let json = parseJson(
+        """{"answer":42,"author":"Douglas Adams"}""")
+      fromJson(guide, json, Joptions(
+        allowExtraKeys: true, allowMissingKeys: true))
+      doAssert guide == AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 42)
+
+    type
+      Foo = object
+        a: array[2, string]
+        case b: bool
+        of false: f: float
+        of true: t: tuple[i: int, s: string]
+        case c: range[0 .. 2]
+        of 0: c0: int
+        of 1: c1: float
+        of 2: c2: string
+
+    block testExceptionOnMissingDiscriminantKey:
+      var foo: Foo
+      let json = parseJson("""{"a":["one","two"]}""")
+      doAssertRaises ValueError, fromJson(foo, json)
+
+    block testDoNotResetMissingFieldsWhenHaveDiscriminantKey:
+      var foo = Foo(a: ["one", "two"], b: true, t: (i: 42, s: "s"),
+                    c: 0, c0: 1)
+      let json = parseJson("""{"b":true,"c":2}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true))
+      doAssert foo.a == ["one", "two"]
+      doAssert foo.b
+      doAssert foo.t == (i: 42, s: "s")
+      doAssert foo.c == 2
+      doAssert foo.c2 == ""
+
+    block testAllowMissingDiscriminantKeys:
+      var foo: Foo
+      let json = parseJson("""{"a":["one","two"],"c":1,"c1":3.14159}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true))
+      doAssert foo.a == ["one", "two"]
+      doAssert not foo.b
+      doAssert foo.f == 0.0
+      doAssert foo.c == 1
+      doAssert foo.c1 == 3.14159
+
+    block testExceptionOnWrongDiscirminatBranchInJson:
+      var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42)
+      let json = parseJson("""{"c2": "hello"}""")
+      doAssertRaises ValueError,
+                     fromJson(foo, json, Joptions(allowMissingKeys: true))
+      # Test that the original fields are not reset.
+      doAssert not foo.b
+      doAssert foo.f == 3.14159
+      doAssert foo.c == 0
+      doAssert foo.c0 == 42
+
+    block testNoExceptionOnRightDiscriminantBranchInJson:
+      var foo = Foo(b: false, f: 0, c:1, c1: 0)
+      let json = parseJson("""{"f":2.71828,"c1": 3.14159}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true))
+      doAssert not foo.b
+      doAssert foo.f == 2.71828
+      doAssert foo.c == 1
+      doAssert foo.c1 == 3.14159
+
+    block testAllowExtraKeysInJsonOnWrongDisciriminatBranch:
+      var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42)
+      let json = parseJson("""{"c2": "hello"}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true,
+                                   allowExtraKeys: true))
+      # Test that the original fields are not reset.
+      doAssert not foo.b
+      doAssert foo.f == 3.14159
+      doAssert foo.c == 0
+      doAssert foo.c0 == 42
+
+
+    block testInvalidTupleLength:
+      let json = parseJson("[0]")
+      # Should raise ValueError instead of index error
+      doAssertRaises(ValueError):
+        discard json.jsonTo((int, int))
+
+    type
+      InnerEnum = enum
+        A
+        B
+        C
+      InnerObject = object
+        x: string
+        y: InnerEnum
+
+    block testOptionsArePassedWhenDeserialising:
+      let json = parseJson("""{"x": "hello"}""")
+      let inner = json.jsonTo(Option[InnerObject], Joptions(allowMissingKeys: true))
+      doAssert inner.isSome()
+      doAssert inner.get().x == "hello"
+      doAssert inner.get().y == A
+
+    block testOptionsArePassedWhenSerialising:
+      let inner = some InnerObject(x: "hello", y: A)
+      let json = inner.toJson(ToJsonOptions(enumMode: joptEnumSymbol))
+      doAssert $json == """{"x":"hello","y":"A"}"""
+
+    block: # bug #21638
+      type Something = object
+
+      doAssert "{}".parseJson.jsonTo(Something) == Something()
+
+    when false:
+      ## TODO: Implement support for nested variant objects allowing the tests
+      ## bellow to pass.
+      block testNestedVariantObjects:
+        type
+          Variant = object
+            case b: bool
+            of false:
+              case bf: bool
+              of false: bff: int
+              of true: bft: float
+            of true:
+              case bt: bool
+              of false: btf: string
+              of true: btt: char
+
+        testRoundtrip(Variant(b: false, bf: false, bff: 42)):
+          """{"b": false, "bf": false, "bff": 42}"""
+        testRoundtrip(Variant(b: false, bf: true, bft: 3.14159)):
+          """{"b": false, "bf": true, "bft": 3.14159}"""
+        testRoundtrip(Variant(b: true, bt: false, btf: "test")):
+          """{"b": true, "bt": false, "btf": "test"}"""
+        testRoundtrip(Variant(b: true, bt: true, btt: 'c')):
+          """{"b": true, "bt": true, "btt": "c"}"""
+
+        # TODO: Add additional tests with missing and extra JSON keys, both when
+        # allowed and forbidden analogous to the tests for the not nested
+        # variant objects.
+
+static: fn()
+fn()
diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim
index 37e73c53f..5993278c7 100644
--- a/tests/stdlib/tlists.nim
+++ b/tests/stdlib/tlists.nim
@@ -1,66 +1,277 @@
 discard """
-  output: '''true'''
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
 """
 
-import lists
+import std/[lists, sequtils]
+import std/assertions
 
 const
   data = [1, 2, 3, 4, 5, 6]
 
-block SinglyLinkedListTest1:
-  var L: TSinglyLinkedList[int]
-  for d in items(data): L.prepend(d)
-  assert($L == "[6, 5, 4, 3, 2, 1]")
 
-  assert(4 in L)
+template main =
+  block SinglyLinkedListTest1:
+    var L: SinglyLinkedList[int]
+    for d in items(data): L.prepend(d)
+    for d in items(data): L.add(d)
+    doAssert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]")
 
-block SinglyLinkedListTest2:
-  var L: TSinglyLinkedList[string]
-  for d in items(data): L.prepend($d)
-  assert($L == """["6", "5", "4", "3", "2", "1"]""")
+    doAssert(4 in L)
 
-  assert("4" in L)
+  block SinglyLinkedListTest2:
+    var L: SinglyLinkedList[string]
+    for d in items(data): L.prepend($d)
+    doAssert($L == """["6", "5", "4", "3", "2", "1"]""")
 
+    doAssert("4" in L)
 
-block DoublyLinkedListTest1:
-  var L: TDoublyLinkedList[int]
-  for d in items(data): L.prepend(d)
-  for d in items(data): L.append(d)
-  L.remove(L.find(1))
-  assert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]")
 
-  assert(4 in L)
+  block DoublyLinkedListTest1:
+    var L: DoublyLinkedList[int]
+    for d in items(data): L.prepend(d)
+    for d in items(data): L.add(d)
+    L.remove(L.find(1))
+    doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]")
 
-block SinglyLinkedRingTest1:
-  var L: TSinglyLinkedRing[int]
-  L.prepend(4)
-  assert($L == "[4]")
-  L.prepend(4)
+    doAssert(4 in L)
 
-  assert($L == "[4, 4]")
-  assert(4 in L)
+  block SinglyLinkedRingTest1:
+    var L: SinglyLinkedRing[int]
+    L.prepend(4)
+    doAssert($L == "[4]")
+    L.prepend(4)
 
+    doAssert($L == "[4, 4]")
+    doAssert(4 in L)
 
-block DoublyLinkedRingTest1:
-  var L: TDoublyLinkedRing[int]
-  L.prepend(4)
-  assert($L == "[4]")
-  L.prepend(4)
 
-  assert($L == "[4, 4]")
-  assert(4 in L)
+  block DoublyLinkedRingTest1:
+    var L: DoublyLinkedRing[int]
+    L.prepend(4)
+    doAssert($L == "[4]")
+    L.prepend(4)
 
-  L.append(3)
-  L.append(5)
-  assert($L == "[4, 4, 3, 5]")
+    doAssert($L == "[4, 4]")
+    doAssert(4 in L)
 
-  L.remove(L.find(3))
-  L.remove(L.find(5))
-  L.remove(L.find(4))
-  L.remove(L.find(4))
-  assert($L == "[]")
-  assert(4 notin L)
+    L.add(3)
+    L.add(5)
+    doAssert($L == "[4, 4, 3, 5]")
 
+    L.remove(L.find(3))
+    L.remove(L.find(5))
+    L.remove(L.find(4))
+    L.remove(L.find(4))
+    doAssert($L == "[]")
+    doAssert(4 notin L)
 
-echo "true"
+  block tlistsToString:
+    block:
+      var l = initDoublyLinkedList[int]()
+      l.add(1)
+      l.add(2)
+      l.add(3)
+      doAssert $l == "[1, 2, 3]"
+    block:
+      var l = initDoublyLinkedList[string]()
+      l.add("1")
+      l.add("2")
+      l.add("3")
+      doAssert $l == """["1", "2", "3"]"""
+    block:
+      var l = initDoublyLinkedList[char]()
+      l.add('1')
+      l.add('2')
+      l.add('3')
+      doAssert $l == """['1', '2', '3']"""
 
+  # Copied here until it is merged into sequtils
+  template take(a: untyped, max: int): untyped =
+    type T = typeof(block: (for ai in a: ai))
+    var ret: seq[T]
+    var i = 0
+    if max > 0:
+      for ai in a:
+        ret.add ai
+        i.inc
+        if i >= max: break
+    ret
+
+  template testCommon(initList, toList) =
+
+    block: # toSinglyLinkedList, toDoublyLinkedList
+      let l = seq[int].default
+      doAssert l.toList.toSeq == []
+      doAssert [1].toList.toSeq == [1]
+      doAssert [1, 2, 3].toList.toSeq == [1, 2, 3]
+
+    block copy:
+      doAssert array[0, int].default.toList.copy.toSeq == []
+      doAssert [1].toList.copy.toSeq == [1]
+      doAssert [1, 2].toList.copy.toSeq == [1, 2]
+      doAssert [1, 2, 3].toList.copy.toSeq == [1, 2, 3]
+      type Foo = ref object
+        x: int
+      var f0 = Foo(x: 0)
+      let f1 = Foo(x: 1)
+      var a = [f0].toList
+      var b = a.copy
+      b.add f1
+      doAssert a.toSeq == [f0]
+      doAssert b.toSeq == [f0, f1]
+      f0.x = 42
+      doAssert a.head.value.x == 42
+      doAssert b.head.value.x == 42
+
+    block: # add, addMoved
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l0.add l3
+        l1.add l3
+        l2.addMoved l3
+        doAssert l0.toSeq == [4, 5, 6]
+        doAssert l1.toSeq == [1, 4, 5, 6]
+        doAssert l2.toSeq == [2, 3, 4, 5, 6]
+        doAssert l3.toSeq == []
+        l2.add l3 # re-adding l3 that was destroyed is now a no-op
+        doAssert l2.toSeq == [2, 3, 4, 5, 6]
+        doAssert l3.toSeq == []
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l3.addMoved l0
+        l2.addMoved l1
+        doAssert l3.toSeq == [4, 5, 6]
+        doAssert l2.toSeq == [2, 3, 1]
+        l3.add l0
+        doAssert l3.toSeq == [4, 5, 6]
+      block:
+        var c = [0, 1].toList
+        c.addMoved c
+        doAssert c.take(6) == [0, 1, 0, 1, 0, 1]
+
+    block: # prepend, prependMoved
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l0.prepend l3
+        l1.prepend l3
+        doAssert l3.toSeq == [4, 5, 6]
+        l2.prependMoved l3
+        doAssert l0.toSeq == [4, 5, 6]
+        doAssert l1.toSeq == [4, 5, 6, 1]
+        doAssert l2.toSeq == [4, 5, 6, 2, 3]
+        doAssert l3.toSeq == []
+        l2.prepend l3 # re-prepending l3 that was destroyed is now a no-op
+        doAssert l2.toSeq == [4, 5, 6, 2, 3]
+        doAssert l3.toSeq == []
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l3.prependMoved l0
+        l2.prependMoved l1
+        doAssert l3.toSeq == [4, 5, 6]
+        doAssert l2.toSeq == [1, 2, 3]
+        l3.prepend l0
+        doAssert l3.toSeq == [4, 5, 6]
+      block:
+        var c = [0, 1].toList
+        c.prependMoved c
+        doAssert c.take(6) == [0, 1, 0, 1, 0, 1]
+
+    block remove:
+      var l = [0, 1, 2, 3].toList
+      let
+        l0 = l.head
+        l1 = l0.next
+        l2 = l1.next
+        l3 = l2.next
+      l.remove l0
+      doAssert l.toSeq == [1, 2, 3]
+      l.remove l2
+      doAssert l.toSeq == [1, 3]
+      l.remove l2
+      doAssert l.toSeq == [1, 3]
+      l.remove l3
+      doAssert l.toSeq == [1]
+      l.remove l1
+      doAssert l.toSeq == []
+      # Cycle preservation
+      var a = [10, 11, 12].toList
+      a.addMoved a
+      doAssert a.take(6) == @[10, 11, 12, 10, 11, 12]
+      a.remove a.head.next
+      doAssert a.take(6) == @[10, 12, 10, 12, 10, 12]
+      a.remove a.head
+      doAssert a.take(6) == @[12, 12, 12, 12, 12, 12]
+
+  testCommon initSinglyLinkedList, toSinglyLinkedList
+  testCommon initDoublyLinkedList, toDoublyLinkedList
+
+  block remove: # return value check
+    var l = [0, 1, 2, 3].toSinglyLinkedList
+    let n = l.head.next.next
+    doAssert l.remove(n) == true
+    doAssert l.toSeq == [0, 1, 3]
+    doAssert l.remove(n) == false
+    doAssert l.toSeq == [0, 1, 3]
+    doAssert l.remove(l.head) == true
+    doAssert l.toSeq == [1, 3]
+    doAssert l.remove(l.head.next) == true
+    doAssert l.toSeq == [1]
+    doAssert l.remove(l.head) == true
+    doAssert l.toSeq == []
+  
+  block issue19297: # add (appends a shallow copy)
+    var a: SinglyLinkedList[int]
+    var b: SinglyLinkedList[int]
+
+    doAssert a.toSeq == @[]
+    a.add(1)
+    doAssert a.toSeq == @[1]
+    a.add(b)
+    doAssert a.toSeq == @[1]
+    a.add(2)
+    doAssert a.toSeq == @[1, 2]
+  
+  block issue19314: # add (appends a shallow copy)
+    var a: DoublyLinkedList[int]
+    var b: DoublyLinkedList[int]
+
+    doAssert a.toSeq == @[]
+    a.add(1)
+    doAssert a.toSeq == @[1]
+    a.add(b)
+    doAssert a.toSeq == @[1]
+    a.add(2)
+    doAssert a.toSeq == @[1, 2]
+
+  block RemoveLastNodeFromSinglyLinkedList:
+    var list = initSinglyLinkedList[string]()
+    let n1 = newSinglyLinkedNode("sonic")
+    let n2 = newSinglyLinkedNode("the")
+    let n3 = newSinglyLinkedNode("tiger")
+    let n4 = newSinglyLinkedNode("hedgehog")
+    list.add(n1)
+    list.add(n2)
+    list.add(n3)
+    list.remove(n3)
+    list.add(n4)
+    doAssert list.toSeq == @["sonic", "the", "hedgehog"]
+
+static: main()
+main()
diff --git a/tests/stdlib/tlocks.nim b/tests/stdlib/tlocks.nim
index e567cfde8..1c5f67119 100644
--- a/tests/stdlib/tlocks.nim
+++ b/tests/stdlib/tlocks.nim
@@ -1,10 +1,11 @@
 discard """
-  output: '''3'''
-  cmd: "nim $target --threads:on $options $file"
+  targets: "c cpp js"
+  matrix: "--mm:refc; --mm:orc"
 """
 
 #bug #6049
 import uselocks
+import std/assertions
 
 var m = createMyType[int]()
-echo $m.use()
+doAssert m.use() == 3
diff --git a/tests/stdlib/tlwip.nim b/tests/stdlib/tlwip.nim
new file mode 100644
index 000000000..fc53be592
--- /dev/null
+++ b/tests/stdlib/tlwip.nim
@@ -0,0 +1,30 @@
+discard """
+  targets: "c"
+  cmd: "nim $target --compileOnly --os:freertos --gc:arc $options $file"
+  disabled: "bsd"
+  disabled: "windows"
+  action: compile
+"""
+
+# Note:
+#   This file tests FreeRTOS/LwIP cross-compilation on UNIX platforms
+#   Windows should run when compiled with esp-idf, however I'm not
+#   sure how to test for only compilation on Windows without running 
+#   a test exe
+# 
+# Note:
+#   disabling *BSDs since they're not playing well with `gcc`
+
+import net
+import asynchttpserver, asyncdispatch
+
+proc cb*(req: Request) {.async.} =
+  await req.respond(Http200, "Hello World")
+
+proc run_http_server*() {.exportc.} =
+  echo "starting http server"
+  var server = newAsyncHttpServer()
+
+  waitFor server.serve(Port(8181), cb)
+
+echo("ok")
diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim
new file mode 100644
index 000000000..06a9a9c27
--- /dev/null
+++ b/tests/stdlib/tmacros.nim
@@ -0,0 +1,349 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+#[
+xxx macros tests need to be reorganized to makes sure each API is tested once
+See also:
+  tests/macros/tdumpast.nim for treeRepr + friends
+]#
+
+import std/macros
+import std/assertions
+
+block: # hasArgOfName
+  macro m(u: untyped): untyped =
+    for name in ["s","i","j","k","b","xs","ys"]:
+      doAssert hasArgOfName(params u,name)
+    doAssert not hasArgOfName(params u,"nonexistent")
+
+  proc p(s: string; i,j,k: int; b: bool; xs,ys: seq[int] = @[]) {.m.} = discard
+
+block: # bug #17454
+  proc f(v: NimNode): string {.raises: [].} = $v
+
+block: # unpackVarargs
+  block:
+    proc bar1(a: varargs[int]): string =
+      for ai in a: result.add " " & $ai
+    proc bar2(a: varargs[int]) =
+      let s1 = bar1(a)
+      let s2 = unpackVarargs(bar1, a) # `unpackVarargs` makes no difference here
+      doAssert s1 == s2
+    bar2(1, 2, 3)
+    bar2(1)
+    bar2()
+
+  block:
+    template call1(fun: typed; args: varargs[untyped]): untyped =
+      unpackVarargs(fun, args)
+    template call2(fun: typed; args: varargs[untyped]): untyped =
+      # fun(args) # works except for last case with empty `args`, pending bug #9996
+      when varargsLen(args) > 0: fun(args)
+      else: fun()
+
+    proc fn1(a = 0, b = 1) = discard (a, b)
+
+    call1(fn1)
+    call1(fn1, 10)
+    call1(fn1, 10, 11)
+
+    call2(fn1)
+    call2(fn1, 10)
+    call2(fn1, 10, 11)
+
+  block:
+    template call1(fun: typed; args: varargs[typed]): untyped =
+      unpackVarargs(fun, args)
+    template call2(fun: typed; args: varargs[typed]): untyped =
+      # xxx this would give a confusing error message:
+      # required type for a: varargs[typed] [varargs] but expression '[10]' is of type: varargs[typed] [varargs]
+      when varargsLen(args) > 0: fun(args)
+      else: fun()
+    macro toString(a: varargs[typed, `$`]): string =
+      var msg = genSym(nskVar, "msg")
+      result = newStmtList()
+      result.add quote do:
+        var `msg` = ""
+      for ai in a:
+        result.add quote do: `msg`.add $`ai`
+      result.add quote do: `msg`
+    doAssert call1(toString) == ""
+    doAssert call1(toString, 10) == "10"
+    doAssert call1(toString, 10, 11) == "1011"
+
+block: # SameType
+  type
+    A = int
+    B = distinct int
+    C = object
+    Generic[T, Y] = object
+  macro isSameType(a, b: typed): untyped =
+    newLit(sameType(a, b))
+
+  static:
+    assert Generic[int, int].isSameType(Generic[int, int])
+    assert Generic[A, string].isSameType(Generic[int, string])
+    assert not Generic[A, string].isSameType(Generic[B, string])
+    assert not Generic[int, string].isSameType(Generic[int, int])
+    assert isSameType(int, A)
+    assert isSameType(10, 20)
+    assert isSameType("Hello", "world")
+    assert not isSameType("Hello", cstring"world")
+    assert not isSameType(int, B)
+    assert not isSameType(int, Generic[int, int])
+    assert not isSameType(C, string)
+    assert not isSameType(C, int)
+
+
+  #[
+    # compiler sameType fails for the following, read more in `types.nim`'s `sameTypeAux`.
+    type
+      D[T] = C
+      G[T] = T
+    static:
+      assert isSameType(D[int], C)
+      assert isSameType(D[int], D[float])
+      assert isSameType(G[float](1.0), float(1.0))
+      assert isSameType(float(1.0), G[float](1.0))
+  ]#
+
+  type Tensor[T] = object
+    data: T
+
+  macro testTensorInt(x: typed): untyped =
+    let
+      tensorIntType = getTypeInst(Tensor[int])[1]
+      xTyp = x.getTypeInst
+    
+    newLit(xTyp.sameType(tensorIntType))
+
+  var
+    x: Tensor[int]
+    x1 = Tensor[float]()
+    x2 = Tensor[A]()
+    x3 = Tensor[B]()
+
+  static: 
+    assert testTensorInt(x)
+    assert not testTensorInt(x1)
+    assert testTensorInt(x2)
+    assert not testTensorInt(x3)
+
+block: # extractDocCommentsAndRunnables
+  macro checkRunnables(prc: untyped) =
+    let runnables = prc.body.extractDocCommentsAndRunnables()
+    doAssert runnables[0][0].eqIdent("runnableExamples")
+
+  macro checkComments(comment: static[string], prc: untyped) =
+    let comments = prc.body.extractDocCommentsAndRunnables()
+    doAssert comments[0].strVal == comment
+    
+  proc a() {.checkRunnables.} =
+    runnableExamples: discard
+    discard
+
+  proc b() {.checkRunnables.} =
+    runnableExamples "-d:ssl": discard
+    discard
+    
+  proc c() {.checkComments("Hello world").} =
+    ## Hello world
+
+block: # bug #19020
+  type
+    foo = object
+
+  template typ(T:typedesc) {.pragma.}
+
+  proc bar() {.typ: foo.} = discard
+
+  static:
+    doAssert $bar.getCustomPragmaVal(typ) == "foo"
+  doAssert $bar.getCustomPragmaVal(typ) == "foo"
+
+block hasCustomPragmaGeneric:
+  template examplePragma() {.pragma.}
+  type
+    Foo[T] {.examplePragma.} = object
+      x {.examplePragma.}: T
+  var f: Foo[string]
+  doAssert f.hasCustomPragma(examplePragma)
+  doAssert f.x.hasCustomPragma(examplePragma)
+
+block getCustomPragmaValGeneric:
+  template examplePragma(x: int) {.pragma.}
+  type
+    Foo[T] {.examplePragma(42).} = object
+      x {.examplePragma(25).}: T
+  var f: Foo[string]
+  doAssert f.getCustomPragmaVal(examplePragma) == 42
+  doAssert f.x.getCustomPragmaVal(examplePragma) == 25
+
+block: # bug #21326
+  macro foo(body: untyped): untyped =
+    let a = body.lineInfoObj()
+    let aLit = a.newLit
+    result = quote do:
+      doAssert $`a` == $`aLit`
+
+  foo:
+    let c = 1
+
+  template name(a: LineInfo): untyped =
+    discard a # `aLit` works though
+
+  macro foo3(body: untyped): untyped =
+    let a = body.lineInfoObj()
+    # let ax = newLit(a)
+    result = getAst(name(a))
+
+  foo3:
+    let c = 1
+
+block: # bug #7375
+  macro fails(b: static[bool]): untyped =
+    doAssert b == false
+    result = newStmtList()
+
+  macro foo(): untyped =
+
+    var b = false
+
+    ## Fails
+    result = quote do:
+      fails(`b`)
+
+  foo()
+
+  macro someMacro(): untyped =
+    template tmpl(boolean: bool) =
+      when boolean:
+        discard "it's true!"
+      else:
+        doAssert false
+    result = getAst(tmpl(true))
+
+  someMacro()
+
+block:
+  macro foo(): untyped =
+    result = quote do: `littleEndian`
+
+  doAssert littleEndian == foo()
+
+block:
+  macro eqSym(x, y: untyped): untyped =
+    let eq = $x == $y # Unfortunately eqIdent compares to string.
+    result = quote do: `eq`
+
+  var r, a, b: int
+
+  template fma(result: var int, a, b: int, op: untyped) =
+    # fused multiple-add
+    when eqSym(op, `+=`):
+      discard "+="
+    else:
+      discard "+"
+
+  fma(r, a, b, `+=`)
+
+block:
+  template test(boolArg: bool) =
+    static:
+      doAssert typeof(boolArg) is bool
+    let x: bool = boolArg # compile error here, because boolArg became an int
+
+  macro testWrapped1(boolArg: bool): untyped =
+    # forwarding boolArg directly works
+    result = getAst(test(boolArg))
+
+  macro testWrapped2(boolArg: bool): untyped =
+    # forwarding boolArg via a local variable also works
+    let b = boolArg
+    result = getAst(test(b))
+
+  macro testWrapped3(boolArg: bool): untyped =
+    # but using a literal `true` as a local variable will be converted to int
+    let b = true
+    result = getAst(test(b))
+
+  test(true) # ok
+  testWrapped1(true) # ok
+  testWrapped2(true) # ok
+  testWrapped3(true) 
+
+block:
+  macro foo(): untyped =
+    var s = { 'a', 'b' }
+    quote do:              
+      let t = `s`         
+      doAssert $typeof(t) == "set[char]"
+
+  foo()
+
+block: # bug #9607
+  proc fun1(info:LineInfo): string = "bar"
+  proc fun2(info:int): string = "bar"
+
+  macro echoL(args: varargs[untyped]): untyped =
+    let info = args.lineInfoObj
+    let fun1 = bindSym"fun1"
+    let fun2 = bindSym"fun2"
+
+    # this would work instead
+    # result = newCall(bindSym"fun2", info.line.newLit)
+
+    result = quote do:
+
+      # BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil
+      `fun1`(`info`)
+
+  macro echoM(args: varargs[untyped]): untyped =
+    let info = args.lineInfoObj
+    let fun1 = bindSym"fun1"
+    let fun2 = bindSym"fun2"
+
+    # this would work instead
+    # result = newCall(bindSym"fun2", info.line.newLit)
+
+    result = quote do:
+
+      # BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil
+      `fun2`(`info`.line)
+
+
+  doAssert echoL() == "bar"
+  doAssert echoM() == "bar"
+
+block:
+  macro hello[T](x: T): untyped =
+    result = quote do:
+      let m: `T` = `x`
+      discard m
+
+  hello(12)
+
+block:
+  proc hello(x: int, y: typedesc) =
+    discard
+
+  macro main =
+    let x = 12
+    result = quote do:
+      `hello`(12, type(x))
+
+  main()
+
+block: # bug #22947
+  macro bar[N: static int](a: var array[N, int]) =
+    result = quote do:
+      for i in 0 ..< `N`:
+        `a`[i] = i
+
+  func foo[N: static int](a: var array[N, int]) =
+    bar(a)
+
+
+  var a: array[4, int]
+  foo(a)
diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim
index 38937590f..32991ccc9 100644
--- a/tests/stdlib/tmarshal.nim
+++ b/tests/stdlib/tmarshal.nim
@@ -1,23 +1,24 @@
 discard """
-  output: '''{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}
-true
-true
-alpha 100
-omega 200
-'''
+  matrix: "--mm:orc; --mm:refc"
 """
 
-import marshal
+import std/marshal
+import std/[assertions, objectdollar, streams]
 
-template testit(x) = discard $$to[type(x)]($$x)
+# TODO: add static tests
 
-var x: array[0..4, array[0..4, string]] = [
-  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
-  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
-  ["test", "1", "2", "3", "4"]]
-testit(x)
-var test2: tuple[name: string, s: int] = ("tuple test", 56)
-testit(test2)
+proc testit[T](x: T): string = $$to[T]($$x)
+
+template check1 =
+  let test1: array[0..1, array[0..4, string]] = [
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]
+  doAssert testit(test1) ==
+    """[["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]"""
+  let test2: tuple[name: string, s: int] = ("tuple test", 56)
+  doAssert testit(test2) == """{"Field0": "tuple test", "Field1": 56}"""
+
+static: check1()
+check1()
 
 type
   TE = enum
@@ -48,60 +49,185 @@ proc buildList(): PNode =
   result.prev.next = result
   result.prev.prev = result.next
 
-var test3: TestObj
-test3.test = 42
-test3.test2 = blah
-testit(test3)
+let test3 = TestObj(test: 42, test2: blah)
+doAssert testit(test3) ==
+  """{"test": 42, "asd": 0, "test2": "blah", "help": ""}"""
 
 var test4: ref tuple[a, b: string]
 new(test4)
 test4.a = "ref string test: A"
 test4.b = "ref string test: B"
-testit(test4)
+discard testit(test4) # serialization uses the pointer address, which is not consistent
 
-var test5 = @[(0,1),(2,3),(4,5)]
-testit(test5)
+let test5 = @[(0,1),(2,3),(4,5)]
+doAssert testit(test5) ==
+  """[{"Field0": 0, "Field1": 1}, {"Field0": 2, "Field1": 3}, {"Field0": 4, "Field1": 5}]"""
 
-var test7 = buildList()
-testit(test7)
+let test6: set[char] = {'A'..'Z', '_'}
+doAssert testit(test6) ==
+  """[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95]"""
 
-var test6: set[char] = {'A'..'Z', '_'}
-testit(test6)
+let test7 = buildList()
+discard testit(test7) # serialization uses the pointer address, which is not consistent
 
 
 # bug #1352
+block:
+  type
+    Entity = object of RootObj
+      name: string
+
+    Person = object of Entity
+      age: int
+      bio: string
+      blob: string
+
+  let instance1 = Person(name: "Cletus", age: 12,
+                         bio: "Я Cletus",
+                         blob: "ABC\x80")
+  doAssert $$instance1 == """{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}"""
+  doAssert to[Person]($$instance1).bio == instance1.bio
+  doAssert to[Person]($$instance1).blob == instance1.blob
+
+# bug #5757
+block:
+  type
+    Something = object
+      x: string
+      y: int
+
+  let data1 = """{"x": "alpha", "y": 100}"""
+  let data2 = """{"x": "omega", "y": 200}"""
+
+  var r = to[Something](data1)
+  doAssert $r.x & " " & $r.y == "alpha 100"
+  r = to[Something](data2)
+  doAssert $r.x & " " & $r.y == "omega 200"
+
+block:
+  type
+    Foo = object
+      a1: string
+      a2: string
+      a3: seq[string]
+      a4: seq[int]
+      a5: seq[int]
+      a6: seq[int]
+  var foo = Foo(a2: "", a4: @[], a6: @[1])
+  foo.a6.setLen 0
+  doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}"""
+  doAssert testit(foo) == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}"""
+
+import std/[options, json]
+
+# bug #15934
+block:
+  let
+    a1 = some(newJNull())
+    a2 = none(JsonNode)
+  doAssert $($$a1).to[:Option[JsonNode]] == "some(null)"
+  doAssert $($$a2).to[:Option[JsonNode]] == "none(JsonNode)"
+  doAssert ($$a1).to[:Option[JsonNode]] == some(newJNull())
+  doAssert ($$a2).to[:Option[JsonNode]] == none(JsonNode)
+
+# bug #15620
+block:
+  let str = """{"numeric": null}"""
+
+  type
+    LegacyEntry = object
+      numeric: string
+
+  let test = to[LegacyEntry](str)
+  doAssert $test == """(numeric: "")"""
+
+block:
+  let str = """{"numeric": null}"""
+
+  type
+    LegacyEntry = object
+      numeric: seq[int]
+
+  var test = to[LegacyEntry](str)
+  doAssert $test == """(numeric: @[])"""
+
+# bug #16022
+block:
+  let p: proc (): string = proc (): string = "hello world"
+  let poc = to[typeof(p)]($$p)
+  doAssert poc() == "hello world"
+
+block:
+  type
+    A {.inheritable.} = object
+    B = object of A
+      f: int
+
+  let a: ref A = new(B)
+  doAssert $$a[] == "{}" # not "{f: 0}"
+
+# bug #16496
+block:
+  type
+    A = ref object
+      data: seq[int]
+
+    B = ref object
+      x: A
+  let o = A(data: @[1, 2, 3, 4])
+  let s1 = @[B(x: o), B(x: o)]
+  let m  = $$ s1
+  let s2 = to[seq[B]](m)
+  doAssert s2[0].x.data == s2[1].x.data
+  doAssert s1[0].x.data == s2[1].x.data
+
+
+block:
+  type
+    Obj = ref object
+      i: int
+      b: bool
+
+  let
+    strm = newStringStream()
+
+  var
+    o = Obj(i: 1, b: false)
+    t1 = @[o, o]
+    t2: seq[Obj]
+
+  doAssert t1[0] == t1[1]
+
+  strm.store(t1)
+  strm.setPosition(0)
+  strm.load(t2)
+  strm.close()
+
+  doAssert t2[0] == t2[1]
+
+
+template checkMarshal(data: typed) =
+  let orig = data
+  let m = $$orig
+
+  let old = to[typeof(orig)](m)
+  doAssert data == old
+
+template main() =
+  type
+    Book = object
+      page: int
+      name: string
+
+  let book = Book(page: 12, name: "persona")
+
+  checkMarshal(486)
+  checkMarshal(3.14)
+  checkMarshal("azure sky")
+  checkMarshal(book)
+  checkMarshal([1, 2, 3])
+  checkMarshal(@[1.5, 2.7, 3.9, 4.2])
+  checkMarshal(@["dream", "is", "possible"])
 
-type
-  Entity = object of RootObj
-    name: string
-
-  Person = object of Entity
-    age: int
-    bio: string
-    blob: string
-
-var instance1 = Person(name: "Cletus", age: 12,
-                       bio: "Я Cletus",
-                       blob: "ABC\x80")
-echo($$instance1)
-echo(to[Person]($$instance1).bio == instance1.bio)
-echo(to[Person]($$instance1).blob == instance1.blob)
-
-# bug 5757
-
-type
-  Something = object
-    x: string
-    y: int
-
-var data1 = """{"x": "alpha", "y": 100}"""
-var data2 = """{"x": "omega", "y": 200}"""
-
-var r = to[Something](data1)
-
-echo r.x, " ", r.y
-
-r = to[Something](data2)
-
-echo r.x, " ", r.y
-
+static: main()
+main()
diff --git a/tests/stdlib/tmarshalsegfault.nim b/tests/stdlib/tmarshalsegfault.nim
new file mode 100644
index 000000000..71f2766c8
--- /dev/null
+++ b/tests/stdlib/tmarshalsegfault.nim
@@ -0,0 +1,54 @@
+# issue #12405
+
+import std/[marshal, streams, times, tables, os, assertions]
+
+type AiredEpisodeState * = ref object
+    airedAt * : DateTime
+    tvShowId * : string
+    seasonNumber * : int
+    number * : int
+    title * : string
+
+type ShowsWatchlistState * = ref object
+    aired * : seq[AiredEpisodeState]
+
+type UiState * = ref object
+    shows: ShowsWatchlistState
+
+# Helpers to marshal and unmarshal
+proc load * ( state : var UiState, file : string ) =
+    var strm = newFileStream( file, fmRead )
+
+    strm.load( state )
+
+    strm.close()
+
+proc store * ( state : UiState, file : string ) =
+    var strm = newFileStream( file, fmWrite )
+
+    strm.store( state )
+
+    strm.close()
+
+# 1. We fill the state initially
+var state : UiState = UiState( shows: ShowsWatchlistState( aired: @[] ) )
+
+# VERY IMPORTANT: For some reason, small numbers (like 2 or 3) don't trigger the bug. Anything above 7 or 8 on my machine triggers though
+for i in 0..30:
+    var episode = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
+
+    state.shows.aired.add( episode )
+
+# 2. Store it in a file with the marshal module, and then load it back up
+store( state, "tmarshalsegfault_data" )
+load( state, "tmarshalsegfault_data" )
+removeFile("tmarshalsegfault_data")
+
+# 3. VERY IMPORTANT: Without this line, for some reason, everything works fine
+state.shows.aired[ 0 ] = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
+
+# 4. And formatting the airedAt date will now trigger the exception
+for ep in state.shows.aired:
+    let x = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
+    let y = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
+    doAssert x == y
diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim
index 581308a7e..22e5f7d88 100644
--- a/tests/stdlib/tmath.nim
+++ b/tests/stdlib/tmath.nim
@@ -1,82 +1,473 @@
 discard """
-  action: run
-  output: '''[Suite] random int
+  targets: "c cpp js"
+  matrix:"; -d:danger; --mm:refc"
+"""
 
-[Suite] random float
+# xxx: there should be a test with `-d:nimTmathCase2 -d:danger --passc:-ffast-math`,
+# but it requires disabling certain lines with `when not defined(nimTmathCase2)`
 
-[Suite] ^
+import std/math
+import std/assertions
 
-'''
-"""
 
-import math, random, os
-import unittest
-import sets
-
-suite "random int":
-  test "there might be some randomness":
-    var set = initSet[int](128)
-    randomize()
-    for i in 1..1000:
-      incl(set, random(high(int)))
-    check len(set) == 1000
-  test "single number bounds work":
-    randomize()
-    var rand: int
-    for i in 1..1000:
-      rand = random(1000)
-      check rand < 1000
-      check rand > -1
-  test "slice bounds work":
-    randomize()
-    var rand: int
-    for i in 1..1000:
-      rand = random(100..1000)
-      check rand < 1000
-      check rand >= 100
-  test "randomize() again gives new numbers":
-    randomize()
-    var rand1 = random(1000000)
-    os.sleep(200)
-    randomize()
-    var rand2 = random(1000000)
-    check rand1 != rand2
-
-
-suite "random float":
-  test "there might be some randomness":
-    var set = initSet[float](128)
-    randomize()
-    for i in 1..100:
-      incl(set, random(1.0))
-    check len(set) == 100
-  test "single number bounds work":
-    randomize()
-    var rand: float
-    for i in 1..1000:
-      rand = random(1000.0)
-      check rand < 1000.0
-      check rand > -1.0
-  test "slice bounds work":
-    randomize()
-    var rand: float
-    for i in 1..1000:
-      rand = random(100.0..1000.0)
-      check rand < 1000.0
-      check rand >= 100.0
-  test "randomize() again gives new numbers":
-    randomize()
-    var rand1:float = random(1000000.0)
-    os.sleep(200)
-    randomize()
-    var rand2:float = random(1000000.0)
-    check rand1 != rand2
-
-suite "^":
-  test "compiles for valid types":
-    check: compiles(5 ^ 2)
-    check: compiles(5.5 ^ 2)
-    check: compiles(5.5 ^ 2.int8)
-    check: compiles(5.5 ^ 2.uint)
-    check: compiles(5.5 ^ 2.uint8)
-    check: not compiles(5.5 ^ 2.2)
\ No newline at end of file
+# Function for approximate comparison of floats
+proc `==~`(x, y: float): bool = abs(x - y) < 1e-9
+
+
+template main() =
+  block:
+    when not defined(js):
+      # check for no side effect annotation
+      proc mySqrt(num: float): float {.noSideEffect.} =
+        # xxx unused
+        sqrt(num)
+
+      # check gamma function
+      doAssert gamma(5.0) == 24.0 # 4!
+      doAssert almostEqual(gamma(0.5), sqrt(PI))
+      doAssert almostEqual(gamma(-0.5), -2 * sqrt(PI))
+      doAssert lgamma(1.0) == 0.0 # ln(1.0) == 0.0
+      doAssert almostEqual(lgamma(0.5), 0.5 * ln(PI))
+      doAssert erf(6.0) > erf(5.0)
+      doAssert erfc(6.0) < erfc(5.0)
+
+  block: # sgn() tests
+    doAssert sgn(1'i8) == 1
+    doAssert sgn(1'i16) == 1
+    doAssert sgn(1'i32) == 1
+    doAssert sgn(1'i64) == 1
+    doAssert sgn(1'u8) == 1
+    doAssert sgn(1'u16) == 1
+    doAssert sgn(1'u32) == 1
+    doAssert sgn(1'u64) == 1
+    doAssert sgn(-12342.8844'f32) == -1
+    doAssert sgn(123.9834'f64) == 1
+    doAssert sgn(0'i32) == 0
+    doAssert sgn(0'f32) == 0
+    doAssert sgn(-0.0'f64) == 0
+    doAssert sgn(NegInf) == -1
+    doAssert sgn(Inf) == 1
+    doAssert sgn(NaN) == 0
+
+  block: # fac() tests
+    when nimvm: discard
+    else:
+      try:
+        discard fac(-1)
+      except AssertionDefect:
+        discard
+
+    doAssert fac(0) == 1
+    doAssert fac(1) == 1
+    doAssert fac(2) == 2
+    doAssert fac(3) == 6
+    doAssert fac(4) == 24
+    doAssert fac(5) == 120
+
+  block: # floorMod/floorDiv
+    doAssert floorDiv(8, 3) == 2
+    doAssert floorMod(8, 3) == 2
+
+    doAssert floorDiv(8, -3) == -3
+    doAssert floorMod(8, -3) == -1
+
+    doAssert floorDiv(-8, 3) == -3
+    doAssert floorMod(-8, 3) == 1
+
+    doAssert floorDiv(-8, -3) == 2
+    doAssert floorMod(-8, -3) == -2
+
+    doAssert floorMod(8.0, -3.0) == -1.0
+    doAssert floorMod(-8.5, 3.0) == 0.5
+
+  block: # euclDiv/euclMod
+    doAssert euclDiv(8, 3) == 2
+    doAssert euclMod(8, 3) == 2
+
+    doAssert euclDiv(8, -3) == -2
+    doAssert euclMod(8, -3) == 2
+
+    doAssert euclDiv(-8, 3) == -3
+    doAssert euclMod(-8, 3) == 1
+
+    doAssert euclDiv(-8, -3) == 3
+    doAssert euclMod(-8, -3) == 1
+
+    doAssert euclMod(8.0, -3.0) == 2.0
+    doAssert euclMod(-8.5, 3.0) == 0.5
+
+    doAssert euclDiv(9, 3) == 3
+    doAssert euclMod(9, 3) == 0
+
+    doAssert euclDiv(9, -3) == -3
+    doAssert euclMod(9, -3) == 0
+
+    doAssert euclDiv(-9, 3) == -3
+    doAssert euclMod(-9, 3) == 0
+
+    doAssert euclDiv(-9, -3) == 3
+    doAssert euclMod(-9, -3) == 0
+
+  block: # ceilDiv
+    doAssert ceilDiv(8,  3) ==  3
+    doAssert ceilDiv(8,  4) ==  2
+    doAssert ceilDiv(8,  5) ==  2
+    doAssert ceilDiv(11, 3) ==  4
+    doAssert ceilDiv(12, 3) ==  4
+    doAssert ceilDiv(13, 3) ==  5
+    doAssert ceilDiv(41, 7) ==  6
+    doAssert ceilDiv(0,  1) ==  0
+    doAssert ceilDiv(1,  1) ==  1
+    doAssert ceilDiv(1,  2) ==  1
+    doAssert ceilDiv(2,  1) ==  2
+    doAssert ceilDiv(2,  2) ==  1
+    doAssert ceilDiv(0, high(int)) == 0
+    doAssert ceilDiv(1, high(int)) == 1
+    doAssert ceilDiv(0, high(int) - 1) == 0
+    doAssert ceilDiv(1, high(int) - 1) == 1
+    doAssert ceilDiv(high(int) div 2, high(int) div 2 + 1) == 1
+    doAssert ceilDiv(high(int) div 2, high(int) div 2 + 2) == 1
+    doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2) == 2
+    doAssert ceilDiv(high(int) div 2 + 2, high(int) div 2) == 2
+    doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2 + 1) == 1
+    doAssert ceilDiv(high(int), 1) == high(int)
+    doAssert ceilDiv(high(int) - 1, 1) == high(int) - 1
+    doAssert ceilDiv(high(int) - 1, 2) == high(int) div 2
+    doAssert ceilDiv(high(int) - 1, high(int)) == 1
+    doAssert ceilDiv(high(int) - 1, high(int) - 1) == 1
+    doAssert ceilDiv(high(int) - 1, high(int) - 2) == 2
+    doAssert ceilDiv(high(int), high(int)) == 1
+    doAssert ceilDiv(high(int), high(int) - 1) == 2
+    doAssert ceilDiv(255'u8,  1'u8) == 255'u8
+    doAssert ceilDiv(254'u8,  2'u8) == 127'u8
+    when not defined(danger):
+      doAssertRaises(AssertionDefect): discard ceilDiv(41,  0)
+      doAssertRaises(AssertionDefect): discard ceilDiv(41, -1)
+      doAssertRaises(AssertionDefect): discard ceilDiv(-1,  1)
+      doAssertRaises(AssertionDefect): discard ceilDiv(-1, -1)
+      doAssertRaises(AssertionDefect): discard ceilDiv(254'u8, 3'u8)
+      doAssertRaises(AssertionDefect): discard ceilDiv(255'u8, 2'u8)
+
+  block: # splitDecimal() tests
+    doAssert splitDecimal(54.674).intpart == 54.0
+    doAssert splitDecimal(54.674).floatpart ==~ 0.674
+    doAssert splitDecimal(-693.4356).intpart == -693.0
+    doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356
+    doAssert splitDecimal(0.0).intpart == 0.0
+    doAssert splitDecimal(0.0).floatpart == 0.0
+
+  block: # trunc tests for vcc
+    doAssert trunc(-1.1) == -1
+    doAssert trunc(1.1) == 1
+    doAssert trunc(-0.1) == -0
+    doAssert trunc(0.1) == 0
+
+    # special case
+    doAssert classify(trunc(1e1000000)) == fcInf
+    doAssert classify(trunc(-1e1000000)) == fcNegInf
+    when not defined(nimTmathCase2):
+      doAssert classify(trunc(0.0/0.0)) == fcNan
+    doAssert classify(trunc(0.0)) == fcZero
+
+    # trick the compiler to produce signed zero
+    let
+      f_neg_one = -1.0
+      f_zero = 0.0
+      f_nan = f_zero / f_zero
+
+    doAssert classify(trunc(f_neg_one*f_zero)) == fcNegZero
+
+    doAssert trunc(-1.1'f32) == -1
+    doAssert trunc(1.1'f32) == 1
+    doAssert trunc(-0.1'f32) == -0
+    doAssert trunc(0.1'f32) == 0
+    doAssert classify(trunc(1e1000000'f32)) == fcInf
+    doAssert classify(trunc(-1e1000000'f32)) == fcNegInf
+    when not defined(nimTmathCase2):
+      doAssert classify(trunc(f_nan.float32)) == fcNan
+    doAssert classify(trunc(0.0'f32)) == fcZero
+  
+  block: # divmod
+    doAssert divmod(int.high, 1) == (int.high, 0)
+    doAssert divmod(-1073741823, 17) == (-63161283, -12)
+    doAssert divmod(int32.high, 1.int32) == (int32.high, 0.int32)
+    doAssert divmod(1073741823.int32, 5.int32) == (214748364.int32, 3.int32)
+    doAssert divmod(4611686018427387903.int64, 5.int64) == (922337203685477580.int64, 3.int64)
+    when not defined(js) and (not compileOption("panics")) and compileOption("overflowChecks"):
+      when nimvm:
+        discard # cannot catch OverflowDefect here
+      else:
+        doAssertRaises(OverflowDefect, (discard divmod(cint.low, -1.cint)))
+        doAssertRaises(OverflowDefect, (discard divmod(clong.low, -1.clong)))
+        doAssertRaises(OverflowDefect, (discard divmod(clonglong.low, -1.clonglong)))
+        doAssertRaises(DivByZeroDefect, (discard divmod(1, 0)))
+  
+  block: # log
+    doAssert log(4.0, 3.0) ==~ ln(4.0) / ln(3.0)
+    doAssert log2(8.0'f64) == 3.0'f64
+    doAssert log2(4.0'f64) == 2.0'f64
+    doAssert log2(2.0'f64) == 1.0'f64
+    doAssert log2(1.0'f64) == 0.0'f64
+    doAssert classify(log2(0.0'f64)) == fcNegInf
+
+    doAssert log2(8.0'f32) == 3.0'f32
+    doAssert log2(4.0'f32) == 2.0'f32
+    doAssert log2(2.0'f32) == 1.0'f32
+    doAssert log2(1.0'f32) == 0.0'f32
+    doAssert classify(log2(0.0'f32)) == fcNegInf
+
+  block: # cumsum
+    block: # cumsum int seq return
+      let counts = [1, 2, 3, 4]
+      doAssert counts.cumsummed == @[1, 3, 6, 10]
+      let empty: seq[int] = @[]
+      doAssert empty.cumsummed == @[]
+
+    block: # cumsum float seq return
+      let counts = [1.0, 2.0, 3.0, 4.0]
+      doAssert counts.cumsummed == @[1.0, 3.0, 6.0, 10.0]
+      let empty: seq[float] = @[]
+      doAssert empty.cumsummed == @[]
+
+    block: # cumsum int in-place
+      var counts = [1, 2, 3, 4]
+      counts.cumsum
+      doAssert counts == [1, 3, 6, 10]
+      var empty: seq[int] = @[]
+      empty.cumsum
+      doAssert empty == @[]
+
+    block: # cumsum float in-place
+      var counts = [1.0, 2.0, 3.0, 4.0]
+      counts.cumsum
+      doAssert counts == [1.0, 3.0, 6.0, 10.0]
+      var empty: seq[float] = @[]
+      empty.cumsum
+      doAssert empty == @[]
+
+  block: # ^ compiles for valid types
+    doAssert: compiles(5 ^ 2)
+    doAssert: compiles(5.5 ^ 2)
+    doAssert: compiles(5.5 ^ 2.int8)
+    doAssert: compiles(5.5 ^ 2.uint)
+    doAssert: compiles(5.5 ^ 2.uint8)
+    doAssert: not compiles(5.5 ^ 2.2)
+
+  block: # isNaN
+    doAssert NaN.isNaN
+    doAssert not Inf.isNaN
+    doAssert isNaN(Inf - Inf)
+    doAssert not isNaN(0.0)
+    doAssert not isNaN(3.1415926)
+    doAssert not isNaN(0'f32)
+
+  block: # signbit
+    doAssert not signbit(0.0)
+    doAssert signbit(-0.0)
+    doAssert signbit(-0.1)
+    doAssert not signbit(0.1)
+
+    doAssert not signbit(Inf)
+    doAssert signbit(-Inf)
+    doAssert not signbit(NaN)
+
+    let x1 = NaN
+    let x2 = -NaN
+    let x3 = -x1
+
+    doAssert isNaN(x1)
+    doAssert isNaN(x2)
+    doAssert isNaN(x3)
+    doAssert not signbit(x1)
+    doAssert signbit(x2)
+    doAssert signbit(x3)
+
+  block: # copySign
+    doAssert copySign(10.0, 1.0) == 10.0
+    doAssert copySign(10.0, -1.0) == -10.0
+    doAssert copySign(-10.0, -1.0) == -10.0
+    doAssert copySign(-10.0, 1.0) == 10.0
+    doAssert copySign(float(10), -1.0) == -10.0
+
+    doAssert copySign(10.0'f64, 1.0) == 10.0
+    doAssert copySign(10.0'f64, -1.0) == -10.0
+    doAssert copySign(-10.0'f64, -1.0) == -10.0
+    doAssert copySign(-10.0'f64, 1.0) == 10.0
+    doAssert copySign(10'f64, -1.0) == -10.0
+
+    doAssert copySign(10.0'f32, 1.0) == 10.0
+    doAssert copySign(10.0'f32, -1.0) == -10.0
+    doAssert copySign(-10.0'f32, -1.0) == -10.0
+    doAssert copySign(-10.0'f32, 1.0) == 10.0
+    doAssert copySign(10'f32, -1.0) == -10.0
+
+    doAssert copySign(Inf, -1.0) == -Inf
+    doAssert copySign(-Inf, 1.0) == Inf
+    doAssert copySign(Inf, 1.0) == Inf
+    doAssert copySign(-Inf, -1.0) == -Inf
+    doAssert copySign(Inf, 0.0) == Inf
+    doAssert copySign(Inf, -0.0) == -Inf
+    doAssert copySign(-Inf, 0.0) == Inf
+    doAssert copySign(-Inf, -0.0) == -Inf
+    doAssert copySign(1.0, -0.0) == -1.0
+    doAssert copySign(0.0, -0.0) == -0.0
+    doAssert copySign(-1.0, 0.0) == 1.0
+    doAssert copySign(10.0, 0.0) == 10.0
+    doAssert copySign(-1.0, NaN) == 1.0
+    doAssert copySign(10.0, NaN) == 10.0
+
+    doAssert copySign(NaN, NaN).isNaN
+    doAssert copySign(-NaN, NaN).isNaN
+    doAssert copySign(NaN, -NaN).isNaN
+    doAssert copySign(-NaN, -NaN).isNaN
+    doAssert copySign(NaN, 0.0).isNaN
+    doAssert copySign(NaN, -0.0).isNaN
+    doAssert copySign(-NaN, 0.0).isNaN
+    doAssert copySign(-NaN, -0.0).isNaN
+
+    doAssert copySign(-1.0, NaN) == 1.0
+    doAssert copySign(-1.0, -NaN) == -1.0
+    doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0
+
+  block: # almostEqual
+    doAssert almostEqual(3.141592653589793, 3.1415926535897936)
+    doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32)
+    doAssert almostEqual(Inf, Inf)
+    doAssert almostEqual(-Inf, -Inf)
+    doAssert not almostEqual(Inf, -Inf)
+    doAssert not almostEqual(-Inf, Inf)
+    doAssert not almostEqual(Inf, NaN)
+    doAssert not almostEqual(NaN, NaN)
+
+  block: # round
+    block: # Round to 0 decimal places
+      doAssert round(54.652) == 55.0
+      doAssert round(54.352) == 54.0
+      doAssert round(-54.652) == -55.0
+      doAssert round(-54.352) == -54.0
+      doAssert round(0.0) == 0.0
+      doAssert 1 / round(0.0) == Inf
+      doAssert 1 / round(-0.0) == -Inf
+      doAssert round(Inf) == Inf
+      doAssert round(-Inf) == -Inf
+      doAssert round(NaN).isNaN
+      doAssert round(-NaN).isNaN
+      doAssert round(-0.5) == -1.0
+      doAssert round(0.5) == 1.0
+      doAssert round(-1.5) == -2.0
+      doAssert round(1.5) == 2.0
+      doAssert round(-2.5) == -3.0
+      doAssert round(2.5) == 3.0
+      doAssert round(2.5'f32) == 3.0'f32
+      doAssert round(2.5'f64) == 3.0'f64
+
+    block: # func round*[T: float32|float64](x: T, places: int): T
+      doAssert round(54.345, 0) == 54.0
+      template fn(x) =
+        doAssert round(x, 2).almostEqual 54.35
+        doAssert round(x, 2).almostEqual 54.35
+        doAssert round(x, -1).almostEqual 50.0
+        doAssert round(x, -2).almostEqual 100.0
+        doAssert round(x, -3).almostEqual 0.0
+      fn(54.346)
+      fn(54.346'f32)
+
+  block: # abs
+    doAssert 1.0 / abs(-0.0) == Inf
+    doAssert 1.0 / abs(0.0) == Inf
+    doAssert -1.0 / abs(-0.0) == -Inf
+    doAssert -1.0 / abs(0.0) == -Inf
+    doAssert abs(0.0) == 0.0
+    doAssert abs(0.0'f32) == 0.0'f32
+
+    doAssert abs(Inf) == Inf
+    doAssert abs(-Inf) == Inf
+    doAssert abs(NaN).isNaN
+    doAssert abs(-NaN).isNaN
+
+  block: # classify
+    doAssert classify(0.3) == fcNormal
+    doAssert classify(-0.3) == fcNormal
+    doAssert classify(5.0e-324) == fcSubnormal
+    doAssert classify(-5.0e-324) == fcSubnormal
+    doAssert classify(0.0) == fcZero
+    doAssert classify(-0.0) == fcNegZero
+    doAssert classify(NaN) == fcNan
+    doAssert classify(0.3 / 0.0) == fcInf
+    doAssert classify(Inf) == fcInf
+    doAssert classify(-0.3 / 0.0) == fcNegInf
+    doAssert classify(-Inf) == fcNegInf
+
+  block: # sum
+    let empty: seq[int] = @[]
+    doAssert sum(empty) == 0
+    doAssert sum([1, 2, 3, 4]) == 10
+    doAssert sum([-4, 3, 5]) == 4
+
+  block: # prod
+    let empty: seq[int] = @[]
+    doAssert prod(empty) == 1
+    doAssert prod([1, 2, 3, 4]) == 24
+    doAssert prod([-4, 3, 5]) == -60
+    doAssert almostEqual(prod([1.5, 3.4]), 5.1)
+    let x: seq[float] = @[]
+    doAssert prod(x) == 1.0
+
+  block: # clamp range
+    doAssert clamp(10, 1..5) == 5
+    doAssert clamp(3, 1..5) == 3
+    doAssert clamp(5, 1..5) == 5
+    doAssert clamp(42.0, 1.0 .. 3.1415926535) == 3.1415926535
+    doAssert clamp(NaN, 1.0 .. 2.0).isNaN
+    doAssert clamp(-Inf, -Inf .. -1.0) == -Inf
+    type A = enum a0, a1, a2, a3, a4, a5
+    doAssert a1.clamp(a2..a4) == a2
+    doAssert clamp((3, 0), (1, 0) .. (2, 9)) == (2, 9)
+
+  block: # edge cases
+    doAssert sqrt(-4.0).isNaN
+
+    doAssert ln(0.0) == -Inf
+    doAssert ln(-0.0) == -Inf
+    doAssert ln(-12.0).isNaN
+
+    doAssert log10(0.0) == -Inf
+    doAssert log10(-0.0) == -Inf
+    doAssert log10(-12.0).isNaN
+
+    doAssert log2(0.0) == -Inf
+    doAssert log2(-0.0) == -Inf
+    doAssert log2(-12.0).isNaN
+
+    when nimvm: discard
+    else:
+      doAssert frexp(0.0) == (0.0, 0)
+      doAssert frexp(-0.0) == (-0.0, 0)
+      doAssert classify(frexp(-0.0)[0]) == fcNegZero
+
+    when not defined(js):
+      doAssert gamma(0.0) == Inf
+      doAssert gamma(-0.0) == -Inf
+      doAssert gamma(-1.0).isNaN
+
+      doAssert lgamma(0.0) == Inf
+      doAssert lgamma(-0.0) == Inf
+      doAssert lgamma(-1.0) == Inf
+
+static: main()
+main()
+
+when not defined(js) and not defined(danger):
+  block: # bug #21792
+    block:
+      type Digit = 0..9
+      var x = [Digit 4, 7]
+
+      doAssertRaises(RangeDefect):
+        discard sum(x)
+
+    block:
+      var x = [int8 124, 127]
+
+      doAssertRaises(OverflowDefect):
+        discard sum(x)
diff --git a/tests/stdlib/tmath2.nim b/tests/stdlib/tmath2.nim
deleted file mode 100644
index eb0506f5f..000000000
--- a/tests/stdlib/tmath2.nim
+++ /dev/null
@@ -1,85 +0,0 @@
-# tests for the interpreter
-
-proc loops(a: var int) =
-  discard
-  #var
-  #  b: int
-  #b = glob
-  #while b != 0:
-  #  b = b + 1
-  #a = b
-
-proc mymax(a, b: int): int =
-  #loops(result)
-  result = a
-  if b > a: result = b
-
-proc test(a, b: int) =
-  var
-    x, y: int
-  x = 0
-  y = 7
-  if x == a + b * 3 - 7 or
-      x == 8 or
-      x == y and y > -56 and y < 699:
-    y = 0
-  elif y == 78 and x == 0:
-    y = 1
-  elif y == 0 and x == 0:
-    y = 2
-  else:
-    y = 3
-
-type
-  TTokType = enum
-    tkNil, tkType, tkConst, tkVar, tkSymbol, tkIf,
-    tkWhile, tkFor, tkLoop, tkCase, tkLabel, tkGoto
-
-proc testCase(t: TTokType): int =
-  case t
-  of tkNil, tkType, tkConst: result = 0
-  of tkVar: result = 1
-  of tkSymbol: result = 2
-  of tkIf..tkFor: result = 3
-  of tkLoop: result = 56
-  else: result = -1
-  test(0, 9) # test the call
-
-proc TestLoops() =
-  var
-    i, j: int
-
-  while i >= 0:
-    if i mod 3 == 0:
-      break
-    i = i + 1
-    while j == 13:
-      j = 13
-      break
-    break
-
-  while true:
-    break
-
-
-var
-  glob: int
-  a: array[0..5, int]
-
-proc main() =
-  #glob = 0
-  #loops( glob )
-  var
-    res: int
-    s: string
-  #write(stdout, mymax(23, 45))
-  write(stdout, "Hallo! Wie heisst du? ")
-  s = readLine(stdin)
-  # test the case statement
-  case s
-  of "Andreas": write(stdout, "Du bist mein Meister!\n")
-  of "Rumpf": write(stdout, "Du bist in der Familie meines Meisters!\n")
-  else: write(stdout, "ich kenne dich nicht!\n")
-  write(stdout, "Du heisst " & s & "\n")
-
-main()
diff --git a/tests/stdlib/tmemfiles1.nim b/tests/stdlib/tmemfiles1.nim
index 8b66dfcc1..33657256c 100644
--- a/tests/stdlib/tmemfiles1.nim
+++ b/tests/stdlib/tmemfiles1.nim
@@ -1,12 +1,11 @@
-discard """
-  file: "tmemfiles1.nim"
-"""
 import memfiles, os
+import std/syncio
+
 var
   mm: MemFile
   fn = "test.mmap"
 # Create a new file
 mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 20)
 mm.close()
-mm.close()
+# mm.close()
 if fileExists(fn): removeFile(fn)
diff --git a/tests/stdlib/tmemfiles2.nim b/tests/stdlib/tmemfiles2.nim
index d6cfa533a..c79f85ebf 100644
--- a/tests/stdlib/tmemfiles2.nim
+++ b/tests/stdlib/tmemfiles2.nim
@@ -1,9 +1,12 @@
 discard """
-  file: "tmemfiles2.nim"
+  disabled: "Windows"
   output: '''Full read size: 20
 Half read size: 10 Data: Hello'''
 """
 import memfiles, os
+import std/syncio
+
+
 const
   fn = "test.mmap"
 var
@@ -12,14 +15,16 @@ var
 
 if fileExists(fn): removeFile(fn)
 
-# Create a new file, data all zeros
-mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 20)
+# Create a new file, data all zeros, starting at size 10
+mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 10, allowRemap=true)
+mm.resize 20  # resize up to 20
 mm.close()
 
 # read, change
 mm_full = memfiles.open(fn, mode = fmWrite, mappedSize = -1, allowRemap = true)
-echo "Full read size: ",mm_full.size
+let size = mm_full.size
 p = mm_full.mapMem(fmReadWrite, 20, 0)
+echo "Full read size: ", size
 var p2 = cast[cstring](p)
 p2[0] = 'H'
 p2[1] = 'e'
@@ -32,7 +37,7 @@ mm_full.close()
 
 # read half, and verify data change
 mm_half = memfiles.open(fn, mode = fmRead, mappedSize = 10)
-echo "Half read size: ",mm_half.size, " Data: ", cast[cstring](mm_half.mem)
+echo "Half read size: ", mm_half.size, " Data: ", cast[cstring](mm_half.mem)
 mm_half.close()
 
 if fileExists(fn): removeFile(fn)
diff --git a/tests/stdlib/tmemlines.nim b/tests/stdlib/tmemlines.nim
index 19821ea26..98e03b5bb 100644
--- a/tests/stdlib/tmemlines.nim
+++ b/tests/stdlib/tmemlines.nim
@@ -1,5 +1,9 @@
+discard """
+outputsub: ""
+"""
+
 import memfiles
-var inp = memfiles.open("readme.txt")
+var inp = memfiles.open("tests/stdlib/tmemlines.nim")
 for line in lines(inp):
   echo("#" & line & "#")
 close(inp)
diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim
index 21edc2322..7bd89d4f2 100644
--- a/tests/stdlib/tmemlinesBuf.nim
+++ b/tests/stdlib/tmemlinesBuf.nim
@@ -1,6 +1,9 @@
-import memfiles
-var inp = memfiles.open("readme.txt")
-var buffer: TaintedString = ""
+import std/[memfiles, assertions]
+var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim")
+var buffer: string = ""
+var lineCount = 0
 for line in lines(inp, buffer):
-  echo("#" & line & "#")
+  lineCount += 1
+
 close(inp)
+doAssert lineCount == 9, $lineCount # this file's number of lines
diff --git a/tests/stdlib/tmemmapstreams.nim b/tests/stdlib/tmemmapstreams.nim
index 243574f1a..9cfae62c7 100644
--- a/tests/stdlib/tmemmapstreams.nim
+++ b/tests/stdlib/tmemmapstreams.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tmemmapstreams.nim"
-  output: '''Created size: 10
+output: '''
+Created size: 10
 Position after writing: 5
 Position after writing one char: 6
 Peeked data: Hello
@@ -12,6 +12,8 @@ Readed line: Hello!
 Position after reading line: 7'''
 """
 import os, streams, memfiles
+import std/syncio
+
 const
   fn = "test.mmapstream"
 var
diff --git a/tests/stdlib/tmemslices.nim b/tests/stdlib/tmemslices.nim
index 951807cc4..c0d6d3960 100644
--- a/tests/stdlib/tmemslices.nim
+++ b/tests/stdlib/tmemslices.nim
@@ -1,5 +1,11 @@
+discard """
+outputsub: "rlwuiadtrnzb"
+"""
+
+# chatever the sub pattern it will find itself
+
 import memfiles
-var inp = memfiles.open("readme.txt")
+var inp = memfiles.open("tests/stdlib/tmemslices.nim")
 for mem in memSlices(inp):
   if mem.size > 3:
     echo("#" & $mem & "#")
diff --git a/tests/stdlib/tmersenne.nim b/tests/stdlib/tmersenne.nim
new file mode 100644
index 000000000..64450a045
--- /dev/null
+++ b/tests/stdlib/tmersenne.nim
@@ -0,0 +1,13 @@
+import std/mersenne
+import std/assertions
+
+template main() =
+  var mt = newMersenneTwister(2525)
+
+  doAssert mt.getNum == 407788156'u32
+  doAssert mt.getNum == 1071751096'u32
+  doAssert mt.getNum == 3805347140'u32
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tmget.nim b/tests/stdlib/tmget.nim
index 5792b6282..f41963f02 100644
--- a/tests/stdlib/tmget.nim
+++ b/tests/stdlib/tmget.nim
@@ -1,20 +1,25 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
   output: '''Can't access 6
 10
 11
+2
 Can't access 6
 10
 11
+2
 Can't access 6
 10
 11
+2
 Can't access 6
 10
 11
-Can't access 6
+2
+0
 10
 11
-Can't access 6
+0
 10
 11
 Can't access 6
@@ -40,6 +45,9 @@ block:
   x[5] += 1
   var c = x[5]
   echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
 
 block:
   var x = newTable[int, int]()
@@ -52,6 +60,9 @@ block:
   x[5] += 1
   var c = x[5]
   echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
 
 block:
   var x = initOrderedTable[int, int]()
@@ -64,6 +75,9 @@ block:
   x[5] += 1
   var c = x[5]
   echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
 
 block:
   var x = newOrderedTable[int, int]()
@@ -76,6 +90,9 @@ block:
   x[5] += 1
   var c = x[5]
   echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
 
 block:
   var x = initCountTable[int]()
@@ -85,7 +102,7 @@ block:
   except KeyError:
     echo "Can't access 6"
   echo x[5]
-  x[5] += 1
+  x.inc 5, 1
   var c = x[5]
   echo c
 
@@ -97,14 +114,14 @@ block:
   except KeyError:
     echo "Can't access 6"
   echo x[5]
-  x[5] += 1
+  x.inc 5, 1
   var c = x[5]
   echo c
 
 import sets
 
 block:
-  var x = initSet[int]()
+  var x = initHashSet[int]()
   x.incl 5
   try:
     echo x[6]
diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim
new file mode 100644
index 000000000..fd66ebd97
--- /dev/null
+++ b/tests/stdlib/tmimetypes.nim
@@ -0,0 +1,28 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/mimetypes
+import std/assertions
+
+
+template main() =
+  var m = newMimetypes()
+  doAssert m.getMimetype("mp4") == "video/mp4"
+  doAssert m.getExt("application/json") == "json"
+  doAssert m.getMimetype("json") == "application/json"
+  m.register("foo", "baa")
+  doAssert m.getMimetype("foo") == "baa"
+  doAssert m.getMimetype("txt") == "text/plain"
+  doAssert m.getExt("text/plain") == "txt"
+  # see also `runnableExamples`.
+  # xxx we should have a way to avoid duplicating code between runnableExamples and tests
+
+  doAssert m.getMimetype("nim") == "text/nim"
+  doAssert m.getMimetype("nimble") == "text/nimble"
+  doAssert m.getMimetype("nimf") == "text/nim"
+  doAssert m.getMimetype("nims") == "text/nim"
+
+static: main()
+main()
diff --git a/tests/stdlib/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim
new file mode 100644
index 000000000..86dcf4162
--- /dev/null
+++ b/tests/stdlib/tmisc_issues.nim
@@ -0,0 +1,39 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/assertions
+
+# bug #20227
+type
+  Data = object
+    id: int
+
+  Test = distinct Data
+
+  Object = object
+    data: Test
+
+
+var x: Object = Object(data: Test(Data(id: 12)))
+doAssert Data(x.data).id == 12
+
+block: # bug #16771
+  type A = object
+    n: int
+
+  proc foo(a, b: var A) =
+    swap a, b
+
+  var a, b: A
+  a.n = 42
+  b.n = 1
+  doAssert a.n == 42
+  doAssert b.n == 1
+  a.swap b
+  doAssert a.n == 1
+  doAssert b.n == 42
+  a.foo b
+  doAssert a.n == 42
+  doAssert b.n == 1
diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim
index 17265e1f7..cc515a175 100644
--- a/tests/stdlib/tmitems.nim
+++ b/tests/stdlib/tmitems.nim
@@ -1,4 +1,5 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
   output: '''@[11, 12, 13]
 @[11, 12, 13]
 @[1, 3, 5]
@@ -16,7 +17,18 @@ fpqeew
 <Students>
   <Student Name="Aprilfoo" />
   <Student Name="bar" />
-</Students>'''
+</Students>
+<chapter>
+    <title>This is a Docbook title</title>
+    <para>
+        This is a Docbook paragraph containing <emphasis>emphasized</emphasis>,
+        <literal>literal</literal> and <replaceable>replaceable</replaceable>
+        text. Sometimes scrunched together like this:
+        <literal>literal</literal><replaceable>replaceable</replaceable>
+        and sometimes not:
+        <literal>literal</literal> <replaceable>replaceable</replaceable>
+    </para>
+</chapter>'''
 """
 
 block:
@@ -51,6 +63,7 @@ block:
 
 block:
   var x = "foobar"
+  prepareMutation(x)
   var y = cast[cstring](addr x[0])
   for c in y.mitems:
     inc c
@@ -64,6 +77,7 @@ block:
 
 block:
   var x = "foobar"
+  prepareMutation(x)
   var y = cast[cstring](addr x[0])
   for i, c in y.mpairs:
     inc c, i
@@ -123,7 +137,7 @@ block:
     x.num += 10
   echo j
 
-import xmltree, xmlparser, streams, strtabs
+import xmltree, xmlparser, parsexml, streams, strtabs
 
 block:
   var d = parseXml(newStringStream """<Students>
@@ -134,3 +148,17 @@ block:
     x = <>Student(Name=x.attrs["Name"] & "foo")
   d[1].attrs["Name"] = "bar"
   echo d
+
+block:
+  var d = parseXml(newStringStream """<chapter>
+    <title>This is a Docbook title</title>
+    <para>
+        This is a Docbook paragraph containing <emphasis>emphasized</emphasis>,
+        <literal>literal</literal> and <replaceable>replaceable</replaceable>
+        text. Sometimes scrunched together like this:
+        <literal>literal</literal><replaceable>replaceable</replaceable>
+        and sometimes not:
+        <literal>literal</literal> <replaceable>replaceable</replaceable>
+    </para>
+</chapter>""",{reportComments, reportWhitespace})
+  echo d
diff --git a/tests/stdlib/tmonotimes.nim b/tests/stdlib/tmonotimes.nim
new file mode 100644
index 000000000..1366dbfe9
--- /dev/null
+++ b/tests/stdlib/tmonotimes.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/[monotimes, times]
+import std/assertions
+
+let d = initDuration(nanoseconds = 10)
+let t1 = getMonoTime()
+let t2 = t1 + d
+
+doAssert t2 - t1 == d
+doAssert t1 == t1
+doAssert t1 != t2
+doAssert t2 - d == t1
+doAssert t1 < t2
+doAssert t1 <= t2
+doAssert t1 <= t1
+doAssert not(t2 < t1)
+doAssert t1 < high(MonoTime)
+doAssert low(MonoTime) < t1
diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim
index c683647bc..8242beb83 100644
--- a/tests/stdlib/tnativesockets.nim
+++ b/tests/stdlib/tnativesockets.nim
@@ -1,8 +1,30 @@
-import nativesockets, unittest
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
 
-suite "nativesockets":
-  test "getHostname":
-    let hostname = getHostname()
-    check hostname.len > 0
-    check hostname.len < 64
+import std/nativesockets
+import stdtest/testutils
+import std/assertions
 
+block:
+  let hostname = getHostname()
+  doAssert hostname.len > 0
+
+when defined(windows):
+  assertAll:
+    toInt(IPPROTO_IP) == 0
+    toInt(IPPROTO_ICMP) == 1
+    toInt(IPPROTO_TCP) == 6
+    toInt(IPPROTO_UDP) == 17
+    toInt(IPPROTO_IPV6) == 41
+    toInt(IPPROTO_ICMPV6) == 58
+    toInt(IPPROTO_RAW) == 20
+
+    # no changes to enum value
+    ord(IPPROTO_TCP) == 6
+    ord(IPPROTO_UDP) == 17
+    ord(IPPROTO_IP) == 18
+    ord(IPPROTO_IPV6) == 19
+    ord(IPPROTO_RAW) == 20
+    ord(IPPROTO_ICMP) == 21
+    ord(IPPROTO_ICMPV6) == 22
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
index d364447da..27a6ac49c 100644
--- a/tests/stdlib/tnet.nim
+++ b/tests/stdlib/tnet.nim
@@ -1,51 +1,92 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+outputsub: ""
+"""
+
 import net, nativesockets
 import unittest
+import std/assertions
 
-suite "isIpAddress tests":
-  test "127.0.0.1 is valid":
+block: # isIpAddress tests
+  block: # 127.0.0.1 is valid
     check isIpAddress("127.0.0.1") == true
 
-  test "ipv6 localhost is valid":
+  block: # ipv6 localhost is valid
     check isIpAddress("::1") == true
 
-  test "fqdn is not an ip address":
+  block: # fqdn is not an ip address
     check isIpAddress("example.com") == false
 
-  test "random string is not an ipaddress":
+  block: # random string is not an ipaddress
     check isIpAddress("foo bar") == false
 
-  test "5127.0.0.1 is invalid":
+  block: # 5127.0.0.1 is invalid
     check isIpAddress("5127.0.0.1") == false
 
-  test "ipv6 is valid":
+  block: # ipv6 is valid
     check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true
 
-  test "invalid ipv6":
+  block: # invalid ipv6
     check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false
 
 
-suite "parseIpAddress tests":
-  test "127.0.0.1 is valid":
+block: # parseIpAddress tests
+  block: # 127.0.0.1 is valid
     discard parseIpAddress("127.0.0.1")
 
-  test "ipv6 localhost is valid":
+  block: # ipv6 localhost is valid
     discard parseIpAddress("::1")
 
-  test "fqdn is not an ip address":
+  block: # fqdn is not an ip address
     expect(ValueError):
       discard parseIpAddress("example.com")
 
-  test "random string is not an ipaddress":
+  block: # random string is not an ipaddress
     expect(ValueError):
       discard parseIpAddress("foo bar")
 
-  test "ipv6 is valid":
+  block: # ipv6 is valid
     discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652")
 
-  test "invalid ipv6":
+  block: # invalid ipv6
     expect(ValueError):
       discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652")
 
+  block: # ipv4-compatible ipv6 address (embedded ipv4 address)
+    check parseIpAddress("::ffff:10.0.0.23") == parseIpAddress("::ffff:0a00:0017")
+
+  block: # octal number in ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("010.8.8.8")
+    expect(ValueError):
+      discard parseIpAddress("8.010.8.8")
+
+  block: # hexadecimal number in ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("0xc0.168.0.1")
+    expect(ValueError):
+      discard parseIpAddress("192.0xa8.0.1")
+
+  block: # less than 4 numbers in ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("127.0.1")
+
+  block: # octal number in embedded ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("::ffff:010.8.8.8")
+    expect(ValueError):
+      discard parseIpAddress("::ffff:8.010.8.8")
+
+  block: # hexadecimal number in embedded ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("::ffff:0xc0.168.0.1")
+    expect(ValueError):
+      discard parseIpAddress("::ffff:192.0xa8.0.1")
+
+  block: # less than 4 numbers in embedded ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("::ffff:127.0.1")
+
 block: # "IpAddress/Sockaddr conversion"
   proc test(ipaddrstr: string) =
     var ipaddr_1 = parseIpAddress(ipaddrstr)
@@ -54,7 +95,7 @@ block: # "IpAddress/Sockaddr conversion"
     doAssert($ipaddrstr == $ipaddr_1)
 
     var sockaddr: Sockaddr_storage
-    var socklen: Socklen
+    var socklen: SockLen
     var ipaddr_2: IpAddress
     var port_2: Port
 
@@ -66,11 +107,11 @@ block: # "IpAddress/Sockaddr conversion"
     doAssert(ipaddr_1 == ipaddr_2)
     doAssert($ipaddr_1 == $ipaddr_2)
 
-    if sockaddr.ss_family == AF_INET.toInt:
+    if sockaddr.ss_family.cint == AF_INET.toInt:
       var sockaddr4: Sockaddr_in
       copyMem(addr sockaddr4, addr sockaddr, sizeof(sockaddr4))
       fromSockAddr(sockaddr4, socklen, ipaddr_2, port_2)
-    elif sockaddr.ss_family == AF_INET6.toInt:
+    elif sockaddr.ss_family.cint == AF_INET6.toInt:
       var sockaddr6: Sockaddr_in6
       copyMem(addr sockaddr6, addr sockaddr, sizeof(sockaddr6))
       fromSockAddr(sockaddr6, socklen, ipaddr_2, port_2)
diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim
index 2ac272fd1..199946482 100644
--- a/tests/stdlib/tnet_ll.nim
+++ b/tests/stdlib/tnet_ll.nim
@@ -1,42 +1,52 @@
-discard """

-  action: run

-  output: '''

-[Suite] inet_ntop tests

-'''

-"""

-

-when defined(windows):

-  import winlean

-elif defined(posix):

-  import posix

-else:

-  {.error: "Unsupported OS".}

-

-import unittest, strutils

-

-suite "inet_ntop tests":

-

-  setup:

-    when defined(windows):

-      var wsa: WSAData

-      discard wsaStartup(0x101'i16, wsa.addr)

-  

-  test "IP V4":

-    var ip4 = 0x10111213

-    var buff: array[0..255, char]

-    let r = inet_ntop(AF_INET, ip4.addr, buff[0].addr, buff.sizeof.int32)

-    let res = if r == nil: "" else: $r

-    check: res == "19.18.17.16"

-      

-

-  test "IP V6":

-    when defined(windows):

-      let ipv6Support = (getVersion() and 0xff) > 0x5

-    else:

-      let ipv6Support = true

-          

-    var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001]

-    var buff: array[0..255, char]

-    let r = inet_ntop(AF_INET6, ip6[0].addr, buff[0].addr, buff.sizeof.int32)

-    let res = if r == nil: "" else: $r

-    check: not ipv6Support or res == "10:110:20:120:30:130:40:140"

+discard """
+  action: run
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+
+[Suite] inet_ntop tests
+'''
+"""
+
+when defined(windows):
+  import winlean
+elif defined(posix):
+  import posix
+else:
+  {.error: "Unsupported OS".}
+
+import unittest, strutils
+
+suite "inet_ntop tests":
+
+  setup:
+    when defined(windows):
+      var wsa: WSAData
+      discard wsaStartup(0x101'i16, wsa.addr)
+  
+  test "IP V4":
+    # regular
+    var ip4 = InAddr()
+    ip4.s_addr = 0x10111213'u32
+    check: ip4.s_addr == 0x10111213'u32
+
+    var buff: array[0..255, char]
+    let r = inet_ntop(AF_INET, cast[pointer](ip4.s_addr.addr), cast[cstring](buff[0].addr), buff.len.int32)
+    let res = if r == nil: "" else: $r
+    check: res == "19.18.17.16"
+      
+  test "IP V6":
+    when defined(windows):
+      let ipv6Support = (getVersion() and 0xff) > 0x5
+    else:
+      let ipv6Support = true
+          
+    var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001]
+    var buff: array[0..255, char]
+    let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), cast[cstring](buff[0].addr), buff.len.int32)
+    let res = if r == nil: "" else: $r
+    check: not ipv6Support or res == "10:110:20:120:30:130:40:140"
+
+  test "InAddr":
+    # issue 19244
+    var ip4 = InAddr(s_addr: 0x10111213'u32)
+    check: ip4.s_addr == 0x10111213'u32
diff --git a/tests/stdlib/tnetbind.nim b/tests/stdlib/tnetbind.nim
new file mode 100644
index 000000000..84f9ac464
--- /dev/null
+++ b/tests/stdlib/tnetbind.nim
@@ -0,0 +1,25 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+joinable: false
+"""
+
+#[
+joinable: false
+otherwise:
+Error: unhandled exception: Address already in use [OSError]
+]#
+
+import net
+
+## Test for net.bindAddr
+
+proc test() =
+  # IPv4 TCP
+  newSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1900), "0.0.0.0")
+  newSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1901))
+
+  # IPv6 TCP
+  newSocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1902), "::")
+  newSocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1903))
+
+test()
diff --git a/tests/stdlib/tnetconnect.nim b/tests/stdlib/tnetconnect.nim
new file mode 100644
index 000000000..ae654aed9
--- /dev/null
+++ b/tests/stdlib/tnetconnect.nim
@@ -0,0 +1,30 @@
+discard """
+  disabled: "i386"
+  matrix: "-d:ssl"
+"""
+
+import std/net
+from std/strutils import `%`
+from stdtest/testutils import enableRemoteNetworking
+
+# bug #15215
+proc test() =
+  let ctx = newContext()
+
+  proc fn(url: string) =
+    let socket = newSocket()
+    defer: close(socket)
+    connect(socket, url, Port(443), 5000) # typically 20 could be enough
+    send(socket, "GET / HTTP/1.0\nHost: $#\nConnection: close\n\n" % [url])
+    wrapSocket(ctx, socket)
+
+  # trying 2 sites makes it more resilent: refs #17458 this could give:
+  # * Call to 'connect' timed out. [TimeoutError]
+  # * No route to host [OSError]
+  try:
+    fn("www.nim-lang.org")
+  except TimeoutError, OSError:
+    fn("www.google.com")
+
+when enableRemoteNetworking:
+  test()
diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim
index 695150179..a1e147ad5 100644
--- a/tests/stdlib/tnetdial.nim
+++ b/tests/stdlib/tnetdial.nim
@@ -2,20 +2,20 @@ discard """
   cmd: "nim c --threads:on $file"
   exitcode: 0
   output: "OK"
-  disabled: "travis"
 """
 
 import os, net, nativesockets, asyncdispatch
+import std/[assertions, typedthreads]
 
 ## Test for net.dial
 
 const port = Port(28431)
 
 proc initIPv6Server(hostname: string, port: Port): AsyncFD =
-  let fd = newNativeSocket(AF_INET6)
+  let fd = createNativeSocket(AF_INET6)
   setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
   var aiList = getAddrInfo(hostname, port, AF_INET6)
-  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
     freeAddrInfo(aiList)
     raiseOSError(osLastError())
   freeAddrInfo(aiList)
@@ -39,10 +39,10 @@ proc testThread() {.thread.} =
   fd.close()
 
 proc test() =
+  let serverFd = initIPv6Server("::1", port)
   var t: Thread[void]
   createThread(t, testThread)
 
-  let serverFd = initIPv6Server("::1", port)
   var done = false
 
   serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
@@ -58,4 +58,5 @@ proc test() =
 
   joinThread(t)
 
+# this would cause #13132 `for i in 0..<10000: test()`
 test()
diff --git a/tests/stdlib/tnilecho.nim b/tests/stdlib/tnilecho.nim
deleted file mode 100644
index 147b5e492..000000000
--- a/tests/stdlib/tnilecho.nim
+++ /dev/null
@@ -1,2 +0,0 @@
-var x = @["1", nil, "3"]
-doAssert $x == "@[1, nil, 3]"
diff --git a/tests/stdlib/tnre.nim b/tests/stdlib/tnre.nim
index fabbb69a8..3b40e9e83 100644
--- a/tests/stdlib/tnre.nim
+++ b/tests/stdlib/tnre.nim
@@ -1,24 +1,8 @@
 discard """
+matrix: "--mm:refc; --mm:orc"
 # Since the tests for nre are all bundled together we treat failure in one test as an nre failure
-# When running 'tests/testament/tester' a failed check() in the test suite will cause the exit
+# When running 'testament/tester' a failed check() in the test suite will cause the exit
 # codes to differ and be reported as a failure
-
-  output:
-    '''[Suite] Test NRE initialization
-
-[Suite] captures
-
-[Suite] find
-
-[Suite] string splitting
-
-[Suite] match
-
-[Suite] replace
-
-[Suite] escape strings
-
-[Suite] Misc tests'''
 """
 
 import nre
diff --git a/tests/stdlib/tntpath.nim b/tests/stdlib/tntpath.nim
new file mode 100644
index 000000000..8efdd6bd0
--- /dev/null
+++ b/tests/stdlib/tntpath.nim
@@ -0,0 +1,50 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/ntpath
+import std/assertions
+
+block: # From Python's `Lib/test/test_ntpath.py`
+  doAssert splitDrive(r"c:\foo\bar") == (r"c:", r"\foo\bar")
+  doAssert splitDrive(r"c:/foo/bar") == (r"c:", r"/foo/bar")
+  doAssert splitDrive(r"\\conky\mountpoint\foo\bar") == (r"\\conky\mountpoint", r"\foo\bar")
+  doAssert splitDrive(r"//conky/mountpoint/foo/bar") == (r"//conky/mountpoint", r"/foo/bar")
+  doAssert splitDrive(r"\\\conky\mountpoint\foo\bar") == (r"", r"\\\conky\mountpoint\foo\bar")
+  doAssert splitDrive(r"///conky/mountpoint/foo/bar") == (r"", r"///conky/mountpoint/foo/bar")
+  doAssert splitDrive(r"\\conky\\mountpoint\foo\bar") == (r"", r"\\conky\\mountpoint\foo\bar")
+  doAssert splitDrive(r"//conky//mountpoint/foo/bar") == (r"", r"//conky//mountpoint/foo/bar")
+  # Issue #19911: UNC part containing U+0130
+  doAssert splitDrive(r"//conky/MOUNTPOİNT/foo/bar") == (r"//conky/MOUNTPOİNT", r"/foo/bar")
+  # gh-81790: support device namespace, including UNC drives.
+  doAssert splitDrive(r"//?/c:") == (r"//?/c:", r"")
+  doAssert splitDrive(r"//?/c:/") == (r"//?/c:", r"/")
+  doAssert splitDrive(r"//?/c:/dir") == (r"//?/c:", r"/dir")
+  doAssert splitDrive(r"//?/UNC") == (r"", r"//?/UNC")
+  doAssert splitDrive(r"//?/UNC/") == (r"", r"//?/UNC/")
+  doAssert splitDrive(r"//?/UNC/server/") == (r"//?/UNC/server/", r"")
+  doAssert splitDrive(r"//?/UNC/server/share") == (r"//?/UNC/server/share", r"")
+  doAssert splitDrive(r"//?/UNC/server/share/dir") == (r"//?/UNC/server/share", r"/dir")
+  doAssert splitDrive(r"//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam") == (r"//?/VOLUME{00000000-0000-0000-0000-000000000000}", r"/spam")
+  doAssert splitDrive(r"//?/BootPartition/") == (r"//?/BootPartition", r"/")
+
+  doAssert splitDrive(r"\\?\c:") == (r"\\?\c:", r"")
+  doAssert splitDrive(r"\\?\c:\") == (r"\\?\c:", r"\")
+  doAssert splitDrive(r"\\?\c:\dir") == (r"\\?\c:", r"\dir")
+  doAssert splitDrive(r"\\?\UNC") == (r"", r"\\?\UNC")
+  doAssert splitDrive(r"\\?\UNC\") == (r"", r"\\?\UNC\")
+  doAssert splitDrive(r"\\?\UNC\server\") == (r"\\?\UNC\server\", r"")
+  doAssert splitDrive(r"\\?\UNC\server\share") == (r"\\?\UNC\server\share", r"")
+  doAssert splitDrive(r"\\?\UNC\server\share\dir") == (r"\\?\UNC\server\share", r"\dir")
+  doAssert splitDrive(r"\\?\VOLUME{00000000-0000-0000-0000-000000000000}\spam") == (r"\\?\VOLUME{00000000-0000-0000-0000-000000000000}", r"\spam")
+  doAssert splitDrive(r"\\?\BootPartition\") == (r"\\?\BootPartition", r"\")
+
+block:
+  doAssert splitDrive(r"C:") == (r"C:", r"")
+  doAssert splitDrive(r"C:\") == (r"C:", r"\")
+  doAssert splitDrive(r"non/absolute/path") == (r"", r"non/absolute/path")
+
+  # Special for `\`-rooted paths on Windows. I don't know if this is correct,
+  # rbut `\` is not recognized as a drive, in contrast to `C:` or `\?\c:`.
+  # This behavior is the same for Python's `splitdrive` function.
+  doAssert splitDrive(r"\\") == (r"", r"\\")
diff --git a/tests/stdlib/tobjectdollar.nim b/tests/stdlib/tobjectdollar.nim
new file mode 100644
index 000000000..cf78fa255
--- /dev/null
+++ b/tests/stdlib/tobjectdollar.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "-d:nimPreviewSlimSystem"
+"""
+
+import std/assertions
+
+type Foo = object
+  a, b: int
+
+let x = Foo(a: 23, b: 45)
+doAssert not compiles($x)
+import std/objectdollar
+doAssert compiles($x)
+doAssert $x == "(a: 23, b: 45)"
diff --git a/tests/stdlib/toids.nim b/tests/stdlib/toids.nim
new file mode 100644
index 000000000..dd5b84c51
--- /dev/null
+++ b/tests/stdlib/toids.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/oids
+import std/assertions
+
+block: # genOid
+  let x = genOid()
+  doAssert ($x).len == 24
+
+block:
+  let x = genOid()
+  let y = parseOid(cstring($x))
+  doAssert x == y
diff --git a/tests/stdlib/topenssl.nim b/tests/stdlib/topenssl.nim
new file mode 100644
index 000000000..af259627f
--- /dev/null
+++ b/tests/stdlib/topenssl.nim
@@ -0,0 +1,46 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/wordwrap
+import openssl
+import std/assertions
+
+const PubKey = r"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAknKWvrdnncCIzBnIGrZ5qtZrPH+Yo3t7ag9WZIu6Gmc/JgIDDaZhJeyGW0YSnifeAEhooWvM4jDWhTEARzktalSHqYtmwI/1Oxwp6NTYH8akMe2LCpZ5pX9FVA6m9o2tkbdXatbDKRqeD4UA8Ow7Iyrdo6eb1SU8vk+26i+uXHTtsb25p8uf2ppOJrJCy+1vr8Gsnuwny1UdoYZTxMsxRFPf+UX/LrSXMHVq/oPVa3SJ4VHMpYrG/httAugVP6K58xiZ93jst63/dd0JL85mWJu1uS3uz92aL5O97xzth3wR4BbdmDUlN4LuTIwi6DtEcC7gUOTnOzH4zgp2b5RyHwIDAQAB"
+const PrivateKey = r"MIIEpAIBAAKCAQEAknKWvrdnncCIzBnIGrZ5qtZrPH+Yo3t7ag9WZIu6Gmc/JgIDDaZhJeyGW0YSnifeAEhooWvM4jDWhTEARzktalSHqYtmwI/1Oxwp6NTYH8akMe2LCpZ5pX9FVA6m9o2tkbdXatbDKRqeD4UA8Ow7Iyrdo6eb1SU8vk+26i+uXHTtsb25p8uf2ppOJrJCy+1vr8Gsnuwny1UdoYZTxMsxRFPf+UX/LrSXMHVq/oPVa3SJ4VHMpYrG/httAugVP6K58xiZ93jst63/dd0JL85mWJu1uS3uz92aL5O97xzth3wR4BbdmDUlN4LuTIwi6DtEcC7gUOTnOzH4zgp2b5RyHwIDAQABAoIBACSOxmLFlfAjaALLTNCeTLEA5bQshgYJhT1sprxixQpiS7lJN0npBsdYzBFs5KjmetzHNpdVOcgdOO/204L0Gwo4H8WLLxNS3HztAulEeM813zc3fUYfWi6eHshk//j8VR/TDNd21TElm99z7FA4KGsXAE0iQhxrN0aqz5aWYIhjprtHA5KxXIiESnTkof5Cud8oXEnPiwPGNhq93QeQzh7xQIKSaDKBcdAa6edTFhzc4RLUQRfrik/GqJzouEDQ9v6H/uiOLTB3FxxwErQIf6dvSVhD9gs1nSLQfyj3S2Hxe9S2zglTl07EsawTQUxtVQkdZUOok67c7CPBxecZ2wECgYEA2c31gr/UJwczT+P/AE52GkHHETXMxqE3Hnh9n4CitfAFSD5X0VwZvGjZIlln2WjisTd92Ymf65eDylX2kCm93nzZ2GfXgS4zl4oY1N87+VeNQlx9f2+6GU7Hs0HFdfu8bGd+0sOuWA1PFqQCobxCACMPTkuzsG9M7knUTN59HS8CgYEArCEoP4ReYoOFveXUE0AteTPb4hryvR9VDEolP+LMoiPe8AzBMeB5fP493TPdjtnWmrPCXNLc7UAFSj2CZsRhau4PuiqnNrsb5iz/7iXVl3E8wZvS4w7WYpO4m33L0cijA6MdcdqilQu4Z5tw4nG45lAW9UYyOc9D4hJTzgtGHhECgYA6QyDoj931brSoK0ocT+DB11Sj4utbOuberMaV8zgTSRhwodSl+WgdAUMMMDRacPcrBrgQiAMSZ15msqYZHEFhEa7Id8arFKvSXquTzf9iDKyJ0unzO/ThLjS3W+GxVNyrdufzA0tQ3IaKfOcDUrOpC7fdbtyrVqqSl4dF5MI9GwKBgQCl3OF6qyOEDDZgsUk1L59h7k3QR6VmBf4e9IeGUxZamvQlHjU/yY1nm1mjgGnbUB/SPKtqZKoMV6eBTVoNiuhQcItpGda9D3mnx+7p3T0/TBd+fJeuwcplfPDjrEktogcq5w/leQc3Ve7gr1EMcwb3r28f8/9L42QHQR/OKODs8QKBgQCFAvxDRPyYg7V/AgD9rt1KzXi4+b3Pls5NXZa2g/w+hmdhHUNxV5IGmHlqFnptGyshgYgQGxMMkW0iJ1j8nLamFnkbFQOp5/UKbdPLRKiB86oPpxsqYtPXucDUqEfcMsp57mD1CpGVODbspogFpSUvQpMECkhvI0XLMbolMdo53g=="
+
+proc rsaPublicEncrypt(fr: string): string =
+  let mKey = "-----BEGIN PUBLIC KEY-----\n" & PubKey.wrapWords(64) & "\n-----END PUBLIC KEY-----"
+  let bio = bioNew(bioSMem())
+  doAssert BIO_write(bio, mKey.cstring, mKey.len.cint) >= 0
+  let rsa = PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil)
+  doAssert rsa != nil
+  doAssert BIO_free(bio) >= 0
+  result = newString(RSA_size(rsa))
+  let frdata = cast[ptr uint8](fr.cstring)
+  var todata = cast[ptr uint8](result.cstring)
+  doAssert RSA_public_encrypt(fr.len.cint, frdata, todata, rsa, RSA_PKCS1_PADDING) != -1
+  RSA_free(rsa)
+
+proc rasPrivateDecrypt(fr: string): string =
+  let mKey = "-----BEGIN RSA PRIVATE KEY-----\n" & PrivateKey.wrapWords(64) & "\n-----END RSA PRIVATE KEY-----"
+  let bio = bioNew(bioSMem())
+  doAssert BIO_write(bio, mKey.cstring, mKey.len.cint) >= 0
+  let rsa = PEM_read_bio_RSAPrivateKey(bio, nil, nil, nil)
+  doAssert rsa != nil
+  doAssert BIO_free(bio) >= 0
+  let rsaLen = RSA_size(rsa)
+  result = newString(rsaLen)
+  let frdata = cast[ptr uint8](fr.cstring)
+  var todata = cast[ptr uint8](result.cstring)
+  let lenOrig = RSA_private_decrypt(rsaLen, frdata, todata, rsa, RSA_PKCS1_PADDING)
+  doAssert lenOrig >= 0 and lenOrig < result.len
+  doAssert result[lenOrig] == '\0'
+  result.setLen lenOrig
+  RSA_free(rsa)
+
+let res = "TEST"
+let miwen = rsaPublicEncrypt(res)
+let mingwen = rasPrivateDecrypt(miwen)
+doAssert mingwen == res
+
diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim
new file mode 100644
index 000000000..63a10e746
--- /dev/null
+++ b/tests/stdlib/toptions.nim
@@ -0,0 +1,207 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/[json, options]
+
+import std/assertions
+import std/objectdollar
+
+
+# RefPerson is used to test that overloaded `==` operator is not called by
+# options. It is defined here in the global scope, because otherwise the test
+# will not even consider the `==` operator. Different bug?
+type RefPerson = ref object
+  name: string
+
+proc `==`(a, b: RefPerson): bool =
+  assert(not a.isNil and not b.isNil)
+  a.name == b.name
+
+
+template disableJsVm(body) =
+  # something doesn't work in JS VM
+  when defined(js):
+    when nimvm: discard
+    else: body
+  else:
+    body
+
+proc main() =
+  type
+    Foo = ref object
+      test: string
+    Test = object
+      foo: Option[Foo]
+
+  let js = """{"foo": {"test": "123"}}"""
+  let parsed = parseJson(js)
+  let a = parsed.to(Test)
+  doAssert $(%*a) == """{"foo":{"test":"123"}}"""
+
+  block options:
+    # work around a bug in unittest
+    let intNone = none(int)
+    let stringNone = none(string)
+
+    block example:
+      proc find(haystack: string, needle: char): Option[int] =
+        for i, c in haystack:
+          if c == needle:
+            return some i
+
+      doAssert("abc".find('c').get() == 2)
+
+      let result = "team".find('i')
+
+      doAssert result == intNone
+      doAssert result.isNone
+
+    block some:
+      doAssert some(6).get() == 6
+      doAssert some("a").unsafeGet() == "a"
+      doAssert some(6).isSome
+      doAssert some("a").isSome
+
+    block none:
+      doAssertRaises UnpackDefect:
+        discard none(int).get()
+      doAssert(none(int).isNone)
+      doAssert(not none(string).isSome)
+
+    block equality:
+      doAssert some("a") == some("a")
+      doAssert some(7) != some(6)
+      doAssert some("a") != stringNone
+      doAssert intNone == intNone
+
+      when compiles(some("a") == some(5)):
+        doAssert false
+      when compiles(none(string) == none(int)):
+        doAssert false
+
+    block get_with_a_default_value:
+      doAssert(some("Correct").get("Wrong") == "Correct")
+      doAssert(stringNone.get("Correct") == "Correct")
+
+    block stringify:
+      doAssert($(some("Correct")) == "some(\"Correct\")")
+      doAssert($(stringNone) == "none(string)")
+
+    disableJsVm:
+      block map_with_a_void_result:
+        var procRan = 0
+        # TODO closure anonymous functions doesn't work in VM with JS
+        # Error: cannot evaluate at compile time: procRan
+        some(123).map(proc (v: int) = procRan = v)
+        doAssert procRan == 123
+        intNone.map(proc (v: int) = doAssert false)
+
+    block map:
+      doAssert(some(123).map(proc (v: int): int = v * 2) == some(246))
+      doAssert(intNone.map(proc (v: int): int = v * 2).isNone)
+
+    block filter:
+      doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123))
+      doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone)
+      doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone)
+
+    block flatMap:
+      proc addOneIfNotZero(v: int): Option[int] =
+        if v != 0:
+          result = some(v + 1)
+        else:
+          result = none(int)
+
+      doAssert(some(1).flatMap(addOneIfNotZero) == some(2))
+      doAssert(some(0).flatMap(addOneIfNotZero) == none(int))
+      doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3))
+
+      proc maybeToString(v: int): Option[string] =
+        if v != 0:
+          result = some($v)
+        else:
+          result = none(string)
+
+      doAssert(some(1).flatMap(maybeToString) == some("1"))
+
+      proc maybeExclaim(v: string): Option[string] =
+        if v != "":
+          result = some v & "!"
+        else:
+          result = none(string)
+
+      doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!"))
+      doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string))
+
+    block SomePointer:
+      var intref: ref int
+      doAssert(option(intref).isNone)
+      intref.new
+      doAssert(option(intref).isSome)
+
+      let tmp = option(intref)
+      doAssert(sizeof(tmp) == sizeof(ptr int))
+
+      var prc = proc (x: int): int = x + 1
+      doAssert(option(prc).isSome)
+      prc = nil
+      doAssert(option(prc).isNone)
+
+    block:
+      doAssert(none[int]().isNone)
+      doAssert(none(int) == none[int]())
+
+    # "$ on typed with .name"
+    block:
+      type Named = object
+        name: string
+
+      let nobody = none(Named)
+      doAssert($nobody == "none(Named)")
+
+    # "$ on type with name()"
+    block:
+      type Person = object
+        myname: string
+
+      let noperson = none(Person)
+      doAssert($noperson == "none(Person)")
+
+    # "Ref type with overloaded `==`"
+    block:
+      let p = some(RefPerson.new())
+      doAssert p.isSome
+
+    block: # test cstring
+      block:
+        let x = some("".cstring)
+        doAssert x.isSome
+        doAssert x.get == ""
+
+      block:
+        let x = some("12345".cstring)
+        doAssert x.isSome
+        doAssert x.get == "12345"
+
+      block:
+        let x = "12345".cstring
+        let y = some(x)
+        doAssert y.isSome
+        doAssert y.get == "12345"
+
+      block:
+        let x = none(cstring)
+        doAssert x.isNone
+        doAssert $x == "none(cstring)"
+
+static: main()
+main()
+
+when not defined(js):
+  block: # bug #22932
+    var it = iterator: int {.closure.} = discard
+    doAssert it.option.isSome # Passes.
+    it = nil
+    doAssert it.option.isNone # Passes.
diff --git a/tests/stdlib/torderedtable.nim b/tests/stdlib/torderedtable.nim
deleted file mode 100644
index 91a916930..000000000
--- a/tests/stdlib/torderedtable.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-import tables, random
-var t = initOrderedTable[int,string]()
-
-# this tests issue #5917
-var data = newSeq[int]()
-for i in 0..<1000:
-  var x = random(1000)
-  if x notin t: data.add(x)
-  t[x] = "meh"
-
-# this checks that keys are re-inserted
-# in order when table is enlarged.
-var i = 0
-for k, v in t:
-  doAssert(k == data[i])
-  doAssert(v == "meh")
-  inc(i)
-
diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim
index e6fbb0e51..611659fdb 100644
--- a/tests/stdlib/tos.nim
+++ b/tests/stdlib/tos.nim
@@ -1,13 +1,5 @@
 discard """
-  output: '''true
-true
-true
-true
-true
-true
-true
-true
-true
+  output: '''
 All:
 __really_obscure_dir_name/are.x
 __really_obscure_dir_name/created
@@ -27,115 +19,857 @@ __really_obscure_dir_name/created
 __really_obscure_dir_name/dirs
 __really_obscure_dir_name/some
 __really_obscure_dir_name/test
-false
-false
-false
-false
-false
-false
-false
-false
-false
-true
-true
 Raises
-true
-true
-true
-true
+Raises
 '''
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
 """
 # test os path creation, iteration, and deletion
 
-import os, strutils
+from stdtest/specialpaths import buildDir
+import std/[syncio, assertions, osproc, os, strutils, pathnorm]
+
+block fileOperations:
+  let files = @["these.txt", "are.x", "testing.r", "files.q"]
+  let dirs = @["some", "created", "test", "dirs"]
 
-let files = @["these.txt", "are.x", "testing.r", "files.q"]
-let dirs = @["some", "created", "test", "dirs"]
+  let dname = "__really_obscure_dir_name"
+
+  createDir(dname)
+  doAssert dirExists(dname)
 
-let dname = "__really_obscure_dir_name"
+  block: # copyFile, copyFileToDir
+    doAssertRaises(OSError): copyFile(dname/"nonexistent.txt", dname/"nonexistent.txt")
+    let fname = "D20201009T112235"
+    let fname2 = "D20201009T112235.2"
+    let str = "foo1\0foo2\nfoo3\0"
+    let file = dname/fname
+    let file2 = dname/fname2
+    writeFile(file, str)
+    doAssert readFile(file) == str
+    let sub = "sub"
+    doAssertRaises(OSError): copyFile(file, dname/sub/fname2)
+    doAssertRaises(OSError): copyFileToDir(file, dname/sub)
+    doAssertRaises(ValueError): copyFileToDir(file, "")
+    copyFile(file, file2)
+    doAssert fileExists(file2)
+    doAssert readFile(file2) == str
+    createDir(dname/sub)
+    copyFileToDir(file, dname/sub)
+    doAssert fileExists(dname/sub/fname)
+    removeDir(dname/sub)
+    doAssert not dirExists(dname/sub)
+    removeFile(file)
+    removeFile(file2)
 
-createDir(dname)
-echo dirExists(dname)
+  # Test creating files and dirs
+  for dir in dirs:
+    createDir(dname/dir)
+    doAssert dirExists(dname/dir)
 
-# Test creating files and dirs
-for dir in dirs:
-  createDir(dname/dir)
-  echo dirExists(dname/dir)
+  for file in files:
+    let fh = open(dname/file, fmReadWrite)
+    fh.close()
+    doAssert fileExists(dname/file)
 
-for file in files:
-  let fh = open(dname/file, fmReadWrite)
-  fh.close()
-  echo fileExists(dname/file)
+  echo "All:"
 
-echo "All:"
+  template norm(x): untyped =
+    (when defined(windows): x.replace('\\', '/') else: x)
 
-template norm(x): untyped =
-  (when defined(windows): x.replace('\\', '/') else: x)
+  for path in walkPattern(dname/"*"):
+    echo path.norm
 
-for path in walkPattern(dname/"*"):
-  echo path.norm
+  echo "Files:"
 
-echo "Files:"
+  for path in walkFiles(dname/"*"):
+    echo path.norm
 
-for path in walkFiles(dname/"*"):
-  echo path.norm
+  echo "Dirs:"
 
-echo "Dirs:"
+  for path in walkDirs(dname/"*"):
+    echo path.norm
 
-for path in walkDirs(dname/"*"):
-  echo path.norm
+  # Test removal of files dirs
+  for dir in dirs:
+    removeDir(dname/dir)
+    doAssert: not dirExists(dname/dir)
 
-# Test removal of files dirs
-for dir in dirs:
-  removeDir(dname/dir)
-  echo dirExists(dname/dir)
+  for file in files:
+    removeFile(dname/file)
+    doAssert: not fileExists(dname/file)
 
-for file in files:
-  removeFile(dname/file)
-  echo fileExists(dname/file)
+  removeDir(dname)
+  doAssert: not dirExists(dname)
 
-removeDir(dname)
-echo dirExists(dname)
+  # createDir should create recursive directories
+  createDir(dirs[0] / dirs[1])
+  doAssert dirExists(dirs[0] / dirs[1]) # true
+  removeDir(dirs[0])
 
-# createDir should create recursive directories
-createDir(dirs[0] / dirs[1])
-echo dirExists(dirs[0] / dirs[1]) # true
-removeDir(dirs[0])
+  # createDir should properly handle trailing separator
+  createDir(dname / "")
+  doAssert dirExists(dname) # true
+  removeDir(dname)
 
-# createDir should properly handle trailing separator
-createDir(dname / "")
-echo dirExists(dname) # true
-removeDir(dname)
+  # createDir should raise IOError if the path exists
+  # and is not a directory
+  open(dname, fmWrite).close
+  try:
+    createDir(dname)
+  except IOError:
+    echo "Raises"
+  removeFile(dname)
 
-# createDir should raise IOError if the path exists
-# and is not a directory
-open(dname, fmWrite).close
-try:
+  # removeFile should not remove directory
   createDir(dname)
-except IOError:
-  echo "Raises"
-removeFile(dname)
+  try:
+    removeFile(dname)
+  except OSError:
+    echo "Raises"
+  removeDir(dname)
+
+  # test copyDir:
+  createDir("a/b")
+  open("a/b/file.txt", fmWrite).close
+  createDir("a/b/c")
+  open("a/b/c/fileC.txt", fmWrite).close
+
+  copyDir("a", "../dest/a")
+  removeDir("a")
+
+  doAssert dirExists("../dest/a/b")
+  doAssert fileExists("../dest/a/b/file.txt")
+
+  doAssert fileExists("../dest/a/b/c/fileC.txt")
+  removeDir("../dest")
+
+  # test copyDir:
+  # if separator at the end of a path
+  createDir("a/b")
+  open("a/file.txt", fmWrite).close
+
+  copyDir("a/", "../dest/a/")
+  removeDir("a")
+
+  doAssert dirExists("../dest/a/b")
+  doAssert fileExists("../dest/a/file.txt")
+  removeDir("../dest")
+
+  # createDir should not fail if `dir` is empty
+  createDir("")
+
+
+  when defined(linux): # bug #24174
+    createDir("a/b")
+    open("a/file.txt", fmWrite).close
+
+    if not fileExists("a/fifoFile"):
+      doAssert execCmd("mkfifo -m 600 a/fifoFile") == 0
+
+    copyDir("a/", "../dest/a/", skipSpecial = true)
+    copyDirWithPermissions("a/", "../dest2/a/", skipSpecial = true)
+    removeDir("a")
+
+  # Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
+  # `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
+  block:
+    const symlinksAreHandled = not defined(windows)
+    const dname = buildDir/"D20210116T140629"
+    const subDir = dname/"sub"
+    const subDir2 = dname/"sub2"
+    const brokenSymlinkName = "D20210101T191320_BROKEN_SYMLINK"
+    const brokenSymlink = dname/brokenSymlinkName
+    const brokenSymlinkSrc = "D20210101T191320_nonexistent"
+    const brokenSymlinkCopy = brokenSymlink & "_COPY"
+    const brokenSymlinkInSubDir = subDir/brokenSymlinkName
+    const brokenSymlinkInSubDir2 = subDir2/brokenSymlinkName
+
+    createDir(subDir)
+    createSymlink(brokenSymlinkSrc, brokenSymlink)
+
+    # Test copyFile
+    when symlinksAreHandled:
+      doAssertRaises(OSError):
+        copyFile(brokenSymlink, brokenSymlinkCopy)
+      doAssertRaises(OSError):
+        copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkFollow})
+    copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkIgnore})
+    doAssert not fileExists(brokenSymlinkCopy)
+    copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkAsIs})
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
+      removeFile(brokenSymlinkCopy)
+    else:
+      doAssert not fileExists(brokenSymlinkCopy)
+    doAssertRaises(AssertionDefect):
+      copyFile(brokenSymlink, brokenSymlinkCopy,
+               {cfSymlinkAsIs, cfSymlinkFollow})
+
+    # Test copyFileWithPermissions
+    when symlinksAreHandled:
+      doAssertRaises(OSError):
+        copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy)
+      doAssertRaises(OSError):
+        copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                                options = {cfSymlinkFollow})
+    copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                            options = {cfSymlinkIgnore})
+    doAssert not fileExists(brokenSymlinkCopy)
+    copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                            options = {cfSymlinkAsIs})
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
+      removeFile(brokenSymlinkCopy)
+    else:
+      doAssert not fileExists(brokenSymlinkCopy)
+    doAssertRaises(AssertionDefect):
+      copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                              options = {cfSymlinkAsIs, cfSymlinkFollow})
+
+    # Test copyFileToDir
+    when symlinksAreHandled:
+      doAssertRaises(OSError):
+        copyFileToDir(brokenSymlink, subDir)
+      doAssertRaises(OSError):
+        copyFileToDir(brokenSymlink, subDir, {cfSymlinkFollow})
+    copyFileToDir(brokenSymlink, subDir, {cfSymlinkIgnore})
+    doAssert not fileExists(brokenSymlinkInSubDir)
+    copyFileToDir(brokenSymlink, subDir, {cfSymlinkAsIs})
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkInSubDir) == brokenSymlinkSrc
+      removeFile(brokenSymlinkInSubDir)
+    else:
+      doAssert not fileExists(brokenSymlinkInSubDir)
+
+    createSymlink(brokenSymlinkSrc, brokenSymlinkInSubDir)
+
+    # Test copyDir
+    copyDir(subDir, subDir2)
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
+    else:
+      doAssert not fileExists(brokenSymlinkInSubDir2)
+    removeDir(subDir2)
+
+    # Test copyDirWithPermissions
+    copyDirWithPermissions(subDir, subDir2)
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
+    else:
+      doAssert not fileExists(brokenSymlinkInSubDir2)
+    removeDir(subDir2)
+
+    # Test moveFile
+    moveFile(brokenSymlink, brokenSymlinkCopy)
+    when not defined(windows):
+      doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
+    else:
+      doAssert symlinkExists(brokenSymlinkCopy)
+    removeFile(brokenSymlinkCopy)
+
+    # Test moveDir
+    moveDir(subDir, subDir2)
+    when not defined(windows):
+      doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
+    else:
+      doAssert symlinkExists(brokenSymlinkInSubDir2)
+
+    removeDir(dname)
 
-# test copyDir:
-createDir("a/b")
-open("a/b/file.txt", fmWrite).close
-createDir("a/b/c")
-open("a/b/c/fileC.txt", fmWrite).close
+block: # moveFile
+  let tempDir = getTempDir() / "D20210609T151608"
+  createDir(tempDir)
+  defer: removeDir(tempDir)
 
-copyDir("a", "../dest/a")
-removeDir("a")
+  writeFile(tempDir / "a.txt", "")
+  moveFile(tempDir / "a.txt", tempDir / "b.txt")
+  doAssert not fileExists(tempDir / "a.txt")
+  doAssert fileExists(tempDir / "b.txt")
+  removeFile(tempDir / "b.txt")
 
-echo dirExists("../dest/a/b")
-echo fileExists("../dest/a/b/file.txt")
+  createDir(tempDir / "moveFile_test")
+  writeFile(tempDir / "moveFile_test/a.txt", "")
+  moveFile(tempDir / "moveFile_test/a.txt", tempDir / "moveFile_test/b.txt")
+  doAssert not fileExists(tempDir / "moveFile_test/a.txt")
+  doAssert fileExists(tempDir / "moveFile_test/b.txt")
+  removeDir(tempDir / "moveFile_test")
 
-echo fileExists("../dest/a/b/c/fileC.txt")
-removeDir("../dest")
+  createDir(tempDir / "moveFile_test")
+  writeFile(tempDir / "a.txt", "")
+  moveFile(tempDir / "a.txt", tempDir / "moveFile_test/b.txt")
+  doAssert not fileExists(tempDir / "a.txt")
+  doAssert fileExists(tempDir / "moveFile_test/b.txt")
+  removeDir(tempDir / "moveFile_test")
+
+block: # moveDir
+  let tempDir = getTempDir() / "D20210609T161443"
+  createDir(tempDir)
+  defer: removeDir(tempDir)
+
+  createDir(tempDir / "moveDir_test")
+  moveDir(tempDir / "moveDir_test/", tempDir / "moveDir_test_dest")
+  doAssert not dirExists(tempDir / "moveDir_test")
+  doAssert dirExists(tempDir / "moveDir_test_dest")
+  removeDir(tempDir / "moveDir_test_dest")
+
+  createDir(tempDir / "moveDir_test")
+  writeFile(tempDir / "moveDir_test/a.txt", "")
+  moveDir(tempDir / "moveDir_test", tempDir / "moveDir_test_dest")
+  doAssert not dirExists(tempDir / "moveDir_test")
+  doAssert not fileExists(tempDir / "moveDir_test/a.txt")
+  doAssert dirExists(tempDir / "moveDir_test_dest")
+  doAssert fileExists(tempDir / "moveDir_test_dest/a.txt")
+  removeDir(tempDir / "moveDir_test_dest")
 
-# Test get/set modification times
-# Should support at least microsecond resolution
 import times
-let tm = fromUnix(0) + 100.microseconds
-writeFile("a", "")
-setLastModificationTime("a", tm)
-echo getLastModificationTime("a") == tm
-removeFile("a")
\ No newline at end of file
+block modificationTime:
+  # Test get/set modification times
+  # Should support at least microsecond resolution
+  let tm = fromUnix(0) + 100.microseconds
+  writeFile("a", "")
+  setLastModificationTime("a", tm)
+
+  when defined(macosx):
+    doAssert true
+  else:
+    doAssert getLastModificationTime("a") == tm
+  removeFile("a")
+
+block walkDirRec:
+  createDir("walkdir_test/a/b")
+  open("walkdir_test/a/b/file_1", fmWrite).close()
+  open("walkdir_test/a/file_2", fmWrite).close()
+
+  for p in walkDirRec("walkdir_test"):
+    doAssert p.fileExists
+    doAssert p.startsWith("walkdir_test")
+
+  var s: seq[string]
+  for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative = true):
+    s.add(p)
+
+  doAssert s.len == 2
+  doAssert "a" / "b" / "file_1" in s
+  doAssert "a" / "file_2" in s
+
+  removeDir("walkdir_test")
+
+import std/sequtils
+
+block: # walkDir
+  doAssertRaises(OSError):
+    for a in walkDir("nonexistent", checkDir = true): discard
+  doAssertRaises(OSError):
+    for p in walkDirRec("nonexistent", checkDir = true): discard
+
+  when not defined(windows):
+    block walkDirRelative:
+      createDir("walkdir_test")
+      createSymlink(".", "walkdir_test/c")
+      for k, p in walkDir("walkdir_test", true):
+        doAssert k == pcLinkToDir
+      removeDir("walkdir_test")
+
+  when defined(posix):
+    block walkDirSpecial:
+      createDir("walkdir_test")
+      doAssert execShellCmd("mkfifo walkdir_test/fifo") == 0
+      createSymlink("fifo", "walkdir_test/fifo_link")
+      let withSpecialFiles = toSeq(walkDir("walkdir_test", relative = true))
+      doAssert (withSpecialFiles.len == 2 and
+                (pcFile, "fifo") in withSpecialFiles and
+                (pcLinkToFile, "fifo_link") in withSpecialFiles)
+      # now Unix special files are excluded from walkdir output:
+      let skipSpecialFiles = toSeq(walkDir("walkdir_test", relative = true,
+                                           skipSpecial = true))
+      doAssert skipSpecialFiles.len == 0
+      removeDir("walkdir_test")
+
+block normalizedPath:
+  doAssert normalizedPath("") == ""
+  block relative:
+    doAssert normalizedPath(".") == "."
+    doAssert normalizedPath("foo/..") == "."
+    doAssert normalizedPath("foo//../bar/.") == "bar"
+    doAssert normalizedPath("..") == ".."
+    doAssert normalizedPath("../") == ".."
+    doAssert normalizedPath("../..") == unixToNativePath"../.."
+    doAssert normalizedPath("../a/..") == ".."
+    doAssert normalizedPath("../a/../") == ".."
+    doAssert normalizedPath("./") == "."
+
+  block absolute:
+    doAssert normalizedPath("/") == unixToNativePath"/"
+    doAssert normalizedPath("/.") == unixToNativePath"/"
+    doAssert normalizedPath("/..") == unixToNativePath"/.."
+    doAssert normalizedPath("/../") == unixToNativePath"/.."
+    doAssert normalizedPath("/../..") == unixToNativePath"/../.."
+    doAssert normalizedPath("/../../") == unixToNativePath"/../.."
+    doAssert normalizedPath("/../../../") == unixToNativePath"/../../.."
+    doAssert normalizedPath("/a/b/../../foo") == unixToNativePath"/foo"
+    doAssert normalizedPath("/a/b/../../../foo") == unixToNativePath"/../foo"
+    doAssert normalizedPath("/./") == unixToNativePath"/"
+    doAssert normalizedPath("//") == unixToNativePath"/"
+    doAssert normalizedPath("///") == unixToNativePath"/"
+    doAssert normalizedPath("/a//b") == unixToNativePath"/a/b"
+    doAssert normalizedPath("/a///b") == unixToNativePath"/a/b"
+    doAssert normalizedPath("/a/b/c/..") == unixToNativePath"/a/b"
+    doAssert normalizedPath("/a/b/c/../") == unixToNativePath"/a/b"
+
+block isHidden:
+  when defined(posix):
+    doAssert ".foo.txt".isHidden
+    doAssert "bar/.foo.ext".isHidden
+    doAssert not "bar".isHidden
+    doAssert not "foo/".isHidden
+    doAssert ".foo/.".isHidden
+    # Corner cases: `isHidden` is not yet `..` aware
+    doAssert not ".foo/..".isHidden
+
+block absolutePath:
+  doAssertRaises(ValueError): discard absolutePath("a", "b")
+  doAssert absolutePath("a") == getCurrentDir() / "a"
+  doAssert absolutePath("a", "/b") == "/b" / "a"
+  when defined(posix):
+    doAssert absolutePath("a", "/b/") == "/b" / "a"
+    doAssert absolutePath("a", "/b/c") == "/b/c" / "a"
+    doAssert absolutePath("/a", "b/") == "/a"
+
+block splitFile:
+  doAssert splitFile("") == ("", "", "")
+  doAssert splitFile("abc/") == ("abc", "", "")
+  doAssert splitFile("/") == ("/", "", "")
+  doAssert splitFile("./abc") == (".", "abc", "")
+  doAssert splitFile(".txt") == ("", ".txt", "")
+  doAssert splitFile("abc/.txt") == ("abc", ".txt", "")
+  doAssert splitFile("abc") == ("", "abc", "")
+  doAssert splitFile("abc.txt") == ("", "abc", ".txt")
+  doAssert splitFile("/abc.txt") == ("/", "abc", ".txt")
+  doAssert splitFile("/foo/abc.txt") == ("/foo", "abc", ".txt")
+  doAssert splitFile("/foo/abc.txt.gz") == ("/foo", "abc.txt", ".gz")
+  doAssert splitFile(".") == ("", ".", "")
+  doAssert splitFile("abc/.") == ("abc", ".", "")
+  doAssert splitFile("..") == ("", "..", "")
+  doAssert splitFile("a/..") == ("a", "..", "")
+  doAssert splitFile("/foo/abc....txt") == ("/foo", "abc...", ".txt")
+
+# execShellCmd is tested in tosproc
+
+block ospaths:
+  doAssert unixToNativePath("") == ""
+  doAssert unixToNativePath(".") == $CurDir
+  doAssert unixToNativePath("..") == $ParDir
+  doAssert isAbsolute(unixToNativePath("/"))
+  doAssert isAbsolute(unixToNativePath("/", "a"))
+  doAssert isAbsolute(unixToNativePath("/a"))
+  doAssert isAbsolute(unixToNativePath("/a", "a"))
+  doAssert isAbsolute(unixToNativePath("/a/b"))
+  doAssert isAbsolute(unixToNativePath("/a/b", "a"))
+  doAssert unixToNativePath("a/b") == joinPath("a", "b")
+
+  when defined(macos):
+    doAssert unixToNativePath("./") == ":"
+    doAssert unixToNativePath("./abc") == ":abc"
+    doAssert unixToNativePath("../abc") == "::abc"
+    doAssert unixToNativePath("../../abc") == ":::abc"
+    doAssert unixToNativePath("/abc", "a") == "abc"
+    doAssert unixToNativePath("/abc/def", "a") == "abc:def"
+  elif doslikeFileSystem:
+    doAssert unixToNativePath("./") == ".\\"
+    doAssert unixToNativePath("./abc") == ".\\abc"
+    doAssert unixToNativePath("../abc") == "..\\abc"
+    doAssert unixToNativePath("../../abc") == "..\\..\\abc"
+    doAssert unixToNativePath("/abc", "a") == "a:\\abc"
+    doAssert unixToNativePath("/abc/def", "a") == "a:\\abc\\def"
+  else:
+    #Tests for unix
+    doAssert unixToNativePath("./") == "./"
+    doAssert unixToNativePath("./abc") == "./abc"
+    doAssert unixToNativePath("../abc") == "../abc"
+    doAssert unixToNativePath("../../abc") == "../../abc"
+    doAssert unixToNativePath("/abc", "a") == "/abc"
+    doAssert unixToNativePath("/abc/def", "a") == "/abc/def"
+
+  block extractFilenameTest:
+    doAssert extractFilename("") == ""
+    when defined(posix):
+      doAssert extractFilename("foo/bar") == "bar"
+      doAssert extractFilename("foo/bar.txt") == "bar.txt"
+      doAssert extractFilename("foo/") == ""
+      doAssert extractFilename("/") == ""
+    when doslikeFileSystem:
+      doAssert extractFilename(r"foo\bar") == "bar"
+      doAssert extractFilename(r"foo\bar.txt") == "bar.txt"
+      doAssert extractFilename(r"foo\") == ""
+      doAssert extractFilename(r"C:\") == ""
+
+  block lastPathPartTest:
+    doAssert lastPathPart("") == ""
+    when defined(posix):
+      doAssert lastPathPart("foo/bar.txt") == "bar.txt"
+      doAssert lastPathPart("foo/") == "foo"
+      doAssert lastPathPart("/") == ""
+    when doslikeFileSystem:
+      doAssert lastPathPart(r"foo\bar.txt") == "bar.txt"
+      doAssert lastPathPart(r"foo\") == "foo"
+
+  template canon(x): untyped = normalizePath(x, '/')
+  doAssert canon"/foo/../bar" == "/bar"
+  doAssert canon"foo/../bar" == "bar"
+
+  doAssert canon"/f/../bar///" == "/bar"
+  doAssert canon"f/..////bar" == "bar"
+
+  doAssert canon"../bar" == "../bar"
+  doAssert canon"/../bar" == "/../bar"
+
+  doAssert canon("foo/../../bar/") == "../bar"
+  doAssert canon("./bla/blob/") == "bla/blob"
+  doAssert canon(".hiddenFile") == ".hiddenFile"
+  doAssert canon("./bla/../../blob/./zoo.nim") == "../blob/zoo.nim"
+
+  doAssert canon("C:/file/to/this/long") == "C:/file/to/this/long"
+  doAssert canon("") == ""
+  doAssert canon("foobar") == "foobar"
+  doAssert canon("f/////////") == "f"
+
+  doAssert relativePath("/foo/bar//baz.nim", "/foo", '/') == "bar/baz.nim"
+  doAssert normalizePath("./foo//bar/../baz", '/') == "foo/baz"
+
+  doAssert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim"
+
+  doAssert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim"
+
+  # `//` is a UNC path, `/` is the current working directory's drive, so can't
+  # run this test on Windows.
+  when not doslikeFileSystem:
+    doAssert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim"
+  doAssert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim"
+  doAssert relativePath("", "/users/moo", '/') == ""
+  doAssert relativePath("foo", "", '/') == "foo"
+  doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
+  doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: ".")
+  doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
+  doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: ".")
+
+  doAssert relativePath("foo", ".", '/') == "foo"
+  doAssert relativePath(".", ".", '/') == "."
+  doAssert relativePath("..", ".", '/') == ".."
+
+  doAssert relativePath("foo", "foo") == "."
+  doAssert relativePath("", "foo") == ""
+  doAssert relativePath("././/foo", "foo//./") == "."
+
+  doAssert relativePath(getCurrentDir() / "bar", "foo") == "../bar".unixToNativePath
+  doAssert relativePath("bar", getCurrentDir() / "foo") == "../bar".unixToNativePath
+
+  when doslikeFileSystem:
+    doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim"
+    doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim"
+    doAssert relativePath(r"c:\foo\bar\baz.nim", r"d:\foo") == r"c:\foo\bar\baz.nim"
+    doAssert relativePath(r"\foo\baz.nim", r"\foo") == r"baz.nim"
+    doAssert relativePath(r"\foo\bar\baz.nim", r"\bar") == r"..\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\bar") == r"baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foO\bar") == r"baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\bar\bar") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\car") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\goo\bar") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"c:\") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\foo") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"c:\foo.nim", r"\foo") == r"c:\foo.nim"
+
+  doAssert joinPath("usr", "") == unixToNativePath"usr"
+  doAssert joinPath("", "lib") == "lib"
+  doAssert joinPath("", "/lib") == unixToNativePath"/lib"
+  doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib"
+  doAssert joinPath("", "") == unixToNativePath"" # issue #13455
+  doAssert joinPath("", "/") == unixToNativePath"/"
+  doAssert joinPath("/", "/") == unixToNativePath"/"
+  doAssert joinPath("/", "") == unixToNativePath"/"
+  doAssert joinPath("/" / "") == unixToNativePath"/" # weird test case...
+  doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c"
+  doAssert joinPath("foo/", "") == unixToNativePath"foo/"
+  doAssert joinPath("foo/", "abc") == unixToNativePath"foo/abc"
+  doAssert joinPath("foo//./", "abc/.//") == unixToNativePath"foo/abc/"
+  doAssert joinPath("foo", "abc") == unixToNativePath"foo/abc"
+  doAssert joinPath("", "abc") == unixToNativePath"abc"
+
+  doAssert joinPath("zook/.", "abc") == unixToNativePath"zook/abc"
+
+  # controversial: inconsistent with `joinPath("zook/.","abc")`
+  # on linux, `./foo` and `foo` are treated a bit differently for executables
+  # but not `./foo/bar` and `foo/bar`
+  doAssert joinPath(".", "/lib") == unixToNativePath"./lib"
+  doAssert joinPath(".", "abc") == unixToNativePath"./abc"
+
+  # cases related to issue #13455
+  doAssert joinPath("foo", "", "") == "foo"
+  doAssert joinPath("foo", "") == "foo"
+  doAssert joinPath("foo/", "") == unixToNativePath"foo/"
+  doAssert joinPath("foo/", ".") == "foo"
+  doAssert joinPath("foo", "./") == unixToNativePath"foo/"
+  doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/"
+
+  # issue #13579
+  doAssert joinPath("/foo", "../a") == unixToNativePath"/a"
+  doAssert joinPath("/foo/", "../a") == unixToNativePath"/a"
+  doAssert joinPath("/foo/.", "../a") == unixToNativePath"/a"
+  doAssert joinPath("/foo/.b", "../a") == unixToNativePath"/foo/a"
+  doAssert joinPath("/foo///", "..//a/") == unixToNativePath"/a/"
+  doAssert joinPath("foo/", "../a") == unixToNativePath"a"
+
+  when doslikeFileSystem:
+    doAssert joinPath("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", "..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
+    doAssert joinPath("C:\\foo", "..\\a") == r"C:\a"
+    doAssert joinPath("C:\\foo\\", "..\\a") == r"C:\a"
+
+block getTempDir:
+  block TMPDIR:
+    # TMPDIR env var is not used if either of these are defined.
+    when not (defined(tempDir) or defined(windows) or defined(android)):
+      if existsEnv("TMPDIR"):
+        let origTmpDir = getEnv("TMPDIR")
+        putEnv("TMPDIR", "/mytmp")
+        doAssert getTempDir() == "/mytmp/"
+        delEnv("TMPDIR")
+        doAssert getTempDir() == "/tmp/"
+        putEnv("TMPDIR", origTmpDir)
+      else:
+        doAssert getTempDir() == "/tmp/"
+
+block: # getCacheDir
+  doAssert getCacheDir().dirExists
+
+block isRelativeTo:
+  doAssert isRelativeTo("/foo", "/")
+  doAssert isRelativeTo("/foo/bar", "/foo")
+  doAssert isRelativeTo("foo/bar", "foo")
+  doAssert isRelativeTo("/foo/bar.nim", "/foo/bar.nim")
+  doAssert isRelativeTo("./foo/", "foo")
+  doAssert isRelativeTo("foo", "./foo/")
+  doAssert isRelativeTo(".", ".")
+  doAssert isRelativeTo("foo/bar", ".")
+  doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim")
+  doAssert not isRelativeTo("/foo2", "/foo")
+
+block: # quoteShellWindows
+  doAssert quoteShellWindows("aaa") == "aaa"
+  doAssert quoteShellWindows("aaa\"") == "aaa\\\""
+  doAssert quoteShellWindows("") == "\"\""
+
+block: # quoteShellCommand
+  when defined(windows):
+    doAssert quoteShellCommand(["a b c", "d", "e"]) == """"a b c" d e"""
+    doAssert quoteShellCommand(["""ab"c""", r"\", "d"]) == """ab\"c \ d"""
+    doAssert quoteShellCommand(["""ab"c""", """ \""", "d"]) == """ab\"c " \\" d"""
+    doAssert quoteShellCommand(["""a\\\b""", """de fg""", "h"]) == """a\\\b "de fg" h"""
+    doAssert quoteShellCommand(["""a\"b""", "c", "d"]) == """a\\\"b c d"""
+    doAssert quoteShellCommand(["""a\\b c""", "d", "e"]) == """"a\\b c" d e"""
+    doAssert quoteShellCommand(["""a\\b\ c""", "d", "e"]) == """"a\\b\ c" d e"""
+    doAssert quoteShellCommand(["ab", ""]) == """ab """""
+
+block: # quoteShellPosix
+  doAssert quoteShellPosix("aaa") == "aaa"
+  doAssert quoteShellPosix("aaa a") == "'aaa a'"
+  doAssert quoteShellPosix("") == "''"
+  doAssert quoteShellPosix("a'a") == "'a'\"'\"'a'"
+
+block: # quoteShell
+  when defined(posix):
+    doAssert quoteShell("") == "''"
+
+block: # normalizePathEnd
+  # handle edge cases correctly: shouldn't affect whether path is
+  # absolute/relative
+  doAssert "".normalizePathEnd(true) == ""
+  doAssert "".normalizePathEnd(false) == ""
+  doAssert "/".normalizePathEnd(true) == $DirSep
+  doAssert "/".normalizePathEnd(false) == $DirSep
+
+  when defined(posix):
+    doAssert "//".normalizePathEnd(false) == "/"
+    doAssert "foo.bar//".normalizePathEnd == "foo.bar"
+    doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/"
+  when defined(windows):
+    doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo"
+    doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\"
+    # this one is controversial: we could argue for returning `D:\` instead,
+    # but this is simplest.
+    doAssert r"D:\".normalizePathEnd == r"D:"
+    doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\"
+    doAssert "/".normalizePathEnd == r"\"
+
+
+import sugar
+
+block: # normalizeExe
+  doAssert "".dup(normalizeExe) == ""
+  when defined(posix):
+    doAssert "foo".dup(normalizeExe) == "./foo"
+    doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar"
+  when defined(windows):
+    doAssert "foo".dup(normalizeExe) == "foo"
+
+block: # isAdmin
+  let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure
+  # In Azure on Windows tests run as an admin user
+  if isAzure and defined(windows): doAssert isAdmin()
+  # In Azure on POSIX tests run as a normal user
+  if isAzure and defined(posix): doAssert not isAdmin()
+
+
+import sugar
+
+block: # normalizeExe
+  doAssert "".dup(normalizeExe) == ""
+  when defined(posix):
+    doAssert "foo".dup(normalizeExe) == "./foo"
+    doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar"
+  when defined(windows):
+    doAssert "foo".dup(normalizeExe) == "foo"
+
+block: # isAdmin
+  let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure
+  # In Azure on Windows tests run as an admin user
+  if isAzure and defined(windows): doAssert isAdmin()
+  # In Azure on POSIX tests run as a normal user
+  if isAzure and defined(posix): doAssert not isAdmin()
+
+when doslikeFileSystem:
+  import std/private/ntpath
+
+  block: # Bug #19103 UNC paths
+
+    # Easiest way of generating a valid, readable and writable UNC path
+    let tempDir = r"\\?\" & getTempDir()
+    doAssert dirExists tempDir
+    createDir tempDir / "test"
+    removeDir tempDir / "test"
+    createDir tempDir / "recursive" / "test"
+    removeDir tempDir / "recursive" / "test"
+
+    let tempDir2 = getTempDir()
+    let (drive, pathNoDrive) = splitDrive(tempDir2)
+    setCurrentDir drive
+    doAssert cmpIgnoreCase(getCurrentDir().splitDrive.drive, drive) == 0
+
+    # Test `\Users` path syntax on Windows by stripping away drive. `\`
+    # resolves to the drive in current working directory. This drive will be
+    # the same as `tempDir2` because of the `setCurrentDir` above.
+    doAssert pathNoDrive[0] == '\\'
+    createDir pathNoDrive / "test"
+    doAssert dirExists pathNoDrive / "test"
+    removeDir pathNoDrive / "test"
+
+    doAssert splitPath("//?/c:") == ("//?/c:", "")
+
+    doAssert relativePath("//?/c:///Users//me", "//?/c:", '/') == "Users/me"
+
+    doAssert parentDir(r"\\?\c:") == r""
+    doAssert parentDir(r"//?/c:/Users") == r"\\?\c:"
+    doAssert parentDir(r"\\localhost\c$") == r""
+    doAssert parentDir(r"\Users") == r"\"
+
+    doAssert tailDir("//?/c:") == ""
+    doAssert tailDir("//?/c:/Users") == "Users"
+    doAssert tailDir(r"\\localhost\c$\Windows\System32") == r"Windows\System32"
+
+    doAssert isRootDir("//?/c:")
+    doAssert isRootDir("//?/UNC/localhost/c$")
+    doAssert not isRootDir(r"\\?\c:\Users")
+
+    doAssert parentDirs(r"C:\Users", fromRoot = true).toSeq == @[r"C:\", r"C:\Users"]
+    doAssert parentDirs(r"C:\Users", fromRoot = false).toSeq == @[r"C:\Users", r"C:"]
+    doAssert parentDirs(r"\\?\c:\Users", fromRoot = true).toSeq ==
+      @[r"\\?\c:\", r"\\?\c:\Users"]
+    doAssert parentDirs(r"\\?\c:\Users", fromRoot = false).toSeq ==
+      @[r"\\?\c:\Users", r"\\?\c:"]
+    doAssert parentDirs(r"//localhost/c$/Users", fromRoot = true).toSeq ==
+      @[r"//localhost/c$/", r"//localhost/c$/Users"]
+    doAssert parentDirs(r"//?/UNC/localhost/c$/Users", fromRoot = false).toSeq ==
+      @[r"//?/UNC/localhost/c$/Users", r"\\?\UNC\localhost\c$"]
+    doAssert parentDirs(r"\Users", fromRoot = true).toSeq == @[r"\", r"\Users"]
+    doAssert parentDirs(r"\Users", fromRoot = false).toSeq == @[r"\Users", r"\"]
+
+    doAssert r"//?/c:" /../ "d/e" == r"\\?\c:\d\e"
+    doAssert r"//?/c:/Users" /../ "d/e" == r"\\?\c:\d\e"
+    doAssert r"\\localhost\c$" /../ "d/e" == r"\\localhost\c$\d\e"
+
+    doAssert splitFile("//?/c:") == ("//?/c:", "", "")
+    doAssert splitFile("//?/c:/Users") == ("//?/c:", "Users", "")
+    doAssert splitFile(r"\\localhost\c$\test.txt") == (r"\\localhost\c$", "test", ".txt")
+
+else:
+  block: # parentDirs
+    doAssert parentDirs("/home", fromRoot=true).toSeq == @["/", "/home"]
+    doAssert parentDirs("/home", fromRoot=false).toSeq == @["/home", "/"]
+    doAssert parentDirs("home", fromRoot=true).toSeq == @["home"]
+    doAssert parentDirs("home", fromRoot=false).toSeq == @["home"]
+
+    doAssert parentDirs("/home/user", fromRoot=true).toSeq == @["/", "/home/", "/home/user"]
+    doAssert parentDirs("/home/user", fromRoot=false).toSeq == @["/home/user", "/home", "/"]
+    doAssert parentDirs("home/user", fromRoot=true).toSeq == @["home/", "home/user"]
+    doAssert parentDirs("home/user", fromRoot=false).toSeq == @["home/user", "home"]
+
+
+# https://github.com/nim-lang/Nim/pull/19643#issuecomment-1235102314
+block:  # isValidFilename
+  # Negative Tests.
+  doAssert not isValidFilename("abcd", maxLen = 2)
+  doAssert not isValidFilename("0123456789", maxLen = 8)
+  doAssert not isValidFilename("con")
+  doAssert not isValidFilename("aux")
+  doAssert not isValidFilename("prn")
+  doAssert not isValidFilename("OwO|UwU")
+  doAssert not isValidFilename(" foo")
+  doAssert not isValidFilename("foo ")
+  doAssert not isValidFilename("foo.")
+  doAssert not isValidFilename("con.txt")
+  doAssert not isValidFilename("aux.bat")
+  doAssert not isValidFilename("prn.exe")
+  doAssert not isValidFilename("nim>.nim")
+  doAssert not isValidFilename(" foo.log")
+  # Positive Tests.
+  doAssert isValidFilename("abcd", maxLen = 42.Positive)
+  doAssert isValidFilename("c0n")
+  doAssert isValidFilename("foo.aux")
+  doAssert isValidFilename("bar.prn")
+  doAssert isValidFilename("OwO_UwU")
+  doAssert isValidFilename("cron")
+  doAssert isValidFilename("ux.bat")
+  doAssert isValidFilename("nim.nim")
+  doAssert isValidFilename("foo.log")
+
+block: # searchExtPos
+  doAssert "foo.nim".searchExtPos == 3
+  doAssert "/foo.nim".searchExtPos == 4
+  doAssert "".searchExtPos == -1
+  doAssert "/".searchExtPos == -1
+  doAssert "a.b/foo".searchExtPos == -1
+  doAssert ".".searchExtPos == -1
+  doAssert "foo.".searchExtPos == 3
+  doAssert "foo..".searchExtPos == 4
+  doAssert "..".searchExtPos == -1
+  doAssert "...".searchExtPos == -1
+  doAssert "./".searchExtPos == -1
+  doAssert "../".searchExtPos == -1
+  doAssert "/.".searchExtPos == -1
+  doAssert "/..".searchExtPos == -1
+  doAssert ".b".searchExtPos == -1
+  doAssert "..b".searchExtPos == -1
+  doAssert "/.b".searchExtPos == -1
+  doAssert "a/.b".searchExtPos == -1
+  doAssert ".a.b".searchExtPos == 2
+  doAssert "a/.b.c".searchExtPos == 4
+  doAssert "a/..b".searchExtPos == -1
+  doAssert "a/b..c".searchExtPos == 4
+
+  when doslikeFileSystem:
+    doAssert "c:a.b".searchExtPos == 3
+    doAssert "c:.a".searchExtPos == -1
+    doAssert r"c:\.a".searchExtPos == -1
+    doAssert "c:..a".searchExtPos == -1
+    doAssert r"c:\..a".searchExtPos == -1
+    doAssert "c:.a.b".searchExtPos == 4
diff --git a/tests/stdlib/tos_unc.nim b/tests/stdlib/tos_unc.nim
new file mode 100644
index 000000000..194deeb42
--- /dev/null
+++ b/tests/stdlib/tos_unc.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  disabled: "posix"
+"""
+
+# bug 10952, UNC paths
+import os
+import std/assertions
+
+doAssert r"\\hostname\foo\bar" / "baz" == r"\\hostname\foo\bar\baz"
+doAssert r"\\?\C:\foo" / "bar" == r"\\?\C:\foo\bar"
diff --git a/tests/stdlib/tosenv.nim b/tests/stdlib/tosenv.nim
new file mode 100644
index 000000000..17e397987
--- /dev/null
+++ b/tests/stdlib/tosenv.nim
@@ -0,0 +1,163 @@
+discard """
+  matrix: "--mm:refc; --mm:arc"
+  joinable: false
+  targets: "c js cpp"
+"""
+
+import std/os
+from std/sequtils import toSeq
+import stdtest/testutils
+
+when defined(nimPreviewSlimSystem):
+  import std/[assertions]
+
+# "LATIN CAPITAL LETTER AE" in UTF-8 (0xc386)
+const unicodeUtf8 = "\xc3\x86"
+
+template main =
+  block: # delEnv, existsEnv, getEnv, envPairs
+    for val in ["val", "", unicodeUtf8]: # ensures empty val works too
+      const key = "NIM_TESTS_TOSENV_KEY"
+      doAssert not existsEnv(key)
+
+      putEnv(key, "tempval")
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == "tempval"
+
+      putEnv(key, val) # change a key that already exists
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == val
+
+      doAssert (key, val) in toSeq(envPairs())
+      delEnv(key)
+      doAssert (key, val) notin toSeq(envPairs())
+      doAssert not existsEnv(key)
+      delEnv(key) # deleting an already deleted env var
+      doAssert not existsEnv(key)
+
+    block:
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == ""
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " "
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval"
+
+    whenVMorJs: discard # xxx improve
+    do:
+      doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE"))
+      doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE"))
+      doAssert not existsEnv("")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT")
+
+static: main()
+main()
+
+when defined(windows):
+  import std/widestrs
+  proc c_wgetenv(env: WideCString): WideCString {.importc: "_wgetenv", header: "<stdlib.h>".}
+proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
+
+when not defined(js) and not defined(nimscript):
+  when defined(nimPreviewSlimSystem):
+    import std/typedthreads
+  block: # bug #18533
+    var thr: Thread[void]
+    proc threadFunc {.thread.} = putEnv("foo", "fooVal2")
+
+    putEnv("foo", "fooVal1")
+    doAssert getEnv("foo") == "fooVal1"
+    createThread(thr, threadFunc)
+    joinThreads(thr)
+    when defined(windows):
+      doAssert getEnv("foo") == $c_wgetenv("foo".newWideCString)
+    else:
+      doAssert getEnv("foo") == $c_getenv("foo".cstring)
+
+    doAssertRaises(OSError): delEnv("foo=bar")
+
+when defined(windows) and not defined(nimscript):
+  import std/encodings
+
+  proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "<stdlib.h>".}
+  proc c_wputenv(env: WideCString): int32 {.importc: "_wputenv", header: "<stdlib.h>".}
+
+  block: # Bug #20083
+    # These test that `getEnv`, `putEnv` and `existsEnv` handle Unicode
+    # characters correctly. This means that module X in the process calling the
+    # CRT environment variable API will get the correct string. Raw CRT API
+    # calls below represent module X.
+
+    # Getting an env. var. with unicode characters returns the correct UTF-8
+    # encoded string.
+    block:
+      const envName = "twin_envvars1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Putting an env. var. with unicode characters gives the correct UTF-16
+    # encoded string from low-level routine.
+    block:
+      const envName = "twin_envvars2"
+      putEnv(envName, unicodeUtf8)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters is retrieved correctly
+    block:
+      const envName = unicodeUtf8 & "1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Env. name containing Unicode characters is set correctly
+    block:
+      const envName = unicodeUtf8 & "2"
+      putEnv(envName, unicodeUtf8)
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters and empty value is set correctly
+    block:
+      const envName = unicodeUtf8 & "3"
+      putEnv(envName, "")
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == ""
+
+    # It's hard to test on Windows code pages, because there is no "change
+    # a process' locale" API.
+    if getCurrentEncoding(true) == "windows-1252":
+      const
+        unicodeAnsi = "\xc6" # `unicodeUtf8` in `windows-1252` encoding
+
+      # Test that env. var. ANSI API has correct encoding
+      block:
+        const
+          envName = unicodeUtf8 & "4"
+          envNameAnsi = unicodeAnsi & "4"
+        putEnv(envName, unicodeUtf8)
+        doAssert $c_getenv(envNameAnsi.cstring) == unicodeAnsi
+
+      block:
+        const
+          envName = unicodeUtf8 & "5"
+          envNameAnsi = unicodeAnsi & "5"
+        doAssert c_putenv((envNameAnsi & "=" & unicodeAnsi).cstring) == 0
+        doAssert getEnv(envName) == unicodeUtf8
+
+      # Env. name containing Unicode characters and empty value is set correctly;
+      # and, if env. name. characters cannot be represented in codepage, don't
+      # raise an error.
+      #
+      # `win_setenv.nim` converts UTF-16 to ANSI when setting empty env. var. The
+      # windows-1250 locale has no representation of `abreveUtf8` below, so the
+      # conversion will fail, but this must not be fatal. It is expected that the
+      # routine ignores updating MBCS environment (`environ` global) and carries
+      # on.
+      block:
+        const
+          # "LATIN SMALL LETTER A WITH BREVE" in UTF-8
+          abreveUtf8 = "\xc4\x83"
+          envName = abreveUtf8 & "6"
+        putEnv(envName, "")
+        doAssert existsEnv(envName)
+        doAssert $c_wgetenv(envName.newWideCString) == ""
+        doAssert getEnv(envName) == ""
diff --git a/tests/stdlib/toserrors.nim b/tests/stdlib/toserrors.nim
new file mode 100644
index 000000000..e907dfe63
--- /dev/null
+++ b/tests/stdlib/toserrors.nim
@@ -0,0 +1,9 @@
+discard """
+  action: compile
+"""
+
+import std/oserrors
+
+let x1 = osLastError()
+raiseOSError(x1)
+echo osErrorMsg(x1)
diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim
new file mode 100644
index 000000000..da4f6252d
--- /dev/null
+++ b/tests/stdlib/tosproc.nim
@@ -0,0 +1,316 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+joinable: false
+"""
+
+#[
+joinable: false
+because it'd need cleanup up stdout
+
+see also: tests/osproc/*.nim; consider merging those into a single test here
+(easier to factor and test more things as a single self contained test)
+]#
+import std/[assertions, syncio]
+
+when defined(case_testfile): # compiled test file for child process
+  from posix import exitnow
+  proc c_exit2(code: cint): void {.importc: "_exit", header: "<unistd.h>".}
+  import os
+  var a = 0
+  proc fun(b = 0) =
+    a.inc
+    if a mod 10000000 == 0: # prevents optimizing it away
+      echo a
+    fun(b+1)
+
+  proc main() =
+    let args = commandLineParams()
+    echo (msg: "child binary", pid: getCurrentProcessId())
+    let arg = args[0]
+    echo (arg: arg)
+    case arg
+    of "exit_0":
+      if true: quit(0)
+    of "exit_1":
+      if true: quit(1)
+    of "exit_2":
+      if true: quit(2)
+    of "exit_42":
+      if true: quit(42)
+    of "exitnow_139":
+      if true: exitnow(139)
+    of "c_exit2_139":
+      if true: c_exit2(139)
+    of "quit_139":
+      # `exitStatusLikeShell` doesn't distinguish between a process that
+      # exit(139) and a process that gets killed with `SIGSEGV` because
+      # 139 = 11 + 128 = SIGSEGV + 128.
+      # However, as #10249 shows, this leads to bad debugging experience
+      # when a child process dies with SIGSEGV, leaving no trace of why it
+      # failed. The shell (and lldb debugger) solves that by inserting a
+      # helpful msg: `segmentation fault` when it detects a signal killed
+      # the child.
+      # todo: expose an API that will show more diagnostic, returning
+      # (exitCode, signal) instead of just `shellExitCode`.
+      if true: quit(139)
+    of "exit_recursion": # stack overflow by infinite recursion
+      fun()
+      echo a
+    of "exit_array": # bad array access
+      echo args[1]
+  main()
+
+elif defined(case_testfile2):
+  import strutils
+  let x = stdin.readLine()
+  echo x.parseInt + 5
+
+elif defined(case_testfile3):
+  echo "start ta_out"
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+
+  stderr.writeLine("to stderr")
+  stderr.flushFile()
+  stderr.writeLine("to stderr")
+  stderr.flushFile()
+
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+  echo "end ta_out"
+
+elif defined(case_testfile4):
+  import system # we could remove that
+  quit(QuitFailure)
+
+else: # main driver
+  import stdtest/[specialpaths, unittest_light]
+  import os, osproc, strutils
+  const nim = getCurrentCompilerExe()
+  const sourcePath = currentSourcePath()
+  let dir = getCurrentDir() / "tests" / "osproc"
+
+  template deferring(cleanup, body) =
+    try: body
+    finally: cleanup
+
+  # we're testing `execShellCmd` so don't rely on it to compile test file
+  # note: this should be exported in posix.nim
+  proc c_system(cmd: cstring): cint {.importc: "system", header: "<stdlib.h>".}
+
+  proc compileNimProg(opt: string, name: string): string =
+    result = buildDir / name.addFileExt(ExeExt)
+    let cmd = "$# c -o:$# --hints:off $# $#" % [nim.quoteShell, result.quoteShell, opt, sourcePath.quoteShell]
+    doAssert c_system(cmd) == 0, $cmd
+    doAssert result.fileExists
+
+  block execShellCmdTest:
+    let output = compileNimProg("-d:release -d:case_testfile", "D20190111T024543")
+
+    ## use it
+    template runTest(arg: string, expected: int) =
+      echo (arg2: arg, expected2: expected)
+      assertEquals execShellCmd(output & " " & arg), expected
+
+    runTest("exit_0", 0)
+    runTest("exitnow_139", 139)
+    runTest("c_exit2_139", 139)
+    when defined(posix):
+      runTest("quit_139", 127) # The quit value gets saturated to 127
+    else:
+      runTest("quit_139", 139)
+
+  block execCmdTest:
+    let output = compileNimProg("-d:release -d:case_testfile", "D20220705T221100")
+    doAssert execCmd(output & " exit_0") == 0
+    doAssert execCmd(output & " exit_1") == 1
+    doAssert execCmd(output & " exit_2") == 2
+    doAssert execCmd(output & " exit_42") == 42
+
+  import std/streams
+
+  block execProcessTest:
+    let dir = sourcePath.parentDir
+    let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim"))
+    doAssert err == 0
+    let exePath = dir / addFileExt("osproctest", ExeExt)
+    let outStr1 = execProcess(exePath, workingDir = dir, args = ["foo",
+        "b A r"], options = {})
+    doAssert outStr1 == dir & "\nfoo\nb A r\n"
+
+    const testDir = "t e st"
+    createDir(testDir)
+    doAssert dirExists(testDir)
+    let outStr2 = execProcess(exePath, workingDir = testDir, args = ["x yz"],
+        options = {})
+    doAssert outStr2 == absolutePath(testDir) & "\nx yz\n"
+
+    removeDir(testDir)
+
+    # test for PipeOutStream
+    var
+      p = startProcess(exePath, args = ["abcdefghi", "foo", "bar", "0123456"])
+      outStrm = p.peekableOutputStream
+
+    var tmp: string
+    doAssert outStrm.readLine(tmp)
+    doAssert outStrm.readChar == 'a'
+    doAssert outStrm.peekChar == 'b'
+    doAssert outStrm.readChar == 'b'
+    doAssert outStrm.readChar == 'c'
+    doAssert outStrm.peekChar == 'd'
+    doAssert outStrm.peekChar == 'd'
+    doAssert outStrm.readChar == 'd'
+    doAssert outStrm.readStr(2) == "ef"
+    doAssert outStrm.peekStr(2) == "gh"
+    doAssert outStrm.peekStr(2) == "gh"
+    doAssert outStrm.readStr(1) == "g"
+    doAssert outStrm.readStr(3) == "hi\n"
+
+    doAssert outStrm.readLine == "foo"
+    doAssert outStrm.readChar == 'b'
+    doAssert outStrm.peekChar == 'a'
+    doAssert outStrm.readLine == "ar"
+
+    tmp.setLen(4)
+    tmp[0] = 'n'
+    doAssert outStrm.readDataStr(tmp, 1..3) == 3
+    doAssert tmp == "n012"
+    doAssert outStrm.peekStr(3) == "345"
+    doAssert outStrm.readDataStr(tmp, 1..2) == 2
+    doAssert tmp == "n342"
+    doAssert outStrm.peekStr(2) == "56"
+    doAssert outStrm.readDataStr(tmp, 0..3) == 3
+    doAssert tmp == "56\n2"
+    p.close
+
+    p = startProcess(exePath, args = ["123"])
+    outStrm = p.peekableOutputStream
+    let c = outStrm.peekChar
+    doAssert outStrm.readLine(tmp)
+    doAssert tmp[0] == c
+    tmp.setLen(7)
+    doAssert outStrm.peekData(addr tmp[0], 7) == 4
+    doAssert tmp[0..3] == "123\n"
+    doAssert outStrm.peekData(addr tmp[0], 7) == 4
+    doAssert tmp[0..3] == "123\n"
+    doAssert outStrm.readData(addr tmp[0], 7) == 4
+    doAssert tmp[0..3] == "123\n"
+    p.close
+
+    try:
+      removeFile(exePath)
+    except OSError:
+      discard
+
+  block: # test for startProcess (more tests needed)
+    # bugfix: windows stdin.close was a noop and led to blocking reads
+    proc startProcessTest(command: string, options: set[ProcessOption] = {
+                    poStdErrToStdOut, poUsePath}, input = ""): tuple[
+                    output: string,
+                    exitCode: int] {.tags:
+                    [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
+      var p = startProcess(command, options = options + {poEvalCommand})
+      var outp = outputStream(p)
+      if input.len > 0: inputStream(p).write(input)
+      close inputStream(p)
+      result = ("", -1)
+      var line = newStringOfCap(120)
+      while true:
+        if outp.readLine(line):
+          result[0].add(line)
+          result[0].add("\n")
+        else:
+          result[1] = peekExitCode(p)
+          if result[1] != -1: break
+      close(p)
+
+    var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4")
+    doAssert result == ("12\n", 0)
+
+  block: # startProcess stdin (replaces old test `tstdin` + `ta_in`)
+    let output = compileNimProg("-d:case_testfile2", "D20200626T215919")
+    var p = startProcess(output, dir) # dir not needed though
+    p.inputStream.write("5\n")
+    p.inputStream.flush()
+    var line = ""
+    var s: seq[string]
+    while p.outputStream.readLine(line):
+      s.add line
+    doAssert s == @["10"]
+
+  block:
+    let output = compileNimProg("-d:case_testfile3", "D20200626T221233")
+    var x = newStringOfCap(120)
+    block: # startProcess stdout poStdErrToStdOut (replaces old test `tstdout` + `ta_out`)
+      var p = startProcess(output, dir, options={poStdErrToStdOut})
+      deferring: p.close()
+      do:
+        var sout: seq[string]
+        while p.outputStream.readLine(x): sout.add x
+        doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stderr", "to stderr", "to stdout", "to stdout", "end ta_out"]
+    block: # startProcess stderr (replaces old test `tstderr` + `ta_out`)
+      var p = startProcess(output, dir, options={})
+      deferring: p.close()
+      do:
+        var serr, sout: seq[string]
+        while p.errorStream.readLine(x): serr.add x
+        while p.outputStream.readLine(x): sout.add x
+        doAssert serr == @["to stderr", "to stderr"]
+        doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stdout", "to stdout", "end ta_out"]
+
+  block: # startProcess exit code (replaces old test `texitcode` + `tafalse`)
+    let output = compileNimProg("-d:case_testfile4", "D20200626T224758")
+    var p = startProcess(output, dir)
+    doAssert waitForExit(p) == QuitFailure
+    p = startProcess(output, dir)
+    var running = true
+    while running:
+      # xxx: avoid busyloop?
+      running = running(p)
+    doAssert waitForExit(p) == QuitFailure
+
+    # make sure that first call to running() after process exit returns false
+    p = startProcess(output, dir)
+    for j in 0..<30: # refs #13449
+      os.sleep(50)
+      if not running(p): break
+    doAssert not running(p)
+    doAssert waitForExit(p) == QuitFailure # avoid zombies
+
+  import std/strtabs
+  block execProcessTest:
+    var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4")
+    stripLineEnd(result[0])
+    doAssert result == ("12", 0)
+    when not defined(windows):
+      doAssert execCmdEx("ls --nonexistent").exitCode != 0
+    when false:
+      # bug: on windows, this raises; on posix, passes
+      doAssert execCmdEx("nonexistent").exitCode != 0
+    when defined(posix):
+      doAssert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0)
+      doAssert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0)
+
+  block: # bug #17749
+    let output = compileNimProg("-d:case_testfile4", "D20210417T011153")
+    var p = startProcess(output, dir)
+    let inp = p.inputStream
+    var count = 0
+    when defined(windows):
+      # xxx we should make osproc.hsWriteData raise IOError on windows, consistent
+      # with posix; we could also (in addition) make IOError a subclass of OSError.
+      type SIGPIPEError = OSError
+    else:
+      type SIGPIPEError = IOError
+    doAssertRaises(SIGPIPEError):
+      for i in 0..<100000:
+        count.inc
+        inp.writeLine "ok" # was giving SIGPIPE and crashing
+    doAssert count >= 100
+    doAssert waitForExit(p) == QuitFailure
+    close(p) # xxx isn't that missing in other places?
diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim
index 7fc6c5d85..93b0317f7 100644
--- a/tests/stdlib/tosprocterminate.nim
+++ b/tests/stdlib/tosprocterminate.nim
@@ -1,7 +1,16 @@
-import os, osproc
+discard """
+  cmd: "nim $target $options -r $file"
+  targets: "c cpp"
+  matrix: "--mm:refc; --mm:orc"
+"""
 
-when defined(Windows):
+import os, osproc, times, std / monotimes
+import std/assertions
+
+when defined(windows):
   const ProgramWhichDoesNotEnd = "notepad"
+elif defined(openbsd):
+  const ProgramWhichDoesNotEnd = "/bin/cat"
 else:
   const ProgramWhichDoesNotEnd = "/bin/sh"
 
@@ -15,7 +24,21 @@ while process.running() and TimeToWait > 0:
   sleep(100)
   TimeToWait = TimeToWait - 100
 
-if process.running():
-  echo("FAILED")
-else:
-  echo("SUCCESS")
+doAssert not process.running()
+echo("stopped process")
+
+process.close()
+
+echo("starting " & ProgramWhichDoesNotEnd)
+process = startProcess(ProgramWhichDoesNotEnd)
+echo("process should be stopped after 2s")
+
+let start = getMonoTime()
+discard process.waitForExit(2000)
+let took = getMonoTime() - start
+
+doAssert not process.running()
+# some additional time to account for overhead
+doAssert took < initDuration(seconds = 3)
+
+echo("stopped process after ", took)
diff --git a/tests/stdlib/tpackedsets.nim b/tests/stdlib/tpackedsets.nim
new file mode 100644
index 000000000..f519c08a7
--- /dev/null
+++ b/tests/stdlib/tpackedsets.nim
@@ -0,0 +1,265 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/packedsets
+import std/sets
+
+import sequtils
+import algorithm
+
+import std/assertions
+
+block basicIntSetTests:
+  var y = initPackedSet[int]()
+  y.incl(1)
+  y.incl(2)
+  y.incl(7)
+  y.incl(1056)
+
+  y.incl(1044)
+  y.excl(1044)
+
+  doAssert y == [1, 2, 7, 1056].toPackedSet
+  doAssert toSeq(y.items) == [1, 2, 7, 1056]
+
+  doAssert y.containsOrIncl(888) == false
+  doAssert 888 in y
+  doAssert y.containsOrIncl(888) == true
+
+  doAssert y.missingOrExcl(888) == false
+  doAssert 888 notin y
+  doAssert y.missingOrExcl(888) == true
+
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+template sortedItems(t: untyped): untyped = sorted(toSeq(t))
+
+type Id = distinct int
+proc `$`(x: Id): string {.borrow.}
+proc cmp(a: Id, b: Id): int {.borrow.}
+proc `==`(a: Id, b: Id): bool {.borrow.}
+proc `<`(a: Id, b: Id): bool {.borrow.}
+
+block genericTests: 
+  # we use HashSet as groundtruth, it's well tested elsewhere
+  template testDel(A: typedesc, t: typed, t0: typed) =
+
+    block:
+      template checkEquals() =
+        doAssert t.len == t0.len
+        for k in t0:
+          doAssert k in t
+        for k in t:
+          doAssert k in t0
+
+        doAssert sortedItems(t) == sortedItems(t0)
+
+      template incl2(i) =
+        t.incl i
+        t0.incl i
+
+      template excl2(i) =
+        t.excl i
+        t0.excl i
+
+      var expected: seq[A]
+      let n = 100
+      let n2 = n*2
+      for i in 0..<n:
+        incl2(A(i))
+      checkEquals()
+      for i in 0..<n:
+        if i mod 3 == 0:
+          if i < n div 2:
+            excl2(A(i))
+          else:
+            t0.excl A(i)
+            doAssert A(i) in t
+            doAssert not t.missingOrExcl A(i)
+
+      checkEquals()
+      for i in n..<n2:
+        incl2(A(i))
+      checkEquals()
+      for i in 0..<n2:
+        if i mod 7 == 0:
+          excl2(A(i))
+      checkEquals()
+
+      # notin check
+      for i in 0..<t.len:
+        if i mod 7 == 0:
+          doAssert A(i) notin t0
+          doAssert A(i) notin t
+          # issue #13505
+          doAssert t.missingOrExcl(A(i))
+
+  var t: PackedSet[int]
+  var t0: HashSet[int]
+  testDel(int, t, t0)
+
+  var distT: PackedSet[Id]
+  var distT0: HashSet[Id]
+  testDel(Id, distT, distT0)
+
+  doAssert union(distT, initPackedSet[Id]()) == distT
+
+  var charT: PackedSet[char]
+  var charT0: HashSet[char]
+  testDel(char, charT, charT0)
+
+
+block typeSafetyTest:
+  # mixing sets of different types shouldn't compile
+  doAssert not compiles( union(initPackedSet[Id](), initPackedSet[int]()) )
+  doAssert     compiles( union(initPackedSet[Id](), initPackedSet[Id]()))
+
+  var ids: PackedSet[Id]
+  doAssert not compiles( ids.incl(3) )
+  doAssert     compiles( ids.incl(Id(3)) )
+
+  type NonOrdinal = string
+  doAssert not compiles( initPackedSet[NonOrdinal]() )
+
+type EnumABCD = enum A, B, C, D
+
+block enumTest:
+  var letterSet = initPackedSet[EnumABCD]()
+
+  for x in [A, C]:
+    letterSet.incl(x)
+
+  doAssert A in letterSet
+  doAssert B notin letterSet
+  doAssert C in letterSet
+  doAssert D notin letterSet
+
+type Foo = distinct int16
+proc `$`(a: Foo): string {.borrow.} # `echo a` below won't work without `$` defined, as expected
+
+block printTest:
+  var a = initPackedSet[EnumABCD]()
+  a.incl A
+  a.incl C 
+  doAssert $a == "{A, C}"
+
+import intsets
+
+block legacyMainModuleTests:
+  template genericTests(A: typedesc[Ordinal], x: typed) =
+    block:
+      proc typSeq(s: seq[int]): seq[A] = s.map(proc (i: int): A = A(i))
+      x.incl(A(1))
+      x.incl(A(2))
+      x.incl(A(7))
+      x.incl(A(1056))
+
+      x.incl(A(1044))
+      x.excl(A(1044))
+
+      doAssert x == typSeq(@[1, 2, 7, 1056]).toPackedSet
+
+      doAssert x.containsOrIncl(A(888)) == false
+      doAssert A(888) in x
+      doAssert x.containsOrIncl(A(888)) == true
+
+      doAssert x.missingOrExcl(A(888)) == false
+      doAssert A(888) notin x
+      doAssert x.missingOrExcl(A(888)) == true
+
+      var xs = toSeq(items(x))
+      xs.sort(cmp[A])
+      doAssert xs == typSeq(@[1, 2, 7, 1056])
+
+      var y: PackedSet[A]
+      assign(y, x)
+      var ys = toSeq(items(y))
+      ys.sort(cmp[A])
+      doAssert ys == typSeq(@[1, 2, 7, 1056])
+
+      doAssert x == y
+
+      var z: PackedSet[A]
+      for i in 0..1000:
+        incl z, A(i)
+        doAssert z.len() == i+1
+      for i in 0..1000:
+        doAssert z.contains(A(i))
+
+      var w = initPackedSet[A]()
+      w.incl(A(1))
+      w.incl(A(4))
+      w.incl(A(50))
+      w.incl(A(1001))
+      w.incl(A(1056))
+
+      var xuw = x.union(w)
+      var xuws = toSeq(items(xuw))
+      xuws.sort(cmp)
+      doAssert xuws == typSeq(@[1, 2, 4, 7, 50, 1001, 1056])
+
+      var xiw = x.intersection(w)
+      var xiws = toSeq(items(xiw))
+      xiws.sort(cmp)
+      doAssert xiws == @[A(1), A(1056)]
+
+      var xdw = x.difference(w)
+      var xdws = toSeq(items(xdw))
+      xdws.sort(cmp[A])
+      doAssert xdws == @[A(2), A(7)]
+
+      var xsw = x.symmetricDifference(w)
+      var xsws = toSeq(items(xsw))
+      xsws.sort(cmp[A])
+      doAssert xsws == typSeq(@[2, 4, 7, 50, 1001])
+
+      x.incl(w)
+      xs = toSeq(items(x))
+      xs.sort(cmp[A])
+      doAssert xs == typSeq(@[1, 2, 4, 7, 50, 1001, 1056])
+
+      doAssert w <= x
+
+      doAssert w < x
+
+      doAssert(not disjoint(w, x))
+
+      var u = initPackedSet[A]()
+      u.incl(A(3))
+      u.incl(A(5))
+      u.incl(A(500))
+      doAssert disjoint(u, x)
+
+      var v = initPackedSet[A]()
+      v.incl(A(2))
+      v.incl(A(50))
+
+      x.excl(v)
+      xs = toSeq(items(x))
+      xs.sort(cmp[A])
+      doAssert xs == typSeq(@[1, 4, 7, 1001, 1056])
+
+      proc bug12366 =
+        var
+          x = initPackedSet[A]()
+          y = initPackedSet[A]()
+          n = 3584
+
+        for i in 0..n:
+          x.incl(A(i))
+          y.incl(A(i))
+
+        let z = symmetricDifference(x, y)
+        doAssert z.len == 0
+        doAssert $z == "{}"
+
+      bug12366()
+
+  var legacyInit = initIntSet()
+  genericTests(int, legacyInit)
+
+  var intGenericInit = initPackedSet[int]()
+  genericTests(int, intGenericInit)
+
+  var intDistinct = initPackedSet[Id]()
+  genericTests(Id, intDistinct)
diff --git a/tests/stdlib/tparscfg.nim b/tests/stdlib/tparscfg.nim
deleted file mode 100644
index fc735f3eb..000000000
--- a/tests/stdlib/tparscfg.nim
+++ /dev/null
@@ -1,69 +0,0 @@
-discard """
-output: '''
-utf-8
-on
-hello
-lihf8515
-10214028
-lihaifeng@wxm.com
-===
-charset=utf-8
-[Package]
-name=hello
---threads:on
-[Author]
-name=lhf
-qq=10214028
-email="lihaifeng@wxm.com"
-===
-charset=utf-8
-[Package]
-name=hello
---threads:on
-[Author]
-name=lihf8515
-qq=10214028
-'''
-"""
-import parsecfg, streams
-
-## Creating a configuration file.
-var dict1=newConfig()
-dict1.setSectionKey("","charset","utf-8")
-dict1.setSectionKey("Package","name","hello")
-dict1.setSectionKey("Package","--threads","on")
-dict1.setSectionKey("Author","name","lihf8515")
-dict1.setSectionKey("Author","qq","10214028")
-dict1.setSectionKey("Author","email","lihaifeng@wxm.com")
-var ss = newStringStream()
-dict1.writeConfig(ss)
-
-## Reading a configuration file.
-var dict2 = loadConfig(newStringStream(ss.data))
-var charset = dict2.getSectionValue("","charset")
-var threads = dict2.getSectionValue("Package","--threads")
-var pname = dict2.getSectionValue("Package","name")
-var name = dict2.getSectionValue("Author","name")
-var qq = dict2.getSectionValue("Author","qq")
-var email = dict2.getSectionValue("Author","email")
-echo charset
-echo threads
-echo pname
-echo name
-echo qq
-echo email
-
-echo "==="
-
-## Modifying a configuration file.
-var dict3 = loadConfig(newStringStream(ss.data))
-dict3.setSectionKey("Author","name","lhf")
-write(stdout, $dict3)
-
-echo "==="
-
-## Deleting a section key in a configuration file.
-var dict4 = loadConfig(newStringStream(ss.data))
-dict4.delSectionKey("Author","email")
-write(stdout, $dict4)
-
diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim
index 1c214e5d2..2600d6f66 100644
--- a/tests/stdlib/tparsecfg.nim
+++ b/tests/stdlib/tparsecfg.nim
@@ -1,23 +1,132 @@
 discard """
-  output: '''OK'''
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
 """
 
-#bug #6046
-import parsecfg
-
-var config = newConfig()
-config.setSectionKey("foo","bar","-1")
-config.setSectionKey("foo","foo","abc")
-config.writeConfig("test.ini")
-
-# test.ini now contains
-# [foo]
-# bar=-1
-# foo=abc
-
-var config2 = loadConfig("test.ini")
-let bar = config2.getSectionValue("foo","bar")
-let foo = config2.getSectionValue("foo","foo")
-assert(bar == "-1")
-assert(foo == "abc")
-echo "OK"
+import parsecfg, streams, sequtils
+import std/assertions
+
+when not defined(js):
+  from stdtest/specialpaths import buildDir
+  import os
+  # bug #6046
+  block:
+    var config = newConfig()
+    config.setSectionKey("foo", "bar", "-1")
+    config.setSectionKey("foo", "foo", "abc")
+
+    const file = buildDir / "tparsecfg.ini"
+    config.writeConfig(file)
+
+    # file now contains
+    # [foo]
+    # bar=-1
+    # foo=abc
+
+    var config2 = loadConfig(file)
+    let bar = config2.getSectionValue("foo", "bar")
+    let foo = config2.getSectionValue("foo", "foo")
+    doAssert(bar == "-1")
+    doAssert(foo == "abc")
+
+## Creating a configuration file.
+var dict1 = newConfig()
+dict1.setSectionKey("", "charset", "utf-8")
+dict1.setSectionKey("Package", "name", "hello")
+dict1.setSectionKey("Package", "--threads", "on")
+dict1.setSectionKey("Author", "name", "lihf8515")
+dict1.setSectionKey("Author", "qq", "10214028")
+dict1.setSectionKey("Author", "email", "lihaifeng@wxm.com")
+var ss = newStringStream()
+dict1.writeConfig(ss)
+
+## Reading a configuration file.
+let dict2 = loadConfig(newStringStream(ss.data))
+doAssert dict2.getSectionValue("", "charset") == "utf-8"
+doAssert dict2.getSectionValue("Package", "--threads") == "on"
+doAssert dict2.getSectionValue("Package", "name") == "hello"
+doAssert dict2.getSectionValue("Author", "name") == "lihf8515"
+doAssert dict2.getSectionValue("Author", "qq") == "10214028"
+doAssert dict2.getSectionValue("Author", "email") == "lihaifeng@wxm.com"
+doAssert toSeq(dict2.sections) == @["", "Package", "Author"]
+
+## Modifying a configuration file.
+var dict3 = loadConfig(newStringStream(ss.data))
+dict3.setSectionKey("Author", "name", "lhf")
+doAssert $dict3 == """charset=utf-8
+[Package]
+name=hello
+--threads:on
+[Author]
+name=lhf
+qq=10214028
+email="lihaifeng@wxm.com"
+"""
+
+## Deleting a section key in a configuration file.
+var dict4 = loadConfig(newStringStream(ss.data))
+dict4.delSectionKey("Author", "email")
+doAssert $dict4 == """charset=utf-8
+[Package]
+name=hello
+--threads:on
+[Author]
+name=lihf8515
+qq=10214028
+"""
+
+block:
+  var dict = loadConfig(newStringStream("""[Simple Values]
+  key=value
+  spaces in keys=allowed
+  spaces in values=allowed as well
+  spaces around the delimiter = obviously
+  you can also use : to delimit keys from values
+  [All Values Are Strings]
+  values like this: 19990429
+  or this: 3.14159265359
+  are they treated as numbers : no
+  integers floats and booleans are held as: strings
+  can use the API to get converted values directly: true
+  [No Values]
+  key_without_value
+  # empty string value is not allowed =
+  [ Seletion A   ]
+  space around section name will be ignored
+  [You can use comments]
+  # like this
+  ; or this
+  # By default only in an empty line.
+  # Inline comments can be harmful because they prevent users
+  # from using the delimiting characters as parts of values.
+  # That being said, this can be customized.
+      [Sections Can Be Indented]
+          can_values_be_as_well = True
+          does_that_mean_anything_special = False
+          purpose = formatting for readability
+          # Did I mention we can indent comments, too?
+  """)
+  )
+
+  let section1 = "Simple Values"
+  doAssert dict.getSectionValue(section1, "key") == "value"
+  doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed"
+  doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well"
+  doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously"
+  doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values"
+
+  let section2 = "All Values Are Strings"
+  doAssert dict.getSectionValue(section2, "values like this") == "19990429"
+  doAssert dict.getSectionValue(section2, "or this") == "3.14159265359"
+  doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no"
+  doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings"
+  doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true"
+
+  let section3 = "Seletion A"
+  doAssert dict.getSectionValue(section3, 
+    "space around section name will be ignored", "not an empty value") == ""
+
+  let section4 = "Sections Can Be Indented"
+  doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True"
+  doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False"
+  doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability"
diff --git a/tests/stdlib/tparsecsv.nim b/tests/stdlib/tparsecsv.nim
new file mode 100644
index 000000000..5a1e41bce
--- /dev/null
+++ b/tests/stdlib/tparsecsv.nim
@@ -0,0 +1,36 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+include parsecsv
+import strutils, os
+import std/assertions
+
+block: # Tests for reading the header row
+  let content = "\nOne,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n"
+  writeFile("temp.csv", content)
+
+  var p: CsvParser
+  p.open("temp.csv")
+  p.readHeaderRow()
+  while p.readRow():
+    let zeros = repeat('0', p.currRow-2)
+    doAssert p.rowEntry("One") == "1" & zeros
+    doAssert p.rowEntry("Two") == "2" & zeros
+    doAssert p.rowEntry("Three") == "3" & zeros
+    doAssert p.rowEntry("Four") == "4" & zeros
+  p.close()
+
+  when not defined(testing):
+    var parser: CsvParser
+    parser.open("temp.csv")
+    parser.readHeaderRow()
+    while parser.readRow():
+      echo "new row: "
+      for col in items(parser.headers):
+        echo "##", col, ":", parser.rowEntry(col), "##"
+    parser.close()
+    removeFile("temp.csv")
+
+  # Tidy up
+  removeFile("temp.csv")
diff --git a/tests/stdlib/tparseipv6.nim b/tests/stdlib/tparseipv6.nim
index 3e1c23e58..31ec4ecfb 100644
--- a/tests/stdlib/tparseipv6.nim
+++ b/tests/stdlib/tparseipv6.nim
@@ -1,4 +1,5 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
   output: "all ok"
 """
 
@@ -8,23 +9,23 @@ const
   positives = [
     "::f:8:a8f:218.17.235.229",
     "::b:228.19.241.2",
-    "::8:c:a:f:8.35.8.096",
-    "::3:e:a:bc:04.19.2.9",
+    "::8:c:a:f:8.35.8.96",
+    "::3:e:a:bc:4.19.2.9",
     "::2:212.242.248.19",
     "::df:a5f:3.250.208.9",
     "::8:c:5:e63:250.208.249.0",
     "::b:f:181.12.9.98",
-    "::a:f8:77.08.243.232",
-    "::a:b:85:e4d9:252.9.229.056",
+    "::a:f8:77.8.243.232",
+    "::a:b:85:e4d9:252.9.229.56",
     "941:c:8a:c:e::917",
     "e8:7a:e:ad:88a:8:203.235.225.46",
-    "139c:9e::f8:254.08.21.249",
+    "139c:9e::f8:254.8.21.249",
     "b38:f0:e::f9:89.6.12.18",
     "ef::8",
     "5::ab",
     "a::8:255.247.96.253",
     "b:c0::c:254.248.95.254",
-    "::8c:2:99.251.024.3",
+    "::8c:2:99.251.24.3",
     "98::c:247.240.249.57",
     "9::9",
     "628::f1ed:f",
@@ -106,68 +107,68 @@ const
     "::315",
     "::a:a",
     "::aed3:a",
-    "f0eb:0:e8:b:c:a:254.098.233.17",
+    "f0eb:0:e8:b:c:a:254.98.233.17",
     "bfa:7fc:c66d:15:e9a:ded:254.119.9.9",
-    "d:ffa8:9:a:879:3:202.39.08.245",
+    "d:ffa8:9:a:879:3:202.39.8.245",
     "8e:2:8:fa8a:f1d1:1aa8:252.254.245.81",
-    "5:d4:a:e9:8:8:06.38.98.253",
-    "9c5:4:a5c:f:a6:8c9d:05.250.8.2",
+    "5:d4:a:e9:8:8:6.38.98.253",
+    "9c5:4:a5c:f:a6:8c9d:5.250.8.2",
     "d19a:2:f808:be:f:c:98.86.197.249",
-    "8:26ac:8:8:cb:f:242.00.254.85",
+    "8:26ac:8:8:cb:f:242.0.254.85",
     "38:e:1:0b88:f:0:8.89.248.92",
-    "e7:ff96:a:f:f:b:253.91.052.195",
+    "e7:ff96:a:f:f:b:253.91.52.195",
     "d:8:2:5:894:5:254.0.240.199",
     "2:98:9:8aa:9c8f:fa:252.98.248.17",
-    "e9:d4f:890:ccbe:5:8:088.200.228.216",
+    "e9:d4f:890:ccbe:5:8:88.200.228.216",
     "3:3:9:5:6a:df5:255.251.8.12",
-    "0280:3:8:8:4:9:255.000.251.249",
+    "0280:3:8:8:4:9:255.0.251.249",
     "8:af7:db:aa:0:9:238.248.250.255",
-    "ff:ee:9a:9252:a:289:059.083.18.255",
+    "ff:ee:9a:9252:a:289:59.83.18.255",
     "9f6:5:fc9:b:a89:a:142.1.250.254",
     "e:981a:da:bf94:9:f8:254.242.18.95",
     "3c:1:4:f2:89:f:8.91.255.14",
-    "e::9a2:c:9.050.80.8",
+    "e::9a2:c:9.50.80.8",
     "9::4a:07:fb:211.241.254.228",
     "9be::2:e:215.189.48.188",
-    "f::f:d:069.148.99.168",
+    "f::f:d:69.148.99.168",
     "f::a:97.18.240.47",
     "c::a98e:1:251.253.252.254",
     "668::82:214.87.208.9",
     "9c0::cf0:ecb:253.208.238.255",
-    "a::0:f1:210.240.238.049",
-    "8::a:1:251.238.34.09",
+    "a::0:f1:210.240.238.49",
+    "8::a:1:251.238.34.9",
     "81:dfe::b8:8.255.249.248",
-    "d3::7:b:9:83.189.08.244",
-    "8::9:8:8:00.7.11.252",
+    "d3::7:b:9:83.189.8.244",
+    "8::9:8:8:0.7.11.252",
     "2:8::c:a8:250.221.9.249",
     "2::f:99.8.249.247",
     "c:22f5::5:2c:243.15.79.89",
     "e:8e::da:251.243.255.2",
     "f15f:9::a:255.70.247.218",
-    "f:b::9f38:31.220.94.022",
-    "9::9a48:03.98.249.119",
+    "f:b::9f38:31.220.94.22",
+    "9::9a48:3.98.249.119",
     "d:d:9b87::2d:a:249.253.38.8",
     "d86d:99b::a9b:5:242.236.8.244",
     "eb:3::f:9cf:1.253.1.228",
     "b::ba2:255.247.114.64",
-    "2f:ec:bcb::9:219.254.250.094",
+    "2f:ec:bcb::9:219.254.250.94",
     "da8a:f6::a:e0:19.251.241.251",
-    "5e:c1::a:021.250.8.254",
+    "5e:c1::a:21.250.8.254",
     "c:9::8c9b:248.219.212.252",
     "2:a::8d4a:216.255.198.223",
-    "1f::66:255.30.08.150",
+    "1f::66:255.30.8.150",
     "bc2b:8f::2ff9:6.245.99.230",
     "a:8::a8:9.251.246.255",
-    "f:7:7::98:06.14.1.208",
+    "f:7:7::98:6.14.1.208",
     "e:2::9:218.249.255.254",
     "79:f::6:250.255.98.246",
-    "47:9:fb9f::9:038.136.17.251",
+    "47:9:fb9f::9:38.136.17.251",
     "ed::a:247.9.23.239",
     "6f::f1:88.254.119.9",
     "a::d:218.199.236.0",
-    "fc88::9:203.196.04.95",
-    "::8.048.255.85",
-    "::253.07.255.36",
+    "fc88::9:203.196.4.95",
+    "::8.48.255.85",
+    "::253.7.255.36",
     "9:d::253.7.178.229",
     "::250.84.158.253",
     "::8.55.204.248",
@@ -175,39 +176,47 @@ const
     "df9:88ca::248.255.108.17",
     "8e9b::250.206.0.82",
     "::209.8.254.209",
-    "::247.088.8.8",
+    "::247.88.8.8",
     "::cb:f:ba41:250.208.19.249",
     "::fe:0e8:243.240.229.5",
     "::c:223.251.5.226",
-    "::8:08.03.8.250",
+    "::8:8.3.8.250",
     "::f:8.88.11.255",
-    "::fda:48:aa:05.189.07.2",
-    "::8:c3f:f:240.06.212.255",
+    "::fda:48:aa:5.189.7.2",
+    "::8:c3f:f:240.6.212.255",
     "::f:0aa:244.123.99.16",
-    "::c9b5:c:034.8.090.196",
+    "::c9b5:c:34.8.90.196",
     "::98:c9:254.14.241.81"
   ]
   negatives = ["foo.bar",
     "::::::::::::",
     "yet another failure",
-    "de:6:c:ab5:6a::9:252.06.06.249",
-    "f9:5f7:fa38:9:b::b6:09.255.248.252",
+    "de:6:c:ab5:6a::9:252.6.6.249",
+    "f9:5f7:fa38:9:b::b6:9.255.248.252",
     "97:c:5b:81:8a::f5dd:144.252.250.9",
-    "9:8:cd:8:a9::f:247.255.09.255",
+    "9:8:cd:8:a9::f:247.255.9.255",
     "18:1:8c:2:3::9:8.254.252.139",
-    "e:c298:3:e:a::bb12:254.246.05.250",
+    "e:c298:3:e:a::bb12:254.246.5.250",
     "e:e:c:8e:fd::8:253.8.49.231",
     "9:97f:f:e929:8a::c9:0.8.252.10",
-    "0df:b24:7:89:c::2b:16.249.240.092",
+    "0df:b24:7:89:c::2b:16.249.240.92",
     "b:8f5f:485:c:9a::84c:178.7.249.34",
+    "::3:e:a:bc:091.19.2.9",
+    "::a:f8:77.08.243.232",
+    "::8c:2:99.251.029.3",
+    "::8:c:a:f:8.35.8.096",
+    "d:ffa8:9:a:879:3:0202.39.8.245",
+    "139c:9e::f8:254.07.21.249",
+    "f0eb:0:e8:b:c:a:254.233.043.17",
+    "::a:b:85:e4d9:252.9.229.056",
   ]
 
-proc ok(pos: openarray[string]) =
+proc ok(pos: openArray[string]) =
   for p in pos:
     if not isIpAddress(p):
       echo "failure ", p
 
-proc notok(neg: openarray[string]) =
+proc notok(neg: openArray[string]) =
   for n in neg:
     if isIpAddress(n):
       echo "failure ", n
diff --git a/tests/stdlib/tparsesql.nim b/tests/stdlib/tparsesql.nim
index 126020ed6..cd582551d 100644
--- a/tests/stdlib/tparsesql.nim
+++ b/tests/stdlib/tparsesql.nim
@@ -1,11 +1,23 @@
 discard """
-  file: "tparsesql.nim"
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
 """
-
 import parsesql
+import std/assertions
+
+doAssert treeRepr(parseSql("INSERT INTO STATS VALUES (10, 5.5); ")
+) == """
 
-doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;"
-doAssert $parseSQL("""
+nkStmtList
+  nkInsert
+    nkIdent STATS
+    nkNone
+    nkValueList
+      nkIntegerLit 10
+      nkNumericLit 5.5"""
+
+doAssert $parseSql("SELECT foo FROM table;") == "select foo from table;"
+doAssert $parseSql("""
 SELECT
   CustomerName,
   ContactName,
@@ -21,26 +33,26 @@ SELECT
   Country
 FROM table;""") == "select CustomerName, ContactName, Address, City, PostalCode, Country, CustomerName, ContactName, Address, City, PostalCode, Country from table;"
 
-doAssert $parseSQL("SELECT foo FROM table limit 10") == "select foo from table limit 10;"
-doAssert $parseSQL("SELECT foo, bar, baz FROM table limit 10") == "select foo, bar, baz from table limit 10;"
-doAssert $parseSQL("SELECT foo AS bar FROM table") == "select foo as bar from table;"
-doAssert $parseSQL("SELECT foo AS foo_prime, bar AS bar_prime, baz AS baz_prime FROM table") == "select foo as foo_prime, bar as bar_prime, baz as baz_prime from table;"
-doAssert $parseSQL("SELECT * FROM table") == "select * from table;"
-doAssert $parseSQL("SELECT count(*) FROM table") == "select count(*) from table;"
-doAssert $parseSQL("SELECT count(*) as 'Total' FROM table") == "select count(*) as 'Total' from table;"
-doAssert $parseSQL("SELECT count(*) as 'Total', sum(a) as 'Aggr' FROM table") == "select count(*) as 'Total', sum(a) as 'Aggr' from table;"
+doAssert $parseSql("SELECT foo FROM table limit 10") == "select foo from table limit 10;"
+doAssert $parseSql("SELECT foo, bar, baz FROM table limit 10") == "select foo, bar, baz from table limit 10;"
+doAssert $parseSql("SELECT foo AS bar FROM table") == "select foo as bar from table;"
+doAssert $parseSql("SELECT foo AS foo_prime, bar AS bar_prime, baz AS baz_prime FROM table") == "select foo as foo_prime, bar as bar_prime, baz as baz_prime from table;"
+doAssert $parseSql("SELECT * FROM table") == "select * from table;"
+doAssert $parseSql("SELECT count(*) FROM table") == "select count(*) from table;"
+doAssert $parseSql("SELECT count(*) as 'Total' FROM table") == "select count(*) as 'Total' from table;"
+doAssert $parseSql("SELECT count(*) as 'Total', sum(a) as 'Aggr' FROM table") == "select count(*) as 'Total', sum(a) as 'Aggr' from table;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 WHERE a = b and c = d
 """) == "select * from table where a = b and c = d;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 WHERE not b
 """) == "select * from table where not b;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT
   *
 FROM
@@ -49,63 +61,63 @@ WHERE
   a and not b
 """) == "select * from table where a and not b;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 ORDER BY 1
 """) == "select * from table order by 1;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 GROUP BY 1
 ORDER BY 1
 """) == "select * from table group by 1 order by 1;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 ORDER BY 1
 LIMIT 100
 """) == "select * from table order by 1 limit 100;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 WHERE a = b and c = d or n is null and not b + 1 = 3
 """) == "select * from table where a = b and c = d or n is null and not b + 1 = 3;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 WHERE (a = b and c = d) or (n is null and not b + 1 = 3)
 """) == "select * from table where(a = b and c = d) or (n is null and not b + 1 = 3);"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM table
 HAVING a = b and c = d
 """) == "select * from table having a = b and c = d;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT a, b FROM table
 GROUP BY a
 """) == "select a, b from table group by a;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT a, b FROM table
 GROUP BY 1, 2
 """) == "select a, b from table group by 1, 2;"
 
-doAssert $parseSQL("SELECT t.a FROM t as t") == "select t.a from t as t;"
+doAssert $parseSql("SELECT t.a FROM t as t") == "select t.a from t as t;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT a, b FROM (
   SELECT * FROM t
 )
 """) == "select a, b from(select * from t);"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT a, b FROM (
   SELECT * FROM t
 ) as foo
 """) == "select a, b from(select * from t) as foo;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT a, b FROM (
   SELECT * FROM (
     SELECT * FROM (
@@ -117,49 +129,49 @@ SELECT a, b FROM (
 ) as inner5
 """) == "select a, b from(select * from(select * from(select * from(select * from innerTable as inner1) as inner2) as inner3) as inner4) as inner5;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT a, b FROM
   (SELECT * FROM a),
   (SELECT * FROM b),
   (SELECT * FROM c)
 """) == "select a, b from(select * from a),(select * from b),(select * from c);"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM Products
 WHERE Price BETWEEN 10 AND 20;
 """) == "select * from Products where Price between 10 and 20;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT id FROM a
 JOIN b
 ON a.id == b.id
 """) == "select id from a join b on a.id == b.id;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT id FROM a
 JOIN (SELECT id from c) as b
 ON a.id == b.id
 """) == "select id from a join(select id from c) as b on a.id == b.id;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT id FROM a
 INNER JOIN b
 ON a.id == b.id
 """) == "select id from a inner join b on a.id == b.id;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT id FROM a
 OUTER JOIN b
 ON a.id == b.id
 """) == "select id from a outer join b on a.id == b.id;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT id FROM a
 CROSS JOIN b
 ON a.id == b.id
 """) == "select id from a cross join b on a.id == b.id;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
 CREATE TABLE holidays (
   num_weeks int,
@@ -169,31 +181,54 @@ CREATE INDEX table1_attr1 ON table1(attr1);
 SELECT * FROM myTab WHERE col1 = 'happy';
 """) == "create type happiness as enum ('happy' , 'very happy' , 'ecstatic' ); create table holidays(num_weeks  int , happiness  happiness );; create index table1_attr1 on table1(attr1 );; select * from myTab where col1 = 'happy';"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country)
 VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway');
 """) == "insert into Customers (CustomerName , ContactName , Address , City , PostalCode , Country ) values ('Cardinal' , 'Tom B. Erichsen' , 'Skagen 21' , 'Stavanger' , '4006' , 'Norway' );"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 INSERT INTO TableName DEFAULT VALUES
 """) == "insert into TableName default values;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 UPDATE Customers
 SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
 WHERE CustomerID = 1;
 """) == "update Customers set ContactName  = 'Alfred Schmidt' , City  = 'Frankfurt' where CustomerID = 1;"
 
-doAssert $parseSQL("DELETE FROM table_name;") == "delete from table_name;"
+doAssert treeRepr(parseSql("""UPDATE Customers
+                              SET ContactName = 'Alice', City= 'Frankfurt';""")
+) == """
+
+nkStmtList
+  nkUpdate
+    nkIdent Customers
+    nkAsgn
+      nkIdent ContactName
+      nkStringLit Alice
+    nkAsgn
+      nkIdent City
+      nkStringLit Frankfurt
+    nkNone"""
+
+doAssert $parseSql("DELETE FROM table_name;") == "delete from table_name;"
+
+doAssert treeRepr(parseSql("DELETE FROM table_name;")
+) == """
+
+nkStmtList
+  nkDelete
+    nkIdent table_name
+    nkNone"""
 
-doAssert $parseSQL("DELETE * FROM table_name;") == "delete from table_name;"
+doAssert $parseSql("DELETE * FROM table_name;") == "delete from table_name;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 --Select all:
 SELECT * FROM Customers;
 """) == "select * from Customers;"
 
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT * FROM Customers WHERE (CustomerName LIKE 'L%'
 OR CustomerName LIKE 'R%' /*OR CustomerName LIKE 'S%'
 OR CustomerName LIKE 'T%'*/ OR CustomerName LIKE 'W%')
@@ -202,9 +237,9 @@ ORDER BY CustomerName;
 """) == "select * from Customers where(CustomerName like 'L%' or CustomerName like 'R%' or CustomerName like 'W%') and Country = 'USA' order by CustomerName;"
 
 # parse quoted keywords as identifires
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT `SELECT`, `FROM` as `GROUP` FROM `WHERE`;
 """) == """select "SELECT", "FROM" as "GROUP" from "WHERE";"""
-doAssert $parseSQL("""
+doAssert $parseSql("""
 SELECT "SELECT", "FROM" as "GROUP" FROM "WHERE";
 """) == """select "SELECT", "FROM" as "GROUP" from "WHERE";"""
diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim
index 6b228d933..9c71a27d6 100644
--- a/tests/stdlib/tparseuints.nim
+++ b/tests/stdlib/tparseuints.nim
@@ -1,13 +1,11 @@
 discard """
-  action: run
-  output: '''
-[Suite] parseutils'''
+  matrix: "--mm:refc; --mm:orc"
 """
+
 import unittest, strutils
 
-suite "parseutils":
-  test "uint":
-    check: parseBiggestUInt("0") == 0'u64
-    check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64
-    expect(ValueError):
-      discard parseBiggestUInt("18446744073709551616")
+block: # parseutils
+  check: parseBiggestUInt("0") == 0'u64
+  check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64
+  expect(ValueError):
+    discard parseBiggestUInt("18446744073709551616")
diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim
new file mode 100644
index 000000000..b69900864
--- /dev/null
+++ b/tests/stdlib/tparseutils.nim
@@ -0,0 +1,112 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp"
+"""
+
+import std/[parseutils, sequtils, sugar, formatfloat]
+import std/assertions
+
+proc test() =
+  let input = "$test{}  $this is ${an{  example}}  "
+  let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
+                    (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
+  doAssert toSeq(interpolatedFragments(input)) == expected
+
+  var value = 0
+  discard parseHex("0x38", value)
+  doAssert value == 56
+
+  value = -1
+  doAssert(parseSaturatedNatural("848", value) == 3)
+  doAssert value == 848
+
+  value = -1
+  discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("9223372036854775808", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("9223372036854775807", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("18446744073709551616", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("18446744073709551615", value)
+  doAssert value == high(int)
+
+  value = -1
+  doAssert(parseSaturatedNatural("1_000_000", value) == 9)
+  doAssert value == 1_000_000
+
+  var i64Value: int64
+  discard parseBiggestInt("9223372036854775807", i64Value)
+  doAssert i64Value == 9223372036854775807
+
+  block:
+    var f: float
+    let res = collect:
+      for x in ["9.123456789012345+","11.123456789012345+","9.123456789012345-","8.123456789012345+","9.12345678901234-","9.123456789012345"]:
+        (parseFloat(x, f, 0), $f)
+    doAssert res == @[(17, "9.123456789012344"), (18, "11.123456789012344"),
+                      (17, "9.123456789012344"), (17, "8.123456789012344"),
+                      (16, "9.12345678901234"), (17, "9.123456789012344")]
+
+test()
+static: test()
+
+block:  # With this included, static: test() crashes the compiler (from a
+        # VM problem with parseSize calling parseFloat).
+  var sz: int64
+  template checkParseSize(s, expectLen, expectVal) =
+    if (let got = parseSize(s, sz); got != expectLen):
+      raise newException(IOError, "got len " & $got & " != " & $expectLen)
+    if sz != expectVal:
+      raise newException(IOError, "got sz " & $sz & " != " & $expectVal)
+  #              STRING    LEN SZ
+  # Good, complete parses
+  checkParseSize "1  b"   , 4, 1
+  checkParseSize "1  B"   , 4, 1
+  checkParseSize "1k"     , 2, 1000
+  checkParseSize "1 kib"  , 5, 1024
+  checkParseSize "1 ki"   , 4, 1024
+  checkParseSize "1mi"    , 3, 1048576
+  checkParseSize "1 mi"   , 4, 1048576
+  checkParseSize "1 mib"  , 5, 1048576
+  checkParseSize "1 Mib"  , 5, 1048576
+  checkParseSize "1 MiB"  , 5, 1048576
+  checkParseSize "1.23GiB", 7, 1320702444 # 1320702443.52 rounded
+  checkParseSize "0.001k" , 6, 1
+  checkParseSize "0.0004k", 7, 0
+  checkParseSize "0.0006k", 7, 1
+  # Incomplete parses
+  checkParseSize "1  "    , 1, 1          # Trailing white IGNORED
+  checkParseSize "1  B "  , 4, 1          # Trailing white IGNORED
+  checkParseSize "1  B/s" , 4, 1          # Trailing junk IGNORED
+  checkParseSize "1 kX"   , 3, 1000
+  checkParseSize "1 kiX"  , 4, 1024
+  checkParseSize "1j"     , 1, 1          # Unknown prefix IGNORED
+  checkParseSize "1 jib"  , 2, 1          # Unknown prefix post space
+  checkParseSize "1  ji"  , 3, 1
+  # Bad parses; `sz` should stay last good|incomplete value
+  checkParseSize "-1b"    , 0, 1          # Negative numbers
+  checkParseSize "abc"    , 0, 1          # Non-numeric
+  checkParseSize " 12"    , 0, 1          # Leading white
+  # Value Edge cases
+  checkParseSize "9223372036854775807", 19, int64.high
+
+block: # bug #23936
+  func parsePyFloat(
+      a: openArray[char],  # here must be openArray instead of string to reproduce this bug
+      res: var BiggestFloat): int =
+    result = parseFloat(a, res)
+
+  static:
+    var f = 0.0
+    doAssert "1.0".parsePyFloat(f) == 3
+    doAssert f == 1.0
diff --git a/tests/stdlib/tparsopt.nim b/tests/stdlib/tparsopt.nim
index 848fba2da..f3a9a9798 100644
--- a/tests/stdlib/tparsopt.nim
+++ b/tests/stdlib/tparsopt.nim
@@ -1,8 +1,16 @@
-# Test the new parseopt module
+discard """
+disabled: true
+"""
+
+# this file has a type in the name, and it does not really test
+# parseopt module, because tester has no support to set arguments. Test the
+# new parseopt module. Therefore it is disabled.
 
 import
   parseopt
 
+import std/[assertions, syncio]
+
 proc writeHelp() =
   writeLine(stdout, "Usage: tparsopt [options] filename [options]")
 
@@ -21,7 +29,7 @@ for kind, key, val in getopt():
     of "version", "v": writeVersion()
     else:
       writeLine(stdout, "Unknown command line option: ", key, ": ", val)
-  of cmdEnd: assert(false) # cannot happen
+  of cmdEnd: doAssert(false) # cannot happen
 if filename == "":
   # no filename has been given, so we show the help:
   writeHelp()
diff --git a/tests/stdlib/tpathnorm.nim b/tests/stdlib/tpathnorm.nim
new file mode 100644
index 000000000..3dd287a77
--- /dev/null
+++ b/tests/stdlib/tpathnorm.nim
@@ -0,0 +1,36 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/os
+import std/assertions
+
+when doslikeFileSystem:
+  import std/pathnorm
+
+  template initVars =
+    var state {.inject.} = 0
+    var result {.inject.}: string
+
+  block: # / -> /
+    initVars
+    addNormalizePath("//?/c:/./foo//bar/../baz", result, state, '/')
+    doAssert result == "//?/c:/foo/baz"
+    addNormalizePath("me", result, state, '/')
+    doAssert result == "//?/c:/foo/baz/me"
+
+  block: # / -> \
+    initVars
+    addNormalizePath(r"//?/c:/./foo//bar/../baz", result, state, '\\')
+    doAssert result == r"\\?\c:\foo\baz"
+    addNormalizePath("me", result, state, '\\')
+    doAssert result == r"\\?\c:\foo\baz\me"
+
+  block: # Append path component to UNC drive
+    initVars
+    addNormalizePath(r"//?/c:", result, state, '\\')
+    doAssert result == r"\\?\c:"
+    addNormalizePath("Users", result, state, '\\')
+    doAssert result == r"\\?\c:\Users"
+    addNormalizePath("me", result, state, '\\')
+    doAssert result == r"\\?\c:\Users\me"
diff --git a/tests/stdlib/tpaths.nim b/tests/stdlib/tpaths.nim
new file mode 100644
index 000000000..edb56209a
--- /dev/null
+++ b/tests/stdlib/tpaths.nim
@@ -0,0 +1,238 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/paths
+import std/assertions
+import pathnorm
+from std/private/ospaths2 {.all.} import joinPathImpl
+import std/[sugar, sets]
+
+
+proc normalizePath*(path: Path; dirSep = DirSep): Path =
+  result = Path(pathnorm.normalizePath(path.string, dirSep))
+
+func joinPath*(parts: varargs[Path]): Path =
+  var estimatedLen = 0
+  var state = 0
+  for p in parts: estimatedLen += p.string.len
+  var res = newStringOfCap(estimatedLen)
+  for i in 0..high(parts):
+    joinPathImpl(res, state, parts[i].string)
+  result = Path(res)
+
+
+func joinPath(head, tail: Path): Path {.inline.} =
+  head / tail
+
+block absolutePath:
+  doAssertRaises(ValueError): discard absolutePath(Path"a", Path"b")
+  doAssert absolutePath(Path"a") == getCurrentDir() / Path"a"
+  doAssert absolutePath(Path"a", Path"/b") == Path"/b" / Path"a"
+  when defined(posix):
+    doAssert absolutePath(Path"a", Path"/b/") == Path"/b" / Path"a"
+    doAssert absolutePath(Path"a", Path"/b/c") == Path"/b/c" / Path"a"
+    doAssert absolutePath(Path"/a", Path"b/") == Path"/a"
+
+block splitFile:
+  doAssert splitFile(Path"") == (Path"", Path"", "")
+  doAssert splitFile(Path"abc/") == (Path"abc", Path"", "")
+  doAssert splitFile(Path"/") == (Path"/", Path"", "")
+  doAssert splitFile(Path"./abc") == (Path".", Path"abc", "")
+  doAssert splitFile(Path".txt") == (Path"", Path".txt", "")
+  doAssert splitFile(Path"abc/.txt") == (Path"abc", Path".txt", "")
+  doAssert splitFile(Path"abc") == (Path"", Path"abc", "")
+  doAssert splitFile(Path"abc.txt") == (Path"", Path"abc", ".txt")
+  doAssert splitFile(Path"/abc.txt") == (Path"/", Path"abc", ".txt")
+  doAssert splitFile(Path"/foo/abc.txt") == (Path"/foo", Path"abc", ".txt")
+  doAssert splitFile(Path"/foo/abc.txt.gz") == (Path"/foo", Path"abc.txt", ".gz")
+  doAssert splitFile(Path".") == (Path"", Path".", "")
+  doAssert splitFile(Path"abc/.") == (Path"abc", Path".", "")
+  doAssert splitFile(Path"..") == (Path"", Path"..", "")
+  doAssert splitFile(Path"a/..") == (Path"a", Path"..", "")
+  doAssert splitFile(Path"/foo/abc....txt") == (Path"/foo", Path"abc...", ".txt")
+
+# execShellCmd is tested in tosproc
+
+block ospaths:
+  doAssert unixToNativePath(Path"") == Path""
+  doAssert unixToNativePath(Path".") == Path($CurDir)
+  doAssert unixToNativePath(Path"..") == Path($ParDir)
+  doAssert isAbsolute(unixToNativePath(Path"/"))
+  doAssert isAbsolute(unixToNativePath(Path"/", Path"a"))
+  doAssert isAbsolute(unixToNativePath(Path"/a"))
+  doAssert isAbsolute(unixToNativePath(Path"/a", Path"a"))
+  doAssert isAbsolute(unixToNativePath(Path"/a/b"))
+  doAssert isAbsolute(unixToNativePath(Path"/a/b", Path"a"))
+  doAssert unixToNativePath(Path"a/b") == joinPath(Path"a", Path"b")
+
+  when defined(macos):
+    doAssert unixToNativePath(Path"./") == Path":"
+    doAssert unixToNativePath(Path"./abc") == Path":abc"
+    doAssert unixToNativePath(Path"../abc") == Path"::abc"
+    doAssert unixToNativePath(Path"../../abc") == Path":::abc"
+    doAssert unixToNativePath(Path"/abc", Path"a") == Path"abc"
+    doAssert unixToNativePath(Path"/abc/def", Path"a") == Path"abc:def"
+  elif doslikeFileSystem:
+    doAssert unixToNativePath(Path"./") == Path(".\\")
+    doAssert unixToNativePath(Path"./abc") == Path(".\\abc")
+    doAssert unixToNativePath(Path"../abc") == Path("..\\abc")
+    doAssert unixToNativePath(Path"../../abc") == Path("..\\..\\abc")
+    doAssert unixToNativePath(Path"/abc", Path"a") == Path("a:\\abc")
+    doAssert unixToNativePath(Path"/abc/def", Path"a") == Path("a:\\abc\\def")
+  else:
+    #Tests for unix
+    doAssert unixToNativePath(Path"./") == Path"./"
+    doAssert unixToNativePath(Path"./abc") == Path"./abc"
+    doAssert unixToNativePath(Path"../abc") == Path"../abc"
+    doAssert unixToNativePath(Path"../../abc") == Path"../../abc"
+    doAssert unixToNativePath(Path"/abc", Path"a") == Path"/abc"
+    doAssert unixToNativePath(Path"/abc/def", Path"a") == Path"/abc/def"
+
+  block extractFilenameTest:
+    doAssert extractFilename(Path"") == Path""
+    when defined(posix):
+      doAssert extractFilename(Path"foo/bar") == Path"bar"
+      doAssert extractFilename(Path"foo/bar.txt") == Path"bar.txt"
+      doAssert extractFilename(Path"foo/") == Path""
+      doAssert extractFilename(Path"/") == Path""
+    when doslikeFileSystem:
+      doAssert extractFilename(Path(r"foo\bar")) == Path"bar"
+      doAssert extractFilename(Path(r"foo\bar.txt")) == Path"bar.txt"
+      doAssert extractFilename(Path(r"foo\")) == Path""
+      doAssert extractFilename(Path(r"C:\")) == Path""
+
+  block lastPathPartTest:
+    doAssert lastPathPart(Path"") == Path""
+    when defined(posix):
+      doAssert lastPathPart(Path"foo/bar.txt") == Path"bar.txt"
+      doAssert lastPathPart(Path"foo/") == Path"foo"
+      doAssert lastPathPart(Path"/") == Path""
+    when doslikeFileSystem:
+      doAssert lastPathPart(Path(r"foo\bar.txt")) == Path"bar.txt"
+      doAssert lastPathPart(Path(r"foo\")) == Path"foo"
+
+  template canon(x): Path = normalizePath(Path(x), '/')
+  doAssert canon"/foo/../bar" == Path"/bar"
+  doAssert canon"foo/../bar" == Path"bar"
+
+  doAssert canon"/f/../bar///" == Path"/bar"
+  doAssert canon"f/..////bar" == Path"bar"
+
+  doAssert canon"../bar" == Path"../bar"
+  doAssert canon"/../bar" == Path"/../bar"
+
+  doAssert canon("foo/../../bar/") == Path"../bar"
+  doAssert canon("./bla/blob/") == Path"bla/blob"
+  doAssert canon(".hiddenFile") == Path".hiddenFile"
+  doAssert canon("./bla/../../blob/./zoo.nim") == Path"../blob/zoo.nim"
+
+  doAssert canon("C:/file/to/this/long") == Path"C:/file/to/this/long"
+  doAssert canon("") == Path""
+  doAssert canon("foobar") == Path"foobar"
+  doAssert canon("f/////////") == Path"f"
+
+  doAssert relativePath(Path"/foo/bar//baz.nim", Path"/foo", '/') == Path"bar/baz.nim"
+  doAssert normalizePath(Path"./foo//bar/../baz", '/') == Path"foo/baz"
+
+  doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/other/bad", '/') == Path"../../me/bar/z.nim"
+
+  doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/other", '/') == Path"../me/bar/z.nim"
+
+  # `//` is a UNC path, `/` is the current working directory's drive, so can't
+  # run this test on Windows.
+  when not doslikeFileSystem:
+    doAssert relativePath(Path"/Users///me/bar//z.nim", Path"//Users/", '/') == Path"me/bar/z.nim"
+  doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/me", '/') == Path"bar/z.nim"
+  doAssert relativePath(Path"", Path"/users/moo", '/') == Path""
+  doAssert relativePath(Path"foo", Path"", '/') == Path"foo"
+  doAssert relativePath(Path"/foo", Path"/Foo", '/') == (when FileSystemCaseSensitive: Path"../foo" else: Path".")
+  doAssert relativePath(Path"/Foo", Path"/foo", '/') == (when FileSystemCaseSensitive: Path"../Foo" else: Path".")
+  doAssert relativePath(Path"/foo", Path"/fOO", '/') == (when FileSystemCaseSensitive: Path"../foo" else: Path".")
+  doAssert relativePath(Path"/foO", Path"/foo", '/') == (when FileSystemCaseSensitive: Path"../foO" else: Path".")
+
+  doAssert relativePath(Path"foo", Path".", '/') == Path"foo"
+  doAssert relativePath(Path".", Path".", '/') == Path"."
+  doAssert relativePath(Path"..", Path".", '/') == Path".."
+
+  doAssert relativePath(Path"foo", Path"foo") == Path"."
+  doAssert relativePath(Path"", Path"foo") == Path""
+  doAssert relativePath(Path"././/foo", Path"foo//./") == Path"."
+
+  doAssert relativePath(getCurrentDir() / Path"bar", Path"foo") == Path"../bar".unixToNativePath
+  doAssert relativePath(Path"bar", getCurrentDir() / Path"foo") == Path"../bar".unixToNativePath
+
+  when doslikeFileSystem:
+    doAssert relativePath(r"c:\foo.nim".Path, r"C:\".Path) == r"foo.nim".Path
+    doAssert relativePath(r"c:\foo\bar\baz.nim".Path, r"c:\foo".Path) == r"bar\baz.nim".Path
+    doAssert relativePath(r"c:\foo\bar\baz.nim".Path, r"d:\foo".Path) == r"c:\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\foo\baz.nim".Path, r"\foo".Path) == r"baz.nim".Path
+    doAssert relativePath(r"\foo\bar\baz.nim".Path, r"\bar".Path) == r"..\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foo\bar".Path) == r"baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foO\bar".Path) == r"baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\bar\bar".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foo\car".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\goo\bar".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"c:\".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\foo".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"c:\foo.nim".Path, r"\foo".Path) == r"c:\foo.nim".Path
+
+  doAssert joinPath(Path"usr", Path"") == unixToNativePath(Path"usr")
+  doAssert joinPath(Path"usr", Path"") == (Path"usr").dup(add Path"")
+  doAssert joinPath(Path"", Path"lib") == Path"lib"
+  doAssert joinPath(Path"", Path"lib") == Path"".dup(add Path"lib")
+  doAssert joinPath(Path"", Path"/lib") == unixToNativePath(Path"/lib")
+  doAssert joinPath(Path"", Path"/lib") == unixToNativePath(Path"/lib")
+  doAssert joinPath(Path"usr/", Path"/lib") == Path"usr/".dup(add Path"/lib")
+  doAssert joinPath(Path"", Path"") == unixToNativePath(Path"") # issue #13455
+  doAssert joinPath(Path"", Path"") == Path"".dup(add Path"")
+  doAssert joinPath(Path"", Path"/") == unixToNativePath(Path"/")
+  doAssert joinPath(Path"", Path"/") == Path"".dup(add Path"/")
+  doAssert joinPath(Path"/", Path"/") == unixToNativePath(Path"/")
+  doAssert joinPath(Path"/", Path"/") == Path"/".dup(add Path"/")
+  doAssert joinPath(Path"/", Path"") == unixToNativePath(Path"/")
+  doAssert joinPath(Path"/" / Path"") == unixToNativePath(Path"/") # weird test case...
+  doAssert joinPath(Path"/", Path"/a/b/c") == unixToNativePath(Path"/a/b/c")
+  doAssert joinPath(Path"foo/", Path"") == unixToNativePath(Path"foo/")
+  doAssert joinPath(Path"foo/", Path"abc") == unixToNativePath(Path"foo/abc")
+  doAssert joinPath(Path"foo//./", Path"abc/.//") == unixToNativePath(Path"foo/abc/")
+  doAssert Path"foo//./".dup(add Path"abc/.//") == unixToNativePath(Path"foo/abc/")
+  doAssert joinPath(Path"foo", Path"abc") == unixToNativePath(Path"foo/abc")
+  doAssert Path"foo".dup(add Path"abc") == unixToNativePath(Path"foo/abc")
+  doAssert joinPath(Path"", Path"abc") == unixToNativePath(Path"abc")
+
+  doAssert joinPath(Path"zook/.", Path"abc") == unixToNativePath(Path"zook/abc")
+
+  # controversial: inconsistent with `joinPath("zook/.","abc")`
+  # on linux, `./foo` and `foo` are treated a bit differently for executables
+  # but not `./foo/bar` and `foo/bar`
+  doAssert joinPath(Path".", Path"/lib") == unixToNativePath(Path"./lib")
+  doAssert joinPath(Path".", Path"abc") == unixToNativePath(Path"./abc")
+
+  # cases related to issue #13455
+  doAssert joinPath(Path"foo", Path"", Path"") == Path"foo"
+  doAssert joinPath(Path"foo", Path"") == Path"foo"
+  doAssert joinPath(Path"foo/", Path"") == unixToNativePath(Path"foo/")
+  doAssert joinPath(Path"foo/", Path".") == Path"foo"
+  doAssert joinPath(Path"foo", Path"./") == unixToNativePath(Path"foo/")
+  doAssert joinPath(Path"foo", Path"", Path"bar/") == unixToNativePath(Path"foo/bar/")
+
+  # issue #13579
+  doAssert joinPath(Path"/foo", Path"../a") == unixToNativePath(Path"/a")
+  doAssert joinPath(Path"/foo/", Path"../a") == unixToNativePath(Path"/a")
+  doAssert joinPath(Path"/foo/.", Path"../a") == unixToNativePath(Path"/a")
+  doAssert joinPath(Path"/foo/.b", Path"../a") == unixToNativePath(Path"/foo/a")
+  doAssert joinPath(Path"/foo///", Path"..//a/") == unixToNativePath(Path"/a/")
+  doAssert joinPath(Path"foo/", Path"../a") == unixToNativePath(Path"a")
+
+  when doslikeFileSystem:
+    doAssert joinPath(Path"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", Path"..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat".Path
+    doAssert joinPath(Path"C:\\foo", Path"..\\a") == r"C:\a".Path
+    doAssert joinPath(Path"C:\\foo\\", Path"..\\a") == r"C:\a".Path
+
+
+block: # bug #23663
+  var s: HashSet[Path]
+  s.incl("/a/b/c/..".Path)
+  doAssert "/a/b/".Path in s
+  doAssert "/a/b/c".Path notin s
diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim
index e5b709a66..da3fc14b7 100644
--- a/tests/stdlib/tpegs.nim
+++ b/tests/stdlib/tpegs.nim
@@ -1,5 +1,9 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
   output: '''
+PEG AST traversal output
+------------------------
 pkNonTerminal: Sum @(2, 3)
   pkSequence: (Product (('+' / '-') Product)*)
     pkNonTerminal: Product @(3, 7)
@@ -26,53 +30,315 @@ pkNonTerminal: Sum @(2, 3)
           pkChar: '+'
           pkChar: '-'
         pkNonTerminal: Product @(3, 7)
+
+Event parser output
+-------------------
+@[5.0]
++
+@[5.0, 3.0]
+@[8.0]
+
+/
+@[8.0, 2.0]
+@[4.0]
+
+-
+@[4.0, 7.0]
+-*
+@[4.0, 7.0, 22.0]
+@[4.0, 154.0]
+-
+@[-150.0]
 '''
 """
 
-import strutils, streams
-import pegs
+when defined(nimHasEffectsOf):
+  {.experimental: "strictEffects".}
+
+import std/[strutils, streams, pegs, assertions]
 
 const
   indent = "  "
 
 let
-  pegSrc = """
-Expr <- Sum
-Sum <- Product (('+' / '-') Product)*
-Product <- Value (('*' / '/') Value)*
-Value <- [0-9]+ / '(' Expr ')'
-  """
-  pegAst: Peg = pegSrc.peg
-
-var
-  outp = newStringStream()
-  processed: seq[string] = @[]
-
-proc prt(outp: Stream, kind: PegKind, s: string; level: int = 0) =
-  outp.writeLine indent.repeat(level) & "$1: $2" % [$kind, s]
-
-proc recLoop(p: Peg, level: int = 0) =
-  case p.kind
-  of pkEmpty..pkWhitespace:
-    discard
-  of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle:
-    outp.prt(p.kind, $p, level)
-  of pkChar, pkGreedyRepChar:
-    outp.prt(p.kind, $p, level)
-  of pkCharChoice, pkGreedyRepSet:
-    outp.prt(p.kind, $p, level)
-  of pkNonTerminal:
-    outp.prt(p.kind,
-      "$1 @($3, $4)" % [p.nt.name, $p.nt.rule.kind, $p.nt.line, $p.nt.col], level)
-    if not(p.nt.name in processed):
-      processed.add p.nt.name
-      p.nt.rule.recLoop level+1
-  of pkBackRef..pkBackRefIgnoreStyle:
-    outp.prt(p.kind, $p, level)
-  else:
-    outp.prt(p.kind, $p, level)
-    for s in items(p):
-      s.recLoop level+1
-
-pegAst.recLoop
-echo outp.data
\ No newline at end of file
+  pegAst = """
+Expr    <- Sum
+Sum     <- Product (('+' / '-')Product)*
+Product <- Value (('*' / '/')Value)*
+Value   <- [0-9]+ / '(' Expr ')'
+  """.peg
+  txt = "(5+3)/2-7*22"
+
+block:
+  var
+    outp = newStringStream()
+    processed: seq[string] = @[]
+
+  proc prt(outp: Stream, kind: PegKind, s: string; level: int = 0) =
+    outp.writeLine indent.repeat(level) & "$1: $2" % [$kind, s]
+
+  proc recLoop(p: Peg, level: int = 0) =
+    case p.kind
+    of pkEmpty..pkWhitespace:
+      discard
+    of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle:
+      outp.prt(p.kind, $p, level)
+    of pkChar, pkGreedyRepChar:
+      outp.prt(p.kind, $p, level)
+    of pkCharChoice, pkGreedyRepSet:
+      outp.prt(p.kind, $p, level)
+    of pkNonTerminal:
+      outp.prt(p.kind,
+        "$1 @($3, $4)" % [p.nt.name, $p.nt.rule.kind, $p.nt.line, $p.nt.col], level)
+      if not(p.nt.name in processed):
+        processed.add p.nt.name
+        p.nt.rule.recLoop level+1
+    of pkBackRef..pkBackRefIgnoreStyle:
+      outp.prt(p.kind, $p, level)
+    else:
+      outp.prt(p.kind, $p, level)
+      for s in items(p):
+        s.recLoop level+1
+
+  pegAst.recLoop
+  echo "PEG AST traversal output"
+  echo "------------------------"
+  echo outp.data
+
+block:
+  var
+    pStack {.threadvar.}: seq[string]
+    valStack {.threadvar.}: seq[float]
+    opStack {.threadvar.}: string
+  let
+    parseArithExpr = pegAst.eventParser:
+      pkNonTerminal:
+        enter:
+          pStack.add p.nt.name
+        leave:
+          pStack.setLen pStack.high
+          if length > 0:
+            let matchStr = s.substr(start, start+length-1)
+            case p.nt.name
+            of "Value":
+              try:
+                valStack.add matchStr.parseFloat
+                echo valStack
+              except ValueError:
+                discard
+            of "Sum", "Product":
+              try:
+                let val {.used.} = matchStr.parseFloat
+              except ValueError:
+                if valStack.len > 1 and opStack.len > 0:
+                  valStack[^2] = case opStack[^1]
+                  of '+': valStack[^2] + valStack[^1]
+                  of '-': valStack[^2] - valStack[^1]
+                  of '*': valStack[^2] * valStack[^1]
+                  else: valStack[^2] / valStack[^1]
+                  valStack.setLen valStack.high
+                  echo valStack
+                  opStack.setLen opStack.high
+                  echo opStack
+      pkChar:
+        leave:
+          if length == 1 and "Value" != pStack[^1]:
+            let matchChar = s[start]
+            opStack.add matchChar
+            echo opStack
+  echo "Event parser output"
+  echo "-------------------"
+  let pLen = parseArithExpr(txt)
+  doAssert txt.len == pLen
+
+
+import std/importutils
+
+block:
+  proc pegsTest() =
+    privateAccess(NonTerminal)
+    privateAccess(Captures)
+
+    if "test" =~ peg"s <- {{\ident}}": # bug #19104
+      doAssert matches[0] == "test"
+      doAssert matches[1] == "test", $matches[1]
+
+    doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
+    doAssert match("(a b c)", peg"'(' @ ')'")
+    doAssert match("W_HI_Le", peg"\y 'while'")
+    doAssert(not match("W_HI_L", peg"\y 'while'"))
+    doAssert(not match("W_HI_Le", peg"\y v'while'"))
+    doAssert match("W_HI_Le", peg"y'while'")
+
+    doAssert($ +digits == $peg"\d+")
+    doAssert "0158787".match(peg"\d+")
+    doAssert "ABC 0232".match(peg"\w+\s+\d+")
+    doAssert "ABC".match(peg"\d+ / \w+")
+
+    var accum: seq[string] = @[]
+    for word in split("00232this02939is39an22example111", peg"\d+"):
+      accum.add(word)
+    doAssert(accum == @["this", "is", "an", "example"])
+
+    doAssert matchLen("key", ident) == 3
+
+    var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
+    doAssert matchLen("key1=  cal9", pattern) == 11
+
+    var ws = newNonTerminal("ws", 1, 1)
+    ws.rule = *whitespace
+
+    var expr = newNonTerminal("expr", 1, 1)
+    expr.rule = sequence(capture(ident), *sequence(
+                  nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
+
+    var c: Captures
+    var s = "a+b +  c +d+e+f"
+    doAssert rawMatch(s, expr.rule, 0, c) == len(s)
+    var a = ""
+    for i in 0..c.ml-1:
+      a.add(substr(s, c.matches[i][0], c.matches[i][1]))
+    doAssert a == "abcdef"
+    #echo expr.rule
+
+    #const filename = "lib/devel/peg/grammar.txt"
+    #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
+    #echo "a <- [abc]*?".match(grammar)
+    doAssert find("_____abc_______", term("abc"), 2) == 5
+    doAssert match("_______ana", peg"A <- 'ana' / . A")
+    doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
+
+    var matches: array[0..MaxSubpatterns-1, string]
+    if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
+      doAssert matches[0] == "abc"
+    else:
+      doAssert false
+
+    var g2 = peg"""S <- A B / C D
+                   A <- 'a'+
+                   B <- 'b'+
+                   C <- 'c'+
+                   D <- 'd'+
+                """
+    doAssert($g2 == "((A B) / (C D))")
+    doAssert match("cccccdddddd", g2)
+    doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+           "var1<-keykey; var2<-key2key2")
+    doAssert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+           "$1<-$2$2; $1<-$2$2")
+    doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
+
+    if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
+      doAssert matches[0] == "a"
+    else:
+      doAssert false
+
+    if match("abcdefg", peg"c {d} ef {g}", matches, 2):
+      doAssert matches[0] == "d"
+      doAssert matches[1] == "g"
+    else:
+      doAssert false
+
+    accum = @[]
+    for x in findAll("abcdef", peg".", 3):
+      accum.add(x)
+    doAssert(accum == @["d", "e", "f"])
+
+    for x in findAll("abcdef", peg"^{.}", 3):
+      doAssert x == "d"
+
+    if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
+      doAssert matches[0] == "f"
+      doAssert matches[1] == "a, b"
+    else:
+      doAssert false
+
+    doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+")
+    # ß is not a lower cased letter?!
+    doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+")
+    doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
+    doAssert(not match("456678", peg"(\letter)+"))
+
+    doAssert("var1 = key; var2 = key2".replacef(
+      peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
+           "var1<-keykey;var2<-key2key2")
+
+    doAssert match("prefix/start", peg"^start$", 7)
+
+    if "foo" =~ peg"{'a'}?.*":
+      doAssert matches[0].len == 0
+    else: doAssert false
+
+    if "foo" =~ peg"{''}.*":
+      doAssert matches[0] == ""
+    else: doAssert false
+
+    if "foo" =~ peg"{'foo'}":
+      doAssert matches[0] == "foo"
+    else: doAssert false
+
+    let empty_test = peg"^\d*"
+    let str = "XYZ"
+
+    doAssert(str.find(empty_test) == 0)
+    doAssert(str.match(empty_test))
+
+    proc handleMatches(m: int, n: int, c: openArray[string]): string =
+      result = ""
+
+      if m > 0:
+        result.add ", "
+
+      result.add case n:
+        of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'"
+        of 1: toLowerAscii(c[0]) & ": ''"
+        else: ""
+
+    doAssert("Var1=key1;var2=Key2;   VAR3".
+      replace(peg"{\ident}('='{\ident})* ';'* \s*",
+      handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''")
+
+
+    doAssert "test1".match(peg"""{@}$""")
+    doAssert "test2".match(peg"""{(!$ .)*} $""")
+
+    doAssert "abbb".match(peg"{a} {b} $2 $^1")
+    doAssert "abBA".match(peg"{a} {b} i$2 i$^2")
+
+    doAssert "abba".match(peg"{a} {b} $^1 {} $^1")
+
+    block:
+      let grammar = peg"""
+program <- {''} stmt* $
+stmt <- call / block
+call <- 'call()' EOL
+EOL <- \n / $
+block <- 'block:' \n indBody
+indBody <- {$^1 ' '+} stmt ($^1 stmt)* {}
+"""
+      let program = """
+call()
+block:
+  block:
+    call()
+    call()
+  call()
+call()
+"""
+      var c: Captures
+      doAssert program.len == program.rawMatch(grammar, 0, c)
+      doAssert c.ml == 1
+
+    block:
+      # bug #21632
+
+      let p = peg"""
+        atext <- \w / \d
+      """
+
+      doAssert "a".match(p)
+      doAssert "1".match(p)
+
+  pegsTest()
+  static:
+    pegsTest()
diff --git a/tests/stdlib/tpermutations.nim b/tests/stdlib/tpermutations.nim
deleted file mode 100644
index a6e07ded6..000000000
--- a/tests/stdlib/tpermutations.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-discard """
-  output: '''@[0, 2, 1]
-@[1, 0, 2]
-@[1, 2, 0]
-@[2, 0, 1]
-@[2, 1, 0]
-@[2, 0, 1]
-@[1, 2, 0]
-@[1, 0, 2]
-@[0, 2, 1]
-@[0, 1, 2]'''
-"""
-import algorithm
-
-var v = @[0, 1, 2]
-while v.nextPermutation():
-  echo v
-while v.prevPermutation():
-  echo v
diff --git a/tests/stdlib/tposix.nim b/tests/stdlib/tposix.nim
index 229035d22..060482229 100644
--- a/tests/stdlib/tposix.nim
+++ b/tests/stdlib/tposix.nim
@@ -1,11 +1,17 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  disabled: windows
+"""
+
 # Test Posix interface
 
 when not defined(windows):
 
   import posix
+  import std/[assertions, syncio]
 
   var
-    u: Tutsname
+    u: Utsname
 
   discard uname(u)
 
@@ -14,3 +20,69 @@ when not defined(windows):
   writeLine(stdout, u.release)
   writeLine(stdout, u.machine)
 
+  when not (defined(nintendoswitch) or defined(macos) or defined(macosx)):
+    block:
+      type Message = object
+        value: int
+
+      const MQ_PATH: cstring = "/top_level_file"
+      const MQ_PRIORITY: cuint = 170
+      const MQ_MESSAGE_SIZE: csize_t = csize_t(sizeof(Message))
+
+      let mqd_a: posix.MqAttr = MqAttr(mq_maxmsg: 10, mq_msgsize: clong(MQ_MESSAGE_SIZE))
+      let writable: posix.Mqd = posix.mq_open(
+        MQ_PATH,
+        posix.O_CREAT or posix.O_WRONLY or posix.O_NONBLOCK,
+        posix.S_IRWXU,
+        addr(mqd_a)
+      )
+      let readable: posix.Mqd = posix.mq_open(
+        MQ_PATH,
+        posix.O_RDONLY or posix.O_NONBLOCK,
+        posix.S_IRWXU,
+        addr(mqd_a)
+      )
+
+      let sent: Message = Message(value: 88)
+      block:
+        let success: int = writable.mq_send(
+          cast[cstring](sent.addr),
+          MQ_MESSAGE_SIZE,
+          MQ_PRIORITY
+        )
+        doAssert success == 0, $success
+
+      block:
+        var buffer: Message
+        var priority: cuint
+        let bytesRead: int = readable.mq_receive(
+          cast[cstring](buffer.addr),
+          MQ_MESSAGE_SIZE,
+          priority
+        )
+        doAssert buffer == sent
+        doAssert bytesRead == int(MQ_MESSAGE_SIZE)
+
+  block:
+    var rl: RLimit
+    var res = getrlimit(RLIMIT_STACK, rl)
+    doAssert res == 0
+
+    # save old value
+    let oldrlim = rl.rlim_cur
+
+    # set new value
+    rl.rlim_cur = rl.rlim_max - 1
+    res = setrlimit(RLIMIT_STACK, rl)
+    doAssert res == 0
+
+    # get new value
+    var rl1: RLimit
+    res = getrlimit(RLIMIT_STACK, rl1)
+    doAssert res == 0
+    doAssert rl1.rlim_cur == rl.rlim_max - 1
+
+    # restore old value
+    rl.rlim_cur = oldrlim
+    res = setrlimit(RLIMIT_STACK, rl)
+    doAssert res == 0
diff --git a/tests/stdlib/tprelude.nim b/tests/stdlib/tprelude.nim
new file mode 100644
index 000000000..47f46b511
--- /dev/null
+++ b/tests/stdlib/tprelude.nim
@@ -0,0 +1,16 @@
+discard """
+  targets: "c js"
+  matrix: "; -d:nimTestTpreludeCase1"
+"""
+
+when defined nimTestTpreludeCase1:
+  include std/prelude
+else:
+  include prelude
+
+import std/assertions
+
+template main() =
+  doAssert toSeq(1..3) == @[1,2,3]
+static: main()
+main()
diff --git a/tests/stdlib/tquit.nim b/tests/stdlib/tquit.nim
deleted file mode 100644
index d18b468c8..000000000
--- a/tests/stdlib/tquit.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test the new beforeQuit variable:
-
-proc myExit() {.noconv.} =
-  write(stdout, "just exiting...\n")
-
-addQuitProc(myExit)
diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim
new file mode 100644
index 000000000..eb32f7757
--- /dev/null
+++ b/tests/stdlib/trandom.nim
@@ -0,0 +1,310 @@
+discard """
+  joinable: false # to avoid messing with global rand state
+  matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
+"""
+import std/[assertions, formatfloat]
+import std/[random, math, stats, sets, tables]
+import std/private/jsutils
+when not defined(js):
+  import std/os
+
+randomize(233)
+
+proc main() =
+  var occur: array[1000, int]
+
+  for i in 0..100_000:
+    let x = rand(high(occur))
+    inc occur[x]
+
+  doAssert max(occur) <= 140 and min(occur) >= 60 # gives some slack
+
+  var a = [0, 1]
+  shuffle(a)
+  doAssert a in [[0,1], [1,0]]
+
+  doAssert rand(0) == 0
+  when not defined(nimscript):
+    doAssert sample("a") == 'a'
+
+  when compileOption("rangeChecks") and not defined(nimscript):
+    doAssertRaises(RangeDefect):
+      discard rand(-1)
+
+    doAssertRaises(RangeDefect):
+      discard rand(-1.0)
+
+  # don't use causes integer overflow
+  doAssert compiles(rand[int](low(int) .. high(int)))
+
+main()
+
+block:
+  when not defined(js):
+    doAssert almostEqual(rand(12.5), 7.355175342026979)
+    doAssert almostEqual(rand(2233.3322), 499.342386778917)
+
+  type DiceRoll = range[0..6]
+  when not defined(js):
+    doAssert rand(DiceRoll).int == 3
+  elif compileOption("jsbigint64"):
+    doAssert rand(DiceRoll).int == 1
+  else:
+    doAssert rand(DiceRoll).int == 6
+
+var rs: RunningStat
+for j in 1..5:
+  for i in 1 .. 100_000:
+    rs.push(gauss())
+  doAssert abs(rs.mean-0) < 0.08, $rs.mean
+  doAssert abs(rs.standardDeviation()-1.0) < 0.1
+  let bounds = [3.5, 5.0]
+  for a in [rs.max, -rs.min]:
+    doAssert a >= bounds[0] and a <= bounds[1]
+  rs.clear()
+
+block:
+  type DiceRoll = range[3..6]
+  var flag = false
+  for i in 0..<100:
+    if rand(5.DiceRoll) < 3:
+      flag = true
+  doAssert flag # because of: rand(max: int): int
+
+
+block: # random int
+  block: # there might be some randomness
+    var set = initHashSet[int](128)
+
+    for i in 1..1000:
+      incl(set, rand(high(int)))
+    doAssert len(set) == 1000
+
+  block: # single number bounds work
+    var rand: int
+    for i in 1..1000:
+      rand = rand(1000)
+      doAssert rand <= 1000
+      doAssert rand >= 0
+
+  block: # slice bounds work
+    var rand: int
+    for i in 1..1000:
+      rand = rand(100..1000)
+      doAssert rand <= 1000
+      doAssert rand >= 100
+
+  block: # again gives new numbers
+    var rand1 = rand(1000000)
+    when not (defined(js) or defined(nimscript)):
+      os.sleep(200)
+
+    var rand2 = rand(1000000)
+    doAssert rand1 != rand2
+
+block: # random float
+  block: # there might be some randomness
+    var set = initHashSet[float](128)
+
+    for i in 1..100:
+      incl(set, rand(1.0))
+    doAssert len(set) == 100
+
+  block: # single number bounds work
+    var rand: float
+    for i in 1..1000:
+      rand = rand(1000.0)
+      doAssert rand <= 1000.0
+      doAssert rand >= 0.0
+
+  block: # slice bounds work
+    var rand: float
+    for i in 1..1000:
+      rand = rand(100.0..1000.0)
+      doAssert rand <= 1000.0
+      doAssert rand >= 100.0
+
+  block: # again gives new numbers
+    var rand1: float = rand(1000000.0)
+    when not (defined(js) or defined(nimscript)):
+      os.sleep(200)
+
+    var rand2: float = rand(1000000.0)
+    doAssert rand1 != rand2
+
+block: # random sample
+  block: # "non-uniform array sample unnormalized int CDF
+    let values = [10, 20, 30, 40, 50] # values
+    let counts = [4, 3, 2, 1, 0]      # weights aka unnormalized probabilities
+    var histo = initCountTable[int]()
+    let cdf = counts.cumsummed        # unnormalized CDF
+    for i in 0 ..< 5000:
+      histo.inc(sample(values, cdf))
+    doAssert histo.len == 4              # number of non-zero in `counts`
+    # Any one bin is a binomial random var for n samples, each with prob p of
+    # adding a count to k; E[k]=p*n, Var k=p*(1-p)*n, approximately Normal for
+    # big n.  So, P(abs(k - p*n)/sqrt(p*(1-p)*n))>3.0) =~ 0.0027, while
+    # P(wholeTestFails) =~ 1 - P(binPasses)^4 =~ 1 - (1-0.0027)^4 =~ 0.01.
+    for i, c in counts:
+      if c == 0:
+        doAssert values[i] notin histo
+        continue
+      let p = float(c) / float(cdf[^1])
+      let n = 5000.0
+      let expected = p * n
+      let stdDev = sqrt(n * p * (1.0 - p))
+      doAssert abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev
+
+  block: # non-uniform array sample normalized float CDF
+    let values = [10, 20, 30, 40, 50]     # values
+    let counts = [0.4, 0.3, 0.2, 0.1, 0]  # probabilities
+    var histo = initCountTable[int]()
+    let cdf = counts.cumsummed            # normalized CDF
+    for i in 0 ..< 5000:
+      histo.inc(sample(values, cdf))
+    doAssert histo.len == 4                  # number of non-zero in ``counts``
+    for i, c in counts:
+      if c == 0:
+        doAssert values[i] notin histo
+        continue
+      let p = float(c) / float(cdf[^1])
+      let n = 5000.0
+      let expected = p * n
+      let stdDev = sqrt(n * p * (1.0 - p))
+      # NOTE: like unnormalized int CDF test, P(wholeTestFails) =~ 0.01.
+      doAssert abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev
+
+block:
+  # 0 is a valid seed
+  var r = initRand(0)
+  doAssert r.rand(1.0) != r.rand(1.0)
+  r = initRand(10)
+  doAssert r.rand(1.0) != r.rand(1.0)
+  # changing the seed changes the sequence
+  var r1 = initRand(123)
+  var r2 = initRand(124)
+  doAssert r1.rand(1.0) != r2.rand(1.0)
+
+block: # bug #17467
+  let n = 1000
+  for i in -n .. n:
+    var r = initRand(i)
+    let x = r.rand(1.0)
+    doAssert x > 1e-4, $(x, i)
+      # This used to fail for each i in 0..<26844, i.e. the 1st produced value
+      # was predictable and < 1e-4, skewing distributions.
+
+block: # bug #16360, Natural overload
+  var r = initRand()
+  template test(a) =
+    let a2 = a
+    block:
+      let a3 = r.rand(a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+    block:
+      let a3 = rand(a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+  test int.high
+  test int.high - 1
+  test int.high - 2
+  test 0
+
+block: # same as above but use slice overload
+  var r = initRand()
+  template test[T](a: T) =
+    let a2: T = a
+    block:
+      let a3 = r.rand(T(0) .. a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+    block:
+      let a3 = rand(T(0) .. a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+  test cast[uint](int.high)
+  test cast[uint](int.high) + 1
+  whenJsNoBigInt64: discard
+  do:
+    test uint64.high
+    test uint64.high - 1
+  test uint.high - 2
+  test uint.high - 1
+  test uint.high
+  test int.high
+  test int.high - 1
+  test int.high - 2
+  test 0
+  test 0'u
+  test 0'u64
+
+block: # bug #16296
+  var r = initRand()
+  template test(x) =
+    let a2 = x
+    let a3 = r.rand(a2)
+    doAssert a3 <= a2.b
+    doAssert a3 >= a2.a
+    doAssert a3.type is a2.a.type
+  test(-2 .. int.high-1)
+  test(int.low .. int.high)
+  test(int.low+1 .. int.high)
+  test(int.low .. int.high-1)
+  test(int.low .. 0)
+  test(int.low .. -1)
+  test(int.low .. 1)
+  test(int64.low .. 1'i64)
+  test(10'u64 .. uint64.high)
+
+block: # bug #17670
+  type UInt48 = range[0'u64..2'u64^48-1]
+  let x = rand(UInt48)
+  doAssert x is UInt48
+
+block: # bug #17898
+  # Checks whether `initRand()` generates unique states.
+  # size should be 2^64, but we don't have time and space.
+
+  # Disable this test for js until js gets proper skipRandomNumbers.
+  when not defined(js):
+    const size = 1000
+    var
+      rands: array[size, Rand]
+      randSet: HashSet[Rand]
+    for i in 0..<size:
+      rands[i] = initRand()
+      randSet.incl rands[i]
+
+    doAssert randSet.len == size
+
+    # Checks random number sequences overlapping.
+    const numRepeat = 100
+    for i in 0..<size:
+      for j in 0..<numRepeat:
+        discard rands[i].next
+        doAssert rands[i] notin randSet
+
+block: # bug #22360
+  const size = 1000
+  var fc = 0
+  var tc = 0
+
+  for _ in 1..size:
+    let s = rand(bool)
+
+    if s:
+      inc tc
+    else:
+      inc fc
+
+  when defined(js) and not compileOption("jsbigint64"):
+    doAssert (tc, fc) == (515, 485), $(tc, fc)
+  else:
+    doAssert (tc, fc) == (510, 490), $(tc, fc)
+
+block:
+  when defined(js) and not compileOption("jsbigint64"):
+    doAssert rand(int32.high) == 335507522
+  else:
+    doAssert rand(int32.high) == 607539621
diff --git a/tests/stdlib/trat_float.nim b/tests/stdlib/trat_float.nim
new file mode 100644
index 000000000..663973bf9
--- /dev/null
+++ b/tests/stdlib/trat_float.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: '''type mismatch: got'''
+  file: "trat_float.nim"
+  line: "9,19"
+"""
+import rationals
+var
+  # this fails - no floats as num or den
+  r = initRational(1.0'f, 1.0'f)
diff --git a/tests/stdlib/trat_init.nim b/tests/stdlib/trat_init.nim
new file mode 100644
index 000000000..2be0c0099
--- /dev/null
+++ b/tests/stdlib/trat_init.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''true'''
+"""
+import rationals
+var
+  z = Rational[int](num: 0, den: 1)
+  o = initRational(num=1, den=1)
+  a = initRational(1, 2)
+
+try:
+  var
+    r = initRational(1, 0)  # this fails - no zero denominator
+except AssertionDefect:
+  echo "true"
diff --git a/tests/stdlib/trationals.nim b/tests/stdlib/trationals.nim
new file mode 100644
index 000000000..22d7f5c2d
--- /dev/null
+++ b/tests/stdlib/trationals.nim
@@ -0,0 +1,117 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[rationals, math]
+import std/assertions
+
+template main() =
+  var
+    z = Rational[int](num: 0, den: 1)
+    o = initRational(num = 1, den = 1)
+    a = initRational(1, 2)
+    u = 3u // 2
+    b = -1 // -2
+    m1 = -1 // 1
+    tt = 10 // 2
+
+  doAssert a == a
+  doAssert a - a == z
+  doAssert a + b == o
+  doAssert a / b == o
+  doAssert a * b == 1 // 4
+  doAssert 3 / a == 6 // 1
+  doAssert a / 3 == 1 // 6
+  doAssert tt * z == z
+  doAssert 10 * a == tt
+  doAssert a * 10 == tt
+  doAssert tt / 10 == a
+  doAssert a - m1 == 3 // 2
+  doAssert a + m1 == -1 // 2
+  doAssert m1 + tt == 16 // 4
+  doAssert m1 - tt == 6 // -1
+
+  doAssert z < o
+  doAssert z <= o
+  doAssert z == z
+  doAssert cmp(z, o) < 0
+  doAssert cmp(o, z) > 0
+
+  doAssert o == o
+  doAssert o >= o
+  doAssert not(o > o)
+  doAssert cmp(o, o) == 0
+  doAssert cmp(z, z) == 0
+  doAssert hash(o) == hash(o)
+
+  doAssert a == b
+  doAssert a >= b
+  doAssert not(b > a)
+  doAssert cmp(a, b) == 0
+  doAssert hash(a) == hash(b)
+
+  var x = 1 // 3
+
+  x *= 5 // 1
+  doAssert x == 5 // 3
+  x += 2 // 9
+  doAssert x == 17 // 9
+  x -= 9 // 18
+  doAssert x == 25 // 18
+  x /= 1 // 2
+  doAssert x == 50 // 18
+
+  var y = 1 // 3
+
+  y *= 4
+  doAssert y == 4 // 3
+  y += 5
+  doAssert y == 19 // 3
+  y -= 2
+  doAssert y == 13 // 3
+  y /= 9
+  doAssert y == 13 // 27
+
+  doAssert toRational(5) == 5 // 1
+  doAssert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
+  doAssert toInt(z) == 0
+
+  when sizeof(int) == 8:
+    doAssert toRational(0.98765432) == 2111111029 // 2137499919
+    doAssert toRational(PI) == 817696623 // 260280919
+  when sizeof(int) == 4:
+    doAssert toRational(0.98765432) == 80 // 81
+    doAssert toRational(PI) == 355 // 113
+
+  doAssert toRational(0.1) == 1 // 10
+  doAssert toRational(0.9) == 9 // 10
+
+  doAssert toRational(0.0) == 0 // 1
+  doAssert toRational(-0.25) == 1 // -4
+  doAssert toRational(3.2) == 16 // 5
+  doAssert toRational(0.33) == 33 // 100
+  doAssert toRational(0.22) == 11 // 50
+  doAssert toRational(10.0) == 10 // 1
+
+  doAssert (1 // 1) div (3 // 10) == 3
+  doAssert (-1 // 1) div (3 // 10) == -3
+  doAssert (3 // 10) mod (1 // 1) == 3 // 10
+  doAssert (-3 // 10) mod (1 // 1) == -3 // 10
+  doAssert floorDiv(1 // 1, 3 // 10) == 3
+  doAssert floorDiv(-1 // 1, 3 // 10) == -4
+  doAssert floorMod(3 // 10, 1 // 1) == 3 // 10
+  doAssert floorMod(-3 // 10, 1 // 1) == 7 // 10
+
+  when sizeof(int) == 8:
+    doAssert almostEqual(PI.toRational.toFloat, PI)
+
+  # unsigned
+  doAssert u == u
+  doAssert u + u == 3u // 1
+  doAssert 3u.toRational - u == u
+  doAssert u * 2 == 3u // 1
+
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tre.nim b/tests/stdlib/tre.nim
new file mode 100644
index 000000000..39637434d
--- /dev/null
+++ b/tests/stdlib/tre.nim
@@ -0,0 +1,122 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/re
+import std/assertions
+
+proc testAll() =
+  doAssert match("(a b c)", rex"\( .* \)")
+  doAssert match("WHiLe", re("while", {reIgnoreCase}))
+
+  doAssert "0158787".match(re"\d+")
+  doAssert "ABC 0232".match(re"\w+\s+\d+")
+  doAssert "ABC".match(rex"\d+ | \w+")
+
+  {.push warnings:off.}
+  doAssert matchLen("key", re"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b") == 3
+  {.pop.}
+
+  var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
+  doAssert matchLen("key1=  cal9", pattern) == 11
+
+  doAssert find("_____abc_______", re"abc") == 5
+  doAssert findBounds("_____abc_______", re"abc") == (5,7)
+
+  var matches: array[6, string]
+  if match("abcdefg", re"c(d)ef(g)", matches, 2):
+    doAssert matches[0] == "d"
+    doAssert matches[1] == "g"
+  else:
+    doAssert false
+
+  if "abc" =~ re"(a)bcxyz|(\w+)":
+    doAssert matches[1] == "abc"
+  else:
+    doAssert false
+
+  if "abc" =~ re"(cba)?.*":
+    doAssert matches[0] == ""
+  else: doAssert false
+
+  if "abc" =~ re"().*":
+    doAssert matches[0] == ""
+  else: doAssert false
+
+  doAssert "var1=key; var2=key2".endsWith(re"\w+=\w+")
+  doAssert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") ==
+         "var1<-keykey; var2<-key2key2")
+  doAssert("var1=key; var2=key2".replace(re"(\w+)=(\w+)", "$1<-$2$2") ==
+         "$1<-$2$2; $1<-$2$2")
+
+  var accum: seq[string] = @[]
+  for word in split("00232this02939is39an22example111", re"\d+"):
+    accum.add(word)
+  doAssert(accum == @["", "this", "is", "an", "example", ""])
+
+  accum = @[]
+  for word in split("00232this02939is39an22example111", re"\d+", maxsplit=2):
+    accum.add(word)
+  doAssert(accum == @["", "this", "is39an22example111"])
+
+  accum = @[]
+  for word in split("AAA :   : BBB", re"\s*:\s*"):
+    accum.add(word)
+  doAssert(accum == @["AAA", "", "BBB"])
+
+  doAssert(split("abc", re"") == @["a", "b", "c"])
+  doAssert(split("", re"") == @[])
+
+  doAssert(split("a;b;c", re";") == @["a", "b", "c"])
+  doAssert(split(";a;b;c", re";") == @["", "a", "b", "c"])
+  doAssert(split(";a;b;c;", re";") == @["", "a", "b", "c", ""])
+  doAssert(split("a;b;c;", re";") == @["a", "b", "c", ""])
+  doAssert(split("00232this02939is39an22example111", re"\d+", maxsplit=2) == @["", "this", "is39an22example111"])
+
+
+  for x in findAll("abcdef", re"^{.}", 3):
+    doAssert x == "d"
+  accum = @[]
+  for x in findAll("abcdef", re".", 3):
+    accum.add(x)
+  doAssert(accum == @["d", "e", "f"])
+
+  doAssert("XYZ".find(re"^\d*") == 0)
+  doAssert("XYZ".match(re"^\d*") == true)
+
+  block:
+    var matches: array[16, string]
+    if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches):
+      for i in 0..matches.high:
+        doAssert matches[i] == $chr(i + 'a'.ord)
+    else:
+      doAssert false
+
+  block:   # Buffer based RE
+    var cs: cstring = "_____abc_______"
+    doAssert(cs.find(re"abc", bufSize=15) == 5)
+    doAssert(cs.matchLen(re"_*abc", bufSize=15) == 8)
+    doAssert(cs.matchLen(re"abc", start=5, bufSize=15) == 3)
+    doAssert(cs.matchLen(re"abc", start=5, bufSize=7) == -1)
+    doAssert(cs.matchLen(re"abc_*", start=5, bufSize=10) == 5)
+    var accum: seq[string] = @[]
+    for x in cs.findAll(re"[a-z]", start=3, bufSize=15):
+      accum.add($x)
+    doAssert(accum == @["a","b","c"])
+
+  block: # bug #9306
+    doAssert replace("bar", re"^", "foo") == "foobar"
+    doAssert replace("foo", re"$", "bar") == "foobar"
+
+
+  block: # bug #9437
+    doAssert replace("foo", re"", "-") == "-f-o-o-"
+    doAssert replace("ooo", re"o", "-") == "---"
+
+  block: # bug #14468
+    accum = @[]
+    for word in split("this is an example", re"\b"):
+      accum.add(word)
+    doAssert(accum == @["this", " ", "is", " ", "an", " ", "example"])
+
+testAll()
diff --git a/tests/stdlib/treadln.nim b/tests/stdlib/treadln.nim
new file mode 100644
index 000000000..4a070e848
--- /dev/null
+++ b/tests/stdlib/treadln.nim
@@ -0,0 +1,23 @@
+
+discard """
+output: '''
+test the improved readline handling that does not care whether its
+Macintosh, Unix or Windows text format.
+'''
+"""
+
+import std/syncio
+
+# test the improved readline handling that does not care whether its
+# Macintosh, Unix or Windows text format.
+
+var
+  inp: File
+  line: string
+
+if open(inp, "tests/stdlib/treadln.nim"):
+  while not endOfFile(inp):
+    line = readLine(inp)
+    if line.len >= 2 and line[0] == '#' and line[1] == ' ':
+      echo line[2..^1]
+  close(inp)
diff --git a/tests/stdlib/tregex.nim b/tests/stdlib/tregex.nim
index ae6714de1..9dd66cd60 100644
--- a/tests/stdlib/tregex.nim
+++ b/tests/stdlib/tregex.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tregex.nim"
   output: "key: keyAYes!"
+  matrix: "--mm:refc; --mm:orc"
 """
 # Test the new regular expression module
 # which is based on the PCRE library
@@ -12,7 +12,7 @@ when defined(powerpc64):
 else:
   import
     re
-
+  import std/syncio
   if "keyA = valueA" =~ re"\s*(\w+)\s*\=\s*(\w+)":
     write(stdout, "key: ", matches[0])
   elif "# comment!" =~ re.re"\s*(\#.*)":
@@ -27,5 +27,3 @@ else:
     echo("Bug!")
 
   #OUT key: keyAYes!
-
-
diff --git a/tests/stdlib/tregistry.nim b/tests/stdlib/tregistry.nim
new file mode 100644
index 000000000..25aed8df8
--- /dev/null
+++ b/tests/stdlib/tregistry.nim
@@ -0,0 +1,16 @@
+discard """
+  disabled: "unix"
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+when defined(windows):
+  import std/registry
+  import std/assertions
+
+  block: # bug #14010
+    let path = "Environment"
+    let key = "D20210328T202842_key"
+    let val = "D20210328T202842_val"
+    let handle = HKEY_CURRENT_USER
+    setUnicodeValue("Environment", key, val, handle)
+    doAssert getUnicodeValue(path, key, handle) == val
diff --git a/tests/stdlib/treguse.nim b/tests/stdlib/treguse.nim
deleted file mode 100644
index 3d09eb731..000000000
--- a/tests/stdlib/treguse.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-discard """
-  file: "treguse.nim"
-  output: "055this should be the casehugh"
-"""
-# Test the register usage of the virtual machine and
-# the blocks in var statements
-
-proc main(a, b: int) =
-  var x = 0
-  write(stdout, x)
-  if x == 0:
-    var y = 55
-    write(stdout, y)
-    write(stdout, "this should be the case")
-    var input = "<no input>"
-    if input == "Andreas":
-      write(stdout, "wow")
-    else:
-      write(stdout, "hugh")
-  else:
-    var z = 66
-    write(stdout, z) # "bug!")
-
-main(45, 1000)
-#OUT 055this should be the casehugh
-
-
diff --git a/tests/stdlib/treloop.nim b/tests/stdlib/treloop.nim
deleted file mode 100644
index b4221525d..000000000
--- a/tests/stdlib/treloop.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-discard """
-  output: '''@["(", "+", " 1", " 2", ")"]'''
-"""
-
-import re
-
-let str = "(+ 1 2)"
-var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
-echo str.findAll(tokenRE)
diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim
index 18fe7e054..3956b98f9 100644
--- a/tests/stdlib/trepr.nim
+++ b/tests/stdlib/trepr.nim
@@ -1,29 +1,328 @@
 discard """
-  file: "trepr.nim"
-  output: "{a, b}{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}"
+  targets: "c cpp js"
+  matrix: "--mm:refc;--mm:arc"
 """
 
-type
-  TEnum = enum
-    a, b
-
-var val = {a, b}
-stdout.write(repr(val))
-stdout.writeLine(repr({'a'..'z', 'A'..'Z'}))
-
-type
-  TObj {.pure, inheritable.} = object
-    data: int
-  TFoo = ref object of TObj
-    d2: float
-var foo: TFoo
-new(foo)
-
-when false:
-  # cannot capture this output as it contains a memory address :-/
-  echo foo.repr
-#var testseq: seq[string] = @[
-#  "a", "b", "c", "d", "e"
-#]
-#echo(repr(testseq))
+# if excessive, could remove 'cpp' from targets
 
+from strutils import endsWith, contains, strip
+from std/macros import newLit
+import std/assertions
+
+macro deb(a): string = newLit a.repr.strip
+macro debTyped(a: typed): string = newLit a.repr.strip
+
+template main() =
+  doAssert repr({3,5}) == "{3, 5}"
+
+  block:
+    type TEnum = enum a, b
+    var val = {a, b}
+    when nimvm:
+      discard
+      #[
+      # BUG:
+      {0, 1}
+      {97..99, 65..67}
+      ]#
+    else:
+      doAssert repr(val) == "{a, b}"
+      doAssert repr({'a'..'c', 'A'..'C'}) == "{'A', 'B', 'C', 'a', 'b', 'c'}"
+
+    type
+      TObj {.pure, inheritable.} = object
+        data: int
+      TFoo = ref object of TObj
+        d2: float
+    var foo: TFoo
+    new(foo)
+
+  #[
+  BUG:
+  --gc:arc returns `"abc"`
+  regular gc returns with address, e.g. 0x1068aae60"abc", but only
+  for c,cpp backends (not js, vm)
+  ]#
+  block:
+    doAssert repr("abc").endsWith "\"abc\""
+    var b: cstring = "def"
+    doAssert repr(b).endsWith "\"def\""
+
+  block:
+    var c = @[1,2]
+    when nimvm:
+      discard # BUG: this shows [1, 2] instead of @[1, 2]
+    else:
+      # BUG (already mentioned above): some backends / gc show address, others don't
+      doAssert repr(c).endsWith "@[1, 2]"
+
+    let d = @["foo", "bar"]
+    let s = repr(d)
+    # depending on backend/gc, we get 0x106a1c350@[0x106a1c390"foo", 0x106a1c3c0"bar"]
+    doAssert "\"foo\"," in s
+
+  var arr = [1, 2, 3]
+  doAssert repr(arr) == "[1, 2, 3]"
+
+  block: # bug #7878
+    proc reprOpenarray(variable: var openArray[int]): string = repr(variable)
+    when defined(js): discard # BUG: doesn't work
+    else:
+      doAssert reprOpenarray(arr) == "[1, 2, 3]"
+
+  block: # bug #17292 repr with `do`
+    template foo(a, b, c, d) = discard
+    block:
+      let a = deb:
+        foo(1, 2, 3, 4)
+      doAssert a == "foo(1, 2, 3, 4)"
+    block:
+      let a = deb:
+        foo(1, 2, 3): 4
+      doAssert a == """
+foo(1, 2, 3):
+  4"""
+
+    block:
+      let a = deb:
+        foo(1, 2): 3
+        do: 4
+      doAssert a == """
+foo(1, 2):
+  3
+do:
+  4"""
+
+    block:
+      let a = deb:
+        foo(1): 3
+        do: 3
+        do: 4
+      doAssert a == """
+foo(1):
+  3
+do:
+  3
+do:
+  4"""
+
+    block:
+      let a = deb:
+        foo(1):
+          3
+        do:
+          discard
+          3
+        do:
+          discard
+          4
+
+      doAssert a == """
+foo(1):
+  3
+do:
+  discard
+  3
+do:
+  discard
+  4"""
+
+    block:
+      let a = deb:
+        foo: 1
+        do: 2
+        do: 3
+        do: 4
+      doAssert a == """
+foo:
+  1
+do:
+  2
+do:
+  3
+do:
+  4"""
+
+  block: # bug #17292 repr with `(discard)` (`discard` would result in illegal code)
+    let a = deb:
+      let f {.inject.} = () => (discard)
+    doAssert a == """
+let f {.inject.} = () =>
+    (discard )"""
+
+    let a2 = deb:
+      block:
+        discard
+      discard
+
+      block:
+        when true: discard
+
+      # let a = b => discard # illegal
+      discard b => (discard) # legal
+
+      block:
+        return
+    doAssert a2 == """
+block:
+  discard
+discard
+block:
+  when true:
+    discard
+discard b =>
+    (discard )
+block:
+  return"""
+
+  block: # bug #17292 (bug 4)
+    let a = deb:
+      proc `=destroy`() = discard
+      proc `'foo`(): int = discard
+      proc `foo bar baz`(): int = discard
+    let a2 = """
+proc `=destroy`() =
+  discard
+
+proc `'foo`(): int =
+  discard
+
+proc `foo bar baz`(): int =
+  discard"""
+    doAssert a2 == a
+
+  block: # setters: `foo=`
+    let a = deb:
+      proc `foo=`() = discard
+    doAssert a == """
+proc `foo=`() =
+  discard"""
+
+  block: # bug #14850
+    block:
+      let a = deb:
+        template bar(): untyped =
+          foo1:
+            discard
+            4
+          foo2(1):
+            discard
+            4
+          foo3(1):
+            discard
+            4
+          do: 1
+          do: 2
+          x.add foo4
+          x.add: foo5: 3
+          x.add foo6 do: 4
+          a.add(foo7 do:
+            echo "baz"
+            4)
+
+      doAssert a == """
+template bar(): untyped =
+  foo1:
+    discard
+    4
+  foo2(1):
+    discard
+    4
+  foo3(1):
+    discard
+    4
+  do:
+    1
+  do:
+    2
+  x.add foo4
+  x.add:
+    foo5:
+      3
+  x.add foo6 do:
+    4
+  a.add(foo7 do:
+    echo "baz"
+    4)"""
+
+  block: # one liner doc comments
+    let a1 = deb:
+      func fn1(): int = 1  ## comment
+      func fn2(): int = 1
+        ## comment
+    let a2 = debTyped:
+      func fn1(): int = 1  ## comment
+      func fn2(): int = 1
+        ## comment
+    doAssert a1 == """
+func fn1(): int =
+  ## comment
+  1
+
+func fn2(): int =
+  ## comment
+  1"""
+    doAssert a2 == """
+func fn1(): int =
+  ## comment
+  result = 1
+
+func fn2(): int =
+  ## comment
+  result = 1"""
+
+  block: # block calls
+    let a = deb:
+      foo(a, b, (c, d)):
+        e
+        f
+      do: g
+      of h: i
+      elif j: k
+      except m: n
+      do () -> u: v
+      finally: o
+
+      a + b:
+        c
+        d
+      do:
+        e
+        f
+      else: g
+
+      *a: b
+      do: c
+
+    doAssert a == """foo(a, b, (c, d)):
+  e
+  f
+do:
+  g
+of h:
+  i
+elif j:
+  k
+except m:
+  n
+do -> u:
+  v
+finally:
+  o
+a + b:
+  c
+  d
+do:
+  e
+  f
+else:
+  g
+*a:
+  b
+do:
+  c"""
+
+  doAssert repr(1..2) == "1 .. 2"
+
+static: main()
+main()
diff --git a/tests/stdlib/trepr2.nim b/tests/stdlib/trepr2.nim
deleted file mode 100644
index 300df565d..000000000
--- a/tests/stdlib/trepr2.nim
+++ /dev/null
@@ -1,32 +0,0 @@
-# test the new "repr" built-in proc
-
-type
-  TEnum = enum
-    en1, en2, en3, en4, en5, en6
-
-  TPoint {.final.} = object
-    x, y, z: int
-    s: array[0..1, string]
-    e: TEnum
-
-var
-  p: TPoint
-  q: ref TPoint
-  s: seq[ref TPoint]
-
-p.x = 0
-p.y = 13
-p.z = 45
-p.s[0] = "abc"
-p.s[1] = "xyz"
-p.e = en6
-
-new(q)
-q[] = p
-
-s = @[q, q, q, q]
-
-writeLine(stdout, repr(p))
-writeLine(stdout, repr(q))
-writeLine(stdout, repr(s))
-writeLine(stdout, repr(en4))
diff --git a/tests/stdlib/trlocks.nim b/tests/stdlib/trlocks.nim
new file mode 100644
index 000000000..135d9b028
--- /dev/null
+++ b/tests/stdlib/trlocks.nim
@@ -0,0 +1,14 @@
+discard """
+  action: "compile"
+  # Disallow joining to ensure it can compile in isolation.
+  # See #15584
+  joinable: false
+  cmd: "nim $target --threads:on $options $file"
+"""
+
+# bugfix #15584
+
+import rlocks
+
+var r: RLock
+r.initRLock()
diff --git a/tests/stdlib/tropes.nim b/tests/stdlib/tropes.nim
new file mode 100644
index 000000000..eb0edc364
--- /dev/null
+++ b/tests/stdlib/tropes.nim
@@ -0,0 +1,104 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/ropes
+import std/assertions
+
+template main() =
+  block:
+    let r: Rope = nil
+    doAssert r[0] == '\0'
+    doAssert $r == ""
+
+  block:
+    var
+      r1 = rope("Hello, ")
+      r2 = rope("Nim-Lang")
+
+    let r = r1 & r2
+    let s = $r
+    doAssert s == "Hello, Nim-Lang"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    let r = rope("Hello, Nim-Lang")
+
+    let s = $r
+    doAssert s == "Hello, Nim-Lang"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    var r: Rope
+    r.add rope("Nim ")
+    r.add rope("is ")
+    r.add rope("a ")
+    r.add rope("great ")
+    r.add rope("language")
+
+    let s = $r
+    doAssert s == "Nim is a great language"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    var r: Rope
+    r.add rope("My Conquest")
+    r.add rope(" is ")
+    r.add rope("the Sea of Stars")
+
+    let s = $r
+    doAssert s == "My Conquest is the Sea of Stars"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    var r: Rope
+    r.add rope("My Conquest")
+    r.add rope(" is ")
+    r.add rope("the Sea of Stars")
+
+    doAssert $r == "My Conquest is the Sea of Stars"
+
+    var i: int
+    for item in r:
+      doAssert r[i] == item
+      inc i
+
+    doAssert r[66] == '\0'
+
+  block:
+    let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")]
+    doAssert $r1 == "Nim is a great language"
+
+    let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")]
+    doAssert $r2 == "Nim is a great language"
+
+  block: # `[]`
+    let r1 = rope("Hello, Nim!")
+
+    doAssert r1[-2] == '\0'
+    doAssert r1[0] == 'H'
+    doAssert r1[7] == 'N'
+    doAssert r1[22] == '\0'
+
+    let r2 = rope("Hello") & rope(", Nim!")
+
+    doAssert r2[-2] == '\0'
+    doAssert r2[0] == 'H'
+    doAssert r2[7] == 'N'
+    doAssert r2[22] == '\0'
+
+static: main()
+main()
diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim
new file mode 100644
index 000000000..ceab34bc9
--- /dev/null
+++ b/tests/stdlib/trst.nim
@@ -0,0 +1,1994 @@
+discard """
+  output: '''
+
+[Suite] RST parsing
+
+[Suite] RST tables
+
+[Suite] RST indentation
+
+[Suite] Markdown indentation
+
+[Suite] Warnings
+
+[Suite] RST include directive
+
+[Suite] RST escaping
+
+[Suite] RST inline markup
+
+[Suite] Misc isssues
+'''
+matrix: "--mm:refc; --mm:orc"
+"""
+
+# tests for rst module
+
+import ../../lib/packages/docutils/[rstgen, rst, rstast]
+import unittest, strutils
+import std/private/miscdollars
+import os
+import std/[assertions, syncio]
+
+const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
+# legacy nimforum / old default mode:
+const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled}
+const pureRst = {roNimFile, roSandboxDisabled}
+
+proc toAst(input: string,
+            rstOptions: RstParseOptions = preferMarkdown,
+            error: ref string = nil,
+            warnings: ref seq[string] = nil): string =
+  ## If `error` is nil then no errors should be generated.
+  ## The same goes for `warnings`.
+  proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
+                      arg: string) =
+    let mc = msgkind.whichMsgClass
+    let a = $msgkind % arg
+    var message: string
+    toLocation(message, filename, line, col + ColRstOffset)
+    message.add " $1: $2" % [$mc, a]
+    if mc == mcError:
+      if error == nil:
+        raise newException(EParseError, "[unexpected error] " & message)
+      error[] = message
+      # we check only first error because subsequent ones may be meaningless
+      raise newException(EParseError, "")
+    else:
+      doAssert warnings != nil, "unexpected RST warning '" & message & "'"
+      warnings[].add message
+  try:
+    const filen = "input"
+
+    proc myFindFile(filename: string): string =
+      # we don't find any files in online mode:
+      result = ""
+
+    var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit,
+                               rstOptions, myFindFile, nil, testMsgHandler)
+    result = treeRepr(rst)
+  except EParseError as e:
+    if e.msg != "":
+      result = e.msg
+
+suite "RST parsing":
+  test "Standalone punctuation is not parsed as heading overlines":
+    check(dedent"""
+        Paragraph
+
+        !""".toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Paragraph'
+          rnParagraph
+            rnLeaf  '!'
+      """)
+
+    check(dedent"""
+        Paragraph1
+
+        ...
+
+        Paragraph2""".toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Paragraph1'
+          rnParagraph
+            rnLeaf  '...'
+          rnParagraph
+            rnLeaf  'Paragraph2'
+      """)
+
+    check(dedent"""
+        ---
+        Paragraph""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  '---'
+          rnLeaf  ' '
+          rnLeaf  'Paragraph'
+      """)
+
+  test "References are whitespace-neutral and case-insensitive":
+    # refname is 'lexical-analysis', the same for all the 3 variants:
+    check(dedent"""
+        Lexical Analysis
+        ================
+
+        Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_.
+        """.toAst ==
+      dedent"""
+        rnInner
+          rnHeadline  level=1  anchor='lexical-analysis'
+            rnLeaf  'Lexical'
+            rnLeaf  ' '
+            rnLeaf  'Analysis'
+          rnParagraph
+            rnLeaf  'Ref'
+            rnLeaf  '.'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'Lexical'
+                rnLeaf  ' '
+                rnLeaf  'Analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  ' '
+            rnLeaf  'or'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'Lexical'
+                rnLeaf  ' '
+                rnLeaf  'analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  ' '
+            rnLeaf  'or'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'lexical'
+                rnLeaf  ' '
+                rnLeaf  'analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  '.'
+            rnLeaf  ' '
+      """)
+
+  test "RST quoted literal blocks":
+    let expected =
+      dedent"""
+        rnInner
+          rnLeaf  'Paragraph'
+          rnLeaf  ':'
+          rnLiteralBlock
+            rnLeaf  '>x'
+        """
+
+    check(dedent"""
+        Paragraph::
+
+        >x""".toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        Paragraph::
+
+            >x""".toAst(rstOptions = preferRst) == expected)
+
+  test "RST quoted literal blocks, :: at a separate line":
+    let expected =
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'Paragraph'
+          rnLiteralBlock
+            rnLeaf  '>x
+        >>y'
+      """
+
+    check(dedent"""
+        Paragraph
+
+        ::
+
+        >x
+        >>y""".toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        Paragraph
+
+        ::
+
+          >x
+          >>y""".toAst(rstOptions = preferRst) == expected)
+
+  test "Markdown quoted blocks":
+    check(dedent"""
+        Paragraph.
+        >x""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'Paragraph'
+          rnLeaf  '.'
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnLeaf  'x'
+      """)
+
+    # bug #17987
+    check(dedent"""
+        foo https://github.com/nim-lang/Nim/issues/8258
+
+        > bar""".toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'foo'
+            rnLeaf  ' '
+            rnStandaloneHyperlink
+              rnLeaf  'https://github.com/nim-lang/Nim/issues/8258'
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnLeaf  'bar'
+      """)
+
+    let expected = dedent"""
+        rnInner
+          rnLeaf  'Paragraph'
+          rnLeaf  '.'
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnInner
+                rnLeaf  'x1'
+                rnLeaf  ' '
+                rnLeaf  'x2'
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnInner
+                rnLeaf  'y1'
+                rnLeaf  ' '
+                rnLeaf  'y2'
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnLeaf  'z'
+        """
+
+    check(dedent"""
+        Paragraph.
+        >x1 x2
+        >>y1 y2
+        >z""".toAst == expected)
+
+    check(dedent"""
+        Paragraph.
+        > x1 x2
+        >> y1 y2
+        > z""".toAst == expected)
+
+    check(dedent"""
+        >x
+        >y
+        >z""".toAst ==
+      dedent"""
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnInner
+              rnLeaf  'x'
+              rnLeaf  ' '
+              rnLeaf  'y'
+              rnLeaf  ' '
+              rnLeaf  'z'
+      """)
+
+    check(dedent"""
+        > z
+        > > >y
+        """.toAst ==
+      dedent"""
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnLeaf  'z'
+          rnMarkdownBlockQuoteItem  quotationDepth=3
+            rnLeaf  'y'
+        """)
+
+  test "Markdown quoted blocks: lazy":
+    let expected = dedent"""
+        rnInner
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnInner
+                rnLeaf  'x'
+                rnLeaf  ' '
+                rnLeaf  'continuation1'
+                rnLeaf  ' '
+                rnLeaf  'continuation2'
+          rnParagraph
+            rnLeaf  'newParagraph'
+      """
+    check(dedent"""
+        >>x
+        continuation1
+        continuation2
+
+        newParagraph""".toAst == expected)
+
+    check(dedent"""
+        >> x
+        continuation1
+        continuation2
+
+        newParagraph""".toAst == expected)
+
+    # however mixing more than 1 non-lazy line and lazy one(s) splits quote
+    # in our parser, which appeared the easiest way to handle such cases:
+    var warnings = new seq[string]
+    check(dedent"""
+        >> x
+        >> continuation1
+        continuation2
+
+        newParagraph""".toAst(warnings=warnings) ==
+      dedent"""
+        rnInner
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnLeaf  'x'
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnInner
+                rnLeaf  'continuation1'
+                rnLeaf  ' '
+                rnLeaf  'continuation2'
+          rnParagraph
+            rnLeaf  'newParagraph'
+        """)
+    check(warnings[] == @[
+        "input(2, 1) Warning: RST style: two or more quoted lines " &
+        "are followed by unquoted line 3"])
+
+  test "Markdown quoted blocks: not lazy":
+    # here is where we deviate from CommonMark specification: 'bar' below is
+    # not considered as continuation of 2-level '>> foo' quote.
+    check(dedent"""
+        >>> foo
+        > bar
+        >> baz
+        """.toAst() ==
+      dedent"""
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=3
+            rnLeaf  'foo'
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnLeaf  'bar'
+          rnMarkdownBlockQuoteItem  quotationDepth=2
+            rnLeaf  'baz'
+        """)
+
+
+  test "Markdown quoted blocks: inline markup works":
+    check(dedent"""
+        > hi **bold** text
+        """.toAst == dedent"""
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnInner
+                rnLeaf  'hi'
+                rnLeaf  ' '
+                rnStrongEmphasis
+                  rnLeaf  'bold'
+                rnLeaf  ' '
+                rnLeaf  'text'
+        """)
+
+  test "Markdown quoted blocks: blank line separator":
+    let expected = dedent"""
+      rnInner
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnInner
+              rnLeaf  'x'
+              rnLeaf  ' '
+              rnLeaf  'y'
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnInner
+              rnLeaf  'z'
+              rnLeaf  ' '
+              rnLeaf  't'
+      """
+    check(dedent"""
+        >x
+        >y
+
+        > z
+        > t""".toAst == expected)
+
+    check(dedent"""
+        >x
+        y
+
+        > z
+         t""".toAst == expected)
+
+  test "Markdown quoted blocks: nested body blocks/elements work #1":
+    let expected = dedent"""
+      rnMarkdownBlockQuote
+        rnMarkdownBlockQuoteItem  quotationDepth=1
+          rnBulletList
+            rnBulletItem
+              rnInner
+                rnLeaf  'x'
+            rnBulletItem
+              rnInner
+                rnLeaf  'y'
+      """
+
+    check(dedent"""
+        > - x
+          - y
+        """.toAst == expected)
+
+    # TODO: if bug #17340 point 28 is resolved then this may work:
+    # check(dedent"""
+    #     > - x
+    #     - y
+    #     """.toAst == expected)
+
+    check(dedent"""
+        > - x
+        > - y
+        """.toAst == expected)
+
+    check(dedent"""
+        >
+        > - x
+        >
+        > - y
+        >
+        """.toAst == expected)
+
+  test "Markdown quoted blocks: nested body blocks/elements work #2":
+    let expected = dedent"""
+      rnAdmonition  adType=note
+        [nil]
+        [nil]
+        rnDefList
+          rnDefItem
+            rnDefName
+              rnLeaf  'deflist'
+              rnLeaf  ':'
+            rnDefBody
+              rnMarkdownBlockQuote
+                rnMarkdownBlockQuoteItem  quotationDepth=2
+                  rnInner
+                    rnLeaf  'quote'
+                    rnLeaf  ' '
+                    rnLeaf  'continuation'
+      """
+
+    check(dedent"""
+        .. Note:: deflist:
+                    >> quote
+                    continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        .. Note::
+           deflist:
+             >> quote
+             continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        .. Note::
+           deflist:
+             >> quote
+             >> continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+    # spaces are not significant between `>`:
+    check(dedent"""
+        .. Note::
+           deflist:
+             > > quote
+             > > continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+  test "Markdown quoted blocks: de-indent handled well":
+    check(dedent"""
+        >
+        >   - x
+        >   - y
+        >
+        > Paragraph.
+        """.toAst(rstOptions = preferRst) == dedent"""
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnInner
+                rnBlockQuote
+                  rnBulletList
+                    rnBulletItem
+                      rnInner
+                        rnLeaf  'x'
+                    rnBulletItem
+                      rnInner
+                        rnLeaf  'y'
+                rnParagraph
+                  rnLeaf  'Paragraph'
+                  rnLeaf  '.'
+          """)
+
+  let expectCodeBlock = dedent"""
+      rnCodeBlock
+        [nil]
+        rnFieldList
+          rnField
+            rnFieldName
+              rnLeaf  'default-language'
+            rnFieldBody
+              rnLeaf  'Nim'
+        rnLiteralBlock
+          rnLeaf  'let a = 1
+      ```'
+      """
+
+  test "Markdown footnotes":
+    # Testing also 1) correct order of manually-numbered and automatically-
+    # numbered footnotes; 2) no spaces between references (html & 3 below):
+
+    check(dedent"""
+        Paragraph [^1] [^html-hyphen][^3] and [^latex]
+
+        [^1]: footnote1
+
+        [^html-hyphen]: footnote2
+           continuation2
+
+        [^latex]: footnote4
+
+        [^3]: footnote3
+            continuation3
+        """.toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'Paragraph'
+            rnLeaf  ' '
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '1'
+              rnLeaf  'footnote-1'
+            rnLeaf  ' '
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '2'
+              rnLeaf  'footnote-htmlminushyphen'
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '3'
+              rnLeaf  'footnote-3'
+            rnLeaf  ' '
+            rnLeaf  'and'
+            rnLeaf  ' '
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '4'
+              rnLeaf  'footnote-latex'
+          rnFootnoteGroup
+            rnFootnote  anchor='footnote-1'
+              rnInner
+                rnLeaf  '1'
+              rnLeaf  'footnote1'
+            rnFootnote  anchor='footnote-htmlminushyphen'
+              rnInner
+                rnLeaf  '2'
+              rnInner
+                rnLeaf  'footnote2'
+                rnLeaf  ' '
+                rnLeaf  'continuation2'
+            rnFootnote  anchor='footnote-latex'
+              rnInner
+                rnLeaf  '4'
+              rnLeaf  'footnote4'
+            rnFootnote  anchor='footnote-3'
+              rnInner
+                rnLeaf  '3'
+              rnInner
+                rnLeaf  'footnote3'
+                rnLeaf  ' '
+                rnLeaf  'continuation3'
+      """)
+
+  test "Markdown code blocks with more > 3 backticks":
+    check(dedent"""
+        ````
+        let a = 1
+        ```
+        ````""".toAst == expectCodeBlock)
+
+  test "Markdown code blocks with ~~~":
+    check(dedent"""
+        ~~~
+        let a = 1
+        ```
+        ~~~""".toAst == expectCodeBlock)
+    check(dedent"""
+        ~~~~~
+        let a = 1
+        ```
+        ~~~~~""".toAst == expectCodeBlock)
+
+  test "Markdown code blocks with Nim-specific arguments":
+    check(dedent"""
+        ```nim number-lines=1 test
+        let a = 1
+        ```""".toAst ==
+      dedent"""
+        rnCodeBlock
+          rnDirArg
+            rnLeaf  'nim'
+          rnFieldList
+            rnField
+              rnFieldName
+                rnLeaf  'number-lines'
+              rnFieldBody
+                rnLeaf  '1'
+            rnField
+              rnFieldName
+                rnLeaf  'test'
+              rnFieldBody
+          rnLiteralBlock
+            rnLeaf  'let a = 1'
+        """)
+
+    check(dedent"""
+        ```nim test = "nim c $1"  number-lines = 1
+        let a = 1
+        ```""".toAst ==
+      dedent"""
+        rnCodeBlock
+          rnDirArg
+            rnLeaf  'nim'
+          rnFieldList
+            rnField
+              rnFieldName
+                rnLeaf  'test'
+              rnFieldBody
+                rnLeaf  '"nim c $1"'
+            rnField
+              rnFieldName
+                rnLeaf  'number-lines'
+              rnFieldBody
+                rnLeaf  '1'
+          rnLiteralBlock
+            rnLeaf  'let a = 1'
+        """)
+
+  test "additional indentation < 4 spaces is handled fine":
+    check(dedent"""
+        Indentation
+
+          ```nim
+            let a = 1
+          ```""".toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Indentation'
+          rnParagraph
+            rnCodeBlock
+              rnDirArg
+                rnLeaf  'nim'
+              [nil]
+              rnLiteralBlock
+                rnLeaf  '  let a = 1'
+      """)
+      # | |
+      # |  \ indentation of exactly two spaces before 'let a = 1'
+
+  test "no blank line is required before or after Markdown code block":
+    let inputBacktick = dedent"""
+        Some text
+        ```
+        CodeBlock()
+        ```
+        Other text"""
+    let inputTilde = dedent"""
+        Some text
+        ~~~~~~~~~
+        CodeBlock()
+        ~~~~~~~~~
+        Other text"""
+    let expected = dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Some'
+            rnLeaf  ' '
+            rnLeaf  'text'
+          rnParagraph
+            rnCodeBlock
+              [nil]
+              rnFieldList
+                rnField
+                  rnFieldName
+                    rnLeaf  'default-language'
+                  rnFieldBody
+                    rnLeaf  'Nim'
+              rnLiteralBlock
+                rnLeaf  'CodeBlock()'
+            rnLeaf  ' '
+            rnLeaf  'Other'
+            rnLeaf  ' '
+            rnLeaf  'text'
+      """
+    check inputBacktick.toAst == expected
+    check inputTilde.toAst == expected
+
+  test "option list has priority over definition list":
+    for opt in [preferMarkdown, preferRst]:
+      check(dedent"""
+          --defusages
+                        file
+          -o            set
+          """.toAst(rstOptions = opt) ==
+        dedent"""
+          rnOptionList
+            rnOptionListItem  order=1
+              rnOptionGroup
+                rnLeaf  '--'
+                rnLeaf  'defusages'
+              rnDescription
+                rnInner
+                  rnLeaf  'file'
+            rnOptionListItem  order=2
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'o'
+              rnDescription
+                rnLeaf  'set'
+          """)
+
+  test "items of 1 option list can be separated by blank lines":
+    check(dedent"""
+        -a  desc1
+
+        -b  desc2
+        """.toAst ==
+      dedent"""
+        rnOptionList
+          rnOptionListItem  order=1
+            rnOptionGroup
+              rnLeaf  '-'
+              rnLeaf  'a'
+            rnDescription
+              rnLeaf  'desc1'
+          rnOptionListItem  order=2
+            rnOptionGroup
+              rnLeaf  '-'
+              rnLeaf  'b'
+            rnDescription
+              rnLeaf  'desc2'
+      """)
+
+  test "definition list does not gobble up the following blocks":
+    check(dedent"""
+        defName
+            defBody
+
+        -b  desc2
+        """.toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnDefList
+            rnDefItem
+              rnDefName
+                rnLeaf  'defName'
+              rnDefBody
+                rnInner
+                  rnLeaf  'defBody'
+          rnOptionList
+            rnOptionListItem  order=1
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'b'
+              rnDescription
+                rnLeaf  'desc2'
+      """)
+
+  test "definition lists work correctly with additional indentation in Markdown":
+    check(dedent"""
+        Paragraph:
+          -c  desc1
+          -b  desc2
+        """.toAst() ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'Paragraph'
+            rnLeaf  ':'
+          rnOptionList
+            rnOptionListItem  order=1
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'c'
+              rnDescription
+                rnLeaf  'desc1'
+            rnOptionListItem  order=2
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'b'
+              rnDescription
+                rnLeaf  'desc2'
+      """)
+
+  test "RST comment":
+    check(dedent"""
+        .. comment1
+         comment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnLeaf  'someParagraph'
+        """)
+
+    check(dedent"""
+        ..
+         comment1
+         comment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnLeaf  'someParagraph'
+        """)
+
+  test "check that additional line right after .. ends comment":
+    check(dedent"""
+        ..
+
+         notAcomment1
+         notAcomment2
+        someParagraph""".toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnBlockQuote
+            rnInner
+              rnLeaf  'notAcomment1'
+              rnLeaf  ' '
+              rnLeaf  'notAcomment2'
+          rnParagraph
+            rnLeaf  'someParagraph'
+        """)
+
+  test "check that additional line right after .. ends comment (Markdown mode)":
+    # in Markdown small indentation does not matter so this should
+    # just be split to 2 paragraphs.
+    check(dedent"""
+        ..
+
+         notAcomment1
+         notAcomment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'notAcomment1'
+            rnLeaf  ' '
+            rnLeaf  'notAcomment2'
+          rnParagraph
+            rnLeaf  'someParagraph'
+        """)
+
+  test "but blank lines after 2nd non-empty line don't end the comment":
+    check(dedent"""
+        ..
+           comment1
+
+
+         comment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnLeaf  'someParagraph'
+        """)
+
+  test "using .. as separator b/w directives and block quotes":
+    check(dedent"""
+        .. note:: someNote
+
+        ..
+
+          someBlockQuote""".toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnAdmonition  adType=note
+            [nil]
+            [nil]
+            rnLeaf  'someNote'
+          rnBlockQuote
+            rnInner
+              rnLeaf  'someBlockQuote'
+        """)
+
+  test "no redundant blank lines in literal blocks":
+    check(dedent"""
+      Check::
+
+
+        code
+
+      """.toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnLeaf  'Check'
+          rnLeaf  ':'
+          rnLiteralBlock
+            rnLeaf  'code'
+      """)
+
+  test "Markdown indented code blocks":
+    check(dedent"""
+      See
+
+          some code""".toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'See'
+          rnLiteralBlock
+            rnLeaf  'some code'
+      """)
+
+    # not a code block -- no blank line before:
+    check(dedent"""
+      See
+          some code""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'See'
+          rnLeaf  ' '
+          rnLeaf  'some'
+          rnLeaf  ' '
+          rnLeaf  'code'
+      """)
+
+suite "RST tables":
+
+  test "formatting in tables works":
+    check(
+      dedent"""
+        =========  ===
+        `build`    `a`
+        =========  ===
+        """.toAst ==
+      dedent"""
+        rnTable  colCount=2
+          rnTableRow
+            rnTableDataCell
+              rnInlineCode
+                rnDirArg
+                  rnLeaf  'nim'
+                [nil]
+                rnLiteralBlock
+                  rnLeaf  'build'
+            rnTableDataCell
+              rnInlineCode
+                rnDirArg
+                  rnLeaf  'nim'
+                [nil]
+                rnLiteralBlock
+                  rnLeaf  'a'
+      """)
+
+  test "tables with slightly overflowed cells cause an error (1)":
+    var error = new string
+    check(
+      dedent"""
+        ======   ======
+         Inputs  Output
+        ======   ======
+        """.toAst(rstOptions = pureRst, error = error) == "")
+    check(error[] == "input(2, 2) Error: Illformed table: " &
+                     "this word crosses table column from the right")
+
+    # In nimforum compatibility mode & Markdown we raise a warning instead:
+    let expected = dedent"""
+      rnTable  colCount=2
+        rnTableRow
+          rnTableDataCell
+            rnLeaf  'Inputs'
+          rnTableDataCell
+            rnLeaf  'Output'
+      """
+    for opt in [preferRst, preferMarkdown]:
+      var warnings = new seq[string]
+
+      check(
+        dedent"""
+          ======   ======
+           Inputs  Output
+          ======   ======
+          """.toAst(rstOptions = opt, warnings = warnings) == expected)
+      check(warnings[] == @[
+        "input(2, 2) Warning: RST style: this word crosses table column from the right"])
+
+  test "tables with slightly overflowed cells cause an error (2)":
+    var error = new string
+    check("" == dedent"""
+      =====  =====  ======
+      Input  Output
+      =====  =====  ======
+      False  False  False
+      =====  =====  ======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(2, 8) Error: Illformed table: " &
+                     "this word crosses table column from the right")
+
+  test "tables with slightly underflowed cells cause an error":
+    var error = new string
+    check("" == dedent"""
+      =====  =====  ======
+      Input Output
+      =====  =====  ======
+      False  False  False
+      =====  =====  ======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(2, 7) Error: Illformed table: " &
+                     "this word crosses table column from the left")
+
+  test "tables with unequal underlines should be reported (1)":
+    var error = new string
+    error[] = "none"
+    check("" == dedent"""
+      =====  ======
+      Input  Output
+      =====  ======
+      False  False
+      =====  =======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(5, 14) Error: Illformed table: " &
+                     "end of table column #2 should end at position 13")
+
+  test "tables with unequal underlines should be reported (2)":
+    var error = new string
+    check("" == dedent"""
+      =====  ======
+      Input  Output
+      =====  =======
+      False  False
+      =====  ======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(3, 14) Error: Illformed table: " &
+                     "end of table column #2 should end at position 13")
+
+  test "tables with empty first cells":
+    check(
+      dedent"""
+          = = =
+          x y z
+              t
+          = = =
+          """.toAst ==
+      dedent"""
+        rnTable  colCount=3
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'x'
+            rnTableDataCell
+              rnInner
+                rnLeaf  'y'
+                rnLeaf  ' '
+            rnTableDataCell
+              rnInner
+                rnLeaf  'z'
+                rnLeaf  ' '
+                rnLeaf  't'
+        """)
+
+  test "tables with spanning cells & separators":
+    check(
+      dedent"""
+        =====  =====  ======
+           Inputs     Output
+        ------------  ------
+          A      B    A or B
+        =====  =====  ======
+        False  False  False
+        True   False  True
+        -----  -----  ------
+        False  True   True
+        True   True   True
+        =====  =====  ======
+        """.toAst ==
+      dedent"""
+        rnTable  colCount=3
+          rnTableRow
+            rnTableHeaderCell  span=2
+              rnLeaf  'Inputs'
+            rnTableHeaderCell  span=1
+              rnLeaf  'Output'
+          rnTableRow  endsHeader
+            rnTableHeaderCell
+              rnLeaf  'A'
+            rnTableHeaderCell
+              rnLeaf  'B'
+            rnTableHeaderCell
+              rnInner
+                rnLeaf  'A'
+                rnLeaf  ' '
+                rnLeaf  'or'
+                rnLeaf  ' '
+                rnLeaf  'B'
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'False'
+            rnTableDataCell
+              rnLeaf  'False'
+            rnTableDataCell
+              rnLeaf  'False'
+          rnTableRow
+            rnTableDataCell  span=1
+              rnLeaf  'True'
+            rnTableDataCell  span=1
+              rnLeaf  'False'
+            rnTableDataCell  span=1
+              rnLeaf  'True'
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'False'
+            rnTableDataCell
+              rnLeaf  'True'
+            rnTableDataCell
+              rnLeaf  'True'
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'True'
+            rnTableDataCell
+              rnLeaf  'True'
+            rnTableDataCell
+              rnLeaf  'True'
+      """)
+
+  test "tables with spanning cells with uneqal underlines cause an error":
+    var error = new string
+    check(
+      dedent"""
+        =====  =====  ======
+           Inputs     Output
+        ------------- ------
+          A      B    A or B
+        =====  =====  ======
+        """.toAst(error=error) == "")
+    check(error[] == "input(3, 1) Error: Illformed table: " &
+                     "spanning underline does not match main table columns")
+
+  let expTable = dedent"""
+      rnTable  colCount=2
+        rnTableRow
+          rnTableDataCell
+            rnLeaf  'Inputs'
+          rnTableDataCell
+            rnLeaf  'Output'
+      """
+
+  test "only tables with `=` columns specs are allowed (1)":
+    var warnings = new seq[string]
+    check(
+      dedent"""
+        ------  ------
+        Inputs  Output
+        ------  ------
+        """.toAst(warnings=warnings) ==
+      expTable)
+    check(warnings[] ==
+          @["input(1, 1) Warning: RST style: " &
+              "only tables with `=` columns specification are allowed",
+            "input(3, 1) Warning: RST style: " &
+              "only tables with `=` columns specification are allowed"])
+
+  test "only tables with `=` columns specs are allowed (2)":
+    var warnings = new seq[string]
+    check(
+      dedent"""
+        ======  ======
+        Inputs  Output
+        ~~~~~~  ~~~~~~
+        """.toAst(warnings=warnings) ==
+      expTable)
+    check(warnings[] ==
+          @["input(3, 1) Warning: RST style: "&
+              "only tables with `=` columns specification are allowed"])
+
+
+suite "RST indentation":
+  test "nested bullet lists":
+    let input = dedent """
+      * - bullet1
+        - bullet2
+      * - bullet3
+        - bullet4
+      """
+    let output = input.toAst
+    check(output == dedent"""
+      rnBulletList
+        rnBulletItem
+          rnBulletList
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet1'
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet2'
+        rnBulletItem
+          rnBulletList
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet3'
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet4'
+      """)
+
+  test "nested markup blocks":
+    let input = dedent"""
+      #) .. Hint:: .. Error:: none
+      #) .. Warning:: term0
+                        Definition0
+      #) some
+         paragraph1
+      #) term1
+           Definition1
+         term2
+           Definition2
+    """
+    check(input.toAst(rstOptions = preferRst) == dedent"""
+      rnEnumList  labelFmt=1)
+        rnEnumItem
+          rnAdmonition  adType=hint
+            [nil]
+            [nil]
+            rnAdmonition  adType=error
+              [nil]
+              [nil]
+              rnLeaf  'none'
+        rnEnumItem
+          rnAdmonition  adType=warning
+            [nil]
+            [nil]
+            rnDefList
+              rnDefItem
+                rnDefName
+                  rnLeaf  'term0'
+                rnDefBody
+                  rnInner
+                    rnLeaf  'Definition0'
+        rnEnumItem
+          rnInner
+            rnLeaf  'some'
+            rnLeaf  ' '
+            rnLeaf  'paragraph1'
+        rnEnumItem
+          rnDefList
+            rnDefItem
+              rnDefName
+                rnLeaf  'term1'
+              rnDefBody
+                rnInner
+                  rnLeaf  'Definition1'
+            rnDefItem
+              rnDefName
+                rnLeaf  'term2'
+              rnDefBody
+                rnInner
+                  rnLeaf  'Definition2'
+      """)
+
+  test "code-block parsing":
+    let input1 = dedent"""
+      .. code-block:: nim
+          :test: "nim c $1"
+
+        template additive(typ: typedesc) =
+          discard
+      """
+    let input2 = dedent"""
+      .. code-block:: nim
+        :test: "nim c $1"
+
+        template additive(typ: typedesc) =
+          discard
+      """
+    let input3 = dedent"""
+      .. code-block:: nim
+         :test: "nim c $1"
+         template additive(typ: typedesc) =
+           discard
+      """
+    let inputWrong = dedent"""
+      .. code-block:: nim
+       :test: "nim c $1"
+
+         template additive(typ: typedesc) =
+           discard
+      """
+    let ast = dedent"""
+      rnCodeBlock
+        rnDirArg
+          rnLeaf  'nim'
+        rnFieldList
+          rnField
+            rnFieldName
+              rnLeaf  'test'
+            rnFieldBody
+              rnInner
+                rnLeaf  '"'
+                rnLeaf  'nim'
+                rnLeaf  ' '
+                rnLeaf  'c'
+                rnLeaf  ' '
+                rnLeaf  '$'
+                rnLeaf  '1'
+                rnLeaf  '"'
+          rnField
+            rnFieldName
+              rnLeaf  'default-language'
+            rnFieldBody
+              rnLeaf  'Nim'
+        rnLiteralBlock
+          rnLeaf  'template additive(typ: typedesc) =
+        discard'
+      """
+    check input1.toAst == ast
+    check input2.toAst == ast
+    check input3.toAst == ast
+    # "template..." should be parsed as a definition list attached to ":test:":
+    check inputWrong.toAst != ast
+
+  test "Markdown definition lists work in conjunction with bullet lists":
+    check(dedent"""
+        * some term
+          : the definition
+
+        Paragraph.""".toAst ==
+      dedent"""
+        rnInner
+          rnBulletList
+            rnBulletItem
+              rnMdDefList
+                rnDefItem
+                  rnDefName
+                    rnLeaf  'some'
+                    rnLeaf  ' '
+                    rnLeaf  'term'
+                  rnDefBody
+                    rnInner
+                      rnLeaf  'the'
+                      rnLeaf  ' '
+                      rnLeaf  'definition'
+          rnParagraph
+            rnLeaf  'Paragraph'
+            rnLeaf  '.'
+      """)
+
+  test "Markdown definition lists work with blank lines and extra paragraphs":
+    check(dedent"""
+        Term1
+
+        :   Definition1
+
+        Term2 *inline markup*
+
+        :   Definition2
+
+            Paragraph2
+
+        Term3
+        : * point1
+          * point2
+        : term3definition2
+      """.toAst == dedent"""
+        rnMdDefList
+          rnDefItem
+            rnDefName
+              rnLeaf  'Term1'
+            rnDefBody
+              rnInner
+                rnLeaf  'Definition1'
+          rnDefItem
+            rnDefName
+              rnLeaf  'Term2'
+              rnLeaf  ' '
+              rnEmphasis
+                rnLeaf  'inline'
+                rnLeaf  ' '
+                rnLeaf  'markup'
+            rnDefBody
+              rnParagraph
+                rnLeaf  'Definition2'
+              rnParagraph
+                rnLeaf  'Paragraph2'
+          rnDefItem
+            rnDefName
+              rnLeaf  'Term3'
+            rnDefBody
+              rnBulletList
+                rnBulletItem
+                  rnInner
+                    rnLeaf  'point1'
+                rnBulletItem
+                  rnInner
+                    rnLeaf  'point2'
+            rnDefBody
+              rnInner
+                rnLeaf  'term3definition2'
+      """)
+
+suite "Markdown indentation":
+  test "Markdown paragraph indentation":
+    # Additional spaces (<=3) of indentation does not break the paragraph.
+    # TODO: in 2nd case de-indentation causes paragraph to break, this is
+    # reasonable but does not seem to conform the Markdown spec.
+    check(dedent"""
+      Start1
+        stop1
+
+        Start2
+      stop2
+      """.toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Start1'
+            rnLeaf  ' '
+            rnLeaf  'stop1'
+          rnParagraph
+            rnLeaf  'Start2'
+          rnParagraph
+            rnLeaf  'stop2'
+            rnLeaf  ' '
+      """)
+
+suite "Warnings":
+  test "warnings for broken footnotes/links/substitutions":
+    let input = dedent"""
+      firstParagraph
+
+      footnoteRef [som]_
+
+      link `a broken Link`_
+
+      substitution |undefined subst|
+
+      link short.link_
+
+      lastParagraph
+      """
+    var warnings = new seq[string]
+    let output = input.toAst(rstOptions=preferRst, warnings=warnings)
+    check(warnings[] == @[
+        "input(3, 14) Warning: broken link 'citation-som'",
+        "input(5, 7) Warning: broken link 'a broken Link'",
+        "input(7, 15) Warning: unknown substitution 'undefined subst'",
+        "input(9, 6) Warning: broken link 'short.link'"
+        ])
+
+  test "Pandoc Markdown concise link warning points to target":
+    var warnings = new seq[string]
+    check(
+      "ref [here][target]".toAst(warnings=warnings) ==
+      dedent"""
+        rnInner
+          rnLeaf  'ref'
+          rnLeaf  ' '
+          rnPandocRef
+            rnInner
+              rnLeaf  'here'
+            rnInner
+              rnLeaf  'target'
+      """)
+    check warnings[] == @["input(1, 12) Warning: broken link 'target'"]
+
+  test "With include directive and blank lines at the beginning":
+    "other.rst".writeFile(dedent"""
+
+
+        firstParagraph
+
+        here brokenLink_""")
+    let input = ".. include:: other.rst"
+    var warnings = new seq[string]
+    let output = input.toAst(warnings=warnings)
+    check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"]
+    check(output == dedent"""
+      rnInner
+        rnParagraph
+          rnLeaf  'firstParagraph'
+        rnParagraph
+          rnLeaf  'here'
+          rnLeaf  ' '
+          rnRstRef
+            rnLeaf  'brokenLink'
+      """)
+    removeFile("other.rst")
+
+  test "warnings for ambiguous links (references + anchors)":
+    # Reference like `x`_ generates a link alias x that may clash with others
+    let input = dedent"""
+      Manual reference: `foo <#foo,string,string>`_
+
+      .. _foo:
+
+      Paragraph.
+
+      Ref foo_
+      """
+    var warnings = new seq[string]
+    let output = input.toAst(warnings=warnings)
+    check(warnings[] == @[
+      dedent """
+      input(7, 5) Warning: ambiguous doc link `foo`
+        clash:
+          (3, 8): (manual directive anchor)
+          (1, 45): (implicitly-generated hyperlink alias)"""
+    ])
+    # reference should be resolved to the manually set anchor:
+    check(output ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Manual'
+            rnLeaf  ' '
+            rnLeaf  'reference'
+            rnLeaf  ':'
+            rnLeaf  ' '
+            rnHyperlink
+              rnInner
+                rnLeaf  'foo'
+              rnInner
+                rnLeaf  '#foo,string,string'
+          rnParagraph  anchor='foo'
+            rnLeaf  'Paragraph'
+            rnLeaf  '.'
+          rnParagraph
+            rnLeaf  'Ref'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'foo'
+              rnLeaf  'foo'
+            rnLeaf  ' '
+      """)
+
+suite "RST include directive":
+  test "Include whole":
+    "other.rst".writeFile("**test1**")
+    let input = ".. include:: other.rst"
+    doAssert "<strong>test1</strong>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+  test "Include starting from":
+    "other.rst".writeFile("""
+And this should **NOT** be visible in `docs.html`
+OtherStart
+*Visible*
+""")
+
+    let input = """
+.. include:: other.rst
+             :start-after: OtherStart
+"""
+    check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+  test "Include everything before":
+    "other.rst".writeFile("""
+*Visible*
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+""")
+
+    let input = """
+.. include:: other.rst
+             :end-before: OtherEnd
+"""
+    doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+
+  test "Include everything between":
+    "other.rst".writeFile("""
+And this should **NOT** be visible in `docs.html`
+OtherStart
+*Visible*
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+""")
+
+    let input = """
+.. include:: other.rst
+             :start-after: OtherStart
+             :end-before: OtherEnd
+"""
+    check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+
+  test "Ignore premature ending string":
+    "other.rst".writeFile("""
+
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+OtherStart
+*Visible*
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+""")
+
+    let input = """
+.. include:: other.rst
+             :start-after: OtherStart
+             :end-before: OtherEnd
+"""
+    doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+suite "RST escaping":
+  test "backspaces":
+    check("""\ this""".toAst == dedent"""
+      rnLeaf  'this'
+      """)
+
+    check("""\\ this""".toAst == dedent"""
+      rnInner
+        rnLeaf  '\'
+        rnLeaf  ' '
+        rnLeaf  'this'
+      """)
+
+    check("""\\\ this""".toAst == dedent"""
+      rnInner
+        rnLeaf  '\'
+        rnLeaf  'this'
+      """)
+
+    check("""\\\\ this""".toAst == dedent"""
+      rnInner
+        rnLeaf  '\'
+        rnLeaf  '\'
+        rnLeaf  ' '
+        rnLeaf  'this'
+      """)
+
+suite "RST inline markup":
+  test "* and ** surrounded by spaces are not inline markup":
+    check("a * b * c ** d ** e".toAst == dedent"""
+      rnInner
+        rnLeaf  'a'
+        rnLeaf  ' '
+        rnLeaf  '*'
+        rnLeaf  ' '
+        rnLeaf  'b'
+        rnLeaf  ' '
+        rnLeaf  '*'
+        rnLeaf  ' '
+        rnLeaf  'c'
+        rnLeaf  ' '
+        rnLeaf  '**'
+        rnLeaf  ' '
+        rnLeaf  'd'
+        rnLeaf  ' '
+        rnLeaf  '**'
+        rnLeaf  ' '
+        rnLeaf  'e'
+      """)
+
+  test "end-string has repeating symbols":
+    check("*emphasis content****".toAst == dedent"""
+      rnEmphasis
+        rnLeaf  'emphasis'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '***'
+      """)
+
+    check("""*emphasis content\****""".toAst == dedent"""
+      rnEmphasis
+        rnLeaf  'emphasis'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '*'
+        rnLeaf  '**'
+      """)  # exact configuration of leafs with * is not really essential,
+            # only total number of * is essential
+
+    check("**strong content****".toAst == dedent"""
+      rnStrongEmphasis
+        rnLeaf  'strong'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '**'
+      """)
+
+    check("""**strong content*\****""".toAst == dedent"""
+      rnStrongEmphasis
+        rnLeaf  'strong'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '*'
+        rnLeaf  '*'
+        rnLeaf  '*'
+      """)
+
+    check("``lit content`````".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  'lit'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '```'
+      """)
+
+  test "interpreted text parsing: code fragments":
+    check(dedent"""
+        .. default-role:: option
+
+        `--gc:refc`""".toAst ==
+      dedent"""
+        rnInner
+          rnDefaultRole
+            rnDirArg
+              rnLeaf  'option'
+            [nil]
+            [nil]
+          rnParagraph
+            rnCodeFragment
+              rnInner
+                rnLeaf  '--'
+                rnLeaf  'gc'
+                rnLeaf  ':'
+                rnLeaf  'refc'
+              rnLeaf  'option'
+        """)
+
+  test """interpreted text can be ended with \` """:
+    let output = (".. default-role:: literal\n" & """`\``""").toAst
+    check(output.endsWith """
+  rnParagraph
+    rnInlineLiteral
+      rnLeaf  '`'""" & "\n")
+
+    let output2 = """`\``""".toAst
+    check(output2 == dedent"""
+      rnInlineCode
+        rnDirArg
+          rnLeaf  'nim'
+        [nil]
+        rnLiteralBlock
+          rnLeaf  '`'
+      """)
+
+    let output3 = """`proc \`+\``""".toAst
+    check(output3 == dedent"""
+      rnInlineCode
+        rnDirArg
+          rnLeaf  'nim'
+        [nil]
+        rnLiteralBlock
+          rnLeaf  'proc `+`'
+      """)
+
+    check("""`\\`""".toAst ==
+      dedent"""
+        rnInlineCode
+          rnDirArg
+            rnLeaf  'nim'
+          [nil]
+          rnLiteralBlock
+            rnLeaf  '\\'
+        """)
+
+  test "Markdown-style code/backtick":
+    # no whitespace is required before `
+    check("`try`...`except`".toAst ==
+      dedent"""
+        rnInner
+          rnInlineCode
+            rnDirArg
+              rnLeaf  'nim'
+            [nil]
+            rnLiteralBlock
+              rnLeaf  'try'
+          rnLeaf  '...'
+          rnInlineCode
+            rnDirArg
+              rnLeaf  'nim'
+            [nil]
+            rnLiteralBlock
+              rnLeaf  'except'
+        """)
+
+
+  test """inline literals can contain \ anywhere""":
+    check("""``\``""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+      """)
+
+    check("""``\\``""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '\'
+      """)
+
+    check("""``\```""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '`'
+      """)
+
+    check("""``\\```""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '\'
+        rnLeaf  '`'
+      """)
+
+    check("""``\````""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '`'
+        rnLeaf  '`'
+      """)
+
+  test "references with _ at the end":
+    check(dedent"""
+      .. _lnk: https
+
+      lnk_""".toAst ==
+      dedent"""
+        rnHyperlink
+          rnInner
+            rnLeaf  'lnk'
+          rnInner
+            rnLeaf  'https'
+      """)
+
+  test "not a hyper link":
+    check(dedent"""
+      .. _lnk: https
+
+      lnk___""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'lnk'
+          rnLeaf  '___'
+      """)
+
+  test "no punctuation in the end of a standalone URI is allowed":
+    check(dedent"""
+        [see (http://no.org)], end""".toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnLeaf  '['
+          rnLeaf  'see'
+          rnLeaf  ' '
+          rnLeaf  '('
+          rnStandaloneHyperlink
+            rnLeaf  'http://no.org'
+          rnLeaf  ')'
+          rnLeaf  ']'
+          rnLeaf  ','
+          rnLeaf  ' '
+          rnLeaf  'end'
+        """)
+
+    # but `/` at the end is OK
+    check(
+      dedent"""
+        See http://no.org/ end""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'See'
+          rnLeaf  ' '
+          rnStandaloneHyperlink
+            rnLeaf  'http://no.org/'
+          rnLeaf  ' '
+          rnLeaf  'end'
+        """)
+
+    # a more complex URL with some made-up ending '&='.
+    # Github Markdown would include final &= and
+    # so would rst2html.py in contradiction with RST spec.
+    check(
+      dedent"""
+        See https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO&= end""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'See'
+          rnLeaf  ' '
+          rnStandaloneHyperlink
+            rnLeaf  'https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO'
+          rnLeaf  '&'
+          rnLeaf  '='
+          rnLeaf  ' '
+          rnLeaf  'end'
+        """)
+
+  test "Markdown-style link can be split to a few lines":
+    check(dedent"""
+        is [term-rewriting
+        macros](manual.html#term-rewriting-macros)""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'is'
+          rnLeaf  ' '
+          rnHyperlink
+            rnLeaf  'term-rewriting macros'
+            rnLeaf  'manual.html#term-rewriting-macros'
+      """)
+
+  test "URL with balanced parentheses (Markdown rule)":
+    # 2 balanced parens, 1 unbalanced:
+    check(dedent"""
+        https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst ==
+      dedent"""
+        rnInner
+          rnStandaloneHyperlink
+            rnLeaf  'https://en.wikipedia.org/wiki/APL_((programming_language))'
+          rnLeaf  ')'
+      """)
+
+    # the same for Markdown-style link:
+    check(dedent"""
+        [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst ==
+      dedent"""
+        rnInner
+          rnHyperlink
+            rnLeaf  'foo [bar]'
+            rnLeaf  'https://en.wikipedia.org/wiki/APL_((programming_language))'
+          rnLeaf  ')'
+      """)
+
+    # unbalanced (here behavior is more RST-like actually):
+    check(dedent"""
+        https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst ==
+      dedent"""
+        rnInner
+          rnStandaloneHyperlink
+            rnLeaf  'https://en.wikipedia.org/wiki/APL_(programming_language'
+          rnLeaf  '('
+      """)
+
+    # unbalanced [, but still acceptable:
+    check(dedent"""
+        [my {link example](http://example.com/bracket_(symbol_[))""".toAst ==
+      dedent"""
+        rnHyperlink
+          rnLeaf  'my {link example'
+          rnLeaf  'http://example.com/bracket_(symbol_[)'
+      """)
+
+  test "not a Markdown link":
+    # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe
+    var warnings = new seq[string]
+    check("[T](f: var Foo)".toAst(warnings = warnings) ==
+      dedent"""
+        rnInner
+          rnLeaf  '['
+          rnLeaf  'T'
+          rnLeaf  ']'
+          rnLeaf  '('
+          rnLeaf  'f'
+          rnLeaf  ':'
+          rnLeaf  ' '
+          rnLeaf  'var'
+          rnLeaf  ' '
+          rnLeaf  'Foo'
+          rnLeaf  ')'
+      """)
+    check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])
+
+suite "Misc isssues":
+  test "Markdown CodeblockFields in one line (lacking enclosing ```)":
+    let message = """
+    ```llvm-profdata merge first.profraw second.profraw third.profraw <more stuff maybe> -output data.profdata```"""
+
+    try:
+      echo rstgen.rstToHtml(message, {roSupportMarkdown}, nil)
+    except EParseError:
+      discard
diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim
index c702ccc2a..6253e7146 100644
--- a/tests/stdlib/trstgen.nim
+++ b/tests/stdlib/trstgen.nim
@@ -1,7 +1,59 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+outputsub: ""
+"""
+
 # tests for rstgen module.
 
 import ../../lib/packages/docutils/rstgen
-import unittest
+import ../../lib/packages/docutils/rst
+import unittest, strutils, strtabs
+import std/private/miscdollars
+import std/assertions
+
+const
+  NoSandboxOpts = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
+  preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile}
+  preferRst = {roSupportMarkdown, roNimFile}
+
+proc toHtml(input: string,
+            rstOptions: RstParseOptions = preferMarkdown,
+            error: ref string = nil,
+            warnings: ref seq[string] = nil): string =
+  ## If `error` is nil then no errors should be generated.
+  ## The same goes for `warnings`.
+  proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
+                      arg: string) =
+    let mc = msgkind.whichMsgClass
+    let a = $msgkind % arg
+    var message: string
+    toLocation(message, filename, line, col + ColRstOffset)
+    message.add " $1: $2" % [$mc, a]
+    if mc == mcError:
+      if error == nil:
+        raise newException(EParseError, "[unexpected error] " & message)
+      error[] = message
+      # we check only first error because subsequent ones may be meaningless
+      raise newException(EParseError, "")
+    else:
+      doAssert warnings != nil, "unexpected RST warning '" & message & "'"
+      warnings[].add message
+  try:
+    result = rstToHtml(input, rstOptions, defaultConfig(),
+                       msgHandler=testMsgHandler)
+  except EParseError as e:
+    if e.msg != "":
+      result = e.msg
+
+# inline code tags (for parsing originated from highlite.nim)
+proc id(str: string): string = """<span class="Identifier">"""  & str & "</span>"
+proc op(str: string): string = """<span class="Operator">"""    & str & "</span>"
+proc pu(str: string): string = """<span class="Punctuation">""" & str & "</span>"
+proc optionListLabel(opt: string): string =
+  """<div class="option-list-label"><tt><span class="option">""" &
+  opt &
+  "</span></tt></div>"
+
 
 suite "YAML syntax highlighting":
   test "Basics":
@@ -16,8 +68,8 @@ suite "YAML syntax highlighting":
     ? key
     : value
     ..."""
-    let output = rstTohtml(input, {}, defaultConfig())
-    assert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
 <span class="Keyword">---</span>
 <span class="StringLit">a string</span><span class="Punctuation">:</span> <span class="StringLit">string</span>
 <span class="StringLit">a list</span><span class="Punctuation">:</span>
@@ -27,7 +79,7 @@ suite "YAML syntax highlighting":
 <span class="Punctuation">?</span> <span class="StringLit">key</span>
 <span class="Punctuation">:</span> <span class="StringLit">value</span>
 <span class="Keyword">...</span></pre>"""
-  
+
   test "Block scalars":
     let input = """.. code-block:: yaml
     a literal block scalar: |
@@ -42,8 +94,8 @@ suite "YAML syntax highlighting":
     another literal block scalar:
       |+ # comment after header
      allowed, since more indented than parent"""
-    let output = rstToHtml(input, {}, defaultConfig())
-    assert output == """<pre class = "listing"><span class="StringLit">a literal block scalar</span><span class="Punctuation">:</span> <span class="Command">|</span><span class="Command"></span><span class="LongStringLit">
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="StringLit">a literal block scalar</span><span class="Punctuation">:</span> <span class="Command">|</span><span class="Command"></span><span class="LongStringLit">
   some text
   # not a comment
  </span><span class="Comment"># a comment, since less indented</span>
@@ -55,7 +107,7 @@ suite "YAML syntax highlighting":
 <span class="StringLit">another literal block scalar</span><span class="Punctuation">:</span>
   <span class="Command">|+</span> <span class="Comment"># comment after header</span><span class="LongStringLit">
  allowed, since more indented than parent</span></pre>"""
- 
+
   test "Directives":
     let input = """.. code-block:: yaml
     %YAML 1.2
@@ -68,8 +120,8 @@ suite "YAML syntax highlighting":
     % not a directive
     ...
     %TAG ! !foo:"""
-    let output = rstToHtml(input, {}, defaultConfig())
-    assert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
 <span class="Keyword">---</span>
 <span class="StringLit">%not a directive</span>
 <span class="Keyword">...</span>
@@ -89,15 +141,34 @@ suite "YAML syntax highlighting":
       more numbers: [-783, 11e78],
       not numbers: [ 42e, 0023, +32.37, 8 ball]
     }"""
-    let output = rstToHtml(input, {}, defaultConfig())
-    assert output == """<pre class = "listing"><span class="Punctuation">{</span>
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Punctuation">{</span>
   <span class="StringLit">&quot;</span><span class="StringLit">quoted string&quot;</span><span class="Punctuation">:</span> <span class="DecNumber">42</span><span class="Punctuation">,</span>
   <span class="StringLit">'single quoted string'</span><span class="Punctuation">:</span> <span class="StringLit">false</span><span class="Punctuation">,</span>
   <span class="Punctuation">[</span> <span class="StringLit">list</span><span class="Punctuation">,</span> <span class="StringLit">&quot;</span><span class="StringLit">with&quot;</span><span class="Punctuation">,</span> <span class="StringLit">'entries'</span> <span class="Punctuation">]</span><span class="Punctuation">:</span> <span class="FloatNumber">73.32e-73</span><span class="Punctuation">,</span>
   <span class="StringLit">more numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span><span class="DecNumber">-783</span><span class="Punctuation">,</span> <span class="FloatNumber">11e78</span><span class="Punctuation">]</span><span class="Punctuation">,</span>
   <span class="StringLit">not numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span> <span class="StringLit">42e</span><span class="Punctuation">,</span> <span class="StringLit">0023</span><span class="Punctuation">,</span> <span class="StringLit">+32.37</span><span class="Punctuation">,</span> <span class="StringLit">8 ball</span><span class="Punctuation">]</span>
 <span class="Punctuation">}</span></pre>"""
-  
+
+  test "Directives: warnings":
+    let input = dedent"""
+      .. non-existent-warning: Paragraph.
+
+      .. another.wrong:warning::: Paragraph.
+      """
+    var warnings = new seq[string]
+    let output = input.toHtml(warnings=warnings)
+    check output == ""
+    doAssert warnings[].len == 2
+    check "(1, 24) Warning: RST style:" in warnings[0]
+    check "double colon :: may be missing at end of 'non-existent-warning'" in warnings[0]
+    check "(3, 25) Warning: RST style:" in warnings[1]
+    check "RST style: too many colons for a directive (should be ::)" in warnings[1]
+
+  test "not a directive":
+    let input = "..warning:: I am not a warning."
+    check input.toHtml == input
+
   test "Anchors, Aliases, Tags":
     let input = """.. code-block:: yaml
     --- !!map
@@ -106,8 +177,8 @@ suite "YAML syntax highlighting":
     : !localtag foo
     alias: *anchor
     """
-    let output = rstToHtml(input, {}, defaultConfig())
-    assert output == """<pre class = "listing"><span class="Keyword">---</span> <span class="TagStart">!!map</span>
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Keyword">---</span> <span class="TagStart">!!map</span>
 <span class="TagStart">!!str</span> <span class="StringLit">string</span><span class="Punctuation">:</span> <span class="TagStart">!&lt;tag:yaml.org,2002:int&gt;</span> <span class="DecNumber">42</span>
 <span class="Punctuation">?</span> <span class="Label">&amp;anchor</span> <span class="TagStart">!!seq</span> <span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">:</span>
 <span class="Punctuation">:</span> <span class="TagStart">!localtag</span> <span class="StringLit">foo</span>
@@ -126,8 +197,8 @@ suite "YAML syntax highlighting":
     example.com/not/a#comment:
       ?not a map key
     """
-    let output = rstToHtml(input, {}, defaultConfig())
-    assert output == """<pre class = "listing"><span class="Keyword">...</span>
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Keyword">...</span>
  <span class="StringLit">%a string</span><span class="Punctuation">:</span>
   <span class="StringLit">a:string:not:a:map</span>
 <span class="Keyword">...</span>
@@ -136,4 +207,1486 @@ suite "YAML syntax highlighting":
   <span class="DecNumber">-3</span>
   <span class="DecNumber">-4</span>
 <span class="StringLit">example.com/not/a#comment</span><span class="Punctuation">:</span>
-  <span class="StringLit">?not a map key</span></pre>"""
\ No newline at end of file
+  <span class="StringLit">?not a map key</span></pre>"""
+
+
+suite "RST/Markdown general":
+  test "RST emphasis":
+    doAssert rstToHtml("*Hello* **world**!", {},
+      newStringTable(modeStyleInsensitive)) ==
+      "<em>Hello</em> <strong>world</strong>!"
+
+  test "Markdown links":
+    check("(( [Nim](https://nim-lang.org/) ))".toHtml ==
+        """(( <a class="reference external" href="https://nim-lang.org/">Nim</a> ))""")
+    check("(([Nim](https://nim-lang.org/)))".toHtml ==
+        """((<a class="reference external" href="https://nim-lang.org/">Nim</a>))""")
+    check("[[Nim](https://nim-lang.org/)]".toHtml ==
+        """[<a class="reference external" href="https://nim-lang.org/">Nim</a>]""")
+
+  test "Markdown tables":
+    let input1 = """
+| A1 header    | A2 \| not fooled
+| :---         | ----:       |
+| C1           | C2 **bold** | ignored |
+| D1 `code \|` | D2          | also ignored
+| E1 \| text   |
+|              | F2 without pipe
+not in table"""
+    let output1 = input1.toHtml
+    #[
+    TODO: `\|` inside a table cell should render as `|`
+        `|` outside a table cell should render as `\|`
+    consistently with markdown, see https://stackoverflow.com/a/66557930/1426932
+    ]#
+    check(output1 == """
+<table border="1" class="docutils"><tr><th>A1 header</th><th>A2 | not fooled</th></tr>
+<tr><td>C1</td><td>C2 <strong>bold</strong></td></tr>
+<tr><td>D1 <tt class="docutils literal"><span class="pre">""" & id"code" & " " & op"\|" & """</span></tt></td><td>D2</td></tr>
+<tr><td>E1 | text</td><td></td></tr>
+<tr><td></td><td>F2 without pipe</td></tr>
+</table><p>not in table</p>""")
+    let input2 = """
+| A1 header | A2 |
+| --- | --- |"""
+    let output2 = input2.toHtml
+    doAssert output2 == """<table border="1" class="docutils"><tr><th>A1 header</th><th>A2</th></tr>
+</table>"""
+
+  test "RST tables":
+    let input1 = """
+Test 2 column/4 rows table:
+====   ===
+H0     H1
+====   ===
+A0     A1
+====   ===
+A2     A3
+====   ===
+A4     A5
+====   === """
+    let output1 = rstToLatex(input1, {})
+    doAssert "{LL}" in output1  # 2 columns
+    doAssert count(output1, "\\\\") == 4  # 4 rows
+    for cell in ["H0", "H1", "A0", "A1", "A2", "A3", "A4", "A5"]:
+      doAssert cell in output1
+
+    let input2 = """
+Now test 3 columns / 2 rows, and also borders containing 4 =, 3 =, 1 = signs:
+
+====   ===  =
+H0     H1   H
+====   ===  =
+A0     A1   X
+       Ax   Y
+====   ===  = """
+    let output2 = rstToLatex(input2, {})
+    doAssert "{LLL}" in output2  # 3 columns
+    doAssert count(output2, "\\\\") == 2  # 2 rows
+    for cell in ["H0", "H1", "H", "A0", "A1", "X", "Ax", "Y"]:
+      doAssert cell in output2
+
+
+  test "RST adornments":
+    let input1 = """
+Check that a few punctuation symbols are not parsed as adornments:
+:word1: word2 .... word3 """
+    let output1 = input1.toHtml
+    discard output1
+
+  test "RST sections":
+    let input1 = """
+Long chapter name
+'''''''''''''''''''
+"""
+    let output1 = input1.toHtml
+    doAssert "Long chapter name" in output1 and "<h1" in output1
+
+    let input2 = """
+Short chapter name:
+
+ChA
+===
+"""
+    let output2 = input2.toHtml
+    doAssert "ChA" in output2 and "<h1" in output2
+
+    let input3 = """
+Very short chapter name:
+
+X
+~
+"""
+    let output3 = input3.toHtml
+    doAssert "X" in output3 and "<h1" in output3
+
+    let input4 = """
+Check that short underline is not enough to make section:
+
+Wrong chapter
+------------
+
+"""
+    var error4 = new string
+    let output4 = input4.toHtml(error = error4)
+    check(error4[] == "input(3, 1) Error: new section expected (underline " &
+            "\'------------\' is too short)")
+
+    let input5 = """
+Check that punctuation after adornment and indent are not detected as adornment.
+
+Some chapter
+--------------
+
+  "punctuation symbols" """
+    let output5 = input5.toHtml
+    doAssert "&quot;punctuation symbols&quot;" in output5 and "<h1" in output5
+
+    # check that EOF after adornment does not prevent it parsing as heading
+    let input6 = dedent """
+      Some chapter
+      ------------"""
+    let output6 = input6.toHtml
+    doAssert "<h1 id=\"some-chapter\">Some chapter</h1>" in output6
+
+    # check that overline and underline match
+    let input7 = dedent """
+      ------------
+      Some chapter
+      -----------
+      """
+    var error7 = new string
+    let output7 = input7.toHtml(error=error7)
+    check(error7[] == "input(1, 1) Error: new section expected (underline " &
+            "\'-----------\' does not match overline \'------------\')")
+
+    let input8 = dedent """
+      -----------
+          Overflow
+      -----------
+      """
+    var error8 = new string
+    let output8 = input8.toHtml(error=error8)
+    check(error8[] == "input(1, 1) Error: new section expected (overline " &
+            "\'-----------\' is too short)")
+
+    # check that hierarchy of title styles works
+    let input9good = dedent """
+      Level1
+      ======
+
+      Level2
+      ------
+
+      Level3
+      ~~~~~~
+
+      L1
+      ==
+
+      Another2
+      --------
+
+      More3
+      ~~~~~
+
+      """
+    let output9good = input9good.toHtml(preferRst)
+    doAssert "<h1 id=\"level1\">Level1</h1>" in output9good
+    doAssert "<h2 id=\"level2\">Level2</h2>" in output9good
+    doAssert "<h3 id=\"level3\">Level3</h3>" in output9good
+    doAssert "<h1 id=\"l1\">L1</h1>" in output9good
+    doAssert "<h2 id=\"another2\">Another2</h2>" in output9good
+    doAssert "<h3 id=\"more3\">More3</h3>" in output9good
+
+    # check that swap causes an exception
+    let input9Bad = dedent """
+      Level1
+      ======
+
+      Level2
+      ------
+
+      Level3
+      ~~~~~~
+
+      L1
+      ==
+
+      More
+      ~~~~
+
+      Another
+      -------
+
+      """
+    var error9Bad = new string
+    let output9Bad = input9Bad.toHtml(preferRst, error=error9Bad)
+    check(error9Bad[] == "input(15, 1) Error: new section expected (section " &
+            "level inconsistent: underline ~~~~~ unexpectedly found, while " &
+            "the following intermediate section level(s) are missing on " &
+            "lines 12..15: underline -----)")
+
+  test "RST sections overline":
+    # the same as input9good but with overline headings
+    # first overline heading has a special meaning: document title
+    let input = dedent """
+      ======
+      Title0
+      ======
+
+      +++++++++
+      SubTitle0
+      +++++++++
+
+      ------
+      Level1
+      ------
+
+      Level2
+      ------
+
+      ~~~~~~
+      Level3
+      ~~~~~~
+
+      --
+      L1
+      --
+
+      Another2
+      --------
+
+      ~~~~~
+      More3
+      ~~~~~
+
+      """
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames = files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == "Title0"
+    doAssert rstGenera.meta[metaSubtitle] == "SubTitle0"
+    doAssert "<h1 id=\"level1\"><center>Level1</center></h1>" in output
+    doAssert "<h2 id=\"level2\">Level2</h2>" in output
+    doAssert "<h3 id=\"level3\"><center>Level3</center></h3>" in output
+    doAssert "<h1 id=\"l1\"><center>L1</center></h1>" in output
+    doAssert "<h2 id=\"another2\">Another2</h2>" in output
+    doAssert "<h3 id=\"more3\"><center>More3</center></h3>" in output
+
+  test "RST sections overline 2":
+    # check that a paragraph prevents interpreting overlines as document titles
+    let input = dedent """
+      Paragraph
+
+      ======
+      Title0
+      ======
+
+      +++++++++
+      SubTitle0
+      +++++++++
+      """
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == ""
+    doAssert rstGenera.meta[metaSubtitle] == ""
+    doAssert "<h1 id=\"title0\"><center>Title0</center></h1>" in output
+    doAssert "<h2 id=\"subtitle0\"><center>SubTitle0</center></h2>" in output
+
+  test "RST+Markdown sections":
+    # check that RST and Markdown headings don't interfere
+    let input = dedent """
+      ======
+      Title0
+      ======
+
+      MySection1a
+      +++++++++++
+
+      # MySection1b
+
+      MySection1c
+      +++++++++++
+
+      ##### MySection5a
+
+      MySection2a
+      -----------
+      """
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {roSupportMarkdown})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == "Title0"
+    doAssert rstGenera.meta[metaSubtitle] == ""
+    doAssert output ==
+             "\n<h1 id=\"mysection1a\">MySection1a</h1>" & # RST
+             "\n<h1 id=\"mysection1b\">MySection1b</h1>" & # Markdown
+             "\n<h1 id=\"mysection1c\">MySection1c</h1>" & # RST
+             "\n<h5 id=\"mysection5a\">MySection5a</h5>" & # Markdown
+             "\n<h2 id=\"mysection2a\">MySection2a</h2>"   # RST
+
+  test "RST inline text":
+    let input1 = "GC_step"
+    let output1 = input1.toHtml
+    doAssert output1 == "GC_step"
+
+  test "RST anchors/links to headings":
+    # Currently in TOC mode anchors are modified (for making links from
+    # the TOC unique)
+    let inputNoToc = dedent"""
+        Type relations
+        ==============
+
+        Convertible relation
+        --------------------
+
+        Ref. `Convertible relation`_
+        """
+    let outputNoToc = inputNoToc.toHtml
+    check outputNoToc.count("id=\"type-relations\"") == 1
+    check outputNoToc.count("id=\"convertible-relation\"") == 1
+    check outputNoToc.count("href=\"#convertible-relation\"") == 1
+
+    let inputTocCases = @[
+      dedent"""
+        .. contents::
+
+        Type relations
+        ==============
+
+        Convertible relation
+        --------------------
+
+        Ref. `Convertible relation`_
+
+        Guards and locks
+        ================
+        """,
+      dedent"""
+        Ref. `Convertible relation`_
+
+        .. contents::
+
+        Type relations
+        ==============
+
+        Convertible relation
+        --------------------
+
+        Guards and locks
+        ================
+        """
+    ]
+    for inputToc in inputTocCases:
+      let outputToc = inputToc.toHtml
+      check outputToc.count("id=\"type-relations\"") == 1
+      check outputToc.count("id=\"type-relations-convertible-relation\"") == 1
+      check outputToc.count("id=\"convertible-relation\">") == 0
+      # Besides "Ref.", heading also contains link to itself:
+      check outputToc.count(
+          "href=\"#type-relations-convertible-relation\">") == 2
+      check outputToc.count("href=\"#convertible-relation\"") == 0
+
+  test "RST links":
+    let input1 = """
+Want to learn about `my favorite programming language`_?
+
+.. _my favorite programming language: https://nim-lang.org"""
+    let output1 = input1.toHtml
+    doAssert "<a" in output1 and "href=\"https://nim-lang.org\"" in output1
+
+  test "RST transitions":
+    let input1 = """
+context1
+
+~~~~
+
+context2
+"""
+    let output1 = input1.toHtml(preferRst)
+    doAssert "<hr" in output1
+
+    let input2 = """
+This is too short to be a transition:
+
+---
+context2
+---
+"""
+    var error2 = new string
+    let output2 = input2.toHtml(error=error2)
+    check(error2[] == "input(3, 1) Error: new section expected (overline " &
+            "\'---\' is too short)")
+
+  test "RST literal block":
+    let input1 = """
+Test literal block
+
+::
+
+  check """
+    let output1 = input1.toHtml(preferRst)
+    doAssert "<pre>" in output1
+
+  test "Markdown code block":
+    let input1 = """
+```
+let x = 1
+``` """
+    let output1 = input1.toHtml({roSupportMarkdown, roPreferMarkdown})
+    doAssert "<pre" in output1 and "class=\"Keyword\"" notin output1
+
+    # Check Nim highlighting by default in .nim files:
+    let output1nim = input1.toHtml({roSupportMarkdown, roPreferMarkdown,
+                                    roNimFile})
+    doAssert "<pre" in output1nim and "class=\"Keyword\"" in output1nim
+
+    let input2 = """
+Parse the block with language specifier:
+```Nim
+let x = 1
+``` """
+    let output2 = input2.toHtml
+    doAssert "<pre" in output2 and "class=\"Keyword\"" in output2
+
+  test "interpreted text":
+    check("""`foo.bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"foo" & op"." & id"bar" & "</span></tt>")
+    check("""`foo\`\`bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"foo" & pu"`" & pu"`" & id"bar" & "</span></tt>")
+    check("""`foo\`bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"foo" & pu"`" & id"bar" & "</span></tt>")
+    check("""`\`bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      pu"`" & id"bar" & "</span></tt>")
+    check("""`a\b\x\\ar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"a" & op"""\""" & id"b" & op"""\""" & id"x" & op"""\\""" & id"ar" &
+      "</span></tt>")
+
+  test "inline literal":
+    check """``foo.bar``""".toHtml == """<tt class="docutils literal"><span class="pre">foo.bar</span></tt>"""
+    check """``foo\bar``""".toHtml == """<tt class="docutils literal"><span class="pre">foo\bar</span></tt>"""
+    check """``f\`o\\o\b`ar``""".toHtml == """<tt class="docutils literal"><span class="pre">f\`o\\o\b`ar</span></tt>"""
+
+  test "default-role":
+    # nim(default) -> literal -> nim -> code(=literal)
+    let input = dedent"""
+      Par1 `value1`.
+
+      .. default-role:: literal
+
+      Par2 `value2`.
+
+      .. default-role:: nim
+
+      Par3 `value3`.
+
+      .. default-role:: code
+
+      Par4 `value4`."""
+    let p1 = """Par1 <tt class="docutils literal"><span class="pre">""" & id"value1" & "</span></tt>."
+    let p2 = """<p>Par2 <tt class="docutils literal"><span class="pre">value2</span></tt>.</p>"""
+    let p3 = """<p>Par3 <tt class="docutils literal"><span class="pre">""" & id"value3" & "</span></tt>.</p>"
+    let p4 = """<p>Par4 <tt class="docutils literal"><span class="pre">value4</span></tt>.</p>"""
+    let expected = p1 & p2 & "\n" & p3 & "\n" & p4
+    check(
+      input.toHtml(NoSandboxOpts) == expected
+    )
+
+  test "role directive":
+    let input = dedent"""
+      .. role:: y(code)
+         :language: yaml
+
+      .. role:: brainhelp(code)
+         :language: brainhelp
+    """
+    var warnings = new seq[string]
+    let output = input.toHtml(
+      NoSandboxOpts,
+      warnings=warnings
+    )
+    check(warnings[].len == 1 and "language 'brainhelp' not supported" in warnings[0])
+
+  test "RST comments":
+    let input1 = """
+
+Check that comment disappears:
+
+..
+  some comment """
+    let output1 = input1.toHtml
+    doAssert output1 == "Check that comment disappears:"
+
+  test "RST line blocks + headings":
+    let input = """
+=====
+Test1
+=====
+
+|
+|
+| line block
+| other line
+
+"""
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == "Test1"
+      # check that title was not overwritten to '|'
+    doAssert output == "<p><br/><br/>line block<br/>other line<br/></p>"
+    let output1l = rstToLatex(input, {})
+    doAssert "line block\n\n" in output1l
+    doAssert "other line\n\n" in output1l
+    doAssert output1l.count("\\vspace") == 2 + 2  # +2 surrounding paddings
+
+  test "RST line blocks":
+    let input2 = dedent"""
+      Paragraph1
+
+      |
+
+      Paragraph2"""
+
+    let output2 = input2.toHtml
+    doAssert "Paragraph1<p><br/></p> <p>Paragraph2</p>" == output2
+
+    let input3 = dedent"""
+      | xxx
+      |   yyy
+      |     zzz"""
+
+    let output3 = input3.toHtml
+    doAssert "xxx<br/>" in output3
+    doAssert "<span style=\"margin-left: 1.0em\">yyy</span><br/>" in output3
+    doAssert "<span style=\"margin-left: 2.0em\">zzz</span><br/>" in output3
+
+    # check that '|   ' with a few spaces is still parsed as new line
+    let input4 = dedent"""
+      | xxx
+      |
+      |     zzz"""
+
+    let output4 = input4.toHtml
+    doAssert "xxx<br/><br/>" in output4
+    doAssert "<span style=\"margin-left: 2.0em\">zzz</span><br/>" in output4
+
+  test "RST enumerated lists":
+    let input1 = dedent """
+      1. line1
+         1
+      2. line2
+         2
+
+      3. line3
+         3
+
+
+      4. line4
+         4
+
+
+
+      5. line5
+         5
+      """
+    let output1 = input1.toHtml
+    for i in 1..5:
+      doAssert ($i & ". line" & $i) notin output1
+      doAssert ("<li>line" & $i & " " & $i & "</li>") in output1
+
+    let input2 = dedent """
+      3. line3
+
+      4. line4
+
+
+      5. line5
+
+
+
+      7. line7
+
+
+
+
+      8. line8
+      """
+    let output2 = input2.toHtml
+    for i in [3, 4, 5, 7, 8]:
+      doAssert ($i & ". line" & $i) notin output2
+      doAssert ("<li>line" & $i & "</li>") in output2
+
+    # check that nested enumerated lists work
+    let input3 = dedent """
+      1.  a) string1
+      2. string2
+      """
+    let output3 = input3.toHtml
+    doAssert count(output3, "<ol ") == 2
+    doAssert count(output3, "</ol>") == 2
+    doAssert "<li>string1</li>" in output3 and "<li>string2</li>" in output3
+
+    let input4 = dedent """
+      Check that enumeration specifiers are respected
+
+      9. string1
+      10. string2
+      12. string3
+
+      b) string4
+      c) string5
+      e) string6
+      """
+    let output4 = input4.toHtml
+    doAssert count(output4, "<ol ") == 4
+    doAssert count(output4, "</ol>") == 4
+    for enumerator in [9, 12]:
+      doAssert "start=\"$1\"" % [$enumerator] in output4
+    for enumerator in [2, 5]:  # 2=b, 5=e
+      doAssert "start=\"$1\"" % [$enumerator] in output4
+
+    let input5 = dedent """
+      Check that auto-numbered enumeration lists work.
+
+      #. string1
+
+      #. string2
+
+      #. string3
+
+      #) string5
+      #) string6
+      """
+    let output5 = input5.toHtml
+    doAssert count(output5, "<ol ") == 2
+    doAssert count(output5, "</ol>") == 2
+    doAssert count(output5, "<li>") == 5
+
+    let input5a = dedent """
+      Auto-numbered RST list can start with 1 even when Markdown support is on.
+
+      1. string1
+      #. string2
+      #. string3
+      """
+    let output5a = input5a.toHtml
+    doAssert count(output5a, "<ol ") == 1
+    doAssert count(output5a, "</ol>") == 1
+    doAssert count(output5a, "<li>") == 3
+
+    let input6 = dedent """
+      ... And for alphabetic enumerators too!
+
+      b. string1
+      #. string2
+      #. string3
+      """
+    let output6 = input6.toHtml
+    doAssert count(output6, "<ol ") == 1
+    doAssert count(output6, "</ol>") == 1
+    doAssert count(output6, "<li>") == 3
+    doAssert "start=\"2\"" in output6 and "class=\"loweralpha simple\"" in output6
+
+    let input7 = dedent """
+      ... And for uppercase alphabetic enumerators.
+
+      C. string1
+      #. string2
+      #. string3
+      """
+    let output7 = input7.toHtml
+    doAssert count(output7, "<ol ") == 1
+    doAssert count(output7, "</ol>") == 1
+    doAssert count(output7, "<li>") == 3
+    doAssert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7
+
+    # check that it's not recognized as enum.list without indentation on 2nd line
+    let input8 = dedent """
+      Paragraph.
+
+      A. stringA
+      B. stringB
+      C. string1
+      string2
+      """
+    var warnings8 = new seq[string]
+    let output8 = input8.toHtml(warnings = warnings8)
+    check(warnings8[].len == 1)
+    check("input(6, 1) Warning: RST style: \n" &
+          "not enough indentation on line 6" in warnings8[0])
+    doAssert output8 == "Paragraph.<ol class=\"upperalpha simple\">" &
+        "<li>stringA</li>\n<li>stringB</li>\n</ol>\n<p>C. string1 string2 </p>"
+
+  test "Markdown enumerated lists":
+    let input1 = dedent """
+      Below are 2 enumerated lists: Markdown-style (5 items) and RST (1 item)
+      1. line1
+      1. line2
+      1. line3
+      1. line4
+
+      1. line5
+
+      #. lineA
+      """
+    let output1 = input1.toHtml
+    for i in 1..5:
+      doAssert ($i & ". line" & $i) notin output1
+      doAssert ("<li>line" & $i & "</li>") in output1
+    doAssert count(output1, "<ol ") == 2
+    doAssert count(output1, "</ol>") == 2
+
+  test "RST bullet lists":
+    let input1 = dedent """
+      * line1
+        1
+      * line2
+        2
+
+      * line3
+        3
+
+
+      * line4
+        4
+
+
+
+      * line5
+        5
+      """
+    let output1 = input1.toHtml
+    for i in 1..5:
+      doAssert ("<li>line" & $i & " " & $i & "</li>") in output1
+    doAssert count(output1, "<ul ") == 1
+    doAssert count(output1, "</ul>") == 1
+
+  test "Nim RST footnotes and citations":
+    # check that auto-label footnote enumerated properly after a manual one
+    let input1 = dedent """
+      .. [1] Body1.
+      .. [#note] Body2
+
+      Ref. [#note]_
+      """
+    let output1 = input1.toHtml(preferRst)
+    doAssert output1.count(">[1]</a>") == 1
+    doAssert output1.count(">[2]</a>") == 2
+    doAssert "href=\"#footnote-note\"" in output1
+    doAssert ">[-1]" notin output1
+    doAssert "Body1." in output1
+    doAssert "Body2" in output1
+
+    # check that there are NO footnotes/citations, only comments:
+    let input2 = dedent """
+      .. [1 #] Body1.
+      .. [# note] Body2.
+      .. [wrong citation] That gives you a comment.
+
+      .. [not&allowed] That gives you a comment.
+
+      Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_.
+      """
+    let output2 = input2.toHtml(preferRst)
+    doAssert output2 == "Not references[#note]_[1 #]_ [wrong citation]_ and [not&amp;allowed]_."
+
+    # check that auto-symbol footnotes work:
+    let input3 = dedent """
+      Ref. [*]_ and [*]_ and [*]_.
+
+      .. [*] Body1
+      .. [*] Body2.
+
+
+      .. [*] Body3.
+      .. [*] Body4
+
+      And [*]_.
+      """
+    let output3 = input3.toHtml(preferRst)
+    # both references and footnotes. Footnotes have link to themselves.
+    doAssert output3.count("href=\"#footnotesym-1\">[*]</a>") == 2
+    doAssert output3.count("href=\"#footnotesym-2\">[**]</a>") == 2
+    doAssert output3.count("href=\"#footnotesym-3\">[***]</a>") == 2
+    doAssert output3.count("href=\"#footnotesym-4\">[^]</a>") == 2
+    # footnote group
+    doAssert output3.count("<hr class=\"footnote\">" &
+                           "<div class=\"footnote-group\">") == 1
+    # footnotes
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-1\">[*]</a></strong></sup></div>") == 1
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-2\">[**]</a></strong></sup></div>") == 1
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-3\">[***]</a></strong></sup></div>") == 1
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-4\">[^]</a></strong></sup></div>") == 1
+    for i in 1 .. 4: doAssert ("Body" & $i) in output3
+
+    # check manual, auto-number and auto-label footnote enumeration
+    let input4 = dedent """
+      .. [3] Manual1.
+      .. [#] Auto-number1.
+      .. [#mylabel] Auto-label1.
+      .. [#note] Auto-label2.
+      .. [#] Auto-number2.
+
+      Ref. [#note]_ and [#]_ and [#]_.
+      """
+    let output4 = input4.toHtml(preferRst)
+    doAssert ">[-1]" notin output1
+    let order = @[
+        "footnote-3", "[3]", "Manual1.",
+        "footnoteauto-1", "[1]", "Auto-number1",
+        "footnote-mylabel", "[2]", "Auto-label1",
+        "footnote-note", "[4]", "Auto-label2",
+        "footnoteauto-2", "[5]", "Auto-number2",
+        ]
+    for i in 0 .. order.len-2:
+      let pos1 = output4.find(order[i])
+      let pos2 = output4.find(order[i+1])
+      doAssert pos1 >= 0
+      doAssert pos2 >= 0
+      doAssert pos1 < pos2
+
+    # forgot [#]_
+    let input5 = dedent """
+      .. [3] Manual1.
+      .. [#] Auto-number1.
+      .. [#note] Auto-label2.
+
+      Ref. [#note]_
+      """
+    var error5 = new string
+    let output5 = input5.toHtml(preferRst, error=error5)
+    check(error5[] == "input(1, 1) Error: mismatch in number of footnotes " &
+            "and their refs: 1 (lines 2) != 0 (lines ) for auto-numbered " &
+            "footnotes")
+
+    # extra [*]_
+    let input6 = dedent """
+      Ref. [*]_
+
+      .. [*] Auto-Symbol.
+
+      Ref. [*]_
+      """
+    var error6 = new string
+    let output6 = input6.toHtml(preferRst, error=error6)
+    check(error6[] == "input(1, 1) Error: mismatch in number of footnotes " &
+            "and their refs: 1 (lines 3) != 2 (lines 2, 6) for auto-symbol " &
+            "footnotes")
+
+    let input7 = dedent """
+      .. [Some:CITATION-2020] Citation.
+
+      Ref. [some:citation-2020]_.
+      """
+    let output7 = input7.toHtml(preferRst)
+    doAssert output7.count("href=\"#citation-somecoloncitationminus2020\"") == 2
+    doAssert output7.count("[Some:CITATION-2020]") == 1
+    doAssert output7.count("[some:citation-2020]") == 1
+    doAssert output3.count("<hr class=\"footnote\">" &
+                           "<div class=\"footnote-group\">") == 1
+
+    let input8 = dedent """
+      .. [Some] Citation.
+
+      Ref. [som]_.
+      """
+    var warnings8 = new seq[string]
+    let output8 = input8.toHtml(preferRst, warnings=warnings8)
+    check(warnings8[] == @["input(3, 7) Warning: broken link 'citation-som'"])
+
+    # check that footnote group does not break parsing of other directives:
+    let input9 = dedent """
+      .. [Some] Citation.
+
+      .. _`internal anchor`:
+
+      .. [Another] Citation.
+      .. just comment.
+      .. [Third] Citation.
+
+      Paragraph1.
+
+      Paragraph2 ref `internal anchor`_.
+      """
+    let output9 = input9.toHtml(preferRst)
+    # _`internal anchor` got erased:
+    check "href=\"#internal-anchor\"" notin output9
+    check "href=\"#citation-another\"" in output9
+    doAssert output9.count("<hr class=\"footnote\">" &
+                           "<div class=\"footnote-group\">") == 1
+    doAssert output9.count("<div class=\"footnote-label\">") == 3
+    doAssert "just comment" notin output9
+
+    # check that nested citations/footnotes work
+    let input10 = dedent """
+      Paragraph1 [#]_.
+
+      .. [First] Citation.
+
+         .. [#] Footnote.
+
+            .. [Third] Citation.
+      """
+    let output10 = input10.toHtml(preferRst)
+    doAssert output10.count("<hr class=\"footnote\">" &
+                            "<div class=\"footnote-group\">") == 3
+    doAssert output10.count("<div class=\"footnote-label\">") == 3
+    doAssert "<a href=\"#citation-first\">[First]</a>" in output10
+    doAssert "<a href=\"#footnoteauto-1\">[1]</a>" in output10
+    doAssert "<a href=\"#citation-third\">[Third]</a>" in output10
+
+    let input11 = ".. [note]\n"  # should not crash
+    let output11 = input11.toHtml(preferRst)
+    doAssert "<a href=\"#citation-note\">[note]</a>" in output11
+
+    # check that references to auto-numbered footnotes work
+    let input12 = dedent """
+      Ref. [#]_ and [#]_ STOP.
+
+      .. [#] Body1.
+      .. [#] Body3
+      .. [2] Body2.
+      """
+    let output12 = input12.toHtml(preferRst)
+    let orderAuto = @[
+        "#footnoteauto-1", "[1]",
+        "#footnoteauto-2", "[3]",
+        "STOP.",
+        "Body1.", "Body3", "Body2."
+        ]
+    for i in 0 .. orderAuto.len-2:
+      let pos1 = output12.find(orderAuto[i])
+      let pos2 = output12.find(orderAuto[i+1])
+      doAssert pos1 >= 0
+      doAssert pos2 >= 0
+      doAssert pos1 < pos2
+
+  test "Nim (RST extension) code-block":
+    # check that presence of fields doesn't consume the following text as
+    # its code (which is a literal block)
+    let input0 = dedent """
+      .. code-block:: nim
+         :number-lines: 0
+
+      Paragraph1"""
+    let output0 = input0.toHtml
+    doAssert "<p>Paragraph1</p>" in output0
+
+  test "Nim code-block :number-lines:":
+    let input = dedent """
+      .. code-block:: nim
+         :number-lines: 55
+
+         x
+         y
+      """
+    check "<pre class=\"line-nums\">55\n56\n</pre>" in input.toHtml
+
+  test "Nim code-block indentation":
+    let input = dedent """
+      .. code-block:: nim
+        :number-lines: 55
+
+       x
+      """
+    let output = input.toHtml
+    check "<pre class=\"line-nums\">55\n</pre>" in output
+    check "<span class=\"Identifier\">x</span>" in output
+
+  test "Nim code-block indentation":
+    let input = dedent """
+      .. code-block:: nim
+        :number-lines: 55
+         let a = 1
+      """
+    var error = new string
+    let output = input.toHtml(error=error)
+    check(error[] == "input(2, 3) Error: invalid field: " &
+                     "extra arguments were given to number-lines: ' let a = 1'")
+    check "" == output
+
+  test "code-block warning":
+    let input = dedent """
+      .. code:: Nim
+         :unsupportedField: anything
+
+      .. code:: unsupportedLang
+
+         anything
+
+      ```anotherLang
+      someCode
+      ```
+      """
+    let warnings = new seq[string]
+    let output = input.toHtml(warnings=warnings)
+    check(warnings[] == @[
+        "input(2, 4) Warning: field 'unsupportedField' not supported",
+        "input(4, 11) Warning: language 'unsupportedLang' not supported",
+        "input(8, 4) Warning: language 'anotherLang' not supported"
+        ])
+    check(output == "<pre class = \"listing\">anything</pre>" &
+                    "<p><pre class = \"listing\">someCode</pre> </p>")
+
+  test "RST admonitions":
+    # check that all admonitions are implemented
+    let input0 = dedent """
+      .. admonition:: endOf admonition
+      .. attention:: endOf attention
+      .. caution:: endOf caution
+      .. danger:: endOf danger
+      .. error:: endOf error
+      .. hint:: endOf hint
+      .. important:: endOf important
+      .. note:: endOf note
+      .. tip:: endOf tip
+      .. warning:: endOf warning
+    """
+    let output0 = input0.toHtml(
+      NoSandboxOpts
+    )
+    for a in ["admonition", "attention", "caution", "danger", "error", "hint",
+        "important", "note", "tip", "warning" ]:
+      doAssert "endOf " & a & "</div>" in output0
+
+    # Test that admonition does not swallow up the next paragraph.
+    let input1 = dedent """
+      .. error:: endOfError
+
+      Test paragraph.
+    """
+    let output1 = input1.toHtml(
+      NoSandboxOpts
+    )
+    doAssert "endOfError</div>" in output1
+    doAssert "<p>Test paragraph. </p>" in output1
+    doAssert "class=\"admonition admonition-error\"" in output1
+
+    # Test that second line is parsed as continuation of the first line.
+    let input2 = dedent """
+      .. error:: endOfError
+        Test2p.
+
+      Test paragraph.
+    """
+    let output2 = input2.toHtml(
+      NoSandboxOpts
+    )
+    doAssert "endOfError Test2p.</div>" in output2
+    doAssert "<p>Test paragraph. </p>" in output2
+    doAssert "class=\"admonition admonition-error\"" in output2
+
+    let input3 = dedent """
+      .. note:: endOfNote
+    """
+    let output3 = input3.toHtml(
+      NoSandboxOpts
+    )
+    doAssert "endOfNote</div>" in output3
+    doAssert "class=\"admonition admonition-info\"" in output3
+
+  test "RST internal links":
+    let input1 = dedent """
+      Start.
+
+      .. _target000:
+
+      Paragraph.
+
+      .. _target001:
+
+      * bullet list
+      * Y
+
+      .. _target002:
+
+      1. enumeration list
+      2. Y
+
+      .. _target003:
+
+      term 1
+        Definition list 1.
+
+      .. _target004:
+
+      | line block
+
+      .. _target005:
+
+      :a: field list value
+
+      .. _target006:
+
+      -a  option description
+
+      .. _target007:
+
+      ::
+
+        Literal block
+
+      .. _target008:
+
+      Doctest blocks are not implemented.
+
+      .. _target009:
+
+          block quote
+
+      .. _target010:
+
+      =====  =====  =======
+        A      B    A and B
+      =====  =====  =======
+      False  False  False
+      =====  =====  =======
+
+      .. _target100:
+
+      .. CAUTION:: admonition
+
+      .. _target101:
+
+      .. code:: nim
+
+         const pi = 3.14
+
+      .. _target102:
+
+      .. code-block::
+
+         const pi = 3.14
+
+      Paragraph2.
+
+      .. _target202:
+
+      ----
+
+      That was a transition.
+    """
+    let output1 = input1.toHtml(
+      preferRst
+    )
+    doAssert "<p id=\"target000\""     in output1
+    doAssert "<ul id=\"target001\""    in output1
+    doAssert "<ol id=\"target002\""    in output1
+    doAssert "<dl id=\"target003\""    in output1
+    doAssert "<p id=\"target004\""     in output1
+    doAssert "<table id=\"target005\"" in output1  # field list
+    doAssert "<div id=\"target006\""   in output1  # option list
+    doAssert "<pre id=\"target007\""   in output1
+    doAssert "<blockquote id=\"target009\"" in output1
+    doAssert "<table id=\"target010\"" in output1  # just table
+    doAssert "<span id=\"target100\""  in output1
+    doAssert "<pre id=\"target101\""   in output1  # code
+    doAssert "<pre id=\"target102\""   in output1  # code-block
+    doAssert "<hr id=\"target202\""    in output1
+
+  test "RST internal links for sections":
+    let input1 = dedent """
+      .. _target101:
+      .. _target102:
+
+      Section xyz
+      -----------
+
+      Ref. target101_
+    """
+    let output1 = input1.toHtml
+    # "target101" should be erased and changed to "section-xyz":
+    check "href=\"#target101\"" notin output1
+    check "id=\"target101\""    notin output1
+    check "href=\"#target102\"" notin output1
+    check "id=\"target102\""    notin output1
+    check "id=\"section-xyz\""     in output1
+    check "href=\"#section-xyz\""  in output1
+
+    let input2 = dedent """
+      .. _target300:
+
+      Section xyz
+      ===========
+
+      .. _target301:
+
+      SubsectionA
+      -----------
+
+      Ref. target300_ and target301_.
+
+      .. _target103:
+
+      .. [cit2020] note.
+
+      Ref. target103_.
+
+    """
+    let output2 = input2.toHtml(preferRst)
+    # "target101" should be erased and changed to "section-xyz":
+    doAssert "href=\"#target300\"" notin output2
+    doAssert "id=\"target300\""    notin output2
+    doAssert "href=\"#target301\"" notin output2
+    doAssert "id=\"target301\""    notin output2
+    doAssert "<h1 id=\"section-xyz\"" in output2
+    doAssert "<h2 id=\"subsectiona\"" in output2
+    # links should preserve their original names but point to section labels:
+    doAssert "href=\"#section-xyz\">target300" in output2
+    doAssert "href=\"#subsectiona\">target301" in output2
+    doAssert "href=\"#citation-cit2020\">target103" in output2
+
+    let output2l = rstToLatex(input2, {})
+    doAssert "\\label{section-xyz}\\hypertarget{section-xyz}{}" in output2l
+    doAssert "\\hyperlink{section-xyz}{target300}"  in output2l
+    doAssert "\\hyperlink{subsectiona}{target301}"  in output2l
+
+  test "RST internal links (inline)":
+    let input1 = dedent """
+      Paragraph with _`some definition`.
+
+      Ref. `some definition`_.
+    """
+    let output1 = input1.toHtml
+    doAssert "<span class=\"target\" " &
+        "id=\"some-definition\">some definition</span>" in output1
+    doAssert "Ref. <a class=\"reference internal\" " &
+        "href=\"#some-definition\">some definition</a>" in output1
+
+  test "RST references (additional symbols)":
+    # check that ., _, -, +, : are allowed symbols in references without ` `
+    let input1 = dedent """
+      sec.1
+      -----
+
+      2-other:sec+c_2
+      ^^^^^^^^^^^^^^^
+
+      .. _link.1_2021:
+
+      Paragraph
+
+      Ref. sec.1_! and 2-other:sec+c_2_;and link.1_2021_.
+    """
+    let output1 = input1.toHtml
+    doAssert "id=\"secdot1\"" in output1
+    doAssert "id=\"Z2minusothercolonsecplusc-2\"" in output1
+    check "id=\"linkdot1-2021\"" in output1
+    let ref1 = "<a class=\"reference internal\" href=\"#secdot1\">sec.1</a>"
+    let ref2 = "<a class=\"reference internal\" href=\"#Z2minusothercolonsecplusc-2\">2-other:sec+c_2</a>"
+    let ref3 = "<a class=\"reference internal\" href=\"#linkdot1-2021\">link.1_2021</a>"
+    let refline = "Ref. " & ref1 & "! and " & ref2 & ";and " & ref3 & "."
+    doAssert refline in output1
+
+  test "Option lists 1":
+    # check that "* b" is not consumed by previous bullet item because of
+    # incorrect indentation handling in option lists
+    let input = dedent """
+      * a
+        -m   desc
+        -n   very long
+             desc
+      * b"""
+    let output = input.toHtml
+    check(output.count("<ul") == 1)
+    check(output.count("<li>") == 2)
+    check(output.count("<div class=\"option-list\"") == 1)
+    check(optionListLabel("-m") &
+          """<div class="option-list-description">desc</div></div>""" in
+          output)
+    check(optionListLabel("-n") &
+          """<div class="option-list-description">very long desc</div></div>""" in
+          output)
+
+  test "Option lists 2":
+    # check that 2nd option list is not united with the 1st
+    let input = dedent """
+      * a
+        -m   desc
+        -n   very long
+             desc
+      -d  option"""
+    let output = input.toHtml
+    check(output.count("<ul") == 1)
+    check output.count("<div class=\"option-list\"") == 2
+    check(optionListLabel("-m") &
+          """<div class="option-list-description">desc</div></div>""" in
+          output)
+    check(optionListLabel("-n") &
+          """<div class="option-list-description">very long desc</div></div>""" in
+          output)
+    check(optionListLabel("-d") &
+          """<div class="option-list-description">option</div></div>""" in
+          output)
+    check "<p>option</p>" notin output
+
+  test "Option list 3 (double /)":
+    let input = dedent """
+      * a
+        //compile  compile1
+        //doc      doc1
+                   cont
+      -d  option"""
+    let output = input.toHtml
+    check(output.count("<ul") == 1)
+    check output.count("<div class=\"option-list\"") == 2
+    check(optionListLabel("compile") &
+          """<div class="option-list-description">compile1</div></div>""" in
+          output)
+    check(optionListLabel("doc") &
+          """<div class="option-list-description">doc1 cont</div></div>""" in
+          output)
+    check(optionListLabel("-d") &
+          """<div class="option-list-description">option</div></div>""" in
+          output)
+    check "<p>option</p>" notin output
+
+  test "Roles: subscript prefix/postfix":
+    let expected = "See <sub>some text</sub>."
+    check "See :subscript:`some text`.".toHtml == expected
+    check "See `some text`:subscript:.".toHtml == expected
+
+  test "Roles: correct parsing from beginning of line":
+    let expected = "<sup>3</sup>He is an isotope of helium."
+    check """:superscript:`3`\ He is an isotope of helium.""".toHtml == expected
+    check """:sup:`3`\ He is an isotope of helium.""".toHtml == expected
+    check """`3`:sup:\ He is an isotope of helium.""".toHtml == expected
+    check """`3`:superscript:\ He is an isotope of helium.""".toHtml == expected
+
+  test "Roles: warnings":
+    let input = dedent"""
+      See function :py:func:`spam`.
+
+      See also `egg`:py:class:.
+      """
+    var warnings = new seq[string]
+    let output = input.toHtml(warnings=warnings)
+    doAssert warnings[].len == 2
+    check "(1, 14) Warning: " in warnings[0]
+    check "language 'py:func' not supported" in warnings[0]
+    check "(3, 15) Warning: " in warnings[1]
+    check "language 'py:class' not supported" in warnings[1]
+    check("""<p>See function <span class="py:func">spam</span>.</p>""" & "\n" &
+          """<p>See also <span class="py:class">egg</span>. </p>""" ==
+          output)
+
+  test "(not) Roles: check escaping 1":
+    let expected = """See :subscript:<tt class="docutils literal">""" &
+                   """<span class="pre">""" & id"some" & " " & id"text" &
+                   "</span></tt>."
+    check """See \:subscript:`some text`.""".toHtml == expected
+    check """See :subscript\:`some text`.""".toHtml == expected
+
+  test "(not) Roles: check escaping 2":
+    check("""See :subscript:\`some text\`.""".toHtml ==
+          "See :subscript:`some text`.")
+
+  test "Field list":
+    check(":field: text".toHtml ==
+            """<table class="docinfo" frame="void" rules="none">""" &
+            """<col class="docinfo-name" /><col class="docinfo-content" />""" &
+            """<tbody valign="top"><tr><th class="docinfo-name">field:</th>""" &
+            """<td>text</td></tr>""" & "\n</tbody></table>")
+
+  test "Field list: body after newline":
+    let output = dedent"""
+      :field:
+        text1""".toHtml
+    check "<table class=\"docinfo\"" in output
+    check ">field:</th>" in output
+    check "<td>text1</td>" in output
+
+  test "Field list (incorrect)":
+    check ":field:text".toHtml == ":field:text"
+
+suite "RST/Code highlight":
+  test "Basic Python code highlight":
+    let pythonCode = """
+    .. code-block:: python
+
+      def f_name(arg=42):
+          print(f"{arg}")
+
+    """
+
+    let expected = """<blockquote><p><span class="Keyword">def</span> f_name<span class="Punctuation">(</span><span class="Punctuation">arg</span><span class="Operator">=</span><span class="DecNumber">42</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
+    print<span class="Punctuation">(</span><span class="RawData">f&quot;{arg}&quot;</span><span class="Punctuation">)</span></p></blockquote>"""
+
+    check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
+      strip(expected)
+
+
+suite "invalid targets":
+  test "invalid image target":
+    let input1 = dedent """.. image:: /images/myimage.jpg
+      :target: https://bar.com
+      :alt: Alt text for the image"""
+    let output1 = input1.toHtml
+    check output1 == """<a class="reference external" href="https://bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
+
+    let input2 = dedent """.. image:: /images/myimage.jpg
+      :target: javascript://bar.com
+      :alt: Alt text for the image"""
+    let output2 = input2.toHtml
+    check output2 == """<img src="/images/myimage.jpg" alt="Alt text for the image"/>"""
+
+    let input3 = dedent """.. image:: /images/myimage.jpg
+      :target: bar.com
+      :alt: Alt text for the image"""
+    let output3 = input3.toHtml
+    check output3 == """<a class="reference external" href="bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
+
+  test "invalid links":
+    check("(([Nim](https://nim-lang.org/)))".toHtml ==
+        """((<a class="reference external" href="https://nim-lang.org/">Nim</a>))""")
+    # unknown protocol is treated just like plain text, not a link
+    var warnings = new seq[string]
+    check("(([Nim](javascript://nim-lang.org/)))".toHtml(warnings=warnings) ==
+        """(([Nim](javascript://nim-lang.org/)))""")
+    check(warnings[] == @["input(1, 9) Warning: broken link 'javascript'"])
+    warnings[].setLen 0
+    check("`Nim <javascript://nim-lang.org/>`_".toHtml(warnings=warnings) ==
+      """Nim &lt;javascript://nim-lang.org/&gt;""")
+    check(warnings[] == @["input(1, 33) Warning: broken link 'javascript'"])
+
+suite "local file inclusion":
+  test "cannot include files in sandboxed mode":
+    var error = new string
+    discard ".. include:: ./readme.md".toHtml(error=error)
+    check(error[] == "input(1, 11) Error: disabled directive: 'include'")
+
+  test "code-block file directive is disabled":
+    var error = new string
+    discard ".. code-block:: nim\n    :file: ./readme.md".toHtml(error=error)
+    check(error[] == "input(2, 20) Error: disabled directive: 'file'")
+
+  test "code-block file directive is disabled - Markdown":
+    var error = new string
+    discard "```nim file = ./readme.md\n```".toHtml(error=error)
+    check(error[] == "input(1, 23) Error: disabled directive: 'file'")
+
+proc documentToHtml*(doc: string, isMarkdown: bool = false): string {.gcsafe.} =
+  var options = {roSupportMarkdown}
+  if isMarkdown:
+    options.incl roPreferMarkdown
+  result = rstToHtml(doc, options, defaultConfig())
diff --git a/tests/stdlib/tsegfaults.nim b/tests/stdlib/tsegfaults.nim
deleted file mode 100644
index 1d8508c52..000000000
--- a/tests/stdlib/tsegfaults.nim
+++ /dev/null
@@ -1,29 +0,0 @@
-discard """
-  output: '''caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!
-caught a crash!'''
-"""
-
-import segfaults
-
-proc main =
-  try:
-    var x: ptr int
-    echo x[]
-    try:
-      raise newException(ValueError, "not a crash")
-    except ValueError:
-      discard
-  except NilAccessError:
-    echo "caught a crash!"
-
-for i in 0..10:
-  main()
diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim
new file mode 100644
index 000000000..1094ae233
--- /dev/null
+++ b/tests/stdlib/tsequtils.nim
@@ -0,0 +1,547 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+# xxx move all tests under `main`
+
+import std/sequtils
+import strutils
+from algorithm import sorted
+import std/assertions
+
+{.experimental: "strictEffects".}
+{.push warningAsError[Effect]: on.}
+{.experimental: "strictFuncs".}
+
+# helper for testing double substitution side effects which are handled
+# by `evalOnceAs`
+var counter = 0
+proc identity[T](a: T): auto =
+  counter.inc
+  a
+
+block: # concat test
+  let
+    s1 = @[1, 2, 3]
+    s2 = @[4, 5]
+    s3 = @[6, 7]
+    total = concat(s1, s2, s3)
+  doAssert total == @[1, 2, 3, 4, 5, 6, 7]
+
+block: # count test
+  let
+    s1 = @[1, 2, 3, 2]
+    s2 = @['a', 'b', 'x', 'a']
+    a1 = [1, 2, 3, 2]
+    a2 = ['a', 'b', 'x', 'a']
+    r0 = count(s1, 0)
+    r1 = count(s1, 1)
+    r2 = count(s1, 2)
+    r3 = count(s2, 'y')
+    r4 = count(s2, 'x')
+    r5 = count(s2, 'a')
+    ar0 = count(a1, 0)
+    ar1 = count(a1, 1)
+    ar2 = count(a1, 2)
+    ar3 = count(a2, 'y')
+    ar4 = count(a2, 'x')
+    ar5 = count(a2, 'a')
+  doAssert r0 == 0
+  doAssert r1 == 1
+  doAssert r2 == 2
+  doAssert r3 == 0
+  doAssert r4 == 1
+  doAssert r5 == 2
+  doAssert ar0 == 0
+  doAssert ar1 == 1
+  doAssert ar2 == 2
+  doAssert ar3 == 0
+  doAssert ar4 == 1
+  doAssert ar5 == 2
+
+block: # cycle tests
+  let
+    a = @[1, 2, 3]
+    b: seq[int] = @[]
+    c = [1, 2, 3]
+
+  doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  doAssert a.cycle(0) == @[]
+  #doAssert a.cycle(-1) == @[] # will not compile!
+  doAssert b.cycle(3) == @[]
+  doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  doAssert c.cycle(0) == @[]
+
+block: # repeat tests
+  doAssert repeat(10, 5) == @[10, 10, 10, 10, 10]
+  doAssert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]]
+  doAssert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]]
+
+block: # deduplicates test
+  let
+    dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
+    dup2 = @["a", "a", "c", "d", "d"]
+    dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4]
+    dup4 = ["a", "a", "c", "d", "d"]
+    unique1 = deduplicate(dup1)
+    unique2 = deduplicate(dup2)
+    unique3 = deduplicate(dup3)
+    unique4 = deduplicate(dup4)
+    unique5 = deduplicate(dup1.sorted, true)
+    unique6 = deduplicate(dup2, true)
+    unique7 = deduplicate(dup3.sorted, true)
+    unique8 = deduplicate(dup4, true)
+  doAssert unique1 == @[1, 3, 4, 2, 8]
+  doAssert unique2 == @["a", "c", "d"]
+  doAssert unique3 == @[1, 3, 4, 2, 8]
+  doAssert unique4 == @["a", "c", "d"]
+  doAssert unique5 == @[1, 2, 3, 4, 8]
+  doAssert unique6 == @["a", "c", "d"]
+  doAssert unique7 == @[1, 2, 3, 4, 8]
+  doAssert unique8 == @["a", "c", "d"]
+
+block: # zip test
+  let
+    short = @[1, 2, 3]
+    long = @[6, 5, 4, 3, 2, 1]
+    words = @["one", "two", "three"]
+    ashort = [1, 2, 3]
+    along = [6, 5, 4, 3, 2, 1]
+    awords = ["one", "two", "three"]
+    zip1 = zip(short, long)
+    zip2 = zip(short, words)
+    zip3 = zip(ashort, along)
+  doAssert zip1 == @[(1, 6), (2, 5), (3, 4)]
+  doAssert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
+  doAssert zip3 == @[(1, 6), (2, 5), (3, 4)]
+  doAssert zip1[2][1] == 4
+  doAssert zip2[2][1] == "three"
+  doAssert zip3[2][1] == 4
+  when (NimMajor, NimMinor) <= (1, 0):
+    let
+      # In Nim 1.0.x and older, zip returned a seq of tuple strictly
+      # with fields named "a" and "b".
+      zipAb = zip(ashort, awords)
+    doAssert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")]
+    doAssert zipAb[2].b == "three"
+  else:
+    let
+      # As zip returns seq of anonymous tuples, they can be assigned
+      # to any variable that's a sequence of named tuples too.
+      zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords)
+      zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words)
+    doAssert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")]
+    doAssert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")]
+    doAssert zipXy[2].y == "three"
+    doAssert zipMn[2].n == "three"
+
+block: # distribute tests
+  let numbers = @[1, 2, 3, 4, 5, 6, 7]
+  doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+  doAssert numbers.distribute(6)[0] == @[1, 2]
+  doAssert numbers.distribute(6)[5] == @[7]
+  let a = @[1, 2, 3, 4, 5, 6, 7]
+  doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
+  doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
+  doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
+  doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
+  doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+  doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
+  doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
+  doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
+  doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
+  doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
+  doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
+  doAssert a.distribute(6, false) == @[
+    @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
+  doAssert a.distribute(8, false) == a.distribute(8, true)
+  doAssert a.distribute(90, false) == a.distribute(90, true)
+  var b = @[0]
+  for f in 1 .. 25: b.add(f)
+  doAssert b.distribute(5, true)[4].len == 5
+  doAssert b.distribute(5, false)[4].len == 2
+
+block: # map test
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    m1 = map(numbers, proc(x: int): int = 2*x)
+    m2 = map(anumbers, proc(x: int): int = 2*x)
+  doAssert m1 == @[2, 8, 10, 16, 18, 14, 8]
+  doAssert m2 == @[2, 8, 10, 16, 18, 14, 8]
+
+block: # apply test
+  var a = @["1", "2", "3", "4"]
+  apply(a, proc(x: var string) = x &= "42")
+  doAssert a == @["142", "242", "342", "442"]
+
+block: # filter proc test
+  let
+    colors = @["red", "yellow", "black"]
+    acolors = ["red", "yellow", "black"]
+    f1 = filter(colors, proc(x: string): bool = x.len < 6)
+    f2 = filter(colors) do (x: string) -> bool: x.len > 5
+    f3 = filter(acolors, proc(x: string): bool = x.len < 6)
+    f4 = filter(acolors) do (x: string) -> bool: x.len > 5
+  doAssert f1 == @["red", "black"]
+  doAssert f2 == @["yellow"]
+  doAssert f3 == @["red", "black"]
+  doAssert f4 == @["yellow"]
+
+block: # filter iterator test
+  let numbers = @[1, 4, 5, 8, 9, 7, 4]
+  let anumbers = [1, 4, 5, 8, 9, 7, 4]
+  doAssert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
+    @[4, 8, 4]
+  doAssert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) ==
+    @[4, 8, 4]
+
+block: # keepIf test
+  var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
+  keepIf(floats, proc(x: float): bool = x > 10)
+  doAssert floats == @[13.0, 12.5, 10.1]
+
+block: # insert tests
+  var dest = @[1, 1, 1, 1, 1, 1, 1, 1]
+  let
+    src = @[2, 2, 2, 2, 2, 2]
+    outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1]
+  dest.insert(src, 3)
+  doAssert dest == outcome, """\
+  Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
+  at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
+
+block: # filterIt test
+  let
+    temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
+    acceptable = filterIt(temperatures, it < 50 and it > -10)
+    notAcceptable = filterIt(temperatures, it > 50 or it < -10)
+  doAssert acceptable == @[-2.0, 24.5, 44.31]
+  doAssert notAcceptable == @[-272.15, 99.9, -113.44]
+
+block: # keepItIf test
+  var candidates = @["foo", "bar", "baz", "foobar"]
+  keepItIf(candidates, it.len == 3 and it[0] == 'b')
+  doAssert candidates == @["bar", "baz"]
+
+block: # all
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert all(numbers, proc (x: int): bool = return x < 10) == true
+  doAssert all(numbers, proc (x: int): bool = return x < 9) == false
+  doAssert all(len0seq, proc (x: int): bool = return false) == true
+  doAssert all(anumbers, proc (x: int): bool = return x < 10) == true
+  doAssert all(anumbers, proc (x: int): bool = return x < 9) == false
+
+block: # allIt
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert allIt(numbers, it < 10) == true
+  doAssert allIt(numbers, it < 9) == false
+  doAssert allIt(len0seq, false) == true
+  doAssert allIt(anumbers, it < 10) == true
+  doAssert allIt(anumbers, it < 9) == false
+
+block: # any
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert any(numbers, proc (x: int): bool = return x > 8) == true
+  doAssert any(numbers, proc (x: int): bool = return x > 9) == false
+  doAssert any(len0seq, proc (x: int): bool = return true) == false
+  doAssert any(anumbers, proc (x: int): bool = return x > 8) == true
+  doAssert any(anumbers, proc (x: int): bool = return x > 9) == false
+
+block: # anyIt
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert anyIt(numbers, it > 8) == true
+  doAssert anyIt(numbers, it > 9) == false
+  doAssert anyIt(len0seq, true) == false
+  doAssert anyIt(anumbers, it > 8) == true
+  doAssert anyIt(anumbers, it > 9) == false
+
+block: # toSeq test
+  block:
+    let
+      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      oddNumbers = toSeq(filter(numeric) do (x: int) -> bool:
+        if x mod 2 == 1:
+          result = true)
+    doAssert oddNumbers == @[1, 3, 5, 7, 9]
+
+  block:
+    doAssert [1, 2].toSeq == @[1, 2]
+    doAssert @[1, 2].toSeq == @[1, 2]
+
+    doAssert @[1, 2].toSeq == @[1, 2]
+    doAssert toSeq(@[1, 2]) == @[1, 2]
+
+  block:
+    iterator myIter(seed: int): auto =
+      for i in 0..<seed:
+        yield i
+    doAssert toSeq(myIter(2)) == @[0, 1]
+
+  block:
+    iterator myIter(): auto {.inline.} =
+      yield 1
+      yield 2
+
+    doAssert myIter.toSeq == @[1, 2]
+    doAssert toSeq(myIter) == @[1, 2]
+
+  when not defined(js):
+    # pending #4695
+    block:
+        iterator myIter(): int {.closure.} =
+          yield 1
+          yield 2
+
+        doAssert myIter.toSeq == @[1, 2]
+        doAssert toSeq(myIter) == @[1, 2]
+
+    block:
+      proc myIter(): auto =
+        iterator ret(): int {.closure.} =
+          yield 1
+          yield 2
+        result = ret
+
+      doAssert myIter().toSeq == @[1, 2]
+      doAssert toSeq(myIter()) == @[1, 2]
+
+    block:
+      proc myIter(n: int): auto =
+        var counter = 0
+        iterator ret(): int {.closure.} =
+          while counter < n:
+            yield counter
+            counter.inc
+        result = ret
+
+      block:
+        let myIter3 = myIter(3)
+        doAssert myIter3.toSeq == @[0, 1, 2]
+      block:
+        let myIter3 = myIter(3)
+        doAssert toSeq(myIter3) == @[0, 1, 2]
+      block:
+        # makes sure this does not hang forever
+        doAssert myIter(3).toSeq == @[0, 1, 2]
+        doAssert toSeq(myIter(3)) == @[0, 1, 2]
+
+block:
+  # tests https://github.com/nim-lang/Nim/issues/7187
+  counter = 0
+  let ret = toSeq(@[1, 2, 3].identity().filter(proc (x: int): bool = x < 3))
+  doAssert ret == @[1, 2]
+  doAssert counter == 1
+block: # foldl tests
+  let
+    numbers = @[5, 9, 11]
+    addition = foldl(numbers, a + b)
+    subtraction = foldl(numbers, a - b)
+    multiplication = foldl(numbers, a * b)
+    words = @["nim", "is", "cool"]
+    concatenation = foldl(words, a & b)
+  doAssert addition == 25, "Addition is (((5)+9)+11)"
+  doAssert subtraction == -15, "Subtraction is (((5)-9)-11)"
+  doAssert multiplication == 495, "Multiplication is (((5)*9)*11)"
+  doAssert concatenation == "nimiscool"
+
+block: # foldr tests
+  let
+    numbers = @[5, 9, 11]
+    addition = foldr(numbers, a + b)
+    subtraction = foldr(numbers, a - b)
+    multiplication = foldr(numbers, a * b)
+    words = @["nim", "is", "cool"]
+    concatenation = foldr(words, a & b)
+  doAssert addition == 25, "Addition is (5+(9+(11)))"
+  doAssert subtraction == 7, "Subtraction is (5-(9-(11)))"
+  doAssert multiplication == 495, "Multiplication is (5*(9*(11)))"
+  doAssert concatenation == "nimiscool"
+  doAssert toSeq(1..3).foldr(a + b) == 6 # issue #14404
+
+block: # mapIt + applyIt test
+  counter = 0
+  var
+    nums = @[1, 2, 3, 4]
+    strings = nums.identity.mapIt($(4 * it))
+  doAssert counter == 1
+  nums.applyIt(it * 3)
+  doAssert nums[0] + nums[3] == 15
+  doAssert strings[2] == "12"
+
+block: # newSeqWith tests
+  var seq2D = newSeqWith(4, newSeq[bool](2))
+  seq2D[0][0] = true
+  seq2D[1][0] = true
+  seq2D[0][1] = true
+  doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
+
+block: # bug #21538
+  var x: seq[int] = @[2, 4]
+  var y = newSeqWith(x.pop(), true)
+  doAssert y == @[true, true, true, true]
+
+block: # mapLiterals tests
+  let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int)
+  doAssert x is array[4, int]
+  doAssert mapLiterals((1, ("abc"), 2), float, nested = false) ==
+    (float(1), "abc", float(2))
+  doAssert mapLiterals(([1], ("abc"), 2), `$`, nested = true) ==
+    (["1"], "abc", "2")
+
+block: # mapIt with openArray
+  counter = 0
+  proc foo(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+  doAssert foo([identity(1), identity(2)]) == @[10, 20]
+  doAssert counter == 2
+
+block: # mapIt with direct openArray
+  proc foo1(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+  counter = 0
+  doAssert foo1(openArray[int]([identity(1), identity(2)])) == @[10, 20]
+  doAssert counter == 2
+
+  # Corner cases (openArray literals should not be common)
+  template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+  counter = 0
+  doAssert foo2(openArray[int]([identity(1), identity(2)])) == @[10, 20]
+  doAssert counter == 2
+
+  counter = 0
+  doAssert openArray[int]([identity(1), identity(2)]).mapIt(it) == @[1, 2]
+  doAssert counter == 2
+
+block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468
+  # NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type
+  # of elements)
+  doAssert: not compiles(mapIt(@[], it))
+  doAssert: not compiles(mapIt([], it))
+  doAssert newSeq[int](0).mapIt(it) == @[]
+
+block: # mapIt redifinition check, see https://github.com/nim-lang/Nim/issues/8580
+  let s2 = [1, 2].mapIt(it)
+  doAssert s2 == @[1, 2]
+
+block:
+  counter = 0
+  doAssert [1, 2].identity().mapIt(it*2).mapIt(it*10) == @[20, 40]
+  # https://github.com/nim-lang/Nim/issues/7187 test case
+  doAssert counter == 1
+
+block: # mapIt with invalid RHS for `let` (#8566)
+  type X = enum
+    A, B
+  doAssert mapIt(X, $it) == @["A", "B"]
+
+block:
+  # bug #9093
+  let inp = "a:b,c:d"
+
+  let outp = inp.split(",").mapIt(it.split(":"))
+  doAssert outp == @[@["a", "b"], @["c", "d"]]
+
+
+block:
+  proc iter(len: int): auto =
+    result = iterator(): int =
+      for i in 0..<len:
+        yield i
+
+  # xxx: obscure CT error: basic_types.nim(16, 16) Error: internal error: symbol has no generated name: true
+  when not defined(js):
+    doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6
+
+block: # strictFuncs tests with ref object
+  type Foo = ref object
+
+  let foo1 = Foo()
+  let foo2 = Foo()
+  let foos = @[foo1, foo2]
+
+  # Procedures that are `func`
+  discard concat(foos, foos)
+  discard count(foos, foo1)
+  discard cycle(foos, 3)
+  discard deduplicate(foos)
+  discard minIndex(foos)
+  discard maxIndex(foos)
+  discard distribute(foos, 2)
+  var mutableFoos = foos
+  mutableFoos.delete(0..1)
+  mutableFoos.insert(foos)
+
+  # Some procedures that are `proc`, but were reverted from `func`
+  discard repeat(foo1, 3)
+  discard zip(foos, foos)
+  let fooTuples = @[(foo1, 1), (foo2, 2)]
+  discard unzip(fooTuples)
+
+template main =
+  # xxx move all tests here
+  block: # delete tests
+    let outcome = @[1, 1, 1, 1, 1, 1, 1, 1]
+    var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1]
+    dest.delete(3, 8)
+    doAssert outcome == dest, """\
+    Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
+    is [1,1,1,1,1,1,1,1]"""
+    var x = @[1, 2, 3]
+    x.delete(100, 100)
+    doAssert x == @[1, 2, 3]
+
+  block: # delete tests
+    var a = @[10, 11, 12, 13, 14]
+    doAssertRaises(IndexDefect): a.delete(4..5)
+    doAssertRaises(IndexDefect): a.delete(4..<6)
+    doAssertRaises(IndexDefect): a.delete(-1..1)
+    doAssertRaises(IndexDefect): a.delete(-1 .. -1)
+    doAssertRaises(IndexDefect): a.delete(5..5)
+    doAssertRaises(IndexDefect): a.delete(5..3)
+    doAssertRaises(IndexDefect): a.delete(5..<5) # edge case
+    doAssert a == @[10, 11, 12, 13, 14]
+    a.delete(4..4)
+    doAssert a == @[10, 11, 12, 13]
+    a.delete(1..2)
+    doAssert a == @[10, 13]
+    a.delete(1..<1) # empty slice
+    doAssert a == @[10, 13]
+    a.delete(0..<0)
+    doAssert a == @[10, 13]
+    a.delete(0..0)
+    doAssert a == @[13]
+    a.delete(0..0)
+    doAssert a == @[]
+    doAssertRaises(IndexDefect): a.delete(0..0)
+    doAssertRaises(IndexDefect): a.delete(0..<0) # edge case
+    block:
+      type A = object
+        a0: int
+      var a = @[A(a0: 10), A(a0: 11), A(a0: 12)]
+      a.delete(0..1)
+      doAssert a == @[A(a0: 12)]
+    block:
+      type A = ref object
+      let a0 = A()
+      let a1 = A()
+      let a2 = A()
+      var a = @[a0, a1, a2]
+      a.delete(0..1)
+      doAssert a == @[a2]
+
+static: main()
+main()
+
+{.pop.}
diff --git a/tests/stdlib/tsetutils.nim b/tests/stdlib/tsetutils.nim
new file mode 100644
index 000000000..c8498f23e
--- /dev/null
+++ b/tests/stdlib/tsetutils.nim
@@ -0,0 +1,49 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/setutils
+import std/assertions
+
+type 
+  Colors = enum
+    red, green = 5, blue = 10
+  Bar = enum
+    bar0 = -1, bar1, bar2
+
+template main =
+  block: # toSet
+    doAssert "abcbb".toSet == {'a', 'b', 'c'}
+    doAssert toSet([10u8, 12, 13]) == {10u8, 12, 13}
+    doAssert toSet(0u16..30) == {0u16..30}
+    type A = distinct char
+    doAssert [A('x')].toSet == {A('x')}
+
+  block: # fullSet
+    doAssert fullSet(Colors) == {red, green, blue}
+    doAssert fullSet(char) == {0.chr..255.chr}
+    doAssert fullSet(Bar) == {bar0, bar1, bar2}
+    doAssert fullSet(bool) == {true, false}
+
+  block: # complement
+    doAssert {red, blue}.complement == {green}
+    doAssert (complement {red, green, blue}).card == 0
+    doAssert (complement {false}) == {true}
+    doAssert {bar0}.complement == {bar1, bar2}
+    doAssert {range[0..10](0), 1, 2, 3}.complement == {range[0..10](4), 5, 6, 7, 8, 9, 10}
+    doAssert {'0'..'9'}.complement == {0.char..255.char} - {'0'..'9'}
+
+  block: # `[]=`
+    type A = enum
+      a0, a1, a2, a3
+    var s = {a0, a3}
+    s[a0] = false
+    s[a1] = false
+    doAssert s == {a3}
+    s[a2] = true
+    s[a3] = true
+    doAssert s == {a2, a3}
+
+main()
+static: main()
diff --git a/tests/stdlib/tsharedlist.nim b/tests/stdlib/tsharedlist.nim
new file mode 100644
index 000000000..b91302d19
--- /dev/null
+++ b/tests/stdlib/tsharedlist.nim
@@ -0,0 +1,49 @@
+discard """
+  matrix: "--mm:orc; --mm:refc"
+"""
+
+import std/sharedlist
+import std/assertions
+
+block:
+  var
+    list: SharedList[int]
+    count: int
+
+  init(list)
+
+  for i in 1 .. 250:
+    list.add i
+
+  for i in list:
+    inc count
+
+  doAssert count == 250
+
+  deinitSharedList(list)
+
+
+block: # bug #17696
+  var keysList = SharedList[string]()
+  init(keysList)
+
+  keysList.add("a")
+  keysList.add("b")
+  keysList.add("c")
+  keysList.add("d")
+  keysList.add("e")
+  keysList.add("f")
+
+
+  # Remove element "b" and "d" from the list. 
+  keysList.iterAndMutate(proc (key: string): bool =
+    if key == "b" or key == "d": # remove only "b" and "d"
+      return true
+    return false
+  )
+
+  var results: seq[string]
+  for key in keysList.items:
+    results.add key
+
+  doAssert results == @["a", "f", "c", "e"]
diff --git a/tests/stdlib/tsharedtable.nim b/tests/stdlib/tsharedtable.nim
new file mode 100644
index 000000000..10ad5f658
--- /dev/null
+++ b/tests/stdlib/tsharedtable.nim
@@ -0,0 +1,90 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+output: '''
+'''
+"""
+
+import sharedtables
+import std/assertions
+
+block:
+  var table: SharedTable[int, int]
+
+  init(table)
+  table[1] = 10
+  doAssert table.mget(1) == 10
+  doAssert table.mgetOrPut(3, 7) == 7
+  doAssert table.mgetOrPut(3, 99) == 7
+  deinitSharedTable(table)
+
+import sequtils, algorithm
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+template sortedItems(t: untyped): untyped = sorted(toSeq(t))
+
+import tables # refs issue #13504
+
+block: # we use Table as groundtruth, it's well tested elsewhere
+  template testDel(t, t0) =
+    template put2(i) =
+      t[i] = i
+      t0[i] = i
+
+    template add2(i, val) =
+      t.add(i, val)
+      t0.add(i, val)
+
+    template del2(i) =
+      t.del(i)
+      t0.del(i)
+
+    template checkEquals() =
+      doAssert t.len == t0.len
+      for k,v in t0:
+        doAssert t.mgetOrPut(k, -1) == v # sanity check
+        doAssert t.mget(k) == v
+
+    let n = 100
+    let n2 = n*2
+    let n3 = n*3
+    let n4 = n*4
+    let n5 = n*5
+
+    for i in 0..<n:
+      put2(i)
+    for i in 0..<n:
+      if i mod 3 == 0:
+        del2(i)
+    for i in n..<n2:
+      put2(i)
+    for i in 0..<n2:
+      if i mod 7 == 0:
+        del2(i)
+
+    checkEquals()
+
+    for i in n2..<n3:
+      t0[i] = -2
+      doAssert t.mgetOrPut(i, -2) == -2
+      doAssert t.mget(i) == -2
+
+    for i in 0..<n4:
+      let ok = i in t0
+      if not ok: t0[i] = -i
+      doAssert t.hasKeyOrPut(i, -i) == ok
+
+    checkEquals()
+
+    for i in n4..<n5:
+      add2(i, i*10)
+      add2(i, i*11)
+      add2(i, i*12)
+      del2(i)
+      del2(i)
+
+    checkEquals()
+
+  var t: SharedTable[int, int]
+  init(t) # ideally should be auto-init
+  var t0: Table[int, int]
+  testDel(t, t0)
+  deinitSharedTable(t)
diff --git a/tests/stdlib/tsince.nim b/tests/stdlib/tsince.nim
new file mode 100644
index 000000000..a0a4229cb
--- /dev/null
+++ b/tests/stdlib/tsince.nim
@@ -0,0 +1,32 @@
+import std/private/since
+import std/assertions
+
+proc fun1(): int {.since: (1, 3).} = 12
+proc fun1Bad(): int {.since: (99, 3).} = 12
+proc fun2(): int {.since: (1, 3, 1).} = 12
+proc fun2Bad(): int {.since: (99, 3, 1).} = 12
+
+doAssert fun1() == 12
+doAssert declared(fun1)
+doAssert not declared(fun1Bad)
+
+doAssert fun2() == 12
+doAssert declared(fun2)
+doAssert not declared(fun2Bad)
+
+var ok = false
+since (1, 3):
+  ok = true
+doAssert ok
+
+ok = false
+since (1, 3, 1):
+  ok = true
+doAssert ok
+
+since (99, 3):
+  doAssert false
+
+template fun3(): int {.since: (1, 3).} = 12
+
+doAssert declared(fun3)
diff --git a/tests/stdlib/tsinglylinkedring.nim b/tests/stdlib/tsinglylinkedring.nim
deleted file mode 100644
index 93f0c69cd..000000000
--- a/tests/stdlib/tsinglylinkedring.nim
+++ /dev/null
@@ -1,29 +0,0 @@
-discard """
-  output: '''[5]
-[4, 5]
-[3, 4, 5]
-[2, 3, 4, 5]
-[2, 3, 4, 5, 6]
-[2, 3, 4, 5, 6, 7]
-[2, 3, 4, 5, 6, 7, 8]
-[1, 2, 3, 4, 5, 6, 7, 8]'''
-"""
-import lists
-
-var r = initSinglyLinkedRing[int]()
-r.prepend(5)
-echo r
-r.prepend(4)
-echo r
-r.prepend(3)
-echo r
-r.prepend(2)
-echo r
-r.append(6)
-echo r
-r.append(7)
-echo r
-r.append(8)
-echo r
-r.prepend(1)
-echo r
diff --git a/tests/stdlib/tsocketstreams.nim b/tests/stdlib/tsocketstreams.nim
new file mode 100644
index 000000000..a37e7c34c
--- /dev/null
+++ b/tests/stdlib/tsocketstreams.nim
@@ -0,0 +1,65 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+OM
+NIM
+3
+NIM
+NIM
+Hello server!
+Hi there client!
+'''"""
+import std/socketstreams, net, streams
+
+block UDP:
+  var recvSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+  var recvStream = newReadSocketStream(recvSocket)
+  recvSocket.bindAddr(Port(12345), "127.0.0.1")
+
+  var sendSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+  sendSocket.connect("127.0.0.1", Port(12345))
+  var sendStream = newWriteSocketStream(sendSocket)
+  sendStream.write "NOM\n"
+  sendStream.setPosition(1)
+  echo sendStream.peekStr(2)
+  sendStream.write "I"
+  sendStream.setPosition(0)
+  echo sendStream.readStr(3)
+  echo sendStream.getPosition()
+  sendStream.flush()
+
+  echo recvStream.readLine()
+  recvStream.setPosition(0)
+  echo recvStream.readLine()
+  recvStream.close()
+
+block TCP:
+  var server = newSocket()
+  server.setSockOpt(OptReusePort, true)
+  server.bindAddr(Port(12345))
+  server.listen()
+
+  var
+    client = newSocket()
+    clientRequestStream = newWriteSocketStream(client)
+    clientResponseStream = newReadSocketStream(client)
+  client.connect("127.0.0.1", Port(12345))
+  clientRequestStream.writeLine("Hello server!")
+  clientRequestStream.flush()
+
+  var
+    incoming: Socket
+    address: string
+  server.acceptAddr(incoming, address)
+  var
+    serverRequestStream = newReadSocketStream(incoming)
+    serverResponseStream = newWriteSocketStream(incoming)
+  echo serverRequestStream.readLine()
+  serverResponseStream.writeLine("Hi there client!")
+  serverResponseStream.flush()
+  serverResponseStream.close()
+  serverRequestStream.close()
+
+  echo clientResponseStream.readLine()
+  clientResponseStream.close()
+  clientRequestStream.close()
diff --git a/tests/stdlib/tsortcall.nim b/tests/stdlib/tsortcall.nim
index efe1d0b8b..32e004921 100644
--- a/tests/stdlib/tsortcall.nim
+++ b/tests/stdlib/tsortcall.nim
@@ -1,5 +1,69 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
 import algorithm
+import unittest
+
+
+suite "test sort, sorted, and isSorted procs":
+  proc foosort(ships: var seq[int]) = sort(ships, system.cmp[int])
+
+  type
+    User = object
+      name: string
+      age: int
+
+  func newUser(name: string, age: int): User =
+    result.name = name
+    result.age = age
+
+  proc compareUsers(x, y: User): int =
+    if x.age == y.age: return 0
+    if x.age < y.age: return -1
+    return 1
+
+  setup:
+    var
+      unSortedIntSeq = @[1, 4, 3, 5, -1]
+      unSortedUserSeq = @[newUser("Andreas", 34), newUser("Alice", 12), newUser("Bob", 23)]
+
+    let
+      sortedIntSeq = @[-1, 1, 3, 4, 5]
+      sortedUserSeq = @[newUser("Alice", 12), newUser("Bob", 23), newUser("Andreas", 34)]
+
+  test "test the shortcut versions of sort, sorted, and isSorted":
+    check(not unSortedIntSeq.isSorted)
+    check sorted(unSortedIntSeq) == sortedIntSeq
+    check sorted(unSortedIntSeq).isSorted
+
+    unSortedIntSeq.sort()
+    check unSortedIntSeq == sortedIntSeq
+    check unSortedIntSeq.isSorted
+
+  test "test the shortcut versions with descending sort order":
+    check(not unSortedIntSeq.isSorted(SortOrder.Descending))
+    check sorted(unSortedIntSeq, SortOrder.Descending) == reversed sortedIntSeq
+    check sorted(unSortedIntSeq).isSorted(SortOrder.Ascending)
+
+    unSortedIntSeq.sort(SortOrder.Descending)
+    check unSortedIntSeq == reversed sortedIntSeq
+    check unSortedIntSeq.isSorted(SortOrder.Descending)
 
-proc foosort(ships: var seq[int]) = sort(ships, system.cmp[int])
+  test "test the versions that accept a custom compareUsers function":
+    check(not unSortedUserSeq.isSorted(compareUsers))
+    check sorted(unSortedUserSeq, compareUsers) == sortedUserSeq
+    check sorted(unSortedUserSeq, compareUsers).isSorted(compareUsers)
 
+    unSortedUserSeq.sort(compareUsers)
+    check unSortedUserSeq == sortedUserSeq
+    check unSortedUserSeq.isSorted(compareUsers)
 
+  test "test the long versions with descending sort order":
+    check(not unSortedUserSeq.isSorted(compareUsers, SortOrder.Descending))
+    check sorted(unSortedUserSeq, compareUsers, SortOrder.Descending) == reversed sortedUserSeq
+    check sorted(unSortedUserSeq, compareUsers,
+                  SortOrder.Descending).isSorted(compareUsers, SortOrder.Descending)
+    unSortedUserSeq.sort(compareUsers, SortOrder.Descending)
+    check unSortedUserSeq == reversed sortedUserSeq
+    check unSortedUserSeq.isSorted(compareUsers, SortOrder.Descending)
diff --git a/tests/stdlib/tsplit.nim b/tests/stdlib/tsplit.nim
deleted file mode 100644
index 44da58aca..000000000
--- a/tests/stdlib/tsplit.nim
+++ /dev/null
@@ -1,20 +0,0 @@
-discard """
-  file: "tsplit.nim"
-  output: "true"
-"""
-import strutils
-
-var s = ""
-for w in split("|abc|xy|z", {'|'}):
-  s.add("#")
-  s.add(w)
-
-if s == "##abc#xy#z":
-  echo "true"
-else:
-  echo "false"
-
-#OUT true
-
-
-
diff --git a/tests/stdlib/tsplit2.nim b/tests/stdlib/tsplit2.nim
deleted file mode 100644
index 7fd9dda74..000000000
--- a/tests/stdlib/tsplit2.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-discard """
-  file: "tsplit2.nim"
-  output: "true"
-"""
-import strutils
-
-var s = ""
-for w in split("|abc|xy|z", {'|'}):
-  s.add("#")
-  s.add(w)
-
-try:
-  discard "hello".split("")
-  echo "false"
-except AssertionError:
-  echo "true"
-
-#OUT true
-
diff --git a/tests/stdlib/tsqlitebindatas.nim b/tests/stdlib/tsqlitebindatas.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/stdlib/tsqlitebindatas.nim
diff --git a/tests/stdlib/tsqlparser.nim b/tests/stdlib/tsqlparser.nim
index 4a7b2f7d7..6f123f21d 100644
--- a/tests/stdlib/tsqlparser.nim
+++ b/tests/stdlib/tsqlparser.nim
@@ -1,4 +1,5 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
   output: '''true'''
 """
 
@@ -6,7 +7,7 @@ discard """
 
 import parsesql, streams, os
 
-var tree = parseSql(newFileStream(getAppDir() / "somesql.sql"), "somesql")
+var tree = parseSql(newFileStream(parentDir(currentSourcePath) / "somesql.sql"), "somesql")
 discard renderSql(tree)
 
 echo "true"
diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim
new file mode 100644
index 000000000..1628b9326
--- /dev/null
+++ b/tests/stdlib/tssl.nim
@@ -0,0 +1,138 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+  disabled: "freebsd" # see #15713
+  disabled: "openbsd" # see #15713
+  disabled: "netbsd" # see #15713
+"""
+
+import std/[net, nativesockets, assertions, typedthreads]
+
+when defined(posix): import os, posix
+else:
+  import winlean
+  const SD_SEND = 1
+
+when not defined(ssl):
+  {.error: "This test must be compiled with -d:ssl".}
+
+const DummyData = "dummy data\n"
+
+proc abruptShutdown(port: Port) {.thread.} =
+  let clientContext = newContext(verifyMode = CVerifyNone)
+  var client = newSocket(buffered = false)
+  clientContext.wrapSocket(client)
+  client.connect("localhost", port)
+
+  discard client.recvLine()
+  client.getFd.close()
+
+proc notifiedShutdown(port: Port) {.thread.} =
+  let clientContext = newContext(verifyMode = CVerifyNone)
+  var client = newSocket(buffered = false)
+  clientContext.wrapSocket(client)
+  client.connect("localhost", port)
+
+  discard client.recvLine()
+  client.close()
+
+proc main() =
+  when defined(posix):
+    var
+      ignoreAction = Sigaction(sa_handler: SIG_IGN)
+      oldSigPipeHandler: Sigaction
+    if sigemptyset(ignoreAction.sa_mask) == -1:
+      raiseOSError(osLastError(), "Couldn't create an empty signal set")
+    if sigaction(SIGPIPE, ignoreAction, oldSigPipeHandler) == -1:
+      raiseOSError(osLastError(), "Couldn't ignore SIGPIPE")
+
+  let serverContext = newContext(verifyMode = CVerifyNone,
+                                 certFile = "tests/testdata/mycert.pem",
+                                 keyFile = "tests/testdata/mycert.pem")
+
+  block peer_close_during_write_without_shutdown:
+    var server = newSocket(buffered = false)
+    defer: server.close()
+    serverContext.wrapSocket(server)
+    server.bindAddr(address = "localhost")
+    let (_, port) = server.getLocalAddr()
+    server.listen()
+
+    var clientThread: Thread[Port]
+    createThread(clientThread, abruptShutdown, port)
+
+    var peer: Socket
+    try:
+      server.accept(peer)
+      peer.send(DummyData)
+
+      joinThread clientThread
+
+      while true:
+        # Send data until we get EPIPE.
+        peer.send(DummyData, {})
+    except OSError:
+      discard
+    finally:
+      peer.close()
+
+  when defined(posix):
+    if sigaction(SIGPIPE, oldSigPipeHandler, nil) == -1:
+      raiseOSError(osLastError(), "Couldn't restore SIGPIPE handler")
+
+  block peer_close_before_received_shutdown:
+    var server = newSocket(buffered = false)
+    defer: server.close()
+    serverContext.wrapSocket(server)
+    server.bindAddr(address = "localhost")
+    let (_, port) = server.getLocalAddr()
+    server.listen()
+
+    var clientThread: Thread[Port]
+    createThread(clientThread, abruptShutdown, port)
+
+    var peer: Socket
+    try:
+      server.accept(peer)
+      peer.send(DummyData)
+
+      joinThread clientThread
+
+      # Tell the OS to close off the write side so shutdown attempts will
+      # be met with SIGPIPE.
+      when defined(posix):
+        discard peer.getFd.shutdown(SHUT_WR)
+      else:
+        discard peer.getFd.shutdown(SD_SEND)
+    finally:
+      peer.close()
+
+  block peer_close_after_received_shutdown:
+    var server = newSocket(buffered = false)
+    defer: server.close()
+    serverContext.wrapSocket(server)
+    server.bindAddr(address = "localhost")
+    let (_, port) = server.getLocalAddr()
+    server.listen()
+
+    var clientThread: Thread[Port]
+    createThread(clientThread, notifiedShutdown, port)
+
+    var peer: Socket
+    try:
+      server.accept(peer)
+      peer.send(DummyData)
+
+      doAssert peer.recv(1024) == "" # Get the shutdown notification
+      joinThread clientThread
+
+      # Tell the OS to close off the write side so shutdown attempts will
+      # be met with SIGPIPE.
+      when defined(posix):
+        discard peer.getFd.shutdown(SHUT_WR)
+      else:
+        discard peer.getFd.shutdown(SD_SEND)
+    finally:
+      peer.close()
+
+when isMainModule: main()
diff --git a/tests/stdlib/tssl.nims b/tests/stdlib/tssl.nims
new file mode 100644
index 000000000..4739e7f07
--- /dev/null
+++ b/tests/stdlib/tssl.nims
@@ -0,0 +1,5 @@
+--threads:on
+--d:ssl
+when defined(freebsd) or defined(netbsd):
+  # See https://github.com/nim-lang/Nim/pull/15066#issuecomment-665541265 and https://github.com/nim-lang/Nim/issues/15493
+  --tlsEmulation:off
diff --git a/tests/stdlib/tstackframes.nim b/tests/stdlib/tstackframes.nim
new file mode 100644
index 000000000..b0f05d51d
--- /dev/null
+++ b/tests/stdlib/tstackframes.nim
@@ -0,0 +1,34 @@
+import std/[strformat,os,osproc,assertions]
+import stdtest/unittest_light
+
+proc main(opt: string, expected: string) =
+  const nim = getCurrentCompilerExe()
+  const file = currentSourcePath().parentDir / "mstackframes.nim"
+  let cmd = fmt"{nim} c -r --excessiveStackTrace:off --stacktraceMsgs:{opt} --hints:off {file}"
+  let (output, exitCode) = execCmdEx(cmd)
+  assertEquals output, expected
+  doAssert exitCode == 0
+
+main("on"): """
+mstackframes.nim(38)     mstackframes
+mstackframes.nim(29)     main
+  z: 0
+  z: 1
+mstackframes.nim(20)     main2 ("main2", 5, 1)
+mstackframes.nim(20)     main2 ("main2", 4, 2)
+mstackframes.nim(20)     main2 ("main2", 3, 3)
+mstackframes.nim(19)     main2 ("main2", 2, 4)
+mstackframes.nim(18)     bar ("bar ",)
+
+"""
+
+main("off"): """
+mstackframes.nim(38)     mstackframes
+mstackframes.nim(29)     main
+mstackframes.nim(20)     main2
+mstackframes.nim(20)     main2
+mstackframes.nim(20)     main2
+mstackframes.nim(19)     main2
+mstackframes.nim(18)     bar
+
+"""
diff --git a/tests/stdlib/tstaticos.nim b/tests/stdlib/tstaticos.nim
new file mode 100644
index 000000000..41ab995dd
--- /dev/null
+++ b/tests/stdlib/tstaticos.nim
@@ -0,0 +1,8 @@
+import std/[assertions, staticos, os]
+
+block:
+  static:
+    doAssert staticDirExists("MISSINGFILE") == false
+    doAssert staticFileExists("MISSINGDIR") == false
+    doAssert staticDirExists(currentSourcePath().parentDir)
+    doAssert staticFileExists(currentSourcePath())
diff --git a/tests/stdlib/tstats.nim b/tests/stdlib/tstats.nim
new file mode 100644
index 000000000..728d93d09
--- /dev/null
+++ b/tests/stdlib/tstats.nim
@@ -0,0 +1,61 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[stats, assertions]
+import std/math
+
+
+func `~=`(x, y: float32): bool =
+  math.almostEqual(x, y)
+
+template main() =
+  var rs: RunningStat
+  rs.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0])
+  doAssert(rs.n == 8)
+  doAssert rs.mean ~= 2.0
+  doAssert rs.variance() ~= 1.5
+  doAssert rs.varianceS() ~= 1.71428571
+  doAssert rs.skewness() ~= 0.81649658
+  doAssert rs.skewnessS() ~= 1.01835015
+  doAssert rs.kurtosis() ~= -1.0
+  doAssert rs.kurtosisS() ~= -0.7000000000000001
+
+  var rs1, rs2: RunningStat
+  rs1.push(@[1.0, 2.0, 1.0, 4.0])
+  rs2.push(@[1.0, 4.0, 1.0, 2.0])
+  let rs3 = rs1 + rs2
+  doAssert rs3.variance ~= rs.variance
+  doAssert rs3.skewness ~= rs.skewness
+  doAssert rs3.kurtosis ~= rs.kurtosis
+  rs1 += rs2
+  doAssert rs1.variance ~= rs.variance
+  doAssert rs1.skewness ~= rs.skewness
+  doAssert rs1.kurtosis ~= rs.kurtosis
+  rs1.clear()
+  rs1.push(@[1.0, 2.2, 1.4, 4.9])
+  doAssert rs1.sum ~= 9.5
+  doAssert rs1.mean() ~= 2.375
+
+  when not defined(cpu32):
+    # XXX For some reason on 32bit CPUs these results differ
+    var rr: RunningRegress
+    rr.push(@[0.0, 1.0, 2.8, 3.0, 4.0], @[0.0, 1.0, 2.3, 3.0, 4.0])
+    doAssert rr.slope() ~= 0.9695585996955861
+    doAssert rr.intercept() ~= -0.03424657534246611
+    doAssert rr.correlation() ~= 0.9905100362239381
+    var rr1, rr2: RunningRegress
+    rr1.push(@[0.0, 1.0], @[0.0, 1.0])
+    rr2.push(@[2.8, 3.0, 4.0], @[2.3, 3.0, 4.0])
+    let rr3 = rr1 + rr2
+    doAssert rr3.correlation() ~= rr.correlation()
+    doAssert rr3.slope() ~= rr.slope()
+    doAssert rr3.intercept() ~= rr.intercept()
+
+  block: # bug #18718
+    var rs: RunningStat
+    rs.push(-1.0)
+    doAssert rs.max == -1.0
+
+static: main()
+main()
diff --git a/tests/stdlib/tstdlib_issues.nim b/tests/stdlib/tstdlib_issues.nim
new file mode 100644
index 000000000..b7b806db8
--- /dev/null
+++ b/tests/stdlib/tstdlib_issues.nim
@@ -0,0 +1,110 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+output: '''
+02
+1
+2
+3
+4
+5
+9
+b = true
+123456789
+Second readLine raised an exception
+123456789
+1
+2aaaaaaaa
+3bbbbbbb
+'''
+"""
+
+import std/[terminal, colors, re, encodings, strutils, os, assertions, syncio]
+
+
+block t9394:
+  let codeFg = ansiForegroundColorCode(colAliceBlue)
+  let codeBg = ansiBackgroundColorCode(colAliceBlue)
+
+  doAssert codeFg == "\27[38;2;240;248;255m"
+  doAssert codeBg == "\27[48;2;240;248;255m"
+
+
+
+block t5382:
+  let regexp = re"^\/([0-9]{2})\.html$"
+  var matches: array[1, string]
+  discard "/02.html".find(regexp, matches)
+  echo matches[0]
+
+
+
+block tcount:
+  # bug #1845, #2224
+  var arr = [3,2,1,5,4]
+
+  # bubble sort
+  for i in low(arr)..high(arr):
+    for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeDefect]
+      if arr[i] > arr[j]:
+        let tmp = arr[i]
+        arr[i] = arr[j]
+        arr[j] = tmp
+
+  for i in low(arr)..high(arr):
+    echo arr[i]
+
+  # check this terminates:
+  for x in countdown('\255', '\0'):
+    discard
+
+
+
+block t8468:
+  when defined(windows):
+    var utf16to8 = open(destEncoding = "utf-16", srcEncoding = "utf-8")
+    var s = "some string"
+    var c = utf16to8.convert(s)
+
+    var z = newStringOfCap(s.len * 2)
+    for x in s:
+      z.add x
+      z.add chr(0)
+
+    doAssert z == c
+
+
+
+block t5349:
+  const fn = "file9char.txt"
+  writeFile(fn, "123456789")
+
+  var f = syncio.open(fn)
+  echo getFileSize(f)
+
+  var line = newString(10)
+  try:
+    let b = readLine(f, line)
+    echo "b = ", b
+  except:
+    echo "First readLine raised an exception"
+  echo line
+
+  try:
+    line = readLine(f)
+    let b = readLine(f, line)
+    echo "b = ", b
+  except:
+    echo "Second readLine raised an exception"
+  echo line
+  f.close()
+
+  removeFile(fn)
+  # bug #8961
+  writeFile("test.txt", "1\C\L2aaaaaaaa\C\L3bbbbbbb")
+
+  for line in lines("test.txt"):
+    echo line
+
+block t9456:
+  var f: File
+  f.close()
diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim
new file mode 100644
index 000000000..bac5018fa
--- /dev/null
+++ b/tests/stdlib/tstdlib_various.nim
@@ -0,0 +1,240 @@
+discard """
+matrix: "--mm:refc"
+output: '''
+abc
+def
+definition
+prefix
+xyz
+def
+definition
+Hi Andreas! How do you feel, Rumpf?
+
+@[0, 2, 1]
+@[1, 0, 2]
+@[1, 2, 0]
+@[2, 0, 1]
+@[2, 1, 0]
+@[2, 0, 1]
+@[1, 2, 0]
+@[1, 0, 2]
+@[0, 2, 1]
+@[0, 1, 2]
+055this should be the casehugh@["(", "+", " 1", " 2", ")"]
+[5]
+[4, 5]
+[3, 4, 5]
+[2, 3, 4, 5]
+[2, 3, 4, 5, 6]
+[1, 2, 3, 4, 5, 6]
+<h1><a href="http://force7.de/nim">Nim</a></h1>
+'''
+"""
+
+import
+  std/[critbits, sets, strutils, tables, random, algorithm, re, ropes,
+  segfaults, lists, parsesql, streams, os, htmlgen, xmltree, strtabs]
+import std/[syncio, assertions]
+
+block tcritbits:
+  var r: CritBitTree[void]
+  r.incl "abc"
+  r.incl "xyz"
+  r.incl "def"
+  r.incl "definition"
+  r.incl "prefix"
+  doAssert r.contains"def"
+  #r.del "def"
+
+  for w in r.items:
+    echo w
+  for w in r.itemsWithPrefix("de"):
+    echo w
+
+
+
+block testequivalence:
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset")
+  doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==")
+  doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==")
+
+
+
+block tformat:
+  echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])
+
+
+
+block tnilecho:
+  var x = @["1", "", "3"]
+  doAssert $x == """@["1", "", "3"]"""
+
+
+
+block torderedtable:
+  var t = initOrderedTable[int,string]()
+
+  # this tests issue #5917
+  var data = newSeq[int]()
+  for i in 0..<1000:
+    var x = rand(1000)
+    if x notin t: data.add(x)
+    t[x] = "meh"
+
+  # this checks that keys are re-inserted
+  # in order when table is enlarged.
+  var i = 0
+  for k, v in t:
+    doAssert(k == data[i])
+    doAssert(v == "meh")
+    inc(i)
+
+
+
+block tpermutations:
+  var v = @[0, 1, 2]
+  while v.nextPermutation():
+    echo v
+  while v.prevPermutation():
+    echo v
+
+
+
+block treguse:
+  proc main(a, b: int) =
+    var x = 0
+    write(stdout, x)
+    if x == 0:
+      var y = 55
+      write(stdout, y)
+      write(stdout, "this should be the case")
+      var input = "<no input>"
+      if input == "Andreas":
+        write(stdout, "wow")
+      else:
+        write(stdout, "hugh")
+    else:
+      var z = 66
+      write(stdout, z) # "bug!")
+
+  main(45, 1000)
+
+
+
+block treloop:
+  let str = "(+ 1 2)"
+  var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
+  echo str.findAll(tokenRE)
+
+
+
+block tropes:
+  var
+    r1 = rope("")
+    r2 = rope("123")
+  doAssert r1.len == 0
+  doAssert r2.len == 3
+  doAssert $r1 == ""
+  doAssert $r2 == "123"
+
+  r1.add("123")
+  r2.add("456")
+  doAssert r1.len == 3
+  doAssert r2.len == 6
+  doAssert $r1 == "123"
+  doAssert $r2 == "123456"
+  doAssert $r1[1] == "2"
+  doAssert $r2[2] == "3"
+
+
+
+block tsegfaults:
+  when not defined(arm64):
+    var crashes = 0
+    proc main =
+      try:
+        var x: ptr int
+        echo x[]
+        try:
+          raise newException(ValueError, "not a crash")
+        except ValueError:
+          discard
+      except NilAccessDefect:
+        inc crashes
+    for i in 0..5:
+      main()
+    assert crashes == 6
+
+
+
+block tsinglylinkedring:
+  var r = initSinglyLinkedRing[int]()
+  r.prepend(5)
+  echo r
+  r.prepend(4)
+  echo r
+  r.prepend(3)
+  echo r
+  r.prepend(2)
+  echo r
+  r.append(6)
+  echo r
+  r.prepend(1)
+  echo r
+
+
+
+block tsplit:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert s == "##abc#xy#z"
+
+
+
+block tsplit2:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert "true".split("") == @["true"]
+
+
+
+block tsqlparser:
+  # Just check that we can parse 'somesql' and render it without crashes.
+  var tree = parseSql(newFileStream( parentDir(currentSourcePath) / "somesql.sql"), "somesql")
+  discard renderSql(tree)
+
+
+
+block txmlgen:
+  var nim = "Nim"
+  echo h1(a(href="http://force7.de/nim", nim))
+
+
+
+block txmltree:
+  var x = <>a(href="nim.de", newText("www.nim-test.de"))
+
+  doAssert($x == "<a href=\"nim.de\">www.nim-test.de</a>")
+  doAssert(newText("foo").innerText == "foo")
+  doAssert(newEntity("bar").innerText == "bar")
+  doAssert(newComment("baz").innerText == "")
+
+  let y = newXmlTree("x", [
+    newText("foo"),
+    newXmlTree("y", [
+      newText("bar")
+    ])
+  ])
+  doAssert(y.innerText == "foobar")
diff --git a/tests/stdlib/tstrbasics.nim b/tests/stdlib/tstrbasics.nim
new file mode 100644
index 000000000..a965ff15f
--- /dev/null
+++ b/tests/stdlib/tstrbasics.nim
@@ -0,0 +1,103 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[strbasics, sugar, assertions]
+
+template strip2(input: string, args: varargs[untyped]): untyped =
+  var a = input
+  when varargsLen(args) > 0:
+    strip(a, args)
+  else:
+    strip(a)
+  a
+
+proc main() =
+  block: # strip
+    block: # bug #17173
+      var a = "  vhellov   "
+      strip(a)
+      doAssert a == "vhellov"
+
+    doAssert strip2("  vhellov   ") == "vhellov"
+    doAssert strip2("  vhellov   ", leading = false) == "  vhellov"
+    doAssert strip2("  vhellov   ", trailing = false) == "vhellov   "
+    doAssert strip2("vhellov", chars = {'v'}) == "hello"
+    doAssert strip2("vhellov", leading = false, chars = {'v'}) == "vhello"
+    doAssert strip2("blaXbla", chars = {'b', 'a'}) == "laXbl"
+    doAssert strip2("blaXbla", chars = {'b', 'a', 'l'}) == "X"
+    doAssert strip2("xxxxxx", chars={'x'}) == ""
+    doAssert strip2("x", chars={'x'}) == ""
+    doAssert strip2("x", chars={'1'}) == "x"
+    doAssert strip2("", chars={'x'}) == ""
+    doAssert strip2("xxx xxx", chars={'x'}) == " "
+    doAssert strip2("xxx  wind", chars={'x'}) == "  wind"
+    doAssert strip2("xxx  iii", chars={'i'}) == "xxx  "
+
+    block:
+      var a = "xxx  iii"
+      doAssert a.dup(strip(chars = {'i'})) == "xxx  "
+      doAssert a.dup(strip(chars = {' '})) == "xxx  iii"
+      doAssert a.dup(strip(chars = {'x'})) == "  iii"
+      doAssert a.dup(strip(chars = {'x', ' '})) == "iii"
+      doAssert a.dup(strip(chars = {'x', 'i'})) == "  "
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+    block:
+      var a = "x  i"
+      doAssert a.dup(strip(chars = {'i'})) == "x  "
+      doAssert a.dup(strip(chars = {' '})) == "x  i"
+      doAssert a.dup(strip(chars = {'x'})) == "  i"
+      doAssert a.dup(strip(chars = {'x', ' '})) == "i"
+      doAssert a.dup(strip(chars = {'x', 'i'})) == "  "
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+    block:
+      var a = ""
+      doAssert a.dup(strip(chars = {'i'})).len == 0
+      doAssert a.dup(strip(chars = {' '})).len == 0
+      doAssert a.dup(strip(chars = {'x'})).len == 0
+      doAssert a.dup(strip(chars = {'x', ' '})).len == 0
+      doAssert a.dup(strip(chars = {'x', 'i'})).len == 0
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+    block:
+      var a = " "
+      doAssert a.dup(strip(chars = {'i'})) == " "
+      doAssert a.dup(strip(chars = {' '})).len == 0
+      doAssert a.dup(strip(chars = {'x'})) == " "
+      doAssert a.dup(strip(chars = {'x', ' '})).len == 0
+      doAssert a.dup(strip(chars = {'x', 'i'})) == " "
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+  block: # setSlice
+    var a = "Hello, Nim!"
+    doAssert a.dup(setSlice(7 .. 9)) == "Nim"
+    doAssert a.dup(setSlice(0 .. 0)) == "H"
+    doAssert a.dup(setSlice(0 .. 1)) == "He"
+    doAssert a.dup(setSlice(0 .. 10)) == a
+    doAssert a.dup(setSlice(1 .. 0)).len == 0
+    doAssert a.dup(setSlice(20 .. -1)).len == 0
+
+    doAssertRaises(AssertionDefect):
+      discard a.dup(setSlice(-1 .. 1))
+
+    doAssertRaises(AssertionDefect):
+      discard a.dup(setSlice(1 .. 11))
+
+  block: # add
+    var a0 = "hi"
+    var b0 = "foobar"
+    when nimvm:
+      discard # pending bug #15952
+    else:
+      a0.add b0.toOpenArray(1,3)
+      doAssert a0 == "hioob"
+    proc fn(c: openArray[char]): string =
+      result.add c
+    doAssert fn("def") == "def"
+    doAssert fn(['d','\0', 'f'])[2] == 'f'
+
+static: main()
+main()
diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim
index 640565a27..60c63b450 100644
--- a/tests/stdlib/tstreams.nim
+++ b/tests/stdlib/tstreams.nim
@@ -1,7 +1,107 @@
-import streams
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  input: "Arne"
+  output: '''
+Hello! What is your name?
+Nice name: Arne
+fs is: nil
+threw exception
+_heh_
+'''
+  nimout: '''
+I
+AM
+GROOT
+'''
+"""
 
-var outp = newFileStream(stdout)
-var inp = newFileStream(stdin)
-write(outp, "Hello! What is your name?")
-var line = readLine(inp)
-write(outp, "Nice name: " & line)
+
+import std/[syncio, streams, assertions]
+
+
+block tstreams:
+  var outp = newFileStream(stdout)
+  var inp = newFileStream(stdin)
+  writeLine(outp, "Hello! What is your name?")
+  var line = readLine(inp)
+  writeLine(outp, "Nice name: " & line)
+
+
+block tstreams2:
+  var
+    fs = newFileStream("amissingfile.txt")
+    line = ""
+  echo "fs is: ",repr(fs)
+  if not isNil(fs):
+    while fs.readLine(line):
+      echo line
+    fs.close()
+
+
+block tstreams3:
+  try:
+    var fs = openFileStream("shouldneverexist.txt")
+  except IOError:
+    echo "threw exception"
+
+  static:
+    var s = newStringStream("I\nAM\nGROOT")
+    for line in s.lines:
+      echo line
+    s.close
+
+
+block:
+  let fs = newFileStream("amissingfile.txt")
+  defer: fs.close()
+  doAssert isNil(fs)
+
+# bug #12410
+
+var a = newStringStream "hehohihahuhyh"
+a.readDataStrImpl = nil
+
+var buffer = "_ooo_"
+
+doAssert a.readDataStr(buffer, 1..3) == 3
+
+echo buffer
+
+
+block:
+  var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran")
+  doAssert(ss.getPosition == 0)
+  doAssert(ss.peekStr(5) == "The q")
+  doAssert(ss.getPosition == 0) # haven't moved
+  doAssert(ss.readStr(5) == "The q")
+  doAssert(ss.getPosition == 5) # did move
+  doAssert(ss.peekLine() == "uick brown fox jumped over the lazy dog.")
+  doAssert(ss.getPosition == 5) # haven't moved
+  var str = newString(100)
+  doAssert(ss.peekLine(str))
+  doAssert(str == "uick brown fox jumped over the lazy dog.")
+  doAssert(ss.getPosition == 5) # haven't moved
+  # bug #19707 - Ensure we dont error with writing over literals on arc/orc
+  ss.setPosition(0)
+  ss.write("hello")
+  ss.setPosition(0)
+  doAssert(ss.peekStr(5) == "hello")
+
+# bug #19716
+static: # Ensure streams it doesnt break with nimscript on arc/orc #19716
+  let s = newStringStream("a")
+  doAssert s.data == "a"
+
+static: # issue #24054, readStr
+  var s = newStringStream("foo bar baz")
+  doAssert s.readStr(3) == "foo"
+
+template main =
+  var strm = newStringStream("abcde")
+  var buffer = "12345"
+  doAssert strm.readDataStr(buffer, 0..3) == 4
+  doAssert buffer == "abcd5"
+  strm.close()
+
+static: main()
+main()
diff --git a/tests/stdlib/tstreams2.nim b/tests/stdlib/tstreams2.nim
deleted file mode 100644
index 90102d8e3..000000000
--- a/tests/stdlib/tstreams2.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-discard """
-  file: "tstreams2.nim"
-  output: '''fs is: nil'''
-"""
-import streams
-var
-  fs = newFileStream("amissingfile.txt")
-  line = ""
-echo "fs is: ",repr(fs)
-if not isNil(fs):
-  while fs.readLine(line):
-    echo line
-  fs.close()
diff --git a/tests/stdlib/tstreams3.nim b/tests/stdlib/tstreams3.nim
deleted file mode 100644
index b2c9170e3..000000000
--- a/tests/stdlib/tstreams3.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-discard """
-  file: "tstreams3.nim"
-  output: "threw exception"
-"""
-import streams
-
-try:
-  var fs = openFileStream("shouldneverexist.txt")
-except IoError:
-  echo "threw exception"
diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim
index db76899d4..ff406f898 100644
--- a/tests/stdlib/tstrformat.nim
+++ b/tests/stdlib/tstrformat.nim
@@ -1,56 +1,590 @@
 discard """
-    action: "run"
+  matrix: "--mm:refc; --mm:orc"
 """
 
-import strformat
-
-type Obj = object
-
-proc `$`(o: Obj): string = "foobar"
-
-var o: Obj
-doAssert fmt"{o}" == "foobar"
-doAssert fmt"{o:10}" == "foobar    "
-
-# see issue #7933
-var str = "abc"
-doAssert fmt">7.1 :: {str:>7.1}" == ">7.1 ::       a"
-doAssert fmt">7.2 :: {str:>7.2}" == ">7.2 ::      ab"
-doAssert fmt">7.3 :: {str:>7.3}" == ">7.3 ::     abc"
-doAssert fmt">7.9 :: {str:>7.9}" == ">7.9 ::     abc"
-doAssert fmt">7.0 :: {str:>7.0}" == ">7.0 ::        "
-doAssert fmt" 7.1 :: {str:7.1}" == " 7.1 :: a      "
-doAssert fmt" 7.2 :: {str:7.2}" == " 7.2 :: ab     "
-doAssert fmt" 7.3 :: {str:7.3}" == " 7.3 :: abc    "
-doAssert fmt" 7.9 :: {str:7.9}" == " 7.9 :: abc    "
-doAssert fmt" 7.0 :: {str:7.0}" == " 7.0 ::        "
-doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 ::    a   "
-doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 ::   ab   "
-doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 ::   abc  "
-doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 ::   abc  "
-doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 ::        "
-str = "äöüe\u0309\u0319o\u0307\u0359"
-doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 ::    ä   "
-doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 ::   äö   "
-doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 ::   äöü  "
-doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 ::        "
-# this is actually wrong, but the unicode module has no support for graphemes
-doAssert fmt"^7.4 :: {str:^7.4}" == "^7.4 ::  äöüe  "
-doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: äöüe\u0309\u0319o\u0307\u0359"
-
-# see issue #7932
-doAssert fmt"{15:08}" == "00000015" # int, works
-doAssert fmt"{1.5:08}" == "000001.5" # float, works
-doAssert fmt"{1.5:0>8}" == "000001.5" # workaround using fill char works for positive floats
-doAssert fmt"{-1.5:0>8}" == "0000-1.5" # even that does not work for negative floats  
-doAssert fmt"{-1.5:08}" == "-00001.5" # works
-doAssert fmt"{1.5:+08}" == "+00001.5" # works
-doAssert fmt"{1.5: 08}" == " 00001.5" # works
-
-# only add explicitly requested sign if value != -0.0 (neg zero)
-doAssert fmt"{-0.0:g}" == "-0"
-doassert fmt"{-0.0:+g}" == "-0"
-doassert fmt"{-0.0: g}" == "-0"
-doAssert fmt"{0.0:g}" == "0"
-doAssert fmt"{0.0:+g}" == "+0"
-doAssert fmt"{0.0: g}" == " 0"
+import genericstrformat
+import std/[strformat, strutils, times, tables, json]
+
+import std/[assertions, formatfloat]
+import std/objectdollar
+
+proc main() =
+  block: # issue #7632
+    doAssert works(5) == "formatted  5"
+    doAssert fails0(6) == "formatted  6"
+    doAssert fails(7) == "formatted  7"
+    doAssert fails2[0](8) == "formatted  8"
+
+  block: # other tests
+    type Obj = object
+
+    proc `$`(o: Obj): string = "foobar"
+
+    # for custom types, formatValue needs to be overloaded.
+    template formatValue(result: var string; value: Obj; specifier: string) =
+      result.formatValue($value, specifier)
+
+    var o: Obj
+    doAssert fmt"{o}" == "foobar"
+    doAssert fmt"{o:10}" == "foobar    "
+
+    doAssert fmt"{o=}" == "o=foobar"
+    doAssert fmt"{o=:10}" == "o=foobar    "
+
+  block: # see issue #7933
+    var str = "abc"
+    doAssert fmt">7.1 :: {str:>7.1}" == ">7.1 ::       a"
+    doAssert fmt">7.2 :: {str:>7.2}" == ">7.2 ::      ab"
+    doAssert fmt">7.3 :: {str:>7.3}" == ">7.3 ::     abc"
+    doAssert fmt">7.9 :: {str:>7.9}" == ">7.9 ::     abc"
+    doAssert fmt">7.0 :: {str:>7.0}" == ">7.0 ::        "
+    doAssert fmt" 7.1 :: {str:7.1}" == " 7.1 :: a      "
+    doAssert fmt" 7.2 :: {str:7.2}" == " 7.2 :: ab     "
+    doAssert fmt" 7.3 :: {str:7.3}" == " 7.3 :: abc    "
+    doAssert fmt" 7.9 :: {str:7.9}" == " 7.9 :: abc    "
+    doAssert fmt" 7.0 :: {str:7.0}" == " 7.0 ::        "
+    doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 ::    a   "
+    doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 ::   ab   "
+    doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 ::   abc  "
+    doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 ::   abc  "
+    doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 ::        "
+
+    doAssert fmt">7.1 :: {str=:>7.1}" == ">7.1 :: str=      a"
+    doAssert fmt">7.2 :: {str=:>7.2}" == ">7.2 :: str=     ab"
+    doAssert fmt">7.3 :: {str=:>7.3}" == ">7.3 :: str=    abc"
+    doAssert fmt">7.9 :: {str=:>7.9}" == ">7.9 :: str=    abc"
+    doAssert fmt">7.0 :: {str=:>7.0}" == ">7.0 :: str=       "
+    doAssert fmt" 7.1 :: {str=:7.1}" == " 7.1 :: str=a      "
+    doAssert fmt" 7.2 :: {str=:7.2}" == " 7.2 :: str=ab     "
+    doAssert fmt" 7.3 :: {str=:7.3}" == " 7.3 :: str=abc    "
+    doAssert fmt" 7.9 :: {str=:7.9}" == " 7.9 :: str=abc    "
+    doAssert fmt" 7.0 :: {str=:7.0}" == " 7.0 :: str=       "
+    doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str=   a   "
+    doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str=  ab   "
+    doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str=  abc  "
+    doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str=  abc  "
+    doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str=       "
+    str = "äöüe\u0309\u0319o\u0307\u0359"
+    doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 ::    ä   "
+    doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 ::   äö   "
+    doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 ::   äöü  "
+    doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 ::        "
+
+    doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str=   ä   "
+    doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str=  äö   "
+    doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str=  äöü  "
+    doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str=       "
+    # this is actually wrong, but the unicode module has no support for graphemes
+    doAssert fmt"^7.4 :: {str:^7.4}" == "^7.4 ::  äöüe  "
+    doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: äöüe\u0309\u0319o\u0307\u0359"
+
+    doAssert fmt"^7.4 :: {str=:^7.4}" == "^7.4 :: str= äöüe  "
+    doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str=äöüe\u0309\u0319o\u0307\u0359"
+
+  block: # see issue #7932
+    doAssert fmt"{15:08}" == "00000015" # int, works
+    doAssert fmt"{1.5:08}" == "000001.5" # float, works
+    doAssert fmt"{1.5:0>8}" == "000001.5" # workaround using fill char works for positive floats
+    doAssert fmt"{-1.5:0>8}" == "0000-1.5" # even that does not work for negative floats
+    doAssert fmt"{-1.5:08}" == "-00001.5" # works
+    doAssert fmt"{1.5:+08}" == "+00001.5" # works
+    doAssert fmt"{1.5: 08}" == " 00001.5" # works
+
+    doAssert fmt"{15=:08}" == "15=00000015" # int, works
+    doAssert fmt"{1.5=:08}" == "1.5=000001.5" # float, works
+    doAssert fmt"{1.5=:0>8}" == "1.5=000001.5" # workaround using fill char works for positive floats
+    doAssert fmt"{-1.5=:0>8}" == "-1.5=0000-1.5" # even that does not work for negative floats
+    doAssert fmt"{-1.5=:08}" == "-1.5=-00001.5" # works
+    doAssert fmt"{1.5=:+08}" == "1.5=+00001.5" # works
+    doAssert fmt"{1.5=: 08}" == "1.5= 00001.5" # works
+
+  block: # only add explicitly requested sign if value != -0.0 (neg zero)
+    doAssert fmt"{-0.0:g}" == "-0"
+    doAssert fmt"{-0.0:+g}" == "-0"
+    doAssert fmt"{-0.0: g}" == "-0"
+    doAssert fmt"{0.0:g}" == "0"
+    doAssert fmt"{0.0:+g}" == "+0"
+    doAssert fmt"{0.0: g}" == " 0"
+
+    doAssert fmt"{-0.0=:g}" == "-0.0=-0"
+    doAssert fmt"{-0.0=:+g}" == "-0.0=-0"
+    doAssert fmt"{-0.0=: g}" == "-0.0=-0"
+    doAssert fmt"{0.0=:g}" == "0.0=0"
+    doAssert fmt"{0.0=:+g}" == "0.0=+0"
+    doAssert fmt"{0.0=: g}" == "0.0= 0"
+
+  block: # seq format
+    let data1 = [1'i64, 10000'i64, 10000000'i64]
+    let data2 = [10000000'i64, 100'i64, 1'i64]
+
+    proc formatValue(result: var string; value: (array|seq|openArray); specifier: string) =
+      result.add "["
+      for i, it in value:
+        if i != 0:
+          result.add ", "
+        result.formatValue(it, specifier)
+      result.add "]"
+
+    doAssert fmt"data1: {data1:8} #" == "data1: [       1,    10000, 10000000] #"
+    doAssert fmt"data2: {data2:8} =" == "data2: [10000000,      100,        1] ="
+
+    doAssert fmt"data1: {data1=:8} #" == "data1: data1=[       1,    10000, 10000000] #"
+    doAssert fmt"data2: {data2=:8} =" == "data2: data2=[10000000,      100,        1] ="
+
+  block: # custom format Value
+    type
+      Vec2[T] = object
+        x,y: T
+
+    proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) =
+      result.add '['
+      result.formatValue value.x, specifier
+      result.add ", "
+      result.formatValue value.y, specifier
+      result.add "]"
+
+    let v1 = Vec2[float32](x:1.0, y: 2.0)
+    let v2 = Vec2[int32](x:1, y: 1337)
+    doAssert fmt"v1: {v1:+08}  v2: {v2:>4}" == "v1: [+0000001, +0000002]  v2: [   1, 1337]"
+    doAssert fmt"v1: {v1=:+08}  v2: {v2=:>4}" == "v1: v1=[+0000001, +0000002]  v2: v2=[   1, 1337]"
+
+  block: # bug #11012
+    type
+      Animal = object
+        name, species: string
+      AnimalRef = ref Animal
+
+    proc print_object(animalAddr: AnimalRef): string =
+      fmt"Received {animalAddr[]}"
+
+    doAssert print_object(AnimalRef(name: "Foo", species: "Bar")) == """Received (name: "Foo", species: "Bar")"""
+
+  block: # bug #11723
+    let pos: Positive = 64
+    doAssert fmt"{pos:3}" == " 64"
+    doAssert fmt"{pos:3b}" == "1000000"
+    doAssert fmt"{pos:3d}" == " 64"
+    doAssert fmt"{pos:3o}" == "100"
+    doAssert fmt"{pos:3x}" == " 40"
+    doAssert fmt"{pos:3X}" == " 40"
+
+    doAssert fmt"{pos=:3}" == "pos= 64"
+    doAssert fmt"{pos=:3b}" == "pos=1000000"
+    doAssert fmt"{pos=:3d}" == "pos= 64"
+    doAssert fmt"{pos=:3o}" == "pos=100"
+    doAssert fmt"{pos=:3x}" == "pos= 40"
+    doAssert fmt"{pos=:3X}" == "pos= 40"
+
+    let nat: Natural = 64
+    doAssert fmt"{nat:3}" == " 64"
+    doAssert fmt"{nat:3b}" == "1000000"
+    doAssert fmt"{nat:3d}" == " 64"
+    doAssert fmt"{nat:3o}" == "100"
+    doAssert fmt"{nat:3x}" == " 40"
+    doAssert fmt"{nat:3X}" == " 40"
+
+    doAssert fmt"{nat=:3}" == "nat= 64"
+    doAssert fmt"{nat=:3b}" == "nat=1000000"
+    doAssert fmt"{nat=:3d}" == "nat= 64"
+    doAssert fmt"{nat=:3o}" == "nat=100"
+    doAssert fmt"{nat=:3x}" == "nat= 40"
+    doAssert fmt"{nat=:3X}" == "nat= 40"
+
+  block: # bug #12612
+    proc my_proc() =
+      const value = "value"
+      const a = &"{value}"
+      doAssert a == value
+
+      const b = &"{value=}"
+      doAssert b == "value=" & value
+
+    my_proc()
+
+  block:
+    template fmt(pattern: string; openCloseChar: char): untyped =
+      fmt(pattern, openCloseChar, openCloseChar)
+
+    let
+      testInt = 123
+      testStr = "foobar"
+      testFlt = 3.141592
+    doAssert ">><<".fmt('<', '>') == "><"
+    doAssert " >> << ".fmt('<', '>') == " > < "
+    doAssert "<<>>".fmt('<', '>') == "<>"
+    doAssert " << >> ".fmt('<', '>') == " < > "
+    doAssert "''".fmt('\'') == "'"
+    doAssert "''''".fmt('\'') == "''"
+    doAssert "'' ''".fmt('\'') == "' '"
+    doAssert "<testInt>".fmt('<', '>') == "123"
+    doAssert "<testInt>".fmt('<', '>') == "123"
+    doAssert "'testFlt:1.2f'".fmt('\'') == "3.14"
+    doAssert "<testInt><testStr>".fmt('<', '>') == "123foobar"
+    doAssert """ ""{"123+123"}"" """.fmt('"') == " \"{246}\" "
+    doAssert "(((testFlt:1.2f)))((111))".fmt('(', ')') == "(3.14)(111)"
+    doAssert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)"
+    doAssert "{}abc`testStr' `testFlt:1.2f' `1+1' ``".fmt('`', '\'') == "{}abcfoobar 3.14 2 `"
+    doAssert """x = '"foo" & "bar"'
+                y = '123 + 111'
+                z = '3 in {2..7}'
+             """.fmt('\'') ==
+             """x = foobar
+                y = 234
+                z = true
+             """
+
+  block: # tests from the very own strformat documentation!
+    let msg = "hello"
+    doAssert fmt"{msg}\n" == "hello\\n"
+
+    doAssert &"{msg}\n" == "hello\n"
+
+    doAssert fmt"{msg}{'\n'}" == "hello\n"
+    doAssert fmt("{msg}\n") == "hello\n"
+    doAssert "{msg}\n".fmt == "hello\n"
+
+    doAssert fmt"{msg=}\n" == "msg=hello\\n"
+
+    doAssert &"{msg=}\n" == "msg=hello\n"
+
+    doAssert fmt"{msg=}{'\n'}" == "msg=hello\n"
+    doAssert fmt("{msg=}\n") == "msg=hello\n"
+    doAssert "{msg=}\n".fmt == "msg=hello\n"
+
+    doAssert &"""{"abc":>4}""" == " abc"
+    doAssert &"""{"abc":<4}""" == "abc "
+
+    doAssert fmt"{-12345:08}" == "-0012345"
+    doAssert fmt"{-1:3}" == " -1"
+    doAssert fmt"{-1:03}" == "-01"
+    doAssert fmt"{16:#X}" == "0x10"
+
+    doAssert fmt"{123.456}" == "123.456"
+    doAssert fmt"{123.456:>9.3f}" == "  123.456"
+    doAssert fmt"{123.456:9.3f}" == "  123.456"
+    doAssert fmt"{123.456:9.4f}" == " 123.4560"
+    doAssert fmt"{123.456:>9.0f}" == "     123."
+    doAssert fmt"{123.456:<9.4f}" == "123.4560 "
+
+    doAssert fmt"{123.456:e}" == "1.234560e+02"
+    doAssert fmt"{123.456:>13e}" == " 1.234560e+02"
+    doAssert fmt"{123.456:13e}" == " 1.234560e+02"
+
+    doAssert &"""{"abc"=:>4}""" == "\"abc\"= abc"
+    doAssert &"""{"abc"=:<4}""" == "\"abc\"=abc "
+
+    doAssert fmt"{-12345=:08}" == "-12345=-0012345"
+    doAssert fmt"{-1=:3}" == "-1= -1"
+    doAssert fmt"{-1=:03}" == "-1=-01"
+    doAssert fmt"{16=:#X}" == "16=0x10"
+
+    doAssert fmt"{123.456=}" == "123.456=123.456"
+    doAssert fmt"{123.456=:>9.3f}" == "123.456=  123.456"
+    doAssert fmt"{123.456=:9.3f}" == "123.456=  123.456"
+    doAssert fmt"{123.456=:9.4f}" == "123.456= 123.4560"
+    doAssert fmt"{123.456=:>9.0f}" == "123.456=     123."
+    doAssert fmt"{123.456=:<9.4f}" == "123.456=123.4560 "
+
+    doAssert fmt"{123.456=:e}" == "123.456=1.234560e+02"
+    doAssert fmt"{123.456=:>13e}" == "123.456= 1.234560e+02"
+    doAssert fmt"{123.456=:13e}" == "123.456= 1.234560e+02"
+
+    let x = 3.14
+    doAssert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847"
+    doAssert fmt"""{(block:
+      var res: string
+      for i in 1..15:
+        res.add (if i mod 15 == 0: "FizzBuzz"
+          elif i mod 5 == 0: "Buzz"
+          elif i mod 3 == 0: "Fizz"
+          else: $i) & " "
+      res)}""" == "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz "
+
+    doAssert fmt"""{ "\{(" & msg & ")\}" }""" == "{(hello)}"
+    doAssert fmt"""{{({ msg })}}""" == "{(hello)}"
+    doAssert fmt"""{ $(\{msg:1,"world":2\}) }""" == """[("hello", 1), ("world", 2)]"""
+  block: # tests for debug format string
+    var name = "hello"
+    let age = 21
+    const hobby = "swim"
+    doAssert fmt"{age*9 + 16=}" == "age*9 + 16=205"
+    doAssert &"name: {name    =}\nage: {  age  =: >7}\nhobby: {   hobby=  : 8}" ==
+          "name: name    =hello\nage:   age  =     21\nhobby:    hobby=  swim    "
+    doAssert fmt"{age  ==  12}" == "false"
+    doAssert fmt"{name.toUpperAscii() = }" == "name.toUpperAscii() = HELLO"
+    doAssert fmt"{name.toUpperAscii( ) =  }" == "name.toUpperAscii( ) =  HELLO"
+    doAssert fmt"{  toUpperAscii(  s  =  name  )  =   }" == "  toUpperAscii(  s  =  name  )  =   HELLO"
+    doAssert fmt"{  strutils.toUpperAscii(  s  =  name  )  =   }" == "  strutils.toUpperAscii(  s  =  name  )  =   HELLO"
+    doAssert fmt"{age==12}" == "false"
+    doAssert fmt"{age!= 12}" == "true"
+    doAssert fmt"{age  <=  12}" == "false"
+    for i in 1 .. 10:
+      doAssert fmt"{age.float =: .2f}" == "age.float = 21.00"
+    doAssert fmt"{age.float() =:.3f}" == "age.float() =21.000"
+    doAssert fmt"{float age=  :.3f}" == "float age=  21.000"
+    doAssert fmt"{12 == int(`!=`(age, 12))}" == "false"
+    doAssert fmt"{0==1}" == "false"
+
+  block: # It is space sensitive.
+    let x = "12"
+    doAssert fmt"{x=:}" == "x=12"
+    doAssert fmt"{x=}" == "x=12"
+    doAssert fmt"{x =:}" == "x =12"
+    doAssert fmt"{x =}" == "x =12"
+    doAssert fmt"{x= :}" == "x= 12"
+    doAssert fmt"{x= }" == "x= 12"
+    doAssert fmt"{x = :}" == "x = 12"
+    doAssert fmt"{x = }" == "x = 12"
+    doAssert fmt"{x   =  :}" == "x   =  12"
+    doAssert fmt"{x   =  }" == "x   =  12"
+
+  block:
+    let x = "hello"
+    doAssert fmt"{x=}" == "x=hello"
+    doAssert fmt"{x =}" == "x =hello"
+
+    let y = 3.1415926
+    doAssert fmt"{y=:.2f}" == fmt"y={y:.2f}"
+    doAssert fmt"{y=}" == fmt"y={y}"
+    doAssert fmt"{y = : <8}" == fmt"y = 3.14159 "
+
+    proc hello(a: string, b: float): int = 12
+    template foo(a: string, b: float): int = 18
+
+    doAssert fmt"{hello(x, y)=}" == "hello(x, y)=12"
+    doAssert fmt"{hello(x, y) =}" == "hello(x, y) =12"
+    doAssert fmt"{hello(x, y)= }" == "hello(x, y)= 12"
+    doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12"
+
+    doAssert fmt"{hello x, y=}" == "hello x, y=12"
+    doAssert fmt"{hello x, y =}" == "hello x, y =12"
+    doAssert fmt"{hello x, y= }" == "hello x, y= 12"
+    doAssert fmt"{hello x, y = }" == "hello x, y = 12"
+
+    doAssert fmt"{x.hello(y)=}" == "x.hello(y)=12"
+    doAssert fmt"{x.hello(y) =}" == "x.hello(y) =12"
+    doAssert fmt"{x.hello(y)= }" == "x.hello(y)= 12"
+    doAssert fmt"{x.hello(y) = }" == "x.hello(y) = 12"
+
+    doAssert fmt"{foo(x, y)=}" == "foo(x, y)=18"
+    doAssert fmt"{foo(x, y) =}" == "foo(x, y) =18"
+    doAssert fmt"{foo(x, y)= }" == "foo(x, y)= 18"
+    doAssert fmt"{foo(x, y) = }" == "foo(x, y) = 18"
+
+    doAssert fmt"{x.foo(y)=}" == "x.foo(y)=18"
+    doAssert fmt"{x.foo(y) =}" == "x.foo(y) =18"
+    doAssert fmt"{x.foo(y)= }" == "x.foo(y)= 18"
+    doAssert fmt"{x.foo(y) = }" == "x.foo(y) = 18"
+
+  block:
+    template check(actual, expected: string) =
+      doAssert actual == expected
+
+    # Basic tests
+    let s = "string"
+    check &"{0} {s}", "0 string"
+    check &"{s[0..2].toUpperAscii}", "STR"
+    check &"{-10:04}", "-010"
+    check &"{-10:<04}", "-010"
+    check &"{-10:>04}", "-010"
+    check &"0x{10:02X}", "0x0A"
+
+    check &"{10:#04X}", "0x0A"
+
+    check &"""{"test":#>5}""", "#test"
+    check &"""{"test":>5}""", " test"
+
+    check &"""{"test":#^7}""", "#test##"
+
+    check &"""{"test": <5}""", "test "
+    check &"""{"test":<5}""", "test "
+    check &"{1f:.3f}", "1.000"
+    check &"Hello, {s}!", "Hello, string!"
+
+    # Tests for identifiers without parenthesis
+    check &"{s} works{s}", "string worksstring"
+    check &"{s:>7}", " string"
+    doAssert(not compiles(&"{s_works}")) # parsed as identifier `s_works`
+
+    # Misc general tests
+    check &"{{}}", "{}"
+    check &"{0}%", "0%"
+    check &"{0}%asdf", "0%asdf"
+    check &("\n{\"\\n\"}\n"), "\n\n\n"
+    check &"""{"abc"}s""", "abcs"
+
+    # String tests
+    check &"""{"abc"}""", "abc"
+    check &"""{"abc":>4}""", " abc"
+    check &"""{"abc":<4}""", "abc "
+    check &"""{"":>4}""", "    "
+    check &"""{"":<4}""", "    "
+
+    # Int tests
+    check &"{12345}", "12345"
+    check &"{ - 12345}", "-12345"
+    check &"{12345:6}", " 12345"
+    check &"{12345:>6}", " 12345"
+    check &"{12345:4}", "12345"
+    check &"{12345:08}", "00012345"
+    check &"{-12345:08}", "-0012345"
+    check &"{0:0}", "0"
+    check &"{0:02}", "00"
+    check &"{-1:3}", " -1"
+    check &"{-1:03}", "-01"
+    check &"{10}", "10"
+    check &"{16:#X}", "0x10"
+    check &"{16:^#7X}", " 0x10  "
+    check &"{16:^+#7X}", " +0x10 "
+
+    # Hex tests
+    check &"{0:x}", "0"
+    check &"{-0:x}", "0"
+    check &"{255:x}", "ff"
+    check &"{255:X}", "FF"
+    check &"{-255:x}", "-ff"
+    check &"{-255:X}", "-FF"
+    check &"{255:x} uNaffeCteD CaSe", "ff uNaffeCteD CaSe"
+    check &"{255:X} uNaffeCteD CaSe", "FF uNaffeCteD CaSe"
+    check &"{255:4x}", "  ff"
+    check &"{255:04x}", "00ff"
+    check &"{-255:4x}", " -ff"
+    check &"{-255:04x}", "-0ff"
+
+    # Float tests
+    check &"{123.456}", "123.456"
+    check &"{-123.456}", "-123.456"
+    check &"{123.456:.3f}", "123.456"
+    check &"{123.456:+.3f}", "+123.456"
+    check &"{-123.456:+.3f}", "-123.456"
+    check &"{-123.456:.3f}", "-123.456"
+    check &"{123.456:1g}", "123.456"
+    check &"{123.456:.1f}", "123.5"
+    check &"{123.456:.0f}", "123."
+    check &"{123.456:>9.3f}", "  123.456"
+    check &"{123.456:9.3f}", "  123.456"
+    check &"{123.456:>9.4f}", " 123.4560"
+    check &"{123.456:>9.0f}", "     123."
+    check &"{123.456:<9.4f}", "123.4560 "
+
+    # Float (scientific) tests
+    check &"{123.456:e}", "1.234560e+02"
+    check &"{123.456:>13e}", " 1.234560e+02"
+    check &"{123.456:<13e}", "1.234560e+02 "
+    check &"{123.456:.1e}", "1.2e+02"
+    check &"{123.456:.2e}", "1.23e+02"
+    check &"{123.456:.3e}", "1.235e+02"
+
+    # Note: times.format adheres to the format protocol. Test that this
+    # works:
+    when nimvm:
+      discard
+    else:
+      var dt = dateTime(2000, mJan, 01, 00, 00, 00)
+      check &"{dt:yyyy-MM-dd}", "2000-01-01"
+
+      var tm = fromUnix(0)
+      discard &"{tm}"
+
+      var noww = now()
+      check &"{noww}", $noww
+
+    # Unicode string tests
+    check &"""{"αβγ"}""", "αβγ"
+    check &"""{"αβγ":>5}""", "  αβγ"
+    check &"""{"αβγ":<5}""", "αβγ  "
+    check &"""a{"a"}α{"α"}€{"€"}𐍈{"𐍈"}""", "aaαα€€𐍈𐍈"
+    check &"""a{"a":2}α{"α":2}€{"€":2}𐍈{"𐍈":2}""", "aa αα €€ 𐍈𐍈 "
+    # Invalid unicode sequences should be handled as plain strings.
+    # Invalid examples taken from: https://stackoverflow.com/a/3886015/1804173
+    let invalidUtf8 = [
+      "\xc3\x28", "\xa0\xa1",
+      "\xe2\x28\xa1", "\xe2\x82\x28",
+      "\xf0\x28\x8c\xbc", "\xf0\x90\x28\xbc", "\xf0\x28\x8c\x28"
+    ]
+    for s in invalidUtf8:
+      check &"{s:>5}", repeat(" ", 5-s.len) & s
+
+    # bug #11089
+    let flfoo: float = 1.0
+    check &"{flfoo}", "1.0"
+
+    # bug #11092
+    check &"{high(int64)}", "9223372036854775807"
+    check &"{low(int64)}", "-9223372036854775808"
+
+    doAssert fmt"{'a'} {'b'}" == "a b"
+
+  block: # test low(int64)
+    doAssert &"{low(int64):-}" == "-9223372036854775808"
+  block: #expressions plus formatting
+    doAssert fmt"{if true\: 123.456 else\: 0=:>9.3f}" == "if true: 123.456 else: 0=  123.456"
+    doAssert fmt"{(if true: 123.456 else: 0)=}" == "(if true: 123.456 else: 0)=123.456"
+    doAssert fmt"{if true\: 123.456 else\: 0=:9.3f}" == "if true: 123.456 else: 0=  123.456"
+    doAssert fmt"{(if true: 123.456 else: 0)=:9.4f}" == "(if true: 123.456 else: 0)= 123.4560"
+    doAssert fmt"{(if true: 123.456 else: 0)=:>9.0f}" == "(if true: 123.456 else: 0)=     123."
+    doAssert fmt"{if true\: 123.456 else\: 0=:<9.4f}" == "if true: 123.456 else: 0=123.4560 "
+
+    doAssert fmt"""{(case true
+      of false: 0.0
+      of true: 123.456)=:e}""" == """(case true
+      of false: 0.0
+      of true: 123.456)=1.234560e+02"""
+
+    doAssert fmt"""{block\:
+      var res = 0.000123456
+      for _ in 0..5\:
+        res *= 10
+      res=:>13e}""" == """block:
+      var res = 0.000123456
+      for _ in 0..5:
+        res *= 10
+      res= 1.234560e+02"""
+    #side effects
+    var x = 5
+    doAssert fmt"{(x=7;123.456)=:13e}" == "(x=7;123.456)= 1.234560e+02"
+    doAssert x==7
+  block: #curly bracket expressions and tuples
+    proc formatValue(result: var string; value:Table|bool|JsonNode; specifier:string) = result.add $value
+
+    doAssert fmt"""{\{"a"\:1,"b"\:2\}.toTable() = }""" == """{"a":1,"b":2}.toTable() = {"a": 1, "b": 2}"""
+    doAssert fmt"""{(\{3: (1,"hi",0.9),4: (4,"lo",1.1)\}).toTable()}""" == """{3: (1, "hi", 0.9), 4: (4, "lo", 1.1)}"""
+    doAssert fmt"""{ (%* \{"name": "Isaac", "books": ["Robot Dreams"]\}) }""" == """{"name":"Isaac","books":["Robot Dreams"]}"""
+    doAssert """%( \%\* {"name": "Isaac"})*""".fmt('%','*') == """{"name":"Isaac"}"""
+  block: #parens in quotes that fool my syntax highlighter
+    doAssert fmt"{(if true: ')' else: '(')}" == ")"
+    doAssert fmt"{(if true: ']' else: ')')}" == "]"
+    doAssert fmt"""{(if true: "\")\"" else: "\"(")}""" == """")""""
+    doAssert &"""{(if true: "\")" else: "")}""" == "\")"
+    doAssert &"{(if true: \"\\\")\" else: \"\")}" == "\")"
+    doAssert fmt"""{(if true: "')" else: "")}""" == "')"
+    doAssert fmt"""{(if true: "'" & "'" & ')' else: "")}""" == "'')"
+    doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')"
+    doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')"
+    doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')"
+
+  block: # issue #20381
+    var ss: seq[string]
+    template myTemplate(s: string) =
+      ss.add s
+      ss.add s
+    proc foo() =
+      myTemplate fmt"hello"
+    foo()
+    doAssert ss == @["hello", "hello"]
+
+  block:
+    proc noraises() {.raises: [].} =
+      const
+        flt = 0.0
+        str = "str"
+
+      doAssert fmt"{flt} {str}" == "0.0 str"
+
+    noraises()
+
+  block:
+    doAssert not compiles(fmt"{formatting errors detected at compile time")
+
+static: main()
+main()
diff --git a/tests/stdlib/tstrformatlineinfo.nim b/tests/stdlib/tstrformatlineinfo.nim
new file mode 100644
index 000000000..3a7bf0d33
--- /dev/null
+++ b/tests/stdlib/tstrformatlineinfo.nim
@@ -0,0 +1,8 @@
+# issue #21759
+
+{.hint[ConvFromXToItselfNotNeeded]: on.}
+
+import std/strformat
+
+echo fmt"{string ""abc""}" #[tt.Hint
+        ^ conversion from string to itself is pointless]#
diff --git a/tests/stdlib/tstrimpl.nim b/tests/stdlib/tstrimpl.nim
new file mode 100644
index 000000000..a8933e53f
--- /dev/null
+++ b/tests/stdlib/tstrimpl.nim
@@ -0,0 +1,12 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/strimpl
+
+import std/assertions
+
+doAssert find(cstring"Hello Nim", cstring"Nim") == 6
+doAssert find(cstring"Hello Nim", cstring"N") == 6
+doAssert find(cstring"Hello Nim", cstring"I") == -1
+doAssert find(cstring"Hello Nim", cstring"O") == -1
diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim
index 660746150..b9b3c78a3 100644
--- a/tests/stdlib/tstring.nim
+++ b/tests/stdlib/tstring.nim
@@ -1,79 +1,124 @@
 discard """
-  file: "tstring.nim"
-  output: "OK"
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
 """
-const characters = "abcdefghijklmnopqrstuvwxyz"
-const numbers = "1234567890"
-
-var s: string
-
-proc test_string_slice() =
-  # test "slice of length == len(characters)":
-  # replace characters completely by numbers
-  s = characters
-  s[0..^1] = numbers
-  doAssert s == numbers
-
-  # test "slice of length > len(numbers)":
-  # replace characters by slice of same length
-  s = characters
-  s[1..16] = numbers
-  doAssert s == "a1234567890rstuvwxyz"
-
-  # test "slice of length == len(numbers)":
-  # replace characters by slice of same length
-  s = characters
-  s[1..10] = numbers
-  doAssert s == "a1234567890lmnopqrstuvwxyz"
-
-  # test "slice of length < len(numbers)":
-  # replace slice of length. and insert remaining chars
-  s = characters
-  s[1..4] = numbers
-  doAssert s == "a1234567890fghijklmnopqrstuvwxyz"
-
-  # test "slice of length == 1":
-  # replace first character. and insert remaining 9 chars
-  s = characters
-  s[1..1] = numbers
-  doAssert s == "a1234567890cdefghijklmnopqrstuvwxyz"
-
-  # test "slice of length == 0":
-  # insert chars at slice start index
-  s = characters
-  s[2..1] = numbers
-  doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
-
-  # test "slice of negative length":
-  # same as slice of zero length
-  s = characters
-  s[2..0] = numbers
-  doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
-
-  # bug #6223
-  doAssertRaises(IndexError):
-    discard s[0..999]
-
-  echo("OK")
-
-proc test_string_cmp() =
-  let world = "hello\0world"
-  let earth = "hello\0earth"
-  let short = "hello\0"
-  let hello = "hello"
-  let goodbye = "goodbye"
-
-  doAssert world == world
-  doAssert world != earth
-  doAssert world != short
-  doAssert world != hello
-  doAssert world != goodbye
-
-  doAssert cmp(world, world) == 0
-  doAssert cmp(world, earth) > 0
-  doAssert cmp(world, short) > 0
-  doAssert cmp(world, hello) > 0
-  doAssert cmp(world, goodbye) > 0
-
-test_string_slice()
-test_string_cmp()
+
+from std/sequtils import toSeq, map
+from std/sugar import `=>`
+import std/assertions
+
+proc tester[T](x: T) =
+  let test = toSeq(0..4).map(i => newSeq[int]())
+  doAssert $test == "@[@[], @[], @[], @[], @[]]"
+
+func reverse*(a: string): string =
+  result = a
+  for i in 0 ..< a.len div 2:
+    swap(result[i], result[^(i + 1)])
+
+proc main() =
+  block: # ..
+    const
+      characters = "abcdefghijklmnopqrstuvwxyz"
+      numbers = "1234567890"
+
+    # test "slice of length == len(characters)":
+    # replace characters completely by numbers
+    var s: string
+    s = characters
+    s[0..^1] = numbers
+    doAssert s == numbers
+
+    # test "slice of length > len(numbers)":
+    # replace characters by slice of same length
+    s = characters
+    s[1..16] = numbers
+    doAssert s == "a1234567890rstuvwxyz"
+
+    # test "slice of length == len(numbers)":
+    # replace characters by slice of same length
+    s = characters
+    s[1..10] = numbers
+    doAssert s == "a1234567890lmnopqrstuvwxyz"
+
+    # test "slice of length < len(numbers)":
+    # replace slice of length. and insert remaining chars
+    s = characters
+    s[1..4] = numbers
+    doAssert s == "a1234567890fghijklmnopqrstuvwxyz"
+
+    # test "slice of length == 1":
+    # replace first character. and insert remaining 9 chars
+    s = characters
+    s[1..1] = numbers
+    doAssert s == "a1234567890cdefghijklmnopqrstuvwxyz"
+
+    # test "slice of length == 0":
+    # insert chars at slice start index
+    s = characters
+    s[2..1] = numbers
+    doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
+
+    # test "slice of negative length":
+    # same as slice of zero length
+    s = characters
+    s[2..0] = numbers
+    doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
+
+    when nimvm:
+      discard
+    else:
+      # bug #6223
+      doAssertRaises(IndexDefect):
+        discard s[0..999]
+
+  block: # ==, cmp
+    let world = "hello\0world"
+    let earth = "hello\0earth"
+    let short = "hello\0"
+    let hello = "hello"
+    let goodbye = "goodbye"
+
+    doAssert world == world
+    doAssert world != earth
+    doAssert world != short
+    doAssert world != hello
+    doAssert world != goodbye
+
+    doAssert cmp(world, world) == 0
+    doAssert cmp(world, earth) > 0
+    doAssert cmp(world, short) > 0
+    doAssert cmp(world, hello) > 0
+    doAssert cmp(world, goodbye) > 0
+
+  block: # bug #7816
+    tester(1)
+
+  block: # bug #14497, reverse
+    doAssert reverse("hello") == "olleh"
+
+  block: # len, high
+    var a = "ab\0cd"
+    var b = a.cstring
+    doAssert a.len == 5
+    block: # bug #16405
+      when defined(js):
+        when nimvm: doAssert b.len == 2
+        else: doAssert b.len == 5
+      else: doAssert b.len == 2
+
+    doAssert a.high == a.len - 1
+    doAssert b.high == b.len - 1
+
+    doAssert "".len == 0
+    doAssert "".high == -1
+    doAssert "".cstring.len == 0
+    doAssert "".cstring.high == -1
+
+    block: # bug #16674
+      var c: cstring = nil
+      doAssert c.len == 0
+      doAssert c.high == -1
+
+static: main()
+main()
diff --git a/tests/stdlib/tstrmiscs.nim b/tests/stdlib/tstrmiscs.nim
new file mode 100644
index 000000000..b42f2e1fe
--- /dev/null
+++ b/tests/stdlib/tstrmiscs.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/strmisc
+import std/assertions
+
+
+doAssert expandTabs("\t", 4) == "    "
+doAssert expandTabs("\tfoo\t", 4) == "    foo "
+doAssert expandTabs("\tfoo\tbar", 4) == "    foo bar"
+doAssert expandTabs("\tfoo\tbar\t", 4) == "    foo bar "
+doAssert expandTabs("", 4) == ""
+doAssert expandTabs("", 0) == ""
+doAssert expandTabs("\t\t\t", 0) == ""
+
+doAssert partition("foo:bar", ":") == ("foo", ":", "bar")
+doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar")
+doAssert partition("foobarbar", "bank") == ("foobarbar", "", "")
+doAssert partition("foobarbar", "foo") == ("", "foo", "barbar")
+doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "")
+
+doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar")
+doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "")
+doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar")
+doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar")
+doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "")
diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim
new file mode 100644
index 000000000..ae7fd98ca
--- /dev/null
+++ b/tests/stdlib/tstrscans.nim
@@ -0,0 +1,288 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[strscans, strutils, assertions]
+
+block ParsePasswd:
+  proc parsePasswd(content: string): seq[string] =
+    result = @[]
+    var idx = 0
+    while true:
+      var entry = ""
+      if scanp(content, idx, +(~{'\L', '\0'} -> entry.add($_)), '\L'):
+        result.add entry
+      else:
+        break
+
+  const etcPasswd = """root:x:0:0:root:/root:/bin/bash
+daemon:x:1:1:daemon:/usr/sbin:/bin/sh
+bin:x:2:2:bin:/bin:/bin/sh
+sys:x:3:3:sys:/dev:/bin/sh
+nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
+messagebus:x:103:107::/var/run/dbus:/bin/false
+"""
+
+  const parsedEtcPasswd = @[
+    "root:x:0:0:root:/root:/bin/bash",
+    "daemon:x:1:1:daemon:/usr/sbin:/bin/sh",
+    "bin:x:2:2:bin:/bin:/bin/sh",
+    "sys:x:3:3:sys:/dev:/bin/sh",
+    "nobody:x:65534:65534:nobody:/nonexistent:/bin/sh",
+    "messagebus:x:103:107::/var/run/dbus:/bin/false",
+    ]
+  doAssert etcPasswd.parsePasswd == parsedEtcPasswd
+
+block LastNot:
+  var idx : int
+
+  idx = 0
+  doAssert scanp("foo", idx,  'f', 'o', ~'a')
+
+  idx = 0
+  doAssert scanp("foo", idx,  'f', 'o', ~'o') == false
+
+  idx = 0
+  doAssert scanp("foox", idx,  'f', 'o', ~'o') == false
+
+  idx = 0
+  doAssert scanp("foox", idx,  'f', 'o', ~'a')
+
+block LastOptional:
+  var idx = 0
+  doAssert scanp("foo", idx, 'f', 'o', 'o', ?'o')
+
+block Tuple:
+  var idx = 0
+  doAssert scanp("foo", idx,  ('f', 'o', 'o'))
+
+block NotWithOptional:
+  var idx : int
+
+  idx = 0
+  doAssert scanp("bc", idx, ~(?'b', 'c')) == false
+
+  idx = 0
+  doAssert scanp("c", idx, ~(?'b', 'c')) == false
+
+  idx = 0
+  doAssert scanp("b", idx, ~(?'b', 'c'))
+
+block NotEmpty:
+  var idx = 0
+  doAssert scanp("", idx, ~()) == false
+
+block EmptyTuple:
+  var idx = 0
+  doAssert scanp("ab", idx, 'a', (), 'b')
+
+block Arrow:
+  let text = "foo;bar;baz;"
+  var idx = 0
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') == false
+
+
+block issue15064:
+  var nick1, msg1: string
+  doAssert scanf("<abcd> a", "<$+> $+", nick1, msg1)
+  doAssert nick1 == "abcd"
+  doAssert msg1 == "a"
+
+  var nick2, msg2: string
+  doAssert(not scanf("<abcd> ", "<$+> $+", nick2, msg2))
+
+  var nick3, msg3: string
+  doAssert scanf("<abcd> ", "<$+> $*", nick3, msg3)
+  doAssert nick3 == "abcd"
+  doAssert msg3 == ""
+
+
+block:
+  proc twoDigits(input: string; x: var int; start: int): int =
+    if start+1 < input.len and input[start] == '0' and input[start+1] == '0':
+      result = 2
+      x = 13
+    else:
+      result = 0
+
+  proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int =
+    result = 0
+    while start+result < input.len and input[start+result] in seps: inc result
+
+  proc demangle(s: string; res: var string; start: int): int =
+    while result+start < s.len and s[result+start] in {'_', '@'}: inc result
+    res = ""
+    while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_':
+      res.add s[result+start]
+      inc result
+    while result+start < s.len and s[result+start] > ' ':
+      inc result
+
+  proc parseGDB(resp: string): seq[string] =
+    const
+      digits = {'0'..'9'}
+      hexdigits = digits + {'a'..'f', 'A'..'F'}
+      whites = {' ', '\t', '\C', '\L'}
+    result = @[]
+    var idx = 0
+    while true:
+      var prc = ""
+      var info = ""
+      if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "),
+               demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')',
+                *`whites`, "at ", +(~{'\C', '\L'} -> info.add($_))):
+        result.add prc & " " & info
+      else:
+        break
+
+  var key, val: string
+  var intVal: int
+  var floatVal: float
+  doAssert scanf("abc:: xyz 89  33.25", "$w$s::$s$w$s$i  $f", key, val, intVal, floatVal)
+  doAssert key == "abc"
+  doAssert val == "xyz"
+  doAssert intVal == 89
+  doAssert floatVal == 33.25
+
+  var binVal: int
+  var octVal: int
+  var hexVal: int
+  doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal)
+  doAssert binVal == 0b0101
+  doAssert octVal == 0o1234
+  doAssert hexVal == 0xabcd
+
+  let xx = scanf("$abc", "$$$i", intVal)
+  doAssert xx == false
+
+
+  let xx2 = scanf("$1234", "$$$i", intVal)
+  doAssert xx2
+
+  let yy = scanf(";.--Breakpoint00 [output]",
+      "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.",
+      intVal, key)
+  doAssert yy
+  doAssert key == "output"
+  doAssert intVal == 13
+
+  var ident = ""
+  var idx = 0
+  let zz = scanp("foobar x x  x   xWZ", idx, +{'a'..'z'} -> add(ident, $_), *(*{
+      ' ', '\t'}, "x"), ~'U', "Z")
+  doAssert zz
+  doAssert ident == "foobar"
+
+  const digits = {'0'..'9'}
+  var year = 0
+  var idx2 = 0
+  if scanp("201655-8-9", idx2, `digits`{4, 6} -> (year = year * 10 + ord($_) -
+      ord('0')), "-8", "-9"):
+    doAssert year == 201655
+
+  const gdbOut = """
+      #0  @foo_96013_1208911747@8 (x0=...)
+          at c:/users/anwender/projects/nim/temp.nim:11
+      #1  0x00417754 in tempInit000 () at c:/users/anwender/projects/nim/temp.nim:13
+      #2  0x0041768d in NimMainInner ()
+          at c:/users/anwender/projects/nim/lib/system.nim:2605
+      #3  0x004176b1 in NimMain ()
+          at c:/users/anwender/projects/nim/lib/system.nim:2613
+      #4  0x004176db in main (argc=1, args=0x712cc8, env=0x711ca8)
+          at c:/users/anwender/projects/nim/lib/system.nim:2620"""
+  const result = @["foo c:/users/anwender/projects/nim/temp.nim:11",
+          "tempInit000 c:/users/anwender/projects/nim/temp.nim:13",
+          "NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605",
+          "NimMain c:/users/anwender/projects/nim/lib/system.nim:2613",
+          "main c:/users/anwender/projects/nim/lib/system.nim:2620"]
+  doAssert parseGDB(gdbOut) == result
+
+  # bug #6487
+  var count = 0
+
+  proc test(): string =
+    inc count
+    result = ",123123"
+
+  var a: int
+  discard scanf(test(), ",$i", a)
+  doAssert count == 1
+
+
+block:
+  let input = """1-3 s: abc
+15-18 9: def
+15-18 A: ghi
+15-18 _: jkl
+"""
+  var
+    lo, hi: int
+    w: string
+    c: char
+    res: int
+  for line in input.splitLines:
+    if line.scanf("$i-$i $c: $w", lo, hi, c, w):
+      inc res
+  doAssert res == 4
+
+block:
+  #whenscanf testing
+  let input = """1-3 s: abc
+15-18 9: def
+15-18 A: ghi
+15-18 _: jkl
+"""
+  proc twoDigits(input: string; x: var int; start: int): int =
+    if start+1 < input.len and input[start] == '0' and input[start+1] == '0':
+      result = 2
+      x = 13
+    else:
+      result = 0
+
+  proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int =
+    result = 0
+    while start+result < input.len and input[start+result] in seps: inc result
+
+  type
+    ScanRetType = tuple
+      success: bool
+      lo: int
+      hi: int
+      ch: char
+      word: string
+
+  var res = 0
+  for line in input.splitLines:
+    let ret: ScanRetType = scanTuple(line, "$i-$i $c: $w")
+    if ret.success:
+      inc res
+  doAssert res == 4
+
+  let (_, key, val, intVal, floatVal) = scanTuple("abc:: xyz 89  33.25", "$w$s::$s$w$s$i  $f")
+  doAssert key == "abc"
+  doAssert val == "xyz"
+  doAssert intVal == 89
+  doAssert floatVal == 33.25
+
+
+  let (_, binVal, octVal, hexVal) = scanTuple("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal)
+  doAssert binVal == 0b0101
+  doAssert octVal == 0o1234
+  doAssert hexVal == 0xabcd
+
+  var (xx,_) = scanTuple("$abc", "$$$i")
+  doAssert xx == false
+
+
+  let (xx2, _) = block: scanTuple("$1234", "$$$i")
+  doAssert xx2
+
+  var (yy, intVal2, key2) = scanTuple(";.--Breakpoint00 [output]",
+      "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.",
+      int)
+  doAssert yy
+  doAssert key2 == "output"
+  doAssert intVal2 == 13
diff --git a/tests/stdlib/tstrset.nim b/tests/stdlib/tstrset.nim
index 1b253f862..bbb6c2677 100644
--- a/tests/stdlib/tstrset.nim
+++ b/tests/stdlib/tstrset.nim
@@ -1,12 +1,16 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
 # test a simple yet highly efficient set of strings
 
 type
   TRadixNodeKind = enum rnLinear, rnFull, rnLeaf
   PRadixNode = ref TRadixNode
-  TRadixNode = object {.inheritable.}
+  TRadixNode {.inheritable.} = object
     kind: TRadixNodeKind
   TRadixNodeLinear = object of TRadixNode
-    len: int8
+    len: uint8
     keys: array[0..31, char]
     vals: array[0..31, PRadixNode]
   TRadixNodeFull = object of TRadixNode
@@ -24,7 +28,7 @@ proc search(r: PRadixNode, s: string): PRadixNode =
     case r.kind
     of rnLinear:
       var x = PRadixNodeLinear(r)
-      for j in 0..ze(x.len)-1:
+      for j in 0..int(x.len)-1:
         if x.keys[j] == s[i]:
           if s[i] == '\0': return r
           r = x.vals[j]
@@ -50,7 +54,7 @@ proc search(r: PRadixNode, s: string): PRadixNode =
 proc contains*(r: PRadixNode, s: string): bool =
   return search(r, s) != nil
 
-proc testOrincl*(r: var PRadixNode, s: string): bool =
+proc testOrIncl*(r: var PRadixNode, s: string): bool =
   nil
 
 proc incl*(r: var PRadixNode, s: string) = discard testOrIncl(r, s)
@@ -63,9 +67,9 @@ proc excl*(r: var PRadixNode, s: string) =
   of rnFull: PRadixNodeFull(x).b['\0'] = nil
   of rnLinear:
     var x = PRadixNodeLinear(x)
-    for i in 0..ze(x.len)-1:
+    for i in 0..int(x.len)-1:
       if x.keys[i] == '\0':
-        swap(x.keys[i], x.keys[ze(x.len)-1])
+        swap(x.keys[i], x.keys[int(x.len)-1])
         dec(x.len)
         break
 
diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim
index a248cc3b2..d261abe76 100644
--- a/tests/stdlib/tstrtabs.nim
+++ b/tests/stdlib/tstrtabs.nim
@@ -1,4 +1,95 @@
-import strtabs
+discard """
+matrix: "--mm:refc; --mm:orc"
+sortoutput: true
+output: '''
+key1: value1
+key2: value2
+key_0: value0
+key_10: value10
+key_11: value11
+key_12: value12
+key_13: value13
+key_14: value14
+key_15: value15
+key_16: value16
+key_17: value17
+key_18: value18
+key_19: value19
+key_20: value20
+key_21: value21
+key_22: value22
+key_23: value23
+key_24: value24
+key_25: value25
+key_26: value26
+key_27: value27
+key_28: value28
+key_29: value29
+key_30: value30
+key_31: value31
+key_32: value32
+key_33: value33
+key_34: value34
+key_35: value35
+key_36: value36
+key_37: value37
+key_38: value38
+key_39: value39
+key_3: value3
+key_40: value40
+key_41: value41
+key_42: value42
+key_43: value43
+key_44: value44
+key_45: value45
+key_46: value46
+key_47: value47
+key_48: value48
+key_49: value49
+key_4: value4
+key_50: value50
+key_51: value51
+key_52: value52
+key_53: value53
+key_54: value54
+key_55: value55
+key_56: value56
+key_57: value57
+key_58: value58
+key_59: value59
+key_5: value5
+key_60: value60
+key_61: value61
+key_62: value62
+key_63: value63
+key_64: value64
+key_65: value65
+key_66: value66
+key_67: value67
+key_68: value68
+key_69: value69
+key_6: value6
+key_70: value70
+key_71: value71
+key_72: value72
+key_73: value73
+key_74: value74
+key_75: value75
+key_76: value76
+key_77: value77
+key_78: value78
+key_79: value79
+key_7: value7
+key_80: value80
+key_8: value8
+key_9: value9
+length of table 0
+length of table 81
+value1 = value2
+'''
+"""
+
+import std/[strtabs, assertions, syncio]
 
 var tab = newStringTable({"key1": "val1", "key2": "val2"},
                          modeStyleInsensitive)
@@ -9,4 +100,18 @@ for key, val in pairs(tab):
   writeLine(stdout, key, ": ", val)
 writeLine(stdout, "length of table ", $tab.len)
 
-writeLine(stdout, `%`("$key1 = $key2; ${PATH}", tab, {useEnvironment}))
+writeLine(stdout, `%`("$key1 = $key2", tab, {useEnvironment}))
+tab.clear
+writeLine(stdout, "length of table ", $tab.len)
+
+block:
+  var x = {"k": "v", "11": "22", "565": "67"}.newStringTable
+  doAssert x["k"] == "v"
+  doAssert x["11"] == "22"
+  doAssert x["565"] == "67"
+  x["11"] = "23"
+  doAssert x["11"] == "23"
+
+  x.clear(modeCaseInsensitive)
+  x["11"] = "22"
+  doAssert x["11"] == "22"
diff --git a/tests/stdlib/tstrtabs.nims b/tests/stdlib/tstrtabs.nims
new file mode 100644
index 000000000..3563ad0ad
--- /dev/null
+++ b/tests/stdlib/tstrtabs.nims
@@ -0,0 +1,5 @@
+import std/[strtabs, assertions]
+
+static:
+  let t = {"name": "John", "city": "Monaco"}.newStringTable
+  doAssert "${name} lives in ${city}" % t == "John lives in Monaco"
diff --git a/tests/stdlib/tstrtabs2.nim b/tests/stdlib/tstrtabs2.nim
new file mode 100644
index 000000000..a4030ec77
--- /dev/null
+++ b/tests/stdlib/tstrtabs2.nim
@@ -0,0 +1,32 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/strtabs
+import std/assertions
+
+macro m =
+  var t = {"name": "John"}.newStringTable
+  doAssert t["name"] == "John"
+
+block:
+  var t = {"name": "John"}.newStringTable
+  doAssert t["name"] == "John"
+
+m()
+
+proc fun()=
+  let ret = newStringTable(modeCaseSensitive)
+  ret["foo"] = "bar"
+
+  doAssert $ret == "{foo: bar}"
+
+  let b = ret["foo"]
+  doAssert b == "bar"
+
+proc main()=
+  static: fun()
+  fun()
+
+main()
diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim
deleted file mode 100644
index 4d4081d39..000000000
--- a/tests/stdlib/tstrutil.nim
+++ /dev/null
@@ -1,306 +0,0 @@
-discard """
-  file: "tstrutil.nim"
-  output: "ha/home/a1xyz/usr/bin"
-"""
-# test the new strutils module
-
-import
-  strutils
-
-import macros
-
-template rejectParse(e) =
-  try:
-    discard e
-    raise newException(AssertionError, "This was supposed to fail: $#!" % astToStr(e))
-  except ValueError: discard
-
-proc testStrip() =
-  write(stdout, strip("  ha  "))
-
-proc testRemoveSuffix =
-  var s = "hello\n\r"
-  s.removeSuffix
-  assert s == "hello"
-  s.removeSuffix
-  assert s == "hello"
-
-  s = "hello\n\n"
-  s.removeSuffix
-  assert s == "hello"
-
-  s = "hello\r"
-  s.removeSuffix
-  assert s == "hello"
-
-  s = "hello \n there"
-  s.removeSuffix
-  assert s == "hello \n there"
-
-  s = "hello"
-  s.removeSuffix("llo")
-  assert s == "he"
-  s.removeSuffix('e')
-  assert s == "h"
-
-  s = "hellos"
-  s.removeSuffix({'s','z'})
-  assert s == "hello"
-  s.removeSuffix({'l','o'})
-  assert s == "he"
-
-  s = "aeiou"
-  s.removeSuffix("")
-  assert s == "aeiou"
-
-  s = ""
-  s.removeSuffix("")
-  assert s == ""
-
-  s = "  "
-  s.removeSuffix
-  assert s == "  "
-
-  s = "  "
-  s.removeSuffix("")
-  assert s == "  "
-
-  s = "    "
-  s.removeSuffix(" ")
-  assert s == "   "
-
-  s = "    "
-  s.removeSuffix(' ')
-  assert s == ""
-
-  # Contrary to Chomp in other languages
-  # empty string does not change behaviour
-  s = "hello\r\n\r\n"
-  s.removeSuffix("")
-  assert s == "hello\r\n\r\n"
-
-proc testRemovePrefix =
-  var s = "\n\rhello"
-  s.removePrefix
-  assert s == "hello"
-  s.removePrefix
-  assert s == "hello"
-
-  s = "\n\nhello"
-  s.removePrefix
-  assert s == "hello"
-
-  s = "\rhello"
-  s.removePrefix
-  assert s == "hello"
-
-  s = "hello \n there"
-  s.removePrefix
-  assert s == "hello \n there"
-
-  s = "hello"
-  s.removePrefix("hel")
-  assert s == "lo"
-  s.removePrefix('l')
-  assert s == "o"
-
-  s = "hellos"
-  s.removePrefix({'h','e'})
-  assert s == "llos"
-  s.removePrefix({'l','o'})
-  assert s == "s"
-
-  s = "aeiou"
-  s.removePrefix("")
-  assert s == "aeiou"
-
-  s = ""
-  s.removePrefix("")
-  assert s == ""
-
-  s = "  "
-  s.removePrefix
-  assert s == "  "
-
-  s = "  "
-  s.removePrefix("")
-  assert s == "  "
-
-  s = "    "
-  s.removePrefix(" ")
-  assert s == "   "
-
-  s = "    "
-  s.removePrefix(' ')
-  assert s == ""
-
-  # Contrary to Chomp in other languages
-  # empty string does not change behaviour
-  s = "\r\n\r\nhello"
-  s.removePrefix("")
-  assert s == "\r\n\r\nhello"
-
-proc main() =
-  testStrip()
-  testRemoveSuffix()
-  testRemovePrefix()
-  for p in split("/home/a1:xyz:/usr/bin", {':'}):
-    write(stdout, p)
-
-proc testDelete =
-  var s = "0123456789ABCDEFGH"
-  delete(s, 4, 5)
-  assert s == "01236789ABCDEFGH"
-  delete(s, s.len-1, s.len-1)
-  assert s == "01236789ABCDEFG"
-  delete(s, 0, 0)
-  assert s == "1236789ABCDEFG"
-
-proc testIsAlphaNumeric =
-  assert isAlphaNumeric("abcdABC1234") == true
-  assert isAlphaNumeric("a") == true
-  assert isAlphaNumeric("abcABC?1234") == false
-  assert isAlphaNumeric("abcABC 1234") == false
-  assert isAlphaNumeric(".") == false
-
-testIsAlphaNumeric()
-
-proc testIsDigit =
-  assert isDigit("1") == true
-  assert isDigit("1234") == true
-  assert isDigit("abcABC?1234") == false
-  assert isDigit(".") == false
-  assert isDigit(":") == false
-
-testIsDigit()
-
-proc testFind =
-  assert "0123456789ABCDEFGH".find('A') == 10
-  assert "0123456789ABCDEFGH".find('A', 5) == 10
-  assert "0123456789ABCDEFGH".find('A', 5, 10) == 10
-  assert "0123456789ABCDEFGH".find('A', 5, 9) == -1
-  assert "0123456789ABCDEFGH".find("A") == 10
-  assert "0123456789ABCDEFGH".find("A", 5) == 10
-  assert "0123456789ABCDEFGH".find("A", 5, 10) == 10
-  assert "0123456789ABCDEFGH".find("A", 5, 9) == -1
-  assert "0123456789ABCDEFGH".find({'A'..'C'}) == 10
-  assert "0123456789ABCDEFGH".find({'A'..'C'}, 5) == 10
-  assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 10) == 10
-  assert "0123456789ABCDEFGH".find({'A'..'C'}, 5, 9) == -1
-
-proc testRFind =
-  assert "0123456789ABCDEFGAH".rfind('A') == 17
-  assert "0123456789ABCDEFGAH".rfind('A', 13) == 10
-  assert "0123456789ABCDEFGAH".rfind('H', 13) == -1
-  assert "0123456789ABCDEFGAH".rfind("A") == 17
-  assert "0123456789ABCDEFGAH".rfind("A", 13) == 10
-  assert "0123456789ABCDEFGAH".rfind("H", 13) == -1
-  assert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17
-  assert "0123456789ABCDEFGAH".rfind({'A'..'C'}, 13) == 12
-  assert "0123456789ABCDEFGAH".rfind({'G'..'H'}, 13) == -1
-
-proc testCountLines =
-  proc assertCountLines(s: string) = assert s.countLines == s.splitLines.len
-  assertCountLines("")
-  assertCountLines("\n")
-  assertCountLines("\n\n")
-  assertCountLines("abc")
-  assertCountLines("abc\n123")
-  assertCountLines("abc\n123\n")
-  assertCountLines("\nabc\n123")
-  assertCountLines("\nabc\n123\n")
-
-proc testParseInts =
-  # binary
-  assert "0b1111".parseBinInt == 15
-  assert "0B1111".parseBinInt == 15
-  assert "1111".parseBinInt == 15
-  assert "1110".parseBinInt == 14
-  assert "1_1_1_1".parseBinInt == 15
-  assert "0b1_1_1_1".parseBinInt == 15
-  rejectParse "".parseBinInt
-  rejectParse "_".parseBinInt
-  rejectParse "0b".parseBinInt
-  rejectParse "0b1234".parseBinInt
-  # hex
-  assert "0x72".parseHexInt == 114
-  assert "0X72".parseHexInt == 114
-  assert "#72".parseHexInt == 114
-  assert "72".parseHexInt == 114
-  assert "FF".parseHexInt == 255
-  assert "ff".parseHexInt == 255
-  assert "fF".parseHexInt == 255  
-  assert "0x7_2".parseHexInt == 114
-  rejectParse "".parseHexInt
-  rejectParse "_".parseHexInt
-  rejectParse "0x".parseHexInt
-  rejectParse "0xFFG".parseHexInt
-  rejectParse "reject".parseHexInt
-  # octal
-  assert "0o17".parseOctInt == 15
-  assert "0O17".parseOctInt == 15
-  assert "17".parseOctInt == 15
-  assert "10".parseOctInt == 8
-  assert "0o1_0_0".parseOctInt == 64
-  rejectParse "".parseOctInt
-  rejectParse "_".parseOctInt
-  rejectParse "0o".parseOctInt
-  rejectParse "9".parseOctInt
-  rejectParse "0o9".parseOctInt
-  rejectParse "reject".parseOctInt
-
-testDelete()
-testFind()
-testRFind()
-testCountLines()
-testParseInts()
-
-assert(insertSep($1000_000) == "1_000_000")
-assert(insertSep($232) == "232")
-assert(insertSep($12345, ',') == "12,345")
-assert(insertSep($0) == "0")
-
-assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0)
-assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1)
-assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5)
-assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3)
-assert(editDistance("prefix__hallo_suffix", "prefix") == 14)
-assert(editDistance("prefix__hallo_suffix", "suffix") == 14)
-assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2)
-assert(editDistance("main", "malign") == 2)
-
-assert "/1/2/3".rfind('/') == 4
-assert "/1/2/3".rfind('/', 1) == 0
-assert "/1/2/3".rfind('0') == -1
-
-assert(toHex(100i16, 32) == "00000000000000000000000000000064")
-assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
-
-assert "".parseHexStr == ""
-assert "00Ff80".parseHexStr == "\0\xFF\x80"
-try:
-  discard "00Ff8".parseHexStr
-  assert false, "Should raise ValueError"
-except ValueError:
-  discard
-
-try:
-  discard "0k".parseHexStr
-  assert false, "Should raise ValueError"
-except ValueError:
-  discard
-
-assert "".toHex == ""
-assert "\x00\xFF\x80".toHex == "00FF80"
-assert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF"
-
-assert(' '.repeat(8)== "        ")
-assert(" ".repeat(8) == "        ")
-assert(spaces(8) == "        ")
-
-assert(' '.repeat(0) == "")
-assert(" ".repeat(0) == "")
-assert(spaces(0) == "")
-
-main()
-#OUT ha/home/a1xyz/usr/bin
diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim
new file mode 100644
index 000000000..35f6bc669
--- /dev/null
+++ b/tests/stdlib/tstrutils.nim
@@ -0,0 +1,913 @@
+discard """
+  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
+"""
+
+import std/strutils
+from stdtest/testutils import disableVm
+import std/assertions
+import std/private/jsutils
+# xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed
+
+template rejectParse(e) =
+  try:
+    discard e
+    raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e))
+  except ValueError: discard
+
+template main() =
+  block: # strip
+    doAssert strip("  ha  ") == "ha"
+    doAssert strip("  foofoofoo  ") == "foofoofoo"
+    doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
+    doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
+    doAssert strip("stripme but don't strip this stripme",
+                   chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
+                   " but don't strip this "
+    doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
+    doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
+
+    block:
+      let a = "xxxxxx"
+      doAssert a.strip(chars={'x'}).len == 0
+
+    doAssert "".strip(chars={'x'}).len == 0
+    doAssert "         ".strip(chars={'x'}) == "         "
+    doAssert "xxx xxx".strip(chars={'x'}) == " "
+    doAssert "xxx  wind".strip(chars={'x'}) == "  wind"
+    doAssert "xxx  iii".strip(chars={'i'}) == "xxx  "
+    doAssert "x".strip(leading = false, chars={'x'}).len == 0
+    doAssert "x".strip(trailing = false, chars={'x'}).len == 0
+    doAssert "x".strip(leading = false, trailing = false, chars={'x'}) == "x"
+
+  block: # split
+    var ret: seq[string] # or use `toSeq` or `collect`
+    for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p
+    doAssert ret == @["/home/a1", "xyz", "/usr/bin"]
+
+    let s = " this is an example  "
+    let s2 = ":this;is;an:example;;"
+
+    doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
+    doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example",
+        "", ""]
+    doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example  "]
+    doAssert s.split(' ', maxsplit = 1) == @["", "this is an example  "]
+    doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example  "]
+    # Empty string:
+    doAssert "".split() == @[""]
+    doAssert "".split(" ") == @[""]
+    doAssert "".split({' '}) == @[""]
+    # Empty separators:
+    doAssert "".split({}) == @[""]
+    doAssert "".split("") == @[""]
+    doAssert s.split({}) == @[s]
+    doAssert s.split("") == @[s]
+
+  block: # splitLines
+    let fixture = "a\nb\rc\r\nd"
+    doAssert len(fixture.splitLines) == 4
+    doAssert splitLines(fixture) == @["a", "b", "c", "d"]
+    doAssert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"]
+
+  block: # rsplit
+    doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"]
+    doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"]
+    doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[" foo bar", ""]
+    doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"]
+    doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"]
+    doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"]
+    doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"]
+    # Empty string:
+    doAssert "".rsplit() == @[""]
+    doAssert "".rsplit(" ") == @[""]
+    doAssert "".rsplit({' '}) == @[""]
+    # Empty separators:
+    let s = " this is an example  "
+    doAssert "".rsplit({}) == @[""]
+    doAssert "".rsplit("") == @[""]
+    doAssert s.rsplit({}) == @[s]
+    doAssert s.rsplit("") == @[s]
+
+  block: # splitWhitespace
+    let s = " this is an example  "
+    doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
+    doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example  "]
+    doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example  "]
+    doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example  "]
+    doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"]
+
+  block: # removeSuffix
+    var s = "hello\n\r"
+    s.removeSuffix
+    doAssert s == "hello"
+    s.removeSuffix
+    doAssert s == "hello"
+
+    s = "hello\n\n"
+    s.removeSuffix
+    doAssert s == "hello"
+
+    s = "hello\r"
+    s.removeSuffix
+    doAssert s == "hello"
+
+    s = "hello \n there"
+    s.removeSuffix
+    doAssert s == "hello \n there"
+
+    s = "hello"
+    s.removeSuffix("llo")
+    doAssert s == "he"
+    s.removeSuffix('e')
+    doAssert s == "h"
+
+    s = "hellos"
+    s.removeSuffix({'s','z'})
+    doAssert s == "hello"
+    s.removeSuffix({'l','o'})
+    doAssert s == "he"
+
+    s = "aeiou"
+    s.removeSuffix("")
+    doAssert s == "aeiou"
+
+    s = ""
+    s.removeSuffix("")
+    doAssert s == ""
+
+    s = "  "
+    s.removeSuffix
+    doAssert s == "  "
+
+    s = "  "
+    s.removeSuffix("")
+    doAssert s == "  "
+
+    s = "    "
+    s.removeSuffix(" ")
+    doAssert s == "   "
+
+    s = "    "
+    s.removeSuffix(' ')
+    doAssert s == ""
+
+    # Contrary to Chomp in other languages
+    # empty string does not change behaviour
+    s = "hello\r\n\r\n"
+    s.removeSuffix("")
+    doAssert s == "hello\r\n\r\n"
+
+  block: # removePrefix
+    var s = "\n\rhello"
+    s.removePrefix
+    doAssert s == "hello"
+    s.removePrefix
+    doAssert s == "hello"
+
+    s = "\n\nhello"
+    s.removePrefix
+    doAssert s == "hello"
+
+    s = "\rhello"
+    s.removePrefix
+    doAssert s == "hello"
+
+    s = "hello \n there"
+    s.removePrefix
+    doAssert s == "hello \n there"
+
+    s = "hello"
+    s.removePrefix("hel")
+    doAssert s == "lo"
+    s.removePrefix('l')
+    doAssert s == "o"
+
+    s = "hellos"
+    s.removePrefix({'h','e'})
+    doAssert s == "llos"
+    s.removePrefix({'l','o'})
+    doAssert s == "s"
+
+    s = "aeiou"
+    s.removePrefix("")
+    doAssert s == "aeiou"
+
+    s = ""
+    s.removePrefix("")
+    doAssert s == ""
+
+    s = "  "
+    s.removePrefix
+    doAssert s == "  "
+
+    s = "  "
+    s.removePrefix("")
+    doAssert s == "  "
+
+    s = "    "
+    s.removePrefix(" ")
+    doAssert s == "   "
+
+    s = "    "
+    s.removePrefix(' ')
+    doAssert s == ""
+
+    # Contrary to Chomp in other languages
+    # empty string does not change behaviour
+    s = "\r\n\r\nhello"
+    s.removePrefix("")
+    doAssert s == "\r\n\r\nhello"
+
+  block: # delete(slice)
+    var s = "0123456789ABCDEFGH"
+    delete(s, 4 .. 5)
+    doAssert s == "01236789ABCDEFGH"
+    delete(s, s.len-1 .. s.len-1)
+    doAssert s == "01236789ABCDEFG"
+    delete(s, 0..0)
+    doAssert s == "1236789ABCDEFG"
+    s = ""
+    doAssertRaises(IndexDefect): delete(s, 0..0)
+    doAssert s == ""
+    s = "abc"
+    doAssertRaises(IndexDefect): delete(s, -1 .. -2)
+    doAssertRaises(IndexDefect): delete(s, 2..3)
+    doAssertRaises(IndexDefect): delete(s, 3..2)
+    delete(s, 2..2)
+    doAssert s == "ab"
+    delete(s, 1..0)
+    doAssert s == "ab"
+    delete(s, 0..0)
+    doAssert s == "b"
+
+  block: # delete(first, last)
+    {.push warning[deprecated]:off.}
+    var s = "0123456789ABCDEFGH"
+    delete(s, 4, 5)
+    doAssert s == "01236789ABCDEFGH"
+    delete(s, s.len-1, s.len-1)
+    doAssert s == "01236789ABCDEFG"
+    delete(s, 0, 0)
+    doAssert s == "1236789ABCDEFG"
+    {.pop.}
+
+  block: # find
+    const haystack: string = "0123456789ABCDEFGH"
+    doAssert haystack.find('A') == 10
+    doAssert haystack.find('A', 5) == 10
+    doAssert haystack.find('A', 5, 10) == 10
+    doAssert haystack.find('A', 5, 9) == -1
+    doAssert haystack.find("A") == 10
+    doAssert haystack.find("A", 5) == 10
+    doAssert haystack.find("A", 5, 10) == 10
+    doAssert haystack.find("A", 5, 9) == -1
+    doAssert haystack.find({'A'..'C'}) == 10
+    doAssert haystack.find({'A'..'C'}, 5) == 10
+    doAssert haystack.find({'A'..'C'}, 5, 10) == 10
+    doAssert haystack.find({'A'..'C'}, 5, 9) == -1
+    doAssert haystack.find('A', 0, 0) == -1 # search limited to the first char
+    doAssert haystack.find('A', 5, 0) == -1 # last < start
+    doAssert haystack.find('A', 5, 4) == -1 # last < start
+
+    block:
+      const haystack: string = "ABCABABABABCAB"
+      doAssert haystack.len == 14
+
+      # only last argument
+      doAssert haystack.find("ABC") == 0
+      doAssert haystack.find("ABC", last=13) == 0 # after the second ABC
+      doAssert haystack.find("ABC", last=5) == 0 # before the second ABC
+
+      # only start argument
+      doAssert haystack.find("ABC", start=0) == 0
+      doAssert haystack.find("ABC", start=1) == 9
+      doAssert haystack.find("ABC", start=9) == 9
+      doAssert haystack.find("ABC", start=10) == -1
+
+      # both start and last arguments
+      doAssert haystack.find("ABC", start=0, last=14) == 0
+      doAssert haystack.find("ABC", start=0, last=13) == 0
+      doAssert haystack.find("ABC", start=0, last=12) == 0
+      doAssert haystack.find("ABC", start=1, last=13) == 9
+      doAssert haystack.find("ABC", start=1, last=12) == 9
+      doAssert haystack.find("ABC", start=1, last=11) == 9
+      doAssert haystack.find("ABC", start=1, last=10) == -1
+
+    doAssert "".find("/") == -1
+    doAssert "/".find("/") == 0
+    doAssert "/".find("//") == -1
+    doAssert "///".find("//", start=3) == -1
+
+    # searching for empty string
+    doAssert "".find("") == 0
+    doAssert "abc".find("") == 0
+    doAssert "abc".find("", start=1) == 1
+    doAssert "abc".find("", start=2) == 2
+    doAssert "abc".find("", start=3) == 3
+    doAssert "abc".find("", start=4) == -1
+    doAssert "abc".find("", start=400) == -1
+    doAssert "abc".find("", start=1, last=3) == 1
+    doAssert "abc".find("", start=1, last=2) == 1
+    doAssert "abc".find("", start=1, last=1) == 1
+    doAssert "abc".find("", start=1, last=0) == 1
+    doAssert "abc".find("", start=1, last = -1) == 1
+
+    # when last <= start, searching for non-empty string
+    block:
+      let last: int = -1 # searching through whole line
+      doAssert "abcd".find("ab", start=0, last=last) == 0
+      doAssert "abcd".find("ab", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=1, last=last) == 1
+      doAssert "abcd".find("bc", start=2, last=last) == -1
+    block:
+      let last: int = 0
+      doAssert "abcd".find("ab", start=0, last=last) == -1
+      doAssert "abcd".find("ab", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=2, last=last) == -1
+    block:
+      let last: int = 1
+      doAssert "abcd".find("ab", start=0, last=last) == 0
+      doAssert "abcd".find("ab", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=2, last=last) == -1
+
+  block: # rfind
+    doAssert "0123456789ABCDEFGAH".rfind('A') == 17
+    doAssert "0123456789ABCDEFGAH".rfind('A', last=13) == 10
+    doAssert "0123456789ABCDEFGAH".rfind('H', last=13) == -1
+    doAssert "0123456789ABCDEFGAH".rfind("A") == 17
+    doAssert "0123456789ABCDEFGAH".rfind("A", last=13) == 10
+    doAssert "0123456789ABCDEFGAH".rfind("H", last=13) == -1
+    doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17
+    doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12
+    doAssert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1
+    doAssert "0123456789ABCDEFGAH".rfind('A', start=18) == -1
+    doAssert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17
+    doAssert "0123456789ABCDEFGAH".rfind("0", start=0) == 0
+    doAssert "0123456789ABCDEFGAH".rfind("0", start=1) == -1
+    doAssert "0123456789ABCDEFGAH".rfind("H", start=11) == 18
+    doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9
+    doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1
+
+    doAssert "/1/2/3".rfind('/') == 4
+    doAssert "/1/2/3".rfind('/', last=1) == 0
+    doAssert "/1/2/3".rfind('0') == -1
+
+    block:
+      const haystack: string = "ABCABABABABCAB"
+      doAssert haystack.len == 14
+      doAssert haystack.rfind("ABC") == 9
+      doAssert haystack.rfind("ABC", last=13) == 9
+      doAssert haystack.rfind("ABC", last=12) == 9
+      doAssert haystack.rfind("ABC", last=11) == 9
+      doAssert haystack.rfind("ABC", last=10) == 0
+
+      doAssert haystack.rfind("ABC", start=0) == 9
+      doAssert haystack.rfind("ABC", start=1) == 9
+      doAssert haystack.rfind("ABC", start=9) == 9
+      doAssert haystack.rfind("ABC", start=10) == -1
+
+      doAssert haystack.rfind("ABC", start=0, last=13) == 9
+      doAssert haystack.rfind("ABC", start=0, last=12) == 9
+      doAssert haystack.rfind("ABC", start=0, last=11) == 9
+      doAssert haystack.rfind("ABC", start=0, last=10) == 0
+      doAssert haystack.rfind("ABC", start=1, last=10) == -1
+
+    doAssert "".rfind("/") == -1
+    doAssert "/".rfind("/") == 0
+    doAssert "/".rfind("//") == -1
+    doAssert "///".rfind("//", start=3) == -1
+
+    # searching for empty string
+    doAssert "".rfind("") == 0
+    doAssert "abc".rfind("") == 3
+    doAssert "abc".rfind("", start=1) == 3
+    doAssert "abc".rfind("", start=2) == 3
+    doAssert "abc".rfind("", start=3) == 3
+    doAssert "abc".rfind("", start=4) == 4
+    doAssert "abc".rfind("", start=400) == 400
+
+    doAssert "abc".rfind("", start=1, last=3) == 3
+    doAssert "abc".rfind("", start=1, last=2) == 2
+    doAssert "abc".rfind("", start=1, last=1) == 1
+    # This returns the start index instead of the last index
+    # because start > last
+    doAssert "abc".rfind("", start=1, last=0) == 1
+    doAssert "abc".rfind("", start=1, last = -1) == 3
+    
+    doAssert "abc".rfind("", start=0, last=0) == 0
+
+    # when last <= start, searching for non-empty string
+    block:
+      let last: int = -1
+      doAssert "abcd".rfind("ab", start=0, last=last) == 0
+      doAssert "abcd".rfind("ab", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=1, last=last) == 1
+      doAssert "abcd".rfind("bc", start=2, last=last) == -1
+    block:
+      let last: int = 0
+      doAssert "abcd".rfind("ab", start=0, last=last) == -1
+      doAssert "abcd".rfind("ab", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=2, last=last) == -1
+    block:
+      let last: int = 1
+      doAssert "abcd".rfind("ab", start=0, last=last) == 0
+      doAssert "abcd".rfind("ab", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=2, last=last) == -1
+
+  block: # trimZeros
+    var x = "1200"
+    x.trimZeros()
+    doAssert x == "1200"
+    x = "120.0"
+    x.trimZeros()
+    doAssert x == "120"
+    x = "0."
+    x.trimZeros()
+    doAssert x == "0"
+    x = "1.0e2"
+    x.trimZeros()
+    doAssert x == "1e2"
+    x = "78.90"
+    x.trimZeros()
+    doAssert x == "78.9"
+    x = "1.23e4"
+    x.trimZeros()
+    doAssert x == "1.23e4"
+    x = "1.01"
+    x.trimZeros()
+    doAssert x == "1.01"
+    x = "1.1001"
+    x.trimZeros()
+    doAssert x == "1.1001"
+    x = "0.0"
+    x.trimZeros()
+    doAssert x == "0"
+    x = "0.01"
+    x.trimZeros()
+    doAssert x == "0.01"
+    x = "1e0"
+    x.trimZeros()
+    doAssert x == "1e0"
+    x = "1.23"
+    x.trimZeros()
+    doAssert x == "1.23"
+
+  block: # countLines
+    proc assertCountLines(s: string) = doAssert s.countLines == s.splitLines.len
+    assertCountLines("")
+    assertCountLines("\n")
+    assertCountLines("\n\n")
+    assertCountLines("abc")
+    assertCountLines("abc\n123")
+    assertCountLines("abc\n123\n")
+    assertCountLines("\nabc\n123")
+    assertCountLines("\nabc\n123\n")
+
+  block: # parseBinInt, parseHexInt, parseOctInt
+    # binary
+    doAssert "0b1111".parseBinInt == 15
+    doAssert "0B1111".parseBinInt == 15
+    doAssert "1111".parseBinInt == 15
+    doAssert "1110".parseBinInt == 14
+    doAssert "1_1_1_1".parseBinInt == 15
+    doAssert "0b1_1_1_1".parseBinInt == 15
+    rejectParse "".parseBinInt
+    rejectParse "_".parseBinInt
+    rejectParse "0b".parseBinInt
+    rejectParse "0b1234".parseBinInt
+    # hex
+    doAssert "0x72".parseHexInt == 114
+    doAssert "0X72".parseHexInt == 114
+    doAssert "#72".parseHexInt == 114
+    doAssert "72".parseHexInt == 114
+    doAssert "FF".parseHexInt == 255
+    doAssert "ff".parseHexInt == 255
+    doAssert "fF".parseHexInt == 255
+    doAssert "0x7_2".parseHexInt == 114
+    rejectParse "".parseHexInt
+    rejectParse "_".parseHexInt
+    rejectParse "0x".parseHexInt
+    rejectParse "0xFFG".parseHexInt
+    rejectParse "reject".parseHexInt
+    # octal
+    doAssert "0o17".parseOctInt == 15
+    doAssert "0O17".parseOctInt == 15
+    doAssert "17".parseOctInt == 15
+    doAssert "10".parseOctInt == 8
+    doAssert "0o1_0_0".parseOctInt == 64
+    rejectParse "".parseOctInt
+    rejectParse "_".parseOctInt
+    rejectParse "0o".parseOctInt
+    rejectParse "9".parseOctInt
+    rejectParse "0o9".parseOctInt
+    rejectParse "reject".parseOctInt
+
+  block: # parseHexStr
+    doAssert "".parseHexStr == ""
+    doAssert "00Ff80".parseHexStr == "\0\xFF\x80"
+    try:
+      discard "00Ff8".parseHexStr
+      doAssert false, "Should raise ValueError"
+    except ValueError:
+      discard
+
+    try:
+      discard "0k".parseHexStr
+      doAssert false, "Should raise ValueError"
+    except ValueError:
+      discard
+
+    doAssert "".toHex == ""
+    doAssert "\x00\xFF\x80".toHex == "00FF80"
+    doAssert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF"
+
+  block: # toHex
+    doAssert(toHex(100i16, 32) == "00000000000000000000000000000064")
+    whenJsNoBigInt64: discard
+    do:
+      doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
+      doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF")
+      doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF")
+      doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF")
+
+  block: # insertSep
+    doAssert(insertSep($1000_000) == "1_000_000")
+    doAssert(insertSep($232) == "232")
+    doAssert(insertSep($12345, ',') == "12,345")
+    doAssert(insertSep($0) == "0")
+
+  block: # repeat, spaces
+    doAssert(' '.repeat(8) == "        ")
+    doAssert(" ".repeat(8) == "        ")
+    doAssert(spaces(8) == "        ")
+
+    doAssert(' '.repeat(0) == "")
+    doAssert(" ".repeat(0) == "")
+    doAssert(spaces(0) == "")
+
+  block: # toBin, toOct
+    whenJsNoBigInt64: # bug #11369
+      discard
+    do:
+      var num: int64 = -1
+      doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111"
+      doAssert num.toOct(24) == "001777777777777777777777"
+
+  block: # replace
+    doAssert "oo".replace("", "abc") == "oo"
+    # bug #8911
+    static:
+      let a = ""
+      let a2 = a.replace("\n", "\\n")
+
+    static:
+      let b = "b"
+      let b2 = b.replace("\n", "\\n")
+
+    block:
+      let c = ""
+      let c2 = c.replace("\n", "\\n")
+
+  block: # replaceWord
+    doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
+    doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
+    doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
+
+  block: # multiReplace
+    doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
+    doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.",
+        "PEOPLE!")) == "HELLO PEOPLE!"
+    doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
+
+  # `parseEnum`, ref issue #14030
+  # check enum defined at top level # xxx this is probably irrelevant, and pollutes scope
+  # for remaining tests
+  type
+    Foo = enum
+      A = -10
+      B = "bb"
+      C = (-5, "ccc")
+      D = 15
+      E = "ee" # check that we count enum fields correctly
+
+  block: # parseEnum
+    block:
+      let a = parseEnum[Foo]("A")
+      let b = parseEnum[Foo]("bb")
+      let c = parseEnum[Foo]("ccc")
+      let d = parseEnum[Foo]("D")
+      let e = parseEnum[Foo]("ee")
+      doAssert a == A
+      doAssert b == B
+      doAssert c == C
+      doAssert d == D
+      doAssert e == E
+      try:
+        let f = parseEnum[Foo]("Bar")
+        doAssert false
+      except ValueError:
+        discard
+
+      # finally using default
+      let g = parseEnum[Foo]("Bar", A)
+      doAssert g == A
+
+    block: # bug #19463
+      const CAMPAIGN_TABLE = "wikientries_campaign"
+      const CHARACTER_TABLE = "wikientries_character"
+
+      type Tables = enum
+        a = CAMPAIGN_TABLE,
+        b = CHARACTER_TABLE,
+
+      let myA = CAMPAIGN_TABLE
+      doAssert $parseEnum[Tables](myA) == "wikientries_campaign"
+
+    block: # check enum defined in block
+      type
+        Bar = enum
+          V
+          W = "ww"
+          X = (3, "xx")
+          Y = 10
+          Z = "zz" # check that we count enum fields correctly
+
+      let a = parseEnum[Bar]("V")
+      let b = parseEnum[Bar]("ww")
+      let c = parseEnum[Bar]("xx")
+      let d = parseEnum[Bar]("Y")
+      let e = parseEnum[Bar]("zz")
+      doAssert a == V
+      doAssert b == W
+      doAssert c == X
+      doAssert d == Y
+      doAssert e == Z
+      try:
+        let f = parseEnum[Bar]("Baz")
+        doAssert false
+      except ValueError:
+        discard
+
+      # finally using default
+      let g = parseEnum[Bar]("Baz", V)
+      doAssert g == V
+
+    block: # check ambiguous enum fails to parse
+      type
+        Ambig = enum
+          f1 = "A"
+          f2 = "B"
+          f3 = "A"
+
+      doAssert not compiles((let a = parseEnum[Ambig]("A")))
+
+    block: # check almost ambiguous enum
+      type
+        AlmostAmbig = enum
+          f1 = "someA"
+          f2 = "someB"
+          f3 = "SomeA"
+
+      let a = parseEnum[AlmostAmbig]("someA")
+      let b = parseEnum[AlmostAmbig]("someB")
+      let c = parseEnum[AlmostAmbig]("SomeA")
+      doAssert a == f1
+      doAssert b == f2
+      doAssert c == f3
+
+    block:
+      type MyEnum = enum enA, enB, enC, enuD, enE
+      doAssert parseEnum[MyEnum]("enu_D") == enuD
+
+      doAssert parseEnum("invalid enum value", enC) == enC
+    
+    block: # issue #22726
+      type SomeEnum = enum A, B, C
+
+      proc assignEnum(dest: var enum, s: string) =
+        type ty = typeof(dest)
+        dest = parseEnum[ty](s)
+      
+      var v: SomeEnum
+      v.assignEnum("A")
+      doAssert v == A
+
+  block: # indentation
+    doAssert 0 == indentation """
+hey
+  low
+    there
+"""
+    doAssert 2 == indentation """
+  hey
+    low
+      there
+"""
+    doAssert 2 == indentation """  hey
+    low
+      there
+"""
+    doAssert 2 == indentation """  hey
+    low
+      there"""
+    doAssert 0 == indentation ""
+    doAssert 0 == indentation "  \n  \n"
+    doAssert 0 == indentation "    "
+
+  block: # indent
+    doAssert "  foo\n  bar".indent(4, "Q") == "QQQQ  foo\nQQQQ  bar"
+
+  block: # unindent
+    doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
+
+    doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
+    doAssert """~~foo
+~~  bar
+~~  baz""".unindent(4, "~") == "foo\n  bar\n  baz"
+    doAssert """foo
+bar
+    baz
+  """.unindent(4) == "foo\nbar\nbaz\n"
+    doAssert """foo
+    bar
+    baz
+  """.unindent(2) == "foo\n  bar\n  baz\n"
+    doAssert """foo
+    bar
+    baz
+  """.unindent(100) == "foo\nbar\nbaz\n"
+
+    doAssert """foo
+    foo
+    bar
+  """.unindent() == "foo\nfoo\nbar\n"
+
+  block: # formatBiggestFloat
+    disableVm:
+      doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
+      when not defined(js):
+        doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586
+      doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
+      doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
+      doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
+                                                      ["1,0e-11", "1,0e-011"]
+  block: # formatFloat
+    disableVm:
+      # bug #6589
+      when not defined(js):
+        doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
+
+  block: # `%`
+    doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
+    doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
+    doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
+             "The cat eats fish."
+
+  block: # formatSize
+    disableVm:
+      whenJsNoBigInt64: discard
+      do:
+        doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231
+      doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
+      doAssert formatSize(4096) == "4KiB"
+      doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB"
+      doAssert formatSize(4096, includeSpace = true) == "4 KiB"
+      doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB"
+
+  block: # formatEng
+    disableVm:
+      doAssert formatEng(0, 2, trim = false) == "0.00"
+      doAssert formatEng(0, 2) == "0"
+      doAssert formatEng(53, 2, trim = false) == "53.00"
+      doAssert formatEng(0.053, 2, trim = false) == "53.00e-3"
+      doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3"
+      doAssert formatEng(0.053, 4, trim = true) == "53e-3"
+      doAssert formatEng(0.053, 0) == "53e-3"
+      doAssert formatEng(52731234) == "52.731234e6"
+      doAssert formatEng(-52731234) == "-52.731234e6"
+      doAssert formatEng(52731234, 1) == "52.7e6"
+      doAssert formatEng(-52731234, 1) == "-52.7e6"
+      doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6"
+      doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6"
+
+      doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV"
+      doAssert formatEng(4.1, siPrefix = true, unit = "V",
+          useUnitSpace = true) == "4.1 V"
+      doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space
+      doAssert formatEng(4100, siPrefix = true) == "4.1 k"
+      doAssert formatEng(4.1, siPrefix = true, unit = "",
+          useUnitSpace = true) == "4.1 " # Includes space
+      doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k"
+      doAssert formatEng(4100) == "4.1e3"
+      doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V"
+      doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 "
+      # Don't use SI prefix as number is too big
+      doAssert formatEng(3.1e22, siPrefix = true, unit = "a",
+          useUnitSpace = true) == "31e21 a"
+      # Don't use SI prefix as number is too small
+      doAssert formatEng(3.1e-25, siPrefix = true, unit = "A",
+          useUnitSpace = true) == "310e-27 A"
+
+  block: # align
+    doAssert align("abc", 4) == " abc"
+    doAssert align("a", 0) == "a"
+    doAssert align("1232", 6) == "  1232"
+    doAssert align("1232", 6, '#') == "##1232"
+
+  block: # alignLeft
+    doAssert alignLeft("abc", 4) == "abc "
+    doAssert alignLeft("a", 0) == "a"
+    doAssert alignLeft("1232", 6) == "1232  "
+    doAssert alignLeft("1232", 6, '#') == "1232##"
+
+  block: # center
+    doAssert center("foo", 13) == "     foo     "
+    doAssert center("foo", 0) == "foo"
+    doAssert center("foo", 3, fillChar = 'a') == "foo"
+    doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
+
+  block: # count
+    doAssert count("foofoofoo", "foofoo") == 1
+    doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
+    doAssert count("foofoofoo", 'f') == 3
+    doAssert count("foofoofoobar", {'f', 'b'}) == 4
+
+  block: # isAlphaAscii
+    doAssert isAlphaAscii('r')
+    doAssert isAlphaAscii('A')
+    doAssert(not isAlphaAscii('$'))
+
+  block: # isAlphaNumeric
+    doAssert isAlphaNumeric('3')
+    doAssert isAlphaNumeric('R')
+    doAssert(not isAlphaNumeric('!'))
+
+  block: # isDigit
+    doAssert isDigit('3')
+    doAssert(not isDigit('a'))
+    doAssert(not isDigit('%'))
+
+  block: # isSpaceAscii
+    doAssert isSpaceAscii('\t')
+    doAssert isSpaceAscii('\l')
+    doAssert(not isSpaceAscii('A'))
+
+  block: # isEmptyOrWhitespace
+    doAssert(isEmptyOrWhitespace(""))
+    doAssert(isEmptyOrWhitespace("       "))
+    doAssert(isEmptyOrWhitespace("\t\l \v\r\f"))
+    doAssert(not isEmptyOrWhitespace("ABc   \td"))
+
+  block: # isLowerAscii
+    doAssert isLowerAscii('a')
+    doAssert isLowerAscii('z')
+    doAssert(not isLowerAscii('A'))
+    doAssert(not isLowerAscii('5'))
+    doAssert(not isLowerAscii('&'))
+    doAssert(not isLowerAscii(' '))
+
+  block: # isUpperAscii
+    doAssert isUpperAscii('A')
+    doAssert(not isUpperAscii('b'))
+    doAssert(not isUpperAscii('5'))
+    doAssert(not isUpperAscii('%'))
+
+  block: # unescape
+    doAssert(unescape(r"\x013", "", "") == "\x013")
+
+  block: # join
+    doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
+    doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
+    doAssert join([1, 2, 3]) == "123"
+    doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
+
+  block: # startsWith / endsWith
+    var s = "abcdef"
+    doAssert s.startsWith('a')
+    doAssert s.startsWith('b') == false
+    doAssert s.endsWith('f')
+    doAssert s.endsWith('a') == false
+    doAssert s.endsWith('\0') == false
+
+  block: # nimIdentNormalize
+    doAssert nimIdentNormalize("") == ""
+    doAssert nimIdentNormalize("foo") == "foo"
+    doAssert nimIdentNormalize("foo_bar") == "foobar"
+    doAssert nimIdentNormalize("Foo_bar") == "Foobar"
+    doAssert nimIdentNormalize("_Foo_bar") == "_foobar"
+
+  block: # bug #19500
+    doAssert "abc \0 def".find("def") == 6
+    doAssert "abc \0 def".find('d') == 6
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim
new file mode 100644
index 000000000..2ea96cfbb
--- /dev/null
+++ b/tests/stdlib/tsugar.nim
@@ -0,0 +1,310 @@
+discard """
+  targets: "c js"
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+x + y = 30
+'''
+"""
+import std/[sugar, algorithm, random, sets, tables, strutils, sequtils]
+import std/[syncio, assertions]
+
+type # for capture test, ref #20679
+  FooCapture = ref object
+    x: int
+
+proc mainProc() =
+  block: # bug #16967
+    var s = newSeq[proc (): int](5)
+    {.push exportc.}
+    proc bar() =
+      for i in 0 ..< s.len:
+        let foo = i + 1
+        capture foo:
+          s[i] = proc(): int = foo
+    {.pop.}
+
+    bar()
+
+    for i, p in s.pairs:
+      let foo = i + 1
+      doAssert p() == foo
+
+template main() =
+  block: # `=>`
+    block:
+      let f1 = () => 42
+      doAssert f1() == 42
+
+      let f2 = (x: int) => x + 1
+      doAssert f2(42) == 43
+
+      let f3 = (x, y: int) => x + y
+      doAssert f3(1, 2) == 3
+
+      var x = 0
+      let f4 = () => (x = 12)
+      f4()
+      doAssert x == 12
+
+      let f5 = () => (discard) # simplest proc that returns void
+      f5()
+
+    block:
+      proc call1(f: () -> int): int = f()
+      doAssert call1(() => 12) == 12
+
+      proc call2(f: int -> int): int = f(42)
+      doAssert call2(x => x) == 42
+      doAssert call2((x) => x) == 42
+      doAssert call2((x: int) => x) == 42
+
+      proc call3(f: (int, int) -> int): int = f(1, 2)
+      doAssert call3((x, y) => x + y) == 3
+      doAssert call3((x, y: int) => x + y) == 3
+      doAssert call3((x: int, y: int) => x + y) == 3
+
+      var a = 0
+      proc call4(f: int -> void) = f(42)
+      call4((x: int) => (a = x))
+      doAssert a == 42
+
+      proc call5(f: (int {.noSideEffect.} -> int)): int = f(42)
+      doAssert call5(x {.noSideEffect.} => x + 1) == 43
+
+  block: # `->`
+    doAssert $(() -> int) == "proc (): int{.closure.}"
+    doAssert $(float -> int) == "proc (i0: float): int{.closure.}"
+    doAssert $((float) -> int) == "proc (i0: float): int{.closure.}"
+    doAssert $((float, bool) -> int) == "proc (i0: float, i1: bool): int{.closure.}"
+
+    doAssert $(() -> void) == "proc (){.closure.}"
+    doAssert $(float -> void) == "proc (i0: float){.closure.}"
+    doAssert $((float) -> void) == "proc (i0: float){.closure.}"
+    doAssert $((float, bool) -> void) == "proc (i0: float, i1: bool){.closure.}"
+
+    doAssert $(() {.inline.} -> int) == "proc (): int{.inline.}"
+    doAssert $(float {.inline.} -> int) == "proc (i0: float): int{.inline.}"
+    doAssert $((float) {.inline.} -> int) == "proc (i0: float): int{.inline.}"
+    doAssert $((float, bool) {.inline.} -> int) == "proc (i0: float, i1: bool): int{.inline.}"
+
+  block: # capture
+    var closure1: () -> int
+    for i in 0 .. 10:
+      if i == 5:
+        capture i:
+          closure1 = () => i
+    doAssert closure1() == 5
+
+    var closure2: () -> (int, int)
+    for i in 0 .. 10:
+      for j in 0 .. 10:
+        if i == 5 and j == 3:
+          capture i, j:
+            closure2 = () => (i, j)
+    doAssert closure2() == (5, 3)
+
+    block: # issue #20679
+      # this should compile. Previously was broken as `var int` is an `nnkHiddenDeref`
+      # which was not handled correctly
+
+      block:
+        var x = 5
+        var s1 = newSeq[proc (): int](2)
+        proc function(data: var int) =
+          for i in 0 ..< 2:
+            data = (i+1) * data
+            capture data:
+              s1[i] = proc(): int = data
+        function(x)
+        doAssert s1[0]() == 5
+        doAssert s1[1]() == 10
+
+
+      block:
+        var y = @[5, 10]
+        var s2 = newSeq[proc (): seq[int]](2)
+        proc functionS(data: var seq[int]) =
+          for i in 0 ..< 2:
+            data.add (i+1) * 5
+            capture data:
+              s2[i] = proc(): seq[int] = data
+        functionS(y)
+        doAssert s2[0]() == @[5, 10, 5]
+        doAssert s2[1]() == @[5, 10, 5, 10]
+
+
+      template typeT(typ, val: untyped): untyped =
+        var x = val
+        var s = newSeq[proc (): typ](2)
+
+        proc functionT[T](data: var T) =
+          for i in 0 ..< 2:
+            if i == 1:
+              data = default(T)
+            capture data:
+              s[i] = proc (): T = data
+
+        functionT(x)
+        doAssert s[0]() == val
+        doAssert s[1]() == x # == default
+        doAssert s[1]() == default(typ)
+
+      block:
+        var x = 1.1
+        typeT(float, x)
+      block:
+        var x = "hello"
+        typeT(string, x)
+      block:
+        var f = FooCapture(x: 5)
+        typeT(FooCapture, f)
+
+  block: # dup
+    block dup_with_field:
+      type
+        Foo = object
+          col, pos: int
+          name: string
+
+      proc inc_col(foo: var Foo) = inc(foo.col)
+      proc inc_pos(foo: var Foo) = inc(foo.pos)
+      proc name_append(foo: var Foo, s: string) = foo.name &= s
+
+      let a = Foo(col: 1, pos: 2, name: "foo")
+      block:
+        let b = a.dup(inc_col, inc_pos):
+          _.pos = 3
+          name_append("bar")
+          inc_pos
+
+        doAssert(b == Foo(col: 2, pos: 4, name: "foobar"))
+
+      block:
+        let b = a.dup(inc_col, pos = 3, name = "bar"):
+          name_append("bar")
+          inc_pos
+
+        doAssert(b == Foo(col: 2, pos: 4, name: "barbar"))
+
+    block:
+      var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      doAssert dup(a, sort(_)) == sorted(a)
+      doAssert a.dup(sort) == sorted(a)
+      # Chaining:
+      var aCopy = a
+      aCopy.insert(10)
+      doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy)
+
+    block:
+      when nimvm: discard
+      else:
+        const b = @[0, 1, 2]
+        discard b.dup shuffle()
+        doAssert b[0] == 0
+        doAssert b[1] == 1
+
+  block: # collect
+    let data = @["bird", "word"] # if this gets stuck in your head, its not my fault
+
+    doAssert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"]
+    doAssert collect(initTable(2), for (i, d) in data.pairs: {i: d}) ==
+      {0: "bird", 1: "word"}.toTable
+    doAssert collect(initHashSet(), for d in data.items: {d}) == data.toHashSet
+
+    block:
+      let x = collect(newSeqOfCap(4)):
+          for (i, d) in data.pairs:
+            if i mod 2 == 0: d
+      doAssert x == @["bird"]
+
+    block: # bug #12874
+      let bug = collect(
+          newSeq,
+          for (i, d) in data.pairs:(
+            block:
+              if i mod 2 == 0:
+                d
+              else:
+                d & d
+            )
+      )
+      doAssert bug == @["bird", "wordword"]
+
+    block:
+      let y = collect(newSeq):
+        for (i, d) in data.pairs:
+          try: parseInt(d) except: 0
+      doAssert y == @[0, 0]
+
+    block:
+      let z = collect(newSeq):
+        for (i, d) in data.pairs:
+          case d
+          of "bird": "word"
+          else: d
+      doAssert z == @["word", "word"]
+
+    block:
+      proc tforum(): seq[int] =
+        collect(newSeq):
+          for y in 0..10:
+            if y mod 5 == 2:
+              for x in 0..y:
+                x
+      doAssert tforum() == @[0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7]
+
+    block:
+      let x = collect:
+        for d in data.items:
+          when d is int: "word"
+          else: d
+      doAssert x == @["bird", "word"]
+
+    block:
+      doAssert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")]
+      doAssert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0]
+      doAssert collect(for (i, d) in pairs(data): {i: d}) ==
+        {1: "word", 0: "bird"}.toTable
+      doAssert collect(for d in data.items: {d}) == data.toHashSet
+
+    block: # bug #14332
+      template foo =
+        discard collect(newSeq, for i in 1..3: i)
+      foo()
+
+  block: # dump
+    # symbols in templates are gensym'd
+    let
+      x {.inject.} = 10
+      y {.inject.} = 20
+    dump(x + y) # x + y = 30
+
+  block: # dumpToString
+    template square(x): untyped = x * x
+    let x {.inject.} = 10
+    doAssert dumpToString(square(x)) == "square(x): x * x = 100"
+    let s = dumpToString(doAssert 1+1 == 2)
+    doAssert "failedAssertImpl" in s
+    let s2 = dumpToString:
+      doAssertRaises(AssertionDefect): doAssert false
+    doAssert "except AssertionDefect" in s2
+
+  block: # bug #20704
+    proc test() =
+      var xs, ys: seq[int]
+      for i in 0..5:
+        xs.add(i)
+
+      xs.apply(proc (d: auto) = ys.add(d))
+      # ^ can be turned into d => ys.add(d) when we can infer void return type, #16906
+      doAssert ys == @[0, 1, 2, 3, 4, 5]
+
+    test()
+
+  mainProc()
+
+when not defined(js): # TODO fixme JS VM
+  static:
+    main()
+
+main()
diff --git a/tests/stdlib/tsums.nim b/tests/stdlib/tsums.nim
new file mode 100644
index 000000000..cf410cddf
--- /dev/null
+++ b/tests/stdlib/tsums.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/sums
+from math import pow
+import std/assertions
+
+var epsilon = 1.0
+while 1.0 + epsilon != 1.0:
+  epsilon /= 2.0
+let data = @[1.0, epsilon, -epsilon]
+doAssert sumKbn(data) == 1.0
+# doAssert sumPairs(data) != 1.0 # known to fail in 64 bits
+doAssert (1.0 + epsilon) - epsilon != 1.0
+
+var tc1: seq[float]
+for n in 1 .. 1000:
+  tc1.add 1.0 / n.float
+doAssert sumKbn(tc1) == 7.485470860550345
+doAssert sumPairs(tc1) == 7.485470860550345
+
+var tc2: seq[float]
+for n in 1 .. 1000:
+  tc2.add pow(-1.0, n.float) / n.float
+doAssert sumKbn(tc2) == -0.6926474305598203
+doAssert sumPairs(tc2) == -0.6926474305598204
diff --git a/tests/stdlib/tsysrand.nim b/tests/stdlib/tsysrand.nim
new file mode 100644
index 000000000..7b7a0fc34
--- /dev/null
+++ b/tests/stdlib/tsysrand.nim
@@ -0,0 +1,34 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--experimental:vmopsDanger; --experimental:vmopsDanger --mm:refc"
+"""
+
+import std/sysrand
+import std/assertions
+
+template main() =
+  block:
+    var x = array[5, byte].default
+    doAssert urandom(x)
+
+  block:
+    var x = newSeq[byte](5)
+    doAssert urandom(x)
+
+  block:
+    var x = @[byte(0), 0, 0, 0, 0]
+    doAssert urandom(x)
+
+  block:
+    var x = @[byte(1), 2, 3, 4, 5]
+    doAssert urandom(x)
+
+  block:
+    doAssert urandom(0).len == 0
+    doAssert urandom(10).len == 10
+    doAssert urandom(20).len == 20
+    doAssert urandom(120).len == 120
+    doAssert urandom(113).len == 113
+    doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice
+
+main()
diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim
new file mode 100644
index 000000000..f634ce0c2
--- /dev/null
+++ b/tests/stdlib/tsystem.nim
@@ -0,0 +1,200 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import stdtest/testutils
+import std/[assertions, formatfloat]
+
+# TODO: in future work move existing `system` tests here, where they belong
+
+
+template main =
+  block: # closure
+    proc outer() =
+      var a = 0
+      proc inner1 = a.inc
+      proc inner2 = discard
+      doAssert inner1 is "closure"
+      doAssert inner2 isnot "closure"
+      doAssert inner1 is (proc)
+      doAssert inner2 is (proc)
+      let inner1b = inner1
+      doAssert inner1b is "closure"
+      doAssert inner1b == inner1
+    outer()
+
+  block: # rawProc, rawProc, bug #17911
+    proc outer() =
+      var a = 0
+      var b = 0
+      proc inner1() = a.inc
+      proc inner2() = a += 2
+      proc inner3() = b.inc
+      let inner1b = inner1
+      doAssert inner2 != inner1
+      doAssert inner3 != inner1
+      whenVMorJs: discard
+      do:
+        doAssert rawProc(inner1b) == rawProc(inner1)
+        doAssert rawProc(inner2) != rawProc(inner1)
+        doAssert rawProc(inner3) != rawProc(inner1)
+
+        doAssert rawEnv(inner1b) == rawEnv(inner1)
+        doAssert rawEnv(inner2) == rawEnv(inner1) # because both use `a`
+        # doAssert rawEnv(inner3) != rawEnv(inner1) # because `a` vs `b` # this doesn't hold
+    outer()
+
+  block: # system.delete
+    block:
+      var s = @[1]
+      s.delete(0)
+      doAssert s == @[]
+
+    block:
+      var s = @["foo", "bar"]
+      s.delete(1)
+      doAssert s == @["foo"]
+
+    when false:
+      var s: seq[string]
+      doAssertRaises(IndexDefect):
+        s.delete(0)
+
+    block:
+      doAssert not compiles(@["foo"].delete(-1))
+
+    block: # bug #6710
+      var s = @["foo"]
+      s.delete(0)
+      doAssert s == @[]
+
+    when false: # bug #16544: deleting out of bounds index should raise
+      var s = @["foo"]
+      doAssertRaises(IndexDefect):
+        s.delete(1)
+
+static: main()
+main()
+
+# bug #19967
+block:
+  type
+    X = object
+      a: string
+      b: set[char]
+      c: int
+      d: float
+      e: int64
+
+
+  var x = X(b: {'a'}, e: 10)
+
+  var y = move x
+
+  doAssert x.a == ""
+  doAssert x.b == {}
+  doAssert x.c == 0
+  doAssert x.d == 0.0
+  doAssert x.e == 0
+
+  reset(y)
+
+  doAssert y.a == ""
+  doAssert y.b == {}
+  doAssert y.c == 0
+  doAssert y.d == 0.0
+  doAssert y.e == 0
+
+block:
+  var x = 2
+  var y = move x
+  doAssert y == 2
+  doAssert x == 0
+  reset y
+  doAssert y == 0
+
+block:
+  type
+    X = object
+      a: string
+      b: float
+
+  var y = X(b: 1314.521)
+
+  reset(y)
+
+  doAssert y.b == 0.0
+
+block:
+  type
+    X = object
+      a: string
+      b: string
+
+  var y = X(b: "1314")
+
+  reset(y)
+
+  doAssert y.b == ""
+
+block:
+  type
+    X = object
+      a: string
+      b: seq[int]
+
+  var y = X(b: @[1, 3])
+
+  reset(y)
+
+  doAssert y.b == @[]
+
+block:
+  type
+    X = object
+      a: string
+      b: tuple[a: int, b: string]
+
+  var y = X(b: (1, "cc"))
+
+  reset(y)
+
+  doAssert y.b == (0, "")
+
+block:
+  type
+    Color = enum
+      Red, Blue, Yellow
+    X = object
+      a: string
+      b: set[Color]
+
+  var y = X(b: {Red, Blue})
+
+  reset(y)
+  doAssert y.b == {}
+
+block: # bug #20516
+  type Foo = object
+    x {.bitsize:4.}: uint
+    y {.bitsize:4.}: uint
+
+  when not defined(js):
+    let a = create(Foo)
+
+block: # bug #6549
+  when not defined(js):
+    block:
+      const v = 18446744073709551615'u64
+
+      doAssert $v == "18446744073709551615"
+      doAssert $float32(v) == "1.8446744e+19", $float32(v)
+      doAssert $float64(v) == "1.8446744073709552e+19", $float64(v)
+
+    block:
+      let v = 18446744073709551615'u64
+
+      doAssert $v == "18446744073709551615"
+      doAssert $float32(v) == "1.8446744e+19"
+      doAssert $float64(v) == "1.8446744073709552e+19"
diff --git a/tests/stdlib/ttables.nim b/tests/stdlib/ttables.nim
new file mode 100644
index 000000000..c529aff9f
--- /dev/null
+++ b/tests/stdlib/ttables.nim
@@ -0,0 +1,316 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import tables, hashes
+import std/assertions
+
+type
+  Person = object
+    firstName, lastName: string
+
+proc hash(x: Person): Hash =
+  ## Piggyback on the already available string hash proc.
+  ##
+  ## Without this proc nothing works!
+  result = x.firstName.hash !& x.lastName.hash
+  result = !$result
+
+var
+  salaries = initTable[Person, int]()
+  p1, p2: Person
+p1.firstName = "Jon"
+p1.lastName = "Ross"
+salaries[p1] = 30_000
+p2.firstName = "소진"
+p2.lastName = "박"
+salaries[p2] = 45_000
+var
+  s2 = initOrderedTable[Person, int]()
+  s3 = initCountTable[Person]()
+s2[p1] = 30_000
+s2[p2] = 45_000
+s3[p1] = 30_000
+s3[p2] = 45_000
+
+block: # Ordered table should preserve order after deletion
+  var
+    s4 = initOrderedTable[int, int]()
+  s4[1] = 1
+  s4[2] = 2
+  s4[3] = 3
+
+  var prev = 0
+  for i in s4.values:
+    doAssert(prev < i)
+    prev = i
+
+  s4.del(2)
+  doAssert(2 notin s4)
+  doAssert(s4.len == 2)
+  prev = 0
+  for i in s4.values:
+    doAssert(prev < i)
+    prev = i
+
+block: # Deletion from OrderedTable should account for collision groups. See issue #5057.
+  # The bug is reproducible only with exact keys
+  const key1 = "boy_jackpot.inGamma"
+  const key2 = "boy_jackpot.outBlack"
+
+  var t = {
+      key1: 0,
+      key2: 0
+  }.toOrderedTable()
+
+  t.del(key1)
+  doAssert(t.len == 1)
+  doAssert(key2 in t)
+
+var
+  t1 = initCountTable[string]()
+  t2 = initCountTable[string]()
+t1.inc("foo")
+t1.inc("bar", 2)
+t1.inc("baz", 3)
+t2.inc("foo", 4)
+t2.inc("bar")
+t2.inc("baz", 11)
+merge(t1, t2)
+doAssert(t1["foo"] == 5)
+doAssert(t1["bar"] == 3)
+doAssert(t1["baz"] == 14)
+
+let
+  t1r = newCountTable[string]()
+  t2r = newCountTable[string]()
+t1r.inc("foo")
+t1r.inc("bar", 2)
+t1r.inc("baz", 3)
+t2r.inc("foo", 4)
+t2r.inc("bar")
+t2r.inc("baz", 11)
+merge(t1r, t2r)
+doAssert(t1r["foo"] == 5)
+doAssert(t1r["bar"] == 3)
+doAssert(t1r["baz"] == 14)
+
+var
+  t1l = initCountTable[string]()
+  t2l = initCountTable[string]()
+t1l.inc("foo")
+t1l.inc("bar", 2)
+t1l.inc("baz", 3)
+t2l.inc("foo", 4)
+t2l.inc("bar")
+t2l.inc("baz", 11)
+
+block:
+  const testKey = "TESTKEY"
+  let t: CountTableRef[string] = newCountTable[string]()
+
+  # Before, does not compile with error message:
+  #test_counttable.nim(7, 43) template/generic instantiation from here
+  #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here
+  #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode
+  doAssert 0 == t[testKey]
+  t.inc(testKey, 3)
+  doAssert 3 == t[testKey]
+
+block:
+  # Clear tests
+  var clearTable = newTable[int, string]()
+  clearTable[42] = "asd"
+  clearTable[123123] = "piuyqwb "
+  doAssert clearTable[42] == "asd"
+  clearTable.clear()
+  doAssert(not clearTable.hasKey(123123))
+  doAssert clearTable.getOrDefault(42) == ""
+
+block: #5482
+  var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
+  var b = newOrderedTable[string, string](initialSize = 2)
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block: #5482
+  var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
+  var b = newOrderedTable[string, string](initialSize = 2)
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block: #5487
+  var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
+  var b = newOrderedTable[string, string]()         # notice, default size!
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block: #5487
+  var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
+  var b = newOrderedTable[string, string]()         # notice, default size!
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block:
+  var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
+  var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
+  var c = newOrderedTable[string, string]()         # notice, default size!
+  c["wrong?"] = "foo"
+  c["wrong?"] = "foo2"
+  doAssert a == b
+  doAssert a == c
+
+block: #6250
+  let
+    a = {3: 1}.toOrderedTable
+    b = {3: 2}.toOrderedTable
+  doAssert((a == b) == false)
+  doAssert((b == a) == false)
+
+block: #6250
+  let
+    a = {3: 2}.toOrderedTable
+    b = {3: 2}.toOrderedTable
+  doAssert((a == b) == true)
+  doAssert((b == a) == true)
+
+block: # CountTable.smallest
+  let t = toCountTable([0, 0, 5, 5, 5])
+  doAssert t.smallest == (0, 2)
+
+block: #10065
+  let t = toCountTable("abracadabra")
+  doAssert t['z'] == 0
+
+  var t_mut = toCountTable("abracadabra")
+  doAssert t_mut['z'] == 0
+  # the previous read may not have modified the table.
+  doAssert t_mut.hasKey('z') == false
+  t_mut['z'] = 1
+  doAssert t_mut['z'] == 1
+  doAssert t_mut.hasKey('z') == true
+
+block: #12813 #13079
+  var t = toCountTable("abracadabra")
+  doAssert len(t) == 5
+
+  t['a'] = 0 # remove a key
+  doAssert len(t) == 4
+
+block:
+  var tp: Table[string, string] = initTable[string, string]()
+  doAssert "test1" == tp.getOrDefault("test1", "test1")
+  tp["test2"] = "test2"
+  doAssert "test2" == tp.getOrDefault("test2", "test1")
+  var tr: TableRef[string, string] = newTable[string, string]()
+  doAssert "test1" == tr.getOrDefault("test1", "test1")
+  tr["test2"] = "test2"
+  doAssert "test2" == tr.getOrDefault("test2", "test1")
+  var op: OrderedTable[string, string] = initOrderedTable[string, string]()
+  doAssert "test1" == op.getOrDefault("test1", "test1")
+  op["test2"] = "test2"
+  doAssert "test2" == op.getOrDefault("test2", "test1")
+  var orf: OrderedTableRef[string, string] = newOrderedTable[string, string]()
+  doAssert "test1" == orf.getOrDefault("test1", "test1")
+  orf["test2"] = "test2"
+  doAssert "test2" == orf.getOrDefault("test2", "test1")
+
+block tableWithoutInit:
+  var
+    a: Table[string, int]
+    b: Table[string, int]
+    c: Table[string, int]
+    d: Table[string, int]
+    e: Table[string, int]
+
+  a["a"] = 7
+  doAssert a.hasKey("a")
+  doAssert a.len == 1
+  doAssert a["a"] == 7
+  a["a"] = 9
+  doAssert a.len == 1
+  doAssert a["a"] == 9
+
+  doAssert b.hasKeyOrPut("b", 5) == false
+  doAssert b.hasKey("b")
+  doAssert b.hasKeyOrPut("b", 8)
+  doAssert b["b"] == 5
+
+  doAssert c.getOrDefault("a") == 0
+  doAssert c.getOrDefault("a", 3) == 3
+  c["a"] = 6
+  doAssert c.getOrDefault("a", 3) == 6
+
+  doAssert d.mgetOrPut("a", 3) == 3
+  doAssert d.mgetOrPut("a", 6) == 3
+
+  var x = 99
+  doAssert e.pop("a", x) == false
+  doAssert x == 99
+  e["a"] = 77
+  doAssert e.pop("a", x)
+  doAssert x == 77
+
+block orderedTableWithoutInit:
+  var
+    a: OrderedTable[string, int]
+    b: OrderedTable[string, int]
+    c: OrderedTable[string, int]
+    d: OrderedTable[string, int]
+
+  a["a"] = 7
+  doAssert a.hasKey("a")
+  doAssert a.len == 1
+  doAssert a["a"] == 7
+  a["a"] = 9
+  doAssert a.len == 1
+  doAssert a["a"] == 9
+
+  doAssert b.hasKeyOrPut("b", 5) == false
+  doAssert b.hasKey("b")
+  doAssert b.hasKeyOrPut("b", 8)
+  doAssert b["b"] == 5
+
+  doAssert c.getOrDefault("a") == 0
+  doAssert c.getOrDefault("a", 3) == 3
+  c["a"] = 6
+  doAssert c.getOrDefault("a", 3) == 6
+
+  doAssert d.mgetOrPut("a", 3) == 3
+  doAssert d.mgetOrPut("a", 6) == 3
+
+block countTableWithoutInit:
+  var
+    a: CountTable[string]
+    b: CountTable[string]
+    c: CountTable[string]
+    d: CountTable[string]
+    e: CountTable[string]
+
+  a["a"] = 7
+  doAssert a.hasKey("a")
+  doAssert a.len == 1
+  doAssert a["a"] == 7
+  a["a"] = 9
+  doAssert a.len == 1
+  doAssert a["a"] == 9
+
+  doAssert b["b"] == 0
+  b.inc("b")
+  doAssert b["b"] == 1
+
+  doAssert c.getOrDefault("a") == 0
+  doAssert c.getOrDefault("a", 3) == 3
+  c["a"] = 6
+  doAssert c.getOrDefault("a", 3) == 6
+
+  e["f"] = 3
+  merge(d, e)
+  doAssert d.hasKey("f")
+  d.inc("f")
+  merge(d, e)
+  doAssert d["f"] == 7
diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim
new file mode 100644
index 000000000..ba65590d9
--- /dev/null
+++ b/tests/stdlib/ttasks.nim
@@ -0,0 +1,561 @@
+discard """
+  targets: "c cpp"
+  matrix: "--gc:orc --threads:off"
+"""
+
+import std/[tasks, strformat]
+import std/assertions
+
+block:
+  var s = ""
+  proc `+`(x: int, y: string) =
+    s.add $x & y
+
+  let literal = "Nim"
+  let t = toTask(521 + literal)
+  t.invoke()
+
+  doAssert s == "521Nim"
+
+block:
+  var s = ""
+  proc `!`(x: int) =
+    s.add $x
+
+  let t = toTask !12
+  t.invoke()
+
+  doAssert s == "12"
+
+
+block:
+  block:
+    var called = 0
+    proc hello(x: static range[1 .. 5]) =
+      called += x
+
+    let b = toTask hello(3)
+    b.invoke()
+    doAssert called == 3
+    b.invoke()
+    doAssert called == 6
+
+  block:
+    var called = 0
+    proc hello(x: range[1 .. 5]) =
+      called += x
+
+    let b = toTask hello(3)
+    b.invoke()
+    doAssert called == 3
+    b.invoke()
+    doAssert called == 6
+
+  block:
+    var called = 0
+    proc hello(x: 1 .. 5) =
+      called += x
+
+    let b = toTask hello(3)
+    b.invoke()
+    doAssert called == 3
+    b.invoke()
+    doAssert called == 6
+
+  block:
+    var temp = ""
+    proc hello(a: int or seq[string]) =
+      when a is seq[string]:
+        for s in a:
+          temp.add s
+      else:
+        temp.addInt a
+
+    let x = @["1", "2", "3", "4"]
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == "1234"
+    b.invoke()
+    doAssert temp == "12341234"
+
+
+  block:
+    var temp = ""
+
+    proc hello(a: int or string) =
+      when a is string:
+        temp.add a
+
+    let x = "!2"
+
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == x
+
+  block:
+    var temp = ""
+    proc hello(a: int or string) =
+      when a is string:
+        temp.add a
+
+    let x = "!2"
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == x
+
+  block:
+    var x = 0
+    proc hello(typ: typedesc) =
+      x += typ(12)
+
+    let b = toTask hello(int)
+    b.invoke()
+    doAssert x == 12
+
+  block:
+    var temp = ""
+    proc hello(a: int or seq[string]) =
+      when a is seq[string]:
+        for s in a:
+          temp.add s
+
+    let x = @["1", "2", "3", "4"]
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == "1234"
+
+  block:
+    var temp = ""
+    proc hello(a: int | string) =
+      when a is string:
+        temp.add a
+
+    let x = "!2"
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == x
+
+  block:
+    var x = 0
+    proc hello(a: int | string) =
+      when a is int:
+        x = a
+
+    let b = toTask hello(12)
+    b.invoke()
+    doAssert x == 12
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(c: seq[int], a: int) =
+      a1 = c
+      a2 = a
+
+    let x = 12
+    var y = @[1, 3, 1, 4, 5, x, 1]
+    let b = toTask hello(y, 12)
+    b.invoke()
+
+    doAssert a1 == y
+    doAssert a2 == x
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(c: seq[int], a: int) =
+      a1 = c
+      a2 = a
+    var x = 2
+    let b = toTask hello(@[1, 3, 1, 4, 5, x, 1], 12)
+    b.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, x, 1]
+    doAssert a2 == 12
+
+  block:
+    var a1: array[7, int]
+    var a2 = 0
+    proc hello(c: array[7, int], a: int) =
+      a1 = c
+      a2 = a
+
+    let b = toTask hello([1, 3, 1, 4, 5, 2, 1], 12)
+    b.invoke()
+
+    doAssert a1 == [1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 12
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(c: seq[int], a: int) =
+      a1 = c
+      a2 = a
+
+    let b = toTask hello(@[1, 3, 1, 4, 5, 2, 1], 12)
+    b.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 12
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(a: int, c: seq[int]) =
+      a1 = c
+      a2 = a
+
+    let b = toTask hello(8, @[1, 3, 1, 4, 5, 2, 1])
+    b.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 8
+
+    let c = toTask 8.hello(@[1, 3, 1, 4, 5, 2, 1])
+    c.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[seq[int]]
+    var a2: int
+    proc hello(a: int, c: openArray[seq[int]]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, @[@[3], @[4], @[5], @[6], @[12], @[7]])
+    b.invoke()
+
+    doAssert a1 ==  @[@[3], @[4], @[5], @[6], @[12], @[7]]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: openArray[int]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, @[3, 4, 5, 6, 12, 7])
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: static varargs[int]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, @[3, 4, 5, 6, 12, 7])
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: static varargs[int]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, [3, 4, 5, 6, 12, 7])
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: varargs[int]) =
+      a1 = @c
+      a2 = a
+
+    let x = 12
+    let b = toTask hello(8, 3, 4, 5, 6, x, 7)
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var x = 12
+
+    proc hello(x: ptr int) =
+      x[] += 12
+
+    let b = toTask hello(addr x)
+    b.invoke()
+
+    doAssert x == 24
+
+    let c = toTask x.addr.hello
+    invoke(c)
+
+    doAssert x == 36
+  block:
+    type
+      Test = ref object
+        id: int
+
+    var x = 0
+    proc hello(a: int, c: static Test) =
+      x += a
+      x += c.id
+
+    let b = toTask hello(8, Test(id: 12))
+    b.invoke()
+
+    doAssert x == 20
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var x = 0
+    proc hello(a: int, c: static Test) =
+      x += a
+      x += c.id
+
+    let b = toTask hello(8, Test(id: 12))
+    b.invoke()
+    doAssert x == 20
+
+  block:
+    var x = 0
+    proc hello(a: int, c: static seq[int]) =
+      x += a
+      for i in c:
+        x += i
+
+    let b = toTask hello(8, @[3, 4, 5, 6, 12, 7])
+    b.invoke()
+    doAssert x == 45
+
+  block:
+    var x = 0
+    proc hello(a: int, c: static array[5, int]) =
+      x += a
+      for i in c:
+        x += i
+
+    let b = toTask hello(8, [3, 4, 5, 6, 12])
+    b.invoke()
+    doAssert x == 38
+
+  block:
+    var aVal = 0
+    var cVal = ""
+
+    proc hello(a: int, c: static string) =
+      aVal += a
+      cVal.add c
+
+    var x = 1314
+    let b = toTask hello(x, "hello")
+    b.invoke()
+
+    doAssert aVal == x
+    doAssert cVal == "hello"
+
+  block:
+    var aVal = ""
+
+    proc hello(a: static string) =
+      aVal.add a
+    let b = toTask hello("hello")
+    b.invoke()
+
+    doAssert aVal == "hello"
+
+  block:
+    var aVal = 0
+    var cVal = ""
+
+    proc hello(a: static int, c: static string) =
+      aVal += a
+      cVal.add c
+    let b = toTask hello(8, "hello")
+    b.invoke()
+
+    doAssert aVal == 8
+    doAssert cVal == "hello"
+
+  block:
+    var aVal = 0
+    var cVal = 0
+
+    proc hello(a: static int, c: int) =
+      aVal += a
+      cVal += c
+
+    let b = toTask hello(c = 0, a = 8)
+    b.invoke()
+
+    doAssert aVal == 8
+    doAssert cVal == 0
+
+  block:
+    var aVal = 0
+    var cVal = 0
+
+    proc hello(a: int, c: static int) =
+      aVal += a
+      cVal += c
+
+    let b = toTask hello(c = 0, a = 8)
+    b.invoke()
+
+    doAssert aVal == 8
+    doAssert cVal == 0
+
+  block:
+    var aVal = 0
+    var cVal = 0
+
+    proc hello(a: static int, c: static int) =
+      aVal += a
+      cVal += c
+
+    let b = toTask hello(0, 8)
+    b.invoke()
+
+    doAssert aVal == 0
+    doAssert cVal == 8
+
+  block:
+    var temp = ""
+    proc hello(x: int, y: seq[string], d = 134) =
+      temp = fmt"{x=} {y=} {d=}"
+
+
+    proc main() =
+      var x = @["23456"]
+      let t = toTask hello(2233, x)
+      t.invoke()
+
+      doAssert temp == """x=2233 y=@["23456"] d=134"""
+
+    main()
+
+
+  block:
+    var temp = ""
+    proc hello(x: int, y: seq[string], d = 134) =
+      temp.add fmt"{x=} {y=} {d=}"
+
+    proc ok() =
+      temp = "ok"
+
+    proc main() =
+      var x = @["23456"]
+      let t = toTask hello(2233, x)
+      t.invoke()
+      t.invoke()
+
+      doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134"""
+
+    main()
+
+    var x = @["4"]
+    let m = toTask hello(2233, x, 7)
+    m.invoke()
+
+    doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134x=2233 y=@["4"] d=7"""
+
+    let n = toTask ok()
+    n.invoke()
+
+    doAssert temp == "ok"
+
+  block:
+    var called = 0
+    block:
+      proc hello() =
+        inc called
+
+      let a = toTask hello()
+      invoke(a)
+
+    doAssert called == 1
+
+    block:
+      proc hello(a: int) =
+        inc called, a
+
+      let b = toTask hello(13)
+      let c = toTask hello(a = 14)
+      b.invoke()
+      c.invoke()
+
+    doAssert called == 28
+
+    block:
+      proc hello(a: int, c: int) =
+        inc called, a
+
+      let b = toTask hello(c = 0, a = 8)
+      b.invoke()
+
+    doAssert called == 36
+
+  block:
+    proc returnsSomething(a, b: int): int = a + b
+
+    proc noArgsButReturnsSomething(): string = "abcdef"
+
+    proc testReturnValues() =
+      let t = toTask returnsSomething(2233, 11)
+      var res: int
+      t.invoke(addr res)
+      doAssert res == 2233+11
+
+      let tb = toTask noArgsButReturnsSomething()
+      var resB: string
+      tb.invoke(addr resB)
+      doAssert resB == "abcdef"
+
+    testReturnValues()
+
+
+block: # bug #23635
+  block:
+    type
+      Store = object
+        run: proc (a: int) {.nimcall, gcsafe.}
+
+    block:
+      var count = 0
+      proc hello(a: int) =
+        inc count, a
+
+      var store = Store()
+      store.run = hello
+
+      let b = toTask store.run(13)
+      b.invoke()
+      doAssert count == 13
+
+  block:
+    type
+      Store = object
+        run: proc () {.nimcall, gcsafe.}
+
+    block:
+      var count = 0
+      proc hello() =
+        inc count, 1
+
+      var store = Store()
+      store.run = hello
+
+      let b = toTask store.run()
+      b.invoke()
+      doAssert count == 1
diff --git a/tests/stdlib/ttempfiles.nim b/tests/stdlib/ttempfiles.nim
new file mode 100644
index 000000000..352788c42
--- /dev/null
+++ b/tests/stdlib/ttempfiles.nim
@@ -0,0 +1,51 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false # not strictly necessary
+"""
+
+import std/tempfiles
+import std/[os, nre]
+import std/[assertions, syncio]
+
+const
+  prefix = "D20210502T100442" # safety precaution to only affect files/dirs with this prefix
+  suffix = ".tmp"
+
+block:
+  var t1 = createTempFile(prefix, suffix)
+  var t2 = createTempFile(prefix, suffix)
+  defer:
+    close(t1.cfile)
+    close(t2.cfile)
+    removeFile(t1.path)
+    removeFile(t2.path)
+
+  doAssert t1.path != t2.path
+
+  let s = "1234"
+  write(t1.cfile, s)
+  doAssert readAll(t2.cfile) == ""
+  doAssert readAll(t1.cfile) == ""
+  t1.cfile.setFilePos 0
+  doAssert readAll(t1.cfile) == s
+
+block: # createTempDir
+  doAssertRaises(OSError): discard createTempDir(prefix, suffix, "nonexistent")
+
+  block:
+    let dir1 = createTempDir(prefix, suffix)
+    let dir2 = createTempDir(prefix, suffix)
+    defer:
+      removeDir(dir1)
+      removeDir(dir2)
+    doAssert dir1 != dir2
+
+    doAssert dirExists(dir1)
+    doAssert dir1.lastPathPart.contains(re"^D20210502T100442(\w+).tmp$")
+    doAssert dir1.parentDir == getTempDir().normalizePathEnd()
+
+  block:
+    let dir3 = createTempDir(prefix, "_mytmp", ".")
+    doAssert dir3.lastPathPart.contains(re"^D20210502T100442(\w+)_mytmp$")
+    doAssert dir3.parentDir == "." # not getCurrentDir(): we honor the absolute/relative state of input `dir`
+    removeDir(dir3)
diff --git a/tests/stdlib/tterminal.nim b/tests/stdlib/tterminal.nim
new file mode 100644
index 000000000..16365e71c
--- /dev/null
+++ b/tests/stdlib/tterminal.nim
@@ -0,0 +1,7 @@
+discard """
+  action: compile
+"""
+import terminal, colors
+
+styledEcho fgColor, colRed, "Test"
+styledEcho bgColor, colBlue, "Test"
diff --git a/tests/stdlib/tterminal_12759.nim b/tests/stdlib/tterminal_12759.nim
new file mode 100644
index 000000000..e9ea3127c
--- /dev/null
+++ b/tests/stdlib/tterminal_12759.nim
@@ -0,0 +1,11 @@
+discard """
+  action: "compile"
+"""
+
+import terminal
+import std/syncio
+
+proc test() {.raises:[IOError, ValueError].} =
+  setBackgroundColor(stdout, bgRed)
+
+test()
diff --git a/tests/stdlib/tterminal_15874.nim b/tests/stdlib/tterminal_15874.nim
new file mode 100644
index 000000000..c3455c350
--- /dev/null
+++ b/tests/stdlib/tterminal_15874.nim
@@ -0,0 +1,8 @@
+discard """
+  cmd: "nim c --app:console $file"
+  action: "compile"
+"""
+
+import terminal
+
+writeStyled("hello", {styleBright})
diff --git a/tests/stdlib/ttestutils.nim b/tests/stdlib/ttestutils.nim
new file mode 100644
index 000000000..0f8bf16cf
--- /dev/null
+++ b/tests/stdlib/ttestutils.nim
@@ -0,0 +1,40 @@
+import stdtest/testutils
+import std/assertions
+
+block: # assertAll
+  assertAll:
+    1+1 == 2
+    var a = 3
+    a == 3
+
+  doAssertRaises(AssertionDefect):
+    assertAll:
+      1+1 == 2
+      var a = 3
+      a == 4
+
+block: # greedyOrderedSubsetLines
+  assertAll:
+    greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4")
+    not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order
+    not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs
+
+    not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5")
+    not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix")
+    not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5")
+    not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix")
+
+block: # greedyOrderedSubsetLines with allowPrefixMatch = true
+  template fn(a, b): bool =
+    greedyOrderedSubsetLines(a, b, allowPrefixMatch = true)
+  assertAll:
+    fn("a1\na3", "a0\na1\na2\na3_suffix\na4")
+    not fn("a1\na3", "a0\na1\na2\nprefix_a3\na4")
+    # these are same as above, could be refactored
+    not fn("a3\na1", "a0\na1\na2\na3\na4") # out of order
+    not fn("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs
+
+    not fn("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5")
+    fn("a1\na5", "a0\na1\na2\na3\na4\na5:suffix")
+    not fn("a5", "a0\na1\na2\na3\na4\nprefix:a5")
+    fn("a5", "a0\na1\na2\na3\na4\na5:suffix")
diff --git a/tests/stdlib/tthreadpool.nim b/tests/stdlib/tthreadpool.nim
new file mode 100644
index 000000000..1947074be
--- /dev/null
+++ b/tests/stdlib/tthreadpool.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+  disabled: "freebsd"
+  output: "42"
+"""
+import std/assertions
+from std/threadpool import spawn, `^`, sync
+block: # bug #12005
+  proc doworkok(i: int) {.thread.} = echo i
+  spawn(doworkok(42))
+  sync() # this works when returning void!
+
+  proc doworkbad(i: int): int {.thread.} = i
+  doAssert ^spawn(doworkbad(42)) == 42 # bug was here
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index 4ab3ba581..0f04168dc 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -1,123 +1,34 @@
-# test the new time module
 discard """
-  file: "ttimes.nim"
-  output: '''[Suite] ttimes
-'''
+  matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off -d:nimStringHash2"
 """
 
-import
-  times, os, strutils, unittest
-
-# $ date --date='@2147483647'
-# Tue 19 Jan 03:14:07 GMT 2038
-
-proc checkFormat(t: DateTime, format, expected: string) =
-  let actual = t.format(format)
-  if actual != expected:
-    echo "Formatting failure!"
-    echo "expected: ", expected
-    echo "actual  : ", actual
-    doAssert false
-
-let t = fromUnix(2147483647).utc
-t.checkFormat("ddd dd MMM hh:mm:ss yyyy", "Tue 19 Jan 03:14:07 2038")
-t.checkFormat("ddd ddMMMhh:mm:ssyyyy", "Tue 19Jan03:14:072038")
-t.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
-  " ss t tt y yy yyy yyyy yyyyy z zz zzz",
-  "19 19 Tue Tuesday 3 03 3 03 14 14 1 01 Jan January 7 07 A AM 8 38 038 2038 02038 +0 +00 +00:00")
-
-t.checkFormat("yyyyMMddhhmmss", "20380119031407")
-
-# issue 7620
-let t7620_am = parse("4/15/2017 12:01:02 AM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc())
-t7620_am.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 AM +0")
-let t7620_pm = parse("4/15/2017 12:01:02 PM +0", "M/d/yyyy' 'h:mm:ss' 'tt' 'z", utc())
-t7620_pm.checkFormat("M/d/yyyy' 'h:mm:ss' 'tt' 'z", "4/15/2017 12:01:02 PM +0")
-
-let t2 = fromUnix(160070789).utc # Mon 27 Jan 16:06:29 GMT 1975
-t2.checkFormat("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
-  " ss t tt y yy yyy yyyy yyyyy z zz zzz",
-  "27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 +0 +00 +00:00")
-
-var t4 = fromUnix(876124714).utc # Mon  6 Oct 08:58:34 BST 1997
-t4.checkFormat("M MM MMM MMMM", "10 10 Oct October")
-
-# Interval tests
-(t4 - initTimeInterval(years = 2)).checkFormat("yyyy", "1995")
-(t4 - initTimeInterval(years = 7, minutes = 34, seconds = 24)).checkFormat("yyyy mm ss", "1990 24 10")
-
-# checking dayOfWeek matches known days
-doAssert getDayOfWeek(01, mJan, 0000) == dSat
-doAssert getDayOfWeek(01, mJan, -0023) == dSat
-doAssert getDayOfWeek(21, mSep, 1900) == dFri
-doAssert getDayOfWeek(01, mJan, 1970) == dThu
-doAssert getDayOfWeek(21, mSep, 1970) == dMon
-doAssert getDayOfWeek(01, mJan, 2000) == dSat
-doAssert getDayOfWeek(01, mJan, 2021) == dFri
-
-# toUnix tests with GM timezone
-let t4L = fromUnix(876124714).utc
-doAssert toUnix(toTime(t4L)) == 876124714
-doAssert toUnix(toTime(t4L)) + t4L.utcOffset == toUnix(toTime(t4))
-
-# adding intervals
-var
-  a1L = toUnix(toTime(t4L + initTimeInterval(hours = 1))) + t4L.utcOffset
-  a1G = toUnix(toTime(t4)) + 60 * 60
-doAssert a1L == a1G
-
-# subtracting intervals
-a1L = toUnix(toTime(t4L - initTimeInterval(hours = 1))) + t4L.utcOffset
-a1G = toUnix(toTime(t4)) - (60 * 60)
-doAssert a1L == a1G
-
-# Comparison between Time objects should be detected by compiler
-# as 'noSideEffect'.
-proc cmpTimeNoSideEffect(t1: Time, t2: Time): bool {.noSideEffect.} =
-  result = t1 == t2
-doAssert cmpTimeNoSideEffect(0.fromUnix, 0.fromUnix)
-# Additionally `==` generic for seq[T] has explicit 'noSideEffect' pragma
-# so we can check above condition by comparing seq[Time] sequences
-let seqA: seq[Time] = @[]
-let seqB: seq[Time] = @[]
-doAssert seqA == seqB
-
-for tz in [
-    (0, "+0", "+00", "+00:00"), # UTC
-    (-3600, "+1", "+01", "+01:00"), # CET
-    (-39600, "+11", "+11", "+11:00"), # two digits
-    (-1800, "+0", "+00", "+00:30"), # half an hour
-    (7200, "-2", "-02", "-02:00"), # positive
-    (38700, "-10", "-10", "-10:45")]: # positive with three quaters hour
-  let ti = DateTime(month: mJan, monthday: 1, utcOffset: tz[0])
-  doAssert ti.format("z") == tz[1]
-  doAssert ti.format("zz") == tz[2]
-  doAssert ti.format("zzz") == tz[3]
-
-block countLeapYears:
-  # 1920, 2004 and 2020 are leap years, and should be counted starting at the following year
-  doAssert countLeapYears(1920) + 1 == countLeapYears(1921)
-  doAssert countLeapYears(2004) + 1 == countLeapYears(2005)
-  doAssert countLeapYears(2020) + 1 == countLeapYears(2021)
-
-block timezoneConversion:
-  var l = now()
-  let u = l.utc
-  l = u.local
-
-  doAssert l.timezone == local()
-  doAssert u.timezone == utc()
+import times, strutils, unittest
+import std/assertions
+
+when not defined(js):
+  import os
+
+proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} =
+  let offset = hours * 3600 + minutes * 60 + seconds
+
+  proc zonedTimeFromAdjTime(adjTime: Time): ZonedTime =
+    result.isDst = false
+    result.utcOffset = offset
+    result.time = adjTime + initDuration(seconds = offset)
+
+  proc zonedTimeFromTime(time: Time): ZonedTime =
+    result.isDst = false
+    result.utcOffset = offset
+    result.time = time
+
+  newTimezone("", zonedTimeFromTime, zonedTimeFromAdjTime)
 
 template parseTest(s, f, sExpected: string, ydExpected: int) =
   let
     parsed = s.parse(f, utc())
     parsedStr = $parsed
   check parsedStr == sExpected
-  if parsed.yearday != ydExpected:
-    echo s
-    echo parsed.repr
-    echo parsed.yearday, " exp: ", ydExpected
-  check(parsed.yearday == ydExpected)
+  check parsed.yearday == ydExpected
 
 template parseTestExcp(s, f: string) =
   expect ValueError:
@@ -130,55 +41,60 @@ template parseTestTimeOnly(s, f, sExpected: string) =
 # explicit timezone offsets in all tests.
 template runTimezoneTests() =
   parseTest("Tuesday at 09:04am on Dec 15, 2015 +0",
-      "dddd at hh:mmtt on MMM d, yyyy z", "2015-12-15T09:04:00+00:00", 348)
+      "dddd 'at' hh:mmtt 'on' MMM d, yyyy z", "2015-12-15T09:04:00Z", 348)
   # ANSIC       = "Mon Jan _2 15:04:05 2006"
   parseTest("Thu Jan 12 15:04:05 2006 +0", "ddd MMM dd HH:mm:ss yyyy z",
-      "2006-01-12T15:04:05+00:00", 11)
+      "2006-01-12T15:04:05Z", 11)
   # UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
   parseTest("Thu Jan 12 15:04:05 2006 +0", "ddd MMM dd HH:mm:ss yyyy z",
-      "2006-01-12T15:04:05+00:00", 11)
+      "2006-01-12T15:04:05Z", 11)
   # RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
   parseTest("Mon Feb 29 15:04:05 -07:00 2016 +0", "ddd MMM dd HH:mm:ss zzz yyyy z",
-      "2016-02-29T15:04:05+00:00", 59) # leap day
+      "2016-02-29T15:04:05Z", 59) # leap day
   # RFC822      = "02 Jan 06 15:04 MST"
   parseTest("12 Jan 16 15:04 +0", "dd MMM yy HH:mm z",
-      "2016-01-12T15:04:00+00:00", 11)
+      "2016-01-12T15:04:00Z", 11)
   # RFC822Z     = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
   parseTest("01 Mar 16 15:04 -07:00", "dd MMM yy HH:mm zzz",
-      "2016-03-01T22:04:00+00:00", 60) # day after february in leap year
+      "2016-03-01T22:04:00Z", 60) # day after february in leap year
   # RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
   parseTest("Monday, 12-Jan-06 15:04:05 +0", "dddd, dd-MMM-yy HH:mm:ss z",
-      "2006-01-12T15:04:05+00:00", 11)
+      "2006-01-12T15:04:05Z", 11)
   # RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
   parseTest("Sun, 01 Mar 2015 15:04:05 +0", "ddd, dd MMM yyyy HH:mm:ss z",
-      "2015-03-01T15:04:05+00:00", 59) # day after february in non-leap year
+      "2015-03-01T15:04:05Z", 59) # day after february in non-leap year
   # RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
   parseTest("Thu, 12 Jan 2006 15:04:05 -07:00", "ddd, dd MMM yyyy HH:mm:ss zzz",
-      "2006-01-12T22:04:05+00:00", 11)
+      "2006-01-12T22:04:05Z", 11)
   # RFC3339     = "2006-01-02T15:04:05Z07:00"
-  parseTest("2006-01-12T15:04:05Z-07:00", "yyyy-MM-ddTHH:mm:ssZzzz",
-      "2006-01-12T22:04:05+00:00", 11)
   parseTest("2006-01-12T15:04:05Z-07:00", "yyyy-MM-dd'T'HH:mm:ss'Z'zzz",
-      "2006-01-12T22:04:05+00:00", 11)
+      "2006-01-12T22:04:05Z", 11)
   # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
   parseTest("2006-01-12T15:04:05.999999999Z-07:00",
-      "yyyy-MM-ddTHH:mm:ss.999999999Zzzz", "2006-01-12T22:04:05+00:00", 11)
+      "yyyy-MM-dd'T'HH:mm:ss.'999999999Z'zzz", "2006-01-12T22:04:05Z", 11)
   for tzFormat in ["z", "zz", "zzz"]:
     # formatting timezone as 'Z' for UTC
     parseTest("2001-01-12T22:04:05Z", "yyyy-MM-dd'T'HH:mm:ss" & tzFormat,
-        "2001-01-12T22:04:05+00:00", 11)
+        "2001-01-12T22:04:05Z", 11)
+  # timezone offset formats
+  parseTest("2001-01-12T15:04:05 +7", "yyyy-MM-dd'T'HH:mm:ss z",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07", "yyyy-MM-dd'T'HH:mm:ss zz",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07:00", "yyyy-MM-dd'T'HH:mm:ss zzz",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07:30:59", "yyyy-MM-dd'T'HH:mm:ss zzzz",
+      "2001-01-12T07:33:06Z", 11)
+  parseTest("2001-01-12T15:04:05 +0700", "yyyy-MM-dd'T'HH:mm:ss ZZZ",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +073059", "yyyy-MM-dd'T'HH:mm:ss ZZZZ",
+      "2001-01-12T07:33:06Z", 11)
   # Kitchen     = "3:04PM"
   parseTestTimeOnly("3:04PM", "h:mmtt", "15:04:00")
-  #when not defined(testing):
-  #  echo "Kitchen: " & $s.parse(f)
-  #  var ti = timeToTimeInfo(getTime())
-  #  echo "Todays date after decoding: ", ti
-  #  var tint = timeToTimeInterval(getTime())
-  #  echo "Todays date after decoding to interval: ", tint
 
   # Bug with parse not setting DST properly if the current local DST differs from
   # the date being parsed. Need to test parse dates both in and out of DST. We
-  # are testing that be relying on the fact that tranforming a TimeInfo to a Time
+  # are testing that be relying on the fact that transforming a TimeInfo to a Time
   # and back again will correctly set the DST value. With the incorrect parse
   # behavior this will introduce a one hour offset from the named time and the
   # parsed time if the DST value differs between the current time and the date we
@@ -195,48 +111,65 @@ template runTimezoneTests() =
     let
       parsedJan = parse("2016-01-05 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz")
       parsedJul = parse("2016-07-01 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz")
-    doAssert toTime(parsedJan).toUnix == 1451962800
-    doAssert toTime(parsedJul).toUnix == 1467342000
+    check toTime(parsedJan).toUnix == 1451962800
+    check toTime(parsedJul).toUnix == 1467342000
+
+template usingTimezone(tz: string, body: untyped) =
+  when defined(linux) or defined(macosx):
+    let oldZone = getEnv("TZ")
+    putEnv("TZ", tz)
+    body
+    putEnv("TZ", oldZone)
 
-suite "ttimes":
+block: # ttimes
 
   # Generate tests for multiple timezone files where available
   # Set the TZ env var for each test
-  when defined(Linux) or defined(macosx):
-    const tz_dir = "/usr/share/zoneinfo"
+  when defined(linux) or defined(macosx):
+    let tz_dir = getEnv("TZDIR", "/usr/share/zoneinfo")
     const f = "yyyy-MM-dd HH:mm zzz"
-    
-    let orig_tz = getEnv("TZ")
+
     var tz_cnt = 0
-    for tz_fn in walkFiles(tz_dir & "/**/*"):
-      if symlinkExists(tz_fn) or tz_fn.endsWith(".tab") or
-          tz_fn.endsWith(".list"):
+    for timezone in walkFiles(tz_dir & "/**/*"):
+      if symlinkExists(timezone) or timezone.endsWith(".tab") or
+          timezone.endsWith(".list"):
         continue
 
-      test "test for " & tz_fn:
-        tz_cnt.inc
-        putEnv("TZ", tz_fn)
-        runTimezoneTests()
+      usingTimezone(timezone):
+        test "test for " & timezone:
+          tz_cnt.inc
+          runTimezoneTests()
 
     test "enough timezone files tested":
       check tz_cnt > 10
 
-    test "dst handling":
-      putEnv("TZ", "Europe/Stockholm")
-      # In case of an impossible time, the time is moved to after the impossible time period
-      check initDateTime(26, mMar, 2017, 02, 30, 00).format(f) == "2017-03-26 03:30 +02:00"
-      # In case of an ambiguous time, the earlier time is choosen
-      check initDateTime(29, mOct, 2017, 02, 00, 00).format(f) == "2017-10-29 02:00 +02:00"
+  else:
+    # not on Linux or macosx: run in the local timezone only
+    test "parseTest":
+      runTimezoneTests()
+
+  block: # dst handling
+    usingTimezone("Europe/Stockholm"):
+      # In case of an impossible time, the time is moved to after the
+      # impossible time period
+      check initDateTime(26, mMar, 2017, 02, 30, 00).format(f) ==
+        "2017-03-26 03:30 +02:00"
+      # In case of an ambiguous time, the earlier time is chosen
+      check initDateTime(29, mOct, 2017, 02, 00, 00).format(f) ==
+        "2017-10-29 02:00 +02:00"
       # These are just dates on either side of the dst switch
-      check initDateTime(29, mOct, 2017, 01, 00, 00).format(f) == "2017-10-29 01:00 +02:00"
+      check initDateTime(29, mOct, 2017, 01, 00, 00).format(f) ==
+        "2017-10-29 01:00 +02:00"
       check initDateTime(29, mOct, 2017, 01, 00, 00).isDst
-      check initDateTime(29, mOct, 2017, 03, 01, 00).format(f) == "2017-10-29 03:01 +01:00"
+      check initDateTime(29, mOct, 2017, 03, 01, 00).format(f) ==
+        "2017-10-29 03:01 +01:00"
       check (not initDateTime(29, mOct, 2017, 03, 01, 00).isDst)
-      
-      check initDateTime(21, mOct, 2017, 01, 00, 00).format(f) == "2017-10-21 01:00 +02:00"
 
-    test "issue #6520":
-      putEnv("TZ", "Europe/Stockholm")
+      check initDateTime(21, mOct, 2017, 01, 00, 00).format(f) ==
+        "2017-10-21 01:00 +02:00"
+
+  block: # issue #6520
+    usingTimezone("Europe/Stockholm"):
       var local = fromUnix(1469275200).local
       var utc = fromUnix(1469275200).utc
 
@@ -244,128 +177,138 @@ suite "ttimes":
       local.utcOffset = 0
       check claimedOffset == utc.toTime - local.toTime
 
-    test "issue #5704":
-      putEnv("TZ", "Asia/Seoul")
-      let diff = parse("19700101-000000", "yyyyMMdd-hhmmss").toTime - parse("19000101-000000", "yyyyMMdd-hhmmss").toTime
+  block: # issue #5704
+    usingTimezone("Asia/Seoul"):
+      let diff = parse("19700101-000000", "yyyyMMdd-hhmmss").toTime -
+        parse("19000101-000000", "yyyyMMdd-hhmmss").toTime
       check diff == initDuration(seconds = 2208986872)
 
-    test "issue #6465":
-      putEnv("TZ", "Europe/Stockholm")      
+  block: # issue #6465
+    usingTimezone("Europe/Stockholm"):
       let dt = parse("2017-03-25 12:00", "yyyy-MM-dd hh:mm")
       check $(dt + initTimeInterval(days = 1)) == "2017-03-26T12:00:00+02:00"
-      check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00"      
-
-    test "datetime before epoch":
-      check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52+00:00"
-
-    test "adding/subtracting time across dst":
-      putenv("TZ", "Europe/Stockholm")
+      check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00"
 
+  block: # adding/subtracting time across dst
+    usingTimezone("Europe/Stockholm"):
       let dt1 = initDateTime(26, mMar, 2017, 03, 00, 00)
       check $(dt1 - 1.seconds) == "2017-03-26T01:59:59+01:00"
 
       var dt2 = initDateTime(29, mOct, 2017, 02, 59, 59)
       check  $(dt2 + 1.seconds) == "2017-10-29T02:00:00+01:00"
 
-    putEnv("TZ", orig_tz)
+  block: # datetime before epoch
+    check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52Z"
 
-  else:
-    # not on Linux or macosx: run in the local timezone only
-    test "parseTest":
-      runTimezoneTests()
-
-  test "incorrect inputs: empty string":
+  block: # incorrect inputs: empty string
     parseTestExcp("", "yyyy-MM-dd")
 
-  test "incorrect inputs: year":
+  block: # incorrect inputs: year
     parseTestExcp("20-02-19", "yyyy-MM-dd")
 
-  test "incorrect inputs: month number":
+  block: # incorrect inputs: month number
     parseTestExcp("2018-2-19", "yyyy-MM-dd")
 
-  test "incorrect inputs: month name":
+  block: # incorrect inputs: month name
     parseTestExcp("2018-Fe", "yyyy-MMM-dd")
 
-  test "incorrect inputs: day":
+  block: # incorrect inputs: day
     parseTestExcp("2018-02-1", "yyyy-MM-dd")
 
-  test "incorrect inputs: day of week":
+  block: # incorrect inputs: day of week
     parseTestExcp("2018-Feb-Mo", "yyyy-MMM-ddd")
 
-  test "incorrect inputs: hour":
+  block: # incorrect inputs: hour
     parseTestExcp("2018-02-19 1:30", "yyyy-MM-dd hh:mm")
 
-  test "incorrect inputs: minute":
+  block: # incorrect inputs: minute
     parseTestExcp("2018-02-19 16:3", "yyyy-MM-dd hh:mm")
 
-  test "incorrect inputs: second":
+  block: # incorrect inputs: second
     parseTestExcp("2018-02-19 16:30:0", "yyyy-MM-dd hh:mm:ss")
 
-  test "incorrect inputs: timezone (z)":
+  block: # incorrect inputs: timezone (z)
     parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss z")
 
-  test "incorrect inputs: timezone (zz) 1":
+  block: # incorrect inputs: timezone (zz) 1
     parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zz")
 
-  test "incorrect inputs: timezone (zz) 2":
+  block: # incorrect inputs: timezone (zz) 2
     parseTestExcp("2018-02-19 16:30:00 +1", "yyyy-MM-dd hh:mm:ss zz")
 
-  test "incorrect inputs: timezone (zzz) 1":
+  block: # incorrect inputs: timezone (zzz) 1
     parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zzz")
 
-  test "incorrect inputs: timezone (zzz) 2":
+  block: # incorrect inputs: timezone (zzz) 2
     parseTestExcp("2018-02-19 16:30:00 +01:", "yyyy-MM-dd hh:mm:ss zzz")
 
-  test "incorrect inputs: timezone (zzz) 3":
+  block: # incorrect inputs: timezone (zzz) 3
     parseTestExcp("2018-02-19 16:30:00 +01:0", "yyyy-MM-dd hh:mm:ss zzz")
 
-  test "dynamic timezone":
-    proc staticOffset(offset: int): Timezone =
-      proc zoneInfoFromTz(adjTime: Time): ZonedTime =
-          result.isDst = false
-          result.utcOffset = offset
-          result.adjTime = adjTime
-
-      proc zoneInfoFromUtc(time: Time): ZonedTime =
-          result.isDst = false
-          result.utcOffset = offset
-          result.adjTime = fromUnix(time.toUnix - offset)
-
-      result.name = ""
-      result.zoneInfoFromTz = zoneInfoFromTz
-      result.zoneInfoFromUtc = zoneInfoFromUtc
-
-    let tz = staticOffset(-9000)
+  block: # incorrect inputs: year (yyyy/uuuu)
+    parseTestExcp("-0001", "yyyy")
+    parseTestExcp("-0001", "YYYY")
+    parseTestExcp("1", "yyyy")
+    parseTestExcp("12345", "yyyy")
+    parseTestExcp("1", "uuuu")
+    parseTestExcp("12345", "uuuu")
+    parseTestExcp("-1 BC", "UUUU g")
+
+  block: # incorrect inputs: invalid sign
+    parseTestExcp("+1", "YYYY")
+    parseTestExcp("+1", "dd")
+    parseTestExcp("+1", "MM")
+    parseTestExcp("+1", "hh")
+    parseTestExcp("+1", "mm")
+    parseTestExcp("+1", "ss")
+
+  block: # _ as a separator
+    discard parse("2000_01_01", "YYYY'_'MM'_'dd")
+
+  block: # dynamic timezone
+    let tz = staticTz(seconds = -9000)
     let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz)
     check dt.utcOffset == -9000
     check dt.isDst == false
     check $dt == "2000-01-01T12:00:00+02:30"
-    check $dt.utc == "2000-01-01T09:30:00+00:00"
+    check $dt.utc == "2000-01-01T09:30:00Z"
     check $dt.utc.inZone(tz) == $dt
 
-  test "isLeapYear":
+  block: # isLeapYear
     check isLeapYear(2016)
     check (not isLeapYear(2015))
     check isLeapYear(2000)
     check (not isLeapYear(1900))
 
-  test "subtract months":
+  block: # TimeInterval
+    let t = fromUnix(876124714).utc # Mon 6 Oct 08:58:34 BST 1997
+    # Interval tests
+    let t2 = t - 2.years
+    check t2.year == 1995
+    let t3 = (t - 7.years - 34.minutes - 24.seconds)
+    check t3.year == 1990
+    check t3.minute == 24
+    check t3.second == 10
+    check (t + 1.hours).toTime.toUnix == t.toTime.toUnix + 60 * 60
+    check (t - 1.hours).toTime.toUnix == t.toTime.toUnix - 60 * 60
+
+  block: # TimeInterval - months
     var dt = initDateTime(1, mFeb, 2017, 00, 00, 00, utc())
-    check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00+00:00"
+    check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00Z"
     dt = initDateTime(15, mMar, 2017, 00, 00, 00, utc())
-    check $(dt - initTimeInterval(months = 1)) == "2017-02-15T00:00:00+00:00"
+    check $(dt - initTimeInterval(months = 1)) == "2017-02-15T00:00:00Z"
     dt = initDateTime(31, mMar, 2017, 00, 00, 00, utc())
     # This happens due to monthday overflow. It's consistent with Phobos.
-    check $(dt - initTimeInterval(months = 1)) == "2017-03-03T00:00:00+00:00"
+    check $(dt - initTimeInterval(months = 1)) == "2017-03-03T00:00:00Z"
 
-  test "duration":
+  block: # duration
     let d = initDuration
     check d(hours = 48) + d(days = 5) == d(weeks = 1)
     let dt = initDateTime(01, mFeb, 2000, 00, 00, 00, 0, utc()) + d(milliseconds = 1)
     check dt.nanosecond == convert(Milliseconds, Nanoseconds, 1)
     check d(seconds = 1, milliseconds = 500) * 2 == d(seconds = 3)
     check d(seconds = 3) div 2 == d(seconds = 1, milliseconds = 500)
-    check d(milliseconds = 1001).seconds == 1
+    check d(milliseconds = 1001).inSeconds == 1
     check d(seconds = 1, milliseconds = 500) - d(milliseconds = 1250) ==
       d(milliseconds = 250)
     check d(seconds = 1, milliseconds = 1) < d(seconds = 1, milliseconds = 2)
@@ -378,19 +321,19 @@ suite "ttimes":
     check (initDuration(seconds = 1, nanoseconds = 3) <=
       initDuration(seconds = 1, nanoseconds = 1)).not
 
-  test "large/small dates":
+  block: # large/small dates
     discard initDateTime(1, mJan, -35_000, 12, 00, 00, utc())
     # with local tz
     discard initDateTime(1, mJan, -35_000, 12, 00, 00)
     discard initDateTime(1, mJan,  35_000, 12, 00, 00)
     # with duration/timeinterval
-    let dt = initDateTime(1, mJan,  35_000, 12, 00, 00, utc()) +
+    let dt = initDateTime(1, mJan, -35_000, 12, 00, 00, utc()) +
       initDuration(seconds = 1)
     check dt.second == 1
     let dt2 = dt + 35_001.years
-    check $dt2 == "0001-01-01T12:00:01+00:00"
+    check $dt2 == "0001-01-01T12:00:01Z"
 
-  test "compare datetimes":
+  block: # compare datetimes
     var dt1 = now()
     var dt2 = dt1
     check dt1 == dt2
@@ -398,32 +341,444 @@ suite "ttimes":
     dt2 = dt2 + 1.seconds
     check dt1 < dt2
 
-  test "adding/subtracting TimeInterval":
+  block: # adding/subtracting TimeInterval
     # add/subtract TimeIntervals and Time/TimeInfo
     let now = getTime().utc
+    let isSpecial = now.isLeapDay
     check now + convert(Seconds, Nanoseconds, 1).nanoseconds == now + 1.seconds
     check now + 1.weeks == now + 7.days
     check now - 1.seconds == now - 3.seconds + 2.seconds
     check now + 65.seconds == now + 1.minutes + 5.seconds
     check now + 60.minutes == now + 1.hours
     check now + 24.hours == now + 1.days
-    check now + 13.months == now + 1.years + 1.months
+    if not isSpecial:
+      check now + 13.months == now + 1.years + 1.months
     check toUnix(fromUnix(0) + 2.seconds) == 2
     check toUnix(fromUnix(0) - 2.seconds) == -2
     var ti1 = now + 1.years
     ti1 = ti1 - 1.years
-    check ti1 == now
+    if not isSpecial:
+      check ti1 == now
     ti1 = ti1 + 1.days
-    check ti1 == now + 1.days
+    if not isSpecial:
+      check ti1 == now + 1.days
 
     # Bug with adding a day to a Time
     let day = 24.hours
     let tomorrow = now + day
     check tomorrow - now == initDuration(days = 1)
-  
-  test "fromWinTime/toWinTime":
-    check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0
-    check (-1).fromWinTime.nanosecond == convert(Seconds, Nanoseconds, 1) - 100
-    check -1.fromWinTime.toWinTime == -1
-    # One nanosecond is discarded due to differences in time resolution
-    check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100 
\ No newline at end of file
+
+  # Disabled for JS because it fails due to precision errors
+  # (The JS target uses float64 for int64).
+  when not defined(js):
+    test "fromWinTime/toWinTime":
+      check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0
+      check (-1).fromWinTime.nanosecond == convert(Seconds, Nanoseconds, 1) - 100
+      check (-1).fromWinTime.toWinTime == -1
+      # One nanosecond is discarded due to differences in time resolution
+      check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
+      check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
+
+  block: # issue 7620
+    let layout = "M/d/yyyy' 'h:mm:ss' 'tt' 'z"
+    let t7620_am = parse("4/15/2017 12:01:02 AM +0", layout, utc())
+    check t7620_am.format(layout) == "4/15/2017 12:01:02 AM Z"
+    let t7620_pm = parse("4/15/2017 12:01:02 PM +0", layout, utc())
+    check t7620_pm.format(layout) == "4/15/2017 12:01:02 PM Z"
+
+  block: # format
+    var dt = initDateTime(1, mJan, -0001,
+                          17, 01, 02, 123_456_789,
+                          staticTz(hours = 1, minutes = 2, seconds = 3))
+    check dt.format("d") == "1"
+    check dt.format("dd") == "01"
+    check dt.format("ddd") == "Fri"
+    check dt.format("dddd") == "Friday"
+    check dt.format("h") == "5"
+    check dt.format("hh") == "05"
+    check dt.format("H") == "17"
+    check dt.format("HH") == "17"
+    check dt.format("m") == "1"
+    check dt.format("mm") == "01"
+    check dt.format("M") == "1"
+    check dt.format("MM") == "01"
+    check dt.format("MMM") == "Jan"
+    check dt.format("MMMM") == "January"
+    check dt.format("s") == "2"
+    check dt.format("ss") == "02"
+    check dt.format("t") == "P"
+    check dt.format("tt") == "PM"
+    check dt.format("yy") == "02"
+    check dt.format("yyyy") == "0002"
+    check dt.format("YYYY") == "2"
+    check dt.format("uuuu") == "-0001"
+    check dt.format("UUUU") == "-1"
+    check dt.format("z") == "-1"
+    check dt.format("zz") == "-01"
+    check dt.format("zzz") == "-01:02"
+    check dt.format("zzzz") == "-01:02:03"
+    check dt.format("g") == "BC"
+
+    check dt.format("fff") == "123"
+    check dt.format("ffffff") == "123456"
+    check dt.format("fffffffff") == "123456789"
+    dt.nanosecond = 1
+    check dt.format("fff") == "000"
+    check dt.format("ffffff") == "000000"
+    check dt.format("fffffffff") == "000000001"
+
+    dt.year = 12345
+    check dt.format("yyyy") == "+12345"
+    check dt.format("uuuu") == "+12345"
+    dt.year = -12345
+    check dt.format("yyyy") == "+12346"
+    check dt.format("uuuu") == "-12345"
+
+    expect ValueError:
+      discard initTimeFormat("'")
+
+    expect ValueError:
+      discard initTimeFormat("'foo")
+
+    expect ValueError:
+      discard initTimeFormat("foo'")
+
+    for tz in [
+        (staticTz(seconds = 0), "+0", "+00", "+00:00"), # UTC
+        (staticTz(seconds = -3600), "+1", "+01", "+01:00"), # CET
+        (staticTz(seconds = -39600), "+11", "+11", "+11:00"), # two digits
+        (staticTz(seconds = -1800), "+0", "+00", "+00:30"), # half an hour
+        (staticTz(seconds = 7200), "-2", "-02", "-02:00"), # positive
+        (staticTz(seconds = 38700), "-10", "-10", "-10:45")]: # positive with three quaters hour
+      let dt = initDateTime(1, mJan, 2000, 00, 00, 00, tz[0])
+      doAssert dt.format("z") == tz[1]
+      doAssert dt.format("zz") == tz[2]
+      doAssert dt.format("zzz") == tz[3]
+
+  block: # format locale
+    let loc = DateTimeLocale(
+      MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"],
+      MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"],
+      ddd: ["Red", "Ora.", "Yel.", "Gre.", "Blu.", "Vio.", "Whi."],
+      dddd: ["Red", "Orange", "Yellow", "Green", "Blue", "Violet", "White"],
+    )
+    var dt = initDateTime(5, mJan, 2010, 17, 01, 02, utc())
+    check dt.format("d", loc) == "5"
+    check dt.format("dd", loc) == "05"
+    check dt.format("ddd", loc) == "Ora."
+    check dt.format("dddd", loc) == "Orange"
+    check dt.format("M", loc) == "1"
+    check dt.format("MM", loc) == "01"
+    check dt.format("MMM", loc) == "Fir"
+    check dt.format("MMMM", loc) == "Firsty"
+
+  block: # parse
+    check $parse("20180101", "yyyyMMdd", utc()) == "2018-01-01T00:00:00Z"
+    parseTestExcp("+120180101", "yyyyMMdd")
+
+    check parse("1", "YYYY", utc()).year == 1
+    check parse("1 BC", "YYYY g", utc()).year == 0
+    check parse("0001 BC", "yyyy g", utc()).year == 0
+    check parse("+12345 BC", "yyyy g", utc()).year == -12344
+    check parse("1 AD", "YYYY g", utc()).year == 1
+    check parse("0001 AD", "yyyy g", utc()).year == 1
+    check parse("+12345 AD", "yyyy g", utc()).year == 12345
+
+    check parse("-1", "UUUU", utc()).year == -1
+    check parse("-0001", "uuuu", utc()).year == -1
+
+    discard parse("foobar", "'foobar'")
+    discard parse("foo'bar", "'foo''''bar'")
+    discard parse("'", "''")
+
+    parseTestExcp("2000 A", "yyyy g")
+
+  block: # parse locale
+    let loc = DateTimeLocale(
+      MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"],
+      MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"],
+      ddd: ["Red", "Ora.", "Yel.", "Gre.", "Blu.", "Vio.", "Whi."],
+      dddd: ["Red", "Orange", "Yellow", "Green", "Blue", "Violet", "White"],
+    )
+    check $parse("02 Fir 2019", "dd MMM yyyy", utc(), loc) == "2019-01-02T00:00:00Z"
+    check $parse("Fourthy 6, 2017", "MMMM d, yyyy", utc(), loc) == "2017-04-06T00:00:00Z"
+
+  block: # timezoneConversion
+    var l = now()
+    let u = l.utc
+    l = u.local
+
+    check l.timezone == local()
+    check u.timezone == utc()
+
+  block: # getDayOfWeek
+    check getDayOfWeek(01, mJan, 0000) == dSat
+    check getDayOfWeek(01, mJan, -0023) == dSat
+    check getDayOfWeek(21, mSep, 1900) == dFri
+    check getDayOfWeek(01, mJan, 1970) == dThu
+    check getDayOfWeek(21, mSep, 1970) == dMon
+    check getDayOfWeek(01, mJan, 2000) == dSat
+    check getDayOfWeek(01, mJan, 2021) == dFri
+
+  block: # between - simple
+    let x = initDateTime(10, mJan, 2018, 13, 00, 00)
+    let y = initDateTime(11, mJan, 2018, 12, 00, 00)
+    doAssert x + between(x, y) == y
+
+  block: # between - dst start
+    usingTimezone("Europe/Stockholm"):
+      let x = initDateTime(25, mMar, 2018, 00, 00, 00)
+      let y = initDateTime(25, mMar, 2018, 04, 00, 00)
+      doAssert x + between(x, y) == y
+
+  block: # between - empty interval
+    let x = now()
+    let y = x
+    doAssert x + between(x, y) == y
+
+  block: # between - dst end
+    usingTimezone("Europe/Stockholm"):
+      let x = initDateTime(27, mOct, 2018, 02, 00, 00)
+      let y = initDateTime(28, mOct, 2018, 01, 00, 00)
+      doAssert x + between(x, y) == y
+
+  block: # between - long day
+    usingTimezone("Europe/Stockholm"):
+      # This day is 25 hours long in Europe/Stockholm
+      let x = initDateTime(28, mOct, 2018, 00, 30, 00)
+      let y = initDateTime(29, mOct, 2018, 00, 00, 00)
+      doAssert between(x, y) == 24.hours + 30.minutes
+      doAssert x + between(x, y) == y
+
+  block: # between - offset change edge case
+    # This test case is important because in this case
+    # `x + between(x.utc, y.utc) == y` is not true, which is very rare.
+    usingTimezone("America/Belem"):
+      let x = initDateTime(24, mOct, 1987, 00, 00, 00)
+      let y = initDateTime(26, mOct, 1987, 23, 00, 00)
+      doAssert x + between(x, y) == y
+      doAssert y + between(y, x) == x
+
+  block: # between - all units
+    let x = initDateTime(1, mJan, 2000, 00, 00, 00, utc())
+    let ti = initTimeInterval(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
+    let y = x + ti
+    doAssert between(x, y) == ti
+    doAssert between(y, x) == -ti
+
+  block: # between - monthday overflow
+      let x = initDateTime(31, mJan, 2001, 00, 00, 00, utc())
+      let y = initDateTime(1, mMar, 2001, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+  block: # between - misc
+    block:
+      let x = initDateTime(31, mDec, 2000, 12, 00, 00, utc())
+      let y = initDateTime(01, mJan, 2001, 00, 00, 00, utc())
+      doAssert between(x, y) == 12.hours
+
+    block:
+      let x = initDateTime(31, mDec, 2000, 12, 00, 00, utc())
+      let y = initDateTime(02, mJan, 2001, 00, 00, 00, utc())
+      doAssert between(x, y) == 1.days + 12.hours
+
+    block:
+      let x = initDateTime(31, mDec, 1995, 00, 00, 00, utc())
+      let y = initDateTime(01, mFeb, 2000, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(01, mDec, 1995, 00, 00, 00, utc())
+      let y = initDateTime(31, mJan, 2000, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(31, mJan, 2000, 00, 00, 00, utc())
+      let y = initDateTime(01, mFeb, 2000, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(01, mJan, 1995, 12, 00, 00, utc())
+      let y = initDateTime(01, mFeb, 1995, 00, 00, 00, utc())
+      doAssert between(x, y) == 4.weeks + 2.days + 12.hours
+
+    block:
+      let x = initDateTime(31, mJan, 1995, 00, 00, 00, utc())
+      let y = initDateTime(10, mFeb, 1995, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(31, mJan, 1995, 00, 00, 00, utc())
+      let y = initDateTime(10, mMar, 1995, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+      doAssert between(x, y) == 1.months + 1.weeks
+
+  block: # default DateTime https://github.com/nim-lang/RFCs/issues/211
+    var num = 0
+    for ai in Month: num.inc
+    check num == 12
+
+    var a: DateTime
+    check a == DateTime.default
+    check not a.isInitialized
+    check $a == "Uninitialized DateTime"
+
+    expect(AssertionDefect): discard getDayOfWeek(a.monthday, a.month, a.year)
+    expect(AssertionDefect): discard a.toTime
+    expect(AssertionDefect): discard a.utc()
+    expect(AssertionDefect): discard a.local()
+    expect(AssertionDefect): discard a.inZone(utc())
+    expect(AssertionDefect): discard a + initDuration(seconds = 1)
+    expect(AssertionDefect): discard a + initTimeInterval(seconds = 1)
+    expect(AssertionDefect): discard a.isLeapDay
+    expect(AssertionDefect): discard a < a
+    expect(AssertionDefect): discard a <= a
+    expect(AssertionDefect): discard getDateStr(a)
+    expect(AssertionDefect): discard getClockStr(a)
+    expect(AssertionDefect): discard a.format "yyyy"
+    expect(AssertionDefect): discard a.format initTimeFormat("yyyy")
+    expect(AssertionDefect): discard between(a, a)
+
+  block: # inX procs
+    doAssert initDuration(seconds = 1).inSeconds == 1
+    doAssert initDuration(seconds = -1).inSeconds == -1
+    doAssert initDuration(seconds = -1, nanoseconds = 1).inSeconds == 0
+    doAssert initDuration(nanoseconds = -1).inSeconds == 0
+    doAssert initDuration(milliseconds = 500).inMilliseconds == 500
+    doAssert initDuration(milliseconds = -500).inMilliseconds == -500
+    doAssert initDuration(nanoseconds = -999999999).inMilliseconds == -999
+
+  block: # getIsoWeekAndYear
+    doAssert getIsoWeekAndYear(initDateTime(04, mNov, 2019, 00, 00, 00)) == (isoweek: 45.IsoWeekRange, isoyear: 2019.IsoYear)
+    doAssert initDateTime(dMon, 45, 2019.IsoYear, 00, 00, 00) == initDateTime(04, mNov, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(28, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear)
+    doAssert initDateTime(dSat, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(28, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(29, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear)
+    doAssert initDateTime(dSun, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(29, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(30, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(30, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dTue, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dWed, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(05, mApr, 2020, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 14, 2020.IsoYear, 00, 00, 00) == initDateTime(05, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(06, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(06, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(10, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dFri, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(10, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(12, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(12, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(13, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(13, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(15, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(16, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(17, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dFri, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(17, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(19, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(19, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(20, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(20, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(23, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(23, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2020, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dFri, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(03, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(03, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(04, mJan, 2021, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2021.IsoYear)
+    doAssert initDateTime(dMon, 01, 2021.IsoYear, 00, 00, 00) == initDateTime(04, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 00, 00, 00)) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear)
+    doAssert initDateTime(dMon, 05, 2021.IsoYear, 00, 00, 00) == initDateTime(01, mFeb, 2021, 00, 00, 00)
+
+    doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1))) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear)
+    doAssert initDateTime(dMon, 05, 2021.IsoYear, 01, 02, 03, 400_000_000, staticTz(hours=1)) == initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1))
+
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0001.IsoYear)
+    doAssert initDateTime(dSun, 13, 0001.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0001, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0000, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0000.IsoYear)
+    doAssert initDateTime(dSat, 13, 0000.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0000, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: (-0001).IsoYear)
+    doAssert initDateTime(dThu, 13, (-0001).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0001, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0002, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0002).IsoYear)
+    doAssert initDateTime(dWed, 14, (-0002).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0002, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0753, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0753).IsoYear)
+    doAssert initDateTime(dMon, 14, (-0753).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0753, 00, 00, 00)
+
+  block: # getWeeksInIsoYear
+    doAssert getWeeksInIsoYear((-0014).IsoYear) == 52
+    doAssert getWeeksInIsoYear((-0013).IsoYear) == 53
+    doAssert getWeeksInIsoYear((-0012).IsoYear) == 52
+
+    doAssert getWeeksInIsoYear((-0009).IsoYear) == 52
+    doAssert getWeeksInIsoYear((-0008).IsoYear) == 53
+    doAssert getWeeksInIsoYear((-0007).IsoYear) == 52
+
+    doAssert getWeeksInIsoYear((-0003).IsoYear) == 52
+    doAssert getWeeksInIsoYear((-0002).IsoYear) == 53
+    doAssert getWeeksInIsoYear((-0001).IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(0003.IsoYear) == 52
+    doAssert getWeeksInIsoYear(0004.IsoYear) == 53
+    doAssert getWeeksInIsoYear(0005.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(1653.IsoYear) == 52
+    doAssert getWeeksInIsoYear(1654.IsoYear) == 53
+    doAssert getWeeksInIsoYear(1655.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(1997.IsoYear) == 52
+    doAssert getWeeksInIsoYear(1998.IsoYear) == 53
+    doAssert getWeeksInIsoYear(1999.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(2008.IsoYear) == 52
+    doAssert getWeeksInIsoYear(2009.IsoYear) == 53
+    doAssert getWeeksInIsoYear(2010.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(2014.IsoYear) == 52
+    doAssert getWeeksInIsoYear(2015.IsoYear) == 53
+    doAssert getWeeksInIsoYear(2016.IsoYear) == 52
+
+  block: # parse and generate iso years
+    # short calendar week with text
+    parseTest("KW 23 2023", "'KW' VV GGGG",
+      "2023-06-05T00:00:00Z", 155)
+    parseTest("KW 5 2023", "'KW' V GGGG",
+      "2023-01-30T00:00:00Z", 29)
+    parseTest("KW 05 23 Saturday", "'KW' V GG dddd",
+      "2023-02-04T00:00:00Z", 34)
+    parseTest("KW 53 20 Fri", "'KW' VV GG ddd",
+      "2021-01-01T00:00:00Z", 0)
+
+    parseTestExcp("KW 23", "'KW' VV") # no year
+    parseTestExcp("KW 23", "'KW' V") # no year
+    parseTestExcp("KW 23", "'KW' GG") # no week
+    parseTestExcp("KW 2023", "'KW' GGGG") # no week
+    
+    var dt = initDateTime(5, mJan, 2023, 0, 0, 0, utc())
+    check dt.format("V") == "1"
+    check dt.format("VV") == "01"
+    check dt.format("GG") == "23"
+    check dt.format("GGGG") == "2023"
+    check dt.format("dddd 'KW'V GGGG") == "Thursday KW1 2023"
+
+  block: # Can be used inside gcsafe proc
+    proc test(): DateTime {.gcsafe.} =
+      result = "1970".parse("yyyy")
+    doAssert test().year == 1970
+
+  block: # test FormatLiterals
+    # since #23861
+    block:
+      let dt = dateTime(2024, mJul, 21, 17, 01, 02, 123_321_123, utc())
+      check dt.format("ss.fff") == "02.123"
+      check dt.format("fff.ffffff") == "123.123321"
+    block:
+      let dt = parse("2024.07.21", "yyyy.MM.dd")
+      check dt.year == 2024
+      check dt.month == mJul
+      check dt.monthday == 21
diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim
new file mode 100644
index 000000000..9bbc2e92c
--- /dev/null
+++ b/tests/stdlib/ttypeinfo.nim
@@ -0,0 +1,93 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/typeinfo
+import std/assertions
+
+type
+  TE = enum
+    blah, blah2
+
+  TestObj = object
+    test, asd: int
+    case test2: TE
+    of blah:
+      help: string
+    else:
+      nil
+
+
+var test = @[0,1,2,3,4]
+var x = toAny(test)
+var y = 78
+x[4] = toAny(y)
+doAssert x[2].getInt == 2
+
+var test2: tuple[name: string, s: int] = ("test", 56)
+var x2 = toAny(test2)
+var i = 0
+for n, a in fields(x2):
+  case i
+  of 0: doAssert n == "Field0" and $a.kind == "akString"
+  of 1: doAssert n == "Field1" and $a.kind == "akInt"
+  else: doAssert false
+  inc i
+
+var test3: TestObj
+test3.test = 42
+test3 = TestObj(test2: blah2)
+var x3 = toAny(test3)
+i = 0
+for n, a in fields(x3):
+  case i
+  of 0: doAssert n == "test" and $a.kind == "akInt"
+  of 1: doAssert n == "asd" and $a.kind == "akInt"
+  of 2: doAssert n == "test2" and $a.kind == "akEnum"
+  else: doAssert false
+  inc i
+
+var test4: ref string
+new(test4)
+test4[] = "test"
+var x4 = toAny(test4)
+doAssert($x4[].kind() == "akString")
+
+block:
+  # gimme a new scope dammit
+  var myArr: array[0..4, array[0..4, string]] = [
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+    ["test", "1", "2", "3", "4"]]
+  var m = toAny(myArr)
+  for i in 0 .. m.len-1:
+    for j in 0 .. m[i].len-1:
+      doAssert getString(m[i][j]) == myArr[i][j]
+
+block:
+  type
+    Test = enum
+      Hello, he_llo
+
+  var x = hello
+  var y = x.toAny
+
+  doAssert getEnumOrdinal(y, "Hello") == 0
+  doAssert getEnumOrdinal(y, "hello") == 1
+
+block: # bug #23556
+  proc test =
+    var
+      t: seq[int]
+      aseq = toAny(t)
+
+    invokeNewSeq(aseq, 0)
+
+    # Got random value only when loop 8 times.
+    for i in 1 .. 8:
+      extendSeq(aseq)
+
+    doAssert t == @[0, 0, 0, 0, 0, 0, 0, 0]
+
+  for i in 1 .. 7:
+    test()
diff --git a/tests/stdlib/ttypeinfo.nims b/tests/stdlib/ttypeinfo.nims
new file mode 100644
index 000000000..d31d0b26f
--- /dev/null
+++ b/tests/stdlib/ttypeinfo.nims
@@ -0,0 +1 @@
+--styleCheck:off
\ No newline at end of file
diff --git a/tests/stdlib/ttypetraits.nim b/tests/stdlib/ttypetraits.nim
new file mode 100644
index 000000000..6851b9220
--- /dev/null
+++ b/tests/stdlib/ttypetraits.nim
@@ -0,0 +1,94 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+# xxx merge with tests/metatype/ttypetraits.nim
+
+import std/typetraits
+import std/assertions
+
+macro testClosure(fn: typed, flag: static bool) =
+  if flag:
+    doAssert hasClosure(fn)
+  else:
+    doAssert not hasClosure(fn)
+
+block:
+  proc h1() =
+    echo 1
+
+  testClosure(h1, false)
+
+  proc h2() {.nimcall.} =
+    echo 2
+
+  testClosure(h2, false)
+
+
+block:
+  proc fn(): auto =
+    proc hello() {.nimcall.} =
+      echo 3
+    hello
+
+  let name = fn()
+  testClosure(name, false)
+
+block:
+  proc fn(): auto =
+    proc hello() =
+      echo 3
+    hello
+
+  let name = fn()
+  testClosure(name, false)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() {.closure.} =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() {.closure.} =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+  let name2 = name
+  testClosure(name2, true)
+
+block:
+  iterator hello(): int =
+    yield 1
+
+  testClosure(hello, false)
+
+when not defined(js):
+  block:
+    iterator hello(): int {.closure.}=
+      yield 1
+
+    testClosure(hello, true)
diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim
new file mode 100644
index 000000000..b9e68b15b
--- /dev/null
+++ b/tests/stdlib/tunicode.nim
@@ -0,0 +1,228 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/unicode
+import std/assertions
+
+proc asRune(s: static[string]): Rune =
+  ## Compile-time conversion proc for converting string literals to a Rune
+  ## value. Returns the first Rune of the specified string.
+  ##
+  ## Shortcuts code like ``"å".runeAt(0)`` to ``"å".asRune`` and returns a
+  ## compile-time constant.
+  if s.len == 0: Rune(0)
+  else: s.runeAt(0)
+
+let
+  someString = "öÑ"
+  someRunes = toRunes(someString)
+  compared = (someString == $someRunes)
+doAssert compared == true
+
+proc testReplacements(word: string): string =
+  case word
+  of "two":
+    return "2"
+  of "foo":
+    return "BAR"
+  of "βeta":
+    return "beta"
+  of "alpha":
+    return "αlpha"
+  else:
+    return "12345"
+
+doAssert translate("two not alpha foo βeta", testReplacements) == "2 12345 αlpha BAR beta"
+doAssert translate("  two not foo βeta  ", testReplacements) == "  2 12345 BAR beta  "
+
+doAssert title("foo bar") == "Foo Bar"
+doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma"
+doAssert title("") == ""
+
+doAssert capitalize("βeta") == "Βeta"
+doAssert capitalize("foo") == "Foo"
+doAssert capitalize("") == ""
+
+doAssert swapCase("FooBar") == "fOObAR"
+doAssert swapCase(" ") == " "
+doAssert swapCase("Αlpha Βeta Γamma") == "αLPHA βETA γAMMA"
+doAssert swapCase("a✓B") == "A✓b"
+doAssert swapCase("Јамогујестистаклоитоминештети") == "јАМОГУЈЕСТИСТАКЛОИТОМИНЕШТЕТИ"
+doAssert swapCase("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ὝΑΛΟΝΦΑΓΕῖΝΔΎΝΑΜΑΙΤΟῦΤΟΟὔΜΕΒΛΆΠΤΕΙ"
+doAssert swapCase("Կրնամապակիուտեևինծիանհանգիստչըներ") == "կՐՆԱՄԱՊԱԿԻՈՒՏԵևԻՆԾԻԱՆՀԱՆԳԻՍՏՉԸՆԵՐ"
+doAssert swapCase("") == ""
+
+doAssert isAlpha("r")
+doAssert isAlpha("α")
+doAssert isAlpha("ϙ")
+doAssert isAlpha("ஶ")
+doAssert isAlpha("网")
+doAssert(not isAlpha("$"))
+doAssert(not isAlpha(""))
+
+doAssert isAlpha("Βeta")
+doAssert isAlpha("Args")
+doAssert isAlpha("𐌼𐌰𐌲𐌲𐌻𐌴𐍃𐍄𐌰𐌽")
+doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει")
+doAssert isAlpha("Јамогујестистаклоитоминештети")
+doAssert isAlpha("Կրնամապակիուտեևինծիանհանգիստչըներ")
+doAssert isAlpha("编程语言")
+doAssert(not isAlpha("$Foo✓"))
+doAssert(not isAlpha("⠙⠕⠑⠎⠝⠞"))
+
+doAssert isSpace("\t")
+doAssert isSpace("\l")
+doAssert(not isSpace("Β"))
+doAssert(not isSpace("Βeta"))
+
+doAssert isSpace("\t\l \v\r\f")
+doAssert isSpace("       ")
+doAssert(not isSpace(""))
+doAssert(not isSpace("ΑΓc   \td"))
+
+doAssert(not isLower(' '.Rune))
+
+doAssert(not isUpper(' '.Rune))
+
+doAssert toUpper("Γ") == "Γ"
+doAssert toUpper("b") == "B"
+doAssert toUpper("α") == "Α"
+doAssert toUpper("✓") == "✓"
+doAssert toUpper("ϙ") == "Ϙ"
+doAssert toUpper("") == ""
+
+doAssert toUpper("ΑΒΓ") == "ΑΒΓ"
+doAssert toUpper("AAccβ") == "AACCΒ"
+doAssert toUpper("A✓$β") == "A✓$Β"
+
+doAssert toLower("a") == "a"
+doAssert toLower("γ") == "γ"
+doAssert toLower("Γ") == "γ"
+doAssert toLower("4") == "4"
+doAssert toLower("Ϙ") == "ϙ"
+doAssert toLower("") == ""
+
+doAssert toLower("abcdγ") == "abcdγ"
+doAssert toLower("abCDΓ") == "abcdγ"
+doAssert toLower("33aaΓ") == "33aaγ"
+
+doAssert reversed("Reverse this!") == "!siht esreveR"
+doAssert reversed("先秦兩漢") == "漢兩秦先"
+doAssert reversed("as⃝df̅") == "f̅ds⃝a"
+doAssert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+doAssert reversed("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ιετπάλβεμὔοοτῦοτιαμανύδνῖεγαϕνολαὕ"
+doAssert reversed("Јамогујестистаклоитоминештети") == "итетшенимотиолкатситсејугомаЈ"
+doAssert reversed("Կրնամապակիուտեևինծիանհանգիստչըներ") == "րենըչտսիգնահնաիծնիևետւոիկապամանրԿ"
+doAssert len(toRunes("as⃝df̅")) == runeLen("as⃝df̅")
+const test = "as⃝"
+doAssert lastRune(test, test.len-1)[1] == 3
+doAssert graphemeLen("è", 0) == 2
+
+# test for rune positioning and runeSubStr()
+let s = "Hänsel  ««: 10,00€"
+
+var t = ""
+for c in s.utf8:
+  t.add c
+
+doAssert(s == t)
+
+doAssert(runeReverseOffset(s, 1) == (20, 18))
+doAssert(runeReverseOffset(s, 19) == (-1, 18))
+
+doAssert(runeStrAtPos(s, 0) == "H")
+doAssert(runeSubStr(s, 0, 1) == "H")
+doAssert(runeStrAtPos(s, 10) == ":")
+doAssert(runeSubStr(s, 10, 1) == ":")
+doAssert(runeStrAtPos(s, 9) == "«")
+doAssert(runeSubStr(s, 9, 1) == "«")
+doAssert(runeStrAtPos(s, 17) == "€")
+doAssert(runeSubStr(s, 17, 1) == "€")
+# echo runeStrAtPos(s, 18) # index error
+
+doAssert(runeSubStr(s, 0) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, -18) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, 10) == ": 10,00€")
+doAssert(runeSubStr(s, 18) == "")
+doAssert(runeSubStr(s, 0, 10) == "Hänsel  ««")
+
+doAssert(runeSubStr(s, 12) == "10,00€")
+doAssert(runeSubStr(s, -6) == "10,00€")
+
+doAssert(runeSubStr(s, 12, 5) == "10,00")
+doAssert(runeSubStr(s, 12, -1) == "10,00")
+doAssert(runeSubStr(s, -6, 5) == "10,00")
+doAssert(runeSubStr(s, -6, -1) == "10,00")
+
+doAssert(runeSubStr(s, 0, 100) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, -100, 100) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, 0, -100) == "")
+doAssert(runeSubStr(s, 100, -100) == "")
+
+block splitTests:
+  let s = " this is an example  "
+  let s2 = ":this;is;an:example;;"
+  let s3 = ":this×is×an:example××"
+  doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
+  doAssert s2.split(seps = [':'.Rune, ';'.Rune]) == @["", "this", "is", "an",
+      "example", "", ""]
+  doAssert s3.split(seps = [':'.Rune, "×".asRune]) == @["", "this", "is",
+      "an", "example", "", ""]
+  doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example  "]
+  doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example  "]
+  doAssert s3.split("×".runeAt(0)) == @[":this", "is", "an:example", "", ""]
+
+block stripTests:
+  doAssert(strip("") == "")
+  doAssert(strip(" ") == "")
+  doAssert(strip("y") == "y")
+  doAssert(strip("  foofoofoo  ") == "foofoofoo")
+  doAssert(strip("sfoofoofoos", runes = ['s'.Rune]) == "foofoofoo")
+
+  block:
+    let stripTestRunes = ['b'.Rune, 'a'.Rune, 'r'.Rune]
+    doAssert(strip("barfoofoofoobar", runes = stripTestRunes) == "foofoofoo")
+  doAssert(strip("sfoofoofoos", leading = false, runes = ['s'.Rune]) == "sfoofoofoo")
+  doAssert(strip("sfoofoofoos", trailing = false, runes = ['s'.Rune]) == "foofoofoos")
+
+  block:
+    let stripTestRunes = ["«".asRune, "»".asRune]
+    doAssert(strip("«TEXT»", runes = stripTestRunes) == "TEXT")
+  doAssert(strip("copyright©", leading = false, runes = ["©".asRune]) == "copyright")
+  doAssert(strip("¿Question?", trailing = false, runes = ["¿".asRune]) == "Question?")
+  doAssert(strip("×text×", leading = false, runes = ["×".asRune]) == "×text")
+  doAssert(strip("×text×", trailing = false, runes = ["×".asRune]) == "text×")
+
+block repeatTests:
+  doAssert repeat('c'.Rune, 5) == "ccccc"
+  doAssert repeat("×".asRune, 5) == "×××××"
+
+block alignTests:
+  doAssert align("abc", 4) == " abc"
+  doAssert align("a", 0) == "a"
+  doAssert align("1232", 6) == "  1232"
+  doAssert align("1232", 6, '#'.Rune) == "##1232"
+  doAssert align("1232", 6, "×".asRune) == "××1232"
+  doAssert alignLeft("abc", 4) == "abc "
+  doAssert alignLeft("a", 0) == "a"
+  doAssert alignLeft("1232", 6) == "1232  "
+  doAssert alignLeft("1232", 6, '#'.Rune) == "1232##"
+  doAssert alignLeft("1232", 6, "×".asRune) == "1232××"
+
+block differentSizes:
+  # upper and lower variants have different number of bytes
+  doAssert toLower("AẞC") == "aßc"
+  doAssert toLower("ȺẞCD") == "ⱥßcd"
+  doAssert toUpper("ⱥbc") == "ȺBC"
+  doAssert toUpper("rsⱦuv") == "RSȾUV"
+  doAssert swapCase("ⱥbCd") == "ȺBcD"
+  doAssert swapCase("XyꟆaB") == "xYᶎAb"
+  doAssert swapCase("aᵹcᲈd") == "AꝽCꙊD"
+
+block: # bug #17768
+  let s1 = "abcdef"
+  let s2 = "abcdéf"
+
+  doAssert s1.runeSubStr(0, -1) == "abcde"
+  doAssert s2.runeSubStr(0, -1) == "abcdé"
diff --git a/tests/stdlib/tunidecode.nim b/tests/stdlib/tunidecode.nim
index 689453c76..653016ea9 100644
--- a/tests/stdlib/tunidecode.nim
+++ b/tests/stdlib/tunidecode.nim
@@ -1,12 +1,13 @@
 discard """
   cmd: "nim $target --hints:on -d:embedUnidecodeTable $options $file"
-  output: "Ausserst"
 """
 
 import unidecode
 
-loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
+import std/unidecode # #14112
+import std/assertions
 
-#assert unidecode("\x53\x17\x4E\xB0") == "Bei Jing"
-echo unidecode("Äußerst")
+loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
 
+doAssert unidecode("北京") == "Bei Jing "
+doAssert unidecode("Äußerst") == "Ausserst"
diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim
index 86b9fd037..0442c7863 100644
--- a/tests/stdlib/tunittest.nim
+++ b/tests/stdlib/tunittest.nim
@@ -1,5 +1,7 @@
 discard """
-  output: '''[Suite] suite with only teardown
+  output: '''
+
+[Suite] suite with only teardown
 
 [Suite] suite with only setup
 
@@ -13,12 +15,16 @@ discard """
 
 [Suite] bug #5784
 
-[Suite] test name filtering
+[Suite] test suite
 
+[Suite] test name filtering
 '''
+matrix: "--mm:refc; --mm:orc"
+targets: "c js"
 """
 
-import unittest, sequtils
+import std/[unittest, sequtils, assertions]
+from std/unittest {.all.} import matchFilter
 
 proc doThings(spuds: var int): int =
   spuds = 24
@@ -29,12 +35,12 @@ test "#964":
   check spuds == 24
 
 
-from strutils import toUpperAscii
+from std/strutils import toUpperAscii
 test "#1384":
   check(@["hello", "world"].map(toUpperAscii) == @["HELLO", "WORLD"])
 
 
-import options
+import std/options
 test "unittest typedescs":
   check(none(int) == none(int))
   check(none(int) != some(1))
@@ -45,17 +51,16 @@ test "unittest multiple requires":
   require(true)
 
 
-import math, random
-from strutils import parseInt
+import std/random
+from std/strutils import parseInt
 proc defectiveRobot() =
-  randomize()
-  case random(1..4)
+  case rand(1..4)
   of 1: raise newException(OSError, "CANNOT COMPUTE!")
   of 2: discard parseInt("Hello World!")
   of 3: raise newException(IOError, "I can't do that Dave.")
-  else: assert 2 + 2 == 5
+  else: doAssert 2 + 2 == 5
 test "unittest expect":
-  expect IOError, OSError, ValueError, AssertionError:
+  expect IOError, OSError, ValueError, AssertionDefect:
     defectiveRobot()
 
 var
@@ -123,38 +128,67 @@ suite "bug #5784":
     var obj: Obj
     check obj.isNil or obj.field == 0
 
-when defined(testing):
-  suite "test name filtering":
-    test "test name":
-      check matchFilter("suite1", "foo", "")
-      check matchFilter("suite1", "foo", "foo")
-      check matchFilter("suite1", "foo", "::")
-      check matchFilter("suite1", "foo", "*")
-      check matchFilter("suite1", "foo", "::foo")
-      check matchFilter("suite1", "::foo", "::foo")
-
-    test "test name - glob":
-      check matchFilter("suite1", "foo", "f*")
-      check matchFilter("suite1", "foo", "*oo")
-      check matchFilter("suite1", "12345", "12*345")
-      check matchFilter("suite1", "q*wefoo", "q*wefoo")
-      check false == matchFilter("suite1", "foo", "::x")
-      check false == matchFilter("suite1", "foo", "::x*")
-      check false == matchFilter("suite1", "foo", "::*x")
-      #  overlap
-      check false == matchFilter("suite1", "12345", "123*345")
-      check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f")
-
-    test "suite name":
-      check matchFilter("suite1", "foo", "suite1::")
-      check false == matchFilter("suite1", "foo", "suite2::")
-      check matchFilter("suite1", "qwe::foo", "qwe::foo")
-      check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo")
-
-    test "suite name - glob":
-      check matchFilter("suite1", "foo", "::*")
-      check matchFilter("suite1", "foo", "*::*")
-      check matchFilter("suite1", "foo", "*::foo")
-      check false == matchFilter("suite1", "foo", "*ite2::")
-      check matchFilter("suite1", "q**we::foo", "q**we::foo")
-      check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e")
+type
+    SomeType = object
+        value: int
+        children: seq[SomeType]
+
+# bug #5252
+
+proc `==`(a, b: SomeType): bool =
+    return a.value == b.value
+
+suite "test suite":
+    test "test":
+        let a = SomeType(value: 10)
+        let b = SomeType(value: 10)
+
+        check(a == b)
+
+suite "test name filtering":
+  test "test name":
+    check matchFilter("suite1", "foo", "")
+    check matchFilter("suite1", "foo", "foo")
+    check matchFilter("suite1", "foo", "::")
+    check matchFilter("suite1", "foo", "*")
+    check matchFilter("suite1", "foo", "::foo")
+    check matchFilter("suite1", "::foo", "::foo")
+
+  test "test name - glob":
+    check matchFilter("suite1", "foo", "f*")
+    check matchFilter("suite1", "foo", "*oo")
+    check matchFilter("suite1", "12345", "12*345")
+    check matchFilter("suite1", "q*wefoo", "q*wefoo")
+    check false == matchFilter("suite1", "foo", "::x")
+    check false == matchFilter("suite1", "foo", "::x*")
+    check false == matchFilter("suite1", "foo", "::*x")
+    #  overlap
+    check false == matchFilter("suite1", "12345", "123*345")
+    check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f")
+
+  test "suite name":
+    check matchFilter("suite1", "foo", "suite1::")
+    check false == matchFilter("suite1", "foo", "suite2::")
+    check matchFilter("suite1", "qwe::foo", "qwe::foo")
+    check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo")
+
+  test "suite name - glob":
+    check matchFilter("suite1", "foo", "::*")
+    check matchFilter("suite1", "foo", "*::*")
+    check matchFilter("suite1", "foo", "*::foo")
+    check false == matchFilter("suite1", "foo", "*ite2::")
+    check matchFilter("suite1", "q**we::foo", "q**we::foo")
+    check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e")
+
+
+block:
+  type MyFoo = object
+  var obj = MyFoo()
+  let check = 1
+  check(obj == obj)
+
+block:
+  let check = 123
+  var a = 1
+  var b = 1
+  check(a == b)
diff --git a/tests/stdlib/tunittest_error.nim b/tests/stdlib/tunittest_error.nim
new file mode 100644
index 000000000..7f05ec2a9
--- /dev/null
+++ b/tests/stdlib/tunittest_error.nim
@@ -0,0 +1,22 @@
+discard """
+  exitcode: 1
+  outputsub: "failed: 1 == 3"
+  matrix: "-d:case1; -d:case2"
+  targets: "c js"
+  joinable: false
+"""
+
+when defined case1:
+  import unittest
+  suite "Test":
+    test "test require":
+      check 1==2
+      check 1==3
+
+when defined case2:
+  import unittest
+  suite "Test":
+    test "test require":
+      require 1 == 3
+      if true:
+        quit 0 # intentional
diff --git a/tests/stdlib/tunittestpass.nim b/tests/stdlib/tunittestpass.nim
new file mode 100644
index 000000000..d8de277b7
--- /dev/null
+++ b/tests/stdlib/tunittestpass.nim
@@ -0,0 +1,20 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+
+import unittest
+
+block:
+  check (type(1.0)) is float
+  check type(1.0) is float
+  check (typeof(1)) isnot float
+  check typeof(1) isnot float
+
+  check 1.0 is float
+  check 1 isnot float
+
+  type T = type(0.1)
+  check T is float
+  check T isnot int
diff --git a/tests/stdlib/tunittesttemplate.nim b/tests/stdlib/tunittesttemplate.nim
new file mode 100644
index 000000000..c29e0de01
--- /dev/null
+++ b/tests/stdlib/tunittesttemplate.nim
@@ -0,0 +1,25 @@
+discard """
+  exitcode: 1
+  outputsub: '''
+    tunittesttemplate.nim(20, 12): Check failed: a.b == 2
+    a.b was 0
+  [FAILED] 1
+'''
+"""
+
+
+
+# bug #6736
+import std/unittest
+
+type
+  A = object
+    b: int
+
+template t: untyped =
+  check(a.b == 2)
+
+suite "1":
+  test "1":
+    var a = A(b: 0)
+    t()
diff --git a/tests/stdlib/tunixsocket.nim b/tests/stdlib/tunixsocket.nim
new file mode 100644
index 000000000..636fd08c6
--- /dev/null
+++ b/tests/stdlib/tunixsocket.nim
@@ -0,0 +1,35 @@
+import std/[assertions, net, os, osproc]
+
+# XXX: Make this test run on Windows too when we add support for Unix sockets on Windows
+when defined(posix) and not defined(nimNetLite):
+  const nim = getCurrentCompilerExe()
+  let
+    dir = currentSourcePath().parentDir()
+    serverPath = dir / "unixsockettest"
+
+  let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "unixsockettest.nim"))
+  doAssert err == 0
+
+  let svproc = startProcess(serverPath, workingDir = dir)
+  doAssert svproc.running()
+  # Wait for the server to open the socket and listen from it
+  sleep(400)
+
+  block unixSocketSendRecv:
+    let
+      unixSocketPath = dir / "usox"
+      socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
+
+    socket.connectUnix(unixSocketPath)
+    # for a blocking Unix socket this should never fail
+    socket.send("data sent through the socket\c\l", maxRetries = 0)
+    var resp: string
+    socket.readLine(resp)
+    doAssert resp == "Hello from server"
+
+    socket.send("bye\c\l")
+    socket.readLine(resp)
+    doAssert resp == "bye"
+    socket.close()
+
+  svproc.close()
diff --git a/tests/stdlib/turi.nim b/tests/stdlib/turi.nim
new file mode 100644
index 000000000..9c717c5b1
--- /dev/null
+++ b/tests/stdlib/turi.nim
@@ -0,0 +1,323 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets:  "c js"
+"""
+
+import std/uri
+from std/uri {.all.} as uri2 import removeDotSegments
+from std/sequtils import toSeq
+import std/assertions
+
+template main() =
+  block: # encodeUrl, decodeUrl
+    const test1 = "abc\L+def xyz"
+    doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
+    doAssert decodeUrl(encodeUrl(test1)) == test1
+    doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz"
+    doAssert decodeUrl(encodeUrl(test1, false), false) == test1
+    doAssert decodeUrl(encodeUrl(test1)) == test1
+
+  block: # removeDotSegments
+    doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz"
+    doAssert removeDotSegments("") == "" # empty test
+    doAssert removeDotSegments(".") == "." # trailing period
+    doAssert removeDotSegments("a1/a2/../a3/a4/a5/./a6/a7/././") == "a1/a3/a4/a5/a6/a7/"
+    doAssert removeDotSegments("https://a1/a2/../a3/a4/a5/./a6/a7/././") == "https://a1/a3/a4/a5/a6/a7/"
+    doAssert removeDotSegments("http://a1/a2") == "http://a1/a2"
+    doAssert removeDotSegments("http://www.ai.") == "http://www.ai."
+    when false: # xxx these cases are buggy
+      # this should work, refs https://webmasters.stackexchange.com/questions/73934/how-can-urls-have-a-dot-at-the-end-e-g-www-bla-de
+      doAssert removeDotSegments("http://www.ai./") == "http://www.ai./" # fails
+      echo removeDotSegments("http://www.ai./")  # http://www.ai/
+      echo removeDotSegments("a/b.../c") # b.c
+      echo removeDotSegments("a/b../c") # bc
+      echo removeDotSegments("a/.../c") # .c
+      echo removeDotSegments("a//../b") # a/b
+      echo removeDotSegments("a/b/c//") # a/b/c//
+
+  block: # parseUri
+    block:
+      let org = "udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
+      let url = parseUri(org)
+      doAssert url.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true
+      let newUrl = parseUri($url)
+      doAssert newUrl.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true
+
+    block:
+      let str = "http://localhost"
+      let test = parseUri(str)
+      doAssert test.path == ""
+
+    block:
+      let str = "http://localhost/"
+      let test = parseUri(str)
+      doAssert test.path == "/"
+
+    block:
+      let str = "http://localhost:8080/test"
+      let test = parseUri(str)
+      doAssert test.scheme == "http"
+      doAssert test.port == "8080"
+      doAssert test.path == "/test"
+      doAssert test.hostname == "localhost"
+      doAssert($test == str)
+
+    block:
+      let str = "foo://username:password@example.com:8042/over/there" &
+                "/index.dtb?type=animal&name=narwhal#nose"
+      let test = parseUri(str)
+      doAssert test.scheme == "foo"
+      doAssert test.username == "username"
+      doAssert test.password == "password"
+      doAssert test.hostname == "example.com"
+      doAssert test.port == "8042"
+      doAssert test.path == "/over/there/index.dtb"
+      doAssert test.query == "type=animal&name=narwhal"
+      doAssert test.anchor == "nose"
+      doAssert($test == str)
+
+    block:
+      # IPv6 address
+      let str = "foo://[::1]:1234/bar?baz=true&qux#quux"
+      let uri = parseUri(str)
+      doAssert uri.scheme == "foo"
+      doAssert uri.hostname == "::1"
+      doAssert uri.port == "1234"
+      doAssert uri.path == "/bar"
+      doAssert uri.query == "baz=true&qux"
+      doAssert uri.anchor == "quux"
+
+    block:
+      let str = "urn:example:animal:ferret:nose"
+      let test = parseUri(str)
+      doAssert test.scheme == "urn"
+      doAssert test.path == "example:animal:ferret:nose"
+      doAssert($test == str)
+
+    block:
+      let str = "mailto:username@example.com?subject=Topic"
+      let test = parseUri(str)
+      doAssert test.scheme == "mailto"
+      doAssert test.username == "username"
+      doAssert test.hostname == "example.com"
+      doAssert test.query == "subject=Topic"
+      doAssert($test == str)
+
+    block:
+      let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+      let test = parseUri(str)
+      doAssert test.scheme == "magnet"
+      doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+      doAssert($test == str)
+
+    block:
+      let str = "/test/foo/bar?q=2#asdf"
+      let test = parseUri(str)
+      doAssert test.scheme == ""
+      doAssert test.path == "/test/foo/bar"
+      doAssert test.query == "q=2"
+      doAssert test.anchor == "asdf"
+      doAssert($test == str)
+
+    block:
+      let str = "test/no/slash"
+      let test = parseUri(str)
+      doAssert test.path == "test/no/slash"
+      doAssert($test == str)
+
+    block:
+      let str = "//git@github.com:dom96/packages"
+      let test = parseUri(str)
+      doAssert test.scheme == ""
+      doAssert test.username == "git"
+      doAssert test.hostname == "github.com"
+      doAssert test.port == "dom96"
+      doAssert test.path == "/packages"
+
+    block:
+      let str = "file:///foo/bar/baz.txt"
+      let test = parseUri(str)
+      doAssert test.scheme == "file"
+      doAssert test.username == ""
+      doAssert test.hostname == ""
+      doAssert test.port == ""
+      doAssert test.path == "/foo/bar/baz.txt"
+
+  block: # combine
+    block:
+      let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz"))
+      doAssert concat.path == "/foo/bar/baz"
+      doAssert concat.hostname == "google.com"
+      doAssert concat.scheme == "http"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz"))
+      doAssert concat.path == "/baz"
+      doAssert concat.hostname == "google.com"
+      doAssert concat.scheme == "http"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+      doAssert concat.path == "/foo/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar"))
+      doAssert concat.path == "/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+      doAssert concat.path == "/foo/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar"))
+      doAssert concat.path == "/foo/test/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"))
+      doAssert concat.path == "/foo/test/bar/"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"),
+                           parseUri("baz"))
+      doAssert concat.path == "/foo/test/bar/baz"
+
+  block: # `/`
+    block:
+      let test = parseUri("http://example.com/foo") / "bar/asd"
+      doAssert test.path == "/foo/bar/asd"
+
+    block:
+      let test = parseUri("http://example.com/foo/") / "/bar/asd"
+      doAssert test.path == "/foo/bar/asd"
+
+  block: # bug #3207
+    doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq"
+
+  block: # bug #4959
+    let foo = parseUri("http://example.com") / "/baz"
+    doAssert foo.path == "/baz"
+
+  block: # bug found on stream 13/10/17
+    let foo = parseUri("http://localhost:9515") / "status"
+    doAssert $foo == "http://localhost:9515/status"
+
+  block: # bug #6649 #6652
+    var foo = parseUri("http://example.com")
+    foo.hostname = "example.com"
+    foo.path = "baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com/"
+    foo.path = "baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com"
+    foo.path = "/baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com/"
+    foo.path = "/baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com/"
+    foo.port = "8000"
+    foo.path = "baz"
+    doAssert $foo == "http://example.com:8000/baz"
+
+    foo = parseUri("file:/dir/file")
+    foo.path = "relative"
+    doAssert $foo == "file:relative"
+
+  block: # isAbsolute tests
+    doAssert "www.google.com".parseUri().isAbsolute() == false
+    doAssert "http://www.google.com".parseUri().isAbsolute() == true
+    doAssert "file:/dir/file".parseUri().isAbsolute() == true
+    doAssert "file://localhost/dir/file".parseUri().isAbsolute() == true
+    doAssert "urn:ISSN:1535-3613".parseUri().isAbsolute() == true
+
+    # path-relative URL *relative
+    doAssert "about".parseUri().isAbsolute == false
+    doAssert "about/staff.html".parseUri().isAbsolute == false
+    doAssert "about/staff.html?".parseUri().isAbsolute == false
+    doAssert "about/staff.html?parameters".parseUri().isAbsolute == false
+
+    # absolute-path-relative URL *relative
+    doAssert "/".parseUri().isAbsolute == false
+    doAssert "/about".parseUri().isAbsolute == false
+    doAssert "/about/staff.html".parseUri().isAbsolute == false
+    doAssert "/about/staff.html?".parseUri().isAbsolute == false
+    doAssert "/about/staff.html?parameters".parseUri().isAbsolute == false
+
+    # scheme-relative URL *relative
+    doAssert "//username:password@example.com:8888".parseUri().isAbsolute == false
+    doAssert "//username@example.com".parseUri().isAbsolute == false
+    doAssert "//example.com".parseUri().isAbsolute == false
+    doAssert "//example.com/".parseUri().isAbsolute == false
+    doAssert "//example.com/about".parseUri().isAbsolute == false
+    doAssert "//example.com/about/staff.html".parseUri().isAbsolute == false
+    doAssert "//example.com/about/staff.html?".parseUri().isAbsolute == false
+    doAssert "//example.com/about/staff.html?parameters".parseUri().isAbsolute == false
+
+    # absolute URL *absolute
+    doAssert "https://username:password@example.com:8888".parseUri().isAbsolute == true
+    doAssert "https://username@example.com".parseUri().isAbsolute == true
+    doAssert "https://example.com".parseUri().isAbsolute == true
+    doAssert "https://example.com/".parseUri().isAbsolute == true
+    doAssert "https://example.com/about".parseUri().isAbsolute == true
+    doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true
+    doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true
+    doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true
+
+  block: # encodeQuery tests
+    doAssert encodeQuery({:}) == ""
+    doAssert encodeQuery({"foo": "bar"}) == "foo=bar"
+    doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz"
+    doAssert encodeQuery({"foo": "bar & baz"}, usePlus = false) == "foo=bar%20%26%20baz"
+    doAssert encodeQuery({"foo": ""}) == "foo"
+    doAssert encodeQuery({"foo": ""}, omitEq = false) == "foo="
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3"
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, sep = ';') == "a=1;b;c=3"
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3"
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false, sep = ';') == "a=1;b=;c=3"
+
+  block: # `?`
+    block:
+      var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"}
+      var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux")
+      doAssert foo == foo1
+    block:
+      var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""}
+      var foo1 = parseUri("http://example.com/foo?do=do&bar")
+      doAssert foo == foo1
+
+  block: # getDataUri, dataUriBase64
+    doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64,"
+    doAssert getDataUri(" ", "text/plain") == "data:text/plain;charset=utf-8;base64,IA=="
+    doAssert getDataUri("c\xf7>", "text/plain") == "data:text/plain;charset=utf-8;base64,Y/c+"
+    doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ="
+    doAssert getDataUri("leasure.", "text/plain") == "data:text/plain;charset=utf-8;base64,bGVhc3VyZS4="
+    doAssert getDataUri("""!@#$%^&*()_+""", "text/plain") == "data:text/plain;charset=utf-8;base64,IUAjJCVeJiooKV8r"
+    doAssert(getDataUri("the quick brown dog jumps over the lazy fox", "text/plain") ==
+      "data:text/plain;charset=utf-8;base64,dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==")
+    doAssert(getDataUri("The present is theirs\n      The future, for which I really worked, is mine.", "text/plain") ==
+      "data:text/plain;charset=utf-8;base64,VGhlIHByZXNlbnQgaXMgdGhlaXJzCiAgICAgIFRoZSBmdXR1cmUsIGZvciB3aGljaCBJIHJlYWxseSB3b3JrZWQsIGlzIG1pbmUu")
+
+  block: # decodeQuery
+    doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")]
+    doAssert toSeq(decodeQuery("a=1;b=0", sep = ';')) == @[("a", "1"), ("b", "0")]
+    doAssert toSeq(decodeQuery("a=1&b=2c=6")) == @[("a", "1"), ("b", "2c=6")]
+    doAssert toSeq(decodeQuery("a=1;b=2c=6", sep = ';')) == @[("a", "1"), ("b", "2c=6")]
+
+  block: # bug #17481
+    let u1 = parseUri("./")
+    let u2 = parseUri("./path")
+    let u3 = parseUri("a/path")
+    doAssert u1.scheme.len == 0
+    doAssert u1.path == "./"
+    doAssert u2.scheme.len == 0
+    doAssert u2.path == "./path"
+    doAssert u3.scheme.len == 0
+    doAssert u3.path == "a/path"
+
+static: main()
+main()
diff --git a/tests/stdlib/tuserlocks.nim b/tests/stdlib/tuserlocks.nim
new file mode 100644
index 000000000..927077120
--- /dev/null
+++ b/tests/stdlib/tuserlocks.nim
@@ -0,0 +1,21 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/rlocks
+import std/assertions
+
+var r: RLock
+r.initRLock()
+doAssert r.tryAcquire()
+doAssert r.tryAcquire()
+r.release()
+r.release()
+
+block:
+  var x = 12
+  withRLock r:
+    inc x
+  doAssert x == 13
+
+r.deinitRLock()
diff --git a/tests/stdlib/tvarargs.nim b/tests/stdlib/tvarargs.nim
new file mode 100644
index 000000000..2edc26264
--- /dev/null
+++ b/tests/stdlib/tvarargs.nim
@@ -0,0 +1,18 @@
+discard """
+  targets: "c js"
+  matrix: "--mm:refc; --mm:orc"
+"""
+import std/assertions
+
+template main =
+  proc hello(x: varargs[string]): seq[string] =
+    var s: seq[string]
+    s.add x
+    s
+
+  doAssert hello() == @[]
+  doAssert hello("a1") == @["a1"]
+  doAssert hello("a1", "a2") == @["a1", "a2"]
+
+static: main()
+main()
diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim
new file mode 100644
index 000000000..f9624ee5b
--- /dev/null
+++ b/tests/stdlib/tvarints.nim
@@ -0,0 +1,73 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/varints
+import std/assertions
+
+# xxx doesn't work with js: tvarints.nim(18, 14) `wrLen == rdLen`  [AssertionDefect]
+
+block:
+  var dest: array[50, byte]
+  var got: uint64
+
+  for test in [0xFFFF_FFFF_FFFFF_FFFFu64, 77u64, 0u64, 10_000_000u64, uint64(high(int64)),
+              uint64(high(int32)), uint64(high(int32)), uint64(high(int64))]:
+    let wrLen = writeVu64(dest, test)
+    let rdLen = readVu64(dest, got)
+    doAssert wrLen == rdLen
+    doAssert got == test
+
+  for test in 0u64..300u64:
+    let wrLen = writeVu64(dest, test)
+    let rdLen = readVu64(dest, got)
+    doAssert wrLen == rdLen
+    doAssert got == test
+
+  # check this also works for floats:
+  for test in [0.0, 0.1, 2.0, +Inf, NegInf]:
+    let t = cast[uint64](test)
+    let wrLenB = writeVu64(dest, t)
+    let rdLenB = readVu64(dest, got)
+    doAssert wrLenB == rdLenB
+    doAssert cast[float64](got) == test
+
+block:
+  var hugeIntArray: array[9, byte]
+  var readedInt: uint64
+
+  template chk(a) =
+    let b = cast[uint64](a)
+    doAssert writeVu64(hugeIntArray, b) == readVu64(hugeIntArray, readedInt)
+    doAssert readedInt == b
+
+  chk 0
+  chk uint64.high
+  chk int64.high
+  chk int32.high
+  chk int16.high
+  chk int16.high
+  chk int8.high
+  chk 0.0
+  chk -0.0
+  chk 0.1
+  chk Inf
+  chk NegInf
+  chk NaN
+  chk 3.1415926535897932384626433
+
+block:
+  template chk(a) =
+    let b = cast[uint64](a)
+    doAssert encodeZigzag(decodeZigzag(b)) == b
+  chk 0
+  chk uint32.high
+  chk int32.high
+  chk int16.high
+  chk int8.high
+  chk 0.0
+  chk 0.1
+  chk 0.9555555555555555555555501
+  chk Inf
+  chk 3.1415926535897932384626433
+  chk 2.71828182845904523536028747
diff --git a/tests/stdlib/tvmutils.nim b/tests/stdlib/tvmutils.nim
new file mode 100644
index 000000000..63804c136
--- /dev/null
+++ b/tests/stdlib/tvmutils.nim
@@ -0,0 +1,31 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+  nimout: '''
+0
+1
+2
+tvmutils.nim(28, 13) [opcLdImmInt]     if i == 4:
+tvmutils.nim(28, 10) [opcEqInt]     if i == 4:
+tvmutils.nim(28, 10) [opcFJmp]     if i == 4:
+tvmutils.nim(28, 13) [opcLdImmInt]     if i == 4:
+tvmutils.nim(28, 10) [opcEqInt]     if i == 4:
+tvmutils.nim(28, 10) [opcFJmp]     if i == 4:
+tvmutils.nim(29, 7) [opcLdConst]       vmTrace(false)
+tvmutils.nim(29, 15) [opcLdImmInt]       vmTrace(false)
+tvmutils.nim(29, 14) [opcIndCall]       vmTrace(false)
+5
+6
+'''
+"""
+# line 20 (only showing a subset of nimout to avoid making the test rigid)
+import std/vmutils
+proc main() =
+  for i in 0..<7:
+    echo i
+    if i == 2:
+      vmTrace(true)
+    if i == 4:
+      vmTrace(false)
+
+static: main()
diff --git a/tests/stdlib/tvolatile.nim b/tests/stdlib/tvolatile.nim
new file mode 100644
index 000000000..c097f9723
--- /dev/null
+++ b/tests/stdlib/tvolatile.nim
@@ -0,0 +1,15 @@
+import std/[volatile, assertions]
+
+var st: int
+var foo: ptr int = addr st
+volatileStore(foo, 12)
+doAssert volatileLoad(foo) == 12
+
+# bug #14623
+proc bar =
+  var st: int
+  var foo: ptr int = addr st
+  volatileStore(foo, 12)
+  doAssert volatileLoad(foo) == 12
+
+bar()
diff --git a/tests/stdlib/twalker.nim b/tests/stdlib/twalker.nim
deleted file mode 100644
index 91c97df01..000000000
--- a/tests/stdlib/twalker.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-# iterate over all files with a given filter:
-
-import
-  "../../lib/pure/os.nim", ../../ lib / pure / times
-
-proc main(filter: string) =
-  for filename in walkFiles(filter):
-    writeLine(stdout, filename)
-
-  for key, val in envPairs():
-    writeLine(stdout, key & '=' & val)
-
-main("*.nim")
diff --git a/tests/stdlib/twchartoutf8.nim b/tests/stdlib/twchartoutf8.nim
index a6602e3e3..e437177ac 100644
--- a/tests/stdlib/twchartoutf8.nim
+++ b/tests/stdlib/twchartoutf8.nim
@@ -1,13 +1,17 @@
 discard """
+  matrix: "--mm:refc; --mm:orc"
   output: '''OK'''
 """
 
+import std/[syncio, assertions]
+
 #assume WideCharToMultiByte always produce correct result
 #windows only
 
 when not defined(windows):
   echo "OK"
 else:
+  import std/widestrs
   {.push gcsafe.}
 
   const CP_UTF8 = 65001'i32
@@ -66,8 +70,7 @@ else:
 
   #RFC-2781 "UTF-16, an encoding of ISO 10646"
 
-  var wc: WideCString
-  unsafeNew(wc, 1024 * 4 + 2)
+  var wc: WideCString = newWideCString(1024 * 2)
 
   #U+0000 to U+D7FF
   #skip the U+0000
diff --git a/tests/stdlib/twith.nim b/tests/stdlib/twith.nim
new file mode 100644
index 000000000..ceadbe7bf
--- /dev/null
+++ b/tests/stdlib/twith.nim
@@ -0,0 +1,44 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/with
+import std/[assertions, formatfloat]
+
+type
+  Foo = object
+    col, pos: string
+    name: string
+
+proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b)
+proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y)
+
+var f: Foo
+with(f, setColor(2, 3, 4), setPosition(0.0, 1.0))
+doAssert f.col == "(2, 3, 4)"
+doAssert f.pos == "(0.0, 1.0)"
+
+f = Foo()
+with f:
+  col = $(2, 3, 4)
+  pos = $(0.0, 1.0)
+  _.name = "bar"
+doAssert f.col == "(2, 3, 4)"
+doAssert f.pos == "(0.0, 1.0)"
+doAssert f.name == "bar"
+
+type
+  Baz* = object
+    a*, b*: int
+  Bar* = object
+    x*: int
+    baz*: Baz
+
+var bar: Bar
+with bar:
+  x = 1
+  with baz:
+    a = 2
+
+doAssert bar.x == 1
+doAssert bar.baz.a == 2
diff --git a/tests/stdlib/twordwrap.nim b/tests/stdlib/twordwrap.nim
new file mode 100644
index 000000000..5d49477d3
--- /dev/null
+++ b/tests/stdlib/twordwrap.nim
@@ -0,0 +1,48 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/wordwrap
+import std/assertions
+
+when true:
+  let
+    inp = """ this is a long text --  muchlongerthan10chars and here
+                it goes"""
+    outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+  doAssert wrapWords(inp, 10, false) == outp
+
+  let
+    longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
+    longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
+  doAssert wrapWords(longInp, 8, true) == longOutp
+
+# test we don't break Umlauts into invalid bytes:
+let fies = "äöüöäöüöäöüöäöüööäöüöäößßßßüöäößßßßßß"
+let fiesRes = "ä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nö\nä\nö\nü\nö\nä\nö\nß\nß\nß\nß\nü\nö\nä\nö\nß\nß\nß\nß\nß\nß"
+doAssert wrapWords(fies, 1, true) == fiesRes
+
+let longlongword = """abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüö
+äzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüüöäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiqfglwcßqfgxvlcwgtfhiaoen
+rsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocfqclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdrtnaetdr
+iaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ
+ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε"""
+let longlongwordRes = """
+abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp
+psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüöäzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüü
+öäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiq
+fglwcßqfgxvlcwgtfhiaoenrsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocf
+qclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdr
+tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψ
+ρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ
+ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε"""
+doAssert wrapWords(longlongword) == longlongwordRes
+
+# bug #14579
+const input60 = """
+This string is wrapped to 60 characters. If we call
+wrapwords on it it will be re-wrapped to 80 characters.
+"""
+const input60Res = """This string is wrapped to 60 characters. If we call wrapwords on it it will be
+re-wrapped to 80 characters."""
+doAssert wrapWords(input60) == input60Res
\ No newline at end of file
diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim
new file mode 100644
index 000000000..3da230b5e
--- /dev/null
+++ b/tests/stdlib/twrapnils.nim
@@ -0,0 +1,224 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/wrapnils
+from std/options import get, isSome
+import std/assertions
+
+proc checkNotZero(x: float): float =
+  doAssert x != 0
+  x
+
+proc main() =
+  var witness = 0
+  block:
+    type Bar = object
+      b1: int
+      b2: ptr string
+
+    type Foo = ref object
+      x1: float
+      x2: Foo
+      x3: string
+      x4: Bar
+      x5: seq[int]
+      x6: ptr Bar
+      x7: array[2, string]
+      x8: seq[int]
+      x9: ref Bar
+
+    type Goo = ref object
+      foo: Foo
+
+    proc fun(a: Bar): auto = a.b2
+
+    var a: Foo
+
+    var x6: ptr Bar
+    when nimvm: discard # pending https://github.com/timotheecour/Nim/issues/568
+    else:
+      x6 = create(Bar)
+      x6.b1 = 42
+    var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6)
+    var a3 = Foo(x1: 1.2, x3: "abc")
+    a3.x2 = a3
+
+    var goo = Goo(foo: a)
+
+    proc initFoo(x1: float): auto =
+      witness.inc
+      result = Foo(x1: x1)
+
+    doAssert ?.a.x2.x2.x1 == 0.0
+    doAssert ?.a3.x2.x2.x1 == 1.2
+    doAssert ?.a3.x2.x2.x3[1] == 'b'
+
+    doAssert ?.a3.x2.x2.x5.len == 0
+    doAssert a3.x2.x2.x3.len == 3
+
+    doAssert ?.a.x2.x2.x3[1] == default(char)
+    # here we only apply wrapnil around goo.foo, not goo (and assume goo is not nil)
+    doAssert ?.(goo.foo).x2.x2.x1 == 0.0
+
+    when nimvm: discard
+    else:
+      doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar
+
+    doAssert ?.a2.x1.checkNotZero == 1.0
+    doAssert a == nil
+    # shows that checkNotZero won't be called if a nil is found earlier in chain
+    doAssert ?.a.x1.checkNotZero == 0.0
+
+    when nimvm: discard
+    else:
+      # checks that a chain without nil but with an empty seq still raises
+      doAssertRaises(IndexDefect): discard ?.a2.x8[3]
+
+    # make sure no double evaluation bug
+    doAssert witness == 0
+    doAssert ?.initFoo(1.3).x1 == 1.3
+    doAssert witness == 1
+
+    # here, it's used twice, to deref `ref Bar` and then `ptr string`
+    doAssert ?.a.x9[].fun[] == ""
+
+    block: # `??.`
+      doAssert (??.a3.x2.x2.x3.len).get == 3
+      doAssert (??.a2.x4).isSome
+      doAssert not (??.a.x4).isSome
+
+  block:
+    type
+      A = object
+        b: B
+      B = object
+        c: C
+      C = object
+        d: D
+      D = ref object
+        e: E
+        e2: array[2, E]
+        e3: seq[E]
+        d3: D
+        i4: int
+      E = object
+        f: int
+        d2: D
+    proc identity[T](a: T): T = a
+    proc identity2[T](a: T, ignore: int): T = a
+    var a: A
+    doAssert ?.a.b.c.d.e.f == 0
+    doAssert ?.a.b.c.d.e.d2.d3[].d3.e.d2.e.f == 0
+    doAssert ?.a.b.c.d.d3[].e.f == 0
+    doAssert ?.a.b.c.d.e2[0].d2.e3[0].f == 0
+    doAssert ?.a == A.default
+    doAssert ?.a.b.c.d.e == E.default
+    doAssert ?.a.b.c.d.e.d2 == nil
+
+    doAssert ?.a.identity.b.c.identity2(12).d.d3.e.f == 0
+    doAssert ?.a.b.c.d.d3.e2[0].f == 0
+    a.b.c.d = D()
+    a.b.c.d.d3 = a.b.c.d
+    a.b.c.d.e2[0].f = 5
+    doAssert ?.a.b.c.d.d3.e2[0].f == 5
+
+    var d: D = nil
+    doAssert ?.d.identity.i4 == 0
+    doAssert ?.d.i4.identity == 0
+
+  block: # case objects
+    type
+      Kind = enum k0, k1, k2
+      V = object
+        case kind: Kind
+        of k0:
+          x0: int
+        of k1:
+          x1: int
+        of k2:
+          x2: int
+      A = object
+        v0: V
+
+    block:
+      var a = V(kind: k0, x0: 3)
+      doAssert ?.a.x0 == 3
+      doAssert ?.a.x1 == 0
+      a = V(kind: k1, x1: 5)
+      doAssert ?.a.x0 == 0
+      doAssert ?.a.x1 == 5
+
+    block:
+      var a = A(v0: V(kind: k0, x0: 10))
+      doAssert ?.a.v0.x0 == 10
+      doAssert ?.a.v0.x1 == 0
+      a.v0 = V(kind: k2, x2: 8)
+      doAssert ?.a.v0.x0 == 0
+      doAssert ?.a.v0.x1 == 0
+      doAssert ?.a.v0.x2 == 8
+
+  block: # `nnkCall`
+    type
+      A = object
+        a0: int
+        d: D
+      D = ref object
+        i4: int
+
+    proc identity[T](a: T): T = a
+    var d: D = nil
+    doAssert ?.d.i4.identity == 0
+    doAssert ?.identity(?.d.i4) == 0
+    doAssert ?.identity(d.i4) == 0
+    doAssert ?.identity(d) == nil
+    doAssert ?.identity(d[]) == default(typeof(d[]))
+    doAssert ?.identity(d[]).i4 == 0
+    var a: A
+    doAssert ?.identity(a) == default(A)
+    doAssert ?.identity(a.a0) == 0
+    doAssert ?.identity(a.d) == nil
+    doAssert ?.identity(a.d.i4) == 0
+
+  block: # lvalue semantic propagation
+    type
+      A = ref object
+        a0: A
+        a1: seq[A]
+        a2: int
+
+      B = object
+        b0: int
+        case cond: bool
+        of false: discard
+        of true:
+          b1: float
+
+    block:
+      var a: A
+      doAssert ?.a.a0.a1[0].a2.addr == nil
+      a = A(a2: 3)
+      doAssert ?.a.a0.a1[0].a2.addr == nil
+      a.a0 = a
+      a.a1 = @[a]
+      let p = ?.a.a0.a1[0].a2.addr
+      doAssert p != nil
+      p[] = 5
+      doAssert a.a2 == 5
+
+    block:
+      var b = B(cond: false, b0: 3)
+      let p = ?.b.b1.addr
+      doAssert p == nil
+      b = B(cond: true, b1: 4.5)
+      let p2 = ?.b.b1.addr
+      doAssert p2 != nil
+      p2[] = 4.6
+      doAssert b.b1 == 4.6
+      # useful pattern, impossible with Options
+      if (let p3 = ?.b.b1.addr; p3 != nil):
+        p3[] = 4.7
+      doAssert b.b1 == 4.7
+
+main()
+static: main()
diff --git a/tests/stdlib/twrongstattype.nim b/tests/stdlib/twrongstattype.nim
new file mode 100644
index 000000000..4a1fc30c6
--- /dev/null
+++ b/tests/stdlib/twrongstattype.nim
@@ -0,0 +1,14 @@
+# issue #24076
+
+when defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
+  import std/posix
+  proc uid(x: uint32): Uid = Uid(x)
+  var y: uint32
+  let myUid = geteuid()
+  discard myUid == uid(y)
+  proc dev(x: uint32): Dev = Dev(x)
+  let myDev = 1.Dev
+  discard myDev == dev(y)
+  proc nlink(x: uint32): Nlink = Nlink(x)
+  let myNlink = 1.Nlink
+  discard myNlink == nlink(y)
diff --git a/tests/stdlib/txmlgen.nim b/tests/stdlib/txmlgen.nim
deleted file mode 100644
index fa1dffe56..000000000
--- a/tests/stdlib/txmlgen.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-discard """
-  file: "txmlgen.nim"
-  output: "<h1><a href=\"http://force7.de/nim\">Nim</a></h1>"
-"""
-import htmlgen
-
-var nim = "Nim"
-echo h1(a(href="http://force7.de/nim", nim))
-
-
-
-
diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim
index a849859e3..add12a3fc 100644
--- a/tests/stdlib/txmltree.nim
+++ b/tests/stdlib/txmltree.nim
@@ -1,27 +1,120 @@
 discard """
-  file: "txmltree.nim"
-  output: '''true
-true
-true
-true
-true
-'''
+  matrix: "--mm:refc; --mm:orc"
 """
 
-import xmltree, strtabs
+import std/[xmltree, assertions, xmlparser]
 
-var x = <>a(href="nim.de", newText("www.nim-test.de"))
 
-echo($x == "<a href=\"nim.de\">www.nim-test.de</a>")
+block:
+  var
+    x: XmlNode
 
-echo(newText("foo").innerText == "foo")
-echo(newEntity("bar").innerText == "bar")
-echo(newComment("baz").innerText == "")
+  x = <>a(href = "http://nim-lang.org", newText("Nim rules."))
+  doAssert $x == """<a href="http://nim-lang.org">Nim rules.</a>"""
 
-let y = newXmlTree("x", [
-  newText("foo"),
-  newXmlTree("y", [
-    newText("bar")
+  x = <>outer(<>inner())
+  doAssert $x == """<outer>
+  <inner />
+</outer>"""
+
+  x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4()))
+  doAssert $x == """<outer>
+  <middle>
+    <inner1 />
+    <inner2 />
+    <inner3 />
+    <inner4 />
+  </middle>
+</outer>"""
+
+  x = <>l0(<>l1(<>l2(<>l3(<>l4()))))
+  doAssert $x == """<l0>
+  <l1>
+    <l2>
+      <l3>
+        <l4 />
+      </l3>
+    </l2>
+  </l1>
+</l0>"""
+
+  x = <>l0(<>l1p1(), <>l1p2(), <>l1p3())
+  doAssert $x == """<l0>
+  <l1p1 />
+  <l1p2 />
+  <l1p3 />
+</l0>"""
+
+  x = <>l0(<>l1(<>l2p1(), <>l2p2()))
+  doAssert $x == """<l0>
+  <l1>
+    <l2p1 />
+    <l2p2 />
+  </l1>
+</l0>"""
+
+  x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4()))
+  doAssert $x == """<l0>
+  <l1>
+    <l2_1 />
+    <l2_2>
+      <l3_1 />
+      <l3_2 />
+      <l3_3>
+        <l4_1 />
+        <l4_2 />
+        <l4_3 />
+      </l3_3>
+    </l2_2>
+    <l2_3 />
+    <l2_4 />
+  </l1>
+</l0>"""
+
+  let
+    innermost = newElement("innermost")
+    middle = newXmlTree("middle", [innermost])
+  innermost.add newText("innermost text")
+  x = newXmlTree("outer", [middle])
+  doAssert $x == """<outer>
+  <middle>
+    <innermost>innermost text</innermost>
+  </middle>
+</outer>"""
+
+  x = newElement("myTag")
+  x.add newText("my text")
+  x.add newElement("sonTag")
+  x.add newEntity("my entity")
+  doAssert $x == "<myTag>my text<sonTag />&my entity;</myTag>"
+
+block: # bug #21290
+  let x = newXmlTree("foo",[
+    newXmlTree("bar",[
+      newText("Hola"),
+      newXmlTree("qux",[
+        newXmlTree("plugh",[])
+      ])
+    ])
   ])
-])
-echo(y.innerText == "foobar")
+
+  let s = $x
+  doAssert $parseXml(s) == s
+  doAssert s == """<foo>
+  <bar>Hola<qux>    <plugh />  </qux></bar>
+</foo>"""
+
+block: #21541
+  let root = <>root()
+  root.add <>child(newText("hello"))
+  root.add <>more(newVerbatimText("hola"))
+  let s = $root
+  doAssert s == """<root>
+  <child>hello</child>
+  <more>hola</more>
+</root>"""
+
+  let temp = newVerbatimText("Hello!")
+  doAssert temp.text == "Hello!"
+  temp.text = "Hola!"
+  doAssert temp.text == "Hola!"
diff --git a/tests/stdlib/tyield.nim b/tests/stdlib/tyield.nim
new file mode 100644
index 000000000..f385ddd05
--- /dev/null
+++ b/tests/stdlib/tyield.nim
@@ -0,0 +1,258 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/[sugar, algorithm]
+import std/assertions
+
+block:
+  var x = @[(6.0, 6, '6'),
+            (5.0, 5, '5'),
+            (4.0, 4, '4'),
+            (3.0, 3, '3'),
+            (2.0, 2, '2'),
+            (1.0, 1, '1')]
+
+  let y = x.reversed
+
+  block:
+    let res = collect:
+      for (f, i, c) in x:
+        (f, i, c)
+
+    doAssert res == x
+
+  iterator popAscending[T](q: var seq[T]): T =
+    while q.len > 0: yield q.pop
+
+  block:
+    var res = collect:
+      for f, i, c in popAscending(x):
+        (f, i, c)
+
+    doAssert res == y
+
+    let z = reversed(res)
+    let res2 = collect:
+      for (f, i, c) in popAscending(res):
+        (f, i, c)
+
+    doAssert res2 == z
+
+
+block:
+  var visits = 0
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    iterator foo(): (int, int) =
+      yield bar()
+
+    for a, b in foo():
+      doAssert a == b
+
+    doAssert visits == 1
+
+  block:
+    proc iterAux(a: seq[int], i: var int): (int, string) =
+      result = (a[i], $a[i])
+      inc i
+
+    iterator pairs(a: seq[int]): (int, string) =
+      var i = 0
+      while i < a.len:
+        yield iterAux(a, i)
+
+    var x = newSeq[int](10)
+    for i in 0 ..< x.len:
+      x[i] = i
+
+    let res = collect:
+      for k, v in x:
+        (k, v)
+
+    let expected = collect:
+      for i in 0 ..< x.len:
+        (i, $i)
+
+    doAssert res == expected
+
+  block:
+    proc bar(): (int, int, int) =
+      inc visits
+      (visits, visits, visits)
+
+    iterator foo(): (int, int, int) =
+      yield bar()
+
+    for a, b, c in foo():
+      doAssert a == b
+
+    doAssert visits == 2
+
+
+  block:
+
+    proc bar(): int =
+      inc visits
+      visits
+
+    proc car(): int =
+      inc visits
+      visits
+
+    iterator foo(): (int, int) =
+      yield (bar(), car())
+      yield (bar(), car())
+
+    for a, b in foo():
+      doAssert b == a + 1
+
+    doAssert visits == 6
+
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield (12, t2())
+      yield bar()
+
+    let res = collect:
+      for (a, b) in foo():
+        (a, b)
+
+    doAssert res == @[(12, 99), (7, 7)]
+    doAssert visits == 7
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield ((12, t2()))
+      yield (bar())
+
+    let res = collect:
+      for (a, b) in foo():
+        (a, b)
+
+    doAssert res == @[(12, 99), (8, 8)]
+    doAssert visits == 8
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t1(): int = 99
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield (t1(), t2())
+      yield bar()
+
+    let res = collect:
+      for a, b in foo():
+        (a, b)
+
+    doAssert res == @[(99, 99), (9, 9)]
+    doAssert visits == 9
+
+
+  block:
+    proc bar(): ((int, int), string) =
+      inc visits
+      ((visits, visits), $visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): ((int, int), string) =
+      yield ((1, 2), $t2())
+      yield bar()
+
+    let res = collect:
+      for a, b in foo():
+        (a, b)
+
+    doAssert res == @[((1, 2), "99"), ((10, 10), "10")]
+    doAssert visits == 10
+
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    iterator foo(): (int, int) =
+      yield (for i in 0 ..< 10: discard bar(); bar())
+      yield (bar())
+
+    let res = collect:
+      for (a, b) in foo():
+        (a, b)
+
+    doAssert res == @[(21, 21), (22, 22)]
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield if true: bar() else: (t2(), t2())
+      yield (bar())
+
+    let res = collect:
+      for a, b in foo():
+        (a, b)
+
+    doAssert res == @[(23, 23), (24, 24)]
+
+
+block:
+  iterator foo(): (int, int, int) =
+    var time = 777
+    yield (1, time, 3)
+
+  let res = collect:
+    for a, b, c in foo():
+      (a, b, c)
+
+  doAssert res == @[(1, 777, 3)]
+
+block:
+  iterator foo(): (int, int, int) =
+    var time = 777
+    yield (1, time, 3)
+
+  let res = collect:
+    for t in foo():
+      (t[0], t[1], t[2])
+
+  doAssert res == @[(1, 777, 3)]
+
+
+block:
+  proc bar(): (int, int, int) =
+    (1, 2, 3)
+  iterator foo(): (int, int, int) =
+    yield bar()
+
+  let res = collect:
+    for a, b, c in foo():
+      (a, b, c)
+
+  doAssert res == @[(1, 2, 3)]
diff --git a/tests/stdlib/unixsockettest.nim b/tests/stdlib/unixsockettest.nim
new file mode 100644
index 000000000..8f95d0808
--- /dev/null
+++ b/tests/stdlib/unixsockettest.nim
@@ -0,0 +1,26 @@
+import std/[assertions, net, os]
+
+let unixSocketPath = getCurrentDir() / "usox"
+
+removeFile(unixSocketPath)
+
+let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
+socket.bindUnix(unixSocketPath)
+socket.listen()
+
+var
+  clientSocket: Socket
+  data: string
+
+socket.accept(clientSocket)
+clientSocket.readLine(data)
+doAssert data == "data sent through the socket"
+clientSocket.send("Hello from server\c\l")
+
+clientSocket.readLine(data)
+doAssert data == "bye"
+clientSocket.send("bye\c\l")
+
+clientSocket.close()
+socket.close()
+removeFile(unixSocketPath)
diff --git a/tests/stdlib/uselocks.nim b/tests/stdlib/uselocks.nim
index cde9641b2..f87623b5e 100644
--- a/tests/stdlib/uselocks.nim
+++ b/tests/stdlib/uselocks.nim
@@ -1,4 +1,5 @@
 import locks
+import std/assertions
 
 type MyType* [T] = object
   lock: Lock
@@ -9,3 +10,7 @@ proc createMyType*[T]: MyType[T] =
 proc use* (m: var MyType): int =
   withLock m.lock:
     result = 3
+
+block:
+  var l: Lock
+  doAssert $l == "()"