mirror of
https://github.com/servo/servo.git
synced 2025-09-08 14:08:22 +01:00
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:
parent
ebc1282c7a
commit
b29eab0ffe
19 changed files with 694 additions and 178 deletions
|
@ -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))
|
||||
|
|
|
@ -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 value’s 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 value’s 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 value’s 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 value’s 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 value’s 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))
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
110
tests/wpt/meta/IndexedDB/key_valid.any.js.ini
vendored
110
tests/wpt/meta/IndexedDB/key_valid.any.js.ini
vendored
|
@ -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
|
||||
|
|
127
tests/wpt/meta/IndexedDB/keygenerator.any.js.ini
vendored
127
tests/wpt/meta/IndexedDB/keygenerator.any.js.ini
vendored
|
@ -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
|
||||
|
|
122
tests/wpt/meta/IndexedDB/keypath.any.js.ini
vendored
122
tests/wpt/meta/IndexedDB/keypath.any.js.ini
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue