Skip to content

Commit cf26e0a

Browse files
committed
Add some unit tests for unarchivers. Provide a way to disconnect the impl from the host (for unit tests).
1 parent eba7042 commit cf26e0a

17 files changed

+211
-13
lines changed

archive/common.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,22 @@
1010

1111
// Requires the following JavaScript features: MessageChannel, MessagePort, and dynamic imports.
1212

13+
/**
14+
* @typedef Implementation
15+
* @property {MessagePort} hostPort The port the host uses to communicate with the implementation.
16+
* @property {Function} disconnectFn A function to call when the port has been disconnected.
17+
*/
18+
1319
/**
1420
* Connects a host to a compress/decompress implementation via MessagePorts. The implementation must
1521
* have an exported connect() function that accepts a MessagePort. If the runtime support Workers
1622
* (e.g. web browsers, deno), imports the implementation inside a Web Worker. Otherwise, it
1723
* dynamically imports the implementation inside the current JS context (node, bun).
1824
* @param {string} implFilename The compressor/decompressor implementation filename relative to this
1925
* path (e.g. './unzip.js').
20-
* @returns {Promise<MessagePort>} The Promise resolves to the MessagePort connected to the
21-
* implementation that the host should use.
26+
* @param {Function} disconnectFn A function to run when the port is disconnected.
27+
* @returns {Promise<Implementation>} The Promise resolves to the Implementation, which includes the
28+
* MessagePort connected to the implementation that the host should use.
2229
*/
2330
export async function getConnectedPort(implFilename) {
2431
const messageChannel = new MessageChannel();
@@ -28,13 +35,19 @@ export async function getConnectedPort(implFilename) {
2835
if (typeof Worker === 'undefined') {
2936
const implModule = await import(`${implFilename}`);
3037
await implModule.connect(implPort);
31-
return hostPort;
38+
return {
39+
hostPort,
40+
disconnectFn: () => implModule.disconnect(),
41+
};
3242
}
3343

3444
return new Promise((resolve, reject) => {
3545
const workerScriptPath = new URL(`./webworker-wrapper.js`, import.meta.url).href;
3646
const worker = new Worker(workerScriptPath, { type: 'module' });
3747
worker.postMessage({ implSrc: implFilename }, [implPort]);
38-
resolve(hostPort);
48+
resolve({
49+
hostPort,
50+
disconnectFn: () => worker.postMessage({ disconnect: true }),
51+
});
3952
});
4053
}

archive/decompress.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ export class Unarchiver extends EventTarget {
5656
*/
5757
port_;
5858

59+
/**
60+
* A function to call to disconnect the implementation from the host.
61+
* @type {Function}
62+
* @private
63+
*/
64+
disconnectFn_;
65+
5966
/**
6067
* @param {ArrayBuffer} arrayBuffer The Array Buffer. Note that this ArrayBuffer must not be
6168
* referenced once it is sent to the Unarchiver, since it is marked as Transferable and sent
@@ -87,6 +94,16 @@ export class Unarchiver extends EventTarget {
8794
this.debugMode_ = !!(options.debug);
8895
}
8996

97+
/**
98+
* Overridden so that the type hints for eventType are specific.
99+
* @param {'progress'|'extract'|'finish'} eventType
100+
* @param {EventListenerOrEventListenerObject} listener
101+
* @override
102+
*/
103+
addEventListener(eventType, listener) {
104+
super.addEventListener(eventType, listener);
105+
}
106+
90107
/**
91108
* This method must be overridden by the subclass to return the script filename.
92109
* @returns {string} The MIME type of the archive.
@@ -164,7 +181,9 @@ export class Unarchiver extends EventTarget {
164181
* using the update() method.
165182
*/
166183
async start() {
167-
this.port_ = await getConnectedPort(this.getScriptFileName());
184+
const impl = await getConnectedPort(this.getScriptFileName());
185+
this.port_ = impl.hostPort;
186+
this.disconnectFn_ = impl.disconnectFn;
168187
return new Promise((resolve, reject) => {
169188
this.port_.onerror = (evt) => {
170189
console.log('Impl error: message = ' + evt.message);
@@ -221,7 +240,9 @@ export class Unarchiver extends EventTarget {
221240
stop() {
222241
if (this.port_) {
223242
this.port_.close();
243+
this.disconnectFn_();
224244
this.port_ = null;
245+
this.disconnectFn_ = null;
225246
}
226247
}
227248
}

archive/unrar.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1466,8 +1466,28 @@ const onmessage = function (event) {
14661466
*/
14671467
export function connect(port) {
14681468
if (hostPort) {
1469-
throw `hostPort already connected`;
1469+
throw `hostPort already connected in unrar.js`;
14701470
}
14711471
hostPort = port;
14721472
port.onmessage = onmessage;
14731473
}
1474+
1475+
export function disconnect() {
1476+
if (!hostPort) {
1477+
throw `hostPort was not connected in unzip.js`;
1478+
}
1479+
1480+
hostPort = null;
1481+
1482+
unarchiveState = UnarchiveState.NOT_STARTED;
1483+
bytestream = null;
1484+
allLocalFiles = null;
1485+
logToConsole = false;
1486+
1487+
currentFilename = '';
1488+
currentFileNumber = 0;
1489+
currentBytesUnarchivedInFile = 0;
1490+
currentBytesUnarchived = 0;
1491+
totalUncompressedBytesInArchive = 0;
1492+
totalFilesInArchive = 0;
1493+
}

archive/untar.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,28 @@ const onmessage = function (event) {
221221
*/
222222
export function connect(port) {
223223
if (hostPort) {
224-
throw `hostPort already connected`;
224+
throw `hostPort already connected in untar.js`;
225225
}
226226
hostPort = port;
227227
port.onmessage = onmessage;
228228
}
229+
230+
export function disconnect() {
231+
if (!hostPort) {
232+
throw `hostPort was not connected in unzip.js`;
233+
}
234+
235+
hostPort = null;
236+
237+
unarchiveState = UnarchiveState.NOT_STARTED;
238+
bytestream = null;
239+
allLocalFiles = null;
240+
logToConsole = false;
241+
242+
currentFilename = '';
243+
currentFileNumber = 0;
244+
currentBytesUnarchivedInFile = 0;
245+
currentBytesUnarchived = 0;
246+
totalUncompressedBytesInArchive = 0;
247+
totalFilesInArchive = 0;
248+
}

archive/unzip.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,8 +781,30 @@ const onmessage = function (event) {
781781
*/
782782
export function connect(port) {
783783
if (hostPort) {
784-
throw `hostPort already connected`;
784+
throw `hostPort already connected in unzip.js`;
785785
}
786+
786787
hostPort = port;
787788
port.onmessage = onmessage;
788789
}
790+
791+
export function disconnect() {
792+
if (!hostPort) {
793+
throw `hostPort was not connected in unzip.js`;
794+
}
795+
796+
hostPort = null;
797+
798+
unarchiveState = UnarchiveState.NOT_STARTED;
799+
bytestream = null;
800+
allLocalFiles = null;
801+
logToConsole = false;
802+
803+
// Progress variables.
804+
currentFilename = '';
805+
currentFileNumber = 0;
806+
currentBytesUnarchivedInFile = 0;
807+
currentBytesUnarchived = 0;
808+
totalUncompressedBytesInArchive = 0;
809+
totalFilesInArchive = 0;
810+
}

archive/webworker-wrapper.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
let implPort;
1717

1818
onmessage = async (evt) => {
19-
const module = await import(evt.data.implSrc);
20-
module.connect(evt.ports[0]);
19+
if (evt.data.implSrc) {
20+
const module = await import(evt.data.implSrc);
21+
module.connect(evt.ports[0]);
22+
} else if (evt.data.disconnect) {
23+
module.disconnect();
24+
}
2125
};

archive/zip.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ const CompressorState = {
8080
FINISHED: 3,
8181
};
8282
let state = CompressorState.NOT_STARTED;
83-
let lastFileReceived = false;
8483
const crc32Table = createCRC32Table();
8584

8685
/** Helper functions. */
@@ -280,8 +279,21 @@ const onmessage = function(evt) {
280279
*/
281280
export function connect(port) {
282281
if (hostPort) {
283-
throw `hostPort already connected`;
282+
throw `hostPort already connected in zip.js`;
284283
}
285284
hostPort = port;
286285
port.onmessage = onmessage;
287286
}
287+
288+
export function disconnect() {
289+
if (!hostPort) {
290+
throw `hostPort was not connected in unzip.js`;
291+
}
292+
293+
hostPort = null;
294+
295+
centralDirectoryInfos = [];
296+
numBytesWritten = 0;
297+
state = CompressorState.NOT_STARTED;
298+
lastFileReceived = false;
299+
}

io/bytestream.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export class ByteStream {
2222
*/
2323
constructor(ab, opt_offset, opt_length) {
2424
if (!(ab instanceof ArrayBuffer)) {
25-
console.error(typeof ab);
2625
throw 'Error! ByteStream constructed with an invalid ArrayBuffer object';
2726
}
2827

506 Bytes
Binary file not shown.
4.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)