From d409137e4c24db62a2c87a62def22e156e73978d Mon Sep 17 00:00:00 2001 From: minghuaw Date: Fri, 15 Aug 2025 15:57:00 +0800 Subject: [PATCH] Script: Implement `TextEncoderStream` (#38466) This implements the `TextEncoderStream` WebIDL interface. Testing: Existing WPT tests should be sufficient Fixes: #37724 --------- Signed-off-by: minghuaw --- components/malloc_size_of/lib.rs | 1 + components/script/dom/mod.rs | 1 + components/script/dom/textencoderstream.rs | 390 ++++++++++++++++++ .../dom/transformstreamdefaultcontroller.rs | 60 +++ .../webidls/TextEncoderStream.webidl | 15 + tests/wpt/meta/encoding/idlharness.any.js.ini | 42 -- .../encoding/streams/backpressure.any.js.ini | 12 - .../streams/encode-bad-chunks.any.js.ini | 35 -- .../encoding/streams/encode-utf8.any.js.ini | 113 ----- .../streams/invalid-realm.window.js.ini | 6 - .../readable-writable-properties.any.js.ini | 6 - .../encoding/streams/realms.window.js.ini | 6 - .../streams/stringification-crash.html.ini | 2 - .../fetch-event.https.h2.html.ini | 9 +- tests/wpt/mozilla/meta/MANIFEST.json | 4 +- .../tests/mozilla/interfaces.https.html | 1 + .../tests/mozilla/interfaces.worker.js | 1 + 17 files changed, 476 insertions(+), 228 deletions(-) create mode 100644 components/script/dom/textencoderstream.rs create mode 100644 components/script_bindings/webidls/TextEncoderStream.webidl delete mode 100644 tests/wpt/meta/encoding/streams/invalid-realm.window.js.ini delete mode 100644 tests/wpt/meta/encoding/streams/stringification-crash.html.ini diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs index abd032dfae6..e156b2ceb5c 100644 --- a/components/malloc_size_of/lib.rs +++ b/components/malloc_size_of/lib.rs @@ -775,6 +775,7 @@ malloc_size_of_is_0!(http::StatusCode); malloc_size_of_is_0!(app_units::Au); malloc_size_of_is_0!(keyboard_types::Modifiers); malloc_size_of_is_0!(mime::Mime); +malloc_size_of_is_0!(std::num::NonZeroU16); malloc_size_of_is_0!(std::num::NonZeroU64); malloc_size_of_is_0!(std::num::NonZeroUsize); malloc_size_of_is_0!(std::sync::atomic::AtomicBool); diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index bc72e651793..be62ba38dc6 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -599,6 +599,7 @@ pub(crate) mod textdecoder; pub(crate) mod textdecodercommon; pub(crate) mod textdecoderstream; pub(crate) mod textencoder; +pub(crate) mod textencoderstream; pub(crate) mod textmetrics; pub(crate) mod texttrack; pub(crate) mod texttrackcue; diff --git a/components/script/dom/textencoderstream.rs b/components/script/dom/textencoderstream.rs new file mode 100644 index 00000000000..2bfa31b65a9 --- /dev/null +++ b/components/script/dom/textencoderstream.rs @@ -0,0 +1,390 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::cell::Cell; +use std::num::{NonZero, NonZeroU16}; +use std::ptr::{self, NonNull}; + +use dom_struct::dom_struct; +use js::conversions::latin1_to_string; +use js::jsapi::{ + JS_DeprecatedStringHasLatin1Chars, JS_GetTwoByteStringCharsAndLength, JS_IsExceptionPending, + JSObject, JSType, ToPrimitive, +}; +use js::jsval::UndefinedValue; +use js::rust::{ + HandleObject as SafeHandleObject, HandleValue as SafeHandleValue, + MutableHandleValue as SafeMutableHandleValue, ToString, +}; +use js::typedarray::Uint8Array; +use script_bindings::conversions::SafeToJSValConvertible; + +use crate::dom::bindings::buffer_source::create_buffer_source; +use crate::dom::bindings::codegen::Bindings::TextEncoderStreamBinding::TextEncoderStreamMethods; +use crate::dom::bindings::error::{Error, Fallible, throw_dom_exception}; +use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::str::DOMString; +use crate::dom::transformstreamdefaultcontroller::TransformerType; +use crate::dom::types::{GlobalScope, TransformStream, TransformStreamDefaultController}; +use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; +use crate::{DomTypeHolder, DomTypes}; + +/// String converted from an input JS Value +enum ConvertedInput<'a> { + String(String), + CodeUnits(&'a [u16]), +} + +/// Converts a JS value to primitive type so that it can be used with +/// `ToString`. +/// +/// Set `rval` to `chunk` if `chunk` is a primitive JS value. Otherwise, convert +/// `chunk` into a primitive JS value and then set `rval` to the converted +/// primitive. This follows the `ToString` procedure with the exception that it +/// does not convert the value to string. +/// +/// See below for the `ToString` procedure in spec: +/// +#[allow(unsafe_code)] +fn jsval_to_primitive( + cx: SafeJSContext, + global: &GlobalScope, + chunk: SafeHandleValue, + mut rval: SafeMutableHandleValue, + can_gc: CanGc, +) -> Fallible<()> { + // Step 1. If argument is a String, return argument. + // Step 2. If argument is a Symbol, throw a TypeError exception. + // Step 3. If argument is undefined, return "undefined". + // Step 4. If argument is null, return "null". + // Step 5. If argument is true, return "true". + // Step 6. If argument is false, return "false". + // Step 7. If argument is a Number, return Number::toString(argument, 10). + // Step 8. If argument is a BigInt, return BigInt::toString(argument, 10). + if chunk.is_primitive() { + rval.set(chunk.get()); + + return Ok(()); + } + + // Step 9. Assert: argument is an Object. + assert!(chunk.is_object()); + + // Step 10. Let primValue be ? ToPrimitive(argument, string). + rooted!(in(*cx) let obj = chunk.to_object()); + let is_success = + unsafe { ToPrimitive(*cx, obj.handle().into(), JSType::JSTYPE_STRING, rval.into()) }; + log::debug!("ToPrimitive is_success={:?}", is_success); + if !is_success { + unsafe { + if !JS_IsExceptionPending(*cx) { + throw_dom_exception( + cx, + global, + Error::Type("Cannot convert JSObject to primitive".to_owned()), + can_gc, + ); + } + } + return Err(Error::JSFailed); + } + + Ok(()) +} + +/// +#[derive(Default, JSTraceable, MallocSizeOf)] +pub(crate) struct Encoder { + /// + leading_surrogate: Cell>, +} + +impl Encoder { + fn encode(&self, maybe_ill_formed: ConvertedInput<'_>) -> String { + match maybe_ill_formed { + ConvertedInput::String(s) => { + // Rust String is already UTF-8 encoded and cannot contain + // surrogate + if !s.is_empty() && self.leading_surrogate.take().is_some() { + let mut output = String::with_capacity(1 + s.len()); + output.push('\u{FFFD}'); + output.push_str(&s); + return output; + } + + s + }, + ConvertedInput::CodeUnits(code_units) => self.encode_from_code_units(code_units), + } + } + + /// Encode an input slice of code unit into unicode scalar values + #[allow(unsafe_code)] + fn encode_from_code_units(&self, input: &[u16]) -> String { + // + // + // Step 3. Let output be the I/O queue of bytes « end-of-queue ». + let mut output = String::with_capacity(input.len()); + // Step 4. While true: + // Step 4.1 Let item be the result of reading from input. + for result in char::decode_utf16(input.iter().cloned()) { + // Step 4.3 Let result be the result of executing the convert code unit + // to scalar value algorithm with encoder, item and input. + + // + match result { + Ok(c) => { + // Step 1. If encoder’s leading surrogate is non-null: + // Step 1.1 Let leadingSurrogate be encoder’s leading surrogate. + // Step 1.2 Set encoder’s leading surrogate to null. + if self.leading_surrogate.take().is_some() { + // Step 1.5 Return U+FFFD (�). + output.push('\u{FFFD}'); + } + + // Step 1.4 Restore item to input. + // Note: pushing item to output is equivalent to restoring item to input + // and rerun the convert-code-unit-to-scalar-value algo + output.push(c); + }, + Err(error) => { + let unpaired_surrogate = error.unpaired_surrogate(); + match code_point_type(unpaired_surrogate) { + CodePointType::LeadingSurrogate => { + // Step 1.1 If encoder’s leading surrogate is non-null: + // Step 1.2 Set encoder’s leading surrogate to null. + if self.leading_surrogate.take().is_some() { + output.push('\u{FFFD}'); + } + + // Step 1.4 Restore item to input. + // Note: Replacing encoder's leading_surrogate is equivalent + // to restore item back to input and rerun the convert- + // code-unit-to-scalar-value algo. + // Step 2. If item is a leading surrogate, then set encoder’s + // leading surrogate to item and return continue. + self.leading_surrogate + .replace(NonZero::new(unpaired_surrogate)); + }, + CodePointType::TrailingSurrogate => match self.leading_surrogate.take() { + // Step 1.1 If encoder’s leading surrogate is non-null: + // Step 1.2 Set encoder’s leading surrogate to null. + Some(leading_surrogate) => { + // Step 1.3 If item is a trailing surrogate, then return a scalar + // value from surrogates given leadingSurrogate and item. + let c = char::decode_utf16([ + leading_surrogate.get(), + unpaired_surrogate, + ]) + .next() + .expect("A pair of surrogate is supplied") + .expect("Decoding a pair of surrogate cannot fail"); + output.push(c); + }, + // Step 3. If item is a trailing surrogate, then return U+FFFD (�). + None => output.push('\u{FFFD}'), + }, + CodePointType::ScalarValue => unreachable!("Scalar Value won't fail"), + } + }, + } + } + + output + } +} + +enum CodePointType { + ScalarValue, + LeadingSurrogate, + TrailingSurrogate, +} + +fn code_point_type(value: u16) -> CodePointType { + match value { + 0xD800..=0xDBFF => CodePointType::LeadingSurrogate, + 0xDC00..=0xDFFF => CodePointType::TrailingSurrogate, + _ => CodePointType::ScalarValue, + } +} + +/// +#[allow(unsafe_code)] +pub(crate) fn encode_and_enqueue_a_chunk( + cx: SafeJSContext, + global: &GlobalScope, + chunk: SafeHandleValue, + encoder: &Encoder, + controller: &TransformStreamDefaultController, + can_gc: CanGc, +) -> Fallible<()> { + // Step 1. Let input be the result of converting chunk to a DOMString. + // Step 2. Convert input to an I/O queue of code units. + rooted!(in(*cx) let mut rval = UndefinedValue()); + jsval_to_primitive(cx, global, chunk, rval.handle_mut(), can_gc)?; + + assert!(!rval.is_object()); + rooted!(in(*cx) let jsstr = unsafe { ToString(*cx, rval.handle()) }); + if jsstr.is_null() { + unsafe { + if !JS_IsExceptionPending(*cx) { + throw_dom_exception( + cx, + global, + Error::Type("Cannot convert JS primitive to string".to_owned()), + can_gc, + ); + } + } + + return Err(Error::JSFailed); + } + + let input = unsafe { + if JS_DeprecatedStringHasLatin1Chars(*jsstr) { + let s = NonNull::new(*jsstr).expect("jsstr cannot be null"); + ConvertedInput::String(latin1_to_string(*cx, s)) + } else { + let mut len = 0; + let data = JS_GetTwoByteStringCharsAndLength(*cx, std::ptr::null(), *jsstr, &mut len); + let maybe_ill_formed_code_units = std::slice::from_raw_parts(data, len); + ConvertedInput::CodeUnits(maybe_ill_formed_code_units) + } + }; + + // Step 3. Let output be the I/O queue of bytes « end-of-queue ». + // Step 4. While true: + // Step 4.1 Let item be the result of reading from input. + // Step 4.3 Let result be the result of executing the convert code unit + // to scalar value algorithm with encoder, item and input. + // Step 4.4 If result is not continue, then process an item with result, + // encoder’s encoder, input, output, and "fatal". + let output = encoder.encode(input); + + // Step 4.2 If item is end-of-queue: + // Step 4.2.1 Convert output into a byte sequence. + let output = output.as_bytes(); + // Step 4.2.2 If output is not empty: + if output.is_empty() { + // Step 4.2.3 + return Ok(()); + } + + // Step 4.2.2.1 Let chunk be the result of creating a Uint8Array object + // given output and encoder’s relevant realm. + rooted!(in(*cx) let mut js_object = ptr::null_mut::()); + let chunk: Uint8Array = create_buffer_source(cx, output, js_object.handle_mut(), can_gc) + .map_err(|_| Error::Type("Cannot convert byte sequence to Uint8Array".to_owned()))?; + rooted!(in(*cx) let mut rval = UndefinedValue()); + chunk.safe_to_jsval(cx, rval.handle_mut()); + // Step 4.2.2.2 Enqueue chunk into encoder’s transform. + controller.enqueue(cx, global, rval.handle(), can_gc)?; + Ok(()) +} + +/// +#[allow(unsafe_code)] +pub(crate) fn encode_and_flush( + cx: SafeJSContext, + global: &GlobalScope, + encoder: &Encoder, + controller: &TransformStreamDefaultController, + can_gc: CanGc, +) -> Fallible<()> { + // Step 1. If encoder’s leading surrogate is non-null: + if encoder.leading_surrogate.get().is_some() { + // Step 1.1 Let chunk be the result of creating a Uint8Array object + // given « 0xEF, 0xBF, 0xBD » and encoder’s relevant realm. + rooted!(in(*cx) let mut js_object = ptr::null_mut::()); + let chunk: Uint8Array = + create_buffer_source(cx, &[0xEF_u8, 0xBF, 0xBD], js_object.handle_mut(), can_gc) + .map_err(|_| { + Error::Type("Cannot convert byte sequence to Uint8Array".to_owned()) + })?; + rooted!(in(*cx) let mut rval = UndefinedValue()); + chunk.safe_to_jsval(cx, rval.handle_mut()); + // Step 1.2 Enqueue chunk into encoder’s transform. + return controller.enqueue(cx, global, rval.handle(), can_gc); + } + + Ok(()) +} + +/// +#[dom_struct] +pub(crate) struct TextEncoderStream { + reflector_: Reflector, + + /// + transform: Dom, +} + +impl TextEncoderStream { + fn new_inherited(transform: &TransformStream) -> TextEncoderStream { + Self { + reflector_: Reflector::new(), + transform: Dom::from_ref(transform), + } + } + + /// + fn new_with_proto( + cx: SafeJSContext, + global: &GlobalScope, + proto: Option, + can_gc: CanGc, + ) -> Fallible> { + // Step 1. Set this’s encoder to an instance of the UTF-8 encoder. + let encoder = Encoder::default(); + + // Step 2. Let transformAlgorithm be an algorithm which takes a chunk argument + // and runs the encode and enqueue a chunk algorithm with this and chunk. + // Step 3. Let flushAlgorithm be an algorithm which runs the encode and flush + // algorithm with this. + let transformer_type = TransformerType::Encoder(encoder); + + // Step 4. Let transformStream be a new TransformStream. + let transform = TransformStream::new_with_proto(global, None, can_gc); + // Step 5. Set up transformStream with transformAlgorithm set to transformAlgorithm + // and flushAlgorithm set to flushAlgorithm. + transform.set_up(cx, global, transformer_type, can_gc)?; + + // Step 6. Set this’s transform to transformStream. + Ok(reflect_dom_object_with_proto( + Box::new(TextEncoderStream::new_inherited(&transform)), + global, + proto, + can_gc, + )) + } +} + +#[allow(non_snake_case)] +impl TextEncoderStreamMethods for TextEncoderStream { + /// + fn Constructor( + global: &::GlobalScope, + proto: Option, + can_gc: CanGc, + ) -> Fallible::TextEncoderStream>> { + TextEncoderStream::new_with_proto(GlobalScope::get_cx(), global, proto, can_gc) + } + + /// + fn Encoding(&self) -> DOMString { + // Returns "utf-8". + DOMString::from("utf-8") + } + + /// + fn Readable(&self) -> DomRoot<::ReadableStream> { + self.transform.get_readable() + } + + /// + fn Writable(&self) -> DomRoot<::WritableStream> { + self.transform.get_writable() + } +} diff --git a/components/script/dom/transformstreamdefaultcontroller.rs b/components/script/dom/transformstreamdefaultcontroller.rs index 54fb7a693a5..d7f30333916 100644 --- a/components/script/dom/transformstreamdefaultcontroller.rs +++ b/components/script/dom/transformstreamdefaultcontroller.rs @@ -28,6 +28,7 @@ use crate::dom::promise::Promise; use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler}; use crate::dom::textdecodercommon::TextDecoderCommon; use crate::dom::textdecoderstream::{decode_and_enqueue_a_chunk, flush_and_enqueue}; +use crate::dom::textencoderstream::{Encoder, encode_and_enqueue_a_chunk, encode_and_flush}; use crate::realms::{InRealm, enter_realm}; use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; @@ -75,6 +76,10 @@ pub(crate) enum TransformerType { /// /// Decoder(Rc), + /// Algorithms supporting `TextEncoderStream` are implemented in Rust + /// + /// + Encoder(Encoder), } impl TransformerType { @@ -256,6 +261,28 @@ impl TransformStreamDefaultController { p }) }, + TransformerType::Encoder(encoder) => { + // + // Step 2. Let transformAlgorithm be an algorithm which takes a chunk argument and runs the encode + // and enqueue a chunk algorithm with this and chunk. + encode_and_enqueue_a_chunk(cx, global, chunk, encoder, self, can_gc) + // + // Step 5. Let transformAlgorithmWrapper be an algorithm that runs these steps given a value chunk: + // Step 5.1 Let result be the result of running transformAlgorithm given chunk. + // Step 5.2 If result is a Promise, then return result. + // Note: not applicable, the spec does NOT require encode_and_enqueue_a_chunk() to return a Promise + // Step 5.3 Return a promise resolved with undefined. + .map(|_| Promise::new_resolved(global, cx, (), can_gc)) + .unwrap_or_else(|e| { + // + // Step 5.1 If this throws an exception e, + let realm = enter_realm(self); + let p = Promise::new_in_current_realm((&realm).into(), can_gc); + // return a promise rejected with e. + p.reject_error(e, can_gc); + p + }) + }, }; Ok(result) @@ -311,6 +338,17 @@ impl TransformStreamDefaultController { // Step 7.3 Return a promise resolved with undefined. Promise::new_resolved(global, cx, (), can_gc) }, + TransformerType::Encoder(_) => { + // + // Step 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason: + // Step 7.1 Let result be the result of running cancelAlgorithm given reason, + // if cancelAlgorithm was given, or null otherwise + // Note: `TextDecoderStream` does NOT specify a cancel algorithm. + // Step 7.2 If result is a Promise, then return result. + // Note: Not applicable. + // Step 7.3 Return a promise resolved with undefined. + Promise::new_resolved(global, cx, (), can_gc) + }, }; Ok(result) @@ -376,6 +414,28 @@ impl TransformStreamDefaultController { p }) }, + TransformerType::Encoder(encoder) => { + // + // Step 3. Let flushAlgorithm be an algorithm which runs the encode and flush algorithm with this. + encode_and_flush(cx, global, encoder, self, can_gc) + // + // Step 6. Let flushAlgorithmWrapper be an algorithm that runs these steps: + // Step 6.1 Let result be the result of running flushAlgorithm, + // if flushAlgorithm was given, or null otherwise. + // Step 6.2 If result is a Promise, then return result. + // Note: Not applicable. The spec does NOT require encode_and_flush algo to return a Promise + // Step 6.3 Return a promise resolved with undefined. + .map(|_| Promise::new_resolved(global, cx, (), can_gc)) + .unwrap_or_else(|e| { + // + // Step 6.1 If this throws an exception e, + let realm = enter_realm(self); + let p = Promise::new_in_current_realm((&realm).into(), can_gc); + // return a promise rejected with e. + p.reject_error(e, can_gc); + p + }) + }, }; Ok(result) diff --git a/components/script_bindings/webidls/TextEncoderStream.webidl b/components/script_bindings/webidls/TextEncoderStream.webidl new file mode 100644 index 00000000000..633c08a198e --- /dev/null +++ b/components/script_bindings/webidls/TextEncoderStream.webidl @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +/* + * For more information on this interface please see + * https://encoding.spec.whatwg.org/#textencoderstream + */ + +[Exposed=*] +interface TextEncoderStream { + [Throws] constructor(); +}; +TextEncoderStream includes TextEncoderCommon; +TextEncoderStream includes GenericTransformStream; diff --git a/tests/wpt/meta/encoding/idlharness.any.js.ini b/tests/wpt/meta/encoding/idlharness.any.js.ini index d4038395869..01ec3bcea85 100644 --- a/tests/wpt/meta/encoding/idlharness.any.js.ini +++ b/tests/wpt/meta/encoding/idlharness.any.js.ini @@ -5,50 +5,8 @@ expected: ERROR [idlharness.any.html] - [TextEncoderStream interface: existence and properties of interface object] - expected: FAIL - - [TextEncoderStream interface object length] - expected: FAIL - - [TextEncoderStream interface object name] - expected: FAIL - - [TextEncoderStream interface: existence and properties of interface prototype object] - expected: FAIL - - [TextEncoderStream interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [TextEncoderStream interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - - [TextEncoderStream interface: attribute encoding] - expected: FAIL - [idlharness.any.worker.html] - [TextEncoderStream interface: existence and properties of interface object] - expected: FAIL - - [TextEncoderStream interface object length] - expected: FAIL - - [TextEncoderStream interface object name] - expected: FAIL - - [TextEncoderStream interface: existence and properties of interface prototype object] - expected: FAIL - - [TextEncoderStream interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [TextEncoderStream interface: existence and properties of interface prototype object's @@unscopables property] - expected: FAIL - - [TextEncoderStream interface: attribute encoding] - expected: FAIL - [idlharness.any.shadowrealm-in-window.html] expected: ERROR diff --git a/tests/wpt/meta/encoding/streams/backpressure.any.js.ini b/tests/wpt/meta/encoding/streams/backpressure.any.js.ini index deb5e1b6dd3..2ed4ae6d2ee 100644 --- a/tests/wpt/meta/encoding/streams/backpressure.any.js.ini +++ b/tests/wpt/meta/encoding/streams/backpressure.any.js.ini @@ -1,10 +1,4 @@ [backpressure.any.worker.html] - [write() should not complete until read relieves backpressure for TextEncoderStream] - expected: FAIL - - [additional writes should wait for backpressure to be relieved for class TextEncoderStream] - expected: FAIL - [backpressure.any.sharedworker.html] expected: ERROR @@ -13,12 +7,6 @@ expected: ERROR [backpressure.any.html] - [write() should not complete until read relieves backpressure for TextEncoderStream] - expected: FAIL - - [additional writes should wait for backpressure to be relieved for class TextEncoderStream] - expected: FAIL - [backpressure.any.shadowrealm.html] expected: TIMEOUT diff --git a/tests/wpt/meta/encoding/streams/encode-bad-chunks.any.js.ini b/tests/wpt/meta/encoding/streams/encode-bad-chunks.any.js.ini index c9ace41f7df..c25cba32a86 100644 --- a/tests/wpt/meta/encoding/streams/encode-bad-chunks.any.js.ini +++ b/tests/wpt/meta/encoding/streams/encode-bad-chunks.any.js.ini @@ -1,22 +1,4 @@ [encode-bad-chunks.any.html] - [a chunk that cannot be converted to a string should error the streams] - expected: FAIL - - [input of type undefined should be converted correctly to string] - expected: FAIL - - [input of type null should be converted correctly to string] - expected: FAIL - - [input of type numeric should be converted correctly to string] - expected: FAIL - - [input of type object should be converted correctly to string] - expected: FAIL - - [input of type array should be converted correctly to string] - expected: FAIL - [encode-bad-chunks.any.sharedworker.html] expected: ERROR @@ -25,20 +7,3 @@ expected: ERROR [encode-bad-chunks.any.worker.html] - [a chunk that cannot be converted to a string should error the streams] - expected: FAIL - - [input of type undefined should be converted correctly to string] - expected: FAIL - - [input of type null should be converted correctly to string] - expected: FAIL - - [input of type numeric should be converted correctly to string] - expected: FAIL - - [input of type object should be converted correctly to string] - expected: FAIL - - [input of type array should be converted correctly to string] - expected: FAIL diff --git a/tests/wpt/meta/encoding/streams/encode-utf8.any.js.ini b/tests/wpt/meta/encoding/streams/encode-utf8.any.js.ini index 789340f3d84..5656e022fe4 100644 --- a/tests/wpt/meta/encoding/streams/encode-utf8.any.js.ini +++ b/tests/wpt/meta/encoding/streams/encode-utf8.any.js.ini @@ -2,121 +2,8 @@ expected: ERROR [encode-utf8.any.html] - [encoding one string of UTF-8 should give one complete chunk] - expected: FAIL - - [a character split between chunks should be correctly encoded] - expected: FAIL - - [a character following one split between chunks should be correctly encoded] - expected: FAIL - - [two consecutive astral characters each split down the middle should be correctly reassembled] - expected: FAIL - - [two consecutive astral characters each split down the middle with an invalid surrogate in the middle should be correctly encoded] - expected: FAIL - - [a stream ending in a leading surrogate should emit a replacement character as a final chunk] - expected: FAIL - - [an unmatched surrogate at the end of a chunk followed by an astral character in the next chunk should be replaced with the replacement character at the start of the next output chunk] - expected: FAIL - - [an unmatched surrogate at the end of a chunk followed by an ascii character in the next chunk should be replaced with the replacement character at the start of the next output chunk] - expected: FAIL - - [an unmatched surrogate at the end of a chunk followed by a plane 1 character split into two chunks should result in the encoded plane 1 character appearing in the last output chunk] - expected: FAIL - - [two leading chunks should result in two replacement characters] - expected: FAIL - - [a non-terminal unpaired leading surrogate should immediately be replaced] - expected: FAIL - - [a terminal unpaired trailing surrogate should immediately be replaced] - expected: FAIL - - [a leading surrogate chunk should be carried past empty chunks] - expected: FAIL - - [a leading surrogate chunk should error when it is clear it didn't form a pair] - expected: FAIL - - [an empty string should result in no output chunk] - expected: FAIL - - [a leading empty chunk should be ignored] - expected: FAIL - - [a trailing empty chunk should be ignored] - expected: FAIL - - [a plain ASCII chunk should be converted] - expected: FAIL - - [characters in the ISO-8859-1 range should be encoded correctly] - expected: FAIL - [encode-utf8.any.sharedworker.html] expected: ERROR [encode-utf8.any.worker.html] - [encoding one string of UTF-8 should give one complete chunk] - expected: FAIL - - [a character split between chunks should be correctly encoded] - expected: FAIL - - [a character following one split between chunks should be correctly encoded] - expected: FAIL - - [two consecutive astral characters each split down the middle should be correctly reassembled] - expected: FAIL - - [two consecutive astral characters each split down the middle with an invalid surrogate in the middle should be correctly encoded] - expected: FAIL - - [a stream ending in a leading surrogate should emit a replacement character as a final chunk] - expected: FAIL - - [an unmatched surrogate at the end of a chunk followed by an astral character in the next chunk should be replaced with the replacement character at the start of the next output chunk] - expected: FAIL - - [an unmatched surrogate at the end of a chunk followed by an ascii character in the next chunk should be replaced with the replacement character at the start of the next output chunk] - expected: FAIL - - [an unmatched surrogate at the end of a chunk followed by a plane 1 character split into two chunks should result in the encoded plane 1 character appearing in the last output chunk] - expected: FAIL - - [two leading chunks should result in two replacement characters] - expected: FAIL - - [a non-terminal unpaired leading surrogate should immediately be replaced] - expected: FAIL - - [a terminal unpaired trailing surrogate should immediately be replaced] - expected: FAIL - - [a leading surrogate chunk should be carried past empty chunks] - expected: FAIL - - [a leading surrogate chunk should error when it is clear it didn't form a pair] - expected: FAIL - - [an empty string should result in no output chunk] - expected: FAIL - - [a leading empty chunk should be ignored] - expected: FAIL - - [a trailing empty chunk should be ignored] - expected: FAIL - - [a plain ASCII chunk should be converted] - expected: FAIL - - [characters in the ISO-8859-1 range should be encoded correctly] - expected: FAIL diff --git a/tests/wpt/meta/encoding/streams/invalid-realm.window.js.ini b/tests/wpt/meta/encoding/streams/invalid-realm.window.js.ini deleted file mode 100644 index 08e9f1ab891..00000000000 --- a/tests/wpt/meta/encoding/streams/invalid-realm.window.js.ini +++ /dev/null @@ -1,6 +0,0 @@ -[invalid-realm.window.html] - [TextEncoderStream: write in detached realm should succeed] - expected: FAIL - - [TextEncoderStream: close in detached realm should succeed] - expected: FAIL diff --git a/tests/wpt/meta/encoding/streams/readable-writable-properties.any.js.ini b/tests/wpt/meta/encoding/streams/readable-writable-properties.any.js.ini index 1f553dbb751..4eec7367139 100644 --- a/tests/wpt/meta/encoding/streams/readable-writable-properties.any.js.ini +++ b/tests/wpt/meta/encoding/streams/readable-writable-properties.any.js.ini @@ -1,7 +1,4 @@ [readable-writable-properties.any.html] - [TextEncoderStream readable and writable properties must pass brand checks] - expected: FAIL - [readable-writable-properties.any.sharedworker.html] expected: ERROR @@ -10,9 +7,6 @@ expected: ERROR [readable-writable-properties.any.worker.html] - [TextEncoderStream readable and writable properties must pass brand checks] - expected: FAIL - [readable-writable-properties.any.shadowrealm.html] expected: TIMEOUT diff --git a/tests/wpt/meta/encoding/streams/realms.window.js.ini b/tests/wpt/meta/encoding/streams/realms.window.js.ini index 9f675afff2c..1f7bddc05c2 100644 --- a/tests/wpt/meta/encoding/streams/realms.window.js.ini +++ b/tests/wpt/meta/encoding/streams/realms.window.js.ini @@ -1,10 +1,4 @@ [realms.window.html] - [a TextEncoderStream object should be associated with the realm the constructor came from] - expected: FAIL - - [TextEncoderStream's readable and writable attributes should come from the same realm as the constructor definition] - expected: FAIL - [the output chunks when read is called after write should come from the same realm as the constructor of TextEncoderStream] expected: FAIL diff --git a/tests/wpt/meta/encoding/streams/stringification-crash.html.ini b/tests/wpt/meta/encoding/streams/stringification-crash.html.ini deleted file mode 100644 index da00626042c..00000000000 --- a/tests/wpt/meta/encoding/streams/stringification-crash.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[stringification-crash.html] - expected: TIMEOUT \ No newline at end of file diff --git a/tests/wpt/meta/service-workers/service-worker/fetch-event.https.h2.html.ini b/tests/wpt/meta/service-workers/service-worker/fetch-event.https.h2.html.ini index e1b6f552679..b99fb1e00f7 100644 --- a/tests/wpt/meta/service-workers/service-worker/fetch-event.https.h2.html.ini +++ b/tests/wpt/meta/service-workers/service-worker/fetch-event.https.h2.html.ini @@ -1,15 +1,16 @@ [fetch-event.https.h2.html] + expected: TIMEOUT [global setup] expected: FAIL [The streaming request body is readable in the service worker.] - expected: FAIL + expected: TIMEOUT [Network fallback for streaming upload.] - expected: FAIL + expected: NOTRUN [When the streaming request body is used, network fallback fails.] - expected: FAIL + expected: NOTRUN [Running clone() in the service worker does not prevent network fallback.] - expected: FAIL + expected: NOTRUN diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index b130875c753..12a84179672 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -13725,14 +13725,14 @@ ] ], "interfaces.https.html": [ - "cbdb5bef0bab4f54514913517c214631a71f7d3a", + "40567f81c201fe775ad4735c231349fac8c33381", [ null, {} ] ], "interfaces.worker.js": [ - "1955d6f821d8445c813ac09e098b2c66f0e07d26", + "66f95241d5518a6b82725529775dc5613cbab1c0", [ "mozilla/interfaces.worker.html", {} diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html index cbdb5bef0ba..40567f81c20 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.https.html +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.https.html @@ -330,6 +330,7 @@ test_interfaces([ "TextDecoder", "TextDecoderStream", "TextEncoder", + "TextEncoderStream", "TimeRanges", "Touch", "TouchEvent", diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js index 1955d6f821d..66f95241d55 100644 --- a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js +++ b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js @@ -113,6 +113,7 @@ test_interfaces([ "TextDecoder", "TextDecoderStream", "TextEncoder", + "TextEncoderStream", "TrustedHTML", "TrustedScript", "TrustedScriptURL",