[Pkg-javascript-devel] Bug#1108872: unblock: node-tar-fs/3.0.9+~cs2.0.4-1

Yadd yadd at debian.org
Sun Jul 6 16:23:19 BST 2025


Package: release.debian.org
Severity: normal
X-Debbugs-Cc: node-tar-fs at packages.debian.org, carnil at debian.org, yadd at debian.org
Control: affects -1 + src:node-tar-fs
User: release.debian.org at 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
-------------- next part --------------
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 at 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 at 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 at 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",
-------------- next part --------------
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 at 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",


More information about the Pkg-javascript-devel mailing list