expand shim coverage, additional fs shims, add light stream shim

This commit is contained in:
Nystik
2026-06-07 12:51:27 +02:00
parent 35348093a6
commit c3a9d511b2
16 changed files with 684 additions and 1 deletions

View File

@@ -0,0 +1,82 @@
class AssertionError extends Error {
constructor(message) {
super(message || "Assertion failed");
this.name = "AssertionError";
}
}
function assert(value, message) {
if (!value) {
throw new AssertionError(message);
}
}
assert.AssertionError = AssertionError;
assert.ok = assert;
assert.strict = assert;
assert.fail = function (message) {
throw new AssertionError(message || "Failed");
};
assert.equal = function (actual, expected, message) {
if (actual != expected) {
throw new AssertionError(message || `${actual} == ${expected}`);
}
};
assert.notEqual = function (actual, expected, message) {
if (actual == expected) {
throw new AssertionError(message || `${actual} != ${expected}`);
}
};
assert.strictEqual = function (actual, expected, message) {
if (actual !== expected) {
throw new AssertionError(message || `${actual} === ${expected}`);
}
};
assert.notStrictEqual = function (actual, expected, message) {
if (actual === expected) {
throw new AssertionError(message || `${actual} !== ${expected}`);
}
};
assert.deepEqual = function (actual, expected, message) {
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
throw new AssertionError(message || "deepEqual");
}
};
assert.deepStrictEqual = assert.deepEqual;
assert.throws = function (fn, message) {
let threw = false;
try {
fn();
} catch {
threw = true;
}
if (!threw) {
throw new AssertionError(message || "Missing expected exception");
}
};
assert.doesNotThrow = function (fn, message) {
try {
fn();
} catch (e) {
throw new AssertionError(message || `Got unwanted exception: ${e.message}`);
}
};
assert.ifError = function (value) {
if (value) {
throw new AssertionError(`ifError got unwanted exception: ${value}`);
}
};
export const assertShim = assert;

View File

@@ -0,0 +1,30 @@
import { describe, it, expect } from "vitest";
import { assertShim as assert } from "./assert.js";
describe("assert shim", () => {
it("is callable and throws on a falsy value", () => {
expect(() => assert(false)).toThrow();
expect(() => assert(true)).not.toThrow();
});
it("equal throws on mismatch and passes on loose match", () => {
expect(() => assert.equal(1, 2)).toThrow();
expect(() => assert.equal(1, 1)).not.toThrow();
expect(() => assert.equal(1, "1")).not.toThrow();
});
it("strictEqual distinguishes type", () => {
expect(() => assert.strictEqual(1, "1")).toThrow();
expect(() => assert.strictEqual(1, 1)).not.toThrow();
});
it("throws() verifies that a function threw", () => {
expect(() =>
assert.throws(() => {
throw new Error("x");
}),
).not.toThrow();
expect(() => assert.throws(() => {})).toThrow();
});
});

View File

@@ -0,0 +1,50 @@
// Linux constant values, to match the platform the process shim reports.
// O_SYMLINK and other macOS/BSD flags are omitted so feature checks treat platform as linux
export const constantsShim = {
// File access checks (fs.access mode).
F_OK: 0,
X_OK: 1,
W_OK: 2,
R_OK: 4,
// open() flags.
O_RDONLY: 0,
O_WRONLY: 1,
O_RDWR: 2,
O_CREAT: 64,
O_EXCL: 128,
O_NOCTTY: 256,
O_TRUNC: 512,
O_APPEND: 1024,
O_DIRECTORY: 65536,
O_NOATIME: 262144,
O_NOFOLLOW: 131072,
O_SYNC: 1052672,
O_DSYNC: 4096,
O_NONBLOCK: 2048,
// File type bits (st_mode & S_IFMT).
S_IFMT: 61440,
S_IFREG: 32768,
S_IFDIR: 16384,
S_IFCHR: 8192,
S_IFBLK: 24576,
S_IFIFO: 4096,
S_IFLNK: 40960,
S_IFSOCK: 49152,
// Permission bits.
S_IRWXU: 448,
S_IRUSR: 256,
S_IWUSR: 128,
S_IXUSR: 64,
S_IRWXG: 56,
S_IRGRP: 32,
S_IWGRP: 16,
S_IXGRP: 8,
S_IRWXO: 7,
S_IROTH: 4,
S_IWOTH: 2,
S_IXOTH: 1,
};

View File

@@ -0,0 +1,85 @@
import { EventEmitter } from "./events.js";
let warned = false;
function warnNoDataFlow(method) {
if (warned) {
return;
}
warned = true;
console.warn(
`[shim:stream] ${method}() called, but stream data flow is not implemented. ` +
"This plugin needs the full stream shim.",
);
}
export class Stream extends EventEmitter {
pipe(destination) {
warnNoDataFlow("pipe");
return destination;
}
}
export class Readable extends Stream {
constructor(options) {
super();
this.readable = true;
this._readableState = { options: options || {} };
}
read() {
warnNoDataFlow("read");
return null;
}
push() {
warnNoDataFlow("push");
return false;
}
_read() {}
}
export class Writable extends Stream {
constructor(options) {
super();
this.writable = true;
this._writableState = { options: options || {} };
}
write() {
warnNoDataFlow("write");
return false;
}
end() {
warnNoDataFlow("end");
return this;
}
_write() {}
}
export class Duplex extends Readable {
constructor(options) {
super(options);
this.writable = true;
}
write() {
warnNoDataFlow("write");
return false;
}
end() {
warnNoDataFlow("end");
return this;
}
}
export class Transform extends Duplex {
_transform() {}
}
export class PassThrough extends Transform {}

View File

@@ -0,0 +1,16 @@
import { describe, it, expect, vi } from "vitest";
import { Readable, Writable } from "./stream.js";
describe("stream shim", () => {
it("warns once when data-flow methods are used", () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
new Readable().read();
new Writable().write("x");
expect(warn).toHaveBeenCalledTimes(1);
expect(warn.mock.calls[0][0]).toContain("[shim:stream]");
warn.mockRestore();
});
});