script: Re-implement evaluate_key_path_on_value in IndexedDB (#38847)

The current implementation of evaluate_key_path_on_value was translated
from gecko, and it is incomplete. The unimplemented part occurs many
crashes in WPT tests.

This PR re-implements it according to the spec. It should eliminate many
crashed WPT tests, and increase the code readability.

Testing: Update WPT test expectation
Fixes: #38817 partially, and #25325

---------

Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
This commit is contained in:
Kingsley Yung 2025-09-05 16:00:07 +08:00 committed by GitHub
parent ebc1282c7a
commit b29eab0ffe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 694 additions and 178 deletions

View file

@ -29,8 +29,9 @@ use crate::dom::domstringlist::DOMStringList;
use crate::dom::globalscope::GlobalScope;
use crate::dom::idbrequest::IDBRequest;
use crate::dom::idbtransaction::IDBTransaction;
use crate::indexed_db;
use crate::indexed_db::{convert_value_to_key, convert_value_to_key_range, extract_key};
use crate::indexed_db::{
self, ExtractionResult, convert_value_to_key, convert_value_to_key_range, extract_key,
};
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
#[derive(JSTraceable, MallocSizeOf)]
@ -242,7 +243,7 @@ impl IDBObjectStore {
serialized_key = Some(convert_value_to_key(cx, key, None)?);
} else {
// Step 11: We should use in-line keys instead
if let Some(Ok(kpk)) = self
if let Some(Ok(ExtractionResult::Key(kpk))) = self
.key_path
.as_ref()
.map(|p| extract_key(cx, value, p, None))

View file

@ -2,6 +2,7 @@
* 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::ffi::CString;
use std::iter::repeat_n;
use std::ptr;
@ -9,24 +10,31 @@ use ipc_channel::ipc::IpcSender;
use js::conversions::jsstr_to_string;
use js::gc::MutableHandle;
use js::jsapi::{
ESClass, GetBuiltinClass, IsArrayBufferObject, JS_DeleteUCProperty,
JS_GetOwnUCPropertyDescriptor, JS_GetStringLength, JS_IsArrayBufferViewObject, JSObject,
ObjectOpResult, ObjectOpResult_SpecialCodes, PropertyDescriptor,
ClippedTime, ESClass, GetBuiltinClass, IsArrayBufferObject, JS_GetStringLength,
JS_IsArrayBufferViewObject, JS_NewObject, NewDateObject,
};
use js::jsval::{DoubleValue, UndefinedValue};
use js::rust::wrappers::{IsArrayObject, JS_GetProperty, JS_HasOwnProperty};
use js::rust::{HandleValue, MutableHandleValue};
use net_traits::indexeddb_thread::{BackendResult, IndexedDBKeyRange, IndexedDBKeyType};
use profile_traits::ipc;
use profile_traits::ipc::IpcReceiver;
use script_bindings::conversions::{SafeToJSValConvertible, root_from_object};
use script_bindings::root::DomRoot;
use script_bindings::str::DOMString;
use serde::{Deserialize, Serialize};
use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use crate::dom::bindings::codegen::Bindings::FileBinding::FileMethods;
use crate::dom::bindings::codegen::UnionTypes::StringOrStringSequence as StrOrStringSequence;
use crate::dom::bindings::conversions::{
SafeToJSValConvertible, get_property_jsval, root_from_handlevalue, root_from_object,
};
use crate::dom::bindings::error::Error;
use crate::dom::bindings::import::module::SafeJSContext;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::structuredclone;
use crate::dom::bindings::utils::set_dictionary_property;
use crate::dom::blob::Blob;
use crate::dom::file::File;
use crate::dom::globalscope::GlobalScope;
use crate::dom::idbkeyrange::IDBKeyRange;
use crate::dom::idbobjectstore::KeyPath;
@ -187,158 +195,265 @@ pub fn convert_value_to_key_range(
Ok(IndexedDBKeyRange::only(key))
}
// https://www.w3.org/TR/IndexedDB-2/#evaluate-a-key-path-on-a-value
/// The result of steps in
/// <https://www.w3.org/TR/IndexedDB-2/#evaluate-a-key-path-on-a-value>
pub(crate) enum EvaluationResult {
Success,
Failure,
}
/// <https://www.w3.org/TR/IndexedDB-2/#evaluate-a-key-path-on-a-value>
#[allow(unsafe_code)]
pub fn evaluate_key_path_on_value(
pub(crate) fn evaluate_key_path_on_value(
cx: SafeJSContext,
value: HandleValue,
mut return_val: MutableHandleValue,
key_path: &KeyPath,
) {
// The implementation is translated from gecko:
// https://github.com/mozilla/gecko-dev/blob/master/dom/indexedDB/KeyPath.cpp
return_val.set(*value);
rooted!(in(*cx) let mut target_object = ptr::null_mut::<JSObject>());
rooted!(in(*cx) let mut current_val = *value);
rooted!(in(*cx) let mut object = ptr::null_mut::<JSObject>());
let mut target_object_prop_name: Option<String> = None;
mut return_val: MutableHandleValue,
) -> Result<EvaluationResult, Error> {
match key_path {
KeyPath::String(path) => {
// Step 3
let path_as_string = path.to_string();
let mut tokenizer = path_as_string.split('.').peekable();
// Step 1. If keyPath is a list of strings, then:
KeyPath::StringSequence(key_path) => {
// Step 1.1. Let result be a new Array object created as if by the expression [].
rooted!(in(*cx) let mut result = unsafe { JS_NewObject(*cx, ptr::null()) });
while let Some(token) = tokenizer.next() {
if target_object.get().is_null() {
if token == "length" && tokenizer.peek().is_none() && current_val.is_string() {
rooted!(in(*cx) let input_val = current_val.to_string());
unsafe {
let string_len = JS_GetStringLength(*input_val) as u64;
string_len.safe_to_jsval(cx, return_val);
}
break;
}
// Step 1.2. Let i be 0.
// Step 1.3. For each item in keyPath:
for (i, item) in key_path.iter().enumerate() {
// Step 1.3.1. Let key be the result of recursively running the steps to evaluate a key
// path on a value using item as keyPath and value as value.
// Step 1.3.2. Assert: key is not an abrupt completion.
// Step 1.3.3. If key is failure, abort the overall algorithm and return failure.
rooted!(in(*cx) let mut key = UndefinedValue());
if let EvaluationResult::Failure = evaluate_key_path_on_value(
cx,
value,
&KeyPath::String(item.clone()),
key.handle_mut(),
)? {
return Ok(EvaluationResult::Failure);
};
if !current_val.is_object() {
// FIXME:(rasviitanen) Return a proper error
return;
}
object.handle_mut().set(current_val.to_object());
rooted!(in(*cx) let mut desc = PropertyDescriptor::default());
rooted!(in(*cx) let mut intermediate = UndefinedValue());
// So rust says that this value is never read, but it is.
#[allow(unused)]
let mut has_prop = false;
unsafe {
let prop_name_as_utf16: Vec<u16> = token.encode_utf16().collect();
let mut is_descriptor_none: bool = false;
let ok = JS_GetOwnUCPropertyDescriptor(
*cx,
object.handle().into(),
prop_name_as_utf16.as_ptr(),
prop_name_as_utf16.len(),
desc.handle_mut().into(),
&mut is_descriptor_none,
);
if !ok {
// FIXME:(arihant2math) Handle this
return;
}
if desc.hasWritable_() || desc.hasValue_() {
intermediate.handle_mut().set(desc.handle().value_);
has_prop = true;
} else {
// If we get here it means the object doesn't have the property or the
// property is available through a getter. We don't want to call any
// getters to avoid potential re-entrancy.
// The blob object is special since its properties are available
// only through getters but we still want to support them for key
// extraction. So they need to be handled manually.
unimplemented!("Blob tokens are not yet supported");
}
}
if has_prop {
// Treat undefined as an error
if intermediate.is_undefined() {
// FIXME:(rasviitanen) Throw/return error
return;
}
if tokenizer.peek().is_some() {
// ...and walk to it if there are more steps...
current_val.handle_mut().set(*intermediate);
} else {
// ...otherwise use it as key
return_val.set(*intermediate);
}
} else {
target_object.handle_mut().set(*object);
target_object_prop_name = Some(token.to_string());
}
}
if !target_object.get().is_null() {
// We have started inserting new objects or are about to just insert
// the first one.
// FIXME:(rasviitanen) Implement this piece
unimplemented!("keyPath tokens that requires insertion are not supported.");
}
} // All tokens processed
if !target_object.get().is_null() {
// If this fails, we lose, and the web page sees a magical property
// appear on the object :-(
// Step 1.3.4. Let p be ! ToString(i).
// Step 1.3.5. Let status be CreateDataProperty(result, p, key).
// Step 1.3.6. Assert: status is true.
unsafe {
let prop_name_as_utf16: Vec<u16> =
target_object_prop_name.unwrap().encode_utf16().collect();
#[allow(clippy::cast_enum_truncation)]
let mut succeeded = ObjectOpResult {
code_: ObjectOpResult_SpecialCodes::Uninitialized as usize,
};
if !JS_DeleteUCProperty(
set_dictionary_property(*cx, result.handle(), &i.to_string(), key.handle())
.map_err(|_| Error::JSFailed)?;
}
// Step 1.3.7. Increase i by 1.
// Done by for loop with enumerate()
}
// Step 1.4. Return result.
result.safe_to_jsval(cx, return_val);
},
KeyPath::String(key_path) => {
// Step 2. If keyPath is the empty string, return value and skip the remaining steps.
if key_path.is_empty() {
return_val.set(*value);
return Ok(EvaluationResult::Success);
}
// NOTE: Use current_value, instead of value described in spec, in the following steps.
rooted!(in(*cx) let mut current_value = *value);
// Step 3. Let identifiers be the result of strictly splitting keyPath on U+002E
// FULL STOP characters (.).
// Step 4. For each identifier of identifiers, jump to the appropriate step below:
for identifier in key_path.split('.') {
// If Type(value) is String, and identifier is "length"
if identifier == "length" && current_value.is_string() {
// Let value be a Number equal to the number of elements in value.
rooted!(in(*cx) let string_value = current_value.to_string());
unsafe {
let string_length = JS_GetStringLength(*string_value) as u64;
string_length.safe_to_jsval(cx, current_value.handle_mut());
}
continue;
}
// If value is an Array and identifier is "length"
if identifier == "length" {
unsafe {
let mut is_array = false;
if !IsArrayObject(*cx, current_value.handle(), &mut is_array) {
return Err(Error::JSFailed);
}
if is_array {
// Let value be ! ToLength(! Get(value, "length")).
rooted!(in(*cx) let object = current_value.to_object());
get_property_jsval(
cx,
object.handle(),
"length",
current_value.handle_mut(),
)?;
continue;
}
}
}
// If value is a Blob and identifier is "size"
if identifier == "size" {
unsafe {
if let Ok(blob) = root_from_handlevalue::<Blob>(current_value.handle(), *cx)
{
// Let value be a Number equal to values size.
blob.Size().safe_to_jsval(cx, current_value.handle_mut());
continue;
}
}
}
// If value is a Blob and identifier is "type"
if identifier == "type" {
unsafe {
if let Ok(blob) = root_from_handlevalue::<Blob>(current_value.handle(), *cx)
{
// Let value be a String equal to values type.
blob.Type().safe_to_jsval(cx, current_value.handle_mut());
continue;
}
}
}
// If value is a File and identifier is "name"
if identifier == "name" {
unsafe {
if let Ok(file) = root_from_handlevalue::<File>(current_value.handle(), *cx)
{
// Let value be a String equal to values name.
file.name().safe_to_jsval(cx, current_value.handle_mut());
continue;
}
}
}
// If value is a File and identifier is "lastModified"
if identifier == "lastModified" {
unsafe {
if let Ok(file) = root_from_handlevalue::<File>(current_value.handle(), *cx)
{
// Let value be a Number equal to values lastModified.
file.LastModified()
.safe_to_jsval(cx, current_value.handle_mut());
continue;
}
}
}
// If value is a File and identifier is "lastModifiedDate"
if identifier == "lastModifiedDate" {
unsafe {
if let Ok(file) = root_from_handlevalue::<File>(current_value.handle(), *cx)
{
// Let value be a new Date object with [[DateValue]] internal slot equal to values lastModified.
let time = ClippedTime {
t: file.LastModified() as f64,
};
NewDateObject(*cx, time).safe_to_jsval(cx, current_value.handle_mut());
continue;
}
}
}
// Otherwise
unsafe {
// If Type(value) is not Object, return failure.
if !current_value.is_object() {
return Ok(EvaluationResult::Failure);
}
rooted!(in(*cx) let object = current_value.to_object());
let identifier_name =
CString::new(identifier).expect("Failed to convert str to CString");
// Let hop be ! HasOwnProperty(value, identifier).
let mut hop = false;
if !JS_HasOwnProperty(*cx, object.handle(), identifier_name.as_ptr(), &mut hop)
{
return Err(Error::JSFailed);
}
// If hop is false, return failure.
if !hop {
return Ok(EvaluationResult::Failure);
}
// Let value be ! Get(value, identifier).
if !JS_GetProperty(
*cx,
target_object.handle().into(),
prop_name_as_utf16.as_ptr(),
prop_name_as_utf16.len(),
&mut succeeded,
object.handle(),
identifier_name.as_ptr(),
current_value.handle_mut(),
) {
// FIXME:(rasviitanen) Throw/return error
// return;
return Err(Error::JSFailed);
}
// If value is undefined, return failure.
if current_value.get().is_undefined() {
return Ok(EvaluationResult::Failure);
}
}
}
},
KeyPath::StringSequence(_) => {
unimplemented!("String sequence keyPath is currently unsupported");
// Step 5. Assert: value is not an abrupt completion.
// Done within Step 4.
// Step 6. Return value.
return_val.set(*current_value);
},
}
Ok(EvaluationResult::Success)
}
// https://www.w3.org/TR/IndexedDB-2/#extract-a-key-from-a-value-using-a-key-path
pub fn extract_key(
/// The result of steps in
/// <https://www.w3.org/TR/IndexedDB-2/#extract-a-key-from-a-value-using-a-key-path>
pub(crate) enum ExtractionResult {
Key(IndexedDBKeyType),
// NOTE: Invalid is not used for now. Remove the unused annotation when it is used.
#[expect(unused)]
Invalid,
Failure,
}
/// <https://www.w3.org/TR/IndexedDB-2/#extract-a-key-from-a-value-using-a-key-path>
pub(crate) fn extract_key(
cx: SafeJSContext,
input: HandleValue,
value: HandleValue,
key_path: &KeyPath,
multi_entry: Option<bool>,
) -> Result<IndexedDBKeyType, Error> {
// Step 1: Evaluate key path
// FIXME:(rasviitanen) Do this propertly
) -> Result<ExtractionResult, Error> {
// Step 1. Let r be the result of running the steps to evaluate a key path on a value with
// value and keyPath. Rethrow any exceptions.
// Step 2. If r is failure, return failure.
rooted!(in(*cx) let mut r = UndefinedValue());
evaluate_key_path_on_value(cx, input, r.handle_mut(), key_path);
if let Some(_multi_entry) = multi_entry {
// FIXME:(rasviitanen) handle multi_entry cases
unimplemented!("multiEntry keys are not yet supported");
} else {
convert_value_to_key(cx, r.handle(), None)
if let EvaluationResult::Failure =
evaluate_key_path_on_value(cx, value, key_path, r.handle_mut())?
{
return Ok(ExtractionResult::Failure);
}
// Step 3. Let key be the result of running the steps to convert a value to a key with r if the
// multiEntry flag is unset, and the result of running the steps to convert a value to a
// multiEntry key with r otherwise. Rethrow any exceptions.
let key = match multi_entry {
Some(true) => {
// TODO: implement convert_value_to_multientry_key
unimplemented!("multiEntry keys are not yet supported");
},
_ => convert_value_to_key(cx, r.handle(), None)?,
};
// TODO: Step 4. If key is invalid, return invalid.
// Step 5. Return key.
Ok(ExtractionResult::Key(key))
}

View file

@ -1,13 +1,11 @@
[create-index.any.html]
expected: CRASH
[Assure no crash when populating index]
expected: TIMEOUT
expected: FAIL
[create-index.any.worker.html]
expected: TIMEOUT
[Assure no crash when populating index]
expected: TIMEOUT
expected: FAIL
[create-index.any.serviceworker.html]

View file

@ -1,8 +1,18 @@
[idbdatabase_deleteObjectStore.any.worker.html]
expected: CRASH
[Deleted object store's name should be removed from database's list. Attempting to use a deleted IDBObjectStore should throw an InvalidStateError]
expected: FAIL
[Attempting to access an index that was deleted as part of object store deletion and then recreated using the same object store name should throw a NotFoundError]
expected: FAIL
[idbdatabase_deleteObjectStore.any.html]
expected: CRASH
[Deleted object store's name should be removed from database's list. Attempting to use a deleted IDBObjectStore should throw an InvalidStateError]
expected: FAIL
[Attempting to access an index that was deleted as part of object store deletion and then recreated using the same object store name should throw a NotFoundError]
expected: FAIL
[idbdatabase_deleteObjectStore.any.serviceworker.html]
expected: ERROR

View file

@ -2,10 +2,37 @@
expected: ERROR
[idbobjectstore_add.any.worker.html]
expected: CRASH
[add() where an index has unique:true specified]
expected: FAIL
[add() autoIncrement and inline keys]
expected: FAIL
[add() autoIncrement and out-of-line keys]
expected: FAIL
[Object store has autoIncrement:true and the key path is an object attribute]
expected: FAIL
[add() a record where a value being indexed does not meet the constraints of a valid key]
expected: FAIL
[idbobjectstore_add.any.serviceworker.html]
expected: ERROR
[idbobjectstore_add.any.html]
expected: CRASH
[add() where an index has unique:true specified]
expected: FAIL
[add() autoIncrement and inline keys]
expected: FAIL
[add() autoIncrement and out-of-line keys]
expected: FAIL
[Object store has autoIncrement:true and the key path is an object attribute]
expected: FAIL
[add() a record where a value being indexed does not meet the constraints of a valid key]
expected: FAIL

View file

@ -1,5 +1,4 @@
[idbobjectstore_getAll-options.tentative.any.worker.html]
expected: CRASH
[Single item get]
expected: FAIL
@ -80,7 +79,6 @@
expected: ERROR
[idbobjectstore_getAll-options.tentative.any.html]
expected: CRASH
[Single item get]
expected: FAIL

View file

@ -1,5 +1,4 @@
[idbobjectstore_getAll.any.html]
expected: CRASH
[Single item get]
expected: FAIL
@ -59,7 +58,6 @@
expected: ERROR
[idbobjectstore_getAll.any.worker.html]
expected: CRASH
[Single item get]
expected: FAIL

View file

@ -1,5 +1,4 @@
[idbobjectstore_getAllKeys-options.tentative.any.worker.html]
expected: CRASH
[Single item get]
expected: FAIL
@ -74,7 +73,6 @@
expected: ERROR
[idbobjectstore_getAllKeys-options.tentative.any.html]
expected: CRASH
[Single item get]
expected: FAIL

View file

@ -5,7 +5,6 @@
expected: ERROR
[idbobjectstore_getAllKeys.any.worker.html]
expected: CRASH
[Single item get]
expected: FAIL
@ -56,7 +55,6 @@
[idbobjectstore_getAllKeys.any.html]
expected: CRASH
[Single item get]
expected: FAIL

View file

@ -1,5 +1,4 @@
[idbobjectstore_getAllRecords.tentative.any.worker.html]
expected: CRASH
[Single item]
expected: FAIL
@ -77,7 +76,6 @@
[idbobjectstore_getAllRecords.tentative.any.html]
expected: CRASH
[Single item]
expected: FAIL

View file

@ -2,10 +2,43 @@
expected: ERROR
[idbobjectstore_put.any.worker.html]
expected: CRASH
[put() record with key already exists]
expected: FAIL
[put() where an index has unique:true specified]
expected: FAIL
[autoIncrement and inline keys]
expected: FAIL
[autoIncrement and out-of-line keys]
expected: FAIL
[Object store has autoIncrement:true and the key path is an object attribute]
expected: FAIL
[put() a record where a value being indexed does not meet the constraints of a valid key]
expected: FAIL
[idbobjectstore_put.any.serviceworker.html]
expected: ERROR
[idbobjectstore_put.any.html]
expected: CRASH
[put() record with key already exists]
expected: FAIL
[put() where an index has unique:true specified]
expected: FAIL
[autoIncrement and inline keys]
expected: FAIL
[autoIncrement and out-of-line keys]
expected: FAIL
[Object store has autoIncrement:true and the key path is an object attribute]
expected: FAIL
[put() a record where a value being indexed does not meet the constraints of a valid key]
expected: FAIL

View file

@ -1,11 +1,117 @@
[key_valid.any.worker.html]
expected: CRASH
[Valid key - new Date()]
expected: FAIL
[Valid key - new Date(0)]
expected: FAIL
[Valid key - [\]]
expected: FAIL
[Valid key - new Array()]
expected: FAIL
[Valid key - ["undefined"\]]
expected: FAIL
[Valid key - Infinity]
expected: FAIL
[Valid key - -Infinity]
expected: FAIL
[Valid key - 0]
expected: FAIL
[Valid key - 1.5]
expected: FAIL
[Valid key - 3e38]
expected: FAIL
[Valid key - 3e-38]
expected: FAIL
[Valid key - "foo"]
expected: FAIL
[Valid key - "\\n"]
expected: FAIL
[Valid key - ""]
expected: FAIL
[Valid key - "\\""]
expected: FAIL
[Valid key - "\\u1234"]
expected: FAIL
[Valid key - "\\u0000"]
expected: FAIL
[Valid key - "NaN"]
expected: FAIL
[key_valid.any.serviceworker.html]
expected: ERROR
[key_valid.any.html]
expected: CRASH
[Valid key - new Date()]
expected: FAIL
[Valid key - new Date(0)]
expected: FAIL
[Valid key - [\]]
expected: FAIL
[Valid key - new Array()]
expected: FAIL
[Valid key - ["undefined"\]]
expected: FAIL
[Valid key - Infinity]
expected: FAIL
[Valid key - -Infinity]
expected: FAIL
[Valid key - 0]
expected: FAIL
[Valid key - 1.5]
expected: FAIL
[Valid key - 3e38]
expected: FAIL
[Valid key - 3e-38]
expected: FAIL
[Valid key - "foo"]
expected: FAIL
[Valid key - "\\n"]
expected: FAIL
[Valid key - ""]
expected: FAIL
[Valid key - "\\""]
expected: FAIL
[Valid key - "\\u1234"]
expected: FAIL
[Valid key - "\\u0000"]
expected: FAIL
[Valid key - "NaN"]
expected: FAIL
[key_valid.any.sharedworker.html]
expected: ERROR

View file

@ -1,5 +1,67 @@
[keygenerator.any.html]
expected: CRASH
[Keygenerator - starts at one, and increments by one]
expected: FAIL
[Keygenerator - increments by one from last set key]
expected: FAIL
[Keygenerator - don't increment when new key is not bigger than current]
expected: FAIL
[Keygenerator ConstraintError when using same id as already generated]
expected: FAIL
[Key generator vs. explicit key 53 bits]
expected: FAIL
[Key generator vs. explicit key greater than 53 bits, less than 64 bits]
expected: FAIL
[Key generator vs. explicit key greater than 53 bits, less than 64 bits (negative)]
expected: FAIL
[Key generator vs. explicit key 63 bits]
expected: FAIL
[Key generator vs. explicit key 63 bits (negative)]
expected: FAIL
[Key generator vs. explicit key 64 bits]
expected: FAIL
[Key generator vs. explicit key 64 bits (negative)]
expected: FAIL
[Key generator vs. explicit key greater than 64 bits, but still finite]
expected: FAIL
[Key generator vs. explicit key greater than 64 bits, but still finite (negative)]
expected: FAIL
[Key generator vs. explicit key equal to Infinity]
expected: FAIL
[Key generator vs. explicit key equal to -Infinity]
expected: FAIL
[Key is injected into value - single segment path]
expected: FAIL
[Key is injected into value - multi-segment path]
expected: FAIL
[Key is injected into value - multi-segment path, partially populated]
expected: FAIL
[Keygenerator overflow]
expected: FAIL
[put() throws if key cannot be injected - single segment path]
expected: FAIL
[put() throws if key cannot be injected - multi-segment path]
expected: FAIL
[keygenerator.any.serviceworker.html]
expected: ERROR
@ -8,4 +70,65 @@
expected: ERROR
[keygenerator.any.worker.html]
expected: CRASH
[Keygenerator - starts at one, and increments by one]
expected: FAIL
[Keygenerator - increments by one from last set key]
expected: FAIL
[Keygenerator - don't increment when new key is not bigger than current]
expected: FAIL
[Keygenerator ConstraintError when using same id as already generated]
expected: FAIL
[Key generator vs. explicit key 53 bits]
expected: FAIL
[Key generator vs. explicit key greater than 53 bits, less than 64 bits]
expected: FAIL
[Key generator vs. explicit key greater than 53 bits, less than 64 bits (negative)]
expected: FAIL
[Key generator vs. explicit key 63 bits]
expected: FAIL
[Key generator vs. explicit key 63 bits (negative)]
expected: FAIL
[Key generator vs. explicit key 64 bits]
expected: FAIL
[Key generator vs. explicit key 64 bits (negative)]
expected: FAIL
[Key generator vs. explicit key greater than 64 bits, but still finite]
expected: FAIL
[Key generator vs. explicit key greater than 64 bits, but still finite (negative)]
expected: FAIL
[Key generator vs. explicit key equal to Infinity]
expected: FAIL
[Key generator vs. explicit key equal to -Infinity]
expected: FAIL
[Key is injected into value - single segment path]
expected: FAIL
[Key is injected into value - multi-segment path]
expected: FAIL
[Key is injected into value - multi-segment path, partially populated]
expected: FAIL
[Keygenerator overflow]
expected: FAIL
[put() throws if key cannot be injected - single segment path]
expected: FAIL
[put() throws if key cannot be injected - multi-segment path]
expected: FAIL

View file

@ -1,11 +1,129 @@
[keypath.any.worker.html]
expected: CRASH
[undefined - my.key]
expected: FAIL
[undefined - my.køi]
expected: FAIL
[undefined - my.key_ya]
expected: FAIL
[undefined - public.key$ya]
expected: FAIL
[undefined - true.$]
expected: FAIL
[undefined - my._]
expected: FAIL
[undefined - delete.a7]
expected: FAIL
[undefined - p.p.p.p.p.p.p.p.p.p.p.p.p.p]
expected: FAIL
[undefined - str.length]
expected: FAIL
[undefined - arr.length]
expected: FAIL
[undefined - length]
expected: FAIL
[undefined - '' uses value as key]
expected: FAIL
[undefined - [''\] uses value as [key\]]
expected: FAIL
[undefined - ['x', 'y'\]]
expected: FAIL
[undefined - [['x'\], 'y'\] (stringifies)]
expected: FAIL
[undefined - ['x', {toString->'y'}\] (stringifies)]
expected: FAIL
[undefined - name,type]
expected: FAIL
[undefined - name,type.name]
expected: FAIL
[undefined - list with 1 field]
expected: FAIL
[undefined - array loop -> stringify becomes [''\]]
expected: FAIL
[keypath.any.serviceworker.html]
expected: ERROR
[keypath.any.html]
expected: CRASH
[undefined - my.key]
expected: FAIL
[undefined - my.køi]
expected: FAIL
[undefined - my.key_ya]
expected: FAIL
[undefined - public.key$ya]
expected: FAIL
[undefined - true.$]
expected: FAIL
[undefined - my._]
expected: FAIL
[undefined - delete.a7]
expected: FAIL
[undefined - p.p.p.p.p.p.p.p.p.p.p.p.p.p]
expected: FAIL
[undefined - str.length]
expected: FAIL
[undefined - arr.length]
expected: FAIL
[undefined - length]
expected: FAIL
[undefined - '' uses value as key]
expected: FAIL
[undefined - [''\] uses value as [key\]]
expected: FAIL
[undefined - ['x', 'y'\]]
expected: FAIL
[undefined - [['x'\], 'y'\] (stringifies)]
expected: FAIL
[undefined - ['x', {toString->'y'}\] (stringifies)]
expected: FAIL
[undefined - name,type]
expected: FAIL
[undefined - name,type.name]
expected: FAIL
[undefined - list with 1 field]
expected: FAIL
[undefined - array loop -> stringify becomes [''\]]
expected: FAIL
[keypath.any.sharedworker.html]
expected: ERROR

View file

@ -5,7 +5,6 @@
expected: ERROR
[nested-cloning-large-multiple.any.html]
expected: CRASH
[multiple requests of objects with blobs and large typed arrays]
expected: FAIL
@ -14,7 +13,6 @@
[nested-cloning-large-multiple.any.worker.html]
expected: CRASH
[multiple requests of objects with blobs and large typed arrays]
expected: FAIL

View file

@ -1,5 +1,4 @@
[nested-cloning-large.any.html]
expected: CRASH
[large typed array]
expected: FAIL
@ -26,7 +25,6 @@
expected: ERROR
[nested-cloning-large.any.worker.html]
expected: CRASH
[large typed array]
expected: FAIL

View file

@ -1,5 +1,4 @@
[nested-cloning-small.any.html]
expected: CRASH
[blob with small typed array]
expected: FAIL
@ -26,7 +25,6 @@
expected: ERROR
[nested-cloning-small.any.worker.html]
expected: CRASH
[blob with small typed array]
expected: FAIL

View file

@ -16,9 +16,6 @@
[Deactivation of new transactions happens at end of invocation]
expected: FAIL
[New transactions from microtask are deactivated before next task]
expected: FAIL
[transaction-deactivation-timing.any.sharedworker.html]
expected: ERROR

View file

@ -2,10 +2,14 @@
expected: ERROR
[transaction-requestqueue.any.worker.html]
expected: CRASH
[Transactions have a request queue]
expected: FAIL
[transaction-requestqueue.any.html]
expected: CRASH
[Transactions have a request queue]
expected: FAIL
[transaction-requestqueue.any.sharedworker.html]
expected: ERROR