Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion builtins/web/text-codec/text-decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ bool TextDecoder::decode(JSContext *cx, unsigned argc, JS::Value *vp) {
}

bool stream = false;
if (args.hasDefined(1)) {
// `options` is a WebIDL dictionary: `null` (like `undefined`) means use the
// defaults, matching how the constructor treats it.
if (args.hasDefined(1) && !args.get(1).isNull()) {
auto options_value = args.get(1);
if (!options_value.isObject()) {
return api::throw_error(cx, api::Errors::TypeError, "TextDecoder.decode",
Expand Down
7 changes: 5 additions & 2 deletions builtins/web/url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,11 @@ jsurl::SpecSlice URLSearchParams::serialize(JSContext *cx, JS::HandleObject self

bool URLSearchParams::append(JSContext *cx, unsigned argc, JS::Value *vp) {
METHOD_HEADER(2)
auto value = validate(cx, args[0], "append");
if (!append_impl(cx, self, value, args[1], "append")) {
auto name = validate(cx, args[0], "append");
if (!name.data) {
return false;
}
if (!append_impl(cx, self, name, args[1], "append")) {
return false;
}

Expand Down
2 changes: 2 additions & 0 deletions tests/integration/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export { handler as crypto } from './crypto/crypto.js';
export { handler as timers } from './timers/timers.js';
export { handler as fetch } from './fetch/fetch.js';
export { handler as event } from './event/event.js';
export { handler as urlsearchparams } from './urlsearchparams/urlsearchparams.js';
export { handler as textdecoder } from './textdecoder/textdecoder.js';
30 changes: 30 additions & 0 deletions tests/integration/textdecoder/textdecoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { serveTest } from "../test-server.js";
import { strictEqual, throws } from "../../assert.js";

const AB = new Uint8Array([0x61, 0x62]); // "ab"

export const handler = serveTest(async (t) => {
await t.test("decode-options-null-uses-defaults", () => {
// `options` is a WebIDL dictionary: null means defaults, not a type error.
strictEqual(new TextDecoder().decode(AB, null), "ab", "null options decode");
});

await t.test("decode-options-undefined-and-omitted", () => {
strictEqual(new TextDecoder().decode(AB, undefined), "ab", "undefined options");
strictEqual(new TextDecoder().decode(AB), "ab", "omitted options");
});

await t.test("decode-options-object", () => {
strictEqual(new TextDecoder().decode(AB, { stream: false }), "ab", "object options");
});

await t.test("decode-options-non-object-still-throws", () => {
// A defined, non-null, non-object value is still a TypeError.
throws(() => new TextDecoder().decode(AB, "nope"), TypeError);
throws(() => new TextDecoder().decode(AB, 42), TypeError);
});

await t.test("constructor-options-null-uses-defaults", () => {
strictEqual(new TextDecoder("utf-8", null).decode(AB), "ab", "ctor null options");
});
});
36 changes: 36 additions & 0 deletions tests/integration/urlsearchparams/urlsearchparams.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { serveTest } from "../test-server.js";
import { strictEqual, throws } from "../../assert.js";

export const handler = serveTest(async (t) => {
await t.test("append-symbol-name-throws-and-does-not-mutate", () => {
const p = new URLSearchParams("a=1");
// A Symbol cannot be converted to a string: append must throw a TypeError
// and leave the params untouched (not append a bogus empty-name entry).
throws(() => p.append(Symbol("s"), "x"), TypeError);
strictEqual(p.toString(), "a=1", "params unchanged after throwing append");
});

await t.test("append-throwing-tostring-name-propagates", () => {
const p = new URLSearchParams();
const bad = {
toString() {
throw new Error("boom");
},
};
throws(() => p.append(bad, "v"), Error, "boom");
strictEqual(p.toString(), "", "params unchanged after throwing toString");
});

await t.test("append-symbol-name-does-not-corrupt-attached-url", () => {
const u = new URL("http://example.com/?a=1");
throws(() => u.searchParams.append(Symbol("s"), "x"), TypeError);
strictEqual(u.href, "http://example.com/?a=1", "url href unchanged");
});

await t.test("append-normal-still-works", () => {
const p = new URLSearchParams("a=1");
p.append("b", "2");
p.append(3, 4); // non-string coercible values are fine
strictEqual(p.toString(), "a=1&b=2&3=4", "valid appends work");
});
});
2 changes: 2 additions & 0 deletions tests/tests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,7 @@ integration_tests(
event
fetch
performance
textdecoder
timers
urlsearchparams
)
Loading