| Index: third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
 | 
| diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..c955f0247dcc3fdcc0076347851f79ee3f7505d1
 | 
| --- /dev/null
 | 
| +++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
 | 
| @@ -0,0 +1,288 @@
 | 
| +<!doctype html>
 | 
| +<meta charset="utf8">
 | 
| +<meta name="timeout" content="long">
 | 
| +<title>IndexedDB: large nested objects are cloned correctly</title>
 | 
| +<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
 | 
| +<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
 | 
| +<script src="/resources/testharness.js"></script>
 | 
| +<script src="/resources/testharnessreport.js"></script>
 | 
| +<script src="support-promises.js"></script>
 | 
| +<script>
 | 
| +'use strict';
 | 
| +
 | 
| +// Should be large enough to trigger large value handling in the IndexedDB
 | 
| +// engines that have special code paths for large values.
 | 
| +const wrapThreshold = 128 * 1024;
 | 
| +
 | 
| +// Returns an IndexedDB value created from a descriptor.
 | 
| +//
 | 
| +// See the bottom of the file for descriptor samples.
 | 
| +function createValue(descriptor) {
 | 
| +  if (typeof(descriptor) != 'object')
 | 
| +    return descriptor;
 | 
| +
 | 
| +  if (Array.isArray(descriptor))
 | 
| +    return descriptor.map((element) => createValue(element));
 | 
| +
 | 
| +  if (!descriptor.hasOwnProperty('type')) {
 | 
| +    const value = {};
 | 
| +    for (let property of Object.getOwnPropertyNames(descriptor))
 | 
| +      value[property] = createValue(descriptor[property]);
 | 
| +    return value;
 | 
| +  }
 | 
| +
 | 
| +  switch (descriptor.type) {
 | 
| +    case 'blob':
 | 
| +      return new Blob(
 | 
| +          [largeValue(descriptor.size, descriptor.seed)],
 | 
| +          { type: descriptor.mimeType });
 | 
| +    case 'buffer':
 | 
| +      return largeValue(descriptor.size, descriptor.seed);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Checks an IndexedDB value against a descriptor.
 | 
| +//
 | 
| +// Returns a Promise that resolves if the value passes the check.
 | 
| +//
 | 
| +// See the bottom of the file for descriptor samples.
 | 
| +function checkValue(testCase, value, descriptor) {
 | 
| +  if (typeof(descriptor) != 'object') {
 | 
| +    assert_equals(
 | 
| +        descriptor, value,
 | 
| +        'IndexedDB result should match put() argument');
 | 
| +    return Promise.resolve();
 | 
| +  }
 | 
| +
 | 
| +  if (Array.isArray(descriptor)) {
 | 
| +    assert_true(
 | 
| +        Array.isArray(value),
 | 
| +        'IndexedDB result type should match put() argument');
 | 
| +    assert_equals(
 | 
| +        descriptor.length, value.length,
 | 
| +        'IndexedDB result array size should match put() argument');
 | 
| +
 | 
| +    const subChecks = [];
 | 
| +    for (let i = 0; i < descriptor.length; ++i)
 | 
| +      subChecks.push(checkValue(testCase, value[i], descriptor[i]));
 | 
| +    return Promise.all(subChecks);
 | 
| +  }
 | 
| +
 | 
| +  if (!descriptor.hasOwnProperty('type')) {
 | 
| +    assert_array_equals(
 | 
| +        Object.getOwnPropertyNames(value).sort(),
 | 
| +        Object.getOwnPropertyNames(descriptor).sort(),
 | 
| +        'IndexedDB result object properties should match put() argument');
 | 
| +    const subChecks = [];
 | 
| +    return Promise.all(Object.getOwnPropertyNames(descriptor).map(property =>
 | 
| +        checkValue(testCase, value[property], descriptor[property])));
 | 
| +  }
 | 
| +
 | 
| +  switch (descriptor.type) {
 | 
| +    case 'blob':
 | 
| +      assert_class_string(
 | 
| +          value, 'Blob',
 | 
| +          'IndexedDB result class should match put() argument');
 | 
| +      assert_equals(
 | 
| +          descriptor.mimeType, value.type,
 | 
| +          'IndexedDB result Blob MIME type should match put() argument');
 | 
| +      assert_equals(descriptor.size, value.size, 'incorrect Blob size');
 | 
| +      return new Promise((resolve, reject) => {
 | 
| +        const reader = new FileReader();
 | 
| +        reader.onloadend = testCase.step_func(() => {
 | 
| +          if (reader.error) {
 | 
| +            reject(reader.error);
 | 
| +            return;
 | 
| +          }
 | 
| +          const view = new Uint8Array(reader.result);
 | 
| +          assert_equals(
 | 
| +              view.join(','),
 | 
| +              largeValue(descriptor.size, descriptor.seed).join(','),
 | 
| +              'IndexedDB result Blob content should match put() argument');
 | 
| +          resolve();
 | 
| +        });
 | 
| +        reader.readAsArrayBuffer(value);
 | 
| +      });
 | 
| +
 | 
| +    case 'buffer':
 | 
| +      assert_class_string(
 | 
| +          value, 'Uint8Array',
 | 
| +          'IndexedDB result type should match put() argument');
 | 
| +      assert_equals(
 | 
| +          value.join(','),
 | 
| +          largeValue(descriptor.size, descriptor.seed).join(','),
 | 
| +          'IndexedDB result typed array content should match put() argument');
 | 
| +      return Promise.resolve();
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Performs a series of put()s and verifies that get()s and getAll() match.
 | 
| +//
 | 
| +// Each element of the valueDescriptors array is fed into createValue(), and the
 | 
| +// resulting value is written to IndexedDB via a put() request. After the writes
 | 
| +// complete, the values are read in the same order in which they were written.
 | 
| +// Last, all the results are read one more time via a getAll().
 | 
| +//
 | 
| +// The test verifies that the get() / getAll() results match the arguments to
 | 
| +// put() and that the order in which the get() result events are fired matches
 | 
| +// the order of the get() requests.
 | 
| +function cloningTest(label, valueDescriptors) {
 | 
| +  promise_test(testCase => {
 | 
| +    return createDatabase(testCase, (database, transaction) => {
 | 
| +      const store = database.createObjectStore('test-store');
 | 
| +      for (let i = 0; i < valueDescriptors.length; ++i) {
 | 
| +        store.put(createValue(valueDescriptors[i]), i);
 | 
| +      }
 | 
| +    }).then(database => {
 | 
| +      const transaction = database.transaction(['test-store'], 'readonly');
 | 
| +      const store = transaction.objectStore('test-store');
 | 
| +      const subChecks = [];
 | 
| +      let resultIndex = 0;
 | 
| +      for (let i = 0; i < valueDescriptors.length; ++i) {
 | 
| +        subChecks.push(new Promise((resolve, reject) => {
 | 
| +          const requestIndex = i;
 | 
| +          const request = store.get(requestIndex);
 | 
| +          request.onerror =
 | 
| +              testCase.step_func(() => { reject(request.error); });
 | 
| +          request.onsuccess = testCase.step_func(() => {
 | 
| +            assert_equals(
 | 
| +                resultIndex, requestIndex,
 | 
| +                'IDBRequest success events should be fired in request order');
 | 
| +            ++resultIndex;
 | 
| +            resolve(checkValue(
 | 
| +                testCase, request.result, valueDescriptors[requestIndex]));
 | 
| +          });
 | 
| +        }));
 | 
| +      }
 | 
| +
 | 
| +      subChecks.push(new Promise((resolve, reject) => {
 | 
| +        const requestIndex = valueDescriptors.length;
 | 
| +        const request = store.getAll();
 | 
| +        request.onerror =
 | 
| +            testCase.step_func(() => { reject(request.error); });
 | 
| +        request.onsuccess = testCase.step_func(() => {
 | 
| +          assert_equals(
 | 
| +              resultIndex, requestIndex,
 | 
| +              'IDBRequest success events should be fired in request order');
 | 
| +          ++resultIndex;
 | 
| +          resolve(checkValue(
 | 
| +              testCase, request.result, valueDescriptors));
 | 
| +        });
 | 
| +      }));
 | 
| +
 | 
| +      return Promise.all(subChecks);
 | 
| +    });
 | 
| +  }, label);
 | 
| +}
 | 
| +
 | 
| +cloningTest('small typed array', [
 | 
| +  { type: 'buffer', size: 64, seed: 1 },
 | 
| +]);
 | 
| +
 | 
| +cloningTest('large typed array', [
 | 
| +  { type: 'buffer', size: wrapThreshold, seed: 1 },
 | 
| +])
 | 
| +
 | 
| +cloningTest('blob', [
 | 
| +  { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-1', seed: 1 },
 | 
| +]);
 | 
| +
 | 
| +cloningTest('blob with small typed array', [
 | 
| +  {
 | 
| +    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01',
 | 
| +            seed: 1 },
 | 
| +    buffer: { type: 'buffer', size: 64, seed: 2 },
 | 
| +  },
 | 
| +]);
 | 
| +
 | 
| +cloningTest('blob with large typed array', [
 | 
| +  {
 | 
| +    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01',
 | 
| +            seed: 1 },
 | 
| +    buffer: { type: 'buffer', size: wrapThreshold, seed: 2 },
 | 
| +  },
 | 
| +]);
 | 
| +
 | 
| +cloningTest('blob array', [
 | 
| +  [
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-1', seed: 1 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-2', seed: 2 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-3', seed: 3 },
 | 
| +  ],
 | 
| +]);
 | 
| +
 | 
| +cloningTest('array of blobs and small typed arrays', [
 | 
| +  [
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01', seed: 1 },
 | 
| +    { type: 'buffer', size: 64, seed: 2 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-03', seed: 3 },
 | 
| +    { type: 'buffer', size: 64, seed: 4 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-05', seed: 5 },
 | 
| +  ],
 | 
| +]);
 | 
| +
 | 
| +cloningTest('array of blobs and large typed arrays', [
 | 
| +  [
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01', seed: 1 },
 | 
| +    { type: 'buffer', size: wrapThreshold, seed: 2 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-03', seed: 3 },
 | 
| +    { type: 'buffer', size: wrapThreshold, seed: 4 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-05', seed: 5 },
 | 
| +  ],
 | 
| +]);
 | 
| +
 | 
| +cloningTest('object with blobs and large typed arrays', [
 | 
| +  {
 | 
| +    blob: { type: 'blob', size: wrapThreshold,
 | 
| +            mimeType: 'text/x-blink1', seed: 1 },
 | 
| +    more: [
 | 
| +      { type: 'buffer', size: wrapThreshold, seed: 2 },
 | 
| +      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink3', seed: 3 },
 | 
| +      { type: 'buffer', size: wrapThreshold, seed: 4 },
 | 
| +    ],
 | 
| +    blob2: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink5',
 | 
| +             seed: 5 },
 | 
| +  },
 | 
| +]);
 | 
| +
 | 
| +cloningTest('multiple requests of objects with blobs and large typed arrays', [
 | 
| +  {
 | 
| +    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink1',
 | 
| +            seed: 1 },
 | 
| +    more: [
 | 
| +      { type: 'buffer', size: wrapThreshold, seed: 2 },
 | 
| +      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink3', seed: 3 },
 | 
| +      { type: 'buffer', size: wrapThreshold, seed: 4 },
 | 
| +    ],
 | 
| +    blob2: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink5',
 | 
| +             seed: 5 },
 | 
| +  },
 | 
| +  [
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink06', seed: 6 },
 | 
| +    { type: 'buffer', size: wrapThreshold, seed: 7 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink08', seed: 8 },
 | 
| +    { type: 'buffer', size: wrapThreshold, seed: 9 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink10', seed: 10 },
 | 
| +  ],
 | 
| +  {
 | 
| +    data: [
 | 
| +      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-11',
 | 
| +        seed: 11 },
 | 
| +      { type: 'buffer', size: wrapThreshold, seed: 12 },
 | 
| +      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-13',
 | 
| +        seed: 13 },
 | 
| +      { type: 'buffer', size: wrapThreshold, seed: 14 },
 | 
| +      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-15',
 | 
| +        seed: 15 },
 | 
| +    ],
 | 
| +  },
 | 
| +  [
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink16', seed: 16 },
 | 
| +    { type: 'buffer', size: wrapThreshold, seed: 17 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink18', seed: 18 },
 | 
| +    { type: 'buffer', size: wrapThreshold, seed: 19 },
 | 
| +    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink20', seed: 20 },
 | 
| +  ],
 | 
| +]);
 | 
| +
 | 
| +</script>
 | 
| 
 |