[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1108872: marked as done (unblock: node-tar-fs/3.0.9+~cs2.0.4-1)



Your message dated Mon, 07 Jul 2025 12:25:31 +0000
with message-id <E1uYkuZ-00Aexs-1H@respighi.debian.org>
and subject line unblock node-tar-fs
has caused the Debian Bug report #1108872,
regarding unblock: node-tar-fs/3.0.9+~cs2.0.4-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1108872: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1108872
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: node-tar-fs@packages.debian.org, carnil@debian.org, yadd@debian.org
Control: affects -1 + src:node-tar-fs
User: release.debian.org@packages.debian.org
Usertags: unblock


[ Reason ]
node-tar-fs is vulnerable to CVE-2025-48387: it may extarct files
outside the specified directory.

[ Impact ]
Medium security issue

[ Tests ]
Tests OK

[ Risks ]
Low risk, patch is trivial

[ Checklist ]
  [X] all changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in testing

[ Other info ]
In this release, upstream choose another test framework not available in
Debian. Then I added a patch to use "tape" which is available. This permits
to drop useless test modules previously embedded.

That's why I added 2 debdiff here:
- the global debdiff
- a debdiff that shows only changes related to installed files

Best regards,
Xavier

unblock node-tar-fs/3.0.9+~cs2.0.4-1
diff --git a/debian/changelog b/debian/changelog
index b01fb20..a93913e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+node-tar-fs (3.0.9+~cs2.0.4-1) unstable; urgency=medium
+
+  * Team upload
+  * Keep previous test from 2.1.1 with tape
+  * New upstream version (Closes: CVE-2025-48387)
+
+ -- Yadd <yadd@debian.org>  Tue, 03 Jun 2025 17:33:46 +0200
+
 node-tar-fs (3.0.8+~cs2.0.4-1) unstable; urgency=medium
 
   * Team upload
diff --git a/debian/patches/fix-test.patch b/debian/patches/fix-test.patch
deleted file mode 100644
index d70b080..0000000
--- a/debian/patches/fix-test.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-Description: Fix test when .gitignore doesn't exist
-Author: Yadd <yadd@debian.org>
-Forwarded: not-needed
-Last-Update: 2025-03-30
-
---- a/test/index.js
-+++ b/test/index.js
-@@ -60,11 +60,11 @@
- })
- 
- test('symlink', function (t) {
--  if (win32) { // no symlink support on win32 currently. TODO: test if this can be enabled somehow
-+  //if (win32) { // no symlink support on win32 currently. TODO: test if this can be enabled somehow
-     t.plan(1)
-     t.ok(true)
-     return
--  }
-+  //}
- 
-   t.plan(5)
- 
-@@ -93,11 +93,11 @@
- })
- 
- test('follow symlinks', function (t) {
--  if (win32) { // no symlink support on win32 currently. TODO: test if this can be enabled somehow
-+  //if (win32) { // no symlink support on win32 currently. TODO: test if this can be enabled somehow
-     t.plan(1)
-     t.ok(true)
-     return
--  }
-+  //}
- 
-   t.plan(5)
- 
diff --git a/debian/patches/keep-test-with-tape.patch b/debian/patches/keep-test-with-tape.patch
new file mode 100644
index 0000000..d9c1daf
--- /dev/null
+++ b/debian/patches/keep-test-with-tape.patch
@@ -0,0 +1,265 @@
+Description: keep test with tape
+Author: Yadd <yadd@debian.org>
+Forwarded: not-needed
+Last-Update: 2025-03-31
+
+--- a/test/index.js
++++ b/test/index.js
+@@ -1,4 +1,4 @@
+-const test = require('brittle')
++const test = require('tape')
+ const rimraf = require('rimraf')
+ const tar = require('../index')
+ const tarStream = require('tar-stream')
+@@ -23,13 +23,13 @@
+     .pipe(tar.extract(b))
+     .on('finish', function () {
+       const files = fs.readdirSync(b)
+-      t.is(files.length, 1)
+-      t.is(files[0], 'hello.txt')
++      t.same(files.length, 1)
++      t.same(files[0], 'hello.txt')
+       const fileB = path.join(b, files[0])
+       const fileA = path.join(a, files[0])
+-      t.alike(fs.readFileSync(fileB, 'utf-8'), fs.readFileSync(fileA, 'utf-8'))
+-      t.alike(fs.statSync(fileB).mode, fs.statSync(fileA).mode)
+-      t.alike(mtime(fs.statSync(fileB)), mtime(fs.statSync(fileA)))
++      t.same(fs.readFileSync(fileB, 'utf-8'), fs.readFileSync(fileA, 'utf-8'))
++      t.same(fs.statSync(fileB).mode, fs.statSync(fileA).mode)
++      t.same(mtime(fs.statSync(fileB)), mtime(fs.statSync(fileA)))
+     })
+ })
+ 
+@@ -44,18 +44,18 @@
+     .pipe(tar.extract(b))
+     .on('finish', function () {
+       const files = fs.readdirSync(b)
+-      t.is(files.length, 1)
+-      t.is(files[0], 'a')
++      t.same(files.length, 1)
++      t.same(files[0], 'a')
+       const dirB = path.join(b, files[0])
+       const dirA = path.join(a, files[0])
+-      t.alike(fs.statSync(dirB).mode, fs.statSync(dirA).mode)
+-      t.alike(mtime(fs.statSync(dirB)), mtime(fs.statSync(dirA)))
++      t.same(fs.statSync(dirB).mode, fs.statSync(dirA).mode)
++      t.same(mtime(fs.statSync(dirB)), mtime(fs.statSync(dirA)))
+       t.ok(fs.statSync(dirB).isDirectory())
+       const fileB = path.join(dirB, 'test.txt')
+       const fileA = path.join(dirA, 'test.txt')
+-      t.alike(fs.readFileSync(fileB, 'utf-8'), fs.readFileSync(fileA, 'utf-8'))
+-      t.alike(fs.statSync(fileB).mode, fs.statSync(fileA).mode)
+-      t.alike(mtime(fs.statSync(fileB)), mtime(fs.statSync(fileA)))
++      t.same(fs.readFileSync(fileB, 'utf-8'), fs.readFileSync(fileA, 'utf-8'))
++      t.same(fs.statSync(fileB).mode, fs.statSync(fileA).mode)
++      t.same(mtime(fs.statSync(fileB)), mtime(fs.statSync(fileA)))
+     })
+ })
+ 
+@@ -80,15 +80,15 @@
+     .pipe(tar.extract(b))
+     .on('finish', function () {
+       const files = fs.readdirSync(b).sort()
+-      t.is(files.length, 2)
+-      t.is(files[0], '.gitignore')
+-      t.is(files[1], 'link')
++      t.same(files.length, 2)
++      t.same(files[0], '.gitignore')
++      t.same(files[1], 'link')
+ 
+       const linkA = path.join(a, 'link')
+       const linkB = path.join(b, 'link')
+ 
+-      t.alike(mtime(fs.lstatSync(linkB)), mtime(fs.lstatSync(linkA)))
+-      t.alike(fs.readlinkSync(linkB), fs.readlinkSync(linkA))
++      t.same(mtime(fs.lstatSync(linkB)), mtime(fs.lstatSync(linkA)))
++      t.same(fs.readlinkSync(linkB), fs.readlinkSync(linkA))
+     })
+ })
+ 
+@@ -113,15 +113,15 @@
+     .pipe(tar.extract(b))
+     .on('finish', function () {
+       const files = fs.readdirSync(b).sort()
+-      t.is(files.length, 2)
+-      t.is(files[0], '.gitignore')
+-      t.is(files[1], 'link')
++      t.same(files.length, 2)
++      t.same(files[0], '.gitignore')
++      t.same(files[1], 'link')
+ 
+       const file1 = path.join(b, '.gitignore')
+       const file2 = path.join(b, 'link')
+ 
+-      t.alike(mtime(fs.lstatSync(file1)), mtime(fs.lstatSync(file2)))
+-      t.alike(fs.readFileSync(file1), fs.readFileSync(file2))
++      t.same(mtime(fs.lstatSync(file1)), mtime(fs.lstatSync(file2)))
++      t.same(fs.readFileSync(file1), fs.readFileSync(file2))
+     })
+ })
+ 
+@@ -137,8 +137,8 @@
+     .pipe(tar.extract(b, { strip: 1 }))
+     .on('finish', function () {
+       const files = fs.readdirSync(b).sort()
+-      t.is(files.length, 1)
+-      t.is(files[0], 'test.txt')
++      t.same(files.length, 1)
++      t.same(files[0], 'test.txt')
+     })
+ })
+ 
+@@ -159,8 +159,8 @@
+     .pipe(tar.extract(b, { strip: 1, map: uppercase }))
+     .on('finish', function () {
+       const files = fs.readdirSync(b).sort()
+-      t.is(files.length, 1)
+-      t.is(files[0], 'TEST.TXT')
++      t.same(files.length, 1)
++      t.same(files[0], 'TEST.TXT')
+     })
+ })
+ 
+@@ -184,9 +184,9 @@
+     .on('finish', function () {
+       const files = fs.readdirSync(b).sort()
+       const stat = fs.statSync(path.join(b, 'a'))
+-      t.is(files.length, 1)
++      t.same(files.length, 1)
+       if (!win32) {
+-        t.is(stat.mode & parseInt(777, 8), parseInt(700, 8))
++        t.same(stat.mode & parseInt(777, 8), parseInt(700, 8))
+       }
+     })
+ })
+@@ -200,18 +200,18 @@
+   const entries = ['file1', 'sub-files/file3', 'sub-dir']
+ 
+   rimraf.sync(b)
+-  tar.pack(a, { entries })
++  tar.pack(a, { entries: entries })
+     .pipe(tar.extract(b))
+     .on('finish', function () {
+       const files = fs.readdirSync(b)
+-      t.is(files.length, 3)
+-      t.not(files.indexOf('file1'), -1)
+-      t.not(files.indexOf('sub-files'), -1)
+-      t.not(files.indexOf('sub-dir'), -1)
++      t.same(files.length, 3)
++      t.notSame(files.indexOf('file1'), -1)
++      t.notSame(files.indexOf('sub-files'), -1)
++      t.notSame(files.indexOf('sub-dir'), -1)
+       const subFiles = fs.readdirSync(path.join(b, 'sub-files'))
+-      t.alike(subFiles, ['file3'])
++      t.same(subFiles, ['file3'])
+       const subDir = fs.readdirSync(path.join(b, 'sub-dir'))
+-      t.alike(subDir, ['file5'])
++      t.same(subDir, ['file5'])
+     })
+ })
+ 
+@@ -221,7 +221,7 @@
+   const e = path.join(__dirname, 'fixtures', 'e')
+ 
+   const checkHeaderType = function (header) {
+-    if (header.name.indexOf('.') === -1) t.is(header.type, header.name)
++    if (header.name.indexOf('.') === -1) t.same(header.type, header.name)
+   }
+ 
+   tar.pack(e, { map: checkHeaderType })
+@@ -235,20 +235,21 @@
+ 
+   rimraf.sync(b)
+ 
+-  let packEntries = 0
+-  let extractEntries = 0
++  var packEntries = 0
++  var extractEntries = 0
+ 
+   const countPackEntry = function (header) { packEntries++ }
+   const countExtractEntry = function (header) { extractEntries++ }
+ 
++  var pack
+   const onPackFinish = function (passedPack) {
+-    t.is(packEntries, 2, 'All entries have been packed') // 2 entries - the file and base directory
+-    t.is(passedPack, pack, 'The finish hook passes the pack')
++    t.equal(packEntries, 2, 'All entries have been packed') // 2 entries - the file and base directory
++    t.equal(passedPack, pack, 'The finish hook passes the pack')
+   }
+ 
+-  const onExtractFinish = function () { t.is(extractEntries, 2) }
++  const onExtractFinish = function () { t.equal(extractEntries, 2) }
+ 
+-  const pack = tar.pack(a, { map: countPackEntry, finish: onPackFinish })
++  pack = tar.pack(a, { map: countPackEntry, finish: onPackFinish })
+ 
+   pack.pipe(tar.extract(b, { map: countExtractEntry, finish: onExtractFinish }))
+     .on('finish', function () {
+@@ -280,28 +281,20 @@
+   })
+ 
+   function packB (pack) {
+-    tar.pack(b, { pack, map: prefixer('b-files') })
++    tar.pack(b, { pack: pack, map: prefixer('b-files') })
+       .pipe(tar.extract(out))
+       .on('finish', assertResults)
+   }
+ 
+   function assertResults () {
+     const containers = fs.readdirSync(out)
+-    t.alike(containers, ['a-files', 'b-files'])
++    t.deepEqual(containers, ['a-files', 'b-files'])
+     const aFiles = fs.readdirSync(path.join(out, 'a-files'))
+-    t.alike(aFiles, ['hello.txt'])
++    t.deepEqual(aFiles, ['hello.txt'])
+   }
+ })
+ 
+ test('do not extract invalid tar', function (t) {
+-  if (win32) { // no symlink support on win32 currently. TODO: test if this can be enabled somehow
+-    t.plan(1)
+-    t.ok(true)
+-    return
+-  }
+-
+-  t.plan(2)
+-
+   const a = path.join(__dirname, 'fixtures', 'invalid.tar')
+ 
+   const out = path.join(__dirname, 'fixtures', 'invalid')
+@@ -314,22 +307,12 @@
+       t.ok(/is not a valid symlink/i.test(err.message))
+       fs.stat(path.join(out, '../bar'), function (err) {
+         t.ok(err)
++        t.end()
+       })
+     })
+-    .on('finish', function () {
+-      t.fail('should not finish')
+-    })
+ })
+ 
+ test('no abs hardlink targets', function (t) {
+-  if (win32) { // no symlink support on win32 currently. TODO: test if this can be enabled somehow
+-    t.plan(1)
+-    t.ok(true)
+-    return
+-  }
+-
+-  t.plan(3)
+-
+   const out = path.join(__dirname, 'fixtures', 'invalid')
+   const outside = path.join(__dirname, 'fixtures', 'outside')
+ 
+@@ -355,8 +338,9 @@
+     .on('error', function (err) {
+       t.ok(err, 'had error')
+       fs.readFile(outside, 'utf-8', function (err, str) {
+-        t.absent(err, 'no error')
+-        t.is(str, 'something')
++        t.error(err, 'no error')
++        t.same(str, 'something')
++        t.end()
+       })
+     })
+ })
diff --git a/debian/patches/series b/debian/patches/series
index a22cf9d..a9a0458 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1 @@
-fix-test.patch
+keep-test-with-tape.patch
diff --git a/debian/tests/test_modules/b4a/LICENSE b/debian/tests/test_modules/b4a/LICENSE
deleted file mode 100644
index 261eeb9..0000000
--- a/debian/tests/test_modules/b4a/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/debian/tests/test_modules/b4a/README.md b/debian/tests/test_modules/b4a/README.md
deleted file mode 100644
index 6acf9ae..0000000
--- a/debian/tests/test_modules/b4a/README.md
+++ /dev/null
@@ -1,145 +0,0 @@
-# Buffer for Array
-
-Buffer for Array (B4A) provides a set of functions for bridging the gap between the Node.js `Buffer` class and the `Uint8Array` class. A browser compatibility layer is also included, making it possible to use B4A in both Node.js and browsers without having to worry about whether you're dealing with buffers or typed arrays.
-
-## Installation
-
-```sh
-npm install b4a
-```
-
-## API
-
-#### `b4a.isBuffer(value)`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferisbufferobj
-
-This will also return `true` when passed a `Uint8Array`.
-
-#### `b4a.isEncoding(encoding)`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferisencodingencoding
-
-#### `b4a.alloc(size[, fill[, encoding]])`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferallocsize-fill-encoding
-
-#### `b4a.allocUnsafe(size)`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferallocunsafesize
-
-#### `b4a.allocUnsafeSlow(size)`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferallocunsafeslowsize
-
-#### `b4a.byteLength(string)`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferbytelengthstring-encoding
-
-#### `b4a.compare(buf1, buf2)`
-
-See https://nodejs.org/api/buffer.html#static-method-buffercomparebuf1-buf2
-
-#### `b4a.concat(buffers[, totalLength])`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferconcatlist-totallength
-
-#### `b4a.copy(source, target[, targetStart[, sourceStart[, sourceEnd]]])`
-
-See https://nodejs.org/api/buffer.html#bufcopytarget-targetstart-sourcestart-sourceend
-
-#### `b4a.equals(buf1, buf2)`
-
-See https://nodejs.org/api/buffer.html#bufequalsotherbuffer
-
-#### `b4a.fill(buffer, value[, offset[, end]][, encoding])`
-
-See https://nodejs.org/api/buffer.html#buffillvalue-offset-end-encoding
-
-#### `b4a.from(array)`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferfromarray
-
-#### `b4a.from(arrayBuffer[, byteOffset[, length]])`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferfromarraybuffer-byteoffset-length
-
-#### `b4a.from(buffer)`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferfrombuffer
-
-#### `b4a.from(string[, encoding])`
-
-See https://nodejs.org/api/buffer.html#static-method-bufferfromstring-encoding
-
-#### `b4a.includes(buffer, value[, byteOffset][, encoding])`
-
-See https://nodejs.org/api/buffer.html#bufincludesvalue-byteoffset-encoding
-
-#### `b4a.indexOf(buffer, value[, byteOffset][, encoding])`
-
-See https://nodejs.org/api/buffer.html#bufindexofvalue-byteoffset-encoding
-
-#### `b4a.lastIndexOf(buffer, value[, byteOffset][, encoding])`
-
-See https://nodejs.org/api/buffer.html#buflastindexofvalue-byteoffset-encoding
-
-#### `b4a.swap16(buffer)`
-
-See https://nodejs.org/api/buffer.html#bufswap16
-
-#### `b4a.swap32(buffer)`
-
-See https://nodejs.org/api/buffer.html#bufswap32
-
-#### `b4a.swap64(buffer)`
-
-See https://nodejs.org/api/buffer.html#bufswap64
-
-#### `b4a.toBuffer(buffer)`
-
-Convert a buffer to its canonical representation. In Node.js, the canonical representation is a `Buffer`. In the browser, the canonical representation is a `Uint8Array`.
-
-#### `b4a.toString(buffer, [encoding[, start[, end]]])`
-
-See https://nodejs.org/api/buffer.html#buftostringencoding-start-end
-
-#### `b4a.write(buffer, string[, offset[, length]][, encoding])`
-
-See https://nodejs.org/api/buffer.html#bufwritestring-offset-length-encoding
-
-#### `b4a.writeDoubleLE(buffer, value[, offset])`
-
-See https://nodejs.org/api/buffer.html#bufwritedoublelevalue-offset
-
-#### `b4a.writeFloatLE(buffer, value[, offset])`
-
-See https://nodejs.org/api/buffer.html#bufwritefloatlevalue-offset
-
-#### `b4a.writeUInt32LE(buffer, value[, offset])`
-
-https://nodejs.org/api/buffer.html#bufwriteuint32levalue-offset
-
-#### `b4a.writeInt32LE(buffer, value[, offset])`
-
-See https://nodejs.org/api/buffer.html#bufwriteint32levalue-offset
-
-#### `b4a.readDoubleLE(buffer[, offset])`
-
-See https://nodejs.org/api/buffer.html#bufreaddoubleleoffset
-
-#### `b4a.readFloatLE(buffer[, offset])`
-
-See https://nodejs.org/api/buffer.html#bufreadfloatleoffset
-
-#### `b4a.readUInt32LE(buffer[, offset])`
-
-See https://nodejs.org/api/buffer.html#bufreaduint32leoffset
-
-#### `b4a.readInt32LE(buffer[, offset])`
-
-See https://nodejs.org/api/buffer.html#bufreadint32leoffset
-
-## License
-
-Apache 2.0
diff --git a/debian/tests/test_modules/b4a/browser.js b/debian/tests/test_modules/b4a/browser.js
deleted file mode 100644
index 798a32f..0000000
--- a/debian/tests/test_modules/b4a/browser.js
+++ /dev/null
@@ -1,576 +0,0 @@
-const ascii = require('./lib/ascii')
-const base64 = require('./lib/base64')
-const hex = require('./lib/hex')
-const utf8 = require('./lib/utf8')
-const utf16le = require('./lib/utf16le')
-
-const LE = new Uint8Array(Uint16Array.of(0xff).buffer)[0] === 0xff
-
-function codecFor (encoding) {
-  switch (encoding) {
-    case 'ascii':
-      return ascii
-    case 'base64':
-      return base64
-    case 'hex':
-      return hex
-    case 'utf8':
-    case 'utf-8':
-    case undefined:
-    case null:
-      return utf8
-    case 'ucs2':
-    case 'ucs-2':
-    case 'utf16le':
-    case 'utf-16le':
-      return utf16le
-    default:
-      throw new Error(`Unknown encoding: ${encoding}`)
-  }
-}
-
-function isBuffer (value) {
-  return value instanceof Uint8Array
-}
-
-function isEncoding (encoding) {
-  try {
-    codecFor(encoding)
-    return true
-  } catch {
-    return false
-  }
-}
-
-function alloc (size, fill, encoding) {
-  const buffer = new Uint8Array(size)
-  if (fill !== undefined) exports.fill(buffer, fill, 0, buffer.byteLength, encoding)
-  return buffer
-}
-
-function allocUnsafe (size) {
-  return new Uint8Array(size)
-}
-
-function allocUnsafeSlow (size) {
-  return new Uint8Array(size)
-}
-
-function byteLength (string, encoding) {
-  return codecFor(encoding).byteLength(string)
-}
-
-function compare (a, b) {
-  if (a === b) return 0
-
-  const len = Math.min(a.byteLength, b.byteLength)
-
-  a = new DataView(a.buffer, a.byteOffset, a.byteLength)
-  b = new DataView(b.buffer, b.byteOffset, b.byteLength)
-
-  let i = 0
-
-  for (let n = len - (len % 4); i < n; i += 4) {
-    const x = a.getUint32(i, LE)
-    const y = b.getUint32(i, LE)
-    if (x !== y) break
-  }
-
-  for (; i < len; i++) {
-    const x = a.getUint8(i)
-    const y = b.getUint8(i)
-    if (x < y) return -1
-    if (x > y) return 1
-  }
-
-  return a.byteLength > b.byteLength ? 1 : a.byteLength < b.byteLength ? -1 : 0
-}
-
-function concat (buffers, totalLength) {
-  if (totalLength === undefined) {
-    totalLength = buffers.reduce((len, buffer) => len + buffer.byteLength, 0)
-  }
-
-  const result = new Uint8Array(totalLength)
-
-  let offset = 0
-  for (const buffer of buffers) {
-    if (offset + buffer.byteLength > result.byteLength) {
-      const sub = buffer.subarray(0, result.byteLength - offset)
-      result.set(sub, offset)
-      return result
-    }
-    result.set(buffer, offset)
-    offset += buffer.byteLength
-  }
-
-  return result
-}
-
-function copy (source, target, targetStart = 0, start = 0, end = source.byteLength) {
-  if (end > 0 && end < start) return 0
-  if (end === start) return 0
-  if (source.byteLength === 0 || target.byteLength === 0) return 0
-
-  if (targetStart < 0) throw new RangeError('targetStart is out of range')
-  if (start < 0 || start >= source.byteLength) throw new RangeError('sourceStart is out of range')
-  if (end < 0) throw new RangeError('sourceEnd is out of range')
-
-  if (targetStart >= target.byteLength) targetStart = target.byteLength
-  if (end > source.byteLength) end = source.byteLength
-  if (target.byteLength - targetStart < end - start) {
-    end = target.length - targetStart + start
-  }
-
-  const len = end - start
-
-  if (source === target) {
-    target.copyWithin(targetStart, start, end)
-  } else {
-    target.set(source.subarray(start, end), targetStart)
-  }
-
-  return len
-}
-
-function equals (a, b) {
-  if (a === b) return true
-  if (a.byteLength !== b.byteLength) return false
-
-  const len = a.byteLength
-
-  a = new DataView(a.buffer, a.byteOffset, a.byteLength)
-  b = new DataView(b.buffer, b.byteOffset, b.byteLength)
-
-  let i = 0
-
-  for (let n = len - (len % 4); i < n; i += 4) {
-    if (a.getUint32(i, LE) !== b.getUint32(i, LE)) return false
-  }
-
-  for (; i < len; i++) {
-    if (a.getUint8(i) !== b.getUint8(i)) return false
-  }
-
-  return true
-}
-
-function fill (buffer, value, offset, end, encoding) {
-  if (typeof value === 'string') {
-    // fill(buffer, string, encoding)
-    if (typeof offset === 'string') {
-      encoding = offset
-      offset = 0
-      end = buffer.byteLength
-
-    // fill(buffer, string, offset, encoding)
-    } else if (typeof end === 'string') {
-      encoding = end
-      end = buffer.byteLength
-    }
-  } else if (typeof value === 'number') {
-    value = value & 0xff
-  } else if (typeof value === 'boolean') {
-    value = +value
-  }
-
-  if (offset < 0 || buffer.byteLength < offset || buffer.byteLength < end) {
-    throw new RangeError('Out of range index')
-  }
-
-  if (offset === undefined) offset = 0
-  if (end === undefined) end = buffer.byteLength
-
-  if (end <= offset) return buffer
-
-  if (!value) value = 0
-
-  if (typeof value === 'number') {
-    for (let i = offset; i < end; ++i) {
-      buffer[i] = value
-    }
-  } else {
-    value = isBuffer(value) ? value : from(value, encoding)
-
-    const len = value.byteLength
-
-    for (let i = 0; i < end - offset; ++i) {
-      buffer[i + offset] = value[i % len]
-    }
-  }
-
-  return buffer
-}
-
-function from (value, encodingOrOffset, length) {
-  // from(string, encoding)
-  if (typeof value === 'string') return fromString(value, encodingOrOffset)
-
-  // from(array)
-  if (Array.isArray(value)) return fromArray(value)
-
-  // from(buffer)
-  if (ArrayBuffer.isView(value)) return fromBuffer(value)
-
-  // from(arrayBuffer[, byteOffset[, length]])
-  return fromArrayBuffer(value, encodingOrOffset, length)
-}
-
-function fromString (string, encoding) {
-  const codec = codecFor(encoding)
-  const buffer = new Uint8Array(codec.byteLength(string))
-  codec.write(buffer, string, 0, buffer.byteLength)
-  return buffer
-}
-
-function fromArray (array) {
-  const buffer = new Uint8Array(array.length)
-  buffer.set(array)
-  return buffer
-}
-
-function fromBuffer (buffer) {
-  const copy = new Uint8Array(buffer.byteLength)
-  copy.set(buffer)
-  return copy
-}
-
-function fromArrayBuffer (arrayBuffer, byteOffset, length) {
-  return new Uint8Array(arrayBuffer, byteOffset, length)
-}
-
-function includes (buffer, value, byteOffset, encoding) {
-  return indexOf(buffer, value, byteOffset, encoding) !== -1
-}
-
-function bidirectionalIndexOf (buffer, value, byteOffset, encoding, first) {
-  if (buffer.byteLength === 0) return -1
-
-  if (typeof byteOffset === 'string') {
-    encoding = byteOffset
-    byteOffset = 0
-  } else if (byteOffset === undefined) {
-    byteOffset = first ? 0 : (buffer.length - 1)
-  } else if (byteOffset < 0) {
-    byteOffset += buffer.byteLength
-  }
-
-  if (byteOffset >= buffer.byteLength) {
-    if (first) return -1
-    else byteOffset = buffer.byteLength - 1
-  } else if (byteOffset < 0) {
-    if (first) byteOffset = 0
-    else return -1
-  }
-
-  if (typeof value === 'string') {
-    value = from(value, encoding)
-  } else if (typeof value === 'number') {
-    value = value & 0xff
-
-    if (first) {
-      return buffer.indexOf(value, byteOffset)
-    } else {
-      return buffer.lastIndexOf(value, byteOffset)
-    }
-  }
-
-  if (value.byteLength === 0) return -1
-
-  if (first) {
-    let foundIndex = -1
-
-    for (let i = byteOffset; i < buffer.byteLength; i++) {
-      if (buffer[i] === value[foundIndex === -1 ? 0 : i - foundIndex]) {
-        if (foundIndex === -1) foundIndex = i
-        if (i - foundIndex + 1 === value.byteLength) return foundIndex
-      } else {
-        if (foundIndex !== -1) i -= i - foundIndex
-        foundIndex = -1
-      }
-    }
-  } else {
-    if (byteOffset + value.byteLength > buffer.byteLength) {
-      byteOffset = buffer.byteLength - value.byteLength
-    }
-
-    for (let i = byteOffset; i >= 0; i--) {
-      let found = true
-
-      for (let j = 0; j < value.byteLength; j++) {
-        if (buffer[i + j] !== value[j]) {
-          found = false
-          break
-        }
-      }
-
-      if (found) return i
-    }
-  }
-
-  return -1
-}
-
-function indexOf (buffer, value, byteOffset, encoding) {
-  return bidirectionalIndexOf(buffer, value, byteOffset, encoding, true /* first */)
-}
-
-function lastIndexOf (buffer, value, byteOffset, encoding) {
-  return bidirectionalIndexOf(buffer, value, byteOffset, encoding, false /* last */)
-}
-
-function swap (buffer, n, m) {
-  const i = buffer[n]
-  buffer[n] = buffer[m]
-  buffer[m] = i
-}
-
-function swap16 (buffer) {
-  const len = buffer.byteLength
-
-  if (len % 2 !== 0) throw new RangeError('Buffer size must be a multiple of 16-bits')
-
-  for (let i = 0; i < len; i += 2) swap(buffer, i, i + 1)
-
-  return buffer
-}
-
-function swap32 (buffer) {
-  const len = buffer.byteLength
-
-  if (len % 4 !== 0) throw new RangeError('Buffer size must be a multiple of 32-bits')
-
-  for (let i = 0; i < len; i += 4) {
-    swap(buffer, i, i + 3)
-    swap(buffer, i + 1, i + 2)
-  }
-
-  return buffer
-}
-
-function swap64 (buffer) {
-  const len = buffer.byteLength
-
-  if (len % 8 !== 0) throw new RangeError('Buffer size must be a multiple of 64-bits')
-
-  for (let i = 0; i < len; i += 8) {
-    swap(buffer, i, i + 7)
-    swap(buffer, i + 1, i + 6)
-    swap(buffer, i + 2, i + 5)
-    swap(buffer, i + 3, i + 4)
-  }
-
-  return buffer
-}
-
-function toBuffer (buffer) {
-  return buffer
-}
-
-function toString (buffer, encoding, start = 0, end = buffer.byteLength) {
-  const len = buffer.byteLength
-
-  if (start >= len) return ''
-  if (end <= start) return ''
-  if (start < 0) start = 0
-  if (end > len) end = len
-
-  if (start !== 0 || end < len) buffer = buffer.subarray(start, end)
-
-  return codecFor(encoding).toString(buffer)
-}
-
-function write (buffer, string, offset, length, encoding) {
-  // write(buffer, string)
-  if (offset === undefined) {
-    encoding = 'utf8'
-
-  // write(buffer, string, encoding)
-  } else if (length === undefined && typeof offset === 'string') {
-    encoding = offset
-    offset = undefined
-
-  // write(buffer, string, offset, encoding)
-  } else if (encoding === undefined && typeof length === 'string') {
-    encoding = length
-    length = undefined
-  }
-
-  return codecFor(encoding).write(buffer, string, offset, length)
-}
-
-function writeDoubleLE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setFloat64(offset, value, true)
-
-  return offset + 8
-}
-
-function writeFloatLE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setFloat32(offset, value, true)
-
-  return offset + 4
-}
-
-function writeUInt32LE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setUint32(offset, value, true)
-
-  return offset + 4
-}
-
-function writeInt32LE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setInt32(offset, value, true)
-
-  return offset + 4
-}
-
-function readDoubleLE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getFloat64(offset, true)
-}
-
-function readFloatLE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getFloat32(offset, true)
-}
-
-function readUInt32LE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getUint32(offset, true)
-}
-
-function readInt32LE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getInt32(offset, true)
-}
-
-function writeDoubleBE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setFloat64(offset, value, false)
-
-  return offset + 8
-}
-
-function writeFloatBE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setFloat32(offset, value, false)
-
-  return offset + 4
-}
-
-function writeUInt32BE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setUint32(offset, value, false)
-
-  return offset + 4
-}
-
-function writeInt32BE (buffer, value, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-  view.setInt32(offset, value, false)
-
-  return offset + 4
-}
-
-function readDoubleBE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getFloat64(offset, false)
-}
-
-function readFloatBE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getFloat32(offset, false)
-}
-
-function readUInt32BE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getUint32(offset, false)
-}
-
-function readInt32BE (buffer, offset) {
-  if (offset === undefined) offset = 0
-
-  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-
-  return view.getInt32(offset, false)
-}
-
-module.exports = exports = {
-  isBuffer,
-  isEncoding,
-  alloc,
-  allocUnsafe,
-  allocUnsafeSlow,
-  byteLength,
-  compare,
-  concat,
-  copy,
-  equals,
-  fill,
-  from,
-  includes,
-  indexOf,
-  lastIndexOf,
-  swap16,
-  swap32,
-  swap64,
-  toBuffer,
-  toString,
-  write,
-  writeDoubleLE,
-  writeFloatLE,
-  writeUInt32LE,
-  writeInt32LE,
-  readDoubleLE,
-  readFloatLE,
-  readUInt32LE,
-  readInt32LE,
-  writeDoubleBE,
-  writeFloatBE,
-  writeUInt32BE,
-  writeInt32BE,
-  readDoubleBE,
-  readFloatBE,
-  readUInt32BE,
-  readInt32BE
-}
diff --git a/debian/tests/test_modules/b4a/index.js b/debian/tests/test_modules/b4a/index.js
deleted file mode 100644
index 5c807d8..0000000
--- a/debian/tests/test_modules/b4a/index.js
+++ /dev/null
@@ -1,189 +0,0 @@
-function isBuffer (value) {
-  return Buffer.isBuffer(value) || value instanceof Uint8Array
-}
-
-function isEncoding (encoding) {
-  return Buffer.isEncoding(encoding)
-}
-
-function alloc (size, fill, encoding) {
-  return Buffer.alloc(size, fill, encoding)
-}
-
-function allocUnsafe (size) {
-  return Buffer.allocUnsafe(size)
-}
-
-function allocUnsafeSlow (size) {
-  return Buffer.allocUnsafeSlow(size)
-}
-
-function byteLength (string, encoding) {
-  return Buffer.byteLength(string, encoding)
-}
-
-function compare (a, b) {
-  return Buffer.compare(a, b)
-}
-
-function concat (buffers, totalLength) {
-  return Buffer.concat(buffers, totalLength)
-}
-
-function copy (source, target, targetStart, start, end) {
-  return toBuffer(source).copy(target, targetStart, start, end)
-}
-
-function equals (a, b) {
-  return toBuffer(a).equals(b)
-}
-
-function fill (buffer, value, offset, end, encoding) {
-  return toBuffer(buffer).fill(value, offset, end, encoding)
-}
-
-function from (value, encodingOrOffset, length) {
-  return Buffer.from(value, encodingOrOffset, length)
-}
-
-function includes (buffer, value, byteOffset, encoding) {
-  return toBuffer(buffer).includes(value, byteOffset, encoding)
-}
-
-function indexOf (buffer, value, byfeOffset, encoding) {
-  return toBuffer(buffer).indexOf(value, byfeOffset, encoding)
-}
-
-function lastIndexOf (buffer, value, byteOffset, encoding) {
-  return toBuffer(buffer).lastIndexOf(value, byteOffset, encoding)
-}
-
-function swap16 (buffer) {
-  return toBuffer(buffer).swap16()
-}
-
-function swap32 (buffer) {
-  return toBuffer(buffer).swap32()
-}
-
-function swap64 (buffer) {
-  return toBuffer(buffer).swap64()
-}
-
-function toBuffer (buffer) {
-  if (Buffer.isBuffer(buffer)) return buffer
-  return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength)
-}
-
-function toString (buffer, encoding, start, end) {
-  return toBuffer(buffer).toString(encoding, start, end)
-}
-
-function write (buffer, string, offset, length, encoding) {
-  return toBuffer(buffer).write(string, offset, length, encoding)
-}
-
-function writeDoubleLE (buffer, value, offset) {
-  return toBuffer(buffer).writeDoubleLE(value, offset)
-}
-
-function writeFloatLE (buffer, value, offset) {
-  return toBuffer(buffer).writeFloatLE(value, offset)
-}
-
-function writeUInt32LE (buffer, value, offset) {
-  return toBuffer(buffer).writeUInt32LE(value, offset)
-}
-
-function writeInt32LE (buffer, value, offset) {
-  return toBuffer(buffer).writeInt32LE(value, offset)
-}
-
-function readDoubleLE (buffer, offset) {
-  return toBuffer(buffer).readDoubleLE(offset)
-}
-
-function readFloatLE (buffer, offset) {
-  return toBuffer(buffer).readFloatLE(offset)
-}
-
-function readUInt32LE (buffer, offset) {
-  return toBuffer(buffer).readUInt32LE(offset)
-}
-
-function readInt32LE (buffer, offset) {
-  return toBuffer(buffer).readInt32LE(offset)
-}
-
-function writeDoubleBE (buffer, value, offset) {
-  return toBuffer(buffer).writeDoubleBE(value, offset)
-}
-
-function writeFloatBE (buffer, value, offset) {
-  return toBuffer(buffer).writeFloatBE(value, offset)
-}
-
-function writeUInt32BE (buffer, value, offset) {
-  return toBuffer(buffer).writeUInt32BE(value, offset)
-}
-
-function writeInt32BE (buffer, value, offset) {
-  return toBuffer(buffer).writeInt32BE(value, offset)
-}
-
-function readDoubleBE (buffer, offset) {
-  return toBuffer(buffer).readDoubleBE(offset)
-}
-
-function readFloatBE (buffer, offset) {
-  return toBuffer(buffer).readFloatBE(offset)
-}
-
-function readUInt32BE (buffer, offset) {
-  return toBuffer(buffer).readUInt32BE(offset)
-}
-
-function readInt32BE (buffer, offset) {
-  return toBuffer(buffer).readInt32BE(offset)
-}
-
-module.exports = {
-  isBuffer,
-  isEncoding,
-  alloc,
-  allocUnsafe,
-  allocUnsafeSlow,
-  byteLength,
-  compare,
-  concat,
-  copy,
-  equals,
-  fill,
-  from,
-  includes,
-  indexOf,
-  lastIndexOf,
-  swap16,
-  swap32,
-  swap64,
-  toBuffer,
-  toString,
-  write,
-  writeDoubleLE,
-  writeFloatLE,
-  writeUInt32LE,
-  writeInt32LE,
-  readDoubleLE,
-  readFloatLE,
-  readUInt32LE,
-  readInt32LE,
-  writeDoubleBE,
-  writeFloatBE,
-  writeUInt32BE,
-  writeInt32BE,
-  readDoubleBE,
-  readFloatBE,
-  readUInt32BE,
-  readInt32BE
-
-}
diff --git a/debian/tests/test_modules/b4a/lib/ascii.js b/debian/tests/test_modules/b4a/lib/ascii.js
deleted file mode 100644
index 3a2e3b2..0000000
--- a/debian/tests/test_modules/b4a/lib/ascii.js
+++ /dev/null
@@ -1,31 +0,0 @@
-function byteLength (string) {
-  return string.length
-}
-
-function toString (buffer) {
-  const len = buffer.byteLength
-
-  let result = ''
-
-  for (let i = 0; i < len; i++) {
-    result += String.fromCharCode(buffer[i])
-  }
-
-  return result
-}
-
-function write (buffer, string, offset = 0, length = byteLength(string)) {
-  const len = Math.min(length, buffer.byteLength - offset)
-
-  for (let i = 0; i < len; i++) {
-    buffer[offset + i] = string.charCodeAt(i)
-  }
-
-  return len
-}
-
-module.exports = {
-  byteLength,
-  toString,
-  write
-}
diff --git a/debian/tests/test_modules/b4a/lib/base64.js b/debian/tests/test_modules/b4a/lib/base64.js
deleted file mode 100644
index d4731e3..0000000
--- a/debian/tests/test_modules/b4a/lib/base64.js
+++ /dev/null
@@ -1,65 +0,0 @@
-const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
-
-const codes = new Uint8Array(256)
-
-for (let i = 0; i < alphabet.length; i++) {
-  codes[alphabet.charCodeAt(i)] = i
-}
-
-codes[/* - */ 0x2d] = 62
-codes[/* _ */ 0x5f] = 63
-
-function byteLength (string) {
-  let len = string.length
-
-  if (string.charCodeAt(len - 1) === 0x3d) len--
-  if (len > 1 && string.charCodeAt(len - 1) === 0x3d) len--
-
-  return (len * 3) >>> 2
-}
-
-function toString (buffer) {
-  const len = buffer.byteLength
-
-  let result = ''
-
-  for (let i = 0; i < len; i += 3) {
-    result += (
-      alphabet[buffer[i] >> 2] +
-      alphabet[((buffer[i] & 3) << 4) | (buffer[i + 1] >> 4)] +
-      alphabet[((buffer[i + 1] & 15) << 2) | (buffer[i + 2] >> 6)] +
-      alphabet[buffer[i + 2] & 63]
-    )
-  }
-
-  if (len % 3 === 2) {
-    result = result.substring(0, result.length - 1) + '='
-  } else if (len % 3 === 1) {
-    result = result.substring(0, result.length - 2) + '=='
-  }
-
-  return result
-};
-
-function write (buffer, string, offset = 0, length = byteLength(string)) {
-  const len = Math.min(length, buffer.byteLength - offset)
-
-  for (let i = 0, j = 0; j < len; i += 4) {
-    const a = codes[string.charCodeAt(i)]
-    const b = codes[string.charCodeAt(i + 1)]
-    const c = codes[string.charCodeAt(i + 2)]
-    const d = codes[string.charCodeAt(i + 3)]
-
-    buffer[j++] = (a << 2) | (b >> 4)
-    buffer[j++] = ((b & 15) << 4) | (c >> 2)
-    buffer[j++] = ((c & 3) << 6) | (d & 63)
-  }
-
-  return len
-};
-
-module.exports = {
-  byteLength,
-  toString,
-  write
-}
diff --git a/debian/tests/test_modules/b4a/lib/hex.js b/debian/tests/test_modules/b4a/lib/hex.js
deleted file mode 100644
index d63c88a..0000000
--- a/debian/tests/test_modules/b4a/lib/hex.js
+++ /dev/null
@@ -1,51 +0,0 @@
-function byteLength (string) {
-  return string.length >>> 1
-}
-
-function toString (buffer) {
-  const len = buffer.byteLength
-
-  buffer = new DataView(buffer.buffer, buffer.byteOffset, len)
-
-  let result = ''
-  let i = 0
-
-  for (let n = len - (len % 4); i < n; i += 4) {
-    result += buffer.getUint32(i).toString(16).padStart(8, '0')
-  }
-
-  for (; i < len; i++) {
-    result += buffer.getUint8(i).toString(16).padStart(2, '0')
-  }
-
-  return result
-}
-
-function write (buffer, string, offset = 0, length = byteLength(string)) {
-  const len = Math.min(length, buffer.byteLength - offset)
-
-  for (let i = 0; i < len; i++) {
-    const a = hexValue(string.charCodeAt(i * 2))
-    const b = hexValue(string.charCodeAt(i * 2 + 1))
-
-    if (a === undefined || b === undefined) {
-      return buffer.subarray(0, i)
-    }
-
-    buffer[offset + i] = (a << 4) | b
-  }
-
-  return len
-}
-
-module.exports = {
-  byteLength,
-  toString,
-  write
-}
-
-function hexValue (char) {
-  if (char >= 0x30 && char <= 0x39) return char - 0x30
-  if (char >= 0x41 && char <= 0x46) return char - 0x41 + 10
-  if (char >= 0x61 && char <= 0x66) return char - 0x61 + 10
-}
diff --git a/debian/tests/test_modules/b4a/lib/utf16le.js b/debian/tests/test_modules/b4a/lib/utf16le.js
deleted file mode 100644
index 87d7ed4..0000000
--- a/debian/tests/test_modules/b4a/lib/utf16le.js
+++ /dev/null
@@ -1,40 +0,0 @@
-function byteLength (string) {
-  return string.length * 2
-}
-
-function toString (buffer) {
-  const len = buffer.byteLength
-
-  let result = ''
-
-  for (let i = 0; i < len - 1; i += 2) {
-    result += String.fromCharCode(buffer[i] + (buffer[i + 1] * 256))
-  }
-
-  return result
-}
-
-function write (buffer, string, offset = 0, length = byteLength(string)) {
-  const len = Math.min(length, buffer.byteLength - offset)
-
-  let units = len
-
-  for (let i = 0; i < string.length; ++i) {
-    if ((units -= 2) < 0) break
-
-    const c = string.charCodeAt(i)
-    const hi = c >> 8
-    const lo = c % 256
-
-    buffer[offset + i * 2] = lo
-    buffer[offset + i * 2 + 1] = hi
-  }
-
-  return len
-}
-
-module.exports = {
-  byteLength,
-  toString,
-  write
-}
diff --git a/debian/tests/test_modules/b4a/lib/utf8.js b/debian/tests/test_modules/b4a/lib/utf8.js
deleted file mode 100644
index b36d072..0000000
--- a/debian/tests/test_modules/b4a/lib/utf8.js
+++ /dev/null
@@ -1,145 +0,0 @@
-function byteLength (string) {
-  let length = 0
-
-  for (let i = 0, n = string.length; i < n; i++) {
-    const code = string.charCodeAt(i)
-
-    if (code >= 0xd800 && code <= 0xdbff && i + 1 < n) {
-      const code = string.charCodeAt(i + 1)
-
-      if (code >= 0xdc00 && code <= 0xdfff) {
-        length += 4
-        i++
-        continue
-      }
-    }
-
-    if (code <= 0x7f) length += 1
-    else if (code <= 0x7ff) length += 2
-    else length += 3
-  }
-
-  return length
-}
-
-let toString
-
-if (typeof TextDecoder !== 'undefined') {
-  const decoder = new TextDecoder()
-
-  toString = function toString (buffer) {
-    return decoder.decode(buffer)
-  }
-} else {
-  toString = function toString (buffer) {
-    const len = buffer.byteLength
-
-    let output = ''
-    let i = 0
-
-    while (i < len) {
-      let byte = buffer[i]
-
-      if (byte <= 0x7f) {
-        output += String.fromCharCode(byte)
-        i++
-        continue
-      }
-
-      let bytesNeeded = 0
-      let codePoint = 0
-
-      if (byte <= 0xdf) {
-        bytesNeeded = 1
-        codePoint = byte & 0x1f
-      } else if (byte <= 0xef) {
-        bytesNeeded = 2
-        codePoint = byte & 0x0f
-      } else if (byte <= 0xf4) {
-        bytesNeeded = 3
-        codePoint = byte & 0x07
-      }
-
-      if (len - i - bytesNeeded > 0) {
-        let k = 0
-
-        while (k < bytesNeeded) {
-          byte = buffer[i + k + 1]
-          codePoint = (codePoint << 6) | (byte & 0x3f)
-          k += 1
-        }
-      } else {
-        codePoint = 0xfffd
-        bytesNeeded = len - i
-      }
-
-      output += String.fromCodePoint(codePoint)
-      i += bytesNeeded + 1
-    }
-
-    return output
-  }
-}
-
-let write
-
-if (typeof TextEncoder !== 'undefined') {
-  const encoder = new TextEncoder()
-
-  write = function write (buffer, string, offset = 0, length = byteLength(string)) {
-    const len = Math.min(length, buffer.byteLength - offset)
-    encoder.encodeInto(string, buffer.subarray(offset, offset + len))
-    return len
-  }
-} else {
-  write = function write (buffer, string, offset = 0, length = byteLength(string)) {
-    const len = Math.min(length, buffer.byteLength - offset)
-
-    buffer = buffer.subarray(offset, offset + len)
-
-    let i = 0
-    let j = 0
-
-    while (i < string.length) {
-      const code = string.codePointAt(i)
-
-      if (code <= 0x7f) {
-        buffer[j++] = code
-        i++
-        continue
-      }
-
-      let count = 0
-      let bits = 0
-
-      if (code <= 0x7ff) {
-        count = 6
-        bits = 0xc0
-      } else if (code <= 0xffff) {
-        count = 12
-        bits = 0xe0
-      } else if (code <= 0x1fffff) {
-        count = 18
-        bits = 0xf0
-      }
-
-      buffer[j++] = bits | (code >> count)
-      count -= 6
-
-      while (count >= 0) {
-        buffer[j++] = 0x80 | ((code >> count) & 0x3f)
-        count -= 6
-      }
-
-      i += code >= 0x10000 ? 2 : 1
-    }
-
-    return len
-  }
-}
-
-module.exports = {
-  byteLength,
-  toString,
-  write
-}
diff --git a/debian/tests/test_modules/b4a/package.json b/debian/tests/test_modules/b4a/package.json
deleted file mode 100644
index 7b30afd..0000000
--- a/debian/tests/test_modules/b4a/package.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-  "name": "b4a",
-  "version": "1.6.7",
-  "description": "Bridging the gap between buffers and typed arrays",
-  "main": "index.js",
-  "files": [
-    "browser.js",
-    "index.js",
-    "lib"
-  ],
-  "browser": {
-    "./index.js": "./browser.js"
-  },
-  "scripts": {
-    "test": "standard && brittle test/*.mjs"
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/holepunchto/b4a.git";
-  },
-  "author": "Holepunch",
-  "license": "Apache-2.0",
-  "bugs": {
-    "url": "https://github.com/holepunchto/b4a/issues";
-  },
-  "homepage": "https://github.com/holepunchto/b4a#readme";,
-  "devDependencies": {
-    "brittle": "^3.5.2",
-    "nanobench": "^3.0.0",
-    "standard": "^17.1.0"
-  }
-}
diff --git a/debian/tests/test_modules/brittle/LICENSE b/debian/tests/test_modules/brittle/LICENSE
deleted file mode 100644
index 261eeb9..0000000
--- a/debian/tests/test_modules/brittle/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/debian/tests/test_modules/brittle/README.md b/debian/tests/test_modules/brittle/README.md
deleted file mode 100644
index a3454dc..0000000
--- a/debian/tests/test_modules/brittle/README.md
+++ /dev/null
@@ -1,665 +0,0 @@
-# brittle
-
-> tap à la mode
-
-A TAP test runner built for modern times.
-
-<img width=300 height=200 src=brittle.png>
-
-## Usage
-
-First install brittle from npm
-
-```
-npm i brittle
-```
-
-Then start writing tests
-
-```javascript
-import test from 'brittle'
-
-test('basic', function (t) {
-  t.is(typeof Date.now(), 'number')
-  t.not(typeof Date.now(), 'string')
-
-  t.ok(Date.now() > 0)
-  t.absent(null)
-
-  t.comment('text')
-
-  t.alike({ a: 1 }, { a: 1 })
-  t.unlike({ a: 2 }, { a: 3 })
-
-  t.pass()
-  t.fail()
-})
-
-test('asynchronous', async function (t) {
-  await new Promise(r => setTimeout(r, 250))
-  t.pass()
-})
-
-test('plans', function (t) {
-  t.plan(2)
-  t.pass()
-  setTimeout(() => t.pass(), 250)
-})
-
-test('classic subtest', function (t) {
-  t.test('subtest', function (sub) {
-    sub.plan(1)
-    sub.pass()
-  })
-})
-
-test('inverted subtest', function (t) {
-  const sub = t.test('subtest')
-  sub.plan(1)
-  sub.pass()
-})
-
-test('executions', async function (t) {
-  t.execution(() => 'should not throw')
-  await t.execution(async () => 'should not reject')
-})
-
-test('exceptions', async function (t) {
-  t.exception(() => { throw Error('expected to throw') })
-  await t.exception(async () => { throw Error('expected to reject') })
-})
-
-const a = test('inverted test without plan needs end()')
-a.pass()
-a.end()
-
-const b = test('inverted test with plan')
-b.plan(1)
-b.pass()
-
-const c = test('inverted tests can be awaited')
-c.plan(1)
-setTimeout(() => c.pass(), 250)
-await c
-```
-
-Every assertion can have a message, i.e. `t.pass('msg')`, `t.ok(false, 'should be true')`, etc.\
-There are also utilities like `t.timeout(ms)`, `t.teardown(fn)`, etc.\
-Check the API but also all the [assertions here](#assertions) and [utilities here](#utilities).
-
-## API
-
-```js
-import { test, solo, skip, hook, todo, configure } from 'brittle'
-```
-
-#### `test([name], [options], callback)`
-
-Create a classic test with an optional `name`.
-
-#### Available `options` for any test creation:
- * `timeout` (`30000`) - milliseconds to wait before ending a stalling test.
- * `solo` (`false`) - Skip all other tests except the `solo()` ones.
- * `hook` (`false`) - setup and teardown resources.
- * `skip` (`false`) - skip this test, alternatively use the `skip()` function.
- * `todo` (`false`) - mark this test as todo and skip it, alternatively use the `todo()` function.
- * `stealth` (`false`) - only print test summary.
-
-The `callback` function (can be async) receives an object called `assert`.\
-`assert` (or `t`) provides the assertions and utilities interface.
-
-```js
-import test from 'brittle'
-
-test('basic', function (t) {
-  t.pass()
-})
-```
-
-Test files can be executed directly with `node`, as they're normal Node.js programs.
-
-The `test` method is conveniently both the default export and named exported method:
-
-```js
-import { test } from 'brittle'
-```
-
-Classic tests will run sequentially, buffering pending tests until any prior test catches up.
-
-Any test function returns a promise so you can optionally await for its result:
-
-```js
-const isOk = await test('basic', function (t) {
-  t.pass()
-})
-```
-
-#### `test([name], [options]) => assert`
-
-Create an inverted test with an optional `name`.
-
-All `options` for inverted tests are [listed here](#available-options-for-any-test-creation).
-
-An object called `assert` (or `t`) is returned, the same as the classic test.
-
-This time it's also a promise, it can be awaited and it resolves at test completion.
-
-```js
-import test from 'brittle'
-
-const t = test('basic')
-
-t.plan(1)
-
-setTimeout(() => {
-  t.pass()
-}, 1000)
-
-await t // Won't proceed past here until plan is fulfilled
-```
-
-For inverted tests without a plan, the `end` method must be called:
-
-```js
-const t = test('basic')
-
-setTimeout(() => {
-  t.pass()
-  t.end()
-}, 1000)
-
-await t
-```
-
-The `end()` method can be called inline, for inverted tests without a plan:
-
-```js
-const t = test('basic')
-t.pass()
-t.end()
-```
-
-Control flow of inverted is entirely dependent on where its `assert` is awaited.\
-The following executes one test after another:
-
-```js
-const a = test('first test')
-const b = test('second test')
-a.plan(1)
-b.plan(1)
-a.pass()
-await a
-b.pass()
-await b
-```
-
-Awaiting the promise gives you its result:
-
-```js
-const t = test('first test')
-t.plan(1)
-t.pass()
-const isOk = await t
-```
-
-#### `stealth([name], [options], callback)`
-#### `stealth([name], [options]) => assert`
-
-Create a stealth test.\
-This will provide a new sub-assert object that only prints the test summary without assertions and ends the current test upon a failed assertion.
-
-All `options` are the same as `test` which are [listed here](#available-options-for-any-test-creation).
-
-#### `t.test([name], [options], callback)`
-#### `t.test([name], [options]) => assert`
-
-A subtest can be created by calling `test` on an `assert` (or `t`) object.\
-This will provide a new sub-assert object.
-
-All `options` for subtests are [listed here](#available-options-for-any-test-creation).
-
-Using this in inverted style can be very useful for flow control within a test:
-
-```js
-test('basic', async function (t) {
-  const a = t.test('sub test')
-  const b = t.test('other sub test')
-
-  a.plan(1)
-  b.plan(1)
-
-  setTimeout(() => a.ok(true), Math.random() * 1000)
-  setTimeout(() => b.ok(true), Math.random() * 1000)
-  
-  // Won't proceed past here until both a and b plans are fulfilled
-  await a
-  await b
-
-  t.pass()
-})
-```
-
-Subtest test options can be set by passing an object to the `test` function:
-
-```js
-test('parent', { timeout: 1000 }, function (t) {
-  t.test('basic using parent config', async function (t) {
-    await new Promise(r => setTimeout(r, 500))
-    t.pass()
-  })
-
-  t.test('another basic using parent config', function (t) {
-    t.pass()
-  })
-})
-```
-
-You can also await for its result as well:
-
-```js
-test('basic', async function (t) {
-  t.plan(1)
-  t.pass()
-  const isOk = await t
-  console.log(isOk)
-})
-```
-
-#### `t.stealth([name], [options], callback)`
-#### `t.stealth([name], [options]) => assert`
-
-Create a stealth sub-test.\
-This will provide a new sub-assert object that only prints the test summary without assertions and ends the current test upon a failed assertion.
-
-All `options` are the same as `test` which are [listed here](#available-options-for-any-test-creation).
-
-#### `solo([name], [options], callback)`
-#### `solo([name], [options]) => assert`
-
-Filter out other tests by using the `solo` method:
-
-```js
-import { test, solo } from 'brittle'
-
-test('this test is skipped', function (t) {
-  t.pass()
-})
-
-solo('some test', function (t) {
-  t.pass()
-})
-```
-
-If a `solo` function is used, `test` functions will not execute.\
-
-If `solo` is used in a future tick (for example, in a `setTimeout` callback),\
-after `test` has already been used those tests won't be filtered.
-
-A few ways to enable `solo` functions:
-- Use `configure({ solo: true })` before any tests.
-- You can call `solo()` without callback underneath the imports.
-- Using the `--solo` flag with the `brittle` test runner.
-
-It can also be used as an inverted test:
-
-```js
-const t = test.solo('inverted some test')
-t.pass()
-t.end()
-```
-
-#### `skip([name], [options], callback)`
-
-Skip a test: 
-
-```js
-import { test, skip } from 'brittle'
-
-skip('this test is skipped', function (t) {
-  t.pass()
-})
-
-test('middle test', function (t) {
-  t.pass()
-})
-
-test.skip('another skipped test', function (t) {
-  t.pass()
-})
-```
-
-Only the `middle test` will be executed.
-
-#### `hook([name], [options], callback)`
-
-Use before tests for setting up and after tests for tearing down. Runs the same way as `test` except always executes regardless of `solo` usage. 
-
-```js
-import { test, solo, hook } from 'brittle'
-
-hook('setup hook', function (t) {
-  // setup resources
-})
-
-solo('solo test', function (t) {
-  t.pass()
-})
-
-test('middle test', function (t) {
-  t.pass()
-})
-
-hook('teardown hook', function (t) {
-  // teardown resources
-})
-```
-
-The `setup hook`, `solo test` and `teardown hook` will be executed.
-
-#### `configure([options])`
-
-The `configure` function can be used to set options for all tests (including child tests).\
-It must be executed before any tests.
-
-#### Options
-
- * `timeout` (`30000`) - milliseconds to wait before ending a stalling test
- * `bail` (`false`) - exit the process on first test failure
- * `solo` (`false`) - skip all other tests except the `solo()` ones
- * `source` (`true`) - shows error `source` information
- * `unstealth` (`false`) - show assertions even if `stealth` is used
-
-```js
-import { configure } from 'brittle'
-
-configure({ timeout: 15000 }) // All tests will have a 15 seconds timeout
-```
-
-### Assertions
-
-#### `t.is(actual, expected, [message])`
-
-Compare `actual` to `expected` with `===`
-
-#### `t.not(actual, expected, [message])`
-
-Compare `actual` to `expected` with `!==`
-
-#### `t.alike(actual, expected, [message])`
-
-Object comparison, comparing all primitives on the 
-`actual` object to those on the `expected` object
-using `===`.
-
-#### `t.unlike(actual, expected, [message])`
-
-Object comparison, comparing all primitives on the 
-`actual` object to those on the `expected` object
-using `!==`.
-
-#### `t.ok(value, [message])`
-
-Checks that `value` is truthy: `!!value === true`
-
-#### `t.absent(value, [message])`
-
-Checks that `value` is falsy: `!!value === false`
-
-#### `t.pass([message])`
-
-Asserts success. Useful for explicitly confirming
-that a function was called, or that behavior is 
-as expected.
-
-#### `t.fail([message])`
-
-Asserts failure. Useful for explicitly checking
-that a function should not be called.
-
-#### `t.exception(Promise|function|async function, [error], [message])`
-
-Verify that a function throws, or a promise rejects.
-
-```js
-t.exception(() => { throw Error('an err') }, /an err/)
-await t.exception(async () => { throw Error('an err') }, /an err/)
-await t.exception(Promise.reject(Error('an err')), /an err/)
-```
-
-If the error is an instance of any of the following native error constructors,
-then this will still result in failure since native errors often tend to be unintentational.
-
-* `SyntaxError`
-* `ReferenceError`
-* `TypeError`
-* `EvalError`
-* `RangeError`
-
-If a `t.exception` is async, then you're supposed to await it.
-
-#### `t.exception.all(Promise|function|async function, [error], [message])`
-
-Verify that a function throws, or a promise rejects, including native errors.
-
-```js
-t.exception.all(() => { throw Error('an err') }, /an err/)
-await t.exception.all(async () => { throw Error('an err') }, /an err/)
-await t.exception.all(Promise.reject(new SyntaxError('native error')), /native error/)
-```
-
-The `t.exception.all` method is an escape-hatch so it can be used with the
-normally filtered native errors.
-
-If a `t.exception.all` is async, then you're supposed to await it.
-
-#### `t.execution(Promise|function|async function, [message])`
-
-Assert that a function executes instead of throwing or that a promise resolves instead of rejecting. Resolves to the execution time, in milliseconds, of the function or promise.
-
-```js
-t.execution(() => {})
-await t.execution(async () => {})
-await t.execution(Promise.resolve('cool'))
-```
-
-If a `t.execution` is async, then you're supposed to await it
-
-#### `t.is.coercively(actual, expected, [message])`
-
-Compare `actual` to `expected` with `==`.
-
-#### `t.not.coercively(actual, expected, [message])`
-
-Compare `actual` to `expected` with `!=`.
-
-#### `t.alike.coercively(actual, expected, [message])`
-
-Object comparison, comparing all primitives on the 
-`actual` object to those on the `expected` object
-using `==`.
-
-#### `t.unlike.coercively(actual, expected, [message])`
-
-Object comparison, comparing all primitives on the 
-`actual` object to those on the `expected` object
-using `!=`.
-
-
-### Utilities
-
-#### `t.plan(n)`
-
-Constrain a test to an explicit amount of assertions.
-
-#### `t.tmp() -> <Promise<String>>`
-
-Creates a temporary folder and returns a promise that resolves its path. Once a test either succeeds or fails, the temporary folder is removed.
-
-#### `t.teardown(function|async function, [options])`
-
-**Options:**
-
- * `order` (`0`) - set the ascending position priority for a teardown to be executed.
- * `force` (`false`) - run the teardown on failure as well as success
-
-The function passed to `teardown` is called right after a test ends:
-
-```js
-test('basic', function (t) {
-  const timeoutId = setTimeout(() => {}, 1000)
-
-  t.teardown(async function () {
-    clearTimeout(timeoutId)
-    await doMoreCleanUp()
-  })
-
-  t.ok('cool')
-})
-```
-
-If `teardown` is called multiple times in a test, every function passed will be called after the test ends:
-
-```js
-test('basic', function (t) {
-  t.teardown(doSomeCleanUp)
-
-  const timeoutId = setTimeout(() => {}, 1000)
-  t.teardown(() => clearTimeout(timeoutId))
-
-  t.ok('again, cool')
-})
-```
-
-Set `order: -Infinity` to always be in first place, and vice versa with `order: Infinity`.\
-If two teardowns have the same `order` they are ordered per time of invocation within that order group.
-
-```js
-test('teardown order', function (t) {
-  t.teardown(async function () {
-    await new Promise(r => setTimeout(r, 200))
-    console.log('teardown B')
-  })
-
-  t.teardown(async function () {
-    await new Promise(r => setTimeout(r, 200))
-    console.log('teardown A')
-  }, { order: -1 })
-
-  t.teardown(async function () {
-    await new Promise(r => setTimeout(r, 200))
-    console.log('teardown C')
-  }, { order: 1 })
-
-  t.pass()
-})
-```
-
-The `A` teardown is executed first, then `B`, and finally `C` due to the `order` option.
-
-#### `t.timeout(ms)`
-
-Fail the test after a given timeout.
-
-#### `t.comment(message)`
-
-Inject a TAP comment into the output.
-
-#### `t.end()`
-
-Force end a test.\
-`end` is determined by `assert` resolution or when a containing async function completes.\
-In case of inverted tests, they're required to be explicitly called.
-
-
-### Readable Properties
-
-#### `t.name`
-The name of the test.
-
-#### `t.passes`
-The number of assertions that passed within the test.
-
-#### `t.fails`
-The number of assertions that failed within the test.
-
-#### `t.assertions`
-The number of assertions that were executed within the test.
-
-## Runner
-
-### Default timeout
-
-The default timeout is 30 seconds.
-
-### Example of `package.json` with `test` script
-
-The following would run all `.js` files in the test folder:
-
-```json
-{
-  "name": "my-app",
-  "version": "1.0.0",
-  "scripts": {
-    "test": "brittle test/*.js"
-  },
-  "devDependencies": {
-    "brittle": "^3.0.0-alpha.3"
-  }
-}
-```
-
-## CLI
-
-```sh
-npm install -g brittle
-```
-
-```shell
-brittle [flags] <files>
-
-Flags:
-  --solo, -s                Engage solo mode
-  --bail, -b                Bail out on first assert failure
-  --coverage, -cov, -c      Turn on coverage
-  --cov-dir <dir>           Configure coverage output directory (default: ./coverage)
-  --trace                   Trace all active promises and print them if the test fails
-  --timeout, -t <timeout>   Set the test timeout in milliseconds (default: 30000)
-  --runner, -r <runner>     Generates an out file that contains all target tests
-  --mine, -m <miners>       Keep running the tests in <miners> processes until they fail.
-  --unstealth, -u           Show assertions even if stealth is used
-  --help|-h                 Show help
-```
-
-Note globbing is supported:
-```sh
-brittle --coverage path/to/test/*.js
-```
-
-Auto generate a single file containing "all tests":
-```shell
-brittle -r test/all.js test/*.js
-
-node test/all.js
-```
-
-You can use an environment variable to also set flags:
-```shell
-BRITTLE="--coverage --bail" brittle test.js
-```
-
-Force disable coverage with an environment variable:
-```shell
-BRITTLE_COVERAGE=false brittle test.js
-```
-### Coverage
-If the `--coverage` flag is set, brittle will output the coverage summary as a table at the end of execution and generate a json coverage report in the coverage output directory (configurable using `--cov-dir`).
-
-The coverage output directory will contain a `coverage-final.json` file which contains an istanbul json coverage report and a `v8-coverage.json` file which contains the raw v8 coverage data.
-
-Istanbul can be used to convert the istanbul json report into other formats. e.g.:
-```
-npx istanbul report html
-```
-
-## License
-Apache-2.0
diff --git a/debian/tests/test_modules/brittle/cmd.js b/debian/tests/test_modules/brittle/cmd.js
deleted file mode 100755
index 315d7e7..0000000
--- a/debian/tests/test_modules/brittle/cmd.js
+++ /dev/null
@@ -1,225 +0,0 @@
-#!/usr/bin/env node
-
-const path = require('path')
-const { command, flag, rest } = require('paparam')
-const Globbie = require('globbie')
-const { spawn } = require('child_process')
-const TracingPromise = require('./lib/tracing-promise')
-
-const args = process.argv.slice(2).concat((process.env.BRITTLE || '').split(/\s|,/g).map(s => s.trim()).filter(s => s))
-const cmd = command('brittle',
-  flag('--solo, -s', 'Engage solo mode'),
-  flag('--bail, -b', 'Bail out on first assert failure'),
-  flag('--coverage, -cov, -c', 'Turn on coverage'),
-  flag('--cov-dir <dir>', 'Configure coverage output directory (default: ./coverage)'),
-  flag('--trace', 'Trace all active promises and print them if the test fails'),
-  flag('--timeout, -t <timeout>', 'Set the test timeout in milliseconds (default: 30000)'),
-  flag('--runner, -r <runner>', 'Generates an out file that contains all target tests'),
-  flag('--mine, -m <miners>', 'Keep running the tests in <miners> processes until they fail.'),
-  flag('--unstealth, -u', 'Print out assertions even if stealth is used'),
-  rest('<files>')
-).parse(args)
-if (!cmd) process.exit(0)
-
-const argv = cmd.flags
-
-const files = []
-for (const g of cmd.rest || []) {
-  const glob = new Globbie(g, { sync: true })
-  const matches = glob.match()
-
-  if (matches.length === 0) {
-    if (g[0] === '-') continue
-    console.error(`Error: no files found when resolving ${g}`)
-    process.exit(1)
-  }
-
-  files.push(...matches)
-}
-
-if (files.length === 0) {
-  console.error('Error: No test files were specified')
-  process.exit(1)
-}
-
-const { solo, bail, timeout, cov, mine, trace, unstealth } = argv
-
-process.title = 'brittle'
-
-if (trace && !mine) {
-  TracingPromise.enable()
-  process.on('exit', function (code) {
-    if (!code) return
-    console.error()
-    console.error('Printing tracing info since the tests failed:')
-    console.error()
-    TracingPromise.print()
-  })
-}
-
-if (argv.runner) {
-  const fs = require('fs')
-
-  if (argv.runner === true) {
-    console.error('--runner must be a path to the generated test runner')
-    process.exit(2)
-  }
-
-  const out = path.resolve(argv.runner)
-  const dir = path.dirname(out)
-
-  let s = ''
-
-  s += 'runTests()\n\nasync function runTests () {\n  const test = (await import(\'brittle\')).default\n\n'
-
-  if (bail || solo || unstealth || timeout) {
-    s += `  test.configure({ bail: ${!!bail}, solo: ${!!solo}, unstealth: ${!!unstealth}, timeout: ${timeout} })\n`
-  }
-
-  s += '  test.pause()\n\n'
-
-  for (const f of files) {
-    const t = path.resolve(f)
-    if (t === out) continue
-
-    let r = path.relative(dir, t)
-    if (r[0] !== '.') r = '.' + path.sep + r
-    s += '  await import(\'' + r + '\')\n'
-  }
-
-  s = s.trimRight()
-
-  s += '\n\n  test.resume()\n}\n'
-  s = '// This runner is auto-generated by Brittle\n\n' + s
-
-  try {
-    fs.mkdirSync(dir)
-  } catch {}
-
-  fs.writeFileSync(out, s)
-  process.exit(0)
-}
-
-if (cov && process.env.BRITTLE_COVERAGE !== 'false') require('bare-cov')({ dir: argv['cov-dir'] })
-
-if (mine) startMining().catch()
-else start().catch(onerror)
-
-function onerror (err) {
-  console.error(err.stack)
-  process.exit(1)
-}
-
-async function start () {
-  const brittle = require('./')
-
-  if (bail || solo || unstealth || timeout) {
-    brittle.configure({ bail, solo, unstealth, timeout: timeout ? Number(timeout) : undefined })
-  }
-
-  brittle.pause()
-
-  for (const f of files) {
-    await import('file://' + path.resolve(f))
-  }
-
-  brittle.resume()
-}
-
-async function startMining () {
-  const args = [__filename]
-    .concat(solo ? ['--solo'] : [])
-    .concat(bail ? ['--bail'] : [])
-    .concat(unstealth ? ['--unstealth'] : [])
-    .concat(trace ? ['--trace'] : [])
-    .concat(timeout ? ['--timeout', timeout + ''] : [])
-    .concat(files)
-
-  const running = new Set()
-  const max = Number(argv.mine) || 1
-
-  let runs = 0
-  let bailed = false
-  let newline = false
-
-  const interval = setInterval(function () {
-    console.log('Still mining... Total runs: ' + runs)
-    newline = true
-  }, 1000)
-
-  bump()
-
-  process.once('SIGINT', bail)
-  process.once('SIGTERM', bail)
-
-  function bail () {
-    bailed = true
-    clearInterval(interval)
-    for (const r of running) r.kill()
-  }
-
-  async function bump () {
-    if (running.size >= max || bailed) return
-
-    const r = run()
-    running.add(r)
-
-    const { exitCode, output } = await r.promise
-    running.delete(r)
-    runs++
-
-    if (bailed) return
-
-    if (!exitCode) {
-      bump()
-      bump()
-      return
-    }
-
-    bailed = true
-
-    clearInterval(interval)
-
-    if (newline) console.log()
-    console.log('Runner failed with exit code ' + exitCode + '!')
-    console.log('Shutting down the rest and printing output...')
-
-    for (const r of running) {
-      r.kill()
-      await r.promise
-    }
-
-    console.log('Done! The tests took ' + runs + ' runs to fail.')
-    console.log()
-
-    for (const { stdout, data } of output) {
-      if (stdout) process.stdout.write(data)
-      else process.stderr.write(data)
-    }
-
-    process.exit(exitCode)
-  }
-
-  function run () {
-    const p = spawn(process.execPath, args)
-
-    const output = []
-
-    p.stdout.on('data', (data) => output.push({ stdout: true, data }))
-    p.stderr.on('data', (data) => output.push({ stdout: false, data }))
-
-    const promise = new Promise((resolve) => {
-      p.on('close', (exitCode) => {
-        resolve({
-          exitCode,
-          output
-        })
-      })
-    })
-
-    return {
-      promise,
-      kill: () => p.kill()
-    }
-  }
-}
diff --git a/debian/tests/test_modules/brittle/index.js b/debian/tests/test_modules/brittle/index.js
deleted file mode 100644
index 4800df8..0000000
--- a/debian/tests/test_modules/brittle/index.js
+++ /dev/null
@@ -1,883 +0,0 @@
-const sameObject = require('same-object')
-const tmp = require('test-tmp')
-const b4a = require('b4a')
-const { getSnapshot, createTypedArray } = require('./lib/snapshot')
-const { INDENT, RUNNER, IS_NODE, IS_BARE, DEFAULT_TIMEOUT } = require('./lib/constants')
-const AssertionError = require('./lib/assertion-error')
-const TracingPromise = require('./lib/tracing-promise')
-const Promise = TracingPromise.Untraced // never trace internal onces
-
-const highDefTimer = IS_NODE ? highDefTimerNode : highDefTimerFallback
-
-// loaded on demand since it's error flow and we want ultra fast positive test runs
-const lazy = {
-  _errors: null,
-  _tmatch: null,
-  get errors () {
-    if (!lazy._errors) lazy._errors = require('./lib/errors.js')
-    return lazy._errors
-  },
-  get tmatch () {
-    if (!lazy._tmatch) lazy._tmatch = require('tmatch')
-    return lazy._tmatch
-  }
-}
-
-class Runner {
-  constructor () {
-    this.tests = { count: 0, pass: 0 }
-    this.assertions = { count: 0, pass: 0 }
-
-    this.next = null
-    this.solos = new Set()
-    this.padded = true
-    this.started = false
-    this.defaultTimeout = DEFAULT_TIMEOUT
-    this.bail = false
-    this.unstealth = false
-    this.skipAll = false
-    this.explicitSolo = false
-    this.source = true
-
-    this._timer = highDefTimer()
-    this._log = console.log.bind(console)
-    this._paused = null
-    this._resume = null
-
-    const target = IS_NODE ? process : global.Bare
-    const ondeadlock = () => {
-      if (this.next && this.next._checkDeadlock === false) return
-      target.off('beforeExit', ondeadlock)
-      this.end()
-    }
-
-    target.on('beforeExit', ondeadlock)
-  }
-
-  resume () {
-    if (!this._paused) return
-    this._resume()
-    this._resume = this._paused = null
-  }
-
-  pause () {
-    if (this._paused) return
-    this._paused = new Promise((resolve) => { this._resume = resolve })
-  }
-
-  async _wait () {
-    await wait()
-    await this._paused
-  }
-
-  async queue (test) {
-    this.start()
-
-    if (test._isSolo) {
-      this.solos.add(test)
-    }
-
-    await this._wait()
-
-    if (this.explicitSolo && !test._isSolo) {
-      return false
-    }
-
-    if (this._shouldTest(test)) {
-      while (this.next !== null) {
-        const next = this.next
-        await next
-        if (next === this.next) this.next = null
-      }
-
-      if (test._isSkip) {
-        this._skip('SKIP', test)
-        return false
-      }
-
-      if (test._isTodo) {
-        this._skip('TODO', test)
-        return false
-      }
-
-      if (!this._shouldTest(test)) {
-        return false
-      }
-
-      this.next = test
-      test._header()
-
-      if (!IS_NODE && !IS_BARE) this._autoExit(test)
-
-      return true
-    }
-
-    return false
-  }
-
-  _skip (reason, test) {
-    if (this._shouldTest(test)) {
-      test._header()
-      this.tests.pass++
-      this.tests.count++
-      this.assert(false, true, this.tests.count, '- ' + test.name + ' # ' + reason, null)
-    }
-  }
-
-  _shouldTest (test) {
-    return test._isHook || (!this.skipAll && (this.solos.size === 0 || this.solos.has(test)))
-  }
-
-  async _autoExit (test) {
-    try {
-      await test
-      await wait(10) // wait 10 ticks...
-      if (this.next === test) {
-        this.end()
-      }
-    } catch {}
-  }
-
-  log (...message) {
-    this._log(...message)
-    this.padded = false
-  }
-
-  padding () {
-    if (this.padded) return
-    this.padded = true
-    this.log()
-  }
-
-  start () {
-    if (this.started) return
-    this.started = true
-    this.log('TAP version 13')
-  }
-
-  comment (...message) {
-    this.log('#', ...message)
-  }
-
-  end () {
-    if (this.next) {
-      if (!this.next._isEnded && !(this.next._hasPlan && this.next._planned === 0)) {
-        this.next._onend(prematureEnd(this.next, 'Test did not end (' + this.next.name + ')'))
-        return
-      }
-
-      if (!this.next._isResolved) {
-        if (this.next._isDone) {
-          this.next._onend(new Error('Teardown did not end (unresolved promise)'))
-          return
-        }
-        this.next._onend(new Error('Test appears deadlocked (unresolved promise)'))
-        return
-      }
-    }
-
-    if (this.bail && this.skipAll) {
-      this.log('Bail out!')
-    }
-
-    this.padding()
-    this.log('1..' + this.tests.count)
-    this.log('# tests = ' + this.tests.pass + '/' + this.tests.count + ' pass')
-    this.log('# asserts = ' + this.assertions.pass + '/' + this.assertions.count + ' pass')
-    this.log('# time = ' + this._timer() + 'ms')
-    this.log()
-
-    if (this.tests.count === this.tests.pass && this.assertions.count === this.assertions.pass) this.log('# ok')
-    else this.log('# not ok')
-  }
-
-  assert (indent, ok, number, message, explanation, stealth) {
-    const ind = indent ? INDENT : ''
-
-    if (ok) {
-      if (!stealth || this.unstealth) this.log(ind + 'ok ' + number, message)
-    } else {
-      if (IS_NODE) process.exitCode = 1
-      if (IS_BARE) global.Bare.exitCode = 1
-      this.log(ind + 'not ok ' + number, message)
-      if (explanation) this.log(lazy.errors.stringify(explanation))
-      if (this.bail && !this.skipAll) this.skipAll = true
-      if (!this.unstealth && stealth) throw new AssertionError({ message: 'Stealth assertion failed' })
-    }
-  }
-}
-
-class Test {
-  constructor (name, parent, opts = {}) {
-    this._resolve = null
-    this._reject = null
-
-    this._promise = new Promise((resolve, reject) => {
-      this._resolve = resolve
-      this._reject = reject
-    })
-
-    this._parents = []
-    this._main = parent ? parent._main : this
-    this._runner = getRunner()
-    this.name = name
-    this.passes = 0
-    this.fails = 0
-    this.assertions = 0
-
-    this._isEnded = false
-    this._isDone = false
-    this._isHook = opts?.hook || false
-    this._isSolo = opts?.solo || false
-    this._isSkip = opts?.skip || false
-    this._isTodo = opts?.todo || false
-    this._isResolved = false
-    this._isQueued = false
-    this._isMain = this._main === this
-    this._isStealth = opts?.stealth || parent?._isStealth || false
-    this._checkDeadlock = opts?.deadlock !== false
-
-    // allow destructuring by binding the functions
-    this.comment = this._comment.bind(this)
-    this.timeout = this._timeout.bind(this)
-    this.teardown = this._teardown.bind(this)
-    this.test = this._test.bind(this)
-    this.plan = this._plan.bind(this)
-
-    this.pass = this._pass.bind(this)
-    this.fail = this._fail.bind(this)
-
-    this.ok = this._ok.bind(this)
-    this.absent = this._absent.bind(this)
-
-    this.is = this._is.bind(this, true)
-    this.is.coercively = this._is.bind(this, false)
-
-    this.not = this._not.bind(this, true)
-    this.not.coercively = this._not.bind(this, false)
-
-    this.alike = this._alike.bind(this, true)
-    this.alike.coercively = this._alike.bind(this, false)
-
-    this.unlike = this._unlike.bind(this, true)
-    this.unlike.coercively = this._unlike.bind(this, false)
-
-    this.exception = this._exception.bind(this, false)
-    this.exception.all = this._exception.bind(this, true)
-
-    this.execution = this._execution.bind(this)
-
-    this.stealth = this._stealth.bind(this)
-
-    this.snapshot = this._snapshot.bind(this)
-
-    this.end = this._end.bind(this)
-
-    this._parent = parent
-    this._first = true
-    this._wait = false
-    this._planned = 0
-    this._hasPlan = false
-    this._active = 0
-    this._timer = null
-
-    this._headerLogged = false
-    this._to = null
-    this._teardowns = []
-    this._tickers = new Map()
-
-    while (parent) {
-      this._parents.push(parent)
-      parent = parent._parent
-    }
-  }
-
-  then (...args) {
-    return this._promise.then(...args)
-  }
-
-  catch (...args) {
-    return this._promise.catch(...args)
-  }
-
-  finally (...args) {
-    return this._promise.finally(...args)
-  }
-
-  _header () {
-    if (this._headerLogged) return
-    this._headerLogged = true
-    this._runner.start()
-    this._runner.padding()
-    this._runner.comment(this.name || 'test')
-  }
-
-  tmp () { return tmp(this) }
-
-  _planDoneOrEnd () {
-    return this._isEnded || (this._hasPlan && this._planned === 0)
-  }
-
-  _timeout (ms) {
-    if (!ms) {
-      if (this._to) clearTimeout(this._to)
-      this._to = null
-      return
-    }
-
-    const ontimeout = () => {
-      this._to = null
-      this._onend(new Error('Test timed out after ' + ms + ' ms'))
-    }
-
-    if (this._to) clearTimeout(this._to)
-    this._to = setTimeout(ontimeout, ms)
-    if (this._to.unref) this._to.unref()
-  }
-
-  _plan (n) {
-    if (typeof n !== 'number' || n < 0) {
-      throw new Error('Plan takes a positive whole number only')
-    }
-
-    this._hasPlan = true
-    this._planned = n
-  }
-
-  _comment (...m) {
-    if (this._isResolved) throw new Error('Can\'t comment after end')
-    this._runner.log(INDENT + '#', ...m)
-  }
-
-  _message (message) {
-    let m = '- '
-
-    if (!this._isMain) {
-      for (let i = this._parents.length - 2; i >= 0; i--) {
-        const p = this._parents[i]
-        if (!p.name) continue
-        m += '(' + p.name + ') - '
-      }
-      if (this.name) {
-        m += '(' + this.name + ') - '
-      }
-    }
-
-    if (message) {
-      m += message
-    }
-
-    return m
-  }
-
-  _tick (ok) {
-    if (ok) this.passes++
-    else this.fails++
-    this.assertions++
-  }
-
-  _track (topLevel, ok) {
-    if (topLevel) {
-      this._runner.tests.count++
-      if (ok) this._runner.tests.pass++
-      return this._runner.tests.count
-    }
-
-    if (this._hasPlan) this._planned--
-    this._tick(ok)
-
-    if (!this._isMain) this._main._tick(ok)
-
-    this._runner.assertions.count++
-    if (ok) this._runner.assertions.pass++
-
-    return this._main.assertions
-  }
-
-  _assertion (ok, message, explanation, caller, top, isStealth = this._isStealth) {
-    this._runner.assert(!this._main._isResolved, ok, this._track(false, ok), this._message(message), explanation, isStealth)
-
-    if (this._isEnded || this._isDone) {
-      throw new AssertionError({ message: 'Assertion after end' })
-    }
-
-    if (this._hasPlan && this._planned < 0) {
-      throw new AssertionError({ message: 'Too many assertions' })
-    }
-
-    if (this._hasPlan && this._planned === 0) {
-      this._checkEnd()
-    }
-  }
-
-  _fail (message = 'failed') {
-    const explanation = explain(false, message, 'fail', this._fail)
-    this._assertion(false, message, explanation, this._fail, undefined)
-  }
-
-  _pass (message = 'passed') {
-    this._assertion(true, message, null, this._pass, undefined)
-  }
-
-  _ok (assertion, message = 'expected truthy value') {
-    const ok = assertion
-    const explanation = explain(ok, message, 'ok', this._ok)
-    this._assertion(ok, message, explanation, this._ok, undefined)
-  }
-
-  _absent (assertion, message = 'expected falsy value') {
-    const ok = !assertion
-    const explanation = explain(ok, message, 'absent', this._absent)
-    this._assertion(ok, message, explanation, this._absent, undefined)
-  }
-
-  _is (strict, actual, expected, message = 'should be equal') {
-    const ok = strict ? actual === expected : actual == expected // eslint-disable-line
-    const explanation = explain(ok, message, 'is', this._is, actual, expected)
-    this._assertion(ok, message, explanation, this._is, undefined)
-  }
-
-  _not (strict, actual, expected, message = 'should not be equal') {
-    const ok = strict ? actual !== expected : actual != expected // eslint-disable-line
-    const explanation = explain(ok, message, 'not', this._not, actual, expected)
-    this._assertion(ok, message, explanation, this._not, undefined)
-  }
-
-  _alike (strict, actual, expected, message = 'should deep equal') {
-    const ok = sameObject(actual, expected, { strict })
-    const explanation = explain(ok, message, 'alike', this._alike, actual, expected)
-    this._assertion(ok, message, explanation, this._alike, undefined)
-  }
-
-  _unlike (strict, actual, expected, message = 'should not deep equal') {
-    const ok = sameObject(actual, expected, { strict }) === false
-    const explanation = explain(ok, message, 'unlike', this._unlike, actual, expected)
-    this._assertion(ok, message, explanation, this._unlike, undefined)
-  }
-
-  _teardown (fn, opts = {}) {
-    if (this._isDone) throw new Error('Can\'t add teardown after end')
-    this._teardowns.push([opts.order || 0, !!opts.force, fn])
-  }
-
-  async _exception (natives, functionOrPromise, expectedError, message) {
-    if (typeof expectedError === 'string') {
-      message = expectedError
-      expectedError = undefined
-    }
-
-    const top = originFrame(this._exception)
-    const pristineMessage = message === undefined
-
-    let ok = null
-    let actual = false
-
-    if (pristineMessage) message = 'should throw'
-
-    this._active++
-    try {
-      if (typeof functionOrPromise === 'function') functionOrPromise = functionOrPromise()
-      if (isPromise(functionOrPromise)) {
-        if (pristineMessage) message = 'should reject'
-        await functionOrPromise
-      }
-      ok = false
-    } catch (err) {
-      const native = natives === false && isUncaught(err)
-      if (native) throw err
-
-      if (!expectedError) {
-        ok = true
-      } else {
-        ok = lazy.tmatch(err, expectedError)
-      }
-
-      actual = err
-    } finally {
-      this._active--
-    }
-
-    const explanation = explain(ok, message, 'exception', this._exception, actual, expectedError, top)
-    this._assertion(ok, message, explanation, this._execution, top)
-    this._checkEnd()
-  }
-
-  async _execution (functionOrPromise, message) {
-    const top = originFrame(this._execution)
-    const pristineMessage = message === undefined
-
-    let ok = false
-    let error = null
-
-    if (pristineMessage) message = 'should return'
-
-    const time = highDefTimer()
-
-    this._active++
-    try {
-      if (typeof functionOrPromise === 'function') functionOrPromise = functionOrPromise()
-      if (isPromise(functionOrPromise)) {
-        if (pristineMessage) message = 'should resolve'
-        await functionOrPromise
-      }
-      ok = true
-    } catch (err) {
-      error = err
-    } finally {
-      this._active--
-    }
-
-    const elapsed = time()
-
-    const explanation = explain(ok, message, 'execution', this._execution, error, null, top)
-    this._assertion(ok, message, explanation, this._execution, top)
-    this._checkEnd()
-
-    return elapsed
-  }
-
-  _stealth (name, opts, fn) {
-    if (typeof name === 'function') return this.stealth(null, null, name)
-    if (typeof opts === 'function') return this.stealth(name, null, opts)
-
-    return this.test(name, { ...opts, stealth: true }, fn)
-  }
-
-  _snapshot (actual, message = 'should match snapshot') {
-    const top = originFrame(this._snapshot)
-
-    if (!top) {
-      this._assertion(true, message, null, this._snapshot, undefined)
-      return
-    }
-
-    if (b4a.isBuffer(actual)) {
-      actual = new Uint8Array(actual.buffer, actual.byteOffset, actual.byteLength)
-    }
-
-    const filename = top.getFileName()
-    const key = (this.name || '') + ' ' + this._message(message)
-    const expected = getSnapshot(filename, key + ' - ' + this._getTick(key), actual)
-
-    const ok = sameObject(actual, expected, { strict: true })
-    const explanation = explain(ok, message, 'snapshot', this._snapshot, actual, expected)
-
-    this._assertion(ok, message, explanation, this._snapshot, undefined)
-  }
-
-  _getTick (key) {
-    const tick = this._tickers.get(key) || 0
-    this._tickers.set(key, 1 + tick)
-    return tick
-  }
-
-  _test (name, opts, fn) {
-    if (typeof name === 'function') return this.test(null, null, name)
-    if (typeof opts === 'function') return this.test(name, null, opts)
-
-    const t = new Test(name, this, opts)
-
-    if (this._hasPlan) this._planned--
-    this._active++
-
-    return fn ? t._run(fn, opts || {}) : t
-  }
-
-  async _run (fn, opts) {
-    this._isQueued = true
-
-    if (!this._parent) {
-      if (!(await this._runner.queue(this))) return
-    }
-
-    this._onstart(opts)
-    this._wait = true
-
-    try {
-      await fn(this)
-    } catch (err) {
-      if (!(err instanceof AssertionError && err.message === 'ERR_ASSERTION: Stealth assertion failed')) {
-        this._wait = false
-        await this._runTeardown(err)
-        throw err
-      }
-    }
-
-    if (!this._hasPlan) this.end()
-
-    this._wait = false
-    this._checkEnd()
-
-    await this
-  }
-
-  _end () {
-    this._isEnded = true
-
-    if (this._hasPlan && this._planned > 0) {
-      throw prematureEnd(this, 'Too few assertions')
-    }
-
-    this._checkEnd()
-  }
-
-  _checkEnd () {
-    if (this._active || this._wait) return
-    if (this._isEnded || (this._hasPlan && this._planned === 0)) this._done()
-  }
-
-  _done () {
-    if (this._isDone) return
-    this._isDone = true
-
-    if (this._teardowns.length) {
-      this._teardowns.sort(cmp)
-      this._runTeardown(null)
-    } else {
-      this._onend(null)
-    }
-
-    if (this._parent) {
-      const p = this._parent
-
-      this._parent._active--
-      this._parent = null
-
-      p._checkEnd()
-    }
-  }
-
-  async _runTeardown (error) {
-    const forced = !!error
-
-    let fired = false
-
-    const t = setTimeout(() => {
-      fired = true
-      this.comment('...teardown still running after 250ms')
-    }, 250)
-
-    if (t.unref) t.unref()
-
-    const time = highDefTimer()
-
-    for (const [, force, teardown] of this._teardowns) {
-      try {
-        if (force || !forced) await teardown()
-      } catch (err) {
-        if (!error) error = err
-      }
-    }
-
-    clearTimeout(t)
-    if (fired) this.comment('...teardown time ' + time() + 'ms')
-    this._onend(error)
-  }
-
-  _onstart (opts) {
-    const to = this._isMain
-      ? (opts && opts.timeout !== undefined) ? opts.timeout : this._runner.defaultTimeout // main tests need a default timeout, unless opt-out
-      : opts && opts.timeout // non main ones do not
-
-    if (this._isMain) {
-      if (!this._isQueued) {
-        if (this._runner.next) throw new Error('Only run test can be running at the same time')
-        this._runner.next = this
-      }
-      this._header()
-      this._timer = highDefTimer()
-    }
-
-    if (to) this._timeout(to)
-  }
-
-  _onend (err) {
-    if (this._isResolved) return
-
-    this._timeout(0) // just to be sure incase someone ran this during teardown...
-
-    const ok = (this.fails === 0)
-
-    if (this._isMain && !err) {
-      const time = this._timer ? ' # time = ' + this._timer() + 'ms' : ''
-      this._runner.assert(false, ok, this._track(true, ok), '- ' + (this.name || '') + time, null)
-    }
-
-    this._isResolved = true
-    this._isDone = true
-
-    if (this._isMain && this._runner.next === this) {
-      this._runner.next = null
-    }
-
-    if (err) this._reject(err)
-    else this._resolve(ok)
-
-    // if test is running without deadlock detection, trigger "io" to rerun it in case idle now
-    if (this._checkDeadlock === false) setImmediate(() => {})
-  }
-}
-
-exports = module.exports = test
-
-exports.Test = Test
-exports.test = test
-exports.hook = hook
-exports.solo = solo
-exports.skip = skip
-exports.todo = todo
-exports.configure = configure
-exports.pause = pause
-exports.resume = resume
-exports.stealth = stealth
-
-// Used by snapshots
-exports.createTypedArray = createTypedArray
-
-function configure ({ timeout = DEFAULT_TIMEOUT, bail = false, solo = false, unstealth = false, source = true } = {}) {
-  const runner = getRunner()
-
-  if (runner.tests.count > 0 || runner.assertions.count > 0) {
-    throw new Error('Configuration must happen prior to registering any tests')
-  }
-
-  runner.defaultTimeout = timeout
-  runner.bail = bail
-  runner.explicitSolo = solo
-  runner.unstealth = unstealth
-  runner.source = source
-}
-
-function highDefTimerNode () {
-  const then = process.hrtime.bigint()
-  return function () {
-    const now = process.hrtime.bigint()
-    return Number(now - then) / 1e6
-  }
-}
-
-function highDefTimerFallback () {
-  const then = Date.now()
-  return function () {
-    const now = Date.now()
-    return now - then
-  }
-}
-
-function cmp (a, b) {
-  return a[0] - b[0]
-}
-
-function test (name, opts, fn, overrides) {
-  if (typeof name === 'function') return test(null, null, name, overrides)
-  if (typeof opts === 'function') return test(name, null, opts, overrides)
-
-  opts = { ...opts, ...overrides }
-
-  const t = new Test(name, null, opts)
-
-  if (fn) return t._run(fn, opts)
-  if (t._isTodo) return t._run(() => {}, opts)
-
-  if (t._isSkip) {
-    throw new Error('An inverted test cannot be skipped')
-  }
-  if (t._isSolo) {
-    t._runner.solo = t
-  }
-
-  t._onstart(opts)
-
-  return t
-}
-
-function hook (name, opts, fn) {
-  return test(name, opts, fn, { hook: true })
-}
-
-function solo (name, opts, fn) {
-  if (!name && !opts && !fn) return test.configure({ solo: true })
-  return test(name, opts, fn, { solo: true })
-}
-
-function skip (name, opts, fn) {
-  return test(name, opts, fn, { skip: true })
-}
-
-function todo (name, opts, fn) {
-  return test(name, opts, fn, { todo: true })
-}
-
-function pause () {
-  getRunner().pause()
-}
-
-function resume () {
-  getRunner().resume()
-}
-
-function wait (ticks = 1) {
-  return new Promise(resolve => {
-    tickish(function loop () {
-      if (--ticks <= 0) return resolve()
-      tickish(loop)
-    })
-  })
-}
-
-function tickish (fn) {
-  if (IS_NODE) { // do both types of tick in node to flush both queues
-    process.nextTick(queueMicrotask, fn)
-  } else {
-    queueMicrotask(fn)
-  }
-}
-
-function explain (ok, message, assert, stackStartFunction, actual, expected, top = !ok && originFrame(stackStartFunction), extra) {
-  const runner = getRunner()
-  return ok ? null : lazy.errors.explain(ok, message, assert, stackStartFunction, actual, expected, runner.source ? top : null, extra)
-}
-
-function originFrame (stackStartFunction) {
-  if (!Error.captureStackTrace) return undefined
-  const { prepareStackTrace } = Error
-  Error.prepareStackTrace = (_, stack) => {
-    if (stack[0].getFunctionName() === '[brittle.error]') return null
-    if (stack[0].getMethodName() === 'coercively') return stack[1]
-    return stack[0]
-  }
-  const err = {}
-  Error.captureStackTrace(err, stackStartFunction)
-  const { stack: top } = err
-  Error.prepareStackTrace = prepareStackTrace
-  return top
-}
-
-function isPromise (p) {
-  return !!(p && typeof p.then === 'function')
-}
-
-function isUncaught (err) {
-  return err instanceof SyntaxError ||
-    err instanceof ReferenceError ||
-    err instanceof TypeError ||
-    err instanceof EvalError ||
-    err instanceof RangeError
-}
-
-function getRunner () {
-  if (!global[RUNNER]) global[RUNNER] = new Runner()
-  return global[RUNNER]
-}
-
-function prematureEnd (t, message) {
-  const details = t._hasPlan
-    ? ' [assertion count (' + t.assertions + ') did not reach plan (' + (t.assertions + t._planned) + ')]'
-    : ''
-
-  return new Error(message + details)
-}
-
-function stealth (name, opts, fn) {
-  return test(name, opts, fn, { stealth: true })
-}
diff --git a/debian/tests/test_modules/brittle/lib/assertion-error.js b/debian/tests/test_modules/brittle/lib/assertion-error.js
deleted file mode 100644
index 2d0320e..0000000
--- a/debian/tests/test_modules/brittle/lib/assertion-error.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const CODE = 'ERR_ASSERTION'
-
-module.exports = class AssertionError extends Error {
-  constructor ({ message }) {
-    super(`${CODE}: ${message}`)
-    this.code = CODE
-
-    if (Error.captureStackTrace) {
-      Error.captureStackTrace(this, AssertionError)
-    }
-  }
-}
diff --git a/debian/tests/test_modules/brittle/lib/constants.js b/debian/tests/test_modules/brittle/lib/constants.js
deleted file mode 100644
index 50e8333..0000000
--- a/debian/tests/test_modules/brittle/lib/constants.js
+++ /dev/null
@@ -1,5 +0,0 @@
-exports.INDENT = '    '
-exports.RUNNER = Symbol.for('brittle-runner')
-exports.IS_NODE = !!(typeof process === 'object' && process && process.versions && (typeof (process.versions.node || process.versions.pear || process.versions.bare) === 'string') && !process.browser)
-exports.IS_BARE = typeof Bare !== 'undefined'
-exports.DEFAULT_TIMEOUT = 30000
diff --git a/debian/tests/test_modules/brittle/lib/errors.js b/debian/tests/test_modules/brittle/lib/errors.js
deleted file mode 100644
index 980ef19..0000000
--- a/debian/tests/test_modules/brittle/lib/errors.js
+++ /dev/null
@@ -1,132 +0,0 @@
-const StackParser = require('error-stack-parser')
-const { INDENT, IS_NODE } = require('./constants')
-const url = requireIfNode('url')
-const fs = requireIfNode('fs')
-const assert = requireIfNode('assert')
-
-const AssertionError = assert ? assert.AssertionError : Error
-const parseStack = StackParser.parse.bind(StackParser)
-
-const IGNORE = typeof __filename === 'string' ? [__filename, __filename.replace(/errors\.js$/, 'index.js')] : []
-
-exports.stringify = stringify
-exports.explain = explain
-
-function explain (ok, message, assert, stackStartFunction, actual, expected, top, extra) {
-  if (ok) return null
-
-  const cwd = getCWD()
-  const err = new AssertionError({ stackStartFunction, message, operator: assert, actual, expected })
-  stackScrub(err)
-  if (top) {
-    const line = top.getLineNumber()
-    const column = top.getColumnNumber()
-    let file = top.getFileName()?.replace(/\?cacheBust=\d+/g, '')
-
-    try {
-      try {
-        if (url) file = url.fileURLToPath(new URL(file, 'file:'))
-      } catch {}
-
-      if (file.startsWith(cwd)) {
-        file = file.replace(cwd, '.')
-      }
-
-      if (fs) {
-        const code = fs.readFileSync(file, { encoding: 'utf-8' })
-        const split = code.split(/[\n\r]/g)
-        const point = Array.from({ length: column - 1 }).map(() => '-').join('') + '^'
-        const source = [...split.slice(line - 2, line), point, ...split.slice(line, line + 2)]
-        err.source = source.join('\n')
-      } else {
-        err.source = ''
-      }
-    } /* c8 ignore next */ catch {}
-  }
-  const { code, generatedMessage, ...info } = err
-  err.code = code
-  err.generatedMessage = generatedMessage
-  Object.defineProperty(info, 'err', { value: err })
-
-  if (err.stack) {
-    info.stack = err.stack.split('\n').slice(1).map((line) => {
-      let match = false
-
-      line = line.slice(7).replace(cwd, () => {
-        match = true
-        return '.'
-      })
-
-      if (match) line = line.replace(/file:\/?\/?\/?/, '')
-      return line
-    }).join('\n').trim()
-  }
-
-  if (!info.stack || code === 'ERR_TIMEOUT' || code === 'ERR_PREMATURE_END' || actual?.code === 'ERR_TIMEOUT' || actual?.code === 'ERR_PREMATURE_END') delete info.stack
-
-  if (actual === undefined && expected === undefined) {
-    delete info.actual
-    delete info.expected
-  }
-  return info
-}
-
-function stackScrub (err) {
-  if (err && err.stack) {
-    const scrubbed = parseStack(err).filter(({ fileName }) => !IGNORE.includes(fileName))
-    if (scrubbed.length > 0) {
-      err.stack = `${Error.prototype.toString.call(err)}\n    at ${scrubbed.join('\n    at ').replace(/\?cacheBust=\d+/g, '')}`
-    }
-  }
-  return err
-}
-
-function indent (src) {
-  return src.split('\n').map(s => INDENT + '  ' + s).join('\n')
-}
-
-function stringify (o) {
-  return indent('---\n' + toYAML(o)).trimRight() + '\n' + INDENT + '  ...'
-}
-
-function getCWD () {
-  return IS_NODE ? process.cwd() : '/no/cwd/exists'
-}
-
-function requireIfNode (name) {
-  try {
-    return IS_NODE ? require(name) : null
-  } catch {
-    return null
-  }
-}
-
-// for the life of me can't find a module that does this, that also works in the browser...
-function toYAML (o, maxDepth = 5, indent = '', prev = null) {
-  if (maxDepth < 0) return indent + '...'
-
-  if (typeof o === 'string') {
-    if (o.indexOf('\n') === -1) return o + '\n'
-    return '|\n' + o.split('\n').map(s => indent + s).join('\n').trimRight() + '\n'
-  }
-
-  if (Array.isArray(o) || o instanceof Set) {
-    let s = prev ? '\n' : ''
-    for (const i of o) {
-      s += indent + '- ' + toYAML(i, maxDepth - 1, indent + '  ', 'array')
-    }
-    return s.trimRight() + '\n'
-  }
-
-  if (o && typeof o === 'object') {
-    const p = prev && prev !== 'array'
-    let s = p ? '\n' : ''
-    for (const k of Object.keys(o)) {
-      const v = o[k]
-      s += indent + k + ': ' + toYAML(v, maxDepth - 1, indent + '  ', 'object')
-    }
-    return (p ? s.trimRight() : s.trim()) + '\n'
-  }
-
-  return '' + o + '\n'
-}
diff --git a/debian/tests/test_modules/brittle/lib/snapshot.js b/debian/tests/test_modules/brittle/lib/snapshot.js
deleted file mode 100644
index 53ec34d..0000000
--- a/debian/tests/test_modules/brittle/lib/snapshot.js
+++ /dev/null
@@ -1,91 +0,0 @@
-const { IS_NODE } = require('./constants')
-const b4a = require('b4a')
-
-exports.createTypedArray = function (TypedArray, src) {
-  const b = b4a.from(src, 'base64')
-  return new TypedArray(b.buffer, b.byteOffset, b.byteLength / TypedArray.BYTES_PER_ELEMENT)
-}
-
-exports.getSnapshot = function (filename, key, actual) {
-  let snap = {}
-
-  const p = split(filename)
-  if (!p) return actual
-
-  try {
-    snap = require(p.filename)
-  } catch {}
-
-  if (snap[key] !== undefined) return snap[key]
-
-  snap[key] = actual
-
-  const fs = requireMaybe('fs')
-  if (!fs) return actual
-
-  try {
-    fs.mkdirSync(p.dirname)
-  } catch {}
-
-  let brittle = false
-  let s = ''
-
-  for (const k of Object.keys(snap)) {
-    s += 'exports[' + toString(k) + '] = '
-
-    const v = snap[k]
-
-    if (isTypedArray(v)) {
-      if (!brittle) {
-        brittle = true
-        s = 'const { createTypedArray } = require(\'brittle\')\n\n' + s
-      }
-      const b = b4a.from(v.buffer, v.byteOffset, v.byteLength)
-      s += 'createTypedArray(' + v.constructor.name + ', ' + toString(b4a.toString(b, 'base64')) + ')\n\n'
-    } else {
-      s += toString(v) + '\n\n'
-    }
-  }
-  s = '/* eslint-disable */\n\n' + s + '/* eslint-enable */\n'
-
-  fs.writeFileSync(p.filename, s)
-  return actual
-}
-
-function isTypedArray (v) {
-  return !!(v && v.BYTES_PER_ELEMENT)
-}
-
-function toString (s) {
-  if (typeof s === 'string' && s.indexOf('\n') > 0 && s.indexOf('`') === -1) return '`' + s + '`'
-  if (typeof s === 'string' && s.indexOf('"') === -1) return '\'' + s + '\''
-  return JSON.stringify(s, null, 2)
-}
-
-function split (filename) {
-  if (filename.startsWith('file://')) filename = filename.slice(7)
-
-  const a = filename.lastIndexOf('/')
-  const b = filename.lastIndexOf('\\')
-  const sep = a > b ? '/' : '\\'
-  const i = a > b ? a : b
-
-  if (i === -1) return null
-
-  const dirname = filename.slice(0, i) + sep + 'fixtures'
-
-  return {
-    dirname,
-    filename: dirname + sep + filename.slice(i + 1).replace(/\.[^.]+$/, '') + '.snapshot.cjs'
-  }
-}
-
-function requireMaybe (name) {
-  if (!IS_NODE) return null
-
-  try {
-    return require(name)
-  } catch {
-    return null
-  }
-}
diff --git a/debian/tests/test_modules/brittle/lib/tracing-promise.js b/debian/tests/test_modules/brittle/lib/tracing-promise.js
deleted file mode 100644
index 21b6711..0000000
--- a/debian/tests/test_modules/brittle/lib/tracing-promise.js
+++ /dev/null
@@ -1,72 +0,0 @@
-const activePromises = new Map()
-
-class TracingPromise extends Promise {
-  constructor (fn) {
-    const stack = (new Error()).stack
-    let deleted = false
-
-    addStack(stack)
-
-    super((resolve, reject) => {
-      const innerResolve = (value) => {
-        if (!deleted) {
-          deleted = true
-          deleteStack(stack)
-        }
-        resolve(value)
-      }
-      const innerReject = (err) => {
-        if (!deleted) {
-          deleted = true
-          deleteStack(stack)
-        }
-        reject(err)
-      }
-
-      return fn(innerResolve, innerReject)
-    })
-  }
-
-  static Untraced = Promise
-
-  static enable () {
-    global.Promise = TracingPromise
-  }
-
-  static print () {
-    if (activePromises.size === 0) {
-      console.error('(All promises are resolved)')
-      return
-    }
-    for (const [stack, count] of activePromises) {
-      const lines = stack.split('\n')
-      lines.shift()
-      lines.shift()
-
-      const trace = lines.map((line) => {
-        line = line.slice(7)
-        if (/\(node:[^(]*\)$/.test(line)) return null
-        if (line.startsWith('TracingPromise.then ')) return null
-        return '  at ' + line
-      }).filter(x => x).join('\n')
-
-      if (!trace) continue
-
-      console.error(count + ' promise' + (count === 1 ? '' : 's') + ' unresolved')
-      console.error(trace)
-      console.error()
-    }
-  }
-}
-
-module.exports = TracingPromise
-
-function addStack (s) {
-  activePromises.set(s, (activePromises.get(s) || 0) + 1)
-}
-
-function deleteStack (s) {
-  const n = activePromises.get(s)
-  if (n === 1) activePromises.delete(s)
-  else activePromises.set(s, n - 1)
-}
diff --git a/debian/tests/test_modules/brittle/package.json b/debian/tests/test_modules/brittle/package.json
deleted file mode 100644
index 24ff526..0000000
--- a/debian/tests/test_modules/brittle/package.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  "name": "brittle",
-  "version": "3.13.1",
-  "description": "A TAP test runner built for modern times",
-  "main": "index.js",
-  "bin": {
-    "brittle": "./cmd.js"
-  },
-  "author": "David Mark Clements (@davidmarkclem)",
-  "license": "Apache-2.0",
-  "scripts": {
-    "test": "standard && node test/all.mjs",
-    "test-bare": "bare test/bare-test.mjs"
-  },
-  "files": [
-    "index.js",
-    "cmd.js",
-    "lib/**.js"
-  ],
-  "dependencies": {
-    "b4a": "^1.6.0",
-    "bare-cov": "^1.0.1",
-    "bare-subprocess": "^5.0.0",
-    "error-stack-parser": "^2.1.4",
-    "globbie": "^1.0.0",
-    "paparam": "^1.6.2",
-    "same-object": "^1.0.2",
-    "test-tmp": "^1.4.0",
-    "tmatch": "^5.0.0"
-  },
-  "devDependencies": {
-    "chalk": "^4.1.2",
-    "safety-catch": "^1.0.2",
-    "standard": "^17.0.0"
-  },
-  "imports": {
-    "child_process": {
-      "bare": "bare-subprocess"
-    }
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/holepunchto/brittle.git";
-  },
-  "bugs": {
-    "url": "https://github.com/holepunchto/brittle/issues";
-  },
-  "homepage": "https://github.com/holepunchto/brittle#readme";
-}
diff --git a/debian/tests/test_modules/same-object/LICENSE b/debian/tests/test_modules/same-object/LICENSE
deleted file mode 100644
index a8ea6f2..0000000
--- a/debian/tests/test_modules/same-object/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2023 Contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/debian/tests/test_modules/same-object/README.md b/debian/tests/test_modules/same-object/README.md
deleted file mode 100644
index eb75c0b..0000000
--- a/debian/tests/test_modules/same-object/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# same-object
-
-Determine if two objects are deeply equal
-
-```
-npm install same-object
-```
-
-Supports circular references, Maps, Symbols, etc.
-
-Aims for ~99% compatibility with `deep-equal` or `assert.deepEqual` without requiring native dependencies.\
-Useful for JavaScript runtimes without native Node modules like `util`, etc.
-
-## Usage
-``` js
-const sameObject = require('same-object')
-
-console.log(sameObject(1, '1')) // true
-console.log(sameObject(1, '1', { strict: true })) // false
-
-console.log(sameObject({ a: 1 }, { a: 1 })) // true
-console.log(sameObject({ a: 1 }, { a: 1, b: 2 })) // false
-
-console.log(sameObject(
-  new Set(['a', 1, 'b', 2]),
-  new Set(['b', 2, 'a', 1])
-)) // true
-```
-
-## API
-
-#### `const bool = sameObject(a, b, [options])`
-
-Compares `a` and `b`, returning whether they are equal or not.
-
-Available `options`:
-```js
-{
-  strict: false
-}
-```
-
-Loosely comparison (`==`) by default.\
-Use `{ strict: true }` for a stronger equality check (`===`).
-
-## References
-The source code is based on:\
-[node/comparisons.js](https://github.com/nodejs/node/blob/2adea16e394448c4c87b0639514f8babbeb7a080/lib/internal/util/comparisons.js)\
-[inspect-js/node-deep-equal](https://github.com/inspect-js/node-deep-equal)\
-[chaijs/deep-eql](https://github.com/chaijs/deep-eql)
-
-## License
-MIT
diff --git a/debian/tests/test_modules/same-object/index.js b/debian/tests/test_modules/same-object/index.js
deleted file mode 100644
index 5ec328a..0000000
--- a/debian/tests/test_modules/same-object/index.js
+++ /dev/null
@@ -1,116 +0,0 @@
-module.exports = same
-
-const isPrimitive = require('./lib/is-primitive.js')
-const sameKeys = require('./lib/same-keys.js')
-const sameKeyValues = require('./lib/same-key-values.js')
-const sameIterable = require('./lib/same-iterable.js')
-const sameSet = require('./lib/same-set.js')
-const sameMap = require('./lib/same-map.js')
-const sameArray = require('./lib/same-array.js')
-const sameRegExp = require('./lib/same-regexp.js')
-
-function same (a, b, opts, memos) {
-  // Short path optimization
-  if (a === b) {
-    if (a !== 0) return true
-    return opts && opts.strict ? Object.is(a, b) : true
-  }
-
-  const aIsPrimitive = isPrimitive(a)
-  const bIsPrimitive = isPrimitive(b)
-
-  if (aIsPrimitive && bIsPrimitive) {
-    if (opts && opts.strict) {
-      return typeof a === 'number' ? (Number.isNaN(a) && Number.isNaN(b)) : a === b
-    }
-    return a == b || (Number.isNaN(a) && Number.isNaN(b)) // eslint-disable-line eqeqeq
-  }
-
-  if (aIsPrimitive !== bIsPrimitive) return false
-
-  if (opts && opts.strict) {
-    if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false
-  }
-
-  const aType = getType(a)
-  const bType = getType(b)
-
-  if (aType !== bType) return false
-
-  if (!sameKeys(a, b, opts, memos)) return false
-
-  switch (aType) {
-    case 'String':
-    case 'Number':
-    case 'Boolean':
-    case 'Date':
-      return same(a.valueOf(), b.valueOf(), opts, memos)
-  }
-
-  if (aType === 'Error') {
-    return sameKeyValues(a, b, opts, memos, ['name', 'message'])
-  }
-
-  switch (aType) {
-    case 'Int8Array':
-    case 'Uint8Array':
-    case 'Uint8ClampedArray':
-    case 'Int16Array':
-    case 'Uint16Array':
-    case 'Int32Array':
-    case 'Uint32Array':
-    case 'Float32Array':
-    case 'Float64Array':
-      return sameIterable(a, b, opts, memos)
-    case 'DataView':
-      return sameIterable(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength), opts, memos)
-    case 'ArrayBuffer':
-      return sameIterable(new Uint8Array(a), new Uint8Array(b), opts, memos)
-  }
-
-  if (aType === 'RegExp') return sameRegExp(a, b)
-
-  if (!memos) {
-    memos = { a: new Map(), b: new Map(), position: 0 }
-  } else {
-    const memoA = memos.a.get(a)
-    if (memoA !== undefined) {
-      const memoB = memos.b.get(b)
-      if (memoB !== undefined) return memoA === memoB
-    }
-    memos.position++
-  }
-
-  memos.a.set(a, memos.position)
-  memos.b.set(b, memos.position)
-
-  const equals = sameObject(a, b, opts, memos, aType)
-
-  memos.a.delete(a)
-  memos.b.delete(b)
-
-  return equals
-}
-
-function sameObject (a, b, opts, memos, aType) {
-  if (aType === 'Array' || aType === 'Arguments') {
-    if (!sameArray(a, b, opts, memos)) return false
-  }
-
-  if (aType === 'Set') {
-    if (!sameSet(a, b, opts, memos)) return false
-  }
-
-  if (aType === 'Map') {
-    if (!sameMap(a, b, opts, memos)) return false
-  }
-
-  if (!sameKeyValues(a, b, opts, memos)) return false
-
-  return true
-}
-
-function getType (o) {
-  // Note: it returns 'Null' for null prototypes
-  return Object.prototype.toString.call(o).slice(8, -1)
-}
diff --git a/debian/tests/test_modules/same-object/lib/find-loose-matching-primitives.js b/debian/tests/test_modules/same-object/lib/find-loose-matching-primitives.js
deleted file mode 100644
index 3489e0f..0000000
--- a/debian/tests/test_modules/same-object/lib/find-loose-matching-primitives.js
+++ /dev/null
@@ -1,18 +0,0 @@
-module.exports = function findLooseMatchingPrimitives (primitive) {
-  switch (typeof primitive) {
-    case 'undefined':
-      return null
-    case 'object':
-      return undefined
-    case 'symbol':
-      return false
-    case 'string':
-      primitive = +primitive
-      // Falls through
-    case 'number':
-      if (Number.isNaN(primitive)) {
-        return false
-      }
-  }
-  return true
-}
diff --git a/debian/tests/test_modules/same-object/lib/is-primitive.js b/debian/tests/test_modules/same-object/lib/is-primitive.js
deleted file mode 100644
index 91134cb..0000000
--- a/debian/tests/test_modules/same-object/lib/is-primitive.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = function isPrimitive (value) {
-  return value === null || typeof value !== 'object'
-}
diff --git a/debian/tests/test_modules/same-object/lib/same-array.js b/debian/tests/test_modules/same-object/lib/same-array.js
deleted file mode 100644
index d9614e2..0000000
--- a/debian/tests/test_modules/same-object/lib/same-array.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const same = require('../index.js')
-
-module.exports = function sameArray (a, b, opts, memos) {
-  if (a.length !== b.length) return false
-
-  for (let i = 0; i < a.length; i++) {
-    const aHasProperty = Object.prototype.hasOwnProperty.call(a, i)
-    const bHasProperty = Object.prototype.hasOwnProperty.call(b, i)
-
-    if (aHasProperty) {
-      if (!bHasProperty || !same(a[i], b[i], opts, memos)) {
-        return false
-      }
-    } else if (bHasProperty) {
-      return false
-    } else {
-      // Array is sparse
-      const aKeys = Object.keys(a)
-
-      for (; i < aKeys.length; i++) {
-        const key = aKeys[i]
-        if (!Object.prototype.hasOwnProperty.call(b, key) ||
-            !same(a[key], b[key], opts, memos)) {
-          return false
-        }
-      }
-
-      if (aKeys.length !== Object.keys(b).length) return false
-
-      return true
-    }
-  }
-
-  return true
-}
diff --git a/debian/tests/test_modules/same-object/lib/same-iterable.js b/debian/tests/test_modules/same-object/lib/same-iterable.js
deleted file mode 100644
index d505f84..0000000
--- a/debian/tests/test_modules/same-object/lib/same-iterable.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const same = require('../index.js')
-
-module.exports = function sameIterable (a, b, opts, memos) {
-  if (a.length !== b.length) return false
-
-  for (let i = 0; i < a.length; i++) {
-    if (!same(a[i], b[i], opts, memos)) {
-      return false
-    }
-  }
-
-  return true
-}
diff --git a/debian/tests/test_modules/same-object/lib/same-key-values.js b/debian/tests/test_modules/same-object/lib/same-key-values.js
deleted file mode 100644
index 60f254a..0000000
--- a/debian/tests/test_modules/same-object/lib/same-key-values.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const same = require('../index.js')
-
-module.exports = function sameKeyValues (a, b, opts, memos, keys = null) {
-  if (keys === null) keys = Object.keys(a)
-
-  for (const key of keys) {
-    if (!same(a[key], b[key], opts, memos)) return false
-  }
-
-  return true
-}
diff --git a/debian/tests/test_modules/same-object/lib/same-keys.js b/debian/tests/test_modules/same-object/lib/same-keys.js
deleted file mode 100644
index 078c1cb..0000000
--- a/debian/tests/test_modules/same-object/lib/same-keys.js
+++ /dev/null
@@ -1,13 +0,0 @@
-module.exports = function sameKeys (a, b, opts, memos) {
-  const aKeys = Object.keys(a)
-  const bKeys = Object.keys(b)
-  if (aKeys.length !== bKeys.length) return false
-
-  for (let i = 0; i < aKeys.length; i++) {
-    if (!Object.prototype.propertyIsEnumerable.call(b, aKeys[i])) return false
-  }
-
-  // + if strict, then check symbol properties: https://github.com/nodejs/node/blob/2adea16e394448c4c87b0639514f8babbeb7a080/lib/internal/util/comparisons.js#L290
-
-  return true
-}
diff --git a/debian/tests/test_modules/same-object/lib/same-map.js b/debian/tests/test_modules/same-object/lib/same-map.js
deleted file mode 100644
index 8426cf8..0000000
--- a/debian/tests/test_modules/same-object/lib/same-map.js
+++ /dev/null
@@ -1,70 +0,0 @@
-const same = require('../index.js')
-const isPrimitive = require('./is-primitive.js')
-const findLooseMatchingPrimitives = require('./find-loose-matching-primitives.js')
-
-module.exports = function sameMap (a, b, opts, memos) {
-  if (a.size !== b.size) return false
-
-  const set = new Set()
-
-  for (const [key, item1] of a) {
-    if (!isPrimitive(key)) {
-      set.add(key)
-    } else {
-      const item2 = b.get(key)
-      if (((item2 === undefined && !b.has(key)) || !same(item1, item2, opts, memos))) {
-        if (opts && opts.strict) return false
-
-        // Discard string, symbol, undefined, and null keys
-        if (!mapMightHaveLoosePrim(a, b, key, item1, memos)) return false
-
-        set.add(key)
-      }
-    }
-  }
-
-  if (set.size > 0) {
-    for (const [key, item] of b) {
-      if (!isPrimitive(key)) {
-        if (!mapHasEqualEntry(set, a, key, item, opts, memos)) {
-          return false
-        }
-        continue
-      }
-
-      if (opts && opts.strict) continue
-
-      if (a.has(key) && same(a.get(key), item, { strict: false }, memos)) continue
-
-      if (mapHasEqualEntry(set, a, key, item, { strict: false }, memos)) continue
-
-      return false
-    }
-
-    return set.size === 0
-  }
-
-  return true
-}
-
-function mapHasEqualEntry (set, a, key, bValue, opts, memos) {
-  for (const key2 of set) {
-    if (same(key, key2, opts, memos) && same(bValue, a.get(key2), opts, memos)) {
-      set.delete(key2)
-      return true
-    }
-  }
-
-  return false
-}
-
-function mapMightHaveLoosePrim (a, b, primitive, item, memos) {
-  const altValue = findLooseMatchingPrimitives(primitive)
-  if (altValue != null) return altValue
-
-  const bValue = b.get(altValue)
-  if (bValue === undefined && !b.has(altValue)) return false
-  if (!same(item, bValue, { strict: false }, memos)) return false
-
-  return !a.has(altValue) && same(item, bValue, { strict: false }, memos)
-}
diff --git a/debian/tests/test_modules/same-object/lib/same-regexp.js b/debian/tests/test_modules/same-object/lib/same-regexp.js
deleted file mode 100644
index aa4b588..0000000
--- a/debian/tests/test_modules/same-object/lib/same-regexp.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = function sameRegExp (a, b) {
-  return a.source === b.source && a.flags === b.flags
-}
diff --git a/debian/tests/test_modules/same-object/lib/same-set.js b/debian/tests/test_modules/same-object/lib/same-set.js
deleted file mode 100644
index 4c15df0..0000000
--- a/debian/tests/test_modules/same-object/lib/same-set.js
+++ /dev/null
@@ -1,64 +0,0 @@
-const same = require('../index.js')
-const isPrimitive = require('./is-primitive.js')
-const findLooseMatchingPrimitives = require('./find-loose-matching-primitives.js')
-
-module.exports = function sameSet (a, b, opts, memos) {
-  if (a.size !== b.size) return false
-
-  const set = new Set()
-
-  for (const aValue of a) {
-    if (!isPrimitive(aValue)) {
-      // Non-null object (non strict only: a not matching primitive)
-      set.add(aValue)
-    } else if (!b.has(aValue)) {
-      if (opts && opts.strict) return false
-
-      // Discard string, symbol, undefined, and null values
-      if (!setMightHaveLoosePrim(a, b, aValue)) return false
-
-      set.add(aValue)
-    }
-  }
-
-  if (set.size > 0) {
-    for (const bValue of b) {
-      if (!isPrimitive(bValue)) {
-        if (!setHasEqualElement(set, bValue, opts, memos)) {
-          return false
-        }
-        continue
-      }
-
-      if (opts && opts.strict) continue
-
-      if (a.has(bValue)) continue
-
-      if (setHasEqualElement(set, bValue, opts, memos)) continue
-
-      return false
-    }
-
-    return set.size === 0
-  }
-
-  return true
-}
-
-function setMightHaveLoosePrim (a, b, primitive) {
-  const altValue = findLooseMatchingPrimitives(primitive)
-  if (altValue != null) return altValue
-
-  return b.has(altValue) && !a.has(altValue)
-}
-
-function setHasEqualElement (set, val1, opts, memos) {
-  for (const val2 of set) {
-    if (same(val1, val2, opts, memos)) {
-      set.delete(val2)
-      return true
-    }
-  }
-
-  return false
-}
diff --git a/debian/tests/test_modules/same-object/package.json b/debian/tests/test_modules/same-object/package.json
deleted file mode 100644
index 7b0af43..0000000
--- a/debian/tests/test_modules/same-object/package.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "name": "same-object",
-  "version": "1.0.2",
-  "description": "Determine if two objects are deeply equal",
-  "main": "index.js",
-  "scripts": {
-    "test": "standard && brittle test.js --coverage"
-  },
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/holepunchto/same-object.git";
-  },
-  "author": "Lucas Barrena (LuKks)",
-  "license": "MIT",
-  "bugs": {
-    "url": "https://github.com/holepunchto/same-object/issues";
-  },
-  "homepage": "https://github.com/holepunchto/same-object";,
-  "devDependencies": {
-    "brittle": "^3.1.1",
-    "deep-equal": "^2.2.0",
-    "standard": "^17.0.0"
-  }
-}
diff --git a/debian/tests/test_modules/same-object/test.js b/debian/tests/test_modules/same-object/test.js
deleted file mode 100644
index 9af358e..0000000
--- a/debian/tests/test_modules/same-object/test.js
+++ /dev/null
@@ -1,1399 +0,0 @@
-const test = require('brittle')
-const sameObject = require('./')
-const deepEqual = require('deep-equal')
-
-test.configure({ bail: true })
-
-// NOTE: most tests were copied and adapted from deep-equal library
-
-const safeBuffer = typeof Buffer === 'function' ? Buffer.from : null
-const buffersAreTypedArrays = typeof Buffer === 'function' && safeBuffer('') instanceof Uint8Array
-
-test('basic', function (t) {
-  t.ok(sameObject(1, '1'))
-  t.absent(sameObject(1, '1', { strict: true }))
-})
-
-test('basic helper', function (t) {
-  unlike(t, 1, '1')
-  alikeLoosely(t, 1, '1')
-})
-
-test('equal', function (t) {
-  alike(t,
-    { a: [2, 3], b: [4] },
-    { a: [2, 3], b: [4] },
-    'two equal objects'
-  )
-
-  alikeLoosely(t,
-    { a: 2, b: '4' },
-    { a: 2, b: 4 },
-    'two loosely equal, strictly inequal objects'
-  )
-
-  unlikeLoosely(t,
-    { a: 2, b: 4 },
-    { a: 2, B: 4 },
-    'two inequal objects'
-  )
-
-  alikeLoosely(t,
-    '-000',
-    false,
-    '`false` and `"-000"`'
-  )
-})
-
-test('Maps', function (t) {
-  alike(t,
-    new Map([['a', 1], ['b', 2]]),
-    new Map([['b', 2], ['a', 1]]),
-    'two equal Maps'
-  )
-
-  unlikeLoosely(t,
-    new Map([['a', [1, 2]]]),
-    new Map([['a', [2, 1]]]),
-    'two Maps with inequal values on the same key'
-  )
-
-  unlikeLoosely(t,
-    new Map([['a', 1]]),
-    new Map([['b', 1]]),
-    'two inequal Maps'
-  )
-
-  alike(t,
-    new Map([[{}, 3], [{}, 2], [{}, 1]]),
-    new Map([[{}, 1], [{}, 2], [{}, 3]]),
-    'two equal Maps in different orders with object keys'
-  )
-
-  alikeLoosely(t,
-    new Map([[undefined, undefined]]),
-    new Map([[undefined, null]]),
-    'undefined keys, nullish values, loosely equal, strictly inequal'
-  )
-
-  alike(t,
-    new Map([[{}, null], [true, 2], [{}, 1], [undefined, {}]]),
-    new Map([[{}, 1], [true, 2], [{}, null], [undefined, {}]]),
-    'two equal Maps in different orders with primitive keys'
-  )
-
-  alike(t,
-    new Map([[false, 3], [{}, 2], [{}, 1]]),
-    new Map([[{}, 1], [{}, 2], [false, 3]]),
-    'two equal Maps in different orders with a mix of keys'
-  )
-
-  alikeLoosely(t,
-    new Map([[null, undefined]]),
-    new Map([[null, null]]),
-    'null keys, nullish values, loosely equal, strictly inequal'
-  )
-
-  alikeLoosely(t,
-    new Map([[undefined, 3]]),
-    new Map([[null, 3]]),
-    'nullish keys, loosely equal, strictly inequal'
-  )
-
-  alike(t,
-    new Map([[{}, null], [true, 2], [{}, 1], [undefined, {}]]),
-    new Map([[{}, 1], [true, 2], [{}, null], [undefined, {}]]),
-    'two equal Maps in different orders with primitive keys'
-  )
-
-  alike(t,
-    new Map([[false, 3], [{}, 2], [{}, 1]]),
-    new Map([[{}, 1], [{}, 2], [false, 3]]),
-    'two equal Maps in different orders with a mix of keys'
-  )
-
-  unlikeLoosely(t,
-    new Map(),
-    new Map([[{}, 1]]),
-    'two inequal Maps'
-  )
-
-  unlikeLoosely(t,
-    new Map([[{}, null], [false, 3]]),
-    new Map([[{}, null], [true, 2]]),
-    'two inequal maps, same size, primitive key, start with object key'
-  )
-
-  unlikeLoosely(t,
-    new Map([[false, 3], [{}, null]]),
-    new Map([[true, 2], [{}, null]]),
-    'two inequal maps, same size, primitive key, start with primitive key'
-  )
-
-  alikeLoosely(t,
-    new Map([[undefined, null], ['+000', 2]]),
-    new Map([[null, undefined], [false, '2']]),
-    'primitive comparisons'
-  )
-})
-
-// +
-test('WeakMaps', function (t) {
-  alike(t,
-    new WeakMap([[Object, null], [Function, true]]),
-    new WeakMap([[Function, true], [Object, null]]),
-    'two equal WeakMaps'
-  )
-
-  alike(t,
-    new WeakMap([[Object, null]]),
-    new WeakMap([[Object, true]]),
-    'two WeakMaps with inequal values on the same key'
-  )
-
-  alike(t,
-    new WeakMap([[Object, null], [Function, true]]),
-    new WeakMap([[Object, null]]),
-    'two inequal WeakMaps'
-  )
-})
-
-test('Sets', function (t) {
-  alike(t,
-    new Set(['a', 1, 'b', 2]),
-    new Set(['b', 2, 'a', 1]),
-    'two equal Sets'
-  )
-
-  unlikeLoosely(t,
-    new Set(['a', 1]),
-    new Set(['b', 1]),
-    'two inequal Sets'
-  )
-
-  alike(t,
-    new Set([{}, 1, {}, {}, 2]),
-    new Set([{}, 1, {}, 2, {}]),
-    'two equal Sets in different orders'
-  )
-
-  unlikeLoosely(t,
-    new Set(),
-    new Set([1]),
-    'two inequally sized Sets'
-  )
-
-  alikeLoosely(t,
-    new Set([{ a: 1 }, 2]),
-    new Set(['2', { a: '1' }]),
-    'two loosely equal, strictly inequal Sets'
-  )
-
-  unlikeLoosely(t,
-    new Set([{ a: 1 }, 2]),
-    new Set(['2', { a: 2 }]),
-    'two inequal Sets'
-  )
-
-  alikeLoosely(t,
-    new Set([null, '', 1, 5, 2, false]),
-    new Set([undefined, 0, '5', true, '2', '-000']),
-    'more primitive comparisons'
-  )
-
-  alike(t,
-    new Set([1, 2]),
-    new Set([2, 1]),
-    'primitives in different keys'
-  )
-
-  alike(t,
-    new Set([{ a: 1 }, { b: 2 }]),
-    new Set([{ b: 2 }, { a: 1 }]),
-    'object values in different keys'
-  )
-
-  alike(t,
-    new Set([new Set([1, 2]), new Set([3, 4])]),
-    new Set([new Set([4, 3]), new Set([2, 1])]),
-    'Set of Sets, all in different keys'
-  )
-
-  unlikeLoosely(t,
-    new Set([{ a: 1 }, 1]),
-    new Set([{ a: 1 }, 2]),
-    'non primitive first, and non alike primitive later'
-  )
-
-  alikeLoosely(t,
-    new Set([{ a: 1 }, Infinity]),
-    new Set([{ a: 1 }, Infinity]),
-    'primitive that is not loose'
-  )
-
-  unlikeLoosely(t,
-    new Set([Symbol.for('hi')]),
-    new Set([Symbol.for('hi2')]),
-    'different symbols in a Set'
-  )
-})
-
-test('Set and Map', function (t) {
-  unlikeLoosely(t,
-    new Set(),
-    new Map(),
-    'Map and Set'
-  )
-
-  // +
-  /* const maplikeSet = new Set()
-  Object.defineProperty(maplikeSet, 'constructor', { enumerable: false, value: Map })
-  maplikeSet.__proto__ = Map.prototype // eslint-disable-line no-proto
-  unlikeLoosely(t,
-    maplikeSet,
-    new Map(),
-    'Map-like Set, and Map'
-  ) */
-})
-
-// +
-test('WeakSets', function (t) {
-  alike(t,
-    new WeakSet([Object, Function]),
-    new WeakSet([Function, Object]),
-    'two equal WeakSets'
-  )
-
-  alike(t,
-    new WeakSet([Object, Function]),
-    new WeakSet([Object]),
-    'two inequal WeakSets'
-  )
-})
-
-test('not equal', function (t) {
-  unlikeLoosely(t,
-    { x: 5, y: [6] },
-    { x: 5, y: 6 },
-    'two inequal objects are'
-  )
-})
-
-test('nested nulls', function (t) {
-  alike(t,
-    [null, null, null],
-    [null, null, null],
-    'same-length arrays of nulls'
-  )
-})
-
-test('objects with strings vs numbers', function (t) {
-  alikeLoosely(t,
-    [{ a: 3 }, { b: 4 }],
-    [{ a: '3' }, { b: '4' }],
-    'objects with equivalent string/number values'
-  )
-})
-
-test('non-objects', function (t) {
-  alike(t, 3, 3, 'same numbers', true, true, true)
-  alike(t, 'beep', 'beep', 'same strings', true, true, true)
-  alikeLoosely(t, '3', 3, 'numeric string and number', true, false)
-  unlikeLoosely(t, '3', [3], 'numeric string and array containing number', false, false)
-  unlikeLoosely(t, 3, [3], 'number and array containing number', false, false)
-})
-
-test('infinities', function (t) {
-  alike(t, Infinity, Infinity, '∞ and ∞', true, true, true)
-  alike(t, -Infinity, -Infinity, '-∞ and -∞', true, true, true)
-  unlikeLoosely(t, Infinity, -Infinity, '∞ and -∞', false, false)
-})
-
-test('arguments class', function (t) {
-  function getArgs () {
-    return arguments
-  }
-
-  alike(t,
-    getArgs(1, 2, 3),
-    getArgs(1, 2, 3),
-    'equivalent arguments objects are equal'
-  )
-
-  unlikeLoosely(t,
-    getArgs(1, 2, 3),
-    [1, 2, 3],
-    'array and arguments with same contents'
-  )
-
-  const args = getArgs()
-  const notArgs = tag({ length: 0 }, 'Arguments')
-  unlikeLoosely(t,
-    args,
-    notArgs,
-    'args and similar arraylike object'
-  )
-})
-
-test('Dates', function (t) {
-  const d0 = new Date(1387585278000)
-  const d1 = new Date('Fri Dec 20 2013 16:21:18 GMT-0800 (PST)')
-
-  alike(t, d0, d1, 'two Dates with the same timestamp', true, true)
-
-  d1.a = true
-
-  unlikeLoosely(t, d0, d1, 'two Dates with the same timestamp but different own properties', false, false)
-
-  t.test('overriding `getTime`', function (st) {
-    const a = new Date('2000')
-    const b = new Date('2000')
-    Object.defineProperty(a, 'getTime', { value: function () { return 5 } })
-    alike(st, a, b, 'two Dates with the same timestamp but one has overridden `getTime`', true, true)
-  })
-
-  // +
-  /* t.test('fake Date', { skip: !hasDunderProto }, function (st) {
-    const a = new Date(2000)
-    const b = tag(Object.create(
-      a.__proto__, // eslint-disable-line no-proto
-      Object.getOwnPropertyDescriptors(a)
-    ), 'Date')
-
-    unlikeLoosely(st,
-      a,
-      b,
-      'Date, and fake Date'
-    )
-  }) */
-
-  const a = new Date('2000')
-  const b = new Date('2000')
-  b.foo = true
-  unlikeLoosely(t,
-    a,
-    b,
-    'two identical Dates, one with an extra property'
-  )
-
-  unlikeLoosely(t,
-    new Date('2000'),
-    new Date('2001'),
-    'two inequal Dates'
-  )
-})
-
-test('buffers', { skip: typeof Buffer !== 'function' }, function (t) {
-  alike(t,
-    safeBuffer('xyz'),
-    safeBuffer('xyz'),
-    'buffers with same contents are equal'
-  )
-
-  unlikeLoosely(t,
-    safeBuffer('xyz'),
-    safeBuffer('xyy'),
-    'buffers with same length and different contents are inequal'
-  )
-
-  unlikeLoosely(t,
-    safeBuffer('xyz'),
-    safeBuffer('xy'),
-    'buffers with different length are inequal'
-  )
-
-  unlikeLoosely(t,
-    safeBuffer('abc'),
-    safeBuffer('xyz'),
-    'buffers with different contents'
-  )
-
-  const emptyBuffer = safeBuffer('')
-
-  unlikeLoosely(t,
-    emptyBuffer,
-    [],
-    'empty buffer and empty array'
-  )
-
-  t.test('bufferlikes', function (st) {
-    const fakeBuffer = {
-      0: 'a',
-      length: 1,
-      __proto__: emptyBuffer.__proto__, // eslint-disable-line no-proto
-      copy: emptyBuffer.copy,
-      slice: emptyBuffer.slice
-    }
-    Object.defineProperty(fakeBuffer, '0', { enumerable: false })
-    Object.defineProperty(fakeBuffer, 'length', { enumerable: false })
-    Object.defineProperty(fakeBuffer, 'copy', { enumerable: false })
-    Object.defineProperty(fakeBuffer, 'slice', { enumerable: false })
-
-    unlikeLoosely(st,
-      safeBuffer('a'),
-      fakeBuffer,
-      'real buffer, and mildly fake buffer'
-    )
-
-    st.test('bufferlike', function (s2t) {
-      const bufferlike = buffersAreTypedArrays ? new Uint8Array() : {}
-      Object.defineProperty(bufferlike, 'length', {
-        enumerable: false,
-        value: bufferlike.length || 0
-      })
-      Object.defineProperty(bufferlike, 'copy', {
-        enumerable: false,
-        value: emptyBuffer.copy
-      })
-      bufferlike.__proto__ = emptyBuffer.__proto__ // eslint-disable-line no-proto
-
-      alike(s2t,
-        emptyBuffer,
-        bufferlike,
-        'empty buffer and empty bufferlike'
-      )
-      s2t.end()
-    })
-
-    st.end()
-  })
-
-  t.end()
-})
-
-test('DataView', function (t) {
-  const view1 = new DataView(new ArrayBuffer(10))
-  const view2 = new DataView(new ArrayBuffer(10))
-
-  alike(t,
-    view1,
-    view2,
-    'two equals DataViews'
-  )
-
-  view1[3] = 7
-
-  unlike(t,
-    view1,
-    view2,
-    'two inequal DataViews'
-  )
-})
-
-test('Arrays', function (t) {
-  const a = []
-  const b = []
-  b.foo = true
-
-  unlikeLoosely(t,
-    a,
-    b,
-    'two identical arrays, one with an extra property'
-  )
-
-  const c = [undefined, 'test']
-  const d = []
-  d[1] = 'test'
-  unlikeLoosely(t, c, d, 'sparse array')
-
-  const e = [undefined, 'test', undefined, undefined, 'test2', undefined]
-  const f = []
-  e[1] = 'test'
-  e[4] = 'test2'
-  unlikeLoosely(t, e, f, 'sparse array')
-
-  const g = new Array(10)
-  const h = new Array(10)
-  g[2] = 'test'
-  g[5] = 'test2'
-  g[8] = 'test3'
-  h[2] = 'test'
-  h[5] = 'test2'
-  h[8] = 'test3'
-  alike(t, g, h, 'sparse array')
-
-  t.end()
-})
-
-test('booleans', function (t) {
-  alike(t,
-    true,
-    true,
-    'trues'
-  )
-
-  alike(t,
-    false,
-    false,
-    'falses'
-  )
-
-  unlikeLoosely(t,
-    true,
-    false,
-    'true and false'
-  )
-
-  t.end()
-})
-
-test('booleans and arrays', function (t) {
-  unlikeLoosely(t,
-    true,
-    [],
-    'true and an empty array',
-    false,
-    false
-  )
-  unlikeLoosely(t,
-    false,
-    [],
-    'false and an empty array'
-  )
-  t.end()
-})
-
-test('arrays initiated', function (t) {
-  const a0 = [
-    undefined,
-    null,
-    -1,
-    0,
-    1,
-    false,
-    true,
-    undefined,
-    '',
-    'abc',
-    null,
-    undefined
-  ]
-  const a1 = [
-    undefined,
-    null,
-    -1,
-    0,
-    1,
-    false,
-    true,
-    undefined,
-    '',
-    'abc',
-    null,
-    undefined
-  ]
-
-  alike(t,
-    a0,
-    a1,
-    'arrays with equal contents are equal'
-  )
-  t.end()
-})
-
-test('arrays assigned', function (t) {
-  const a0 = [
-    undefined,
-    null,
-    -1,
-    0,
-    1,
-    false,
-    true,
-    undefined,
-    '',
-    'abc',
-    null,
-    undefined
-  ]
-  const a1 = []
-
-  a1[0] = undefined
-  a1[1] = null
-  a1[2] = -1
-  a1[3] = 0
-  a1[4] = 1
-  a1[5] = false
-  a1[6] = true
-  a1[7] = undefined
-  a1[8] = ''
-  a1[9] = 'abc'
-  a1[10] = null
-  a1[11] = undefined
-  a1.length = 12
-
-  alike(t, a0, a1, 'a literal array and an assigned array', true, true)
-  t.end()
-})
-
-test('arrays push', function (t) {
-  const a0 = [
-    undefined,
-    null,
-    -1,
-    0,
-    1,
-    false,
-    true,
-    undefined,
-    '',
-    'abc',
-    null,
-    undefined
-  ]
-  const a1 = []
-
-  a1.push(undefined)
-  a1.push(null)
-  a1.push(-1)
-  a1.push(0)
-  a1.push(1)
-  a1.push(false)
-  a1.push(true)
-  a1.push(undefined)
-  a1.push('')
-  a1.push('abc')
-  a1.push(null)
-  a1.push(undefined)
-  a1.length = 12
-
-  alike(t, a0, a1, 'a literal array and a pushed array', true, true)
-  t.end()
-})
-
-test('null == undefined', function (t) {
-  alikeLoosely(t, null, undefined, 'null and undefined', true, false)
-  alikeLoosely(t, [null], [undefined], '[null] and [undefined]', true, false)
-
-  t.end()
-})
-
-// node 14 changed `deepEqual` to make two NaNs loosely equal
-test('NaNs', function (t) {
-  alike(t,
-    NaN,
-    NaN,
-    'two NaNs'
-  )
-
-  alike(t,
-    { a: NaN },
-    { a: NaN },
-    'two equiv objects with a NaN value'
-  )
-
-  unlikeLoosely(t, NaN, 1, 'NaN and 1', false, false)
-
-  t.end()
-})
-
-test('zeroes', function (t) {
-  alikeLoosely(t, 0, -0, '0 and -0', true, false)
-  unlike(t, 0, -0, '0 and -0', true, false)
-
-  alikeLoosely(t, { a: 0 }, { a: -0 }, 'two objects with a same-keyed 0/-0 value', true, false)
-  unlike(t, { a: 0 }, { a: -0 }, 'two objects with a same-keyed 0/-0 value', true, false)
-
-  t.end()
-})
-
-test('Object.create', function (t) {
-  const a = { a: 'A' }
-  const b = Object.create(a)
-  b.b = 'B'
-  const c = Object.create(a)
-  c.b = 'C'
-
-  unlikeLoosely(t,
-    b,
-    c,
-    'two objects with the same [[Prototype]] but a different own property'
-  )
-
-  t.end()
-})
-
-test('Object.create(null)', function (t) {
-  alike(t,
-    Object.create(null),
-    Object.create(null),
-    'two empty null objects'
-  )
-
-  alike(t,
-    Object.create(null, { a: { value: 'b' } }),
-    Object.create(null, { a: { value: 'b' } }),
-    'two null objects with the same property pair'
-  )
-
-  t.end()
-})
-
-test('regexes vs dates', function (t) {
-  const d = new Date(1387585278000)
-  const r = /abc/
-
-  unlikeLoosely(t, d, r, 'Date and RegExp', false, false)
-
-  t.end()
-})
-
-test('regexp', function (t) {
-  unlikeLoosely(t, /abc/, /xyz/, 'two different regexes', false, false)
-  alike(t, /abc/, /abc/, 'two abc regexes', true, true, false)
-  alike(t, /xyz/, /xyz/, 'two xyz regexes', true, true, false)
-  unlike(t, /abc/i, /def/g, 'two xyz regexes')
-
-  // +
-  /* t.test('fake RegExp', function (st) {
-    const a = /abc/g
-    const b = tag(Object.create(
-      a.__proto__, // eslint-disable-line no-proto
-      Object.getOwnPropertyDescriptors(a)
-    ), 'RegExp')
-
-    unlikeLoosely(st,a, b, 'regex and fake regex', false, false)
-
-    st.end()
-  }) */
-
-  const a = /abc/gi
-  const b = /abc/gi
-  b.foo = true
-  unlikeLoosely(t,
-    a,
-    b,
-    'two identical regexes, one with an extra property'
-  )
-
-  const c = /abc/g
-  const d = /abc/i
-  unlikeLoosely(t,
-    c,
-    d,
-    'two regexes with the same source but different flags'
-  )
-
-  t.end()
-})
-
-test('object literals', function (t) {
-  alikeLoosely(t,
-    { prototype: 2 },
-    { prototype: '2' },
-    'two loosely equal, strictly inequal prototype properties'
-  )
-
-  t.end()
-})
-
-test('arrays and objects', function (t) {
-  unlikeLoosely(t, [], {}, 'empty array and empty object', false, false)
-  unlikeLoosely(t, [], { length: 0 }, 'empty array and empty arraylike object', false, false)
-  unlikeLoosely(t, [1], { 0: 1 }, 'array and similar object', false, false)
-
-  t.end()
-})
-
-test('functions', function (t) {
-  function f () {}
-
-  alike(t, f, f, 'a function and itself', true, true, true)
-  alike(t, [f], [f], 'a function and itself in an array', true, true, true)
-
-  unlikeLoosely(t, function () {}, function () {}, 'two distinct functions', false, false, true)
-  unlikeLoosely(t, [function () {}], [function () {}], 'two distinct functions in an array', false, false, true)
-
-  unlikeLoosely(t, f, {}, 'function and object', false, false, true)
-  unlikeLoosely(t, [f], [{}], 'function and object in an array', false, false, true)
-
-  t.end()
-})
-
-test('Errors', function (t) {
-  alike(t, new Error('xyz'), new Error('xyz'), 'two errors of the same type with the same message', true, true, false)
-  unlikeLoosely(t, new Error('xyz'), new TypeError('xyz'), 'two errors of different types with the same message', false, false)
-  unlikeLoosely(t, new Error('xyz'), new Error('zyx'), 'two errors of the same type with a different message', false, false)
-
-  // +
-  /* t.test('errorlike', { skip: !Object.defineProperty }, function (st) {
-    const err = new Error('foo')
-    // TODO: add `__proto__` when brand check is available
-    const errorlike = tag({ message: err.message, stack: err.stack, name: err.name, constructor: err.constructor }, 'Error')
-    Object.defineProperty(errorlike, 'message', { enumerable: false })
-    Object.defineProperty(errorlike, 'stack', { enumerable: false })
-    Object.defineProperty(errorlike, 'name', { enumerable: false })
-    Object.defineProperty(errorlike, 'constructor', { enumerable: false })
-    st.absent(errorlike instanceof Error)
-    st.ok(err instanceof Error)
-    unlikeLoosely(st,
-      err,
-      errorlike,
-      'error, and errorlike object'
-    )
-
-    st.end()
-  }) */
-
-  // +
-  unlikeLoosely(t,
-    new Error('a'),
-    Object.assign(new Error('a'), { code: 10 }),
-    'two otherwise equal errors with different own properties'
-  )
-
-  // +
-  /* t.test('fake error', { skip: !process.env.ASSERT || !hasDunderProto }, function (st) {
-    const a = tag({
-      __proto__: null
-    }, 'Error')
-    const b = new RangeError('abc')
-    b.__proto__ = null // eslint-disable-line no-proto
-
-    unlikeLoosely(st,
-      a,
-      b,
-      'null object faking as an Error, RangeError with null proto'
-    )
-    st.end()
-  }) */
-
-  t.end()
-})
-
-test('object and null', function (t) {
-  unlikeLoosely(t,
-    {},
-    null,
-    'null and an object'
-  )
-
-  t.end()
-})
-
-test('error = Object', function (t) {
-  unlikeLoosely(t,
-    new Error('a'),
-    { message: 'a' }
-  )
-
-  t.end()
-})
-
-test('[[Prototypes]]', function (t) {
-  function C () {}
-  const instance = new C()
-  delete instance.constructor
-
-  alikeLoosely(t, {}, instance, 'two identical objects with different [[Prototypes]]', true, false)
-
-  t.test('Dates with different prototypes', function (st) {
-    const d1 = new Date(0)
-    const d2 = new Date(0)
-
-    alike(st, d1, d2, 'two dates with the same timestamp', true, true)
-
-    const newProto = {
-      __proto__: Date.prototype
-    }
-    d2.__proto__ = newProto // eslint-disable-line no-proto
-    st.ok(d2 instanceof Date, 'd2 is still a Date instance after tweaking [[Prototype]]')
-
-    alikeLoosely(st, d1, d2, 'two dates with the same timestamp and different [[Prototype]]', true, false)
-
-    st.end()
-  })
-
-  t.end()
-})
-
-test('toStringTag', function (t) {
-  const o1 = {}
-  t.is(Object.prototype.toString.call(o1), '[object Object]', 'o1: Symbol.toStringTag works')
-
-  const o2 = {}
-  t.is(Object.prototype.toString.call(o2), '[object Object]', 'o2: original Symbol.toStringTag works')
-
-  alike(t, o1, o2, 'two normal empty objects', true, true)
-
-  o2[Symbol.toStringTag] = 'jifasnif'
-  t.is(Object.prototype.toString.call(o2), '[object jifasnif]', 'o2: modified Symbol.toStringTag works')
-
-  unlikeLoosely(t, o1, o2, 'two normal empty objects with different toStringTags', false, false)
-
-  t.end()
-})
-
-test('boxed primitives', function (t) {
-  unlikeLoosely(t, Object(false), false, 'boxed and primitive `false`', false, false)
-  unlikeLoosely(t, Object(true), true, 'boxed and primitive `true`', false, false)
-  unlikeLoosely(t, Object(3), 3, 'boxed and primitive `3`', false, false)
-  unlikeLoosely(t, Object(NaN), NaN, 'boxed and primitive `NaN`', false, false)
-  unlikeLoosely(t, Object(''), '', 'boxed and primitive `""`', false, false)
-  unlikeLoosely(t, Object('str'), 'str', 'boxed and primitive `"str"`', false, false)
-
-  t.test('symbol', function (st) {
-    const s = Symbol('')
-    unlikeLoosely(st, Object(s), s, 'boxed and primitive `Symbol()`', false, false)
-    st.end()
-  })
-
-  t.test('bigint', function (st) {
-    const hhgtg = BigInt(42)
-    unlikeLoosely(st, Object(hhgtg), hhgtg, 'boxed and primitive `BigInt(42)`', false, false)
-    st.end()
-  })
-
-  // +
-  /* t.test('`valueOf` is called for boxed primitives', function (st) {
-    const a = Object(5)
-    a.valueOf = function () { throw new Error('failed') }
-    const b = Object(5)
-    b.valueOf = function () { throw new Error('failed') }
-
-    unlikeLoosely(st, a, b, 'two boxed numbers with a thrower valueOf', false, false)
-
-    st.end()
-  }) */
-
-  t.end()
-})
-
-test('getters', function (t) {
-  const a = {}
-  Object.defineProperty(a, 'a', { enumerable: true, get: function () { return 5 } })
-  const b = {}
-  Object.defineProperty(b, 'a', { enumerable: true, get: function () { return 6 } })
-
-  unlikeLoosely(t, a, b, 'two objects with the same getter but producing different values', false, false)
-
-  t.end()
-})
-
-test('fake arrays: extra keys will be tested', function (t) {
-  const a = tag({
-    __proto__: Array.prototype,
-    0: 1,
-    1: 1,
-    2: 'broken',
-    length: 2
-  }, 'Array')
-
-  if (Object.defineProperty) {
-    Object.defineProperty(a, 'length', {
-      enumerable: false
-    })
-  }
-
-  unlikeLoosely(t, a, [1, 1], 'fake and real array with same contents and [[Prototype]]', false, false)
-
-  const b = tag(/abc/, 'Array')
-  b.__proto__ = Array.prototype // eslint-disable-line no-proto
-  b.length = 3
-  if (Object.defineProperty) {
-    Object.defineProperty(b, 'length', {
-      enumerable: false
-    })
-  }
-  unlikeLoosely(t, b, ['a', 'b', 'c'], 'regex faking as array, and array', false, false)
-
-  t.end()
-})
-
-test('circular references', function (t) {
-  const b = {}
-  b.b = b
-
-  const c = {}
-  c.b = c
-
-  alike(t,
-    b,
-    c,
-    'two self-referencing objects'
-  )
-
-  const d = {}
-  d.a = 1
-  d.b = d
-
-  const e = {}
-  e.a = 1
-  e.b = e.a
-
-  unlikeLoosely(t,
-    d,
-    e,
-    'two deeply self-referencing objects'
-  )
-
-  t.end()
-})
-
-test('TypedArrays', function (t) {
-  // +
-  /* t.test('Buffer faked as Uint8Array', function (st) {
-    const a = safeBuffer('test')
-    const b = tag(Object.create(
-      a.__proto__, // eslint-disable-line no-proto
-      Object.assign(Object.getOwnPropertyDescriptors(a), {
-        length: {
-          enumerable: false,
-          value: 4
-        }
-      })
-    ), 'Uint8Array')
-
-    unlikeLoosely(st,
-      a,
-      b,
-      'Buffer and Uint8Array'
-    )
-
-    st.end()
-  }) */
-
-  // +
-  /* t.test('one TypedArray faking as another', { skip: !hasDunderProto }, function (st) {
-    const a = new Uint8Array(10)
-    const b = tag(new Int8Array(10), 'Uint8Array')
-    b.__proto__ = Uint8Array.prototype // eslint-disable-line no-proto
-
-    unlikeLoosely(st,
-      a,
-      b,
-      'Uint8Array, and Int8Array pretending to be a Uint8Array'
-    )
-
-    st.end()
-  }) */
-
-  t.test('ArrayBuffers', { skip: typeof ArrayBuffer !== 'function' }, function (st) {
-    const buffer1 = new ArrayBuffer(8) // initial value of 0's
-    const buffer2 = new ArrayBuffer(8) // initial value of 0's
-
-    const view1 = new Int8Array(buffer1)
-    const view2 = new Int8Array(buffer2)
-
-    alike(st,
-      view1,
-      view2,
-      'Int8Arrays of similar ArrayBuffers'
-    )
-
-    alike(st,
-      buffer1,
-      buffer2,
-      'similar ArrayBuffers'
-    )
-
-    for (let i = 0; i < view1.byteLength; i += 1) {
-      view1[i] = 9 // change all values to 9's
-    }
-
-    unlikeLoosely(st,
-      view1,
-      view2,
-      'Int8Arrays of different ArrayBuffers'
-    )
-
-    unlikeLoosely(st,
-      buffer1,
-      buffer2,
-      'different ArrayBuffers'
-    )
-
-    // node < 0.11 has a nonconfigurable own byteLength property
-    t.test('lies about byteLength', { skip: !('byteLength' in ArrayBuffer.prototype) }, function (s2t) {
-      const empty4 = new ArrayBuffer(4)
-      const empty6 = new ArrayBuffer(6)
-      Object.defineProperty(empty6, 'byteLength', { value: 4 })
-
-      unlikeLoosely(s2t,
-        empty4,
-        empty6,
-        'different-length ArrayBuffers, one lying'
-      )
-      s2t.end()
-    })
-
-    st.end()
-  })
-
-  t.test('SharedArrayBuffers', { skip: typeof SharedArrayBuffer !== 'function' }, function (st) {
-    const buffer1 = new SharedArrayBuffer(8) // initial value of 0's
-    const buffer2 = new SharedArrayBuffer(8) // initial value of 0's
-
-    const view1 = new Int8Array(buffer1)
-    const view2 = new Int8Array(buffer2)
-
-    alike(st,
-      view1,
-      view2,
-      'Int8Arrays of similar SharedArrayBuffers'
-    )
-
-    alike(st,
-      buffer1,
-      buffer2,
-      'similar SharedArrayBuffers'
-    )
-
-    for (let i = 0; i < view1.byteLength; i += 1) {
-      view1[i] = 9 // change all values to 9's
-    }
-
-    unlikeLoosely(st,
-      view1,
-      view2,
-      'Int8Arrays of different SharedArrayBuffers'
-    )
-
-    // +
-    /* unlikeLoosely(st,
-      buffer1,
-      buffer2,
-      'different SharedArrayBuffers'
-    ) */
-
-    // +
-    /* t.test('lies about byteLength', { skip: !('byteLength' in SharedArrayBuffer.prototype) }, function (s2t) {
-      const empty4 = new SharedArrayBuffer(4)
-      const empty6 = new SharedArrayBuffer(6)
-      Object.defineProperty(empty6, 'byteLength', { value: 4 })
-
-      unlikeLoosely(s2t,
-        empty4,
-        empty6,
-        'different-length SharedArrayBuffers, one lying'
-      )
-      s2t.end()
-    }) */
-
-    st.end()
-  })
-
-  t.end()
-})
-
-test('String object', function (t) {
-  alike(t,
-    new String('hi'), // eslint-disable-line no-new-wrappers
-    new String('hi'), // eslint-disable-line no-new-wrappers
-    'two same String objects'
-  )
-
-  unlike(t,
-    new String('hi'), // eslint-disable-line no-new-wrappers
-    new String('hi2'), // eslint-disable-line no-new-wrappers
-    'two different String objects'
-  )
-})
-
-test('Number object', function (t) {
-  alike(t,
-    new Number(1), // eslint-disable-line no-new-wrappers
-    new Number(1), // eslint-disable-line no-new-wrappers
-    'two same Number objects'
-  )
-
-  t.absent(sameObject(
-    new Number(1), // eslint-disable-line no-new-wrappers
-    new Number(2) // eslint-disable-line no-new-wrappers
-  ), 'two different Number objects')
-})
-
-test('Boolean object', function (t) {
-  alike(t,
-    new Boolean(true), // eslint-disable-line no-new-wrappers
-    new Boolean(true), // eslint-disable-line no-new-wrappers
-    'two same Boolean objects'
-  )
-
-  t.absent(sameObject(
-    new Boolean(true), // eslint-disable-line no-new-wrappers
-    new Boolean(false) // eslint-disable-line no-new-wrappers
-  ), 'two different Boolean objects')
-})
-
-test('objects', function (t) {
-  t.is(sameObject({ foo: 1 }, { foo: 1 }), true)
-  t.is(sameObject({ foo: 1 }, { foo: 1, bar: true }), false)
-  t.is(sameObject({ foo: 1, nested: { a: 1 } }, { foo: 1, nested: { a: 1 } }), true)
-  t.is(sameObject([{ a: 1 }, { b: 1 }], [{ a: 1 }, { b: 1 }]), true)
-})
-
-test('typed arrays', function (t) {
-  t.is(sameObject(new Uint8Array([1, 2, 3]), new Uint8Array([1, 2, 3])), true)
-  t.is(sameObject(new Uint8Array([1, 2, 1]), new Uint8Array([1, 2, 3])), false)
-})
-
-test('symbols', function (t) {
-  alike(t, Symbol.for('hello'), Symbol.for('hello'), 'same symbol', true, true)
-  unlike(t, Symbol.for('hello'), Symbol.for('holas'), 'diff symbol', false, true)
-
-  alike(t, [Symbol.for('hello')], [Symbol.for('hello')], 'symbol inside object', true, true)
-  alike(t, { sym: Symbol.for('hello') }, { sym: Symbol.for('hello') }, 'symbol inside object', true, true)
-
-  unlike(t, { sym: Symbol.for('hello') }, { sym: Symbol.for('holas') }, 'diff symbol inside object', false, true)
-})
-
-test('numbers', function (t) {
-  alike(t, BigInt('9007199254740991'), BigInt('9007199254740991'), 'BigInt', true, true)
-  alike(t, Infinity, Infinity, 'Infinity', true, true)
-
-  // Note: deep-equal library fails, but Node's assert version passes, so we follow Node standard
-  t.ok(sameObject(NaN, NaN, { strict: true }), 'NaN (alike)')
-  t.ok(sameObject(NaN, NaN, { strict: false }), 'NaN (alike loosely)')
-})
-
-// +
-test.skip('symbol as key', function (t) {
-  alike(t, { a: true, [Symbol.for('aa')]: true }, { a: true, [Symbol.for('aa')]: true })
-  unlike(t, { a: true, [Symbol.for('aa')]: true }, { a: true, [Symbol.for('cc')]: true })
-})
-
-test('promises', function (t) {
-  const promise = new Promise(noop)
-  alike(t, promise, promise, 'two promises with same reference')
-
-  // +
-  /* alike(t,
-    new Promise(noop),
-    new Promise(noop),
-    'two promises'
-  )
-
-  alike(t,
-    Promise.resolve('hi'),
-    Promise.resolve('hi'),
-    'resolve with same primitive'
-  )
-
-  unlike(t,
-    Promise.resolve('hi1'),
-    Promise.resolve('hi2'),
-    'resolve with different primitive'
-  )
-
-  alike(t,
-    Promise.resolve({ a: 1 }),
-    Promise.resolve({ a: 1 }),
-    'resolve with same objects'
-  )
-
-  unlike(t,
-    Promise.resolve({ a: 1 }),
-    Promise.resolve({ a: 2 }),
-    'resolve with different objects'
-  ) */
-
-  function noop (resolve, reject) {}
-})
-
-test('functions', function (t) {
-  unlike(t, function () {}, function () {}, 'two different functions', true, true)
-
-  const fn = function () {}
-  alike(t, fn, fn, 'two same functions', true, true)
-})
-
-// + merge this case with the other one
-test('circular references x2', function (t) {
-  const obj = { root: null }
-  obj.root = obj
-  const obj2 = { root: null }
-  obj2.root = obj2
-  alike(t, obj, obj2)
-
-  const obj3 = [{ root: null }]
-  obj3.root = obj3
-  const obj4 = [{ root: null }]
-  obj4.root = obj4
-  alike(t, obj3, obj4)
-
-  const obj5 = { sub: { root: null, sub2: { obj2, obj3 } } }
-  obj5.sub.root = obj5
-  const obj6 = { sub: { root: null, sub2: { obj2, obj3 } } }
-  obj6.sub.root = obj6
-  alike(t, obj5, obj6)
-
-  const obj7 = [{ root: null }]
-  obj7[0].root = obj7
-  const obj8 = [{ root: null }]
-  obj8[0].root = obj8
-  alike(t, obj7, obj8)
-
-  const o = {}
-  const obj9 = { a: o, b: o }
-  const o2 = {}
-  const obj10 = { a: o2, b: o2 }
-  alike(t, obj9, obj10)
-
-  const obj11 = [o, o]
-  const obj12 = [o, o]
-  alike(t, obj11, obj12)
-
-  const obj13 = [o, obj, o]
-  obj13.obj = obj
-  const obj14 = [o, obj, o]
-  obj14.obj = obj
-  alike(t, obj13, obj14)
-})
-
-function alike (t, a, b, comment = '') {
-  try {
-    t.ok(deepEqual(a, b, { strict: true }), '[deep-equal normal] ' + comment)
-    t.ok(deepEqual(b, a, { strict: true }), '[deep-equal reversed] ' + comment)
-  } catch (error) {
-    if (error.message === 'Cannot convert a Symbol value to a string') t.comment('alike => ' + error.message + ' [deep-equal] ' + comment)
-    else throw error
-  }
-
-  t.ok(sameObject(a, b, { strict: true }), '[same-object normal] ' + comment)
-  t.ok(sameObject(b, a, { strict: true }), '[same-object reversed] ' + comment)
-}
-
-function alikeLoosely (t, a, b, comment = '') { // eslint-disable-line no-unused-vars
-  try {
-    t.ok(deepEqual(a, b, { strict: false }), '[deep-equal normal] ' + comment)
-    t.ok(deepEqual(b, a, { strict: false }), '[deep-equal reversed] ' + comment)
-  } catch (error) {
-    if (error.message === 'Cannot convert a Symbol value to a string') t.comment('alike loosely => ' + error.message + ' [deep-equal] ' + comment)
-    else throw error
-  }
-
-  t.ok(sameObject(a, b, { strict: false }), '[same-object normal] ' + comment)
-  t.ok(sameObject(b, a, { strict: false }), '[same-object reversed] ' + comment)
-}
-
-function unlike (t, a, b, comment = '') {
-  try {
-    t.absent(deepEqual(a, b, { strict: true }), '[deep-equal normal] ' + comment)
-    t.absent(deepEqual(b, a, { strict: true }), '[deep-equal reversed] ' + comment)
-  } catch (error) {
-    if (error.message === 'Cannot convert a Symbol value to a string') t.comment('unlike => ' + error.message + ' [deep-equal] ' + comment)
-    else throw error
-  }
-
-  t.absent(sameObject(a, b, { strict: true }), '[same-object normal] ' + comment)
-  t.absent(sameObject(b, a, { strict: true }), '[same-object reversed] ' + comment)
-}
-
-function unlikeLoosely (t, a, b, comment = '') { // eslint-disable-line no-unused-vars
-  try {
-    t.absent(deepEqual(a, b, { strict: false }), '[deep-equal normal] ' + comment)
-    t.absent(deepEqual(b, a, { strict: false }), '[deep-equal reversed] ' + comment)
-  } catch (error) {
-    if (error.message === 'Cannot convert a Symbol value to a string') t.comment('unlike loosely => ' + error.message + ' [deep-equal] ' + comment)
-    else throw error
-  }
-
-  t.absent(sameObject(a, b, { strict: false }), '[same-object normal] ' + comment)
-  t.absent(sameObject(b, a, { strict: false }), '[same-object reversed] ' + comment)
-}
-
-function tag (obj, value) {
-  Object.defineProperty(obj, Symbol.toStringTag, { value })
-  return obj
-}
diff --git a/debian/tests/test_modules/test-tmp/LICENSE b/debian/tests/test_modules/test-tmp/LICENSE
deleted file mode 100644
index 2b42dab..0000000
--- a/debian/tests/test_modules/test-tmp/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2023 Mathias Buus
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/debian/tests/test_modules/test-tmp/README.md b/debian/tests/test_modules/test-tmp/README.md
deleted file mode 100644
index 766e569..0000000
--- a/debian/tests/test_modules/test-tmp/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# test-tmp
-
-Get a fresh tmpdir for tests
-
-```
-npm install test-tmp
-```
-
-## Usage
-
-``` js
-const test = require('brittle')
-const tmp = require('test-tmp')
-
-test('my test', async function (t) {
-  const dir = await tmp(t)
-  console.log('fresh dir for this test', dir)
-})
-```
-
-## License
-
-MIT
diff --git a/debian/tests/test_modules/test-tmp/index.js b/debian/tests/test_modules/test-tmp/index.js
deleted file mode 100644
index 7a015c8..0000000
--- a/debian/tests/test_modules/test-tmp/index.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const os = require('os')
-const path = require('path')
-const fs = require('fs')
-
-module.exports = tmp
-
-async function tmp (t, { dir = null, name = null, order = Infinity, force = true } = {}) {
-  if (!valid(name)) name = Math.random().toString(16).slice(2)
-
-  if (dir) {
-    await fs.promises.mkdir(dir, { recursive: true })
-  }
-
-  const tmpdir = path.join(await fs.promises.realpath(dir || os.tmpdir()), 'tmp-test-' + name)
-
-  try {
-    await gc(tmpdir)
-  } catch {}
-
-  await fs.promises.mkdir(tmpdir, { recursive: true })
-
-  if (t) t.teardown(gc, { order, force })
-  return tmpdir
-
-  async function gc () {
-    await fs.promises.rm(tmpdir, { recursive: true })
-  }
-
-  function valid (name) {
-    if (typeof name !== 'string') return false
-
-    const chars = /[<>:/\\|?*]/
-    const max = 64
-
-    return !chars.test(name) && name.length <= max
-  }
-}
diff --git a/debian/tests/test_modules/test-tmp/package.json b/debian/tests/test_modules/test-tmp/package.json
deleted file mode 100644
index 0654573..0000000
--- a/debian/tests/test_modules/test-tmp/package.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
-  "name": "test-tmp",
-  "version": "1.4.0",
-  "description": "Get a fresh tmpdir for tests",
-  "main": "index.js",
-  "imports": {
-    "os": {
-      "bare": "bare-os",
-      "default": "os"
-    },
-    "path": {
-      "bare": "bare-path",
-      "default": "path"
-    },
-    "fs": {
-      "bare": "bare-fs",
-      "default": "fs"
-    }
-  },
-  "scripts": {
-    "test": "standard && brittle test.js"
-  },
-  "devDependencies": {
-    "brittle": "^3.3.2",
-    "standard": "^17.1.0"
-  },
-  "repository": {
-    "type": "git",
-    "url": "https://github.com/mafintosh/test-tmp.git";
-  },
-  "author": "Mathias Buus (@mafintosh)",
-  "license": "MIT",
-  "bugs": {
-    "url": "https://github.com/mafintosh/test-tmp/issues";
-  },
-  "homepage": "https://github.com/mafintosh/test-tmp";,
-  "dependencies": {
-    "bare-fs": "^4.0.1",
-    "bare-os": "^3.3.0",
-    "bare-path": "^3.0.0"
-  }
-}
diff --git a/debian/tests/test_modules/test-tmp/test.js b/debian/tests/test_modules/test-tmp/test.js
deleted file mode 100644
index 0e768a1..0000000
--- a/debian/tests/test_modules/test-tmp/test.js
+++ /dev/null
@@ -1,47 +0,0 @@
-const test = require('brittle')
-const tmp = require('./')
-const fs = require('fs')
-const os = require('os')
-const path = require('path')
-
-test('basic', async function (t) {
-  const dir = await tmp(t)
-
-  t.alike(await fs.promises.readdir(dir), [])
-})
-
-test('specified name', async function (t) {
-  const name = 'testdir'
-  const dir = await tmp(t, { name })
-  t.ok(dir.includes(name), 'directory contains specified name')
-  t.alike(await fs.promises.readdir(dir), [])
-})
-
-test('invalid directory name', async function (t) {
-  const name = '<>:/\\|?*'
-  try {
-    await tmp(t, { name })
-    t.pass('should default to a random name when an invalid input is provided')
-  } catch (error) {
-    t.fail('expected to handle an invalid directory name')
-  }
-})
-
-test('reuse directory', async function (t) {
-  const name = 'existing-dir'
-  const existing = path.join(await fs.promises.realpath(os.tmpdir()), 'tmp-test-' + name)
-
-  await fs.promises.mkdir(existing, { recursive: true })
-
-  const dir = await tmp(t, { name })
-  t.is(dir, existing, 'uses the existing directory when it already exists')
-})
-
-test('specify root directory', async function (t) {
-  const dir = await tmp(t, { dir: './tmp-storage' })
-
-  const children = await fs.promises.readdir('./tmp-storage')
-  t.is(children.length, 1)
-
-  t.alike(await fs.promises.readdir(dir), [])
-})
diff --git a/index.js b/index.js
index f1e1a6a..5df3665 100644
--- a/index.js
+++ b/index.js
@@ -164,23 +164,23 @@ exports.extract = function extract (cwd, opts) {
       return next()
     }
 
-    if (header.type === 'directory') {
-      stack.push([name, header.mtime])
-      return mkdirfix(name, {
-        fs: xfs,
-        own,
-        uid: header.uid,
-        gid: header.gid,
-        mode: header.mode
-      }, stat)
-    }
-
-    const dir = path.dirname(name)
+    const dir = path.join(name, '.') === path.join(cwd, '.') ? cwd : path.dirname(name)
 
     validate(xfs, dir, path.join(cwd, '.'), function (err, valid) {
       if (err) return next(err)
       if (!valid) return next(new Error(dir + ' is not a valid path'))
 
+      if (header.type === 'directory') {
+        stack.push([name, header.mtime])
+        return mkdirfix(name, {
+          fs: xfs,
+          own,
+          uid: header.uid,
+          gid: header.gid,
+          mode: header.mode
+        }, stat)
+      }
+
       mkdirfix(dir, {
         fs: xfs,
         own,
@@ -228,15 +228,19 @@ exports.extract = function extract (cwd, opts) {
     function onlink () {
       if (win32) return next() // skip links on win for now before it can be tested
       xfs.unlink(name, function () {
-        const dst = path.join(cwd, path.join('/', header.linkname))
+        const link = path.join(cwd, path.join('/', header.linkname))
 
-        xfs.link(dst, name, function (err) {
-          if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {
-            stream = xfs.createReadStream(dst)
-            return onfile()
-          }
+        fs.realpath(link, function (err, dst) {
+          if (err || !inCwd(dst)) return next(new Error(name + ' is not a valid hardlink'))
 
-          stat(err)
+          xfs.link(dst, name, function (err) {
+            if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {
+              stream = xfs.createReadStream(dst)
+              return onfile()
+            }
+
+            stat(err)
+          })
         })
       })
     }
@@ -317,10 +321,11 @@ exports.extract = function extract (cwd, opts) {
 
 function validate (fs, name, root, cb) {
   if (name === root) return cb(null, true)
+
   fs.lstat(name, function (err, st) {
-    if (err && err.code === 'ENOENT') return validate(fs, path.join(name, '..'), root, cb)
-    else if (err) return cb(err)
-    cb(null, st.isDirectory())
+    if (err && err.code !== 'ENOENT' && err.code !== 'EPERM') return cb(err)
+    if (err || st.isDirectory()) return validate(fs, path.join(name, '..'), root, cb)
+    cb(null, false)
   })
 }
 
diff --git a/package.json b/package.json
index 6668d68..16c8a0c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "tar-fs",
-  "version": "3.0.8",
+  "version": "3.0.9",
   "description": "filesystem bindings for tar-stream",
   "dependencies": {
     "pump": "^3.0.0",
diff --git a/debian/changelog b/debian/changelog
index b01fb20..a93913e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+node-tar-fs (3.0.9+~cs2.0.4-1) unstable; urgency=medium
+
+  * Team upload
+  * Keep previous test from 2.1.1 with tape
+  * New upstream version (Closes: CVE-2025-48387)
+
+ -- Yadd <yadd@debian.org>  Tue, 03 Jun 2025 17:33:46 +0200
+
 node-tar-fs (3.0.8+~cs2.0.4-1) unstable; urgency=medium
 
diff --git a/index.js b/index.js
index f1e1a6a..5df3665 100644
--- a/index.js
+++ b/index.js
@@ -164,23 +164,23 @@ exports.extract = function extract (cwd, opts) {
       return next()
     }
 
-    if (header.type === 'directory') {
-      stack.push([name, header.mtime])
-      return mkdirfix(name, {
-        fs: xfs,
-        own,
-        uid: header.uid,
-        gid: header.gid,
-        mode: header.mode
-      }, stat)
-    }
-
-    const dir = path.dirname(name)
+    const dir = path.join(name, '.') === path.join(cwd, '.') ? cwd : path.dirname(name)
 
     validate(xfs, dir, path.join(cwd, '.'), function (err, valid) {
       if (err) return next(err)
       if (!valid) return next(new Error(dir + ' is not a valid path'))
 
+      if (header.type === 'directory') {
+        stack.push([name, header.mtime])
+        return mkdirfix(name, {
+          fs: xfs,
+          own,
+          uid: header.uid,
+          gid: header.gid,
+          mode: header.mode
+        }, stat)
+      }
+
       mkdirfix(dir, {
         fs: xfs,
         own,
@@ -228,15 +228,19 @@ exports.extract = function extract (cwd, opts) {
     function onlink () {
       if (win32) return next() // skip links on win for now before it can be tested
       xfs.unlink(name, function () {
-        const dst = path.join(cwd, path.join('/', header.linkname))
+        const link = path.join(cwd, path.join('/', header.linkname))
 
-        xfs.link(dst, name, function (err) {
-          if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {
-            stream = xfs.createReadStream(dst)
-            return onfile()
-          }
+        fs.realpath(link, function (err, dst) {
+          if (err || !inCwd(dst)) return next(new Error(name + ' is not a valid hardlink'))
 
-          stat(err)
+          xfs.link(dst, name, function (err) {
+            if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {
+              stream = xfs.createReadStream(dst)
+              return onfile()
+            }
+
+            stat(err)
+          })
         })
       })
     }
@@ -317,10 +321,11 @@ exports.extract = function extract (cwd, opts) {
 
 function validate (fs, name, root, cb) {
   if (name === root) return cb(null, true)
+
   fs.lstat(name, function (err, st) {
-    if (err && err.code === 'ENOENT') return validate(fs, path.join(name, '..'), root, cb)
-    else if (err) return cb(err)
-    cb(null, st.isDirectory())
+    if (err && err.code !== 'ENOENT' && err.code !== 'EPERM') return cb(err)
+    if (err || st.isDirectory()) return validate(fs, path.join(name, '..'), root, cb)
+    cb(null, false)
   })
 }
 
diff --git a/package.json b/package.json
index 6668d68..16c8a0c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "tar-fs",
-  "version": "3.0.8",
+  "version": "3.0.9",
   "description": "filesystem bindings for tar-stream",
   "dependencies": {
     "pump": "^3.0.0",

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply to: